Browse Source

* synchronized with trunk

git-svn-id: branches/unicodekvm@49342 -
nickysn 4 years ago
parent
commit
cff7bed8bd
61 changed files with 4678 additions and 436 deletions
  1. 12 0
      .gitattributes
  2. 1 1
      compiler/Makefile
  3. 1 1
      compiler/Makefile.fpc
  4. 2 2
      compiler/aarch64/aasmcpu.pas
  5. 1 1
      compiler/aarch64/agcpugas.pas
  6. 36 13
      compiler/aarch64/aoptcpu.pas
  7. 45 12
      compiler/aarch64/cgcpu.pas
  8. 319 84
      compiler/aarch64/ncpumat.pas
  9. 2 1
      compiler/aggas.pas
  10. 11 5
      compiler/arm/aoptcpu.pas
  11. 226 5
      compiler/armgen/aoptarm.pas
  12. 1 1
      compiler/globals.pas
  13. 1 1
      compiler/m68k/cpupara.pas
  14. 14 0
      compiler/msg/errore.msg
  15. 1 1
      compiler/msgidx.inc
  16. 165 151
      compiler/msgtxt.inc
  17. 10 2
      compiler/nflw.pas
  18. 1 1
      compiler/options.pas
  19. 6 0
      compiler/paramgr.pas
  20. 8 4
      compiler/rgobj.pas
  21. 1 1
      compiler/symsym.pas
  22. 1 0
      compiler/systems/t_sinclairql.pas
  23. 2 2
      compiler/utils/msgused.pl
  24. 9 9
      packages/fcl-image/src/fpwritepnm.pp
  25. 2 1
      packages/graph/src/ptcgraph/ptcgraph.pp
  26. 2 2
      packages/pastojs/src/pas2jscompiler.pp
  27. 53 0
      packages/qlunits/examples/mtinf.pas
  28. 2 0
      packages/qlunits/fpmake.pp
  29. 67 35
      packages/qlunits/src/qdos.pas
  30. 50 0
      packages/qlunits/src/qdosfuncs.inc
  31. 6 1
      packages/qlunits/src/sms.pas
  32. 16 0
      packages/qlunits/src/smsfuncs.inc
  33. 3 3
      packages/rtl-extra/fpmake.pp
  34. 9 9
      packages/rtl-objpas/fpmake.pp
  35. 12 0
      packages/rtl-objpas/src/inc/rtti.pp
  36. 245 29
      packages/rtl-objpas/tests/tests.rtti.pas
  37. 49 5
      packages/rtl-objpas/tests/tests.rtti.util.pas
  38. 2 2
      rtl/aarch64/math.inc
  39. 21 0
      rtl/darwin/pthread.inc
  40. 9 8
      rtl/inc/genmath.inc
  41. 21 0
      rtl/inc/systemh.inc
  42. 36 0
      rtl/inc/text.inc
  43. 3 3
      rtl/objpas/sysutils/dati.inc
  44. 1 1
      rtl/sinclairql/Makefile
  45. 1 1
      rtl/sinclairql/Makefile.fpc
  46. 1 2
      rtl/sinclairql/qdosfuncs.inc
  47. 2 1
      rtl/sinclairql/si_prc.pp
  48. 73 18
      rtl/sinclairql/sysutils.pp
  49. 20 0
      rtl/unix/cthreads.pp
  50. 1 1
      tests/Makefile
  51. 1 1
      tests/Makefile.fpc
  52. 469 0
      tests/bench/bdiv.pp
  53. 208 0
      tests/bench/bdiv_s32.inc
  54. 772 0
      tests/bench/bdiv_s64.inc
  55. 769 0
      tests/bench/bdiv_u32.inc
  56. 621 0
      tests/bench/bdiv_u64.inc
  57. 3 0
      tests/test/cg/tmoddiv6.pp
  58. 189 0
      tests/test/units/system/ttxtflsh.pp
  59. 21 0
      tests/webtbs/tw38832.pp
  60. 18 0
      tests/webtbs/tw38833.pp
  61. 24 15
      utils/pas2js/dist/rtl.js

+ 12 - 0
.gitattributes

@@ -8843,12 +8843,15 @@ packages/pxlib/src/pxlib.pp svneol=native#text/plain
 packages/qlunits/Makefile svneol=native#text/plain
 packages/qlunits/Makefile svneol=native#text/plain
 packages/qlunits/Makefile.fpc svneol=native#text/plain
 packages/qlunits/Makefile.fpc svneol=native#text/plain
 packages/qlunits/README.txt svneol=native#text/plain
 packages/qlunits/README.txt svneol=native#text/plain
+packages/qlunits/examples/mtinf.pas svneol=native#text/plain
 packages/qlunits/examples/qlcube.pas svneol=native#text/plain
 packages/qlunits/examples/qlcube.pas svneol=native#text/plain
 packages/qlunits/fpmake.pp svneol=native#text/plain
 packages/qlunits/fpmake.pp svneol=native#text/plain
 packages/qlunits/src/qdos.pas svneol=native#text/plain
 packages/qlunits/src/qdos.pas svneol=native#text/plain
+packages/qlunits/src/qdosfuncs.inc svneol=native#text/plain
 packages/qlunits/src/qlfloat.pas svneol=native#text/plain
 packages/qlunits/src/qlfloat.pas svneol=native#text/plain
 packages/qlunits/src/qlutil.pas svneol=native#text/plain
 packages/qlunits/src/qlutil.pas svneol=native#text/plain
 packages/qlunits/src/sms.pas svneol=native#text/plain
 packages/qlunits/src/sms.pas svneol=native#text/plain
+packages/qlunits/src/smsfuncs.inc svneol=native#text/plain
 packages/regexpr/Makefile svneol=native#text/plain
 packages/regexpr/Makefile svneol=native#text/plain
 packages/regexpr/Makefile.fpc svneol=native#text/plain
 packages/regexpr/Makefile.fpc svneol=native#text/plain
 packages/regexpr/Makefile.fpc.fpcmake svneol=native#text/plain
 packages/regexpr/Makefile.fpc.fpcmake svneol=native#text/plain
@@ -12551,6 +12554,11 @@ tests/bench/bansi1.inc svneol=native#text/plain
 tests/bench/bansi1.pp svneol=native#text/plain
 tests/bench/bansi1.pp svneol=native#text/plain
 tests/bench/bansi1mt.pp svneol=native#text/plain
 tests/bench/bansi1mt.pp svneol=native#text/plain
 tests/bench/bcase.pp svneol=native#text/pascal
 tests/bench/bcase.pp svneol=native#text/pascal
+tests/bench/bdiv.pp svneol=native#text/pascal
+tests/bench/bdiv_s32.inc svneol=native#text/plain
+tests/bench/bdiv_s64.inc svneol=native#text/plain
+tests/bench/bdiv_u32.inc svneol=native#text/plain
+tests/bench/bdiv_u64.inc svneol=native#text/plain
 tests/bench/blists1.inc svneol=native#text/plain
 tests/bench/blists1.inc svneol=native#text/plain
 tests/bench/blists1.pp svneol=native#text/plain
 tests/bench/blists1.pp svneol=native#text/plain
 tests/bench/bmd5.pp svneol=native#text/plain
 tests/bench/bmd5.pp svneol=native#text/plain
@@ -14169,6 +14177,7 @@ tests/test/cg/tmoddiv2.pp svneol=native#text/plain
 tests/test/cg/tmoddiv3.pp svneol=native#text/pascal
 tests/test/cg/tmoddiv3.pp svneol=native#text/pascal
 tests/test/cg/tmoddiv4.pp svneol=native#text/pascal
 tests/test/cg/tmoddiv4.pp svneol=native#text/pascal
 tests/test/cg/tmoddiv5.pp svneol=native#text/pascal
 tests/test/cg/tmoddiv5.pp svneol=native#text/pascal
+tests/test/cg/tmoddiv6.pp svneol=native#text/pascal
 tests/test/cg/tmul3264.pp svneol=native#text/plain
 tests/test/cg/tmul3264.pp svneol=native#text/plain
 tests/test/cg/tneg.pp svneol=native#text/plain
 tests/test/cg/tneg.pp svneol=native#text/plain
 tests/test/cg/tnegnotassign1.pp svneol=native#text/plain
 tests/test/cg/tnegnotassign1.pp svneol=native#text/plain
@@ -16428,6 +16437,7 @@ tests/test/units/system/tstring.pp svneol=native#text/plain
 tests/test/units/system/ttrig.pas svneol=native#text/plain
 tests/test/units/system/ttrig.pas svneol=native#text/plain
 tests/test/units/system/ttrig.pp svneol=native#text/plain
 tests/test/units/system/ttrig.pp svneol=native#text/plain
 tests/test/units/system/ttrunc.pp svneol=native#text/plain
 tests/test/units/system/ttrunc.pp svneol=native#text/plain
+tests/test/units/system/ttxtflsh.pp svneol=native#text/plain
 tests/test/units/system/tval.inc svneol=native#text/plain
 tests/test/units/system/tval.inc svneol=native#text/plain
 tests/test/units/system/tval.pp svneol=native#text/plain
 tests/test/units/system/tval.pp svneol=native#text/plain
 tests/test/units/system/tval1.pp svneol=native#text/plain
 tests/test/units/system/tval1.pp svneol=native#text/plain
@@ -18902,6 +18912,8 @@ tests/webtbs/tw38718.pp svneol=native#text/pascal
 tests/webtbs/tw38733.pp svneol=native#text/pascal
 tests/webtbs/tw38733.pp svneol=native#text/pascal
 tests/webtbs/tw38766.pp svneol=native#text/plain
 tests/webtbs/tw38766.pp svneol=native#text/plain
 tests/webtbs/tw38802.pp svneol=native#text/pascal
 tests/webtbs/tw38802.pp svneol=native#text/pascal
+tests/webtbs/tw38832.pp svneol=native#text/pascal
+tests/webtbs/tw38833.pp svneol=native#text/plain
 tests/webtbs/tw3893.pp svneol=native#text/plain
 tests/webtbs/tw3893.pp svneol=native#text/plain
 tests/webtbs/tw3898.pp svneol=native#text/plain
 tests/webtbs/tw3898.pp svneol=native#text/plain
 tests/webtbs/tw3899.pp svneol=native#text/plain
 tests/webtbs/tw3899.pp svneol=native#text/plain

+ 1 - 1
compiler/Makefile

@@ -587,7 +587,7 @@ ifeq ($(findstring $(PPC_TARGET),x86_64 aarch64 arm),)
 $(error The $(PPC_TARGET) architecture is not (yet) supported by the FPC/LLVM code generator)
 $(error The $(PPC_TARGET) architecture is not (yet) supported by the FPC/LLVM code generator)
 endif
 endif
 ifeq ($(findstring $(OS_TARGET),darwin iphonesim linux),)
 ifeq ($(findstring $(OS_TARGET),darwin iphonesim linux),)
-$(error The $(PPC_TARGET) target OS is not (yet) supported by the FPC/LLVM code generator)
+$(error The $(OS_TARGET) target OS is not (yet) supported by the FPC/LLVM code generator)
 endif
 endif
 override LOCALOPT+=-dllvm -Fullvm
 override LOCALOPT+=-dllvm -Fullvm
 endif
 endif

+ 1 - 1
compiler/Makefile.fpc

@@ -332,7 +332,7 @@ $(error The $(PPC_TARGET) architecture is not (yet) supported by the FPC/LLVM co
 endif
 endif
 
 
 ifeq ($(findstring $(OS_TARGET),darwin iphonesim linux),)
 ifeq ($(findstring $(OS_TARGET),darwin iphonesim linux),)
-$(error The $(PPC_TARGET) target OS is not (yet) supported by the FPC/LLVM code generator)
+$(error The $(OS_TARGET) target OS is not (yet) supported by the FPC/LLVM code generator)
 endif
 endif
 
 
 override LOCALOPT+=-dllvm -Fullvm
 override LOCALOPT+=-dllvm -Fullvm

+ 2 - 2
compiler/aarch64/aasmcpu.pas

@@ -1061,7 +1061,8 @@ implementation
                  { check for pre/post indexed in spilling_get_operation_type_ref }
                  { check for pre/post indexed in spilling_get_operation_type_ref }
                  result:=operand_read;
                  result:=operand_read;
              end;
              end;
-           A_MOVK:
+           A_MOVK,
+           A_BFI:
              begin
              begin
                if opnr=0 then
                if opnr=0 then
                  result:=operand_readwrite
                  result:=operand_readwrite
@@ -1074,7 +1075,6 @@ implementation
            A_ADRP,
            A_ADRP,
            A_AND,
            A_AND,
            A_ASR,
            A_ASR,
-           A_BFI,
            A_BFXIL,
            A_BFXIL,
            A_CLZ,
            A_CLZ,
            A_CSEL,
            A_CSEL,

+ 1 - 1
compiler/aarch64/agcpugas.pas

@@ -837,7 +837,7 @@ unit agcpugas;
        as_aarch64_clang_gas_info : tasminfo =
        as_aarch64_clang_gas_info : tasminfo =
           (
           (
             id     : as_clang_gas;
             id     : as_clang_gas;
-            idtxt  : 'CLANG';
+            idtxt  : 'AS-CLANG';
             asmbin : 'clang';
             asmbin : 'clang';
             asmcmd : '-x assembler -c -target $TRIPLET -o $OBJ $MARCHOPT $EXTRAOPT -x assembler $ASM';
             asmcmd : '-x assembler -c -target $TRIPLET -o $OBJ $MARCHOPT $EXTRAOPT -x assembler $ASM';
             supported_targets : [system_aarch64_win64];
             supported_targets : [system_aarch64_win64];

+ 36 - 13
compiler/aarch64/aoptcpu.pas

@@ -44,6 +44,10 @@ Interface
         function RegLoadedWithNewValue(reg: tregister; hp: tai): boolean;override;
         function RegLoadedWithNewValue(reg: tregister; hp: tai): boolean;override;
         function InstructionLoadsFromReg(const reg: TRegister; const hp: tai): boolean;override;
         function InstructionLoadsFromReg(const reg: TRegister; const hp: tai): boolean;override;
         function LookForPostindexedPattern(var p : tai) : boolean;
         function LookForPostindexedPattern(var p : tai) : boolean;
+      public
+        { With these routines, there's optimisation code that's general for all ARM platforms }
+        function OptPass1LDR(var p: tai): Boolean; override;
+        function OptPass1STR(var p: tai): Boolean; override;
       private
       private
         function RemoveSuperfluousFMov(const p: tai; movp: tai; const optimizer: string): boolean;
         function RemoveSuperfluousFMov(const p: tai; movp: tai; const optimizer: string): boolean;
         function OptPass1Shift(var p: tai): boolean;
         function OptPass1Shift(var p: tai): boolean;
@@ -199,9 +203,9 @@ Implementation
         not(RegModifiedBetween(taicpu(hp1).oper[2]^.reg,p,hp1)) then
         not(RegModifiedBetween(taicpu(hp1).oper[2]^.reg,p,hp1)) then
         begin
         begin
           if taicpu(p).opcode = A_LDR then
           if taicpu(p).opcode = A_LDR then
-            DebugMsg('Peephole LdrAdd/Sub2Ldr Postindex done', p)
+            DebugMsg(SPeepholeOptimization + 'LdrAdd/Sub2Ldr Postindex done', p)
           else
           else
-            DebugMsg('Peephole StrAdd/Sub2Str Postindex done', p);
+            DebugMsg(SPeepholeOptimization + 'StrAdd/Sub2Str Postindex done', p);
 
 
           taicpu(p).oper[1]^.ref^.addressmode:=AM_POSTINDEXED;
           taicpu(p).oper[1]^.ref^.addressmode:=AM_POSTINDEXED;
           if taicpu(hp1).opcode=A_ADD then
           if taicpu(hp1).opcode=A_ADD then
@@ -244,7 +248,7 @@ Implementation
           dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(movp.Next));
           dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(movp.Next));
           if assigned(dealloc) then
           if assigned(dealloc) then
             begin
             begin
-              DebugMsg('Peephole '+optimizer+' removed superfluous vmov', movp);
+              DebugMsg(SPeepholeOptimization + optimizer+' removed superfluous vmov', movp);
               result:=true;
               result:=true;
 
 
               { taicpu(p).oper[0]^.reg is not used anymore, try to find its allocation
               { taicpu(p).oper[0]^.reg is not used anymore, try to find its allocation
@@ -291,6 +295,24 @@ Implementation
     end;
     end;
 
 
 
 
+  function TCpuAsmOptimizer.OptPass1LDR(var p: tai): Boolean;
+    begin
+      Result := False;
+      if inherited OptPass1LDR(p) or
+        LookForPostindexedPattern(p) then
+        Exit(True);
+    end;
+
+
+  function TCpuAsmOptimizer.OptPass1STR(var p: tai): Boolean;
+    begin
+      Result := False;
+      if inherited OptPass1STR(p) or
+        LookForPostindexedPattern(p) then
+        Exit(True);
+    end;
+
+
   function TCpuAsmOptimizer.OptPass1Shift(var p : tai): boolean;
   function TCpuAsmOptimizer.OptPass1Shift(var p : tai): boolean;
     var
     var
       hp1,hp2: tai;
       hp1,hp2: tai;
@@ -395,7 +417,7 @@ Implementation
                 RemoveInstruction(hp1);
                 RemoveInstruction(hp1);
                 RemoveCurrentp(p);
                 RemoveCurrentp(p);
 
 
-                DebugMsg('Peephole FoldShiftProcess done', hp2);
+                DebugMsg(SPeepholeOptimization + 'FoldShiftProcess done', hp2);
                 Result:=true;
                 Result:=true;
                 break;
                 break;
               end;
               end;
@@ -488,7 +510,7 @@ Implementation
           hp3.free;
           hp3.free;
           hp4.free;
           hp4.free;
           p:=hp2;
           p:=hp2;
-          DebugMsg('Peephole Bl2B done', p);
+          DebugMsg(SPeepholeOptimization + 'Bl2B done', p);
           Result:=true;
           Result:=true;
         end;
         end;
     end;
     end;
@@ -503,7 +525,7 @@ Implementation
        (taicpu(p).oppostfix=PF_None) then
        (taicpu(p).oppostfix=PF_None) then
        begin
        begin
          RemoveCurrentP(p);
          RemoveCurrentP(p);
-         DebugMsg('Peephole Mov2None done', p);
+         DebugMsg(SPeepholeOptimization + 'Mov2None done', p);
          Result:=true;
          Result:=true;
        end
        end
 
 
@@ -669,9 +691,9 @@ Implementation
                                 }
                                 }
                                 taicpu(p).opcode := TargetOpcode;
                                 taicpu(p).opcode := TargetOpcode;
                                 if TargetOpcode = A_STP then
                                 if TargetOpcode = A_STP then
-                                  DebugMsg('Peephole Optimization: StrStr2Stp', p)
+                                  DebugMsg(SPeepholeOptimization + 'StrStr2Stp', p)
                                 else
                                 else
-                                  DebugMsg('Peephole Optimization: LdrLdr2Ldp', p);
+                                  DebugMsg(SPeepholeOptimization + 'LdrLdr2Ldp', p);
                                 taicpu(p).ops := 3;
                                 taicpu(p).ops := 3;
                                 taicpu(p).loadref(2, taicpu(p).oper[1]^.ref^);
                                 taicpu(p).loadref(2, taicpu(p).oper[1]^.ref^);
                                 taicpu(p).loadreg(1, taicpu(hp1).oper[0]^.reg);
                                 taicpu(p).loadreg(1, taicpu(hp1).oper[0]^.reg);
@@ -695,9 +717,9 @@ Implementation
                                 }
                                 }
                                 taicpu(p).opcode := TargetOpcode;
                                 taicpu(p).opcode := TargetOpcode;
                                 if TargetOpcode = A_STP then
                                 if TargetOpcode = A_STP then
-                                  DebugMsg('Peephole Optimization: StrStr2Stp (reverse)', p)
+                                  DebugMsg(SPeepholeOptimization + 'StrStr2Stp (reverse)', p)
                                 else
                                 else
-                                  DebugMsg('Peephole Optimization: LdrLdr2Ldp (reverse)', p);
+                                  DebugMsg(SPeepholeOptimization + 'LdrLdr2Ldp (reverse)', p);
                                 taicpu(p).ops := 3;
                                 taicpu(p).ops := 3;
                                 taicpu(p).loadref(2, taicpu(hp1).oper[1]^.ref^);
                                 taicpu(p).loadref(2, taicpu(hp1).oper[1]^.ref^);
                                 taicpu(p).loadreg(1, taicpu(p).oper[0]^.reg);
                                 taicpu(p).loadreg(1, taicpu(p).oper[0]^.reg);
@@ -752,7 +774,7 @@ Implementation
           p.free;
           p.free;
           hp1.free;
           hp1.free;
           p:=hp2;
           p:=hp2;
-          DebugMsg('Peephole CMPB.E/NE2CBNZ/CBZ done', p);
+          DebugMsg(SPeepholeOptimization + 'CMPB.E/NE2CBNZ/CBZ done', p);
           Result:=true;
           Result:=true;
         end;
         end;
     end;
     end;
@@ -764,9 +786,10 @@ Implementation
       if p.typ=ait_instruction then
       if p.typ=ait_instruction then
         begin
         begin
           case taicpu(p).opcode of
           case taicpu(p).opcode of
-            A_LDR,
+            A_LDR:
+              Result:=OptPass1LDR(p);
             A_STR:
             A_STR:
-              Result:=LookForPostindexedPattern(p);
+              Result:=OptPass1STR(p);
             A_MOV:
             A_MOV:
               Result:=OptPass1Mov(p);
               Result:=OptPass1Mov(p);
             A_STP:
             A_STP:

+ 45 - 12
compiler/aarch64/cgcpu.pas

@@ -583,13 +583,15 @@ implementation
         opc: tasmop;
         opc: tasmop;
         shift: byte;
         shift: byte;
         so: tshifterop;
         so: tshifterop;
-        reginited,doinverted: boolean;
+        reginited,doinverted,extendedsize: boolean;
         manipulated_a: tcgint;
         manipulated_a: tcgint;
         leftover_a: word;
         leftover_a: word;
       begin
       begin
 {$ifdef extdebug}
 {$ifdef extdebug}
         list.concat(tai_comment.Create(strpnew('Generating constant ' + tostr(a) + ' / $' + hexstr(a, 16))));
         list.concat(tai_comment.Create(strpnew('Generating constant ' + tostr(a) + ' / $' + hexstr(a, 16))));
 {$endif extdebug}
 {$endif extdebug}
+        extendedsize := (size in [OS_64,OS_S64]);
+
         case a of
         case a of
           { Small positive number }
           { Small positive number }
           $0..$FFFF:
           $0..$FFFF:
@@ -613,19 +615,50 @@ implementation
             end;
             end;
           else
           else
             begin
             begin
+              if not extendedsize then
+                { Mostly so programmers don't get confused when they view the disassembly and
+                  'a' is sign-extended to 64-bit, say, but also avoids potential problems with
+                  third-party assemblers if the number is out of bounds for a given size }
+                a := Cardinal(a);
 
 
-              if size in [OS_64,OS_S64] then
+              { Check to see if a is a valid shifter constant that can be encoded in ORR as is }
+              if is_shifter_const(a,size) then
+                begin
+                  { Use synthetic "MOV" instruction instead of "ORR reg,wzr,#a" (an alias),
+                    since AArch64 conventions prefer this, and it's clearer in the
+                    disassembly }
+                  list.concat(taicpu.op_reg_const(A_MOV,reg,a));
+                  Exit;
+                end;
+
+              { If the value of a fits into 32 bits, it's fastest to use movz/movk regardless }
+              if extendedsize and ((a shr 32) <> 0) then
                 begin
                 begin
-                  { Check to see if a is a valid shifter constant that can be encoded in ORR as is }
-                  if is_shifter_const(a,size) then
+                  { This determines whether this write can be performed with an ORR followed by MOVK
+                    by copying the 3nd word to the 1st word for the ORR constant, then overwriting
+                    the 1st word.  The alternative would require 4 instructions.  This sequence is
+                    common when division reciprocals are calculated (e.g. 3 produces AAAAAAAAAAAAAAAB). }
+                  leftover_a := word(a and $FFFF);
+                  manipulated_a := (a and $FFFFFFFFFFFF0000) or ((a shr 32) and $FFFF);
+                  { if manipulated_a = a, don't check, because is_shifter_const was already
+                    called for a and it returned False.  Reduces processing time. [Kit] }
+                  if (manipulated_a <> a) and is_shifter_const(manipulated_a, OS_64) then
                     begin
                     begin
-                      list.concat(taicpu.op_reg_reg_const(A_ORR,reg,makeregsize(NR_XZR,size),a));
+                      { Encode value as:
+                          orr  reg,xzr,manipulated_a
+                          movk reg,#(leftover_a)
+
+                        Use "orr" instead of "mov" here for the assembly dump so it better
+                        implies that something special is happening with the number arrangement.
+                      }
+                      list.concat(taicpu.op_reg_reg_const(A_ORR, reg, NR_XZR, manipulated_a));
+                      list.concat(taicpu.op_reg_const(A_MOVK, reg, leftover_a));
                       Exit;
                       Exit;
                     end;
                     end;
 
 
                   { This determines whether this write can be performed with an ORR followed by MOVK
                   { This determines whether this write can be performed with an ORR followed by MOVK
                     by copying the 2nd word to the 4th word for the ORR constant, then overwriting
                     by copying the 2nd word to the 4th word for the ORR constant, then overwriting
-                    the 4th word (unless the word is.  The alternative would require 3 instructions }
+                    the 4th word.  The alternative would require 3 instructions }
                   leftover_a := word(a shr 48);
                   leftover_a := word(a shr 48);
                   manipulated_a := (a and $0000FFFFFFFFFFFF);
                   manipulated_a := (a and $0000FFFFFFFFFFFF);
 
 
@@ -642,13 +675,16 @@ implementation
                   manipulated_a := manipulated_a or (((a shr 16) and $FFFF) shl 48);
                   manipulated_a := manipulated_a or (((a shr 16) and $FFFF) shl 48);
                   { if manipulated_a = a, don't check, because is_shifter_const was already
                   { if manipulated_a = a, don't check, because is_shifter_const was already
                     called for a and it returned False.  Reduces processing time. [Kit] }
                     called for a and it returned False.  Reduces processing time. [Kit] }
-                  if (manipulated_a <> a) and is_shifter_const(manipulated_a, size) then
+                  if (manipulated_a <> a) and is_shifter_const(manipulated_a, OS_64) then
                     begin
                     begin
                       { Encode value as:
                       { Encode value as:
                           orr  reg,xzr,manipulated_a
                           orr  reg,xzr,manipulated_a
                           movk reg,#(leftover_a),lsl #48
                           movk reg,#(leftover_a),lsl #48
+
+                        Use "orr" instead of "mov" here for the assembly dump so it better
+                        implies that something special is happening with the number arrangement.
                       }
                       }
-                      list.concat(taicpu.op_reg_reg_const(A_ORR, reg, makeregsize(NR_XZR, size), manipulated_a));
+                      list.concat(taicpu.op_reg_reg_const(A_ORR, reg, NR_XZR, manipulated_a));
                       shifterop_reset(so);
                       shifterop_reset(so);
                       so.shiftmode := SM_LSL;
                       so.shiftmode := SM_LSL;
                       so.shiftimm := 48;
                       so.shiftimm := 48;
@@ -679,10 +715,7 @@ implementation
                   end;
                   end;
                 end
                 end
               else
               else
-                begin
-                  a:=cardinal(a);
-                  doinverted:=False;
-                end;
+                doinverted:=False;
             end;
             end;
         end;
         end;
 
 

+ 319 - 84
compiler/aarch64/ncpumat.pas

@@ -71,20 +71,35 @@ implementation
       var
       var
          op         : tasmop;
          op         : tasmop;
          tmpreg,
          tmpreg,
+         zeroreg,
          numerator,
          numerator,
          divider,
          divider,
+         largernumreg,
+         largerresreg,
          resultreg  : tregister;
          resultreg  : tregister;
-         hl : tasmlabel;
+         hl         : tasmlabel;
          overflowloc: tlocation;
          overflowloc: tlocation;
-         power: longint;
+         power      : longint;
+         opsize     : tcgsize;
+
+         dividend   : Int64;
+         high_bit,
+         reciprocal : QWord;
+         { Just to save on stack space and the like }
+         reciprocal_signed : Int64 absolute reciprocal;
+
+         expandword,
+         magic_add  : Boolean;
+         shift      : byte;
+
+         shifterop  : tshifterop;
+         hp         : taicpu;
 
 
        procedure genOrdConstNodeDiv;
        procedure genOrdConstNodeDiv;
          var
          var
            helper1, helper2: TRegister;
            helper1, helper2: TRegister;
            so: tshifterop;
            so: tshifterop;
-           opsize: TCgSize;
          begin
          begin
-           opsize:=def_cgsize(resultdef);
            if tordconstnode(right).value=0 then
            if tordconstnode(right).value=0 then
              internalerror(2020021601)
              internalerror(2020021601)
            else if tordconstnode(right).value=1 then
            else if tordconstnode(right).value=1 then
@@ -98,7 +113,7 @@ implementation
                current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_NEG,
                current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_NEG,
                  resultreg,numerator),toppostfix(ord(cs_check_overflow in current_settings.localswitches)*ord(PF_S))));
                  resultreg,numerator),toppostfix(ord(cs_check_overflow in current_settings.localswitches)*ord(PF_S))));
              end
              end
-           else if ispowerof2(tordconstnode(right).value,power) then
+           else if isabspowerof2(tordconstnode(right).value,power) then
              begin
              begin
                if (is_signed(right.resultdef)) then
                if (is_signed(right.resultdef)) then
                  begin
                  begin
@@ -115,98 +130,318 @@ implementation
                     so.shiftimm:=resultdef.size*8-power;
                     so.shiftimm:=resultdef.size*8-power;
                     current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,helper2,numerator,helper1,so));
                     current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,helper2,numerator,helper1,so));
                     cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SAR,def_cgsize(resultdef),power,helper2,resultreg);
                     cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SAR,def_cgsize(resultdef),power,helper2,resultreg);
+
+                    if (tordconstnode(right).value < 0) then
+                      { Invert the result }
+                      current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_NEG,resultreg,resultreg));
                   end
                   end
-               else
-                 cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SHR,opsize,power,numerator,resultreg)
+                else
+                  cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SHR,opsize,power,numerator,resultreg)
              end
              end
            else
            else
-             { Everything else is handled in the generic code }
-             cg.g_div_const_reg_reg(current_asmdata.CurrAsmList,opsize,
-               tordconstnode(right).value.svalue,numerator,resultreg);
+             { Generic division }
+             begin
+               if is_signed(left.resultdef) then
+                 op:=A_SDIV
+               else
+                 op:=A_UDIV;
+
+               { If we didn't acquire the original divisor earlier, grab it now }
+               if divider = NR_NO then
+                 begin
+                   divider:=cg.getintregister(current_asmdata.CurrAsmList,opsize);
+                   cg.a_load_const_reg(current_asmdata.CurrAsmList,opsize,tordconstnode(right).value.svalue,divider);
+                 end;
+
+               current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,resultreg,numerator,divider));
+             end;
          end;
          end;
 
 
-      begin
-       secondpass(left);
-       secondpass(right);
-       { avoid warning }
-       divider:=NR_NO;
-
-       { set result location }
-       location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
-       location.register:=cg.getintregister(current_asmdata.CurrAsmList,def_cgsize(resultdef));
-       resultreg:=location.register;
-
-       { put numerator in register }
-       hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true);
-       numerator:=left.location.register;
-
-       if (right.nodetype=ordconstn) and
-          ((tordconstnode(right).value=1) or
-           (tordconstnode(right).value=int64(-1)) or
-           (tordconstnode(right).value=0) or
-           ispowerof2(tordconstnode(right).value,power)) then
+       procedure genOverflowCheck;
          begin
          begin
-           genOrdConstNodeDiv;
-           if nodetype=modn then
+           { in case of overflow checking, also check for low(int64) div (-1)
+             (no hardware support for this either) }
+           if (cs_check_overflow in current_settings.localswitches) and
+              is_signed(left.resultdef) and
+              ((right.nodetype<>ordconstn) or
+               (tordconstnode(right).value=-1)) then
              begin
              begin
-               divider:=cg.getintregister(current_asmdata.CurrAsmList,def_cgsize(resultdef));
-               cg.a_load_const_reg(current_asmdata.CurrAsmList,def_cgsize(resultdef),int64(tordconstnode(right).value),divider);
+               { num=ffff... and div=8000... <=>
+                 num xor not(div xor 8000...) = 0
+                 (and we have the "eon" operation, which performs "xor not(...)" }
+               tmpreg:=hlcg.getintregister(current_asmdata.CurrAsmList,left.resultdef);
+               hlcg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_XOR,left.resultdef,low(int64),numerator,tmpreg);
+               current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_EON,
+                 tmpreg,numerator,tmpreg));
+               current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_CMP,tmpreg,0));
+               { now the zero/equal flag is set in case we divided low(int64) by
+                 (-1) }
+               location_reset(overflowloc,LOC_FLAGS,OS_NO);
+               overflowloc.resflags:=F_EQ;
+               cg.g_overflowcheck_loc(current_asmdata.CurrAsmList,location,resultdef,overflowloc);
              end;
              end;
-         end
-       else
-         begin
-           { load divider in a register }
-           hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,true);
-           divider:=right.location.register;
-
-           { start division }
-           if is_signed(left.resultdef) then
-             op:=A_SDIV
-           else
-             op:=A_UDIV;
-           current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,location.register,numerator,divider));
          end;
          end;
 
 
-       { no divide-by-zero detection available in hardware, emulate (if it's a
-         constant, this will have been detected earlier already) }
-       if (right.nodetype<>ordconstn) then
-         begin
-           current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_CMP,
-             right.location.register,0));
+      begin
+        secondpass(left);
+        secondpass(right);
+        { avoid warning }
+        divider := NR_NO;
+        largernumreg := NR_NO;
+        expandword := False;
 
 
-           current_asmdata.getjumplabel(hl);
-           current_asmdata.CurrAsmList.concat(taicpu.op_cond_sym(A_B,C_NE,hl));
-           cg.a_call_name(current_asmdata.CurrAsmList,'FPC_DIVBYZERO',false);
-           cg.a_label(current_asmdata.CurrAsmList,hl);
-         end;
+        opsize := def_cgsize(resultdef);
 
 
-       { in case of overflow checking, also check for low(int64) div (-1)
-         (no hardware support for this either) }
-       if (cs_check_overflow in current_settings.localswitches) and
-          is_signed(left.resultdef) and
-          ((right.nodetype<>ordconstn) or
-           (tordconstnode(right).value=-1)) then
-         begin
-           { num=ffff... and div=8000... <=>
-             num xor not(div xor 8000...) = 0
-             (and we have the "eon" operation, which performs "xor not(...)" }
-           tmpreg:=hlcg.getintregister(current_asmdata.CurrAsmList,left.resultdef);
-           hlcg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_XOR,left.resultdef,low(int64),left.location.register,tmpreg);
-           current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_EON,
-             tmpreg,left.location.register,tmpreg));
-           current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_CMP,tmpreg,0));
-           { now the zero/equal flag is set in case we divided low(int64) by
-             (-1) }
-           location_reset(overflowloc,LOC_FLAGS,OS_NO);
-           overflowloc.resflags:=F_EQ;
-           cg.g_overflowcheck_loc(current_asmdata.CurrAsmList,location,resultdef,overflowloc);
-         end;
+        { set result location }
+        location_reset(location,LOC_REGISTER,opsize);
+        location.register:=cg.getintregister(current_asmdata.CurrAsmList,opsize);
+        resultreg:=location.register;
 
 
-       { in case of modulo, multiply result again by the divider and subtract
-         from the numerator }
-       if nodetype=modn then
-         current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_reg(A_MSUB,resultreg,
-           resultreg,divider,numerator));
+        { put numerator in register }
+        hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true);
+        numerator:=left.location.register;
+
+        if (right.nodetype=ordconstn) then
+          begin
+            { If optimising for size, just use regular division operations }
+            if (cs_opt_size in current_settings.optimizerswitches) or
+              ((tordconstnode(right).value=1) or
+              (tordconstnode(right).value=int64(-1)) or
+              isabspowerof2(tordconstnode(right).value,power)) then
+              begin
+
+                { Store divisor for later (and executed at the same time as the multiplication) }
+                if (nodetype=modn) then
+                  begin
+                    if (tordconstnode(right).value = 1) or (tordconstnode(right).value = int64(-1)) then
+                      begin
+                        { Just evaluates to zero }
+                        current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_MOVZ,resultreg, 0));
+                        Exit;
+                      end
+                    { "not cs_opt_size" saves from checking the value of the divisor again
+                      (if cs_opt_size is not set, then the divisor is a power of 2) }
+                    else if not (cs_opt_size in current_settings.optimizerswitches) then
+                      begin
+                        divider:=cg.getintregister(current_asmdata.CurrAsmList,opsize);
+                        cg.a_load_const_reg(current_asmdata.CurrAsmList,opsize,tordconstnode(right).value.svalue,divider);
+                      end
+                  end;
+
+                genOrdConstNodeDiv;
+                genOverflowCheck;
+
+                { in case of modulo, multiply result again by the divider and subtract
+                  from the numerator }
+                if (nodetype=modn) then
+                  begin
+                    if ispowerof2(tordconstnode(right).value,power) then
+                      begin
+                        shifterop.shiftmode := SM_LSL;
+                        shifterop.shiftimm := power;
+
+                        current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_shifterop(A_SUB,resultreg,numerator,resultreg,shifterop));
+                      end
+                    else
+                      current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_reg(A_MSUB,resultreg,
+                        resultreg,divider,numerator));
+                  end;
+
+                Exit;
+              end
+            else
+              begin
+                if is_signed(left.resultdef) then
+                  begin
+                    if (nodetype=modn) then { Signed mod doesn't work properly }
+                      begin
+                        divider:=cg.getintregister(current_asmdata.CurrAsmList,opsize);
+                        cg.a_load_const_reg(current_asmdata.CurrAsmList,opsize,tordconstnode(right).value.svalue,divider);
+                        genOrdConstNodeDiv;
+                      end
+                    else
+                      begin
+                        { Read signed value to avoid Internal Error 200706094 }
+                        dividend := tordconstnode(right).value.svalue;
+
+                        calc_divconst_magic_signed(resultdef.size * 8, dividend, reciprocal_signed, shift);
+                        cg.a_load_const_reg(current_asmdata.CurrAsmList, opsize, reciprocal_signed, resultreg);
+
+                        { SMULH is only available for the full 64-bit registers }
+                        if opsize in [OS_64, OS_S64] then
+                          begin
+                            current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SMULH,resultreg,resultreg,numerator));
+                            largerresreg := resultreg;
+                          end
+                        else
+                          begin
+                            largerresreg := newreg(getregtype(resultreg), getsupreg(resultreg), R_SUBWHOLE);
+                            largernumreg := newreg(getregtype(numerator), getsupreg(numerator), R_SUBWHOLE);
+                            current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_MUL,largerresreg,largerresreg,largernumreg));
+                            expandword := True; { Merge the shift operation with something below }
+                          end;
+
+                        { Store divisor for later (and executed at the same time as the multiplication) }
+                        if nodetype=modn then
+                          begin
+                            divider:=cg.getintregister(current_asmdata.CurrAsmList,opsize);
+                            cg.a_load_const_reg(current_asmdata.CurrAsmList,opsize,dividend,divider);
+                          end;
+
+                        { add or subtract dividend }
+                        if (dividend > 0) and (reciprocal_signed < 0) then
+                          begin
+                            if expandword then
+                              begin
+                                shifterop.shiftmode := SM_ASR;
+                                shifterop.shiftimm := 32;
+                                expandword := False;
+                                current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,largerresreg,largernumreg,largerresreg,shifterop));
+                              end
+                            else
+                              current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_ADD,resultreg,resultreg,numerator));
+                          end
+                        else if (dividend < 0) and (reciprocal_signed > 0) then
+                          begin
+                            if expandword then
+                              begin
+                                { We can't append LSR to the SUB below because it's on the wrong operand }
+                                expandword := False;
+                                current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_ASR,largerresreg,largerresreg,32));
+                              end;
+
+                            current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SUB,resultreg,resultreg,numerator));
+                          end
+                        else if expandword then
+                          Inc(shift,32);
+
+                        { shift if necessary }
+                        if (shift <> 0) then
+                          begin
+                            if expandword then
+                              current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_ASR,largerresreg,largerresreg,shift))
+                            else
+                              current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_ASR,resultreg,resultreg,shift));
+                          end;
+
+                        { extract and add the sign bit }
+                        shifterop.shiftmode := SM_LSR;
+                        shifterop.shiftimm := left.resultdef.size*8 - 1;
+
+                        if (dividend < 0) then
+                          current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,resultreg,resultreg,resultreg,shifterop))
+                        else
+                          current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,resultreg,resultreg,numerator,shifterop));
+                      end;
+                  end
+                else
+                  begin
+                    calc_divconst_magic_unsigned(resultdef.size * 8, tordconstnode(right).value, reciprocal, magic_add, shift);
+                    { Add explicit typecast to tcgint type, to avoid range or overflow check }
+                    cg.a_load_const_reg(current_asmdata.CurrAsmList, opsize, tcgint(reciprocal), resultreg);
+                    { UMULH is only available for the full 64-bit registers }
+                    if opsize in [OS_64, OS_S64] then
+                      begin
+                        current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_UMULH,resultreg,resultreg,numerator));
+                        largerresreg := resultreg;
+                      end
+                    else
+                      begin
+                        largerresreg := newreg(getregtype(resultreg), getsupreg(resultreg), R_SUBWHOLE);
+                        largernumreg := newreg(getregtype(numerator), getsupreg(numerator), R_SUBWHOLE);
+                        current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_MUL,largerresreg,largerresreg,largernumreg));
+                        expandword := True; { Try to merge the shift operation with something below }
+                      end;
+
+                    { Store divisor for later (and executed at the same time as the multiplication) }
+                    if (nodetype=modn) then
+                      begin
+                        divider:=cg.getintregister(current_asmdata.CurrAsmList,opsize);
+                        cg.a_load_const_reg(current_asmdata.CurrAsmList,opsize,tordconstnode(right).value.svalue,divider);
+                      end;
+
+                    if magic_add then
+                      begin
+                        { We can't append LSR to the ADD below because it would require extending the registers
+                          and interfere with the carry bit }
+                        if expandword then
+                          current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_LSR,largerresreg,largerresreg,32));
+
+                        { Add the reciprocal to the high-order word, tracking the carry bit, shift, then
+                          insert the carry bit via CSEL and ORR }
+
+                        if opsize in [OS_64,OS_S64] then
+                          zeroreg := NR_XZR
+                        else
+                          zeroreg := NR_WZR;
+
+                        high_bit := QWord(1) shl ((resultdef.size * 8) - shift);
+
+                        tmpreg := cg.getintregister(current_asmdata.CurrAsmList, opsize);
+                        cg.a_load_const_reg(current_asmdata.CurrAsmList, opsize, high_bit, tmpreg);
+
+                        { Generate ADDS instruction }
+                        hp := taicpu.op_reg_reg_reg(A_ADD,resultreg,resultreg,numerator);
+                        hp.oppostfix := PF_S;
+                        current_asmdata.CurrAsmList.concat(hp);
+
+                        current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_cond(A_CSEL,tmpreg,tmpreg,zeroreg, C_CS));
+
+                        shifterop.shiftmode := SM_LSR;
+                        shifterop.shiftimm := shift;
+
+                        current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,resultreg,tmpreg,resultreg,shifterop));
+                      end
+                    else if expandword then
+                      { Include the right-shift by 32 to get the high-order DWord }
+                      current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_LSR,largerresreg,largerresreg,shift + 32))
+                    else
+                      current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_LSR,resultreg,resultreg,shift));
+                  end;
+
+              end;
+
+          end
+        { no divide-by-zero detection available in hardware, emulate (if it's a
+          constant, this will have been detected earlier already) }
+        else
+          begin
+            { load divider in a register }
+            hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,true);
+            divider:=right.location.register;
+
+            { ARM-64 developer guides recommend checking for division by zero conditions
+              AFTER the division, since the check and the division can be done in tandem }
+            if is_signed(left.resultdef) then
+              op:=A_SDIV
+            else
+              op:=A_UDIV;
+
+            current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,resultreg,numerator,divider));
+
+            current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_CMP,divider,0));
+            current_asmdata.getjumplabel(hl);
+            current_asmdata.CurrAsmList.concat(taicpu.op_cond_sym(A_B,C_NE,hl));
+            cg.a_call_name(current_asmdata.CurrAsmList,'FPC_DIVBYZERO',false);
+            cg.a_label(current_asmdata.CurrAsmList,hl);
+          end;
+
+        genOverflowCheck;
+
+        { in case of modulo, multiply result again by the divider and subtract
+          from the numerator }
+        if (nodetype=modn) then
+          begin
+            { If we didn't acquire the original divisor earlier, grab it now }
+            if divider = NR_NO then
+              begin
+                divider:=cg.getintregister(current_asmdata.CurrAsmList,opsize);
+                cg.a_load_const_reg(current_asmdata.CurrAsmList,opsize,tordconstnode(right).value.svalue,divider);
+              end;
+
+            current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_reg(A_MSUB,resultreg,
+              resultreg,divider,numerator));
+          end;
     end;
     end;
 
 
 
 

+ 2 - 1
compiler/aggas.pas

@@ -513,7 +513,8 @@ implementation
          system_i386_OS2,
          system_i386_OS2,
          system_i386_EMX: ;
          system_i386_EMX: ;
          system_m68k_atari, { atari tos/mint GNU AS also doesn't seem to like .section (KB) }
          system_m68k_atari, { atari tos/mint GNU AS also doesn't seem to like .section (KB) }
-         system_m68k_amiga: { amiga has old GNU AS (2.14), which blews up from .section (KB) }
+         system_m68k_amiga, { amiga has old GNU AS (2.14), which blews up from .section (KB) }
+         system_m68k_sinclairql: { same story, only ancient GNU tools available (KB) }
            begin
            begin
              { ... but vasm is GAS compatible on amiga/atari, and supports named sections }
              { ... but vasm is GAS compatible on amiga/atari, and supports named sections }
              if create_smartlink_sections then
              if create_smartlink_sections then

+ 11 - 5
compiler/arm/aoptcpu.pas

@@ -59,7 +59,11 @@ Type
     function InstructionLoadsFromReg(const reg : TRegister; const hp : tai) : boolean; override;
     function InstructionLoadsFromReg(const reg : TRegister; const hp : tai) : boolean; override;
 
 
     function RegLoadedWithNewValue(reg : tregister; hp : tai) : boolean; override;
     function RegLoadedWithNewValue(reg : tregister; hp : tai) : boolean; override;
-    function OptPass1And(var p: tai): Boolean; override; { There's optimisation code that's general for all ARM platforms }
+
+     { With these routines, there's optimisation code that's general for all ARM platforms }
+    function OptPass1And(var p: tai): Boolean; override;
+    function OptPass1LDR(var p: tai): Boolean; override;
+    function OptPass1STR(var p: tai): Boolean; override;
   protected
   protected
     function LookForPreindexedPattern(p: taicpu): boolean;
     function LookForPreindexedPattern(p: taicpu): boolean;
     function LookForPostindexedPattern(p: taicpu): boolean;
     function LookForPostindexedPattern(p: taicpu): boolean;
@@ -69,9 +73,7 @@ Type
     function OptPass1DataCheckMov(var p: tai): Boolean;
     function OptPass1DataCheckMov(var p: tai): Boolean;
     function OptPass1ADDSUB(var p: tai): Boolean;
     function OptPass1ADDSUB(var p: tai): Boolean;
     function OptPass1CMP(var p: tai): Boolean;
     function OptPass1CMP(var p: tai): Boolean;
-    function OptPass1LDR(var p: tai): Boolean;
     function OptPass1STM(var p: tai): Boolean;
     function OptPass1STM(var p: tai): Boolean;
-    function OptPass1STR(var p: tai): Boolean;
     function OptPass1MOV(var p: tai): Boolean;
     function OptPass1MOV(var p: tai): Boolean;
     function OptPass1MUL(var p: tai): Boolean;
     function OptPass1MUL(var p: tai): Boolean;
     function OptPass1MVN(var p: tai): Boolean;
     function OptPass1MVN(var p: tai): Boolean;
@@ -834,7 +836,9 @@ Implementation
     var
     var
       hp1: tai;
       hp1: tai;
     begin
     begin
-      Result := False;
+      Result := inherited OptPass1LDR(p);
+      if Result then
+        Exit;
 
 
       { change
       { change
         ldr reg1,ref
         ldr reg1,ref
@@ -1022,7 +1026,9 @@ Implementation
     var
     var
       hp1: tai;
       hp1: tai;
     begin
     begin
-      Result := False;
+      Result := inherited OptPass1STR(p);
+      if Result then
+        Exit;
 
 
       { Common conditions }
       { Common conditions }
       if (taicpu(p).oper[1]^.typ = top_ref) and
       if (taicpu(p).oper[1]^.typ = top_ref) and

+ 226 - 5
compiler/armgen/aoptarm.pas

@@ -26,7 +26,7 @@ Unit aoptarm;
 {$i fpcdefs.inc}
 {$i fpcdefs.inc}
 
 
 { $define DEBUG_PREREGSCHEDULER}
 { $define DEBUG_PREREGSCHEDULER}
-{ $define DEBUG_AOPTCPU}
+{$define DEBUG_AOPTCPU}
 
 
 Interface
 Interface
 
 
@@ -41,12 +41,15 @@ Type
 
 
     function RemoveSuperfluousMove(const p: tai; movp: tai; const optimizer: string): boolean;
     function RemoveSuperfluousMove(const p: tai; movp: tai; const optimizer: string): boolean;
     function RedundantMovProcess(var p: tai; var hp1: tai): boolean;
     function RedundantMovProcess(var p: tai; var hp1: tai): boolean;
-    function GetNextInstructionUsingReg(Current: tai; out Next: tai; reg: TRegister): Boolean;
+    function GetNextInstructionUsingReg(Current: tai; out Next: tai; const reg: TRegister): Boolean;
 
 
     function OptPass1UXTB(var p: tai): Boolean;
     function OptPass1UXTB(var p: tai): Boolean;
     function OptPass1UXTH(var p: tai): Boolean;
     function OptPass1UXTH(var p: tai): Boolean;
     function OptPass1SXTB(var p: tai): Boolean;
     function OptPass1SXTB(var p: tai): Boolean;
     function OptPass1SXTH(var p: tai): Boolean;
     function OptPass1SXTH(var p: tai): Boolean;
+
+    function OptPass1LDR(var p: tai): Boolean; virtual;
+    function OptPass1STR(var p: tai): Boolean; virtual;
     function OptPass1And(var p: tai): Boolean; virtual;
     function OptPass1And(var p: tai): Boolean; virtual;
   End;
   End;
 
 
@@ -69,15 +72,23 @@ Implementation
     systems,
     systems,
     cpuinfo,
     cpuinfo,
     cgobj,procinfo,
     cgobj,procinfo,
-    aasmbase,aasmdata;
+    aasmbase,aasmdata,itcpugas;
 
 
 
 
 {$ifdef DEBUG_AOPTCPU}
 {$ifdef DEBUG_AOPTCPU}
+  const
+    SPeepholeOptimization: shortstring = 'Peephole Optimization: ';
+
   procedure TARMAsmOptimizer.DebugMsg(const s: string;p : tai);
   procedure TARMAsmOptimizer.DebugMsg(const s: string;p : tai);
     begin
     begin
       asml.insertbefore(tai_comment.Create(strpnew(s)), p);
       asml.insertbefore(tai_comment.Create(strpnew(s)), p);
     end;
     end;
 {$else DEBUG_AOPTCPU}
 {$else DEBUG_AOPTCPU}
+  { Empty strings help the optimizer to remove string concatenations that won't
+    ever appear to the user on release builds. [Kit] }
+  const
+    SPeepholeOptimization = '';
+
   procedure TARMAsmOptimizer.DebugMsg(const s: string;p : tai);inline;
   procedure TARMAsmOptimizer.DebugMsg(const s: string;p : tai);inline;
     begin
     begin
     end;
     end;
@@ -179,7 +190,7 @@ Implementation
 
 
 
 
   function TARMAsmOptimizer.GetNextInstructionUsingReg(Current: tai;
   function TARMAsmOptimizer.GetNextInstructionUsingReg(Current: tai;
-    Out Next: tai; reg: TRegister): Boolean;
+    Out Next: tai; const reg: TRegister): Boolean;
     var
     var
       gniResult: Boolean;
       gniResult: Boolean;
     begin
     begin
@@ -395,7 +406,14 @@ Implementation
                   UpdateUsedRegs(TmpUsedRegs, tai(current_hp.Next));
                   UpdateUsedRegs(TmpUsedRegs, tai(current_hp.Next));
                   LDRChange := False;
                   LDRChange := False;
 
 
-                  if (taicpu(next_hp).opcode in [A_LDR,A_STR]) and (taicpu(next_hp).ops = 2) then
+                  if (taicpu(next_hp).opcode in [A_LDR,A_STR]) and (taicpu(next_hp).ops = 2)
+{$ifdef AARCH64}
+                    { If r0 is the zero register, then this sequence of instructions will cause
+                      an access violation, but that's better than an assembler error caused by
+                      changing r0 to xzr inside the reference (Where it's illegal). [Kit] }
+                    and (getsupreg(taicpu(p).oper[1]^.reg) <> RS_XZR)
+{$endif AARCH64}
+                    then
                     begin
                     begin
 
 
                       { Change the registers from r1 to r0 }
                       { Change the registers from r1 to r0 }
@@ -1018,6 +1036,209 @@ Implementation
     end;
     end;
 
 
 
 
+  function TARMAsmOptimizer.OptPass1LDR(var p : tai) : Boolean;
+    var
+      hp1: tai;
+      Reference: TReference;
+      NewOp: TAsmOp;
+    begin
+      Result := False;
+      if (taicpu(p).ops <> 2) or (taicpu(p).condition <> C_None) then
+        Exit;
+
+      Reference := taicpu(p).oper[1]^.ref^;
+      if (Reference.addressmode = AM_OFFSET) and
+        not RegInRef(taicpu(p).oper[0]^.reg, Reference) and
+        { Delay calling GetNextInstruction for as long as possible }
+        GetNextInstruction(p, hp1) and
+        (hp1.typ = ait_instruction) and
+        (taicpu(hp1).condition = C_None) and
+        (taicpu(hp1).oppostfix = taicpu(p).oppostfix) then
+        begin
+          if (taicpu(hp1).opcode = A_STR) and
+            RefsEqual(taicpu(hp1).oper[1]^.ref^, Reference) and
+            (getregtype(taicpu(p).oper[0]^.reg) = getregtype(taicpu(hp1).oper[0]^.reg)) then
+            begin
+              { With:
+                  ldr reg1,[ref]
+                  str reg2,[ref]
+
+                If reg1 = reg2, Remove str
+              }
+              if taicpu(p).oper[0]^.reg = taicpu(hp1).oper[0]^.reg then
+                begin
+                  DebugMsg(SPeepholeOptimization + 'Removed redundant store instruction (load/store -> load/nop)', hp1);
+                  RemoveInstruction(hp1);
+                  Result := True;
+                  Exit;
+                end;
+            end
+          else if (taicpu(hp1).opcode = A_LDR) and
+            RefsEqual(taicpu(hp1).oper[1]^.ref^, Reference) then
+            begin
+              { With:
+                  ldr reg1,[ref]
+                  ldr reg2,[ref]
+
+                If reg1 = reg2, delete the second ldr
+                If reg1 <> reg2, changing the 2nd ldr to a mov might introduce
+                  a dependency, but it will likely open up new optimisations, so
+                  do it for now and handle any new dependencies later.
+              }
+              if taicpu(p).oper[0]^.reg = taicpu(hp1).oper[0]^.reg then
+                begin
+                  DebugMsg(SPeepholeOptimization + 'Removed duplicate load instruction (load/load -> load/nop)', hp1);
+                  RemoveInstruction(hp1);
+                  Result := True;
+                  Exit;
+                end
+              else if
+                (getregtype(taicpu(p).oper[0]^.reg) = R_INTREGISTER) and
+                (getregtype(taicpu(hp1).oper[0]^.reg) = R_INTREGISTER) and
+                (getsubreg(taicpu(p).oper[0]^.reg) = getsubreg(taicpu(hp1).oper[0]^.reg)) then
+                begin
+                  DebugMsg(SPeepholeOptimization + 'Changed second ldr' + oppostfix2str[taicpu(hp1).oppostfix] + ' to mov (load/load -> load/move)', hp1);
+                  taicpu(hp1).opcode := A_MOV;
+                  taicpu(hp1).oppostfix := PF_None;
+                  taicpu(hp1).loadreg(1, taicpu(p).oper[0]^.reg);
+                  AllocRegBetween(taicpu(p).oper[0]^.reg, p, hp1, UsedRegs);
+                  Result := True;
+                  Exit;
+                end;
+            end;
+        end;
+    end;
+
+
+    function TARMAsmOptimizer.OptPass1STR(var p : tai) : Boolean;
+      var
+        hp1: tai;
+        Reference: TReference;
+        SizeMismatch: Boolean;
+        SrcReg: TRegister;
+        NewOp: TAsmOp;
+      begin
+        Result := False;
+        if (taicpu(p).ops <> 2) or (taicpu(p).condition <> C_None) then
+          Exit;
+
+        Reference := taicpu(p).oper[1]^.ref^;
+        if (Reference.addressmode = AM_OFFSET) and
+          not RegInRef(taicpu(p).oper[0]^.reg, Reference) and
+          { Delay calling GetNextInstruction for as long as possible }
+          GetNextInstruction(p, hp1) and
+          (hp1.typ = ait_instruction) and
+          (taicpu(hp1).condition = C_None) and
+          (taicpu(hp1).oppostfix = taicpu(p).oppostfix) then
+
+        if GetNextInstruction(p, hp1) and
+          (hp1.typ = ait_instruction) and
+          (taicpu(hp1).condition = C_None) then
+          begin
+            { Saves constant dereferencing and makes it easier to change the size if necessary }
+            SrcReg := taicpu(p).oper[0]^.reg;
+
+            if (taicpu(hp1).opcode = A_LDR) and
+              RefsEqual(taicpu(hp1).oper[1]^.ref^, Reference) and
+              (
+                (taicpu(hp1).oppostfix = taicpu(p).oppostfix) or
+                ((taicpu(p).oppostfix = PF_B) and (taicpu(hp1).oppostfix = PF_SB)) or
+                ((taicpu(p).oppostfix = PF_H) and (taicpu(hp1).oppostfix = PF_SH))
+{$ifdef AARCH64}
+                or ((taicpu(p).oppostfix = PF_W) and (taicpu(hp1).oppostfix = PF_SW))
+{$endif AARCH64}
+              ) then
+              begin
+                { With:
+                    str reg1,[ref]
+                    ldr reg2,[ref]
+
+                  If reg1 = reg2, Remove ldr.
+                  If reg1 <> reg2, replace ldr with "mov reg2,reg1"
+                }
+
+                if (SrcReg = taicpu(hp1).oper[0]^.reg) and
+                  { e.g. the ldrb in strb/ldrb is not a null operation as it clears the upper 24 bits }
+                  (taicpu(p).oppostfix=PF_None) then
+                  begin
+                    DebugMsg(SPeepholeOptimization + 'Removed redundant load instruction (store/load -> store/nop)', hp1);
+                    RemoveInstruction(hp1);
+                    Result := True;
+                    Exit;
+                  end
+                else if (getregtype(taicpu(p).oper[0]^.reg) = R_INTREGISTER) and
+                  (getregtype(taicpu(hp1).oper[0]^.reg) = R_INTREGISTER) and
+                  (getsubreg(taicpu(p).oper[0]^.reg) = getsubreg(taicpu(hp1).oper[0]^.reg)) then
+                  begin
+                    NewOp:=A_NONE;
+                    if taicpu(hp1).oppostfix=PF_None then
+                      NewOp:=A_MOV
+                    else 
+{$ifndef AARCH64}
+                      if (current_settings.cputype >= cpu_armv6) then
+{$endif not AARCH64}
+                      case taicpu(hp1).oppostfix of
+                        PF_B:
+                          NewOp := A_UXTB;
+                        PF_SB:
+                          NewOp := A_SXTB;
+                        PF_H:
+                          NewOp := A_UXTH;
+                        PF_SH:
+                          NewOp := A_SXTH;
+{$ifdef AARCH64}
+                        PF_SW:
+                          NewOp := A_SXTW;
+                        PF_W:
+                          NewOp := A_MOV;
+{$endif AARCH64}
+                      else
+                        InternalError(2021043001);
+                      end;
+                    if (NewOp<>A_None) then
+                      begin
+                        DebugMsg(SPeepholeOptimization + 'Changed ldr' + oppostfix2str[taicpu(hp1).oppostfix] + ' to ' + gas_op2str[NewOp] + ' (store/load -> store/move)', hp1);
+
+                        taicpu(hp1).oppostfix := PF_None;
+                        taicpu(hp1).opcode := NewOp;
+                        taicpu(hp1).loadreg(1, taicpu(p).oper[0]^.reg);
+                        AllocRegBetween(taicpu(p).oper[0]^.reg, p, hp1, UsedRegs);
+                        Result := True;
+                        Exit;
+                      end;
+                end
+              end
+            else if (taicpu(hp1).opcode = A_STR) and
+              RefsEqual(taicpu(hp1).oper[1]^.ref^, Reference) then
+              begin
+                { With:
+                    str reg1,[ref]
+                    str reg2,[ref]
+
+                  If reg1 <> reg2, delete the first str
+                  IF reg1 = reg2, delete the second str
+                }
+                if SrcReg = taicpu(hp1).oper[0]^.reg then
+                  begin
+                    DebugMsg(SPeepholeOptimization + 'Removed duplicate store instruction (store/store -> store/nop)', hp1);
+                    RemoveInstruction(hp1);
+                    Result := True;
+                    Exit;
+                  end
+                else if
+                  { Registers same byte size? }
+                  (tcgsize2size[reg_cgsize(taicpu(p).oper[0]^.reg)] = tcgsize2size[reg_cgsize(taicpu(hp1).oper[0]^.reg)]) then
+                  begin
+                    DebugMsg(SPeepholeOptimization + 'Removed dominated store instruction (store/store -> nop/store)', p);
+                    RemoveCurrentP(p, hp1);
+                    Result := True;
+                    Exit;
+                  end;
+              end;
+          end;
+      end;
+
+
   function TARMAsmOptimizer.OptPass1And(var p : tai) : Boolean;
   function TARMAsmOptimizer.OptPass1And(var p : tai) : Boolean;
     var
     var
       hp1, hp2: tai;
       hp1, hp2: tai;

+ 1 - 1
compiler/globals.pas

@@ -416,7 +416,7 @@ interface
 {$if defined(m68k)}
 {$if defined(m68k)}
        { Sinclair QL specific }
        { Sinclair QL specific }
        sinclairql_metadata_format: string[4] = 'QHDR';
        sinclairql_metadata_format: string[4] = 'QHDR';
-       sinclairql_vlink_experimental: boolean = false; { temporary }
+       sinclairql_vlink_experimental: boolean = true; { temporary }
 {$endif defined(m68k)}
 {$endif defined(m68k)}
 
 
        { default name of the C-style "main" procedure of the library/program }
        { default name of the C-style "main" procedure of the library/program }

+ 1 - 1
compiler/m68k/cpupara.pas

@@ -83,7 +83,7 @@ unit cpupara;
       begin
       begin
         { d0 and d1 are considered volatile }
         { d0 and d1 are considered volatile }
         Result:=VOLATILE_INTREGISTERS;
         Result:=VOLATILE_INTREGISTERS;
-        if (target_info.system in [system_m68k_palmos]) or
+        if (target_info.system in [system_m68k_palmos,system_m68k_macosclassic]) or
            ((target_info.system in [system_m68k_atari]) and (calloption in [pocall_syscall])) then
            ((target_info.system in [system_m68k_atari]) and (calloption in [pocall_syscall])) then
           include(result,RS_D2);
           include(result,RS_D2);
       end;
       end;

+ 14 - 0
compiler/msg/errore.msg

@@ -3908,10 +3908,23 @@ F*0*_Only options valid for the default or selected platform are listed.
 6*2Amot_Standard Motorola assembler
 6*2Amot_Standard Motorola assembler
 6*2Avasm_Use vasm to assemble
 6*2Avasm_Use vasm to assemble
 A*2Aas_Assemble using GNU AS
 A*2Aas_Assemble using GNU AS
+A*2Aas-darwin_Assemble using GNU AS for Darwin targets
+A*2Aclang_Assemble using clang
+A*2Aelf_Assemble using internal ELF writer
+a*2Aas_Assemble using GNU AS
+a*2Aclang_Assemble using clang for darwin/ios targets
+a*2Aas-clang_Assemble using clang for other targets 
 P*2Aas_Assemble using GNU AS
 P*2Aas_Assemble using GNU AS
 S*2Aas_Assemble using GNU AS
 S*2Aas_Assemble using GNU AS
+s*2Aas_Assemble using GNU AS
+v*2Aas_Assemble using GNU AS
+W*2Abinaryen_Assemble using GNU AS for wasm32 (wasm-as)
+W*2Allvm-mc_Assemble using llvm-mc
+W*2Awabt_Assemble using wasa
+x*2Aas_Assemble using GNU AS
 Z*2Asdcc-sdasz80_Assemble using SDCC-SDASZ80
 Z*2Asdcc-sdasz80_Assemble using SDCC-SDASZ80
 Z*2Az80asm_Assemble using z80asm
 Z*2Az80asm_Assemble using z80asm
+Z*2Avasm_Assemble using Vasm
 # Used only internally by IDE
 # Used only internally by IDE
 **1b_Generate browser info
 **1b_Generate browser info
 **2bl_Generate local symbol info
 **2bl_Generate local symbol info
@@ -4183,6 +4196,7 @@ A*2Twince_Windows CE
 # aarch64 targets
 # aarch64 targets
 a*2Tandroid_Android
 a*2Tandroid_Android
 a*2Tdarwin_Darwin/Mac OS X
 a*2Tdarwin_Darwin/Mac OS X
+a*2Tfreebsd_FreeBSD
 a*2Tios_iOS
 a*2Tios_iOS
 a*2Tlinux_Linux
 a*2Tlinux_Linux
 a*2Twin64_Windows 64
 a*2Twin64_Windows 64

+ 1 - 1
compiler/msgidx.inc

@@ -1139,7 +1139,7 @@ const
   option_info=11024;
   option_info=11024;
   option_help_pages=11025;
   option_help_pages=11025;
 
 
-  MsgTxtSize = 87287;
+  MsgTxtSize = 87808;
 
 
   MsgIdxMax : array[1..20] of longint=(
   MsgIdxMax : array[1..20] of longint=(
     28,107,361,131,99,63,146,36,223,68,
     28,107,361,131,99,63,146,36,223,68,

+ 165 - 151
compiler/msgtxt.inc

@@ -1,8 +1,8 @@
 const msgtxt_codepage=20127;
 const msgtxt_codepage=20127;
 {$ifdef Delphi}
 {$ifdef Delphi}
-const msgtxt : array[0..000363] of string[240]=(
+const msgtxt : array[0..000365] of string[240]=(
 {$else Delphi}
 {$else Delphi}
-const msgtxt : array[0..000363,1..240] of char=(
+const msgtxt : array[0..000365,1..240] of char=(
 {$endif Delphi}
 {$endif Delphi}
   '01000_T_Compiler: $1'#000+
   '01000_T_Compiler: $1'#000+
   '01001_D_Compiler OS: $1'#000+
   '01001_D_Compiler OS: $1'#000+
@@ -1507,272 +1507,286 @@ const msgtxt : array[0..000363,1..240] of char=(
   '6*2Amot_Standard Motorola assembler'#010+
   '6*2Amot_Standard Motorola assembler'#010+
   '6*2Avasm_Use vasm to assemble'#010+
   '6*2Avasm_Use vasm to assemble'#010+
   'A*2Aas_Assemble using GNU AS'#010+
   'A*2Aas_Assemble using GNU AS'#010+
+  'A*2Aas-darwin_Assemble using GNU AS for Darwin targets'#010+
+  'A*2Aclang_As','semble using clang'#010+
+  'A*2Aelf_Assemble using internal ELF writer'#010+
+  'a*2Aas_Assemble using GNU AS'#010+
+  'a*2Aclang_Assemble using clang for darwin/ios targets'#010+
+  'a*2Aas-clang_Assemble using clang for other targets '#010+
   'P*2Aas_Assemble using GNU AS'#010+
   'P*2Aas_Assemble using GNU AS'#010+
-  'S*2Aas_Assemble using GNU AS'#010+
-  'Z*2Asdcc-','sdasz80_Assemble using SDCC-SDASZ80'#010+
+  'S*2Aas_Assemb','le using GNU AS'#010+
+  's*2Aas_Assemble using GNU AS'#010+
+  'v*2Aas_Assemble using GNU AS'#010+
+  'W*2Abinaryen_Assemble using GNU AS for wasm32 (wasm-as)'#010+
+  'W*2Allvm-mc_Assemble using llvm-mc'#010+
+  'W*2Awabt_Assemble using wasa'#010+
+  'x*2Aas_Assemble using GNU AS'#010+
+  'Z*2Asdcc-sdasz80_','Assemble using SDCC-SDASZ80'#010+
   'Z*2Az80asm_Assemble using z80asm'#010+
   'Z*2Az80asm_Assemble using z80asm'#010+
+  'Z*2Avasm_Assemble using Vasm'#010+
   '**1b_Generate browser info'#010+
   '**1b_Generate browser info'#010+
   '**2bl_Generate local symbol info'#010+
   '**2bl_Generate local symbol info'#010+
   '**1B_Build all modules'#010+
   '**1B_Build all modules'#010+
   '**1C<x>_Code generation options:'#010+
   '**1C<x>_Code generation options:'#010+
-  '**2C3_Turn on ieee error checking for constants'#010+
-  '**2Ca<x','>_Select ABI; see fpc -i or fpc -ia for possible values'#010+
+  '**2C3_Turn on ieee error checking ','for constants'#010+
+  '**2Ca<x>_Select ABI; see fpc -i or fpc -ia for possible values'#010+
   '**2Cb_Generate code for a big-endian variant of the target architectur'+
   '**2Cb_Generate code for a big-endian variant of the target architectur'+
   'e'#010+
   'e'#010+
   '**2Cc<x>_Set default calling convention to <x>'#010+
   '**2Cc<x>_Set default calling convention to <x>'#010+
-  '**2CD_Create also dynamic library (not supported)'#010+
-  '**2Ce_Compilati','on with emulated floating point opcodes'#010+
+  '**2CD_Create also dynamic library (not suppo','rted)'#010+
+  '**2Ce_Compilation with emulated floating point opcodes'#010+
   '**2CE_Generate FPU code which can raise exceptions'#010+
   '**2CE_Generate FPU code which can raise exceptions'#010+
   '**2Cf<x>_Select fpu instruction set to use; see fpc -i or fpc -if for '+
   '**2Cf<x>_Select fpu instruction set to use; see fpc -i or fpc -if for '+
   'possible values'#010+
   'possible values'#010+
-  '**2CF<x>_Minimal floating point constant precision (default, 32',', 64)'+
+  '**2CF<x>_Minimal floating point constant p','recision (default, 32, 64)'+
   #010+
   #010+
   '**2Cg_Generate PIC code'#010+
   '**2Cg_Generate PIC code'#010+
   '**2Ch<n>[,m]_<n> bytes min heap size (between 1023 and 67107840) and o'+
   '**2Ch<n>[,m]_<n> bytes min heap size (between 1023 and 67107840) and o'+
   'ptionally [m] max heap size'#010+
   'ptionally [m] max heap size'#010+
   '**2Ci_IO-checking'#010+
   '**2Ci_IO-checking'#010+
   'A*2CI<x>_Select instruction set on ARM: ARM or THUMB'#010+
   'A*2CI<x>_Select instruction set on ARM: ARM or THUMB'#010+
-  'L*2Cl<x>_LLVM code generation options'#010+
-  'L*3','Clflto_Enable Link-time optimisation (needed both when compiling '+
-  'units and programs/libraries)'#010+
+  'L*2Cl<x>_LLVM code g','eneration options'#010+
+  'L*3Clflto_Enable Link-time optimisation (needed both when compiling un'+
+  'its and programs/libraries)'#010+
   'L*3Clfltonosystem_Disable LTO for the system unit (needed with at leas'+
   'L*3Clfltonosystem_Disable LTO for the system unit (needed with at leas'+
   't Xcode 10.2 and earlier due to linker bugs)'#010+
   't Xcode 10.2 and earlier due to linker bugs)'#010+
-  'L*3Clv<x>_LLVM target version:',' Xcode-10.1, 7.0, 8.0, .., 10.0'#010+
+  'L*3Clv<x>','_LLVM target version: Xcode-10.1, 7.0, 8.0, .., 10.0'#010+
   '**2Cn_Omit linking stage'#010+
   '**2Cn_Omit linking stage'#010+
   'P*2CN_Generate nil-pointer checks (AIX-only)'#010+
   'P*2CN_Generate nil-pointer checks (AIX-only)'#010+
   '**2Co_Check overflow of integer operations'#010+
   '**2Co_Check overflow of integer operations'#010+
   '**2CO_Check for possible overflow of integer operations'#010+
   '**2CO_Check for possible overflow of integer operations'#010+
-  '**2Cp<x>_Select instruction set; see fp','c -i or fpc -ic for possible '+
+  '**2Cp<x>_Select in','struction set; see fpc -i or fpc -ic for possible '+
   'values'#010+
   'values'#010+
   '**2CP<x>=<y>_ packing settings'#010+
   '**2CP<x>=<y>_ packing settings'#010+
   '**3CPPACKSET=<y>_ <y> set allocation: 0, 1 or DEFAULT or NORMAL, 2, 4 '+
   '**3CPPACKSET=<y>_ <y> set allocation: 0, 1 or DEFAULT or NORMAL, 2, 4 '+
   'and 8'#010+
   'and 8'#010+
   '**3CPPACKENUM=<y>_ <y> enum packing: 0, 1, 2 and 4 or DEFAULT or NORMA'+
   '**3CPPACKENUM=<y>_ <y> enum packing: 0, 1, 2 and 4 or DEFAULT or NORMA'+
   'L'#010+
   'L'#010+
-  '**3CPPACKRECORD=<y>_ <y> ','record packing: 0 or DEFAULT or NORMAL, 1, '+
+  '**3C','PPACKRECORD=<y>_ <y> record packing: 0 or DEFAULT or NORMAL, 1, '+
   '2, 4, 8, 16 and 32'#010+
   '2, 4, 8, 16 and 32'#010+
   '**2Cr_Range checking'#010+
   '**2Cr_Range checking'#010+
   '**2CR_Verify object method call validity'#010+
   '**2CR_Verify object method call validity'#010+
   '**2Cs<n>_Set stack checking size to <n>'#010+
   '**2Cs<n>_Set stack checking size to <n>'#010+
   '**2Ct_Stack checking (for testing only, see manual)'#010+
   '**2Ct_Stack checking (for testing only, see manual)'#010+
-  '8*2CT<x>_Target-specific',' code generation options'#010+
+  '8*2','CT<x>_Target-specific code generation options'#010+
   '3*2CT<x>_Target-specific code generation options'#010+
   '3*2CT<x>_Target-specific code generation options'#010+
   '4*2CT<x>_Target-specific code generation options'#010+
   '4*2CT<x>_Target-specific code generation options'#010+
   'p*2CT<x>_Target-specific code generation options'#010+
   'p*2CT<x>_Target-specific code generation options'#010+
-  'P*2CT<x>_Target-specific code generation options'#010+
-  'J*2CT<x>_Target-spe','cific code generation options'#010+
+  'P*2CT<x>_Target-specific code generation option','s'#010+
+  'J*2CT<x>_Target-specific code generation options'#010+
   'A*2CT<x>_Target-specific code generation options'#010+
   'A*2CT<x>_Target-specific code generation options'#010+
   'p*3CTsmalltoc_ Generate smaller TOCs at the expense of execution speed'+
   'p*3CTsmalltoc_ Generate smaller TOCs at the expense of execution speed'+
   ' (AIX)'#010+
   ' (AIX)'#010+
-  'P*3CTsmalltoc_ Generate smaller TOCs at the expense of execution speed'+
-  ' (AIX)'#010+
-  'J*3CTau','togetterprefix=X_  Automatically create getters for propertie'+
-  's with prefix X (empty string disables)'#010+
+  'P*3CTsmalltoc_ Generate smaller TOCs at the expense of executio','n spe'+
+  'ed (AIX)'#010+
+  'J*3CTautogetterprefix=X_  Automatically create getters for properties '+
+  'with prefix X (empty string disables)'#010+
   'J*3CTautosetterprefix=X_  Automatically create setters for properties '+
   'J*3CTautosetterprefix=X_  Automatically create setters for properties '+
   'with prefix X (empty string disables)'#010+
   'with prefix X (empty string disables)'#010+
-  '8*3CTcld_                 Emit ','a CLD instruction before using the x8'+
+  '8*3CTcld_ ','                Emit a CLD instruction before using the x8'+
   '6 string instructions'#010+
   '6 string instructions'#010+
   '3*3CTcld_                 Emit a CLD instruction before using the x86 '+
   '3*3CTcld_                 Emit a CLD instruction before using the x86 '+
   'string instructions'#010+
   'string instructions'#010+
-  '4*3CTcld_                 Emit a CLD instruction before using the x86 '+
+  '4*3CTcld_                 Emit a CLD instruction before using the x86 ',
   'string instructions'#010+
   'string instructions'#010+
-  '8','*3CTfarprocspushoddbp_       Increment BP before pushing it in the '+
-  'prologue of far functions'#010+
+  '8*3CTfarprocspushoddbp_       Increment BP before pushing it in the pr'+
+  'ologue of far functions'#010+
   'J*3CTcompactintarrayinit_ Generate smaller (but potentially slower) co'+
   'J*3CTcompactintarrayinit_ Generate smaller (but potentially slower) co'+
   'de for initializing integer array constants'#010+
   'de for initializing integer array constants'#010+
-  'J*3CTenumfieldinit_       Initial','ize enumeration fields in construct'+
+  'J*3CTenumfie','ldinit_       Initialize enumeration fields in construct'+
   'ors to enumtype(0), after calling inherited constructors'#010+
   'ors to enumtype(0), after calling inherited constructors'#010+
   'J*3CTinitlocals_          Initialize local variables that trigger a JV'+
   'J*3CTinitlocals_          Initialize local variables that trigger a JV'+
-  'M bytecode verification error if used uninitialized (slows down code)'#010+
-  'J*3CTlow','ercaseprocstart_  Lowercase the first character of procedure'+
-  '/function/method names'#010+
+  'M bytecode verification error if used uninitialized (slow','s down code'+
+  ')'#010+
+  'J*3CTlowercaseprocstart_  Lowercase the first character of procedure/f'+
+  'unction/method names'#010+
   'A*3CTthumbinterworking_ Generate Thumb interworking-safe code if possi'+
   'A*3CTthumbinterworking_ Generate Thumb interworking-safe code if possi'+
   'ble'#010+
   'ble'#010+
   'J*2Cv_Var/out parameter copy-out checking'#010+
   'J*2Cv_Var/out parameter copy-out checking'#010+
-  'A*2CV<x>_Set section threadvar model to <','x>'#010+
+  'A*2CV<x>_Set section',' threadvar model to <x>'#010+
   '**2CX_Create also smartlinked library'#010+
   '**2CX_Create also smartlinked library'#010+
   '**1d<x>_Defines the symbol <x>'#010+
   '**1d<x>_Defines the symbol <x>'#010+
   '**1D_Generate a DEF file'#010+
   '**1D_Generate a DEF file'#010+
   '**2DD<x>_Set the date string returned by %DATE% to x, it is not checke'+
   '**2DD<x>_Set the date string returned by %DATE% to x, it is not checke'+
   'd for being a valid date string'#010+
   'd for being a valid date string'#010+
-  '**2Dd<x>_Set description to <x>'#010+
-  '**2DT<x>_','Set the time string returned by %TIME% to x, it is not chec'+
-  'ked for being a valid time string'#010+
+  '**2Dd<x>_Set descrip','tion to <x>'#010+
+  '**2DT<x>_Set the time string returned by %TIME% to x, it is not checke'+
+  'd for being a valid time string'#010+
   '**2Dv<x>_Set DLL version to <x>'#010+
   '**2Dv<x>_Set DLL version to <x>'#010+
   '*O2Dw_PM application'#010+
   '*O2Dw_PM application'#010+
   '**1e<x>_Set path to executable'#010+
   '**1e<x>_Set path to executable'#010+
   '**1E_Same as -Cn'#010+
   '**1E_Same as -Cn'#010+
   '**1fPIC_Same as -Cg'#010+
   '**1fPIC_Same as -Cg'#010+
-  '**1F<x>_Set file names and',' paths:'#010+
+  '**1F<','x>_Set file names and paths:'#010+
   '**2Fa<x>[,y]_(for a program) load units <x> and [y] before uses is par'+
   '**2Fa<x>[,y]_(for a program) load units <x> and [y] before uses is par'+
   'sed'#010+
   'sed'#010+
   '**2Fc<x>_Set input codepage to <x>'#010+
   '**2Fc<x>_Set input codepage to <x>'#010+
   '**2FC<x>_Set RC compiler binary name to <x>'#010+
   '**2FC<x>_Set RC compiler binary name to <x>'#010+
   '**2Fd_Disable the compiler'#039's internal directory cache'#010+
   '**2Fd_Disable the compiler'#039's internal directory cache'#010+
-  '**2FD<x>_Set the director','y where to search for compiler utilities'#010+
+  '**2F','D<x>_Set the directory where to search for compiler utilities'#010+
   '**2Fe<x>_Redirect error output to <x>'#010+
   '**2Fe<x>_Redirect error output to <x>'#010+
   '**2FE<x>_Set exe/unit output path to <x>'#010+
   '**2FE<x>_Set exe/unit output path to <x>'#010+
   '**2Ff<x>_Add <x> to framework path (Darwin only), or set IDF path to <'+
   '**2Ff<x>_Add <x> to framework path (Darwin only), or set IDF path to <'+
   'x> (Xtensa-FreeRTOS)'#010+
   'x> (Xtensa-FreeRTOS)'#010+
-  '**2FF_Use fpcres as RC to RES',' compiler instead of windres or gorc'#010+
+  '**2FF_Us','e fpcres as RC to RES compiler instead of windres or gorc'#010+
   '**2Fi<x>_Add <x> to include path'#010+
   '**2Fi<x>_Add <x> to include path'#010+
   '**2Fl<x>_Add <x> to library path'#010+
   '**2Fl<x>_Add <x> to library path'#010+
   '**2FL<x>_Use <x> as dynamic linker'#010+
   '**2FL<x>_Use <x> as dynamic linker'#010+
   '**2Fm<x>_Load unicode conversion table from <x>.txt in the compiler di'+
   '**2Fm<x>_Load unicode conversion table from <x>.txt in the compiler di'+
   'r'#010+
   'r'#010+
-  '**2FM<x>_Set the directory whe','re to search for unicode binary files'#010+
+  '**2FM<x>_','Set the directory where to search for unicode binary files'#010+
   '**2FN<x>_Add <x> to list of default unit scopes (namespaces)'#010+
   '**2FN<x>_Add <x> to list of default unit scopes (namespaces)'#010+
   '**2Fo<x>_Add <x> to object path'#010+
   '**2Fo<x>_Add <x> to object path'#010+
   '**2Fr<x>_Load error message file <x>'#010+
   '**2Fr<x>_Load error message file <x>'#010+
   '**2FR<x>_Set resource (.res) linker to <x>'#010+
   '**2FR<x>_Set resource (.res) linker to <x>'#010+
-  '**2Fu<x>_Add <x> to unit path',#010+
+  '**2Fu<x>','_Add <x> to unit path'#010+
   '**2FU<x>_Set unit output path to <x>, overrides -FE'#010+
   '**2FU<x>_Set unit output path to <x>, overrides -FE'#010+
   '**2FW<x>_Store generated whole-program optimization feedback in <x>'#010+
   '**2FW<x>_Store generated whole-program optimization feedback in <x>'#010+
   '**2Fw<x>_Load previously stored whole-program optimization feedback fr'+
   '**2Fw<x>_Load previously stored whole-program optimization feedback fr'+
   'om <x>'#010+
   'om <x>'#010+
-  '*g1g_Generate debug information (default f','ormat for target)'#010+
+  '*g1g_Generate debug i','nformation (default format for target)'#010+
   '*g2gc_Generate checks for pointers (experimental, only available on so'+
   '*g2gc_Generate checks for pointers (experimental, only available on so'+
   'me targets, might generate false positive)'#010+
   'me targets, might generate false positive)'#010+
   '*g2gh_Use heaptrace unit (for memory leak/corruption debugging)'#010+
   '*g2gh_Use heaptrace unit (for memory leak/corruption debugging)'#010+
-  '*g2gl_Use line info unit (show more info with',' backtraces)'#010+
+  '*g2gl_Use line info unit',' (show more info with backtraces)'#010+
   '*g2gm_Generate Microsoft CodeView debug information (experimental)'#010+
   '*g2gm_Generate Microsoft CodeView debug information (experimental)'#010+
   '*g2go<x>_Set debug information options'#010+
   '*g2go<x>_Set debug information options'#010+
   '*g3godwarfsets_ Enable DWARF '#039'set'#039' type debug information (bre'+
   '*g3godwarfsets_ Enable DWARF '#039'set'#039' type debug information (bre'+
   'aks gdb < 6.5)'#010+
   'aks gdb < 6.5)'#010+
-  '*g3gostabsabsincludes_ Store absolute/full i','nclude file paths in Sta'+
+  '*g3gostabsabsincludes_ ','Store absolute/full include file paths in Sta'+
   'bs'#010+
   'bs'#010+
   '*g3godwarfmethodclassprefix_ Prefix method names in DWARF with class n'+
   '*g3godwarfmethodclassprefix_ Prefix method names in DWARF with class n'+
   'ame'#010+
   'ame'#010+
   '*g3godwarfcpp_ Simulate C++ debug information in DWARF'#010+
   '*g3godwarfcpp_ Simulate C++ debug information in DWARF'#010+
-  '*g3godwarfomflinnum_ Generate line number information in OMF LINNUM re'+
-  'cords in MS LI','NK format in addition to the DWARF debug information ('+
+  '*g3godwarfomflinnum_ Generate line number information in OMF LI','NNUM '+
+  'records in MS LINK format in addition to the DWARF debug information ('+
   'Open Watcom Debugger/Linker compatibility)'#010+
   'Open Watcom Debugger/Linker compatibility)'#010+
   '*g2gp_Preserve case in stabs symbol names'#010+
   '*g2gp_Preserve case in stabs symbol names'#010+
   '*g2gs_Generate Stabs debug information'#010+
   '*g2gs_Generate Stabs debug information'#010+
-  '*g2gt_Trash local variables (to detect uninitialized uses; mul','tiple '+
+  '*g2gt_Trash local variables (to detect un','initialized uses; multiple '+
   #039't'#039' changes the trashing value)'#010+
   #039't'#039' changes the trashing value)'#010+
   '*g2gv_Generates programs traceable with Valgrind'#010+
   '*g2gv_Generates programs traceable with Valgrind'#010+
   '*g2gw_Generate DWARFv2 debug information (same as -gw2)'#010+
   '*g2gw_Generate DWARFv2 debug information (same as -gw2)'#010+
   '*g2gw2_Generate DWARFv2 debug information'#010+
   '*g2gw2_Generate DWARFv2 debug information'#010+
-  '*g2gw3_Generate DWARFv3 debug information'#010+
-  '*g2gw4_Genera','te DWARFv4 debug information (experimental)'#010+
+  '*g2gw3_Generate DWARFv3 debug info','rmation'#010+
+  '*g2gw4_Generate DWARFv4 debug information (experimental)'#010+
   '**1i_Information'#010+
   '**1i_Information'#010+
   '**2iD_Return compiler date'#010+
   '**2iD_Return compiler date'#010+
   '**2iSO_Return compiler OS'#010+
   '**2iSO_Return compiler OS'#010+
   '**2iSP_Return compiler host processor'#010+
   '**2iSP_Return compiler host processor'#010+
   '**2iTO_Return target OS'#010+
   '**2iTO_Return target OS'#010+
   '**2iTP_Return target processor'#010+
   '**2iTP_Return target processor'#010+
-  '**2iV_Return short compiler versi','on'#010+
+  '**2iV_Return',' short compiler version'#010+
   '**2iW_Return full compiler version'#010+
   '**2iW_Return full compiler version'#010+
   '**2ia_Return list of supported ABI targets'#010+
   '**2ia_Return list of supported ABI targets'#010+
   '**2ib_Return the used code generation backend type'#010+
   '**2ib_Return the used code generation backend type'#010+
   '**2ic_Return list of supported CPU instruction sets'#010+
   '**2ic_Return list of supported CPU instruction sets'#010+
-  '**2if_Return list of supported FPU instruction sets'#010+
-  '**2i','i_Return list of supported inline assembler modes'#010+
+  '**2if_Return list of supported FPU ','instruction sets'#010+
+  '**2ii_Return list of supported inline assembler modes'#010+
   '**2im_Return list of supported modeswitches'#010+
   '**2im_Return list of supported modeswitches'#010+
   '**2io_Return list of supported optimizations'#010+
   '**2io_Return list of supported optimizations'#010+
   '**2ir_Return list of recognized compiler and RTL features'#010+
   '**2ir_Return list of recognized compiler and RTL features'#010+
-  '**2it_Return list of supported targets'#010+
-  '**2i','u_Return list of supported microcontroller types'#010+
+  '**2it_Return list of s','upported targets'#010+
+  '**2iu_Return list of supported microcontroller types'#010+
   '**2iw_Return list of supported whole program optimizations'#010+
   '**2iw_Return list of supported whole program optimizations'#010+
   '**1I<x>_Add <x> to include path'#010+
   '**1I<x>_Add <x> to include path'#010+
   '**1k<x>_Pass <x> to the linker'#010+
   '**1k<x>_Pass <x> to the linker'#010+
   '**1l_Write logo'#010+
   '**1l_Write logo'#010+
-  '**1M<x>_Set language mode to <x> / enable modeswitch ','<x> (see option'+
+  '**1M<x>_Set language mode to <x>',' / enable modeswitch <x> (see option'+
   ' -im)'#010+
   ' -im)'#010+
   '**2Mfpc_Free Pascal dialect (default)'#010+
   '**2Mfpc_Free Pascal dialect (default)'#010+
   '**2Mobjfpc_FPC mode with Object Pascal support'#010+
   '**2Mobjfpc_FPC mode with Object Pascal support'#010+
   '**2Mdelphi_Delphi 7 compatibility mode'#010+
   '**2Mdelphi_Delphi 7 compatibility mode'#010+
   '**2Mtp_TP/BP 7.0 compatibility mode'#010+
   '**2Mtp_TP/BP 7.0 compatibility mode'#010+
-  '**2Mmacpas_Macintosh Pascal dialects compatibility mode'#010+
-  '**2','Miso_ISO 7185 mode'#010+
+  '**2Mmacpas_Macintosh Pascal dialects c','ompatibility mode'#010+
+  '**2Miso_ISO 7185 mode'#010+
   '**2Mextendedpascal_ISO 10206 mode'#010+
   '**2Mextendedpascal_ISO 10206 mode'#010+
   '**2Mdelphiunicode_Delphi 2009 and later compatibility mode'#010+
   '**2Mdelphiunicode_Delphi 2009 and later compatibility mode'#010+
   '**2*_Each mode (as listed above) enables its default set of modeswitch'+
   '**2*_Each mode (as listed above) enables its default set of modeswitch'+
   'es.'#010+
   'es.'#010+
-  '**2*_Other modeswitches are disabled and need to be en','abled one by a'+
+  '**2*_Other modeswitches are disab','led and need to be enabled one by a'+
   'nother.'#010+
   'nother.'#010+
   '**1M<x>-_Disable modeswitch <x> (see option -im)'#010+
   '**1M<x>-_Disable modeswitch <x> (see option -im)'#010+
   '**1n_Do not read the default config files'#010+
   '**1n_Do not read the default config files'#010+
   '**1o<x>_Change the name of the executable produced to <x>'#010+
   '**1o<x>_Change the name of the executable produced to <x>'#010+
   '**1O<x>_Optimizations:'#010+
   '**1O<x>_Optimizations:'#010+
-  '**2O-_Disable optimizations'#010+
-  '**2O1_Level 1 opti','mizations (quick and debugger friendly)'#010+
+  '**2O-_Disable optimizatio','ns'#010+
+  '**2O1_Level 1 optimizations (quick and debugger friendly)'#010+
   '**2O2_Level 2 optimizations (-O1 + quick optimizations)'#010+
   '**2O2_Level 2 optimizations (-O1 + quick optimizations)'#010+
   '**2O3_Level 3 optimizations (-O2 + slow optimizations)'#010+
   '**2O3_Level 3 optimizations (-O2 + slow optimizations)'#010+
-  '**2O4_Level 4 optimizations (-O3 + optimizations which might have unex'+
-  'pected side effects',')'#010+
+  '**2O4_Level 4 optimizations (-O3 + optimizations which might have un','e'+
+  'xpected side effects)'#010+
   '**2Oa<x>=<y>_Set alignment'#010+
   '**2Oa<x>=<y>_Set alignment'#010+
   '**2Oo[NO]<x>_Enable or disable optimizations; see fpc -i or fpc -io fo'+
   '**2Oo[NO]<x>_Enable or disable optimizations; see fpc -i or fpc -io fo'+
   'r possible values'#010+
   'r possible values'#010+
   '**2Op<x>_Set target cpu for optimizing; see fpc -i or fpc -ic for poss'+
   '**2Op<x>_Set target cpu for optimizing; see fpc -i or fpc -ic for poss'+
   'ible values'#010+
   'ible values'#010+
-  '**2OW<x>_Generate whole-program optimizat','ion feedback for optimizati'+
+  '**2OW<x>_Generate wh','ole-program optimization feedback for optimizati'+
   'on <x>; see fpc -i or fpc -iw for possible values'#010+
   'on <x>; see fpc -i or fpc -iw for possible values'#010+
   '**2Ow<x>_Perform whole-program optimization <x>; see fpc -i or fpc -iw'+
   '**2Ow<x>_Perform whole-program optimization <x>; see fpc -i or fpc -iw'+
   ' for possible values'#010+
   ' for possible values'#010+
   '**2Os_Optimize for size rather than speed'#010+
   '**2Os_Optimize for size rather than speed'#010+
-  '**1pg_Generate profile code fo','r gprof (defines FPC_PROFILE)'#010+
+  '**1pg_Gen','erate profile code for gprof (defines FPC_PROFILE)'#010+
   'F*1P<x>_Target CPU / compiler related options:'#010+
   'F*1P<x>_Target CPU / compiler related options:'#010+
   'F*2PB_Show default compiler binary'#010+
   'F*2PB_Show default compiler binary'#010+
   'F*2PP_Show default target cpu'#010+
   'F*2PP_Show default target cpu'#010+
   'F*2P<x>_Set target CPU (aarch64,arm,avr,i386,i8086,jvm,m68k,mips,mipse'+
   'F*2P<x>_Set target CPU (aarch64,arm,avr,i386,i8086,jvm,m68k,mips,mipse'+
-  'l,powerpc,powerpc64,sparc,x8','6_64)'#010+
+  'l,power','pc,powerpc64,sparc,x86_64)'#010+
   '**1R<x>_Assembler reading style:'#010+
   '**1R<x>_Assembler reading style:'#010+
   '**2Rdefault_Use default assembler for target'#010+
   '**2Rdefault_Use default assembler for target'#010+
   '3*2Ratt_Read AT&T style assembler'#010+
   '3*2Ratt_Read AT&T style assembler'#010+
   '3*2Rintel_Read Intel style assembler'#010+
   '3*2Rintel_Read Intel style assembler'#010+
   '4*2Ratt_Read AT&T style assembler'#010+
   '4*2Ratt_Read AT&T style assembler'#010+
-  '4*2Rintel_Read Intel style assembler'#010+
-  '8*2Ratt_Read A','T&T style assembler'#010+
+  '4*2Rintel_Read Intel style ass','embler'#010+
+  '8*2Ratt_Read AT&T style assembler'#010+
   '8*2Rintel_Read Intel style assembler'#010+
   '8*2Rintel_Read Intel style assembler'#010+
   '6*2RMOT_Read Motorola style assembler'#010+
   '6*2RMOT_Read Motorola style assembler'#010+
   '**1S<x>_Syntax options:'#010+
   '**1S<x>_Syntax options:'#010+
   '**2S2_Same as -Mobjfpc'#010+
   '**2S2_Same as -Mobjfpc'#010+
   '**2Sc_Support operators like C (*=,+=,/= and -=)'#010+
   '**2Sc_Support operators like C (*=,+=,/= and -=)'#010+
   '**2Sa_Turn on assertions'#010+
   '**2Sa_Turn on assertions'#010+
-  '**2Sd_Same as -Mdelphi'#010+
-  '*','*2Se<x>_Error options. <x> is a combination of the following:'#010+
+  '**2','Sd_Same as -Mdelphi'#010+
+  '**2Se<x>_Error options. <x> is a combination of the following:'#010+
   '**3*_<n> : Compiler halts after the <n> errors (default is 1)'#010+
   '**3*_<n> : Compiler halts after the <n> errors (default is 1)'#010+
   '**3*_w : Compiler also halts after warnings'#010+
   '**3*_w : Compiler also halts after warnings'#010+
   '**3*_n : Compiler also halts after notes'#010+
   '**3*_n : Compiler also halts after notes'#010+
-  '**3*_h : Compiler also halts af','ter hints'#010+
+  '**3*_h : C','ompiler also halts after hints'#010+
   '**2Sf_Enable certain features in compiler and RTL; see fpc -i or fpc -'+
   '**2Sf_Enable certain features in compiler and RTL; see fpc -i or fpc -'+
   'ir for possible values)'#010+
   'ir for possible values)'#010+
   '**2Sg_Enable LABEL and GOTO (default in -Mtp and -Mdelphi)'#010+
   '**2Sg_Enable LABEL and GOTO (default in -Mtp and -Mdelphi)'#010+
-  '**2Sh_Use reference counted strings (ansistring by default) instead of'+
-  ' shorts','trings'#010+
+  '**2Sh_Use reference counted strings (ansistring by defau','lt) instead '+
+  'of shortstrings'#010+
   '**2Si_Turn on inlining of procedures/functions declared as "inline"'#010+
   '**2Si_Turn on inlining of procedures/functions declared as "inline"'#010+
   '**2Sj_Allows typed constants to be writeable (default in all modes)'#010+
   '**2Sj_Allows typed constants to be writeable (default in all modes)'#010+
   '**2Sk_Load fpcylix unit'#010+
   '**2Sk_Load fpcylix unit'#010+
   '**2SI<x>_Set interface style to <x>'#010+
   '**2SI<x>_Set interface style to <x>'#010+
-  '**3SIcom_COM compatible interface (de','fault)'#010+
+  '**3SIcom_COM com','patible interface (default)'#010+
   '**3SIcorba_CORBA compatible interface'#010+
   '**3SIcorba_CORBA compatible interface'#010+
   '**2sT_Generate script only to link on target'#010+
   '**2sT_Generate script only to link on target'#010+
   '**2Sm_Support macros like C (global)'#010+
   '**2Sm_Support macros like C (global)'#010+
   '**2So_Same as -Mtp'#010+
   '**2So_Same as -Mtp'#010+
   '**2Sr_Transparent file names in ISO mode'#010+
   '**2Sr_Transparent file names in ISO mode'#010+
-  '**2Ss_Constructor name must be init (destructor must ','be done)'#010+
+  '**2Ss_Constructor name must be i','nit (destructor must be done)'#010+
   '**2Sv_Support vector processing (use CPU vector extensions if availabl'+
   '**2Sv_Support vector processing (use CPU vector extensions if availabl'+
   'e)'#010+
   'e)'#010+
   '**2Sx_Enable exception keywords (default in Delphi/ObjFPC modes)'#010+
   '**2Sx_Enable exception keywords (default in Delphi/ObjFPC modes)'#010+
   '**2Sy_@<pointer> returns a typed pointer, same as $T+'#010+
   '**2Sy_@<pointer> returns a typed pointer, same as $T+'#010+
-  '**1s_Do not call assembler and linker'#010+
-  '*','*2sh_Generate script to link on host'#010+
+  '**1s_Do not call a','ssembler and linker'#010+
+  '**2sh_Generate script to link on host'#010+
   '**2st_Generate script to assemble and link on target'#010+
   '**2st_Generate script to assemble and link on target'#010+
   '**2sr_Skip register allocation phase (use with -alr)'#010+
   '**2sr_Skip register allocation phase (use with -alr)'#010+
   '**1T<x>_Target operating system:'#010+
   '**1T<x>_Target operating system:'#010+
   '3*2Tandroid_Android'#010+
   '3*2Tandroid_Android'#010+
   '3*2Taros_AROS'#010+
   '3*2Taros_AROS'#010+
-  '3*2Tbeos_BeOS'#010+
-  '3*2Tdarwin_Darwi','n/Mac OS X'#010+
+  '3*2Tbeos_','BeOS'#010+
+  '3*2Tdarwin_Darwin/Mac OS X'#010+
   '3*2Tembedded_Embedded'#010+
   '3*2Tembedded_Embedded'#010+
   '3*2Temx_OS/2 via EMX (including EMX/RSX extender)'#010+
   '3*2Temx_OS/2 via EMX (including EMX/RSX extender)'#010+
   '3*2Tfreebsd_FreeBSD'#010+
   '3*2Tfreebsd_FreeBSD'#010+
   '3*2Tgo32v2_Version 2 of DJ Delorie DOS extender'#010+
   '3*2Tgo32v2_Version 2 of DJ Delorie DOS extender'#010+
   '3*2Thaiku_Haiku'#010+
   '3*2Thaiku_Haiku'#010+
-  '3*2Tiphonesim_iPhoneSimulator from iOS SDK 3.2+ (older versions: -Tdar'+
-  'win',')'#010+
+  '3*2Tiphonesim_iPhoneSimulator from iOS SDK 3.2+ (old','er versions: -Td'+
+  'arwin)'#010+
   '3*2Tlinux_Linux'#010+
   '3*2Tlinux_Linux'#010+
   '3*2Tnativent_Native NT API (experimental)'#010+
   '3*2Tnativent_Native NT API (experimental)'#010+
   '3*2Tnetbsd_NetBSD'#010+
   '3*2Tnetbsd_NetBSD'#010+
@@ -1780,8 +1794,8 @@ const msgtxt : array[0..000363,1..240] of char=(
   '3*2Tnetwlibc_Novell Netware Module (libc)'#010+
   '3*2Tnetwlibc_Novell Netware Module (libc)'#010+
   '3*2Topenbsd_OpenBSD'#010+
   '3*2Topenbsd_OpenBSD'#010+
   '3*2Tos2_OS/2 / eComStation'#010+
   '3*2Tos2_OS/2 / eComStation'#010+
-  '3*2Tsymbian_Symbian OS'#010+
-  '3*2Tsolar','is_Solaris'#010+
+  '3*2Tsymbian','_Symbian OS'#010+
+  '3*2Tsolaris_Solaris'#010+
   '3*2Twatcom_Watcom compatible DOS extender'#010+
   '3*2Twatcom_Watcom compatible DOS extender'#010+
   '3*2Twdosx_WDOSX DOS extender'#010+
   '3*2Twdosx_WDOSX DOS extender'#010+
   '3*2Twin32_Windows 32 Bit'#010+
   '3*2Twin32_Windows 32 Bit'#010+
@@ -1790,8 +1804,8 @@ const msgtxt : array[0..000363,1..240] of char=(
   '4*2Taros_AROS'#010+
   '4*2Taros_AROS'#010+
   '4*2Tdarwin_Darwin/Mac OS X'#010+
   '4*2Tdarwin_Darwin/Mac OS X'#010+
   '4*2Tdragonfly_DragonFly BSD'#010+
   '4*2Tdragonfly_DragonFly BSD'#010+
-  '4*2Tembedded_Embedded'#010+
-  '4','*2Tfreebsd_FreeBSD'#010+
+  '4*','2Tembedded_Embedded'#010+
+  '4*2Tfreebsd_FreeBSD'#010+
   '4*2Thaiku_Haiku'#010+
   '4*2Thaiku_Haiku'#010+
   '4*2Tiphonesim_iPhoneSimulator'#010+
   '4*2Tiphonesim_iPhoneSimulator'#010+
   '4*2Tlinux_Linux'#010+
   '4*2Tlinux_Linux'#010+
@@ -1800,8 +1814,8 @@ const msgtxt : array[0..000363,1..240] of char=(
   '4*2Tsolaris_Solaris'#010+
   '4*2Tsolaris_Solaris'#010+
   '4*2Twin64_Win64 (64 bit Windows systems)'#010+
   '4*2Twin64_Win64 (64 bit Windows systems)'#010+
   '6*2Tamiga_Commodore Amiga'#010+
   '6*2Tamiga_Commodore Amiga'#010+
-  '6*2Tatari_Atari ST/STe/TT'#010+
-  '6*2Tembe','dded_Embedded'#010+
+  '6*2Tatari_Ata','ri ST/STe/TT'#010+
+  '6*2Tembedded_Embedded'#010+
   '6*2Tlinux_Linux'#010+
   '6*2Tlinux_Linux'#010+
   '6*2Tnetbsd_NetBSD'#010+
   '6*2Tnetbsd_NetBSD'#010+
   '6*2Tmacosclassic_Classic Mac OS'#010+
   '6*2Tmacosclassic_Classic Mac OS'#010+
@@ -1810,8 +1824,8 @@ const msgtxt : array[0..000363,1..240] of char=(
   '8*2Tembedded_Embedded'#010+
   '8*2Tembedded_Embedded'#010+
   '8*2Tmsdos_MS-DOS (and compatible)'#010+
   '8*2Tmsdos_MS-DOS (and compatible)'#010+
   '8*2Twin16_Windows 16 Bit'#010+
   '8*2Twin16_Windows 16 Bit'#010+
-  'A*2Tandroid_Android'#010+
-  'A*2Taros_AROS'#010,
+  'A*2Tandroid_A','ndroid'#010+
+  'A*2Taros_AROS'#010+
   'A*2Tembedded_Embedded'#010+
   'A*2Tembedded_Embedded'#010+
   'A*2Tfreertos_FreeRTOS'#010+
   'A*2Tfreertos_FreeRTOS'#010+
   'A*2Tgba_Game Boy Advance'#010+
   'A*2Tgba_Game Boy Advance'#010+
@@ -1823,7 +1837,8 @@ const msgtxt : array[0..000363,1..240] of char=(
   'A*2Tsymbian_Symbian'#010+
   'A*2Tsymbian_Symbian'#010+
   'A*2Twince_Windows CE'#010+
   'A*2Twince_Windows CE'#010+
   'a*2Tandroid_Android'#010+
   'a*2Tandroid_Android'#010+
-  'a*2Tdarwin_Darwin/Mac OS X',#010+
+  'a*2Td','arwin_Darwin/Mac OS X'#010+
+  'a*2Tfreebsd_FreeBSD'#010+
   'a*2Tios_iOS'#010+
   'a*2Tios_iOS'#010+
   'a*2Tlinux_Linux'#010+
   'a*2Tlinux_Linux'#010+
   'a*2Twin64_Windows 64'#010+
   'a*2Twin64_Windows 64'#010+
@@ -1835,9 +1850,9 @@ const msgtxt : array[0..000363,1..240] of char=(
   'M*2Tembedded_Embedded'#010+
   'M*2Tembedded_Embedded'#010+
   'M*2Tlinux_Linux'#010+
   'M*2Tlinux_Linux'#010+
   'P*2Taix_AIX'#010+
   'P*2Taix_AIX'#010+
-  'P*2Tamiga_AmigaOS'#010+
+  'P*2Tami','ga_AmigaOS'#010+
   'P*2Tdarwin_Darwin/Mac OS X'#010+
   'P*2Tdarwin_Darwin/Mac OS X'#010+
-  'P*2','Tembedded_Embedded'#010+
+  'P*2Tembedded_Embedded'#010+
   'P*2Tlinux_Linux'#010+
   'P*2Tlinux_Linux'#010+
   'P*2Tmacosclassic_Classic Mac OS'#010+
   'P*2Tmacosclassic_Classic Mac OS'#010+
   'P*2Tmorphos_MorphOS'#010+
   'P*2Tmorphos_MorphOS'#010+
@@ -1847,9 +1862,9 @@ const msgtxt : array[0..000363,1..240] of char=(
   'p*2Tdarwin_Darwin/Mac OS X'#010+
   'p*2Tdarwin_Darwin/Mac OS X'#010+
   'p*2Tembedded_Embedded'#010+
   'p*2Tembedded_Embedded'#010+
   'p*2Tlinux_Linux'#010+
   'p*2Tlinux_Linux'#010+
-  'R*2Tlinux_Linux'#010+
+  'R*2Tl','inux_Linux'#010+
   'R*2Tembedded_Embedded'#010+
   'R*2Tembedded_Embedded'#010+
-  'r*2Tlinu','x_Linux'#010+
+  'r*2Tlinux_Linux'#010+
   'r*2Tembedded_Embedded'#010+
   'r*2Tembedded_Embedded'#010+
   'S*2Tlinux_Linux'#010+
   'S*2Tlinux_Linux'#010+
   'S*2Tsolaris_Solaris'#010+
   'S*2Tsolaris_Solaris'#010+
@@ -1859,162 +1874,161 @@ const msgtxt : array[0..000363,1..240] of char=(
   'x*2Tfreertos_FreeRTOS'#010+
   'x*2Tfreertos_FreeRTOS'#010+
   'x*2Tlinux_Linux'#010+
   'x*2Tlinux_Linux'#010+
   'Z*2Tembedded_Embedded'#010+
   'Z*2Tembedded_Embedded'#010+
-  'Z*2Tzxspectrum_ZX Spectrum'#010+
+  'Z*2Tzxspectru','m_ZX Spectrum'#010+
   'Z*2Tmsxdos_MSX-DOS'#010+
   'Z*2Tmsxdos_MSX-DOS'#010+
-  'W*2Tembe','dded_Embedded'#010+
+  'W*2Tembedded_Embedded'#010+
   'W*2Twasi_The WebAssembly System Interface (WASI)'#010+
   'W*2Twasi_The WebAssembly System Interface (WASI)'#010+
   '**1u<x>_Undefines the symbol <x>'#010+
   '**1u<x>_Undefines the symbol <x>'#010+
   '**1U_Unit options:'#010+
   '**1U_Unit options:'#010+
   '**2Un_Do not check where the unit name matches the file name'#010+
   '**2Un_Do not check where the unit name matches the file name'#010+
-  '**2Ur_Generate release unit files (never automatically recompile','d)'#010+
+  '**2Ur_Generate release ','unit files (never automatically recompiled)'#010+
   '**2Us_Compile a system unit'#010+
   '**2Us_Compile a system unit'#010+
   '**1v<x>_Be verbose. <x> is a combination of the following letters:'#010+
   '**1v<x>_Be verbose. <x> is a combination of the following letters:'#010+
   '**2*_e : Show errors (default)       0 : Show nothing (except errors)'#010+
   '**2*_e : Show errors (default)       0 : Show nothing (except errors)'#010+
-  '**2*_w : Show warnings               u : Show unit info'#010+
-  '**2*_n : Show no','tes                  t : Show tried/used files'#010+
+  '**2*_w : Show warnings         ','      u : Show unit info'#010+
+  '**2*_n : Show notes                  t : Show tried/used files'#010+
   '**2*_h : Show hints                  c : Show conditionals'#010+
   '**2*_h : Show hints                  c : Show conditionals'#010+
   '**2*_i : Show general info           d : Show debug info'#010+
   '**2*_i : Show general info           d : Show debug info'#010+
-  '**2*_l : Show linenumbers            r : Rhide/GCC compatibility mode'#010+
-  '**2*_s ',': Show time stamps            q : Show message numbers'#010+
+  '**2*_l : Show linenumbers           ',' r : Rhide/GCC compatibility mod'+
+  'e'#010+
+  '**2*_s : Show time stamps            q : Show message numbers'#010+
   '**2*_a : Show everything             x : Show info about invoked tools'+
   '**2*_a : Show everything             x : Show info about invoked tools'+
   #010+
   #010+
   '**2*_b : Write file names messages   p : Write tree.log with parse tre'+
   '**2*_b : Write file names messages   p : Write tree.log with parse tre'+
   'e'#010+
   'e'#010+
-  '**2*_    with full path              v : W','rite fpcdebug.txt with'#010+
+  '*','*2*_    with full path              v : Write fpcdebug.txt with'#010+
   '**2*_z : Write output to stderr          lots of debugging info'#010+
   '**2*_z : Write output to stderr          lots of debugging info'#010+
   '**2*_m<x>,<y> : Do not show messages numbered <x> and <y>'#010+
   '**2*_m<x>,<y> : Do not show messages numbered <x> and <y>'#010+
-  'F*1V<x>_Append '#039'-<x>'#039' to the used compiler binary name (e.g. f'+
-  'or version)'#010+
-  '**1W<x>_Target-specif','ic options (targets)'#010+
+  'F*1V<x>_Append '#039'-<x>'#039' to the used compiler binary name',' (e.g.'+
+  ' for version)'#010+
+  '**1W<x>_Target-specific options (targets)'#010+
   '3*2WA_Specify native type application (Windows)'#010+
   '3*2WA_Specify native type application (Windows)'#010+
   '4*2WA_Specify native type application (Windows)'#010+
   '4*2WA_Specify native type application (Windows)'#010+
   'A*2WA_Specify native type application (Windows)'#010+
   'A*2WA_Specify native type application (Windows)'#010+
-  '3*2Wb_Create a bundle instead of a library (Darwin)'#010+
-  'P*2Wb_Create a bundle i','nstead of a library (Darwin)'#010+
+  '3*2Wb_Create a bundle instead of a',' library (Darwin)'#010+
+  'P*2Wb_Create a bundle instead of a library (Darwin)'#010+
   'p*2Wb_Create a bundle instead of a library (Darwin)'#010+
   'p*2Wb_Create a bundle instead of a library (Darwin)'#010+
   'a*2Wb_Create a bundle instead of a library (Darwin)'#010+
   'a*2Wb_Create a bundle instead of a library (Darwin)'#010+
   'A*2Wb_Create a bundle instead of a library (Darwin)'#010+
   'A*2Wb_Create a bundle instead of a library (Darwin)'#010+
-  '4*2Wb_Create a bundle instead of a library (Darwin)'#010+
-  '3*2','WB_Create a relocatable image (Windows, Symbian)'#010+
+  '4*2Wb_Create a',' bundle instead of a library (Darwin)'#010+
+  '3*2WB_Create a relocatable image (Windows, Symbian)'#010+
   '3*2WB<x>_Set image base to <x> (Windows, Symbian)'#010+
   '3*2WB<x>_Set image base to <x> (Windows, Symbian)'#010+
   '4*2WB_Create a relocatable image (Windows)'#010+
   '4*2WB_Create a relocatable image (Windows)'#010+
   '4*2WB<x>_Set image base to <x> (Windows)'#010+
   '4*2WB<x>_Set image base to <x> (Windows)'#010+
-  'A*2WB_Create a relocatable image (Windows, Symbian)'#010+
-  'A*2WB','<x>_Set image base to <x> (Windows, Symbian)'#010+
+  'A*2WB_Create a r','elocatable image (Windows, Symbian)'#010+
+  'A*2WB<x>_Set image base to <x> (Windows, Symbian)'#010+
   'Z*2WB<x>_Set image base to <x> (ZX Spectrum)'#010+
   'Z*2WB<x>_Set image base to <x> (ZX Spectrum)'#010+
   '3*2WC_Specify console type application (EMX, OS/2, Windows)'#010+
   '3*2WC_Specify console type application (EMX, OS/2, Windows)'#010+
-  '4*2WC_Specify console type application (Windows)'#010+
-  'A*2WC_Specify console type application (W','indows)'#010+
+  '4*2WC_Specify console type application (Windows)'#010,
+  'A*2WC_Specify console type application (Windows)'#010+
   'P*2WC_Specify console type application (Classic Mac OS)'#010+
   'P*2WC_Specify console type application (Classic Mac OS)'#010+
   '3*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)'#010+
   '3*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)'#010+
   '4*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)'#010+
   '4*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)'#010+
-  'A*2WD_Use DEFFILE to export functions of DLL or EXE ','(Windows)'#010+
+  'A*2WD_Use D','EFFILE to export functions of DLL or EXE (Windows)'#010+
   '3*2We_Use external resources (Darwin)'#010+
   '3*2We_Use external resources (Darwin)'#010+
   '4*2We_Use external resources (Darwin)'#010+
   '4*2We_Use external resources (Darwin)'#010+
   'a*2We_Use external resources (Darwin)'#010+
   'a*2We_Use external resources (Darwin)'#010+
   'A*2We_Use external resources (Darwin)'#010+
   'A*2We_Use external resources (Darwin)'#010+
-  'P*2We_Use external resources (Darwin)'#010+
+  'P*2We_Use external resources (Darwin)',#010+
   'p*2We_Use external resources (Darwin)'#010+
   'p*2We_Use external resources (Darwin)'#010+
-  '3*','2WF_Specify full-screen type application (EMX, OS/2)'#010+
+  '3*2WF_Specify full-screen type application (EMX, OS/2)'#010+
   '3*2WG_Specify graphic type application (EMX, OS/2, Windows)'#010+
   '3*2WG_Specify graphic type application (EMX, OS/2, Windows)'#010+
   '4*2WG_Specify graphic type application (Windows)'#010+
   '4*2WG_Specify graphic type application (Windows)'#010+
-  'A*2WG_Specify graphic type application (Windows)'#010+
-  'P*2WG_Specify graphic type ap','plication (Classic Mac OS)'#010+
+  'A*2WG_Specify graphic type applicatio','n (Windows)'#010+
+  'P*2WG_Specify graphic type application (Classic Mac OS)'#010+
   '3*2Wi_Use internal resources (Darwin)'#010+
   '3*2Wi_Use internal resources (Darwin)'#010+
   '4*2Wi_Use internal resources (Darwin)'#010+
   '4*2Wi_Use internal resources (Darwin)'#010+
   'a*2Wi_Use internal resources (Darwin)'#010+
   'a*2Wi_Use internal resources (Darwin)'#010+
   'A*2Wi_Use internal resources (Darwin)'#010+
   'A*2Wi_Use internal resources (Darwin)'#010+
-  'P*2Wi_Use internal resources (Darwin)'#010+
-  'p*2Wi_Use internal reso','urces (Darwin)'#010+
+  'P*2Wi_Use internal r','esources (Darwin)'#010+
+  'p*2Wi_Use internal resources (Darwin)'#010+
   '3*2WI_Turn on/off the usage of import sections (Windows)'#010+
   '3*2WI_Turn on/off the usage of import sections (Windows)'#010+
   '4*2WI_Turn on/off the usage of import sections (Windows)'#010+
   '4*2WI_Turn on/off the usage of import sections (Windows)'#010+
   'A*2WI_Turn on/off the usage of import sections (Windows)'#010+
   'A*2WI_Turn on/off the usage of import sections (Windows)'#010+
-  '8*2Wh_Use huge code for units (ignored for models with',' CODE in a uni'+
+  '8*2Wh_Use hug','e code for units (ignored for models with CODE in a uni'+
   'que segment)'#010+
   'que segment)'#010+
   '8*2Wm<x>_Set memory model'#010+
   '8*2Wm<x>_Set memory model'#010+
   '8*3WmTiny_Tiny memory model'#010+
   '8*3WmTiny_Tiny memory model'#010+
   '8*3WmSmall_Small memory model (default)'#010+
   '8*3WmSmall_Small memory model (default)'#010+
   '8*3WmMedium_Medium memory model'#010+
   '8*3WmMedium_Medium memory model'#010+
   '8*3WmCompact_Compact memory model'#010+
   '8*3WmCompact_Compact memory model'#010+
-  '8*3WmLarge_Large memory model'#010+
-  '8*3WmHuge_Huge memory m','odel'#010+
+  '8*3WmLarge_L','arge memory model'#010+
+  '8*3WmHuge_Huge memory model'#010+
   '3*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
   '3*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
   'n)'#010+
   'n)'#010+
   '4*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
   '4*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
   'n)'#010+
   'n)'#010+
-  'p*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
-  'n)'#010+
-  'P*2WM<x>_Minimum',' Mac OS X deployment version: 10.4, 10.5.1, ... (Dar'+
+  'p*2WM<x>_Minimum Mac OS X deployment version: 10','.4, 10.5.1, ... (Dar'+
   'win)'#010+
   'win)'#010+
+  'P*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
+  'n)'#010+
   '3*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+
   '3*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+
   '4*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+
   '4*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+
-  'A*2WN_Do not generate relocation code, need','ed for debugging (Windows'+
+  'A*','2WN_Do not generate relocation code, needed for debugging (Windows'+
   ')'#010+
   ')'#010+
   'A*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
   'A*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
   'le values'#010+
   'le values'#010+
   'm*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
   'm*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
   'le values'#010+
   'le values'#010+
-  'R*2Wp<x>_Specify the controller type; see fpc -i or f','pc -iu for poss'+
+  'R*2Wp<x>_Spe','cify the controller type; see fpc -i or fpc -iu for poss'+
   'ible values'#010+
   'ible values'#010+
   'V*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
   'V*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
   'le values'#010+
   'le values'#010+
   'x*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
   'x*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
   'le values'#010+
   'le values'#010+
-  '3*2WP<x>_Minimum iOS deployment version: 3.0, 5.0.1, ','... (iphonesim)'+
+  '3*2WP<x>_Min','imum iOS deployment version: 3.0, 5.0.1, ... (iphonesim)'+
   #010+
   #010+
   '4*2WP<x>_Minimum iOS deployment version: 8.0, 8.0.2, ... (iphonesim)'#010+
   '4*2WP<x>_Minimum iOS deployment version: 8.0, 8.0.2, ... (iphonesim)'#010+
   'a*2WP<x>_Minimum iOS deployment version: 7.0, 7.1.2, ... (Darwin)'#010+
   'a*2WP<x>_Minimum iOS deployment version: 7.0, 7.1.2, ... (Darwin)'#010+
-  'A*2WP<x>_Minimum iOS deployment version: 3.0, 5.0.1, ... (Darwin)'#010+
-  '3*2WR_Generate relocati','on code (Windows)'#010+
+  'A*2WP<x>_Minimum iOS deployment version: 3.0, 5.','0.1, ... (Darwin)'#010+
+  '3*2WR_Generate relocation code (Windows)'#010+
   '4*2WR_Generate relocation code (Windows)'#010+
   '4*2WR_Generate relocation code (Windows)'#010+
   'A*2WR_Generate relocation code (Windows)'#010+
   'A*2WR_Generate relocation code (Windows)'#010+
   '8*2Wt<x>_Set the target executable format'#010+
   '8*2Wt<x>_Set the target executable format'#010+
   '8*3Wtexe_Create a DOS .EXE file (default)'#010+
   '8*3Wtexe_Create a DOS .EXE file (default)'#010+
-  '8*3Wtcom_Create a DOS .COM file (requires tiny memory mo','del)'#010+
+  '8*3Wtcom_Create',' a DOS .COM file (requires tiny memory model)'#010+
   'P*2WT_Specify MPW tool type application (Classic Mac OS)'#010+
   'P*2WT_Specify MPW tool type application (Classic Mac OS)'#010+
   '6*2WQ<x>_Set executable metadata format (Sinclair QL)'#010+
   '6*2WQ<x>_Set executable metadata format (Sinclair QL)'#010+
   '6*3WQqhdr_Set metadata to QDOS File Header style (default)'#010+
   '6*3WQqhdr_Set metadata to QDOS File Header style (default)'#010+
-  '6*3WQxtcc_Set metadata to XTcc style'#010+
-  '**2WX_Enable executable stac','k (Linux)'#010+
+  '6*3WQxtcc_Set metadata t','o XTcc style'#010+
+  '**2WX_Enable executable stack (Linux)'#010+
   '**1X_Executable options:'#010+
   '**1X_Executable options:'#010+
   '**2X9_Generate linkerscript for GNU Binutils ld older than version 2.1'+
   '**2X9_Generate linkerscript for GNU Binutils ld older than version 2.1'+
   '9.1 (Linux)'#010+
   '9.1 (Linux)'#010+
   '**2Xa_Generate code which allows to use more than 2 GB static data on '+
   '**2Xa_Generate code which allows to use more than 2 GB static data on '+
-  '64 Bit targets (Linux)'#010+
-  '**2Xc_Pass --shared/-dynamic t','o the linker (BeOS, Darwin, FreeBSD, L'+
-  'inux)'#010+
+  '64 Bit targe','ts (Linux)'#010+
+  '**2Xc_Pass --shared/-dynamic to the linker (BeOS, Darwin, FreeBSD, Lin'+
+  'ux)'#010+
   '**2Xd_Do not search default library path (sometimes required for cross'+
   '**2Xd_Do not search default library path (sometimes required for cross'+
   '-compiling when not using -XR)'#010+
   '-compiling when not using -XR)'#010+
   '**2Xe_Use external linker'#010+
   '**2Xe_Use external linker'#010+
-  '**2Xf_Substitute pthread library name for linking (BSD)'#010+
-  '**2Xg_Create ','debuginfo in a separate file and add a debuglink sectio'+
-  'n to executable'#010+
+  '**2Xf_Substitute pthread lib','rary name for linking (BSD)'#010+
+  '**2Xg_Create debuginfo in a separate file and add a debuglink section '+
+  'to executable'#010+
   '**2XD_Try to link units dynamically      (defines FPC_LINK_DYNAMIC)'#010+
   '**2XD_Try to link units dynamically      (defines FPC_LINK_DYNAMIC)'#010+
   '**2Xi_Use internal linker'#010+
   '**2Xi_Use internal linker'#010+
-  'L*2XlS<x>_LLVM utilties suffix (e.g. -7 in case clang is called clang-'+
-  '7)'#010+
-  '**','2XLA_Define library substitutions for linking'#010+
+  'L*2XlS<x>_LLVM utilties suffix (e.','g. -7 in case clang is called clan'+
+  'g-7)'#010+
+  '**2XLA_Define library substitutions for linking'#010+
   '**2XLO_Define order of library linking'#010+
   '**2XLO_Define order of library linking'#010+
   '**2XLD_Exclude default order of standard libraries'#010+
   '**2XLD_Exclude default order of standard libraries'#010+
   '**2Xm_Generate link map'#010+
   '**2Xm_Generate link map'#010+
-  '**2XM<x>_Set the name of the '#039'main'#039' program routine (default i'+
-  's '#039'main'#039')'#010+
-  '**2Xn_Us','e target system native linker instead of GNU ld (Solaris, AI'+
-  'X)'#010+
+  '**2XM<x>_Set the name of the '#039'main'#039' pro','gram routine (default'+
+  ' is '#039'main'#039')'#010+
+  '**2Xn_Use target system native linker instead of GNU ld (Solaris, AIX)'+
+  #010+
   'F*2Xp<x>_First search for the compiler binary in the directory <x>'#010+
   'F*2Xp<x>_First search for the compiler binary in the directory <x>'#010+
   '**2XP<x>_Prepend the binutils names with the prefix <x>'#010+
   '**2XP<x>_Prepend the binutils names with the prefix <x>'#010+
-  '**2Xr<x>_Set the linker'#039's rlink-path to <x> (needed fo','r cross co'+
+  '**2Xr<x>_Set ','the linker'#039's rlink-path to <x> (needed for cross co'+
   'mpile, see the ld manual for more information) (BeOS, Linux)'#010+
   'mpile, see the ld manual for more information) (BeOS, Linux)'#010+
   '**2XR<x>_Prepend <x> to all linker search paths (BeOS, Darwin, FreeBSD'+
   '**2XR<x>_Prepend <x> to all linker search paths (BeOS, Darwin, FreeBSD'+
   ', Linux, Mac OS, Solaris)'#010+
   ', Linux, Mac OS, Solaris)'#010+
-  '**2Xs_Strip all symbols from executable'#010+
-  '**2XS_Try to link units staticall','y (default, defines FPC_LINK_STATIC'+
-  ')'#010+
+  '**2Xs_Strip all symbols from exe','cutable'#010+
+  '**2XS_Try to link units statically (default, defines FPC_LINK_STATIC)'#010+
   '**2Xt_Link with static libraries (-static is passed to linker)'#010+
   '**2Xt_Link with static libraries (-static is passed to linker)'#010+
   '**2Xu_Generate executable in UF2 format  (embedded targets only)'#010+
   '**2Xu_Generate executable in UF2 format  (embedded targets only)'#010+
-  '**2Xv_Generate table for Virtual Entry calls'#010+
-  '**2XV_Use VLink as external li','nker       (default on Amiga, MorphOS)'+
-  #010+
+  '**2Xv_Generate table for Virtual E','ntry calls'#010+
+  '**2XV_Use VLink as external linker       (default on Amiga, MorphOS)'#010+
   '**2XX_Try to smartlink units             (defines FPC_LINK_SMART)'#010+
   '**2XX_Try to smartlink units             (defines FPC_LINK_SMART)'#010+
   '**1*_'#010+
   '**1*_'#010+
   '**1?_Show this help'#010+
   '**1?_Show this help'#010+

+ 10 - 2
compiler/nflw.pas

@@ -111,6 +111,7 @@ interface
           loopiteration : tnode;
           loopiteration : tnode;
           loopvar_notid:cardinal;
           loopvar_notid:cardinal;
           constructor create(l,r,_t1,_t2 : tnode;back : boolean);virtual;reintroduce;
           constructor create(l,r,_t1,_t2 : tnode;back : boolean);virtual;reintroduce;
+          destructor destroy;override;
           function pass_typecheck:tnode;override;
           function pass_typecheck:tnode;override;
           function pass_1 : tnode;override;
           function pass_1 : tnode;override;
           function makewhileloop : tnode;
           function makewhileloop : tnode;
@@ -1774,6 +1775,13 @@ implementation
          include(loopflags,lnf_testatbegin);
          include(loopflags,lnf_testatbegin);
       end;
       end;
 
 
+    destructor tfornode.destroy;
+      begin
+         if assigned(loopiteration) then
+           loopiteration.destroy;
+         inherited destroy;
+      end;
+
     function tfornode.simplify(forinline : boolean) : tnode;
     function tfornode.simplify(forinline : boolean) : tnode;
       begin
       begin
         result:=nil;
         result:=nil;
@@ -2734,10 +2742,10 @@ implementation
          begin
          begin
            result:=right;
            result:=right;
            right:=nil;
            right:=nil;
-         end;
+         end
        { if the finally block contains no code, we can kill
        { if the finally block contains no code, we can kill
          it and just return the try part }
          it and just return the try part }
-       if has_no_code(right) and not(assigned(third)) and not(implicitframe) then
+       else if has_no_code(right) and not(assigned(third)) and not(implicitframe) then
          begin
          begin
            result:=left;
            result:=left;
            left:=nil;
            left:=nil;

+ 1 - 1
compiler/options.pas

@@ -2764,7 +2764,7 @@ begin
                     'L':
                     'L':
                       begin
                       begin
                         if (target_info.system in [system_m68k_sinclairql]) then
                         if (target_info.system in [system_m68k_sinclairql]) then
-                          sinclairql_vlink_experimental:=true
+                          sinclairql_vlink_experimental:=false
                         else
                         else
                           IllegalPara(opt);
                           IllegalPara(opt);
                       end;
                       end;

+ 6 - 0
compiler/paramgr.pas

@@ -801,6 +801,12 @@ implementation
       var
       var
         reg : tregisterrec;
         reg : tregisterrec;
       begin
       begin
+        { Explicitly zero the whole record, to avoid
+          trouble as this record is used as is in a
+          hash calculation, which might give unreliable
+          results if the record as gaps between fields
+          due to field alignment. PM 2021-05-06 }
+        fillchar(result,sizeof(trttiparaloc),#0);
         if paraloc^.Loc=LOC_REFERENCE then
         if paraloc^.Loc=LOC_REFERENCE then
           begin
           begin
             reg:=tregisterrec(paraloc^.reference.index);
             reg:=tregisterrec(paraloc^.reference.index);

+ 8 - 4
compiler/rgobj.pas

@@ -2846,8 +2846,10 @@ unit rgobj;
                     set weigth of the newly allocated register higher than the old one,
                     set weigth of the newly allocated register higher than the old one,
                     so it will selected for spilling with a lower priority than
                     so it will selected for spilling with a lower priority than
                     the original one, this prevents an endless spilling loop if orgreg
                     the original one, this prevents an endless spilling loop if orgreg
-                    is short living, see e.g. tw25164.pp }
-                  add_reg_instruction(instr,loadreg,reginfo[orgreg].weight+1);
+                    is short living, see e.g. tw25164.pp
+
+                    the min trick is needed to avoid an overflow in case weight=high(weight which might happen }
+                  add_reg_instruction(instr,loadreg,min(high(reginfo[orgreg].weight)-1,reginfo[orgreg].weight)+1);
                   ungetregisterinline(list,loadreg);
                   ungetregisterinline(list,loadreg);
                 end;
                 end;
             end;
             end;
@@ -2878,8 +2880,10 @@ unit rgobj;
                     set weigth of the newly allocated register higher than the old one,
                     set weigth of the newly allocated register higher than the old one,
                     so it will selected for spilling with a lower priority than
                     so it will selected for spilling with a lower priority than
                     the original one, this prevents an endless spilling loop if orgreg
                     the original one, this prevents an endless spilling loop if orgreg
-                    is short living, see e.g. tw25164.pp }
-                  add_reg_instruction(instr,storereg,reginfo[orgreg].weight+1);
+                    is short living, see e.g. tw25164.pp
+
+                    the min trick is needed to avoid an overflow in case weight=high(weight which might happen }
+                  add_reg_instruction(instr,storereg,min(high(reginfo[orgreg].weight)-1,reginfo[orgreg].weight)+1);
                 end;
                 end;
             end;
             end;
 
 

+ 1 - 1
compiler/symsym.pas

@@ -1861,7 +1861,7 @@ implementation
                   (varregable <> vr_none)) or
                   (varregable <> vr_none)) or
                  (not refpara and
                  (not refpara and
                   not(varregable in [vr_none,vr_addr])))
                   not(varregable in [vr_none,vr_addr])))
-{$if not defined(powerpc) and not defined(powerpc64)}
+{$if not defined(powerpc) and not defined(powerpc64) and not defined(aarch64)}
                 and ((vardef.typ <> recorddef) or
                 and ((vardef.typ <> recorddef) or
                      (varregable = vr_addr) or
                      (varregable = vr_addr) or
                      tabstractrecordsymtable(tabstractrecorddef(vardef).symtable).has_single_field(tempdef) or
                      tabstractrecordsymtable(tabstractrecorddef(vardef).symtable).has_single_field(tempdef) or

+ 1 - 0
compiler/systems/t_sinclairql.pas

@@ -266,6 +266,7 @@ begin
   GCSectionsStr:='';
   GCSectionsStr:='';
   DynLinkStr:='';
   DynLinkStr:='';
   FlagsStr:='';
   FlagsStr:='';
+  QLFlagsStr:='';
   MapStr:='';
   MapStr:='';
 
 
   if (cs_link_map in current_settings.globalswitches) then
   if (cs_link_map in current_settings.globalswitches) then

+ 2 - 2
compiler/utils/msgused.pl

@@ -4,8 +4,8 @@
 
 
 unlink("./msgidx.inc");
 unlink("./msgidx.inc");
 unlink("./msgtxt.inc");
 unlink("./msgtxt.inc");
-@compiler_src = (glob("./*.inc"),
-                 glob("./*.pas"));
+@compiler_src = (glob("./*.inc"),glob("./*/*.inc"),
+                 glob("./*.pas"),glob("./*/*.pas"));
 
 
 open(MESSAGE_FILE, "< ./msg/errore.msg") or
 open(MESSAGE_FILE, "< ./msg/errore.msg") or
   die "Couldn't open <./msg/errore.msg> for reading: $!\n";
   die "Couldn't open <./msg/errore.msg> for reading: $!\n";

+ 9 - 9
packages/fcl-image/src/fpwritepnm.pp

@@ -15,8 +15,8 @@
 {*****************************************************************************}
 {*****************************************************************************}
 {Support for writing PNM (Portable aNyMap) formats added :
 {Support for writing PNM (Portable aNyMap) formats added :
     * PBM (P1,P4) : Portable BitMap format : 1 bit per pixel
     * PBM (P1,P4) : Portable BitMap format : 1 bit per pixel
-    * PGM (P2,P5) : Portable GrayMap format : 8 bits per pixel
-    * PPM (P5,P6) : Portable PixelMap foramt : 24 bits per pixel}
+    * PGM (P2,P5) : Portable GrayMap format : 8 bits per pixel for P2 (ASCII), 8 or 16 bit for P5 (binary)
+    * PPM (P3,P6) : Portable PixelMap format : 24 bits per pixel for P3 (ASCII), 24 or 48 bit for P6 (binary)}
 {$mode objfpc}{$h+}
 {$mode objfpc}{$h+}
 unit FPWritePNM;
 unit FPWritePNM;
 
 
@@ -38,7 +38,7 @@ type
   protected
   protected
     procedure InternalWrite(Stream:TStream;Img:TFPCustomImage);override;
     procedure InternalWrite(Stream:TStream;Img:TFPCustomImage);override;
   public
   public
-    Property FullWidth: Boolean Read FFullWidth Write SetFullWidth;
+    Property FullWidth: Boolean Read FFullWidth Write SetFullWidth; {if true write 16 bits per colour for P5, P6 formats}
     function GuessColorDepthOfImage(Img: TFPCustomImage): TPNMColorDepth;
     function GuessColorDepthOfImage(Img: TFPCustomImage): TPNMColorDepth;
     function GetColorDepthOfExtension(AExtension: string): TPNMColorDepth;
     function GetColorDepthOfExtension(AExtension: string): TPNMColorDepth;
     function GetFileExtension(AColorDepth: TPNMColorDepth): string;
     function GetFileExtension(AColorDepth: TPNMColorDepth): string;
@@ -233,18 +233,18 @@ var useBitMapType: integer;
                 4:if(Red<=$2F00)or(Green<=$2F00)or(Blue<=$2F00)
                 4:if(Red<=$2F00)or(Green<=$2F00)or(Blue<=$2F00)
                   then
                   then
                     aLine[Coulumn shr 3]:=aLine[Coulumn shr 3] or ($80 shr (Coulumn and $07));
                     aLine[Coulumn shr 3]:=aLine[Coulumn shr 3] or ($80 shr (Coulumn and $07));
-                5: if FullWidth then
-                     dLine[Coulumn]:=Word(Round(Red*0.299+Green*0.587+Blue*0.114))
-                   else
+                5: if FullWidth then {16 bit per colour}
+                     dLine[Coulumn]:=NToBe(Word(Round(Red*0.299+Green*0.587+Blue*0.114))) {write in big-endian format}
+                   else {8 bit per colour}
                      aLine[Coulumn]:=Hi(Word(Round(Red*0.299+Green*0.587+Blue*0.114)));
                      aLine[Coulumn]:=Hi(Word(Round(Red*0.299+Green*0.587+Blue*0.114)));
                 6:if FullWidth then
                 6:if FullWidth then
-                  begin
-                    dLine[3*Coulumn]:=NToBE(Red);
+                  begin {16 bit per colour}
+                    dLine[3*Coulumn]:=NToBE(Red); {write in big-endian format}
                     dLine[3*Coulumn+1]:=NToBE(Green);
                     dLine[3*Coulumn+1]:=NToBE(Green);
                     dLine[3*Coulumn+2]:=NToBE(Blue);
                     dLine[3*Coulumn+2]:=NToBE(Blue);
                   end
                   end
                   else
                   else
-                  begin
+                  begin {8 bit per colour}
                     aLine[3*Coulumn]:=Hi(Red);
                     aLine[3*Coulumn]:=Hi(Red);
                     aLine[3*Coulumn+1]:=Hi(Green);
                     aLine[3*Coulumn+1]:=Hi(Green);
                     aLine[3*Coulumn+2]:=Hi(Blue);
                     aLine[3*Coulumn+2]:=Hi(Blue);

+ 2 - 1
packages/graph/src/ptcgraph/ptcgraph.pp

@@ -18,6 +18,7 @@ unit ptcgraph;
 
 
 {//$define logging}
 {//$define logging}
 {$define FPC_GRAPH_SUPPORTS_TRUECOLOR}
 {$define FPC_GRAPH_SUPPORTS_TRUECOLOR}
+{$modeswitch DEFAULTPARAMETERS+}
 
 
 {******************************************************************************}
 {******************************************************************************}
                                     interface
                                     interface
@@ -139,7 +140,7 @@ var
   WindowTitle: AnsiString;
   WindowTitle: AnsiString;
   PTCWrapperObject: TPTCWrapperThread;
   PTCWrapperObject: TPTCWrapperThread;
 
 
-function InstallUserMode(Width, Height: SmallInt; Colors: LongInt; HardwarePages: SmallInt; XAspect, YAspect: Word): smallint;
+function InstallUserMode(Width, Height: SmallInt; Colors: LongInt; HardwarePages: SmallInt = 1; XAspect: Word = 10000; YAspect: Word = 10000): smallint;
 
 
 {******************************************************************************}
 {******************************************************************************}
                                  implementation
                                  implementation

+ 2 - 2
packages/pastojs/src/pas2jscompiler.pp

@@ -1,4 +1,4 @@
-{ Author: Mattias Gaertner  2019  [email protected]
+{ Author: Mattias Gaertner  2021  [email protected]
 
 
 Abstract:
 Abstract:
   TPas2jsCompiler is the wheel boss of the pas2js compiler.
   TPas2jsCompiler is the wheel boss of the pas2js compiler.
@@ -4828,7 +4828,7 @@ begin
   if FHasShownLogo then exit;
   if FHasShownLogo then exit;
   FHasShownLogo:=true;
   FHasShownLogo:=true;
   WriteVersionLine;
   WriteVersionLine;
-  Log.LogPlain('Copyright (c) 2019 Free Pascal team.');
+  Log.LogPlain('Copyright (c) 2021 Free Pascal team.');
   if coShowInfos in Options then
   if coShowInfos in Options then
     WriteEncoding;
     WriteEncoding;
 end;
 end;

+ 53 - 0
packages/qlunits/examples/mtinf.pas

@@ -0,0 +1,53 @@
+{
+    Copyright (c) 2021 Karoly Balogh
+
+    System info/System variables access on a Sinclair QL
+    Example program for Free Pascal's Sinclair QL support
+
+    This example program is in the Public Domain under the terms of
+    Unlicense: http://unlicense.org/
+
+ **********************************************************************}
+
+program mtinf;
+
+uses
+  qdos;
+
+type
+  Tver = array[0..3] of char;
+
+var
+  job_id: longint;
+  ver_ascii: longint;
+  system_vars: pbyte;
+
+function get_id_str(const id: dword): string;
+const
+  QDOS = $D2540000;
+  SMS = $53324154; { S2AT }
+  SMSQ = $534D5351; { SMSQ }
+  ARGOS_THOR = $DC010000;
+begin
+  case id of
+    QDOS: get_id_str:='QDOS';
+    SMS: get_id_str:='SMS';
+    SMSQ: get_id_str:='SMSQ';
+    ARGOS_THOR: get_id_str:='Thor (ARGOS)';
+  else
+    get_id_str:='unknown ($'+hexstr(id,8)+')';
+  end;
+end;
+
+begin
+  job_id:=mt_inf(@system_vars,@ver_ascii);
+
+  writeln('Job ID:',lo(job_id),' Tag:',hi(job_id));
+  writeln('Identification: ',get_id_str(pdword(@system_vars[SV_IDENT])^));
+  writeln('Version: ',Tver(ver_ascii));
+
+  writeln('System vars are at: $',hexstr(system_vars));
+  writeln('Processor type: 680',hexstr(system_vars[SV_PTYP],2));
+  writeln('Monitor mode: ',system_vars[SV_TVMOD]);
+  writeln('Random number: ',pword(@system_vars[SV_RAND])^);
+end.

+ 2 - 0
packages/qlunits/fpmake.pp

@@ -25,6 +25,7 @@ begin
 {$endif ALLPACKAGES}
 {$endif ALLPACKAGES}
     P.Version:='3.3.1';
     P.Version:='3.3.1';
     P.SourcePath.Add('src');
     P.SourcePath.Add('src');
+    P.IncludePath.Add('src');
 
 
     P.OSes:=[sinclairql];
     P.OSes:=[sinclairql];
 
 
@@ -35,6 +36,7 @@ begin
 
 
     P.ExamplePath.Add('examples');
     P.ExamplePath.Add('examples');
     T:=P.Targets.AddExampleProgram('qlcube.pas');
     T:=P.Targets.AddExampleProgram('qlcube.pas');
+    T:=P.Targets.AddExampleProgram('mtinf.pas');
 
 
 {$ifndef ALLPACKAGES}
 {$ifndef ALLPACKAGES}
     Run;
     Run;

+ 67 - 35
packages/qlunits/src/qdos.pas

@@ -54,6 +54,68 @@ const
   Q_OPEN_OVER = 3;  { Not available on microdrives. }
   Q_OPEN_OVER = 3;  { Not available on microdrives. }
   Q_OPEN_DIR = 4;
   Q_OPEN_DIR = 4;
 
 
+{ sysvars offsets }
+const
+   SV_IDENT = $00;
+   SV_CHEAP = $04;
+   SV_CHPFR = $08;
+   SV_FREE = $0c;
+   SV_BASIC = $10;
+   SV_TRNSP = $14;
+   SV_TRNFR = $18;
+   SV_RESPR = $1c;
+   SV_RAMT = $20;
+   SV_RAND = $2e;
+   SV_POLLM = $30;
+   SV_TVMOD = $32;
+   SV_SCRST = $33;
+   SV_MCSTA = $34;
+   SV_PCINT = $35;
+   SV_NETNR = $37;
+   SV_I2LST = $38;
+   SV_PLIST = $3c;
+   SV_SHLST = $40;
+   SV_DRLST = $44;
+   SV_DDLST = $48;
+   SV_KEYQ = $4c;
+   SV_TRAPV = $50;
+   SV_BTPNT = $54;
+   SV_BTBAS = $58;
+   SV_BTTOP = $5c;
+   SV_JBTAG = $60;
+   SV_JBMAX = $62;
+   SV_JBPNT = $64;
+   SV_JBBAS = $68;
+   SV_JBTOP = $6c;
+   SV_CHTAG = $70;
+   SV_CHMAX = $72;
+   SV_CHPNT = $74;
+   SV_CHBAS = $78;
+   SV_CHTOP = $7c;
+   SV_CAPS = $88;
+   SV_ARBUF = $8a;
+   SV_ARDEL = $8c;
+   SV_ARFRQ = $8e;
+   SV_ARCNT = $90;
+   SV_CQCH = $92;
+   SV_SOUND = $96;
+   SV_SER1C = $98;
+   SV_SER2C = $9c;
+   SV_TMODE = $a0;
+   SV_PTYP = $a1;
+   SV_CSUB = $a2;
+   SV_TIMO = $a6;
+   SV_TIMOV = $a8;
+   SV_FSTAT = $aa;
+   SV_MDRUN = $ee;
+   SV_MDCNT = $ef;
+   SV_MDDID = $f0;
+   SV_MDSTA = $f8;
+   SV_FSDEF = $100;
+   SV_FSLST = $140;
+   SV_TOP = $180;
+
+
 type
 type
   Tqlfloat = array[0..5] of byte;
   Tqlfloat = array[0..5] of byte;
   Pqlfloat = ^Tqlfloat;
   Pqlfloat = ^Tqlfloat;
@@ -81,43 +143,13 @@ type
   PWindowDef = ^TWindowDef;
   PWindowDef = ^TWindowDef;
 
 
 
 
-{ the functions declared as external here are implemented in the system unit. They're included
-  here via externals, do avoid double implementation of assembler wrappers (KB) }
-
-procedure mt_frjob(jobID: Tjobid; exitCode: longint); external name '_mt_frjob';
-function mt_inf(sys_vars: ppchar; ver_ascii: plongint): Tjobid; external name '_mt_inf';
-
-procedure mt_dmode(s_mode: pword; d_type: pword); external name '_mt_dmode';
-
-function mt_alchp(size: dword; sizegot: pdword; jobid: Tjobid): pointer; external name '_mt_alchp';
-procedure mt_rechp(area: pointer); external name '_mt_rechp';
-
-function io_open_qlstr(name_qlstr: pointer; mode: longint): Tchanid; external name '_io_open_qlstr';
-function io_open(name: pchar; mode: longint): Tchanid; external name '_io_open';
-function io_close(chan: Tchanid): longint; external name '_io_close';
-function io_delet(name: pchar): longint; external name '_io_delet';
-
-function io_fbyte(chan: Tchanid; timeout: Ttimeout): longint; external name '_io_fbyte';
-function io_fline(chan: Tchanid; timeout: Ttimeout; buf: pointer; len: word): longint; external name '_io_fline';
-function io_fstrg(chan: Tchanid; timeout: Ttimeout; buf: pointer; len: word): longint; external name '_io_fstrg';
-function io_sbyte(chan: Tchanid; timeout: Ttimeout; c: char): longint; external name '_io_sbyte';
-function io_sstrg(chan: Tchanid; timeout: Ttimeout; buf: pointer; len: word): longint; external name '_io_sstrg';
-
-function fs_posab(chan: Tchanid; var new_pos: longint): longint; external name '_fs_posab';
-function fs_posre(chan: Tchanid; var new_pos: longint): longint; external name '_fs_posre';
-function fs_headr(chan: Tchanid; buf: pointer; buf_size: word): longint; external name '_fs_headr';
-function fs_rename_qlstr(chan: Tchanid; new_name_as_qlstr: pointer): longint; external name '_fs_rename_qlstr';
-function fs_rename(chan: Tchanid; new_name: pchar): longint; external name '_fs_rename';
-function fs_truncate(chan: Tchanid): longint; external name '_fs_truncate';
-function fs_mkdir(chan: Tchanid): longint; external name '_iof_mkdr'; { SMS }
-
-function sd_wdef(chan: Tchanid; timeout: Ttimeout; border_colour: byte; border_width: word; window: PQLRect): longint; external name '_sd_wdef'; 
-function sd_clear(chan: Tchanid; timeout: Ttimeout): longint; external name '_sd_clear';
+{ the functions declared in qdosfuncs.inc are implemented in the system unit. They're included
+  here via externals, do avoid double implementation of assembler wrappers. for this reason,
+  qdosfuncs.inc in packages/qlunits must be kept identical to the one in rtl/sinclairql (KB). }
 
 
-function ut_con(params: PWindowDef): Tchanid; external name '_ut_con';
-function ut_scr(params: PWindowDef): Tchanid; external name '_ut_scr';
+{$i qdosfuncs.inc}
 
 
-function mt_rclck: longint; external name '_mt_rclck';
+{ other functions, not used/implemented by the RTL }
 
 
 procedure sd_point(chan: Tchanid; timeout: Ttimeout; x: Pqlfloat; y: Pqlfloat);
 procedure sd_point(chan: Tchanid; timeout: Ttimeout; x: Pqlfloat; y: Pqlfloat);
 procedure sd_point(chan: Tchanid; timeout: Ttimeout; x: double; y: double);
 procedure sd_point(chan: Tchanid; timeout: Ttimeout; x: double; y: double);

+ 50 - 0
packages/qlunits/src/qdosfuncs.inc

@@ -0,0 +1,50 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2020-2021 by Karoly Balogh
+
+    Headers to QDOS OS functions used by the Sinclair QL RTL
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+
+
+procedure mt_frjob(jobID: Tjobid; exitCode: longint); external name '_mt_frjob';
+function mt_inf(sys_vars: ppchar; ver_ascii: plongint): Tjobid; external name '_mt_inf';
+
+procedure mt_dmode(s_mode: pword; d_type: pword); external name '_mt_dmode';
+
+function mt_alchp(size: dword; sizegot: pdword; jobid: Tjobid): pointer; external name '_mt_alchp';
+procedure mt_rechp(area: pointer); external name '_mt_rechp';
+
+function io_open_qlstr(name_qlstr: pointer; mode: longint): Tchanid; external name '_io_open_qlstr';
+function io_open(name: pchar; mode: longint): Tchanid; external name '_io_open';
+function io_close(chan: Tchanid): longint; external name '_io_close';
+function io_delet(name: pchar): longint; external name '_io_delet';
+
+function io_fbyte(chan: Tchanid; timeout: Ttimeout): longint; external name '_io_fbyte';
+function io_fline(chan: Tchanid; timeout: Ttimeout; buf: pointer; len: word): longint; external name '_io_fline';
+function io_fstrg(chan: Tchanid; timeout: Ttimeout; buf: pointer; len: word): longint; external name '_io_fstrg';
+function io_sbyte(chan: Tchanid; timeout: Ttimeout; c: char): longint; external name '_io_sbyte';
+function io_sstrg(chan: Tchanid; timeout: Ttimeout; buf: pointer; len: word): longint; external name '_io_sstrg';
+
+function fs_posab(chan: Tchanid; var new_pos: longint): longint; external name '_fs_posab';
+function fs_posre(chan: Tchanid; var new_pos: longint): longint; external name '_fs_posre';
+function fs_headr(chan: Tchanid; buf: pointer; buf_size: word): longint; external name '_fs_headr';
+function fs_rename_qlstr(chan: Tchanid; new_name_as_qlstr: pointer): longint; external name '_fs_rename_qlstr';
+function fs_rename(chan: Tchanid; new_name: pchar): longint; external name '_fs_rename';
+function fs_truncate(chan: Tchanid): longint; external name '_fs_truncate';
+function fs_mkdir(chan: Tchanid): longint; external name '_iof_mkdr'; { SMS }
+
+function sd_wdef(chan: Tchanid; timeout: Ttimeout; border_colour: byte; border_width: word; window: PQLRect): longint; external name '_sd_wdef'; 
+function sd_clear(chan: Tchanid; timeout: Ttimeout): longint; external name '_sd_clear';
+
+function ut_con(params: PWindowDef): Tchanid; external name '_ut_con';
+function ut_scr(params: PWindowDef): Tchanid; external name '_ut_scr';
+
+function mt_rclck: longint; external name '_mt_rclck';

+ 6 - 1
packages/qlunits/src/sms.pas

@@ -22,7 +22,12 @@ uses
   qdos;
   qdos;
 
 
 
 
-function iof_mkdr(chan: Tchanid): longint; external name '_iof_mkdr';
+{ the functions declared in smsfuncs.inc are implemented in the system unit. They're included
+  here via externals, do avoid double implementation of assembler wrappers. for this reason,
+  smsfuncs.inc in packages/qlunits must be kept identical to the one in rtl/sinclairql (KB). }
+
+{$i smsfuncs.inc}
+
 
 
 implementation
 implementation
 
 

+ 16 - 0
packages/qlunits/src/smsfuncs.inc

@@ -0,0 +1,16 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2021 by Karoly Balogh
+
+    Headers to SMS only OS functions used by the Sinclair QL RTL
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+
+function iof_mkdr(chan: Tchanid): longint; external name '_iof_mkdr';

+ 3 - 3
packages/rtl-extra/fpmake.pp

@@ -21,9 +21,9 @@ Const
 
 
   PrinterOSes   = [go32v2,msdos,os2,win32,win64]+unixlikes-[beos,haiku,morphos];
   PrinterOSes   = [go32v2,msdos,os2,win32,win64]+unixlikes-[beos,haiku,morphos];
   SerialOSes    = [android,linux,netbsd,openbsd,win32,win64];
   SerialOSes    = [android,linux,netbsd,openbsd,win32,win64];
-  UComplexOSes  = [atari,embedded,emx,gba,go32v2,msdos,nativent,nds,netware,netwlibc,os2,symbian,watcom,wii,wince,win32,win64,freertos]+UnixLikes+AllAmigaLikeOSes;
-  MatrixOSes    = [atari,embedded,emx,gba,go32v2,msdos,nativent,nds,netware,netwlibc,os2,symbian,watcom,wii,win32,win64,wince,freertos]+UnixLikes+AllAmigaLikeOSes;
-  ObjectsOSes   = [atari,embedded,emx,gba,go32v2,macosclassic,msdos,nds,netware,netwlibc,os2,symbian,watcom,wii,win16,win32,win64,wince,freertos]+UnixLikes+AllAmigaLikeOSes;
+  UComplexOSes  = [atari,embedded,emx,gba,go32v2,msdos,nativent,nds,netware,netwlibc,os2,sinclairql,symbian,watcom,wii,wince,win32,win64,freertos]+UnixLikes+AllAmigaLikeOSes;
+  MatrixOSes    = [atari,embedded,emx,gba,go32v2,msdos,nativent,nds,netware,netwlibc,os2,sinclairql,symbian,watcom,wii,win32,win64,wince,freertos]+UnixLikes+AllAmigaLikeOSes;
+  ObjectsOSes   = [atari,embedded,emx,gba,go32v2,macosclassic,msdos,nds,netware,netwlibc,os2,sinclairql,symbian,watcom,wii,win16,win32,win64,wince,freertos]+UnixLikes+AllAmigaLikeOSes;
   WinsockOSes   = [win32,win64,wince,os2,emx,netware,netwlibc];
   WinsockOSes   = [win32,win64,wince,os2,emx,netware,netwlibc];
   WinSock2OSes  = [win32,win64,wince];
   WinSock2OSes  = [win32,win64,wince];
   SocketsOSes   = UnixLikes+AllAmigaLikeOSes+[netware,netwlibc,os2,emx,wince,win32,win64];
   SocketsOSes   = UnixLikes+AllAmigaLikeOSes+[netware,netwlibc,os2,emx,wince,win32,win64];

+ 9 - 9
packages/rtl-objpas/fpmake.pp

@@ -15,22 +15,22 @@ Const
 //  AllUnixOSes  = [Linux,FreeBSD,NetBSD,OpenBSD,Darwin,QNX,BeOS,Solaris,Haiku,iphonesim,ios,aix,Android];
 //  AllUnixOSes  = [Linux,FreeBSD,NetBSD,OpenBSD,Darwin,QNX,BeOS,Solaris,Haiku,iphonesim,ios,aix,Android];
 //    unixlikes-[beos];
 //    unixlikes-[beos];
 //
 //
-  StrUtilsOSes  = [atari,emx,gba,go32v2,msdos,nds,netware,wince,nativent,os2,netwlibc,symbian,watcom,wii,win32,win64,freertos]+UnixLikes+AllAmigaLikeOSes;
-  VarUtilsOSes  = [atari,emx,gba,go32v2,msdos,nds,netware,wince,nativent,os2,netwlibc,symbian,watcom,wii,win32,win64,freertos]+UnixLikes+AllAmigaLikeOSes;
-  ConvUtilsOSes = [nativent,netware,netwlibc,win32,win64,wince]+AllAmigaLikeOSes+UnixLikes-[BeOS];
+  StrUtilsOSes  = [atari,emx,gba,go32v2,msdos,nds,netware,wince,nativent,os2,netwlibc,sinclairql,symbian,watcom,wii,win32,win64,freertos]+UnixLikes+AllAmigaLikeOSes;
+  VarUtilsOSes  = [atari,emx,gba,go32v2,msdos,nds,netware,wince,nativent,os2,netwlibc,sinclairql,symbian,watcom,wii,win32,win64,freertos]+UnixLikes+AllAmigaLikeOSes;
+  ConvUtilsOSes = [nativent,netware,netwlibc,sinclairql,win32,win64,wince]+AllAmigaLikeOSes+UnixLikes-[BeOS];
   ConvUtilOSes  = [atari,Go32v2,msdos,os2,emx,freertos,watcom];
   ConvUtilOSes  = [atari,Go32v2,msdos,os2,emx,freertos,watcom];
-  DateUtilsOSes = [gba,nativent,nds,netware,netwlibc,symbian,wii,win32,win64,wince,freertos]+UnixLikes+AllAmigaLikeOSes;
+  DateUtilsOSes = [gba,nativent,nds,netware,netwlibc,sinclairql,symbian,wii,win32,win64,wince,freertos]+UnixLikes+AllAmigaLikeOSes;
   DateUtilOSes  = [atari,Go32v2,msdos,os2,emx,freertos,watcom];
   DateUtilOSes  = [atari,Go32v2,msdos,os2,emx,freertos,watcom];
   StdConvsOSes  = [NativeNT,Win32,win64,os2,msdos,go32v2,freertos]+UnixLikes-[BeOS];
   StdConvsOSes  = [NativeNT,Win32,win64,os2,msdos,go32v2,freertos]+UnixLikes-[BeOS];
-  FmtBCDOSes    = [atari,emx,gba,go32v2,msdos,nativent,nds,netware,netwlibc,os2,symbian,watcom,wii,win32,win64,wince,freertos]+UnixLikes+AllAmigaLikeOSes;
-  VariantsOSes  = [atari,emx,gba,go32v2,msdos,nativent,nds,netware,netwlibc,os2,symbian,watcom,wii,win32,win64,wince,freertos]+UnixLikes+AllAmigaLikeOSes;
-  RttiOSes      = [atari,emx,gba,go32v2,msdos,nativent,nds,netware,netwlibc,os2,watcom,wii,win32,win64,wince,freertos]+UnixLikes+AllAmigaLikeOSes;
-  UItypesOSes   = [atari,emx,gba,go32v2,msdos,nativent,nds,netware,netwlibc,os2,watcom,wii,win32,win64,wince,freertos]+UnixLikes+AllAmigaLikeOSes-ConvUtilOSes;
+  FmtBCDOSes    = [atari,emx,gba,go32v2,msdos,nativent,nds,netware,netwlibc,os2,sinclairql,symbian,watcom,wii,win32,win64,wince,freertos]+UnixLikes+AllAmigaLikeOSes;
+  VariantsOSes  = [atari,emx,gba,go32v2,msdos,nativent,nds,netware,netwlibc,os2,sinclairql,symbian,watcom,wii,win32,win64,wince,freertos]+UnixLikes+AllAmigaLikeOSes;
+  RttiOSes      = [atari,emx,gba,go32v2,msdos,nativent,nds,netware,netwlibc,os2,sinclairql,watcom,wii,win32,win64,wince,freertos]+UnixLikes+AllAmigaLikeOSes;
+  UItypesOSes   = [atari,emx,gba,go32v2,msdos,nativent,nds,netware,netwlibc,os2,sinclairql,watcom,wii,win32,win64,wince,freertos]+UnixLikes+AllAmigaLikeOSes-ConvUtilOSes;
   AllTargetsObjPas = DateUtilsOses +DateUtilOSes+
   AllTargetsObjPas = DateUtilsOses +DateUtilOSes+
                   VarutilsOses + ConvutilsOSes + ConvutilOSes + StdConvsOSes+
                   VarutilsOses + ConvutilsOSes + ConvutilOSes + StdConvsOSes+
                   FmtBCDOSes + StrUtilsOSes + UITypesOSes;
                   FmtBCDOSes + StrUtilsOSes + UITypesOSes;
 
 
-  CommonSrcOSes = [atari,emx,gba,go32v2,msdos,nds,netware,wince,nativent,os2,netwlibc,symbian,watcom,wii,freertos]+UnixLikes+AllAmigaLikeOSes;
+  CommonSrcOSes = [atari,emx,gba,go32v2,msdos,nds,netware,wince,nativent,os2,netwlibc,sinclairql,symbian,watcom,wii,freertos]+UnixLikes+AllAmigaLikeOSes;
 
 
 Var
 Var
   P : TPackage;
   P : TPackage;

+ 12 - 0
packages/rtl-objpas/src/inc/rtti.pp

@@ -113,9 +113,11 @@ type
   public
   public
     class function Empty: TValue; static;
     class function Empty: TValue; static;
     class procedure Make(ABuffer: pointer; ATypeInfo: PTypeInfo; out result: TValue); static;
     class procedure Make(ABuffer: pointer; ATypeInfo: PTypeInfo; out result: TValue); static;
+    class procedure Make(AValue: NativeInt; ATypeInfo: PTypeInfo; out Result: TValue); static; inline;
     { Note: a TValue based on an open array is only valid until the routine having the open array parameter is left! }
     { Note: a TValue based on an open array is only valid until the routine having the open array parameter is left! }
     class procedure MakeOpenArray(AArray: Pointer; ALength: SizeInt; ATypeInfo: PTypeInfo; out Result: TValue); static;
     class procedure MakeOpenArray(AArray: Pointer; ALength: SizeInt; ATypeInfo: PTypeInfo; out Result: TValue); static;
 {$ifndef NoGenericMethods}
 {$ifndef NoGenericMethods}
+    generic class procedure Make<T>(const AValue: T; out Result: TValue); static; inline;
     generic class function From<T>(constref aValue: T): TValue; static; inline;
     generic class function From<T>(constref aValue: T): TValue; static; inline;
     { Note: a TValue based on an open array is only valid until the routine having the open array parameter is left! }
     { Note: a TValue based on an open array is only valid until the routine having the open array parameter is left! }
     generic class function FromOpenArray<T>(constref aValue: array of T): TValue; static; inline;
     generic class function FromOpenArray<T>(constref aValue: array of T): TValue; static; inline;
@@ -1722,6 +1724,11 @@ begin
   end;
   end;
 end;
 end;
 
 
+class procedure TValue.Make(AValue: NativeInt; ATypeInfo: PTypeInfo; out Result: TValue);
+begin
+  TValue.Make(@AValue, ATypeInfo, Result);
+end;
+
 class procedure TValue.MakeOpenArray(AArray: Pointer; ALength: SizeInt; ATypeInfo: PTypeInfo; out Result: TValue);
 class procedure TValue.MakeOpenArray(AArray: Pointer; ALength: SizeInt; ATypeInfo: PTypeInfo; out Result: TValue);
 var
 var
   el: TValue;
   el: TValue;
@@ -1749,6 +1756,11 @@ begin
 end;
 end;
 
 
 {$ifndef NoGenericMethods}
 {$ifndef NoGenericMethods}
+generic class procedure TValue.Make<T>(const AValue: T; out Result: TValue);
+begin
+  TValue.Make(@AValue, PTypeInfo(System.TypeInfo(T)), Result);
+end;
+
 generic class function TValue.From<T>(constref aValue: T): TValue;
 generic class function TValue.From<T>(constref aValue: T): TValue;
 begin
 begin
   TValue.Make(@aValue, PTypeInfo(System.TypeInfo(T)), Result);
   TValue.Make(@aValue, PTypeInfo(System.TypeInfo(T)), Result);

+ 245 - 29
packages/rtl-objpas/tests/tests.rtti.pas

@@ -78,6 +78,16 @@ type
     procedure TestMakeAnsiChar;
     procedure TestMakeAnsiChar;
     procedure TestMakeWideChar;
     procedure TestMakeWideChar;
 
 
+    procedure TestMakeNativeInt;
+
+    procedure TestMakeGenericNil;
+    procedure TestMakeGenericLongInt;
+    procedure TestMakeGenericString;
+    procedure TestMakeGenericObject;
+    procedure TestMakeGenericDouble;
+    procedure TestMakeGenericAnsiChar;
+    procedure TestMakeGenericWideChar;
+
     procedure TestFromOrdinal;
     procedure TestFromOrdinal;
 
 
     procedure TestDataSize;
     procedure TestDataSize;
@@ -104,6 +114,10 @@ type
     procedure MakeFromOrdinalSet;
     procedure MakeFromOrdinalSet;
     procedure MakeFromOrdinalString;
     procedure MakeFromOrdinalString;
     procedure MakeFromOrdinalNil;
     procedure MakeFromOrdinalNil;
+
+{$ifndef fpc}
+    procedure Ignore(const aMsg: String);
+{$endif}
   end;
   end;
 
 
 implementation
 implementation
@@ -302,6 +316,13 @@ begin
   CheckTrue(IsTestCaseClassFound, 'RTTI information does not contain class of testcase.');
   CheckTrue(IsTestCaseClassFound, 'RTTI information does not contain class of testcase.');
 end;*)
 end;*)
 
 
+{$ifndef fpc}
+procedure TTestCase1.Ignore(const aMsg: string);
+begin
+  { empty }
+end;
+{$endif}
+
 procedure TTestCase1.TestGetValueStringCastError;
 procedure TTestCase1.TestGetValueStringCastError;
 var
 var
   ATestClass : TTestValueClass;
   ATestClass : TTestValueClass;
@@ -552,7 +573,7 @@ var
 begin
 begin
   fs := 3.14;
   fs := 3.14;
 
 
-  TValue.Make(@fs, TypeInfo(fs), v);
+  TValue.Make(@fs, TypeInfo(Single), v);
   CheckEquals(v.IsClass, False);
   CheckEquals(v.IsClass, False);
   CheckEquals(v.IsObject, False);
   CheckEquals(v.IsObject, False);
   CheckEquals(v.IsOrdinal, False);
   CheckEquals(v.IsOrdinal, False);
@@ -586,7 +607,7 @@ var
 begin
 begin
   fd := 3.14;
   fd := 3.14;
 
 
-  TValue.Make(@fd, TypeInfo(fd), v);
+  TValue.Make(@fd, TypeInfo(Double), v);
   CheckEquals(v.IsClass, False);
   CheckEquals(v.IsClass, False);
   CheckEquals(v.IsObject, False);
   CheckEquals(v.IsObject, False);
   CheckEquals(v.IsOrdinal, False);
   CheckEquals(v.IsOrdinal, False);
@@ -620,7 +641,7 @@ var
 begin
 begin
   fe := 3.14;
   fe := 3.14;
 
 
-  TValue.Make(@fe, TypeInfo(fe), v);
+  TValue.Make(@fe, TypeInfo(Extended), v);
   CheckEquals(v.IsClass, False);
   CheckEquals(v.IsClass, False);
   CheckEquals(v.IsObject, False);
   CheckEquals(v.IsObject, False);
   CheckEquals(v.IsOrdinal, False);
   CheckEquals(v.IsOrdinal, False);
@@ -654,7 +675,7 @@ var
 begin
 begin
   fcu := 3.14;
   fcu := 3.14;
 
 
-  TValue.Make(@fcu, TypeInfo(fcu), v);
+  TValue.Make(@fcu, TypeInfo(Currency), v);
   CheckEquals(v.IsClass, False);
   CheckEquals(v.IsClass, False);
   CheckEquals(v.IsObject, False);
   CheckEquals(v.IsObject, False);
   CheckEquals(v.IsOrdinal, False);
   CheckEquals(v.IsOrdinal, False);
@@ -689,7 +710,7 @@ var
 begin
 begin
   fco := 314;
   fco := 314;
 
 
-  TValue.Make(@fco, TypeInfo(fco), v);
+  TValue.Make(@fco, TypeInfo(Comp), v);
 
 
   if v.Kind <> tkFloat then
   if v.Kind <> tkFloat then
     Exit;
     Exit;
@@ -726,11 +747,13 @@ var
 begin
 begin
   e := te1;
   e := te1;
 
 
-  TValue.Make(@e, TypeInfo(e), v);
+  TValue.Make(@e, TypeInfo(TTestEnum), v);
   Check(not v.IsClass);
   Check(not v.IsClass);
   Check(not v.IsArray);
   Check(not v.IsArray);
   Check(not v.IsEmpty);
   Check(not v.IsEmpty);
+{$ifdef fpc}
   Check(not v.IsOpenArray);
   Check(not v.IsOpenArray);
+{$endif}
   Check(not v.IsObject);
   Check(not v.IsObject);
   Check(v.IsOrdinal);
   Check(v.IsOrdinal);
 
 
@@ -745,11 +768,13 @@ var
 begin
 begin
   c := #20;
   c := #20;
 
 
-  TValue.Make(@c, TypeInfo(c), v);
+  TValue.Make(@c, TypeInfo(AnsiChar), v);
   Check(not v.IsClass);
   Check(not v.IsClass);
   Check(not v.IsArray);
   Check(not v.IsArray);
   Check(not v.IsEmpty);
   Check(not v.IsEmpty);
+{$ifdef fpc}
   Check(not v.IsOpenArray);
   Check(not v.IsOpenArray);
+{$endif}
   Check(not v.IsObject);
   Check(not v.IsObject);
   Check(v.IsOrdinal);
   Check(v.IsOrdinal);
 
 
@@ -765,11 +790,195 @@ var
 begin
 begin
   c := #$1234;
   c := #$1234;
 
 
-  TValue.Make(@c, TypeInfo(c), v);
+  TValue.Make(@c, TypeInfo(WideChar), v);
   Check(not v.IsClass);
   Check(not v.IsClass);
   Check(not v.IsArray);
   Check(not v.IsArray);
   Check(not v.IsEmpty);
   Check(not v.IsEmpty);
+{$ifdef fpc}
   Check(not v.IsOpenArray);
   Check(not v.IsOpenArray);
+{$endif}
+  Check(not v.IsObject);
+  Check(v.IsOrdinal);
+
+  Check(v.GetReferenceToRawData <> @c);
+  Check(WideChar(v.AsOrdinal) = #$1234);
+  Check(v.AsWideChar = #$1234);
+end;
+
+procedure TTestCase1.TestMakeNativeInt;
+var
+  fni: NativeInt;
+  s: AnsiString;
+  v: TValue;
+  o: TObject;
+begin
+  fni := 2021;
+
+  TValue.Make(fni, TypeInfo(LongInt), v);
+  CheckEquals(v.IsClass, False);
+  CheckEquals(v.IsObject, False);
+  CheckEquals(v.IsOrdinal, True);
+  Check(NativeInt(v.GetReferenceToRawData) <> fni);
+  CheckEquals(v.AsOrdinal, 2021);
+
+  s := 'Hello World';
+  TValue.Make(NativeInt(s), TypeInfo(AnsiString), v);
+  CheckEquals(v.IsClass, False);
+  CheckEquals(v.IsObject, False);
+  CheckEquals(v.IsOrdinal, False);
+  CheckEquals(v.AsString, s);
+
+  o := TObject.Create;
+  TValue.Make(NativeInt(o), TypeInfo(TObject), v);
+  CheckEquals(v.IsClass, False);
+  CheckEquals(v.IsObject, True);
+  CheckEquals(v.IsOrdinal, False);
+  Check(PPointer(v.GetReferenceToRawData)^ = Pointer(o));
+  Check(v.AsObject = o);
+  o.Free;
+end;
+
+procedure TTestCase1.TestMakeGenericNil;
+var
+  value: TValue;
+begin
+  TValue.{$ifdef fpc}specialize{$endif} Make<TObject>(Nil, value);
+  CheckTrue(value.IsEmpty);
+  CheckTrue(value.IsObject);
+  CheckTrue(value.IsClass);
+  CheckTrue(value.IsOrdinal);
+  CheckFalse(value.IsArray);
+  CheckTrue(value.AsObject=Nil);
+  CheckTrue(value.AsClass=Nil);
+  CheckTrue(value.AsInterface=Nil);
+  CheckEquals(0, value.AsOrdinal);
+
+  TValue.{$ifdef fpc}specialize{$endif} Make<TClass>(Nil, value);
+  CheckTrue(value.IsEmpty);
+  CheckTrue(value.IsClass);
+  CheckTrue(value.IsOrdinal);
+  CheckFalse(value.IsArray);
+  CheckTrue(value.AsObject=Nil);
+  CheckTrue(value.AsClass=Nil);
+  CheckTrue(value.AsInterface=Nil);
+  CheckEquals(0, value.AsOrdinal);
+end;
+
+procedure TTestCase1.TestMakeGenericLongInt;
+var
+  value: TValue;
+begin
+  TValue.{$ifdef fpc}specialize{$endif} Make<LongInt>(0, value);
+  CheckTrue(value.IsOrdinal);
+  CheckFalse(value.IsEmpty);
+  CheckFalse(value.IsClass);
+  CheckFalse(value.IsObject);
+  CheckFalse(value.IsArray);
+  CheckEquals(0, value.AsOrdinal);
+  CheckEquals(0, value.AsInteger);
+  CheckEquals(0, value.AsInt64);
+  CheckEquals(0, value.AsUInt64);
+end;
+
+procedure TTestCase1.TestMakeGenericString;
+var
+  value: TValue;
+begin
+  TValue.{$ifdef fpc}specialize{$endif} Make<String>('test', value);
+  CheckFalse(value.IsEmpty);
+  CheckFalse(value.IsObject);
+  CheckFalse(value.IsClass);
+  CheckFalse(value.IsArray);
+  CheckEquals('test', value.AsString);
+end;
+
+procedure TTestCase1.TestMakeGenericObject;
+var
+  value: TValue;
+  TestClass: TTestValueClass;
+begin
+  TestClass := TTestValueClass.Create;
+  TestClass.AInteger := 54329;
+  TValue.{$ifdef fpc}specialize{$endif} Make<TTestValueClass>(TestClass, value);
+  CheckEquals(value.IsClass, False);
+  CheckEquals(value.IsObject, True);
+  Check(value.AsObject=TestClass);
+  Check(PPointer(value.GetReferenceToRawData)^ = Pointer(TestClass));
+  CheckEquals(TTestValueClass(value.AsObject).AInteger, 54329);
+  TestClass.Free;
+end;
+
+procedure TTestCase1.TestMakeGenericDouble;
+var
+  fd: Double;
+  v: TValue;
+  hadexcept: Boolean;
+begin
+  fd := 3.14;
+
+  TValue.{$ifdef fpc}specialize{$endif} Make<Double>(fd, v);
+  CheckEquals(v.IsClass, False);
+  CheckEquals(v.IsObject, False);
+  CheckEquals(v.IsOrdinal, False);
+  Check(v.AsExtended=fd);
+  Check(v.GetReferenceToRawData <> @fd);
+
+  try
+    hadexcept := False;
+    v.AsInt64;
+  except
+    hadexcept := True;
+  end;
+
+  CheckTrue(hadexcept, 'No signed type conversion exception');
+
+  try
+    hadexcept := False;
+    v.AsUInt64;
+  except
+    hadexcept := True;
+  end;
+
+  CheckTrue(hadexcept, 'No unsigned type conversion exception');
+end;
+
+
+procedure TTestCase1.TestMakeGenericAnsiChar;
+var
+  c: AnsiChar;
+  v: TValue;
+begin
+  c := #20;
+
+  TValue.{$ifdef fpc}specialize{$endif} Make<AnsiChar>(c, v);
+  Check(not v.IsClass);
+  Check(not v.IsArray);
+  Check(not v.IsEmpty);
+{$ifdef fpc}
+  Check(not v.IsOpenArray);
+{$endif}
+  Check(not v.IsObject);
+  Check(v.IsOrdinal);
+
+  Check(v.GetReferenceToRawData <> @c);
+  Check(AnsiChar(v.AsOrdinal) = #20);
+  Check(v.AsAnsiChar = #20);
+end;
+
+procedure TTestCase1.TestMakeGenericWideChar;
+var
+  c: WideChar;
+  v: TValue;
+begin
+  c := #$1234;
+
+  TValue.{$ifdef fpc}specialize{$endif} Make<WideChar>(c, v);
+  Check(not v.IsClass);
+  Check(not v.IsArray);
+  Check(not v.IsEmpty);
+{$ifdef fpc}
+  Check(not v.IsOpenArray);
+{$endif}
   Check(not v.IsObject);
   Check(not v.IsObject);
   Check(v.IsOrdinal);
   Check(v.IsOrdinal);
 
 
@@ -880,9 +1089,13 @@ begin
   end;
   end;
 end;
 end;
 
 
-procedure TTestCase1.TestIsType;
 type
 type
   TMyLongInt = type LongInt;
   TMyLongInt = type LongInt;
+
+procedure TTestCase1.TestIsType;
+{ Delphi does not provide type information for local types :/ }
+{type
+  TMyLongInt = type LongInt;}
 var
 var
   v: TValue;
   v: TValue;
   l: LongInt;
   l: LongInt;
@@ -890,21 +1103,21 @@ var
 begin
 begin
   l := 42;
   l := 42;
   ml := 42;
   ml := 42;
-  TValue.Make(@l, TypeInfo(l), v);
-  Check(v.IsType(TypeInfo(l)));
-  Check(not v.IsType(TypeInfo(ml)));
+  TValue.Make(@l, TypeInfo(LongInt), v);
+  Check(v.IsType(TypeInfo(LongInt)));
+  Check(not v.IsType(TypeInfo(TMyLongInt)));
   Check(not v.IsType(TypeInfo(String)));
   Check(not v.IsType(TypeInfo(String)));
-  Check(v.specialize IsType<LongInt>);
-  Check(not v.specialize IsType<TMyLongInt>);
-  Check(not v.specialize IsType<String>);
+  Check(v.{$ifdef fpc}specialize{$endif} IsType<LongInt>);
+  Check(not v.{$ifdef fpc}specialize{$endif} IsType<TMyLongInt>);
+  Check(not v.{$ifdef fpc}specialize{$endif} IsType<String>);
 
 
-  TValue.Make(@ml, TypeInfo(ml), v);
-  Check(v.IsType(TypeInfo(ml)));
-  Check(not v.IsType(TypeInfo(l)));
+  TValue.Make(@ml, TypeInfo(TMyLongInt), v);
+  Check(v.IsType(TypeInfo(TMyLongInt)));
+  Check(not v.IsType(TypeInfo(LongInt)));
   Check(not v.IsType(TypeInfo(String)));
   Check(not v.IsType(TypeInfo(String)));
-  Check(v.specialize IsType<TMyLongInt>);
-  Check(not v.specialize IsType<LongInt>);
-  Check(not v.specialize IsType<String>);
+  Check(v.{$ifdef fpc}specialize{$endif} IsType<TMyLongInt>);
+  Check(not v.{$ifdef fpc}specialize{$endif} IsType<LongInt>);
+  Check(not v.{$ifdef fpc}specialize{$endif} IsType<String>);
 end;
 end;
 
 
 procedure TTestCase1.TestPropGetValueBoolean;
 procedure TTestCase1.TestPropGetValueBoolean;
@@ -1467,7 +1680,7 @@ begin
     try
     try
       ARttiType := c.GetType(ATestClass.ClassInfo);
       ARttiType := c.GetType(ATestClass.ClassInfo);
       AProperty := ARttiType.GetProperty('AObject');
       AProperty := ARttiType.GetProperty('AObject');
-      TypeInfo := GetPropInfo(ATestClass, 'AObject')^.PropType;
+      TypeInfo := GetPropInfo(ATestClass, 'AObject')^.PropType{$ifndef fpc}^{$endif};
 
 
       O := TPersistent.Create;
       O := TPersistent.Create;
       TValue.Make(@O, TypeInfo, AValue);
       TValue.Make(@O, TypeInfo, AValue);
@@ -1503,16 +1716,19 @@ begin
     try
     try
       ARttiType := c.GetType(ATestClass.ClassInfo);
       ARttiType := c.GetType(ATestClass.ClassInfo);
       AProperty := ARttiType.GetProperty('AUnknown');
       AProperty := ARttiType.GetProperty('AUnknown');
-      TypeInfo := GetPropInfo(ATestClass, 'AUnknown')^.PropType;
+      TypeInfo := GetPropInfo(ATestClass, 'AUnknown')^.PropType{$ifndef fpc}^{$endif};
 
 
       i := TInterfacedObject.Create;
       i := TInterfacedObject.Create;
       TValue.Make(@i, TypeInfo, AValue);
       TValue.Make(@i, TypeInfo, AValue);
       AProperty.SetValue(ATestClass, AValue);
       AProperty.SetValue(ATestClass, AValue);
       Check(ATestClass.AUnknown = i);
       Check(ATestClass.AUnknown = i);
 
 
+    {$ifdef fpc}
+      { Delphi does not provide an implicit assignment overload for IUnknown }
       i := TInterfacedObject.Create;
       i := TInterfacedObject.Create;
       AProperty.SetValue(ATestClass, i);
       AProperty.SetValue(ATestClass, i);
       Check(ATestClass.AUnknown = i);
       Check(ATestClass.AUnknown = i);
+    {$endif}
     finally
     finally
       AtestClass.Free;
       AtestClass.Free;
     end;
     end;
@@ -1542,7 +1758,7 @@ begin
       ARttiType := c.GetType(ATestClass.ClassInfo);
       ARttiType := c.GetType(ATestClass.ClassInfo);
 
 
       AProperty := ARttiType.GetProperty('ASingle');
       AProperty := ARttiType.GetProperty('ASingle');
-      TypeInfo := GetPropInfo(ATestClass, 'ASingle')^.PropType;
+      TypeInfo := GetPropInfo(ATestClass, 'ASingle')^.PropType{$ifndef fpc}^{$endif};
 
 
       S := 1.1;
       S := 1.1;
       TValue.Make(@S, TypeInfo, AValue);
       TValue.Make(@S, TypeInfo, AValue);
@@ -1554,7 +1770,7 @@ begin
       CheckEquals(S, ATestClass.ASingle, 0.001);
       CheckEquals(S, ATestClass.ASingle, 0.001);
 
 
       AProperty := ARttiType.GetProperty('ADouble');
       AProperty := ARttiType.GetProperty('ADouble');
-      TypeInfo := GetPropInfo(ATestClass, 'ADouble')^.PropType;
+      TypeInfo := GetPropInfo(ATestClass, 'ADouble')^.PropType{$ifndef fpc}^{$endif};
 
 
       D := 2.1;
       D := 2.1;
       TValue.Make(@D, TypeInfo, AValue);
       TValue.Make(@D, TypeInfo, AValue);
@@ -1566,7 +1782,7 @@ begin
       CheckEquals(D, ATestClass.ADouble, 0.001);
       CheckEquals(D, ATestClass.ADouble, 0.001);
 
 
       AProperty := ARttiType.GetProperty('AExtended');
       AProperty := ARttiType.GetProperty('AExtended');
-      TypeInfo := GetPropInfo(ATestClass, 'AExtended')^.PropType;
+      TypeInfo := GetPropInfo(ATestClass, 'AExtended')^.PropType{$ifndef fpc}^{$endif};
 
 
       E := 3.1;
       E := 3.1;
       TValue.Make(@E, TypeInfo, AValue);
       TValue.Make(@E, TypeInfo, AValue);
@@ -1578,7 +1794,7 @@ begin
       CheckEquals(E, ATestClass.AExtended, 0.001);
       CheckEquals(E, ATestClass.AExtended, 0.001);
 
 
       AProperty := ARttiType.GetProperty('ACurrency');
       AProperty := ARttiType.GetProperty('ACurrency');
-      TypeInfo := GetPropInfo(ATestClass, 'ACurrency')^.PropType;
+      TypeInfo := GetPropInfo(ATestClass, 'ACurrency')^.PropType{$ifndef fpc}^{$endif};
 
 
       Cur := 40;
       Cur := 40;
       TValue.Make(@Cur, TypeInfo, AValue);
       TValue.Make(@Cur, TypeInfo, AValue);
@@ -1590,7 +1806,7 @@ begin
       CheckEquals(Cur, ATestClass.ACurrency, 0.001);
       CheckEquals(Cur, ATestClass.ACurrency, 0.001);
 
 
       AProperty := ARttiType.GetProperty('AComp');
       AProperty := ARttiType.GetProperty('AComp');
-      TypeInfo := GetPropInfo(ATestClass, 'AComp')^.PropType;
+      TypeInfo := GetPropInfo(ATestClass, 'AComp')^.PropType{$ifndef fpc}^{$endif};
 
 
       Cmp := 50;
       Cmp := 50;
       TValue.Make(@Cmp, TypeInfo, AValue);
       TValue.Make(@Cmp, TypeInfo, AValue);
@@ -1625,7 +1841,7 @@ begin
     try
     try
       ARttiType := c.GetType(ATestClass.ClassInfo);
       ARttiType := c.GetType(ATestClass.ClassInfo);
       AProperty := ARttiType.GetProperty('AArray');
       AProperty := ARttiType.GetProperty('AArray');
-      TypeInfo := GetPropInfo(ATestClass, 'AArray')^.PropType;
+      TypeInfo := GetPropInfo(ATestClass, 'AArray')^.PropType{$ifndef fpc}^{$endif};
 
 
       A := [1, 2, 3, 4, 5];
       A := [1, 2, 3, 4, 5];
       TValue.Make(@A, TypeInfo, AValue);
       TValue.Make(@A, TypeInfo, AValue);

+ 49 - 5
packages/rtl-objpas/tests/tests.rtti.util.pas

@@ -1,6 +1,8 @@
 unit Tests.Rtti.Util;
 unit Tests.Rtti.Util;
 
 
+{$ifdef fpc}
 {$mode objfpc}{$H+}
 {$mode objfpc}{$H+}
+{$endif}
 
 
 interface
 interface
 
 
@@ -10,14 +12,22 @@ uses
 {$ifndef fpc}
 {$ifndef fpc}
 type
 type
   CodePointer = Pointer;
   CodePointer = Pointer;
+  PCodePointer = ^CodePointer;
+  SizeInt = NativeInt;
+  QWord = UInt64;
 
 
   TValueHelper = record helper for TValue
   TValueHelper = record helper for TValue
+    class procedure Make<T>(const aValue: T; var aResult: TValue); overload; static;
     function AsUnicodeString: UnicodeString;
     function AsUnicodeString: UnicodeString;
     function AsAnsiString: AnsiString;
     function AsAnsiString: AnsiString;
     function AsChar: Char; inline;
     function AsChar: Char; inline;
     function AsAnsiChar: AnsiChar;
     function AsAnsiChar: AnsiChar;
     function AsWideChar: WideChar;
     function AsWideChar: WideChar;
   end;
   end;
+
+  TTypeDataHelper = record helper for TTypeData
+    function SetSize: SizeInt; inline;
+  end;
 {$endif}
 {$endif}
 
 
 const
 const
@@ -42,7 +52,9 @@ function GetDoubleValue(aValue: Double): TValue;
 function GetExtendedValue(aValue: Extended): TValue;
 function GetExtendedValue(aValue: Extended): TValue;
 function GetCompValue(aValue: Comp): TValue;
 function GetCompValue(aValue: Comp): TValue;
 function GetCurrencyValue(aValue: Currency): TValue;
 function GetCurrencyValue(aValue: Currency): TValue;
+{$ifdef fpc}
 function GetArray(const aArg: array of SizeInt): TValue;
 function GetArray(const aArg: array of SizeInt): TValue;
+{$endif}
 
 
 implementation
 implementation
 
 
@@ -50,6 +62,11 @@ uses
   SysUtils, Math;
   SysUtils, Math;
 
 
 {$ifndef fpc}
 {$ifndef fpc}
+class procedure TValueHelper.Make<T>(const aValue: T; var aResult: TValue);
+begin
+  TValue.Make(@aValue, PTypeInfo(System.TypeInfo(T)), aResult);
+end;
+
 function TValueHelper.AsUnicodeString: UnicodeString;
 function TValueHelper.AsUnicodeString: UnicodeString;
 begin
 begin
   Result := UnicodeString(AsString);
   Result := UnicodeString(AsString);
@@ -60,24 +77,29 @@ begin
   Result := AnsiString(AsString);
   Result := AnsiString(AsString);
 end;
 end;
 
 
-function TValue.AsWideChar: WideChar;
+function TValueHelper.AsWideChar: WideChar;
 begin
 begin
   if Kind <> tkWideChar then
   if Kind <> tkWideChar then
     raise EInvalidCast.Create('Invalid cast');
     raise EInvalidCast.Create('Invalid cast');
   Result := WideChar(Word(AsOrdinal));
   Result := WideChar(Word(AsOrdinal));
 end;
 end;
 
 
-function TValue.AsAnsiChar: AnsiChar;
+function TValueHelper.AsAnsiChar: AnsiChar;
 begin
 begin
   if Kind <> tkChar then
   if Kind <> tkChar then
     raise EInvalidCast.Create('Invalid cast');
     raise EInvalidCast.Create('Invalid cast');
   Result := AnsiChar(Byte(AsOrdinal));
   Result := AnsiChar(Byte(AsOrdinal));
 end;
 end;
 
 
-function TValue.AsChar: Char;
+function TValueHelper.AsChar: Char;
 begin
 begin
   Result := AsWideChar;
   Result := AsWideChar;
 end;
 end;
+
+function TTypeDataHelper.SetSize: NativeInt;
+begin
+  Result := SetTypeOrSize;
+end;
 {$endif}
 {$endif}
 
 
 function CopyValue({$ifdef fpc}constref{$else}const [ref]{$endif} aValue: TValue): TValue;
 function CopyValue({$ifdef fpc}constref{$else}const [ref]{$endif} aValue: TValue): TValue;
@@ -105,7 +127,7 @@ var
 begin
 begin
 {$ifdef debug}
 {$ifdef debug}
   Writeln('Empty: ', aValue1.IsEmpty, ' ', aValue2.IsEmpty);
   Writeln('Empty: ', aValue1.IsEmpty, ' ', aValue2.IsEmpty);
-  Writeln('Kind: ', aValue1.Kind, ' ', aValue2.Kind);
+  Writeln('Kind: ', TypeKindToStr(aValue1.Kind), ' ', TypeKindToStr(aValue2.Kind));
   Writeln('Array: ', aValue1.IsArray, ' ', aValue2.IsArray);
   Writeln('Array: ', aValue1.IsArray, ' ', aValue2.IsArray);
 {$endif}
 {$endif}
   if aValue1.IsEmpty and aValue2.IsEmpty then
   if aValue1.IsEmpty and aValue2.IsEmpty then
@@ -120,7 +142,7 @@ begin
       for i := 0 to aValue1.GetArrayLength - 1 do
       for i := 0 to aValue1.GetArrayLength - 1 do
         if not EqualValues(aValue1.GetArrayElement(i), aValue2.GetArrayElement(i)) then begin
         if not EqualValues(aValue1.GetArrayElement(i), aValue2.GetArrayElement(i)) then begin
 {$ifdef debug}
 {$ifdef debug}
-          Writeln('Element ', i, ' differs: ', HexStr(aValue1.GetArrayElement(i).AsOrdinal, 4), ' ', HexStr(aValue2.GetArrayElement(i).AsOrdinal, 4));
+          Writeln('Element ', i, ' differs: ', IntToHex(aValue1.GetArrayElement(i).AsOrdinal, 4), ' ', IntToHex(aValue2.GetArrayElement(i).AsOrdinal, 4));
 {$endif}
 {$endif}
           Result := False;
           Result := False;
           Break;
           Break;
@@ -131,8 +153,10 @@ begin
     td1 := aValue1.TypeData;
     td1 := aValue1.TypeData;
     td2 := aValue2.TypeData;
     td2 := aValue2.TypeData;
     case aValue1.Kind of
     case aValue1.Kind of
+    {$ifdef fpc}
       tkBool:
       tkBool:
         Result := aValue1.AsBoolean xor not aValue2.AsBoolean;
         Result := aValue1.AsBoolean xor not aValue2.AsBoolean;
+    {$endif}
       tkSet:
       tkSet:
         if td1^.SetSize = td2^.SetSize then
         if td1^.SetSize = td2^.SetSize then
           if td1^.SetSize < SizeOf(SizeInt) then
           if td1^.SetSize < SizeOf(SizeInt) then
@@ -144,12 +168,16 @@ begin
       tkEnumeration,
       tkEnumeration,
       tkChar,
       tkChar,
       tkWChar,
       tkWChar,
+    {$ifdef fpc}
       tkUChar,
       tkUChar,
+    {$endif}
       tkInt64,
       tkInt64,
       tkInteger:
       tkInteger:
         Result := aValue1.AsOrdinal = aValue2.AsOrdinal;
         Result := aValue1.AsOrdinal = aValue2.AsOrdinal;
+    {$ifdef fpc}
       tkQWord:
       tkQWord:
         Result := aValue1.AsUInt64 = aValue2.AsUInt64;
         Result := aValue1.AsUInt64 = aValue2.AsUInt64;
+    {$endif}
       tkFloat:
       tkFloat:
         if td1^.FloatType <> td2^.FloatType then
         if td1^.FloatType <> td2^.FloatType then
           Result := False
           Result := False
@@ -167,9 +195,17 @@ begin
               Result := aValue1.AsCurrency = aValue2.AsCurrency;
               Result := aValue1.AsCurrency = aValue2.AsCurrency;
           end;
           end;
         end;
         end;
+    {$ifdef fpc}
       tkSString,
       tkSString,
+    {$else}
+      tkShortString,
+    {$endif}
       tkUString,
       tkUString,
+    {$ifdef fpc}
       tkAString,
       tkAString,
+    {$else}
+      tkAnsiString,
+    {$endif}
       tkWString:
       tkWString:
         Result := aValue1.AsString = aValue2.AsString;
         Result := aValue1.AsString = aValue2.AsString;
       tkDynArray,
       tkDynArray,
@@ -186,13 +222,21 @@ begin
       tkClass,
       tkClass,
       tkClassRef,
       tkClassRef,
       tkInterface,
       tkInterface,
+    {$ifdef fpc}
       tkInterfaceRaw,
       tkInterfaceRaw,
+    {$endif}
       tkPointer:
       tkPointer:
         Result := PPointer(aValue1.GetReferenceToRawData)^ = PPointer(aValue2.GetReferenceToRawData)^;
         Result := PPointer(aValue1.GetReferenceToRawData)^ = PPointer(aValue2.GetReferenceToRawData)^;
+    {$ifdef fpc}
       tkProcVar:
       tkProcVar:
+    {$else}
+      tkProcedure:
+    {$endif}
         Result := PCodePointer(aValue1.GetReferenceToRawData)^ = PCodePointer(aValue2.GetReferenceToRawData)^;
         Result := PCodePointer(aValue1.GetReferenceToRawData)^ = PCodePointer(aValue2.GetReferenceToRawData)^;
       tkRecord,
       tkRecord,
+    {$ifdef fpc}
       tkObject,
       tkObject,
+    {$endif}
       tkMethod,
       tkMethod,
       tkVariant: begin
       tkVariant: begin
         if aValue1.DataSize = aValue2.DataSize then
         if aValue1.DataSize = aValue2.DataSize then

+ 2 - 2
rtl/aarch64/math.inc

@@ -51,7 +51,7 @@
     {$endif FPC_SYSTEM_HAS_SQRT}
     {$endif FPC_SYSTEM_HAS_SQRT}
 
 
 
 
-{$ifndef VER3_2}
+{$if not defined(VER3_2) and not defined(CPULLVM)}
     {$ifndef FPC_SYSTEM_HAS_FRAC}
     {$ifndef FPC_SYSTEM_HAS_FRAC}
     {$define FPC_SYSTEM_HAS_FRAC}
     {$define FPC_SYSTEM_HAS_FRAC}
     function fpc_frac_real(d : ValReal) : ValReal;compilerproc;
     function fpc_frac_real(d : ValReal) : ValReal;compilerproc;
@@ -61,7 +61,7 @@
         result:=0;
         result:=0;
       end;
       end;
     {$endif FPC_SYSTEM_HAS_FRAC}
     {$endif FPC_SYSTEM_HAS_FRAC}
-{$endif VER3_2}
+{$endif not VER3_2 and not CPULLVM }
 
 
 
 
     {$ifndef FPC_SYSTEM_HAS_INT}
     {$ifndef FPC_SYSTEM_HAS_INT}

+ 21 - 0
rtl/darwin/pthread.inc

@@ -84,3 +84,24 @@ function pthread_mutexattr_destroy(_para1:Ppthread_mutexattr_t):cint;cdecl;exter
 function pthread_mutexattr_gettype(_para1:Ppthread_mutexattr_t; _para2:Pcint):cint;cdecl;external 'c' name 'pthread_mutexattr_gettype';
 function pthread_mutexattr_gettype(_para1:Ppthread_mutexattr_t; _para2:Pcint):cint;cdecl;external 'c' name 'pthread_mutexattr_gettype';
 function pthread_mutexattr_settype(_para1:Ppthread_mutexattr_t; _para2:cint):cint;cdecl;external 'c' name 'pthread_mutexattr_settype';
 function pthread_mutexattr_settype(_para1:Ppthread_mutexattr_t; _para2:cint):cint;cdecl;external 'c' name 'pthread_mutexattr_settype';
 function pthread_cond_timedwait(__cond:ppthread_cond_t; __mutex:ppthread_mutex_t; __abstime:ptimespec):cint; cdecl;external 'c' name 'pthread_cond_timedwait';
 function pthread_cond_timedwait(__cond:ppthread_cond_t; __mutex:ppthread_mutex_t; __abstime:ptimespec):cint; cdecl;external 'c' name 'pthread_cond_timedwait';
+
+var
+  // available in macOS 10.6 / iOS 3.2 and higher
+  pthread_setname_np: function(name: PAnsiChar):cint;cdecl;
+
+var
+  PthreadDLL: Pointer;
+
+function LoadPthreads: Boolean;
+begin
+  PThreadDLL:=DlOpen('libSystem.dylib',RTLD_LAZY);
+  Result:=PThreadDLL<>Nil;
+  if not Result then
+    exit;
+  Pointer(pthread_setname_np):=dlsym(PthreadDLL,'pthread_setname_np');
+end;
+
+function UnLoadPthreads: Boolean;
+begin
+  Result:=dlclose(PThreadDLL)=0;
+end;

+ 9 - 8
rtl/inc/genmath.inc

@@ -1435,6 +1435,12 @@ end;
       hfsq,f,s,z,R,w,t1,t2,dk: double;
       hfsq,f,s,z,R,w,t1,t2,dk: double;
       k,hx,i,j: longint;
       k,hx,i,j: longint;
       lx: longword;
       lx: longword;
+{$push}
+{ if we have to check manually fpu exceptions, then force the exit statements here to
+  throw one }
+{$CHECKFPUEXCEPTIONS+}
+{ turn off fastmath as it converts (d-d)/zero into 0 and thus not raising an exception }
+{$OPTIMIZATION NOFASTMATH}
     begin
     begin
       hx := float64high(d);
       hx := float64high(d);
       lx := float64low(d);
       lx := float64low(d);
@@ -1443,20 +1449,15 @@ end;
       if (hx < $00100000) then              { x < 2**-1022  }
       if (hx < $00100000) then              { x < 2**-1022  }
       begin
       begin
         if (((hx and $7fffffff) or longint(lx))=0) then
         if (((hx and $7fffffff) or longint(lx))=0) then
-          begin
-            float_raise(float_flag_divbyzero);
-            exit(-two54/zero);                { log(+-0)=-inf }
-          end;
+          exit(-two54/zero);                { log(+-0)=-inf }
         if (hx<0) then
         if (hx<0) then
-          begin
-            float_raise(float_flag_invalid);
-            exit((d-d)/zero);                 { log(-#) = NaN }
-          end;
+          exit((d-d)/zero);                 { log(-#) = NaN }
         dec(k, 54); d := d * two54;         { subnormal number, scale up x }
         dec(k, 54); d := d * two54;         { subnormal number, scale up x }
         hx := float64high(d);
         hx := float64high(d);
       end;
       end;
       if (hx >= $7ff00000) then
       if (hx >= $7ff00000) then
         exit(d+d);
         exit(d+d);
+{$pop}
       inc(k, (hx shr 20)-1023);
       inc(k, (hx shr 20)-1023);
       hx := hx and $000fffff;
       hx := hx and $000fffff;
       i := (hx + $95f64) and $100000;
       i := (hx + $95f64) and $100000;

+ 21 - 0
rtl/inc/systemh.inc

@@ -1447,6 +1447,27 @@ procedure SetTextCodePage(var T: Text; CodePage: TSystemCodePage);
 {$ifdef FPC_HAS_FEATURE_UNICODESTRINGS}
 {$ifdef FPC_HAS_FEATURE_UNICODESTRINGS}
 Function GetFullName(var T:Text) : UnicodeString;
 Function GetFullName(var T:Text) : UnicodeString;
 {$endif FPC_HAS_FEATURE_UNICODESTRINGS}
 {$endif FPC_HAS_FEATURE_UNICODESTRINGS}
+procedure SetTextAutoFlush (var T: Text; AutoFlush: boolean);
+(* By default, output to text files is buffered in case of "regular" files,  *)
+(* i.e. files on regular block devices, and not buffered in case of various  *)
+(* other devices like console or sockets. Calling this procedure right after *)
+(* opening the file (i.e. after Rewrite or Append) allows changing the       *)
+(* default behaviour either to always perform flush after every Write or     *)
+(* WriteLn in case of AutoFlush = true, i.e. disable output buffering for    *)
+(* the given particular open text file even in case of regular files on      *)
+(* block devices, or to enforce output buffering even in case of text files  *)
+(* used for output to other devices like console or sockets in case of       *)
+(* AutoFlush = false. Note that reopening the file resets the behaviour to   *)
+(* the default. Runtime error 103 is triggered if the text file is not open, *)
+(* runtime error 105 if the text file is open strictly for input. The call   *)
+(* is ignored if InOutRes is not 0 before the call.                          *)
+function GetTextAutoFlush (var T: Text): boolean;
+(* Check whether output buffering is enabled for the currently open file, or *)
+(* not - either due to default behaviour for the associated device, or due   *)
+(* a previous call of SetTextAutoFlush. Runtime error 103 is triggered if    *)
+(* the text file is not open, runtime error 105 if the text file is open     *)
+(* strictly for input. The call is ignored if InOutRes is not 0 before the   *)
+(* call.                                                                     *)
 {$endif FPC_HAS_FEATURE_TEXTIO}
 {$endif FPC_HAS_FEATURE_TEXTIO}
 
 
 {****************************************************************************
 {****************************************************************************

+ 36 - 0
rtl/inc/text.inc

@@ -614,6 +614,42 @@ begin
 end;
 end;
 
 
 
 
+procedure SetTextAutoFlush (var T: Text; AutoFlush: boolean);[IOCheck];
+Begin
+  If InOutRes<>0 then
+   exit;
+  if TextRec(T).mode<>fmOutput then
+   begin
+     if TextRec(T).mode=fmInput then
+      InOutRes:=105
+     else
+      InOutRes:=103;
+     exit;
+   end;
+  if AutoFlush then
+   TextRec(T).FlushFunc := TextRec(T).InOutFunc
+  else
+   TextRec(T).FlushFunc := nil;
+End;
+
+
+function GetTextAutoFlush (var T: Text): boolean;[IOCheck];
+Begin
+  GetTextAutoFlush := false;
+  If InOutRes<>0 then
+   exit;
+  if TextRec(t).mode<>fmOutput then
+   begin
+     if TextRec(t).mode=fmInput then
+      InOutRes:=105
+     else
+      InOutRes:=103;
+     exit;
+   end;
+  GetTextAutoFlush := Assigned (TextRec(T).FlushFunc);
+End;
+
+
 Function fpc_get_input:PText;compilerproc;
 Function fpc_get_input:PText;compilerproc;
 begin
 begin
   fpc_get_input:=@Input;
   fpc_get_input:=@Input;

+ 3 - 3
rtl/objpas/sysutils/dati.inc

@@ -1141,7 +1141,7 @@ var
             end ;
             end ;
             'H':
             'H':
               if isInterval then
               if isInterval then
-                StoreInt(Hour + trunc(abs(DateTime))*24, 0)
+                StoreInt(Hour + trunc(abs(DateTime))*24, Count)
               else
               else
               if Clock12 then
               if Clock12 then
               begin
               begin
@@ -1159,14 +1159,14 @@ var
                   StoreInt(Hour, 2);
                   StoreInt(Hour, 2);
               end;
               end;
             'N': if isInterval then
             'N': if isInterval then
-                   StoreInt(Minute + (Hour + trunc(abs(DateTime))*24)*60, 0)
+                   StoreInt(Minute + (Hour + trunc(abs(DateTime))*24)*60, Count)
                  else
                  else
                  if Count = 1 then
                  if Count = 1 then
                    StoreInt(Minute, 0)
                    StoreInt(Minute, 0)
                  else
                  else
                    StoreInt(Minute, 2);
                    StoreInt(Minute, 2);
             'S': if isInterval then
             'S': if isInterval then
-                   StoreInt(Second + (Minute + (Hour + trunc(abs(DateTime))*24)*60)*60, 0)
+                   StoreInt(Second + (Minute + (Hour + trunc(abs(DateTime))*24)*60)*60, Count)
                  else
                  else
                  if Count = 1 then
                  if Count = 1 then
                    StoreInt(Second, 0)
                    StoreInt(Second, 0)

+ 1 - 1
rtl/sinclairql/Makefile

@@ -3622,7 +3622,7 @@ include $(INC)/makefile.inc
 SYSINCDEPS=$(addprefix $(INC)/,$(SYSINCNAMES))
 SYSINCDEPS=$(addprefix $(INC)/,$(SYSINCNAMES))
 include $(PROCINC)/makefile.cpu
 include $(PROCINC)/makefile.cpu
 SYSCPUDEPS=$(addprefix $(PROCINC)/,$(CPUINCNAMES))
 SYSCPUDEPS=$(addprefix $(PROCINC)/,$(CPUINCNAMES))
-SYSDEPS=$(SYSINCDEPS) $(SYSCPUDEPS) qdos.inc qdosfuncs.inc sms.inc
+SYSDEPS=$(SYSINCDEPS) $(SYSCPUDEPS) qdos.inc qdosh.inc qdosfuncs.inc sms.inc
 $(SYSTEMUNIT)$(PPUEXT) : $(SYSTEMUNIT).pp $(SYSDEPS)
 $(SYSTEMUNIT)$(PPUEXT) : $(SYSTEMUNIT).pp $(SYSDEPS)
 	$(COMPILER) $(FPC_SYSTEM_OPT) -Us -Sg @rtl.cfg $(SYSTEMUNIT).pp $(REDIR)
 	$(COMPILER) $(FPC_SYSTEM_OPT) -Us -Sg @rtl.cfg $(SYSTEMUNIT).pp $(REDIR)
 uuchar$(PPUEXT): $(SYSTEMUNIT)$(PPUEXT) $(INC)/uuchar.pp
 uuchar$(PPUEXT): $(SYSTEMUNIT)$(PPUEXT) $(INC)/uuchar.pp

+ 1 - 1
rtl/sinclairql/Makefile.fpc

@@ -71,7 +71,7 @@ include $(PROCINC)/makefile.cpu
 SYSCPUDEPS=$(addprefix $(PROCINC)/,$(CPUINCNAMES))
 SYSCPUDEPS=$(addprefix $(PROCINC)/,$(CPUINCNAMES))
 
 
 # Put system unit dependencies together.
 # Put system unit dependencies together.
-SYSDEPS=$(SYSINCDEPS) $(SYSCPUDEPS) qdos.inc qdosfuncs.inc sms.inc
+SYSDEPS=$(SYSINCDEPS) $(SYSCPUDEPS) qdos.inc qdosh.inc qdosfuncs.inc sms.inc
 
 
 
 
 #
 #

+ 1 - 2
rtl/sinclairql/qdosfuncs.inc

@@ -1,6 +1,6 @@
 {
 {
     This file is part of the Free Pascal run time library.
     This file is part of the Free Pascal run time library.
-    Copyright (c) 2020 by Karoly Balogh
+    Copyright (c) 2020-2021 by Karoly Balogh
 
 
     Headers to QDOS OS functions used by the Sinclair QL RTL
     Headers to QDOS OS functions used by the Sinclair QL RTL
 
 
@@ -13,7 +13,6 @@
 
 
  **********************************************************************}
  **********************************************************************}
 
 
-{$i qdosh.inc}
 
 
 procedure mt_frjob(jobID: Tjobid; exitCode: longint); external name '_mt_frjob';
 procedure mt_frjob(jobID: Tjobid; exitCode: longint); external name '_mt_frjob';
 function mt_inf(sys_vars: ppchar; ver_ascii: plongint): Tjobid; external name '_mt_inf';
 function mt_inf(sys_vars: ppchar; ver_ascii: plongint): Tjobid; external name '_mt_inf';

+ 2 - 1
rtl/sinclairql/si_prc.pp

@@ -19,6 +19,7 @@ interface
 
 
 implementation
 implementation
 
 
+{$i qdosh.inc}
 {$i qdosfuncs.inc}
 {$i qdosfuncs.inc}
 
 
 var
 var
@@ -79,7 +80,7 @@ asm
     move.l (a1)+,d7
     move.l (a1)+,d7
     beq @noreloc
     beq @noreloc
 
 
-{.$DEFINE PACKEDRELOCS}
+{$DEFINE PACKEDRELOCS}
 {$IFNDEF PACKEDRELOCS}
 {$IFNDEF PACKEDRELOCS}
 @relocloop:
 @relocloop:
     { we read the offsets and relocate them }
     { we read the offsets and relocate them }

+ 73 - 18
rtl/sinclairql/sysutils.pp

@@ -53,6 +53,7 @@ uses
 { Include platform independent implementation part }
 { Include platform independent implementation part }
 {$i sysutils.inc}
 {$i sysutils.inc}
 
 
+{$i qdosh.inc}
 {$i qdosfuncs.inc}
 {$i qdosfuncs.inc}
 {$i smsfuncs.inc}
 {$i smsfuncs.inc}
 
 
@@ -65,9 +66,17 @@ uses
 (****** non portable routines ******)
 (****** non portable routines ******)
 
 
 function FileOpen(const FileName: rawbytestring; Mode: Integer): THandle;
 function FileOpen(const FileName: rawbytestring; Mode: Integer): THandle;
+var
+  QLMode: Integer;
 begin
 begin
   FileOpen:=-1;
   FileOpen:=-1;
-  if FileOpen < -1 then
+  case Mode of
+    fmOpenRead: QLMode := Q_OPEN_IN;
+    fmOpenWrite: QLMode :=  Q_OPEN_OVER;
+    fmOpenReadWrite: QLMode := Q_OPEN;
+  end;
+  FileOpen := io_open(pchar(Filename), QLMode);
+  if FileOpen < 0 then
     FileOpen:=-1;
     FileOpen:=-1;
 end;
 end;
 
 
@@ -99,8 +108,9 @@ end;
 
 
 function FileCreate(const FileName: RawByteString) : THandle;
 function FileCreate(const FileName: RawByteString) : THandle;
 begin
 begin
-  FileCreate:=-1;
-  if FileCreate < -1 then
+  DeleteFile(FileName);
+  FileCreate := io_open(pchar(FileName), Q_OPEN_NEW);
+  if FileCreate < 0 then
     FileCreate:=-1;
     FileCreate:=-1;
 end;
 end;
 
 
@@ -119,12 +129,12 @@ end;
 
 
 function FileRead(Handle: THandle; out Buffer; Count: LongInt): LongInt;
 function FileRead(Handle: THandle; out Buffer; Count: LongInt): LongInt;
 begin
 begin
-  FileRead:=-1;
   if (Count<=0) then
   if (Count<=0) then
     exit;
     exit;
 
 
-  FileRead:=-1;
-  if FileRead < -1 then
+  { io_fstrg handles EOF }
+  FileRead := io_fstrg(Handle, -1, @Buffer, Count);
+  if FileRead < 0 then
     FileRead:=-1;
     FileRead:=-1;
 end;
 end;
 
 
@@ -134,9 +144,8 @@ begin
   FileWrite:=-1;
   FileWrite:=-1;
   if (Count<=0) then 
   if (Count<=0) then 
     exit;
     exit;
-
-  FileWrite:=-1;
-  if FileWrite < -1 then
+  FileWrite:= io_sstrg(Handle, -1, @Buffer, Count);
+  if FileWrite < 0 then
     FileWrite:=-1;
     FileWrite:=-1;
 end;
 end;
 
 
@@ -144,42 +153,88 @@ end;
 function FileSeek(Handle: THandle; FOffset, Origin: LongInt) : LongInt;
 function FileSeek(Handle: THandle; FOffset, Origin: LongInt) : LongInt;
 var
 var
   dosResult: longint;
   dosResult: longint;
-begin
-  FileSeek:=-1;
+  seekEOF: longint;
+begin
+  FileSeek := -1;
+
+  case Origin of
+    fsFromBeginning: dosResult := fs_posab(Handle, FOffset);
+    fsFromCurrent: dosResult := fs_posre(Handle, FOffset);
+    fsFromEnd: 
+      begin
+        seekEOF := $7FFFFFBF;
+        dosResult := fs_posab(Handle, seekEOF);
+        fOffset := -FOffset;
+        dosResult := fs_posre(Handle, FOffset);
+      end;  
+  end;
 
 
-  dosResult:=-1;
-  if dosResult < 0 then
-    exit;
+  { We might need to handle Errors in dosResult, but
+    EOF is permitted as a non-error in QDOS/SMSQ. }
+  if dosResult = ERR_EF then
+    dosResult := 0;
 
 
-  FileSeek:=dosResult;
+  if dosResult <> 0 then
+    begin
+      FileSeek := -1;
+      exit;
+    end;
+
+  { However, BEWARE! FS_POSAB/FS_POSRE use FOFFSET as a VAR parameter.
+    the new file position is returned in FOFFSET. }
+
+  { Did we change FOffset? }
+  FileSeek := FOffset;
 end;
 end;
 
 
 function FileSeek(Handle: THandle; FOffset: Int64; Origin: Longint): Int64;
 function FileSeek(Handle: THandle; FOffset: Int64; Origin: Longint): Int64;
+var
+  longOffset: longint;
 begin
 begin
-  FileSeek:=FileSeek(Handle,LongInt(FOffset),Origin);
+  longOffset := longint(FOffset);
+  FileSeek:=FileSeek(Handle, longOffset, Origin);
+  flush(output);
 end;
 end;
 
 
 
 
 procedure FileClose(Handle: THandle);
 procedure FileClose(Handle: THandle);
 begin
 begin
+  io_close(Handle);
 end;
 end;
 
 
 
 
 function FileTruncate(Handle: THandle; Size: Int64): Boolean;
 function FileTruncate(Handle: THandle; Size: Int64): Boolean;
 begin
 begin
-  FileTruncate:=False;
+  FileTruncate := False;
+  if FileSeek(Handle, LongInt(Size), fsFromBeginning) = -1 then
+    exit;
+  if fs_truncate(Handle) = 0 then
+    FileTruncate := True;
 end;
 end;
 
 
-
 function DeleteFile(const FileName: RawByteString) : Boolean;
 function DeleteFile(const FileName: RawByteString) : Boolean;
 begin
 begin
   DeleteFile:=false;
   DeleteFile:=false;
+  if io_delet(pchar(Filename)) < 0 then
+    exit;
+  DeleteFile := True;
 end;
 end;
 
 
 
 
 function RenameFile(const OldName, NewName: RawByteString): Boolean;
 function RenameFile(const OldName, NewName: RawByteString): Boolean;
+var
+  Handle: THandle;
+  QLerr: longint;
 begin
 begin
   RenameFile:=false;
   RenameFile:=false;
+  Handle := FileOpen(OldName, fmOpenReadWrite);
+  if Handle = -1 then
+    exit;
+
+  QLerr := fs_rename(Handle, pchar(NewName));
+  FileClose(Handle);
+  if QLerr >= 0 then
+    RenameFile := true; 
 end;
 end;
 
 
 
 

+ 20 - 0
rtl/unix/cthreads.pp

@@ -60,6 +60,10 @@ interface
  {$endif darwin}
  {$endif darwin}
 {$endif}
 {$endif}
 
 
+{$if defined(Darwin) or defined(iphonesim)}
+  {$define dynpthreads}
+{$endif darwin}
+
 {$define basicevents_with_pthread_cond}
 {$define basicevents_with_pthread_cond}
 
 
 Procedure SetCThreadManager;
 Procedure SetCThreadManager;
@@ -544,6 +548,15 @@ Type  PINTRTLEvent = ^TINTRTLEvent;
           pthread_setname_np(pthread_t(threadHandle), @CuttedName[1]);
           pthread_setname_np(pthread_t(threadHandle), @CuttedName[1]);
         end;
         end;
       end;
       end;
+{$elseif defined(Darwin) or defined(iphonesim)}
+  {$ifdef dynpthreads}
+      if Assigned(pthread_setname_np) then
+  {$endif dynpthreads}
+      begin
+        // only allowed to set from within the thread
+        if threadHandle=TThreadID(-1) then
+          pthread_setname_np(@ThreadName[1]);
+      end;
 {$else}
 {$else}
        {$Warning SetThreadDebugName needs to be implemented}
        {$Warning SetThreadDebugName needs to be implemented}
 {$endif}
 {$endif}
@@ -559,6 +572,13 @@ Type  PINTRTLEvent = ^TINTRTLEvent;
       begin
       begin
         CSetThreadDebugNameA(threadHandle, AnsiString(ThreadName));
         CSetThreadDebugNameA(threadHandle, AnsiString(ThreadName));
       end;
       end;
+{$elseif defined(Darwin) or defined(iphonesim)}
+  {$ifdef dynpthreads}
+      if Assigned(pthread_setname_np) then
+  {$endif dynpthreads}
+      begin
+        CSetThreadDebugNameA(threadHandle, AnsiString(ThreadName));
+      end;
 {$else}
 {$else}
        {$Warning SetThreadDebugName needs to be implemented}
        {$Warning SetThreadDebugName needs to be implemented}
 {$endif}
 {$endif}

+ 1 - 1
tests/Makefile

@@ -2421,7 +2421,7 @@ endif
 TEST_OUTPUTDIR=output/$(TEST_TARGETSUFFIX)
 TEST_OUTPUTDIR=output/$(TEST_TARGETSUFFIX)
 C_SUBDIR=$(TEST_OS_TARGET)/$(TEST_CPU_TARGET)
 C_SUBDIR=$(TEST_OS_TARGET)/$(TEST_CPU_TARGET)
 ifneq ($(DATE),__missing_command_DATE)
 ifneq ($(DATE),__missing_command_DATE)
-TEST_DATETIME:=$(shell $(DATE) +%Y%m%d%H%M)
+TEST_DATETIME:=$(shell $(DATE) -u +%Y%m%d%H%M)
 else
 else
 TEST_DATETIME="No-date"
 TEST_DATETIME="No-date"
 endif
 endif

+ 1 - 1
tests/Makefile.fpc

@@ -111,7 +111,7 @@ C_SUBDIR=$(TEST_OS_TARGET)/$(TEST_CPU_TARGET)
 
 
 # Date and time the testsuite was run
 # Date and time the testsuite was run
 ifneq ($(DATE),__missing_command_DATE)
 ifneq ($(DATE),__missing_command_DATE)
-TEST_DATETIME:=$(shell $(DATE) +%Y%m%d%H%M)
+TEST_DATETIME:=$(shell $(DATE) -u +%Y%m%d%H%M)
 else
 else
 # Use a spaceless string, as it will be used for file names
 # Use a spaceless string, as it will be used for file names
 TEST_DATETIME="No-date"
 TEST_DATETIME="No-date"

+ 469 - 0
tests/bench/bdiv.pp

@@ -0,0 +1,469 @@
+{ %OPT=-O2 }
+program bdiv;
+
+{$mode objfpc}{$H+}
+
+uses
+  SysUtils;
+
+{ Utility functions }
+function GetRealTime(const st: TSystemTime): Real;
+  begin
+    Result := st.Hour*3600.0 + st.Minute*60.0 + st.Second + st.MilliSecond/1000.0;
+  end;
+
+{$push}
+{$warn 5057 off}
+function GetRealTime : Real;
+  var
+    st:TSystemTime;
+  begin
+    GetLocalTime(st);
+    result:=GetRealTime(st);
+  end;
+{$pop}
+
+const
+  ITERATIONS = 524288;
+  INTERNAL_LOOPS = 64;
+
+{ TTestAncestor }
+type
+  TTestAncestor = class
+    private
+      FStartTime: Real;
+      FEndTime: Real;
+      FAvgTime: Real;
+      procedure SetStartTime;
+      procedure SetEndTime;
+    protected
+      procedure DoTestIteration(Iteration: Integer); virtual; abstract;
+    public
+      constructor Create; virtual;
+      destructor Destroy; override;
+      procedure Run;
+      function TestTitle: shortstring; virtual; abstract;
+      function WriteResults: Boolean; virtual; abstract;
+      property RunTime: Real read FAvgTime;
+  end;
+
+  TTestClass = class of TTestAncestor;
+
+  TUInt32DivTest = class(TTestAncestor)
+    protected
+      FInputArray: array[$00..$FF] of Cardinal;
+      FResultArray: array[$00..$FF] of Cardinal;
+      function GetDivisor: Cardinal; virtual; abstract;
+      function DoVariableDiv(Numerator: Cardinal): Cardinal; inline;
+    public
+      function WriteResults: Boolean; override;
+  end;
+
+  TUInt32ModTest = class(TUInt32DivTest)
+    protected
+      function DoVariableMod(Numerator: Cardinal): Cardinal; inline;
+    public
+      function WriteResults: Boolean; override;
+  end;
+
+  TSInt32DivTest = class(TTestAncestor)
+    protected
+      FInputArray: array[$00..$FF] of Integer;
+      FResultArray: array[$00..$FF] of Integer;
+      function GetDivisor: Integer; virtual; abstract;
+      function DoVariableDiv(Numerator: Integer): Integer; inline;
+    public
+      function WriteResults: Boolean; override;
+  end;
+
+  TSInt32ModTest = class(TSInt32DivTest)
+    protected
+      function DoVariableMod(Numerator: Integer): Integer; inline;
+    public
+      function WriteResults: Boolean; override;
+  end;
+
+  TUInt64DivTest = class(TTestAncestor)
+    protected
+      FInputArray: array[$00..$FF] of QWord;
+      FResultArray: array[$00..$FF] of QWord;
+      function GetDivisor: QWord; virtual; abstract;
+      function DoVariableDiv(Numerator: QWord): QWord; inline;
+    public
+      function WriteResults: Boolean; override;
+  end;
+
+  TUInt64ModTest = class(TUInt64DivTest)
+    protected
+      function DoVariableMod(Numerator: QWord): QWord; inline;
+    public
+      function WriteResults: Boolean; override;
+  end;
+
+  TSInt64DivTest = class(TTestAncestor)
+    protected
+      FInputArray: array[$00..$FF] of Int64;
+      FResultArray: array[$00..$FF] of Int64;
+      function GetDivisor: Int64; virtual; abstract;
+      function DoVariableDiv(Numerator: Int64): Int64; inline;
+    public
+      function WriteResults: Boolean; override;
+  end;
+
+  TSInt64ModTest = class(TSInt64DivTest)
+    protected
+      function DoVariableMod(Numerator: Int64): Int64; inline;
+    public
+      function WriteResults: Boolean; override;
+  end;
+
+{$I bdiv_u32.inc}
+{$I bdiv_u64.inc}
+{$I bdiv_s32.inc}
+{$I bdiv_s64.inc}
+
+{ TTestAncestor }
+
+constructor TTestAncestor.Create;
+  begin
+    FStartTime := 0;
+    FEndTime := 0;
+    FAvgTime := 0;
+  end;
+
+destructor TTestAncestor.Destroy;
+  begin
+    inherited Destroy;
+  end;
+
+procedure TTestAncestor.SetStartTime;
+  begin
+    FStartTime := GetRealTime();
+  end;
+
+procedure TTestAncestor.SetEndTime;
+  begin
+    FEndTime := GetRealTime();
+    if FEndTime < FStartTime then { Happens if the test runs past midnight }
+      FEndTime := FEndTime + 86400.0;
+  end;
+
+procedure TTestAncestor.Run;
+  var
+    X: Integer;
+  begin
+    SetStartTime;
+    for X := 0 to ITERATIONS - 1 do
+      DoTestIteration(X);
+
+    SetEndTime;
+
+    FAvgTime := FEndTime - FStartTime;
+  end;
+
+{ TUInt32DivTest }
+
+function TUInt32DivTest.DoVariableDiv(Numerator: Cardinal): Cardinal;
+  begin
+    Result := Numerator div GetDivisor;
+  end;
+
+function TUInt32DivTest.WriteResults: Boolean;
+  var
+    X: Integer;
+    Expected: Cardinal;
+  begin
+    Result := True;
+    for X := 0 to 255 do
+      begin
+        Expected := DoVariableDiv(FInputArray[X]);
+        if FResultArray[X] <> Expected then
+          begin
+            WriteLn('FAIL - ', FInputArray[X], ' div ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
+            Result := False;
+            Exit;
+          end;
+      end;
+  end;
+
+{ TUInt32ModTest }
+
+function TUInt32ModTest.DoVariableMod(Numerator: Cardinal): Cardinal;
+  begin
+    Result := Numerator mod GetDivisor;
+  end;
+
+function TUInt32ModTest.WriteResults: Boolean;
+  var
+    X: Integer;
+    Expected: Cardinal;
+  begin
+    Result := True;
+    for X := 0 to 255 do
+      begin
+        Expected := DoVariableMod(FInputArray[X]);
+        if FResultArray[X] <> Expected then
+          begin
+            WriteLn('FAIL - ', FInputArray[X], ' mod ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
+            Result := False;
+            Exit;
+          end;
+      end;
+  end;
+
+{ TSInt32DivTest }
+
+function TSInt32DivTest.DoVariableDiv(Numerator: Integer): Integer;
+  begin
+    Result := Numerator div GetDivisor;
+  end;
+
+function TSInt32DivTest.WriteResults: Boolean;
+  var
+    X: Integer;
+    Expected: Integer;
+  begin
+    Result := True;
+    for X := 0 to 255 do
+      begin
+        Expected := DoVariableDiv(FInputArray[X]);
+        if FResultArray[X] <> Expected then
+          begin
+            WriteLn('FAIL - ', FInputArray[X], ' div ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
+            Result := False;
+            Exit;
+          end;
+      end;
+  end;
+
+{ TSInt32ModTest }
+
+function TSInt32ModTest.DoVariableMod(Numerator: Integer): Integer;
+  begin
+    Result := Numerator mod GetDivisor;
+  end;
+
+function TSInt32ModTest.WriteResults: Boolean;
+  var
+    X: Integer;
+    Expected: Integer;
+  begin
+    Result := True;
+    for X := 0 to 255 do
+      begin
+        Expected := DoVariableMod(FInputArray[X]);
+        if FResultArray[X] <> Expected then
+          begin
+            WriteLn('FAIL - ', FInputArray[X], ' mod ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
+            Result := False;
+            Exit;
+          end;
+      end;
+  end;
+
+{ TUInt64DivTest }
+
+function TUInt64DivTest.DoVariableDiv(Numerator: QWord): QWord;
+  begin
+    Result := Numerator div GetDivisor;
+  end;
+
+function TUInt64DivTest.WriteResults: Boolean;
+  var
+    X: Integer;
+    Expected: QWord;
+  begin
+    Result := True;
+    for X := 0 to 255 do
+      begin
+        Expected := DoVariableDiv(FInputArray[X]);
+        if FResultArray[X] <> Expected then
+          begin
+            WriteLn('FAIL - ', FInputArray[X], ' div ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
+            Result := False;
+            Exit;
+          end;
+      end;
+  end;
+
+{ TUInt64ModTest }
+
+function TUInt64ModTest.DoVariableMod(Numerator: QWord): QWord;
+  begin
+    Result := Numerator mod GetDivisor;
+  end;
+
+function TUInt64ModTest.WriteResults: Boolean;
+  var
+    X: Integer;
+    Expected: QWord;
+  begin
+    Result := True;
+    for X := 0 to 255 do
+      begin
+        Expected := DoVariableMod(FInputArray[X]);
+        if FResultArray[X] <> Expected then
+          begin
+            WriteLn('FAIL - ', FInputArray[X], ' mod ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
+            Result := False;
+            Exit;
+          end;
+      end;
+  end;
+
+{ TSInt64DivTest }
+
+function TSInt64DivTest.DoVariableDiv(Numerator: Int64): Int64;
+  begin
+    Result := Numerator div GetDivisor;
+  end;
+
+function TSInt64DivTest.WriteResults: Boolean;
+  var
+    X: Integer;
+    Expected: Int64;
+  begin
+    Result := True;
+    for X := 0 to 255 do
+      begin
+        Expected := DoVariableDiv(FInputArray[X]);
+        if FResultArray[X] <> Expected then
+          begin
+            WriteLn('FAIL - ', FInputArray[X], ' div ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
+            Result := False;
+            Exit;
+          end;
+      end;
+  end;
+
+{ TSInt64ModTest }
+
+function TSInt64ModTest.DoVariableMod(Numerator: Int64): Int64;
+  begin
+    Result := Numerator mod GetDivisor;
+  end;
+
+function TSInt64ModTest.WriteResults: Boolean;
+  var
+    X: Integer;
+    Expected: Int64;
+  begin
+    Result := True;
+    for X := 0 to 255 do
+      begin
+        Expected := DoVariableMod(FInputArray[X]);
+        if FResultArray[X] <> Expected then
+          begin
+            WriteLn('FAIL - ', FInputArray[X], ' mod ', GetDivisor, '; expected ', Expected, ' got ', FResultArray[X]);
+            Result := False;
+            Exit;
+          end;
+      end;
+  end;
+
+{ Main function }
+const
+  TestClasses: array[0..53] of TTestClass = (
+    TUInt32Bit1Test,
+    TUInt32Bit1ModTest,
+    TUInt32Bit2Test,
+    TUInt32Bit2ModTest,
+    TUInt32Bit3Test,
+    TUInt32Bit3ModTest,
+    TUInt32Bit10Test,
+    TUInt32Bit10ModTest,
+    TUInt32Bit100Test,
+    TUInt32Bit100ModTest,
+    TUInt32Bit1000Test,
+    TUInt32Bit1000ModTest,
+    TUInt32Bit60000Test,
+    TUInt32Bit60000ModTest,
+    TUInt32Bit146097Test,
+    TUInt32Bit146097ModTest,
+    TUInt32Bit3600000Test,
+    TUInt32Bit3600000ModTest,
+    TUInt64Bit1Test,
+    TUInt64Bit1ModTest,
+    TUInt64Bit2Test,
+    TUInt64Bit2ModTest,
+    TUInt64Bit3Test,
+    TUInt64Bit3ModTest,
+    TUInt64Bit5Test,
+    TUInt64Bit5ModTest,
+    TUInt64Bit10Test,
+    TUInt64Bit10ModTest,
+    TUInt64Bit100Test,
+    TUInt64Bit100ModTest,
+    TUInt64Bit1000000000Test,
+    TUInt64Bit1000000000ModTest,
+    TSInt32Bit1Test,
+    TSInt32Bit1ModTest,
+    TSInt32Bit100Test,
+    TSInt32Bit100ModTest,
+    TSInt64Bit1Test,
+    TSInt64Bit1ModTest,
+    TSInt64Bit10Test,
+    TSInt64Bit10ModTest,
+    TSInt64Bit18Test,
+    TSInt64Bit18ModTest,
+    TSInt64Bit24Test,
+    TSInt64Bit24ModTest,
+    TSInt64Bit100Test,
+    TSInt64Bit100ModTest,
+    TSInt64Bit153Test,
+    TSInt64Bit153ModTest,
+    TSInt64Bit1461Test,
+    TSInt64Bit1461ModTest,
+    TSInt64Bit10000Test,
+    TSInt64Bit10000ModTest,
+    TSInt64Bit86400000Test,
+    TSInt64Bit86400000ModTest
+  );
+
+var
+  CurrentObject: TTestAncestor;
+  Failed: Boolean;
+  X: Integer;
+  SummedUpAverageDuration, AverageDuration : Double;
+begin
+  SummedUpAverageDuration := 0.0;
+  Failed := False;
+  WriteLn('Division compilation and timing test (using constants from System and Sysutils)');
+  WriteLn('-------------------------------------------------------------------------------');
+  for X := Low(TestClasses) to High(TestClasses) do
+    begin
+      try
+        CurrentObject := TestClasses[X].Create;
+        try
+          Write(CurrentObject.TestTitle:43, ' - ');
+          CurrentObject.Run;
+
+          if CurrentObject.WriteResults then
+            begin
+              AverageDuration := ((CurrentObject.RunTime * 1000000000.0) / (ITERATIONS * INTERNAL_LOOPS));
+              WriteLn('Pass - average iteration duration: ', AverageDuration:1:3, ' ns');
+              SummedUpAverageDuration := SummedUpAverageDuration + AverageDuration;
+            end
+          else
+            { Final average isn't processed if a test failed, so there's no need
+              to calculate and add the average duration to it }
+            Failed := True;
+
+        finally
+          CurrentObject.Free;
+        end;
+      except on E: Exception do
+        begin
+          WriteLn('Exception "', E.ClassName, '" raised while running test object of class "', TestClasses[X].ClassName, '"');
+          Failed := True;
+        end;
+      end;
+    end;
+
+  if Failed then
+    Halt(1);
+
+  WriteLn(#10'ok');
+  WriteLn('- Sum of average durations: ', SummedUpAverageDuration:1:3, ' ns');
+  WriteLn('- Overall average duration: ', (SummedUpAverageDuration / Length(TestClasses)):1:3, ' ns');
+end.

+ 208 - 0
tests/bench/bdiv_s32.inc

@@ -0,0 +1,208 @@
+type
+  { TSInt32Bit1Test }
+
+  TSInt32Bit1Test = class(TSInt32DivTest)
+    protected
+      function GetDivisor: Integer; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TSInt32Bit1ModTest }
+
+  TSInt32Bit1ModTest = class(TSInt32ModTest)
+    protected
+      function GetDivisor: Integer; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TSInt32Bit100Test }
+
+  TSInt32Bit100Test = class(TSInt32DivTest)
+    protected
+      function GetDivisor: Integer; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TSInt32Bit100ModTest }
+
+  TSInt32Bit100ModTest = class(TSInt32ModTest)
+    protected
+      function GetDivisor: Integer; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+{ TSInt32Bit1Test }
+
+function TSInt32Bit1Test.TestTitle: shortstring;
+  begin
+    Result := 'Signed 32-bit division by 1';
+  end;
+
+function TSInt32Bit1Test.GetDivisor: Integer;
+  begin
+    Result := 1;
+  end;
+
+procedure TSInt32Bit1Test.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Integer;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      0:
+        Numerator := -2147483648;
+      1:
+        Numerator := -2147483600;
+      2:
+        Numerator := -2147483599;
+      253:
+        Numerator := 2147483599;
+      254:
+        Numerator := 2147483600;
+      255:
+        Numerator := 2147483647;
+      else
+        Numerator := Index - 128;
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator div 1;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TSInt32Bit1ModTest }
+
+function TSInt32Bit1ModTest.TestTitle: shortstring;
+  begin
+    Result := 'Signed 32-bit modulus by 1';
+  end;
+
+function TSInt32Bit1ModTest.GetDivisor: Integer;
+  begin
+    Result := 1;
+  end;
+
+procedure TSInt32Bit1ModTest.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Integer;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      0:
+        Numerator := -2147483648;
+      1:
+        Numerator := -2147483600;
+      2:
+        Numerator := -2147483599;
+      253:
+        Numerator := 2147483599;
+      254:
+        Numerator := 2147483600;
+      255:
+        Numerator := 2147483647;
+      else
+        Numerator := Index - 128;
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator mod 1;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TSInt32Bit100Test }
+
+function TSInt32Bit100Test.TestTitle: shortstring;
+  begin
+    Result := 'Signed 32-bit division by 100';
+  end;
+
+function TSInt32Bit100Test.GetDivisor: Integer;
+  begin
+    Result := 100;
+  end;
+
+procedure TSInt32Bit100Test.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Integer;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      0:
+        Numerator := -2147483648;
+      1:
+        Numerator := -2147483600;
+      2:
+        Numerator := -2147483599;
+      253:
+        Numerator := 2147483599;
+      254:
+        Numerator := 2147483600;
+      255:
+        Numerator := 2147483647;
+      else
+        Numerator := Index - 128;
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator div 100;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TSInt32Bit100ModTest }
+
+function TSInt32Bit100ModTest.TestTitle: shortstring;
+  begin
+    Result := 'Signed 32-bit modulus by 100';
+  end;
+
+function TSInt32Bit100ModTest.GetDivisor: Integer;
+  begin
+    Result := 100;
+  end;
+
+procedure TSInt32Bit100ModTest.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Integer;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      0:
+        Numerator := -2147483648;
+      1:
+        Numerator := -2147483600;
+      2:
+        Numerator := -2147483599;
+      253:
+        Numerator := 2147483599;
+      254:
+        Numerator := 2147483600;
+      255:
+        Numerator := 2147483647;
+      else
+        Numerator := Index - 128;
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator mod 100;
+      
+    FResultArray[Index] := Answer;
+  end;

+ 772 - 0
tests/bench/bdiv_s64.inc

@@ -0,0 +1,772 @@
+type
+  { TSInt64Bit1Test }
+
+  TSInt64Bit1Test = class(TSInt64DivTest)
+    protected
+      function GetDivisor: Int64; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TSInt64Bit1ModTest }
+
+  TSInt64Bit1ModTest = class(TSInt64ModTest)
+    protected
+      function GetDivisor: Int64; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TSInt64Bit10Test }
+
+  TSInt64Bit10Test = class(TSInt64DivTest)
+    protected
+      function GetDivisor: Int64; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TSInt64Bit10ModTest }
+
+  TSInt64Bit10ModTest = class(TSInt64ModTest)
+    protected
+      function GetDivisor: Int64; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TSInt64Bit18Test }
+
+  TSInt64Bit18Test = class(TSInt64DivTest)
+    protected
+      function GetDivisor: Int64; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TSInt64Bit18ModTest }
+
+  TSInt64Bit18ModTest = class(TSInt64ModTest)
+    protected
+      function GetDivisor: Int64; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TSInt64Bit24Test }
+
+  TSInt64Bit24Test = class(TSInt64DivTest)
+    protected
+      function GetDivisor: Int64; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TSInt64Bit24ModTest }
+
+  TSInt64Bit24ModTest = class(TSInt64ModTest)
+    protected
+      function GetDivisor: Int64; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TSInt64Bit100Test }
+
+  TSInt64Bit100Test = class(TSInt64DivTest)
+    protected
+      function GetDivisor: Int64; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TSInt64Bit100ModTest }
+
+  TSInt64Bit100ModTest = class(TSInt64ModTest)
+    protected
+      function GetDivisor: Int64; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TSInt64Bit153Test }
+const
+  FS64_153Input: array[$0..$F] of Int64 =
+    (0, 1, 152, 153, 154, -1, -152, -153, -154,
+    8000000000000000117, 8000000000000000118, 8000000000000000119, 
+    -8000000000000000117, -8000000000000000118, -8000000000000000119,
+    Int64($8000000000000000));
+
+type
+  TSInt64Bit153Test = class(TSInt64DivTest)
+    protected
+      function GetDivisor: Int64; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TSInt64Bit153ModTest }
+
+  TSInt64Bit153ModTest = class(TSInt64ModTest)
+    protected
+      function GetDivisor: Int64; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TSInt64Bit1461Test }
+const
+  FS64_1461Input: array[$0..$F] of Int64 =
+    (0, 1, 1460, 1461, 1462, -1, -1460, -1461, -1462,
+    8000000000000000582, 8000000000000000583, 8000000000000000584, 
+    -8000000000000000582, -8000000000000000583, -8000000000000000584,
+    Int64($8000000000000000));
+
+type
+  TSInt64Bit1461Test = class(TSInt64DivTest)
+    protected
+      function GetDivisor: Int64; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TSInt64Bit1461ModTest }
+
+  TSInt64Bit1461ModTest = class(TSInt64ModTest)
+    protected
+      function GetDivisor: Int64; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TSInt64Bit10000Test }
+const
+  FS64_10000Input: array[$0..$F] of Int64 =
+    (0, 1, 9999, 10000, 10001, -1, -9999, -10000, -10001,
+    7999999999999999999, 8000000000000000000, 8000000000000000001, 
+    -7999999999999999999, -8000000000000000000, -8000000000000000001,
+    Int64($8000000000000000));
+
+type
+  TSInt64Bit10000Test = class(TSInt64DivTest)
+    protected
+      function GetDivisor: Int64; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TSInt64Bit10000ModTest }
+
+  TSInt64Bit10000ModTest = class(TSInt64ModTest)
+    protected
+      function GetDivisor: Int64; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+  
+  { TSInt64Bit86400000Test }
+const
+  FS64_86400000Input: array[$0..$F] of Int64 =
+    (0, 1, 86399999, 86400000, 86400001, -1, -86399999, -86400000, -86400001,
+    8639999999999999999, 8640000000000000000, 8640000000000000001, 
+    -8639999999999999999, -8640000000000000000, -8640000000000000001,
+    Int64($8000000000000000));
+
+type
+  TSInt64Bit86400000Test = class(TSInt64DivTest)
+    protected
+      function GetDivisor: Int64; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TSInt64Bit86400000ModTest }
+
+  TSInt64Bit86400000ModTest = class(TSInt64ModTest)
+    protected
+      function GetDivisor: Int64; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+{ TSInt64Bit1Test }
+
+function TSInt64Bit1Test.TestTitle: shortstring;
+  begin
+    Result := 'Signed 64-bit division by 1';
+  end;
+
+function TSInt64Bit1Test.GetDivisor: Int64;
+  begin
+    Result := 1;
+  end;
+
+procedure TSInt64Bit1Test.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Int64;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      0:
+        Numerator := Int64($8000000000000000);
+      1:
+        Numerator := Int64($8000000000000006);
+      2:
+        Numerator := Int64($8000000000000007);
+      253:
+        Numerator := Int64($7FFFFFFFFFFFFFF9);
+      254:
+        Numerator := Int64($7FFFFFFFFFFFFFFA);
+      255:
+        Numerator := Int64($7FFFFFFFFFFFFFFF);
+      else
+        Numerator := Index - 128;
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator div 1;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TSInt64Bit1ModTest }
+
+function TSInt64Bit1ModTest.TestTitle: shortstring;
+  begin
+    Result := 'Signed 64-bit modulus by 1';
+  end;
+
+function TSInt64Bit1ModTest.GetDivisor: Int64;
+  begin
+    Result := 1;
+  end;
+
+procedure TSInt64Bit1ModTest.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Int64;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      0:
+        Numerator := Int64($8000000000000000);
+      1:
+        Numerator := Int64($8000000000000006);
+      2:
+        Numerator := Int64($8000000000000007);
+      253:
+        Numerator := Int64($7FFFFFFFFFFFFFF9);
+      254:
+        Numerator := Int64($7FFFFFFFFFFFFFFA);
+      255:
+        Numerator := Int64($7FFFFFFFFFFFFFFF);
+      else
+        Numerator := Index - 128;
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator mod 1;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TSInt64Bit10Test }
+
+function TSInt64Bit10Test.TestTitle: shortstring;
+  begin
+    Result := 'Signed 64-bit division by 10';
+  end;
+
+function TSInt64Bit10Test.GetDivisor: Int64;
+  begin
+    Result := 10;
+  end;
+
+procedure TSInt64Bit10Test.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Int64;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      0:
+        Numerator := Int64($8000000000000000);
+      1:
+        Numerator := Int64($8000000000000006);
+      2:
+        Numerator := Int64($8000000000000007);
+      253:
+        Numerator := Int64($7FFFFFFFFFFFFFF9);
+      254:
+        Numerator := Int64($7FFFFFFFFFFFFFFA);
+      255:
+        Numerator := Int64($7FFFFFFFFFFFFFFF);
+      else
+        Numerator := Index - 128;
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator div 10;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TSInt64Bit10ModTest }
+
+function TSInt64Bit10ModTest.TestTitle: shortstring;
+  begin
+    Result := 'Signed 64-bit modulus by 10';
+  end;
+
+function TSInt64Bit10ModTest.GetDivisor: Int64;
+  begin
+    Result := 10;
+  end;
+
+procedure TSInt64Bit10ModTest.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Int64;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      0:
+        Numerator := Int64($8000000000000000);
+      1:
+        Numerator := Int64($8000000000000006);
+      2:
+        Numerator := Int64($8000000000000007);
+      253:
+        Numerator := Int64($7FFFFFFFFFFFFFF9);
+      254:
+        Numerator := Int64($7FFFFFFFFFFFFFFA);
+      255:
+        Numerator := Int64($7FFFFFFFFFFFFFFF);
+      else
+        Numerator := Index - 128;
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator mod 10;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TSInt64Bit18Test }
+
+function TSInt64Bit18Test.TestTitle: shortstring;
+  begin
+    Result := 'Signed 64-bit division by 18';
+  end;
+
+function TSInt64Bit18Test.GetDivisor: Int64;
+  begin
+    Result := 18;
+  end;
+
+procedure TSInt64Bit18Test.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Int64;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    Numerator := Index - 128;
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator div 18;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TSInt64Bit18ModTest }
+
+function TSInt64Bit18ModTest.TestTitle: shortstring;
+  begin
+    Result := 'Signed 64-bit modulus by 18';
+  end;
+
+function TSInt64Bit18ModTest.GetDivisor: Int64;
+  begin
+    Result := 18;
+  end;
+
+procedure TSInt64Bit18ModTest.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Int64;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    Numerator := Index - 128;
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator mod 18;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TSInt64Bit24Test }
+
+function TSInt64Bit24Test.TestTitle: shortstring;
+  begin
+    Result := 'Signed 64-bit division by 24';
+  end;
+
+function TSInt64Bit24Test.GetDivisor: Int64;
+  begin
+    Result := 24;
+  end;
+
+procedure TSInt64Bit24Test.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Int64;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    Numerator := Index - 128;
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator div 24;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TSInt64Bit24ModTest }
+
+function TSInt64Bit24ModTest.TestTitle: shortstring;
+  begin
+    Result := 'Signed 64-bit modulus by 24';
+  end;
+
+function TSInt64Bit24ModTest.GetDivisor: Int64;
+  begin
+    Result := 24;
+  end;
+
+procedure TSInt64Bit24ModTest.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Int64;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    Numerator := Index - 128;
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator mod 24;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TSInt64Bit100Test }
+
+function TSInt64Bit100Test.TestTitle: shortstring;
+  begin
+    Result := 'Signed 64-bit division by 100';
+  end;
+
+function TSInt64Bit100Test.GetDivisor: Int64;
+  begin
+    Result := 100;
+  end;
+
+procedure TSInt64Bit100Test.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Int64;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      0:
+        Numerator := Int64($8000000000000000);
+      1:
+        Numerator := Int64($8000000000000008);
+      2:
+        Numerator := Int64($8000000000000009);
+      253:
+        Numerator := Int64($7FFFFFFFFFFFFFF7);
+      254:
+        Numerator := Int64($7FFFFFFFFFFFFFF8);
+      255:
+        Numerator := Int64($7FFFFFFFFFFFFFFF);
+      else
+        Numerator := Index - 128;
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator div 100;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TSInt64Bit100ModTest }
+
+function TSInt64Bit100ModTest.TestTitle: shortstring;
+  begin
+    Result := 'Signed 64-bit modulus by 100';
+  end;
+
+function TSInt64Bit100ModTest.GetDivisor: Int64;
+  begin
+    Result := 100;
+  end;
+
+procedure TSInt64Bit100ModTest.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Int64;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      0:
+        Numerator := Int64($8000000000000000);
+      1:
+        Numerator := Int64($8000000000000008);
+      2:
+        Numerator := Int64($8000000000000009);
+      253:
+        Numerator := Int64($7FFFFFFFFFFFFFF7);
+      254:
+        Numerator := Int64($7FFFFFFFFFFFFFF8);
+      255:
+        Numerator := Int64($7FFFFFFFFFFFFFFF);
+      else
+        Numerator := Index - 128;
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator mod 100;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TSInt64Bit153Test }
+
+function TSInt64Bit153Test.TestTitle: shortstring;
+  begin
+    Result := 'Signed 64-bit division by 153';
+  end;
+
+function TSInt64Bit153Test.GetDivisor: Int64;
+  begin
+    Result := 153;
+  end;
+
+procedure TSInt64Bit153Test.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Int64;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    Numerator := FS64_153Input[Index and $F];
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator div 153;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TSInt64Bit153ModTest }
+
+function TSInt64Bit153ModTest.TestTitle: shortstring;
+  begin
+    Result := 'Signed 64-bit modulus by 153';
+  end;
+
+function TSInt64Bit153ModTest.GetDivisor: Int64;
+  begin
+    Result := 153;
+  end;
+
+procedure TSInt64Bit153ModTest.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Int64;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    Numerator := FS64_153Input[Index and $F];
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator mod 153;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TSInt64Bit1461Test }
+
+function TSInt64Bit1461Test.TestTitle: shortstring;
+  begin
+    Result := 'Signed 64-bit division by 1,461';
+  end;
+
+function TSInt64Bit1461Test.GetDivisor: Int64;
+  begin
+    Result := 1461;
+  end;
+
+procedure TSInt64Bit1461Test.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Int64;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    Numerator := FS64_1461Input[Index and $F];
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator div 1461;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TSInt64Bit1461ModTest }
+
+function TSInt64Bit1461ModTest.TestTitle: shortstring;
+  begin
+    Result := 'Signed 64-bit modulus by 1,461';
+  end;
+
+function TSInt64Bit1461ModTest.GetDivisor: Int64;
+  begin
+    Result := 1461;
+  end;
+
+procedure TSInt64Bit1461ModTest.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Int64;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    Numerator := FS64_1461Input[Index and $F];
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator mod 1461;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TSInt64Bit10000Test }
+
+function TSInt64Bit10000Test.TestTitle: shortstring;
+  begin
+    Result := 'Signed 64-bit division by 10,000 (Currency)';
+  end;
+
+function TSInt64Bit10000Test.GetDivisor: Int64;
+  begin
+    Result := 10000;
+  end;
+
+procedure TSInt64Bit10000Test.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Int64;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    Numerator := FS64_10000Input[Index and $F];
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator div 10000;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TSInt64Bit10000ModTest }
+
+function TSInt64Bit10000ModTest.TestTitle: shortstring;
+  begin
+    Result := 'Signed 64-bit modulus by 10,000 (Currency)';
+  end;
+
+function TSInt64Bit10000ModTest.GetDivisor: Int64;
+  begin
+    Result := 10000;
+  end;
+
+procedure TSInt64Bit10000ModTest.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Int64;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    Numerator := FS64_10000Input[Index and $F];
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator mod 10000;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TSInt64Bit86400000Test }
+
+function TSInt64Bit86400000Test.TestTitle: shortstring;
+  begin
+    Result := 'Signed 64-bit division by 86,400,000';
+  end;
+
+function TSInt64Bit86400000Test.GetDivisor: Int64;
+  begin
+    Result := 86400000;
+  end;
+
+procedure TSInt64Bit86400000Test.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Int64;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    Numerator := FS64_86400000Input[Index and $F];
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator div 86400000;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TSInt64Bit86400000ModTest }
+
+function TSInt64Bit86400000ModTest.TestTitle: shortstring;
+  begin
+    Result := 'Signed 64-bit modulus by 86,400,000';
+  end;
+
+function TSInt64Bit86400000ModTest.GetDivisor: Int64;
+  begin
+    Result := 86400000;
+  end;
+
+procedure TSInt64Bit86400000ModTest.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Int64;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    Numerator := FS64_86400000Input[Index and $F];
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator mod 86400000;
+      
+    FResultArray[Index] := Answer;
+  end;

+ 769 - 0
tests/bench/bdiv_u32.inc

@@ -0,0 +1,769 @@
+type
+  { TUInt32Bit1Test }
+
+  TUInt32Bit1Test = class(TUInt32DivTest)
+    protected
+      function GetDivisor: Cardinal; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TUInt32Bit1ModTest }
+
+  TUInt32Bit1ModTest = class(TUInt32ModTest)
+    protected
+      function GetDivisor: Cardinal; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TUInt32Bit2Test }
+
+  TUInt32Bit2Test = class(TUInt32DivTest)
+    protected
+      function GetDivisor: Cardinal; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TUInt32Bit2ModTest }
+
+  TUInt32Bit2ModTest = class(TUInt32ModTest)
+    protected
+      function GetDivisor: Cardinal; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TUInt32Bit3Test }
+
+  TUInt32Bit3Test = class(TUInt32DivTest)
+    protected
+      function GetDivisor: Cardinal; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TUInt32Bit3ModTest }
+
+  TUInt32Bit3ModTest = class(TUInt32ModTest)
+    protected
+      function GetDivisor: Cardinal; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TUInt32Bit10Test }
+
+  TUInt32Bit10Test = class(TUInt32DivTest)
+    protected
+      function GetDivisor: Cardinal; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TUInt32Bit10ModTest }
+
+  TUInt32Bit10ModTest = class(TUInt32ModTest)
+    protected
+      function GetDivisor: Cardinal; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TUInt32Bit100Test }
+
+  TUInt32Bit100Test = class(TUInt32DivTest)
+    protected
+      function GetDivisor: Cardinal; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TUInt32Bit100ModTest }
+
+  TUInt32Bit100ModTest = class(TUInt32ModTest)
+    protected
+      function GetDivisor: Cardinal; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TUInt32Bit1000Test }
+const
+  FU32_1000Input: array[$0..$F] of Cardinal =
+    (0, 1, 999, 1000, 1001, 1999, 2000, 2001,
+    4294958999, 4294959000, 4294959001,
+    $7FFFFFFE, $7FFFFFFF, $80000000, $80000001, $FFFFFFFF);
+
+type
+  TUInt32Bit1000Test = class(TUInt32DivTest)
+    protected
+      function GetDivisor: Cardinal; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TUInt32Bit1000ModTest }
+
+  TUInt32Bit1000ModTest = class(TUInt32ModTest)
+    protected
+      function GetDivisor: Cardinal; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TUInt32Bit60000Test }
+const
+  FU32_60000Input: array[$0..$F] of Cardinal =
+    (0, 1, 59999, 60000, 60001, 119999, 120000, 120001,
+    4294919999, 4294920000, 4294920001,
+    $7FFFFFFE, $7FFFFFFF, $80000000, $80000001, $FFFFFFFF);
+
+type
+  TUInt32Bit60000Test = class(TUInt32DivTest)
+    protected
+      function GetDivisor: Cardinal; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TUInt32Bit60000ModTest }
+
+  TUInt32Bit60000ModTest = class(TUInt32ModTest)
+    protected
+      function GetDivisor: Cardinal; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TUInt32Bit146097Test }
+const
+  FU32_146097Input: array[$0..$F] of Cardinal =
+    (0, 1, 146096, 146097, 146098, 292193, 292194, 292195,
+    4294959605, 4294959606, 4294959607,    
+    $7FFFFFFE, $7FFFFFFF, $80000000, $80000001, $FFFFFFFF);
+
+type
+  TUInt32Bit146097Test = class(TUInt32DivTest)
+    protected
+      function GetDivisor: Cardinal; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TUInt32Bit146097ModTest }
+
+  TUInt32Bit146097ModTest = class(TUInt32ModTest)
+    protected
+      function GetDivisor: Cardinal; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+  
+  { TUInt32Bit3600000Test }
+const
+  FU32_3600000Input: array[$0..$F] of Cardinal =
+    (0, 1, 3599999, 3600000, 3600001, 7199999, 7200000, 7200001,
+    3600000000, 4294799999, 4294800000, 4294800001,
+    $7FFFFFFF, $80000000, $80000001, $FFFFFFFF);
+
+type
+  TUInt32Bit3600000Test = class(TUInt32DivTest)
+    protected
+      function GetDivisor: Cardinal; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TUInt32Bit3600000ModTest }
+
+  TUInt32Bit3600000ModTest = class(TUInt32ModTest)
+    protected
+      function GetDivisor: Cardinal; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+
+{ TUInt32Bit1Test }
+
+function TUInt32Bit1Test.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 32-bit division by 1';
+  end;
+
+function TUInt32Bit1Test.GetDivisor: Cardinal;
+  begin
+    Result := 1;
+  end;
+
+procedure TUInt32Bit1Test.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Cardinal;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      253:
+        Numerator := 4294967293;
+      254:
+        Numerator := 4294967294;
+      255:
+        Numerator := 4294967295;
+      else
+        Numerator := Cardinal(Index);
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator div 1;
+
+    FResultArray[Index] := Answer;
+  end;
+  
+{ TUInt32Bit1Test }
+
+function TUInt32Bit1ModTest.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 32-bit modulus by 1';
+  end;
+
+function TUInt32Bit1ModTest.GetDivisor: Cardinal;
+  begin
+    Result := 1;
+  end;
+
+procedure TUInt32Bit1ModTest.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Cardinal;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      253:
+        Numerator := 4294967293;
+      254:
+        Numerator := 4294967294;
+      255:
+        Numerator := 4294967295;
+      else
+        Numerator := Cardinal(Index);
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator mod 1;
+
+    FResultArray[Index] := Answer;
+  end;
+
+{ TUInt32Bit2Test }
+
+function TUInt32Bit2Test.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 32-bit division by 2';
+  end;
+
+function TUInt32Bit2Test.GetDivisor: Cardinal;
+  begin
+    Result := 2;
+  end;
+
+procedure TUInt32Bit2Test.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Cardinal;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      253:
+        Numerator := 4294967293;
+      254:
+        Numerator := 4294967294;
+      255:
+        Numerator := 4294967295;
+      else
+        Numerator := Cardinal(Index);
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator div 2;
+
+    FResultArray[Index] := Answer;
+  end;
+
+{ TUInt32Bit2ModTest }
+
+function TUInt32Bit2ModTest.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 32-bit modulus by 2';
+  end;
+
+function TUInt32Bit2ModTest.GetDivisor: Cardinal;
+  begin
+    Result := 2;
+  end;
+
+procedure TUInt32Bit2ModTest.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Cardinal;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      253:
+        Numerator := 4294967293;
+      254:
+        Numerator := 4294967294;
+      255:
+        Numerator := 4294967295;
+      else
+        Numerator := Cardinal(Index);
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator mod 2;
+
+    FResultArray[Index] := Answer;
+  end;
+
+{ TUInt32Bit3Test }
+
+function TUInt32Bit3Test.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 32-bit division by 3';
+  end;
+
+function TUInt32Bit3Test.GetDivisor: Cardinal;
+  begin
+    Result := 3;
+  end;
+
+procedure TUInt32Bit3Test.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Cardinal;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      254:
+        Numerator := 4294967294;
+      255:
+        Numerator := 4294967295;
+      else
+        Numerator := Cardinal(Index);
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator div 3;
+
+    FResultArray[Index] := Answer;
+  end;
+
+{ TUInt32Bit3ModTest }
+
+function TUInt32Bit3ModTest.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 32-bit modulus by 3';
+  end;
+
+function TUInt32Bit3ModTest.GetDivisor: Cardinal;
+  begin
+    Result := 3;
+  end;
+
+procedure TUInt32Bit3ModTest.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Cardinal;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      254:
+        Numerator := 4294967294;
+      255:
+        Numerator := 4294967295;
+      else
+        Numerator := Cardinal(Index);
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator mod 3;
+
+    FResultArray[Index] := Answer;
+  end;
+
+{ TUInt32Bit10Test }
+
+function TUInt32Bit10Test.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 32-bit division by 10';
+  end;
+
+function TUInt32Bit10Test.GetDivisor: Cardinal;
+  begin
+    Result := 10;
+  end;
+
+procedure TUInt32Bit10Test.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Cardinal;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      253:
+        Numerator := 4294967289;
+      254:
+        Numerator := 4294967290;
+      255:
+        Numerator := 4294967295;
+      else
+        Numerator := Cardinal(Index);
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator div 10;
+
+    FResultArray[Index] := Answer;
+  end;
+
+{ TUInt32Bit10ModTest }
+
+function TUInt32Bit10ModTest.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 32-bit modulus by 10';
+  end;
+
+function TUInt32Bit10ModTest.GetDivisor: Cardinal;
+  begin
+    Result := 10;
+  end;
+
+procedure TUInt32Bit10ModTest.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Cardinal;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      253:
+        Numerator := 4294967289;
+      254:
+        Numerator := 4294967290;
+      255:
+        Numerator := 4294967295;
+      else
+        Numerator := Cardinal(Index);
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator mod 10;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TUInt32Bit100Test }
+
+function TUInt32Bit100Test.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 32-bit division by 100';
+  end;
+
+function TUInt32Bit100Test.GetDivisor: Cardinal;
+  begin
+    Result := 100;
+  end;
+
+procedure TUInt32Bit100Test.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Cardinal;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      253:
+        Numerator := 4294967199;
+      254:
+        Numerator := 4294967200;
+      255:
+        Numerator := 4294967295;
+      else
+        Numerator := Cardinal(Index);
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator div 100;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TUInt32Bit100ModTest }
+
+function TUInt32Bit100ModTest.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 32-bit modulus by 100';
+  end;
+
+function TUInt32Bit100ModTest.GetDivisor: Cardinal;
+  begin
+    Result := 100;
+  end;
+
+procedure TUInt32Bit100ModTest.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Cardinal;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      253:
+        Numerator := 4294967199;
+      254:
+        Numerator := 4294967200;
+      255:
+        Numerator := 4294967295;
+      else
+        Numerator := Cardinal(Index);
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator mod 100;
+
+    FResultArray[Index] := Answer;
+  end;
+
+{ TUInt32Bit1000Test }
+
+function TUInt32Bit1000Test.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 32-bit division by 1,000';
+  end;
+
+function TUInt32Bit1000Test.GetDivisor: Cardinal;
+  begin
+    Result := 1000;
+  end;
+
+procedure TUInt32Bit1000Test.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Cardinal;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    Numerator := FU32_1000Input[Index and $F];
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator div 1000;
+
+    FResultArray[Index] := Answer;
+  end;
+
+{ TUInt32Bit1000ModTest }
+
+function TUInt32Bit1000ModTest.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 32-bit modulus by 1,000';
+  end;
+
+function TUInt32Bit1000ModTest.GetDivisor: Cardinal;
+  begin
+    Result := 1000;
+  end;
+
+procedure TUInt32Bit1000ModTest.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Cardinal;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    Numerator := FU32_1000Input[Index and $F];
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator mod 1000;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TUInt32Bit60000Test }
+
+function TUInt32Bit60000Test.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 32-bit division by 60,000';
+  end;
+
+function TUInt32Bit60000Test.GetDivisor: Cardinal;
+  begin
+    Result := 60000;
+  end;
+
+procedure TUInt32Bit60000Test.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Cardinal;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    Numerator := FU32_60000Input[Index and $F];
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator div 60000;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TUInt32Bit60000ModTest }
+
+function TUInt32Bit60000ModTest.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 32-bit modulus by 60,000';
+  end;
+
+function TUInt32Bit60000ModTest.GetDivisor: Cardinal;
+  begin
+    Result := 60000;
+  end;
+
+procedure TUInt32Bit60000ModTest.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Cardinal;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    Numerator := FU32_60000Input[Index and $F];
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator mod 60000;
+
+    FResultArray[Index] := Answer;
+  end;
+
+{ TUInt32Bit146097Test }
+
+function TUInt32Bit146097Test.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 32-bit division by 146,097';
+  end;
+
+function TUInt32Bit146097Test.GetDivisor: Cardinal;
+  begin
+    Result := 146097;
+  end;
+
+procedure TUInt32Bit146097Test.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Cardinal;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    Numerator := FU32_146097Input[Index and $F];
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator div 146097;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TUInt32Bit146097ModTest }
+
+function TUInt32Bit146097ModTest.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 32-bit modulus by 146,097';
+  end;
+
+function TUInt32Bit146097ModTest.GetDivisor: Cardinal;
+  begin
+    Result := 146097;
+  end;
+
+procedure TUInt32Bit146097ModTest.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Cardinal;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    Numerator := FU32_146097Input[Index and $F];
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator mod 146097;
+
+    FResultArray[Index] := Answer;
+  end;
+
+{ TUInt32Bit3600000Test }
+
+function TUInt32Bit3600000Test.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 32-bit division by 3,600,000';
+  end;
+
+function TUInt32Bit3600000Test.GetDivisor: Cardinal;
+  begin
+    Result := 3600000;
+  end;
+
+procedure TUInt32Bit3600000Test.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Cardinal;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    Numerator := FU32_3600000Input[Index and $F];
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator div 3600000;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TUInt32Bit3600000ModTest }
+
+function TUInt32Bit3600000ModTest.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 32-bit modulus by 3,600,000';
+  end;
+
+function TUInt32Bit3600000ModTest.GetDivisor: Cardinal;
+  begin
+    Result := 3600000;
+  end;
+
+procedure TUInt32Bit3600000ModTest.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: Cardinal;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    Numerator := FU32_3600000Input[Index and $F];
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator mod 3600000;
+
+    FResultArray[Index] := Answer;
+  end;

+ 621 - 0
tests/bench/bdiv_u64.inc

@@ -0,0 +1,621 @@
+type
+  { TUInt64Bit1Test }
+
+  TUInt64Bit1Test = class(TUInt64DivTest)
+    protected
+      function GetDivisor: QWord; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TUInt64Bit1ModTest }
+
+  TUInt64Bit1ModTest = class(TUInt64ModTest)
+    protected
+      function GetDivisor: QWord; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TUInt64Bit2Test }
+
+  TUInt64Bit2Test = class(TUInt64DivTest)
+    protected
+      function GetDivisor: QWord; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TUInt64Bit2ModTest }
+
+  TUInt64Bit2ModTest = class(TUInt64ModTest)
+    protected
+      function GetDivisor: QWord; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TUInt64Bit3Test }
+
+  TUInt64Bit3Test = class(TUInt64DivTest)
+    protected
+      function GetDivisor: QWord; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TUInt64Bit3ModTest }
+
+  TUInt64Bit3ModTest = class(TUInt64ModTest)
+    protected
+      function GetDivisor: QWord; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TUInt64Bit5Test }
+
+  TUInt64Bit5Test = class(TUInt64DivTest)
+    protected
+      function GetDivisor: QWord; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TUInt64Bit5ModTest }
+
+  TUInt64Bit5ModTest = class(TUInt64ModTest)
+    protected
+      function GetDivisor: QWord; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TUInt64Bit10Test }
+
+  TUInt64Bit10Test = class(TUInt64DivTest)
+    protected
+      function GetDivisor: QWord; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TUInt64Bit10ModTest }
+
+  TUInt64Bit10ModTest = class(TUInt64ModTest)
+    protected
+      function GetDivisor: QWord; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TUInt64Bit100Test }
+
+  TUInt64Bit100Test = class(TUInt64DivTest)
+    protected
+      function GetDivisor: QWord; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TUInt64Bit100ModTest }
+
+  TUInt64Bit100ModTest = class(TUInt64ModTest)
+    protected
+      function GetDivisor: QWord; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  { TUInt64Bit1000000000Test }
+const
+  FU64_1000000000Input: array[$0..$F] of QWord =
+    (0, 1, 999999999, 1000000000, 1000000001, 5000000000,
+    7999999999999999999, 8000000000000000000, 8000000000000000001,
+    QWord(15999999999999999999), QWord(16000000000000000000), QWord(16000000000000000001),
+    $7FFFFFFFFFFFFFFF, QWord($8000000000000000), QWord($8000000000000001), QWord($FFFFFFFFFFFFFFFF));
+
+type
+  TUInt64Bit1000000000Test = class(TUInt64DivTest)
+    protected
+      function GetDivisor: QWord; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+  TUInt64Bit1000000000ModTest = class(TUInt64ModTest)
+    protected
+      function GetDivisor: QWord; override;
+      procedure DoTestIteration(Iteration: Integer); override;
+    public
+      function TestTitle: shortstring; override;
+  end;
+
+{ TUInt64Bit1Test }
+
+function TUInt64Bit1Test.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 64-bit division by 1';
+  end;
+
+function TUInt64Bit1Test.GetDivisor: QWord;
+  begin
+    Result := 1;
+  end;
+
+procedure TUInt64Bit1Test.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: QWord;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      253:
+        Numerator := QWord($FFFFFFFFFFFFFFFD);
+      254:
+        Numerator := QWord($FFFFFFFFFFFFFFFE);
+      255:
+        Numerator := QWord($FFFFFFFFFFFFFFFF);
+      else
+        Numerator := QWord(Index);
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator div 1;
+
+    FResultArray[Index] := Answer;
+  end;
+
+{ TUInt64Bit1ModTest }
+
+function TUInt64Bit1ModTest.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 64-bit modulus by 1';
+  end;
+
+function TUInt64Bit1ModTest.GetDivisor: QWord;
+  begin
+    Result := 1;
+  end;
+
+procedure TUInt64Bit1ModTest.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: QWord;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      253:
+        Numerator := QWord($FFFFFFFFFFFFFFFD);
+      254:
+        Numerator := QWord($FFFFFFFFFFFFFFFE);
+      255:
+        Numerator := QWord($FFFFFFFFFFFFFFFF);
+      else
+        Numerator := QWord(Index);
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator mod 1;
+
+    FResultArray[Index] := Answer;
+  end;
+
+{ TUInt64Bit2Test }
+
+function TUInt64Bit2Test.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 64-bit division by 2';
+  end;
+
+function TUInt64Bit2Test.GetDivisor: QWord;
+  begin
+    Result := 2;
+  end;
+
+procedure TUInt64Bit2Test.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: QWord;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      253:
+        Numerator := QWord($FFFFFFFFFFFFFFFD);
+      254:
+        Numerator := QWord($FFFFFFFFFFFFFFFE);
+      255:
+        Numerator := QWord($FFFFFFFFFFFFFFFF);
+      else
+        Numerator := QWord(Index);
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator div 2;
+
+    FResultArray[Index] := Answer;
+  end;
+
+{ TUInt64Bit2ModTest }
+
+function TUInt64Bit2ModTest.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 64-bit modulus by 2';
+  end;
+
+function TUInt64Bit2ModTest.GetDivisor: QWord;
+  begin
+    Result := 2;
+  end;
+
+procedure TUInt64Bit2ModTest.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: QWord;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      253:
+        Numerator := QWord($FFFFFFFFFFFFFFFD);
+      254:
+        Numerator := QWord($FFFFFFFFFFFFFFFE);
+      255:
+        Numerator := QWord($FFFFFFFFFFFFFFFF);
+      else
+        Numerator := QWord(Index);
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator mod 2;
+
+    FResultArray[Index] := Answer;
+  end;
+
+{ TUInt64Bit3Test }
+
+function TUInt64Bit3Test.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 64-bit division by 3';
+  end;
+
+function TUInt64Bit3Test.GetDivisor: QWord;
+  begin
+    Result := 3;
+  end;
+
+procedure TUInt64Bit3Test.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: QWord;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      254:
+        Numerator := QWord($FFFFFFFFFFFFFFFE);
+      255:
+        Numerator := QWord($FFFFFFFFFFFFFFFF);
+      else
+        Numerator := QWord(Index);
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator div 3;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TUInt64Bit3ModTest }
+
+function TUInt64Bit3ModTest.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 64-bit modulus by 3';
+  end;
+
+function TUInt64Bit3ModTest.GetDivisor: QWord;
+  begin
+    Result := 3;
+  end;
+
+procedure TUInt64Bit3ModTest.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: QWord;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      254:
+        Numerator := QWord($FFFFFFFFFFFFFFFE);
+      255:
+        Numerator := QWord($FFFFFFFFFFFFFFFF);
+      else
+        Numerator := QWord(Index);
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator mod 3;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TUInt64Bit5Test }
+
+function TUInt64Bit5Test.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 64-bit division by 5';
+  end;
+
+function TUInt64Bit5Test.GetDivisor: QWord;
+  begin
+    Result := 5;
+  end;
+
+procedure TUInt64Bit5Test.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: QWord;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      254:
+        Numerator := QWord($FFFFFFFFFFFFFFFE);
+      255:
+        Numerator := QWord($FFFFFFFFFFFFFFFF);
+      else
+        Numerator := QWord(Index);
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator div 5;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TUInt64Bit5ModTest }
+
+function TUInt64Bit5ModTest.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 64-bit modulus by 5';
+  end;
+
+function TUInt64Bit5ModTest.GetDivisor: QWord;
+  begin
+    Result := 5;
+  end;
+
+procedure TUInt64Bit5ModTest.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: QWord;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      254:
+        Numerator := QWord($FFFFFFFFFFFFFFFE);
+      255:
+        Numerator := QWord($FFFFFFFFFFFFFFFF);
+      else
+        Numerator := QWord(Index);
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator mod 5;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TUInt64Bit10Test }
+
+function TUInt64Bit10Test.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 64-bit division by 10';
+  end;
+
+function TUInt64Bit10Test.GetDivisor: QWord;
+  begin
+    Result := 10;
+  end;
+
+procedure TUInt64Bit10Test.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: QWord;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      253:
+        Numerator := QWord($FFFFFFFFFFFFFFF9);
+      254:
+        Numerator := QWord($FFFFFFFFFFFFFFFA);
+      255:
+        Numerator := QWord($FFFFFFFFFFFFFFFF);
+      else
+        Numerator := QWord(Index);
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator div 10;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TUInt64Bit10ModTest }
+
+function TUInt64Bit10ModTest.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 64-bit modulus by 10';
+  end;
+
+function TUInt64Bit10ModTest.GetDivisor: QWord;
+  begin
+    Result := 10;
+  end;
+
+procedure TUInt64Bit10ModTest.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: QWord;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      253:
+        Numerator := QWord($FFFFFFFFFFFFFFF9);
+      254:
+        Numerator := QWord($FFFFFFFFFFFFFFFA);
+      255:
+        Numerator := QWord($FFFFFFFFFFFFFFFF);
+      else
+        Numerator := QWord(Index);
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator mod 10;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TUInt64Bit100Test }
+
+function TUInt64Bit100Test.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 64-bit division by 100';
+  end;
+
+function TUInt64Bit100Test.GetDivisor: QWord;
+  begin
+    Result := 100;
+  end;
+
+procedure TUInt64Bit100Test.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: QWord;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      253:
+        Numerator := QWord($FFFFFFFFFFFFFFEF);
+      254:
+        Numerator := QWord($FFFFFFFFFFFFFFF0);
+      255:
+        Numerator := QWord($FFFFFFFFFFFFFFFF);
+      else
+        Numerator := Cardinal(Index);
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator div 100;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TUInt64Bit100ModTest }
+
+function TUInt64Bit100ModTest.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 64-bit modulus by 100';
+  end;
+
+function TUInt64Bit100ModTest.GetDivisor: QWord;
+  begin
+    Result := 100;
+  end;
+
+procedure TUInt64Bit100ModTest.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: QWord;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    case Index of
+      253:
+        Numerator := QWord($FFFFFFFFFFFFFFEF);
+      254:
+        Numerator := QWord($FFFFFFFFFFFFFFF0);
+      255:
+        Numerator := QWord($FFFFFFFFFFFFFFFF);
+      else
+        Numerator := Cardinal(Index);
+    end;
+
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator mod 100;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TUInt64Bit1000000000Test }
+
+function TUInt64Bit1000000000Test.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 64-bit division by 1,000,000,000';
+  end;
+
+function TUInt64Bit1000000000Test.GetDivisor: QWord;
+  begin
+    Result := 1000000000;
+  end;
+
+procedure TUInt64Bit1000000000Test.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: QWord;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    Numerator := FU64_1000000000Input[Index and $F];
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator div 1000000000;
+      
+    FResultArray[Index] := Answer;
+  end;
+
+{ TUInt64Bit1000000000ModTest }
+
+function TUInt64Bit1000000000ModTest.TestTitle: shortstring;
+  begin
+    Result := 'Unsigned 64-bit modulus by 1,000,000,000';
+  end;
+
+function TUInt64Bit1000000000ModTest.GetDivisor: QWord;
+  begin
+    Result := 1000000000;
+  end;
+
+procedure TUInt64Bit1000000000ModTest.DoTestIteration(Iteration: Integer);
+  var
+    Numerator, Answer: QWord;
+    Index, X: Integer;
+  begin
+    Index := Iteration and $FF;
+    Numerator := FU64_1000000000Input[Index and $F];
+    FInputArray[Index] := Numerator;
+    for X := 0 to INTERNAL_LOOPS - 1 do
+      Answer := Numerator mod 1000000000;
+      
+    FResultArray[Index] := Answer;
+  end;

+ 3 - 0
tests/test/cg/tmoddiv6.pp

@@ -0,0 +1,3 @@
+{ %OPT=-O2 }
+{ this benchmark can be used also as a test case }
+{$I ../../bench/bdiv.pp}

+ 189 - 0
tests/test/units/system/ttxtflsh.pp

@@ -0,0 +1,189 @@
+{ $DEFINE VERBOSE}
+{ $DEFINE DEBUG}
+(* Define the following if the test will be run manually in a console       *)
+(* (no output redirection) - otherwise the test will fail for some targets. *)
+{ $DEFINE TESTINCONSOLE}
+{$I-}
+uses
+ Dos;
+var
+ T: text;
+ IOR: integer;
+ TElapsed1, TElapsed2: int64;
+ I: longint;
+const
+ TestFName = 'ttxtflsh.txt';
+ NoTestFName = '_NoSuchF.FFF';
+{$IF DEFINED(OS2) or DEFINED(WINDOWS) or DEFINED(GO32V2) or DEFINED(WATCOM) or DEFINED(MSDOS)}
+ ConsoleDeviceName = 'CON';
+ {$DEFINE TESTCONSOLEOK}
+{$ELSE}
+(* {$IF DEFINED(UNIX)}
+{ I don't know whether there's a device on Unix allowing to enforce output to console even if standard output is redirected for the given process... }
+ ConsoleDeviceName = '/dev/tty';
+  {$DEFINE TESTCONSOLEOK}
+ {$ELSE}
+*)
+  {$IFDEF TESTINCONSOLE}
+ ConsoleDeviceName = '';
+   {$DEFINE TESTCONSOLEOK}
+  {$ENDIF TESTINCONSOLE}
+ { $ENDIF}
+{$ENDIF}
+
+
+procedure ChkErr (Err: boolean; MsgOK, MsgErr: string; N: byte);
+begin
+ if Err then
+  begin
+   if IOResult = 0 then
+    begin
+    end;
+   WriteLn ('Error: ', MsgErr);
+{$IFDEF VERBOSE}
+   WriteLn ('Exit value: ', N);
+{$ENDIF VERBOSE}
+   Halt (N);
+  end
+{$IFDEF VERBOSE}
+ else
+  WriteLn (MsgOK)
+{$ENDIF VERBOSE}
+     ;
+end;
+
+function PerfTest: int64;
+var
+ T1: int64;
+begin
+ T1 := GetMsCount;
+ for I := 0 to 50000 do
+  Write (T, I);
+ PerfTest := GetMsCount - T1;
+ ChkErr (IOResult <> 0, 'Test text output successful.',
+  'Test text output failed!', 255);
+end;
+
+begin
+ Assign (T, NoTestFName);
+ Reset (T);
+ SetTextAutoFlush (T, true);
+ ChkErr (GetTextAutoFlush (T),
+  'Set/GetTextAutoFlush call correctly ignored with non-zero InOutRes.',
+  'Set/GetTextAutoFlush call not ignored in spite of non-zero InOutRes!', 1);
+ if IOResult <> 0 then
+  begin
+  end;
+ SetTextAutoFlush (T, true);
+ IOR := IOResult;
+{$IFDEF DEBUG}
+ WriteLn (StdErr, IOR);
+{$ENDIF DEBUG}
+ ChkErr (IOR <> 103,
+  'SetTextAutoFlush correctly errors out with expected RTE if file not open.',
+  'SetTextAutoFlush does not finish with expected RTE if file not open!', 2);
+ Assign (T, TestFName);
+ Rewrite (T);
+ ChkErr (IOResult <> 0, 'Test file ' + TestFName + ' created successfully.',
+  'Test file ' + TestFName + ' creation failed!', 3);
+ Close (T);
+ Reset (T);
+ SetTextAutoFlush (T, true);
+ IOR := IOResult;
+{$IFDEF DEBUG}
+ WriteLn (StdErr, IOR);
+{$ENDIF DEBUG}
+ ChkErr (IOR <> 105,
+  'SetTextAutoFlush correctly errors out if file not open for writing.',
+  'SetTextAutoFlush does not finish with expected RTE if file not open for writing!', 4);
+ Close (T);
+ Rewrite (T);
+{$IFDEF DEBUG}
+ WriteLn (StdErr, Longint (TextRec(T).FlushFunc));
+{$ENDIF DEBUG}
+ ChkErr (GetTextAutoFlush (T) or (IOResult <> 0),
+  'GetTextAutoFlush returns expected default value for a regular file.',
+  'GetTextAutoFlush returns unexpected default value for a regular file!', 5);
+ SetTextAutoFlush (T, true);
+{$IFDEF DEBUG}
+ WriteLn (StdErr, Longint (TextRec(T).FlushFunc));
+{$ENDIF DEBUG}
+ ChkErr (not (GetTextAutoFlush (T)) or (IOResult <> 0),
+  'GetTextAutoFlush returns expected modified value after SetTextAutoFlush.',
+  'GetTextAutoFlush does not return expected modified value after SetTextAutoFlush!', 6);
+ TElapsed1 := PerfTest;
+{$IFDEF DEBUG}
+ WriteLn (StdErr, 'Run 1: ', TElapsed1, ' ms');
+{$ENDIF DEBUG}
+ Close (T);
+ Rewrite (T);
+{$IFDEF DEBUG}
+ WriteLn (StdErr, Longint (TextRec(T).FlushFunc));
+{$ENDIF DEBUG}
+ ChkErr (GetTextAutoFlush (T) or (IOResult <> 0),
+  'GetTextAutoFlush returns expected default value after file reopening.',
+  'GetTextAutoFlush does not return expected default value after file reopening!', 7);
+ TElapsed2 := PerfTest;
+{$IFDEF DEBUG}
+ WriteLn (StdErr, 'Run 2: ', TElapsed2, ' ms');
+{$ENDIF DEBUG}
+ ChkErr (TElapsed1 <= TElapsed2,
+  'Output performance lower with enforced flushing as expected.',
+  'Output performance not lower with enforced flushing!', 11);
+ Close (T);
+ Append (T);
+{$IFDEF DEBUG}
+ WriteLn (StdErr, Longint (TextRec(T).FlushFunc));
+{$ENDIF DEBUG}
+ ChkErr (GetTextAutoFlush (T) or (IOResult <> 0),
+  'GetTextAutoFlush returns expected default value after file reopening for appending.',
+  'GetTextAutoFlush does not return expected default value after file reopening for appending!', 13);
+ Close (T);
+ Erase (T);
+ if IOResult <> 0 then
+  begin
+  end;
+
+{$IFDEF TESTCONSOLEOK}
+ Assign (T, ConsoleDeviceName);
+ Rewrite (T);
+{$IFDEF DEBUG}
+ WriteLn (StdErr, Longint (TextRec(T).FlushFunc));
+{$ENDIF DEBUG}
+ ChkErr (not (GetTextAutoFlush (T)) or (IOResult <> 0),
+  'GetTextAutoFlush returns expected default value for console output.',
+  'GetTextAutoFlush returns unexpected default value for console output!', 8);
+ SetTextAutoFlush (T, false);
+{$IFDEF DEBUG}
+ WriteLn (StdErr, Longint (TextRec(T).FlushFunc));
+{$ENDIF DEBUG}
+ ChkErr (GetTextAutoFlush (T) or (IOResult <> 0),
+  'GetTextAutoFlush returns expected modified value after SetTextAutoFlush with console.',
+  'GetTextAutoFlush does not return expected modified value after SetTextAutoFlush with console!', 9);
+ TElapsed1 := PerfTest;
+{$IFDEF DEBUG}
+ WriteLn (StdErr, 'Run 1: ', TElapsed1, ' ms');
+{$ENDIF DEBUG}
+ Close (T);
+ Rewrite (T);
+{$IFDEF DEBUG}
+ WriteLn (StdErr, Longint (TextRec(T).FlushFunc));
+{$ENDIF DEBUG}
+ ChkErr (not (GetTextAutoFlush (T)) or (IOResult <> 0),
+  'GetTextAutoFlush returns expected default value after file reopening for console.',
+  'GetTextAutoFlush returns unexpected default value after file reopening for console!', 10);
+ TElapsed2 := PerfTest;
+{$IFDEF DEBUG}
+ WriteLn (StdErr, 'Run 2: ', TElapsed2, ' ms');
+{$ENDIF DEBUG}
+ ChkErr (TElapsed1 >= TElapsed2,
+  'Output performance higher with disabled flushing as expected.',
+  'Output performance not higher with disabled flushing!', 12);
+ Close (T);
+
+{$ENDIF TESTCONSOLEOK}
+
+{$IFDEF VERBOSE}
+ WriteLn ('TTxtFlsh finished successfully.');
+{$ENDIF VERBOSE}
+end.

+ 21 - 0
tests/webtbs/tw38832.pp

@@ -0,0 +1,21 @@
+program Math1;
+
+{$mode delphi}{$H+}
+
+uses
+ {$IFDEF UNIX}
+ cthreads,
+ {$ENDIF}
+ Classes,
+ Math
+ { you can add units after this };
+
+var x:double;
+begin
+ SetExceptionMask([exInvalidOp,exDenormalized,exZeroDivide,exOverflow,exUnderflow,exPrecision]);
+ x:=0;
+ writeln('ln(x)');
+ writeln(ln(x));
+ writeln('1/x');
+ writeln(1/x);
+end.

+ 18 - 0
tests/webtbs/tw38833.pp

@@ -0,0 +1,18 @@
+program EmptyTryFinally1;
+
+{$mode delphi}
+{$apptype console}
+
+var
+  finallyrun: boolean;
+begin
+  finallyrun:=false;
+  try
+   // Empty try statement block
+  finally
+    WriteLn('I should actually visible . . .'); // but I'm not
+    finallyrun:=true;
+  end;
+  if not finallyrun then
+    halt(1);
+end.

+ 24 - 15
utils/pas2js/dist/rtl.js

@@ -229,7 +229,10 @@ var rtl = {
   createCallback: function(scope, fn){
   createCallback: function(scope, fn){
     var cb;
     var cb;
     if (typeof(fn)==='string'){
     if (typeof(fn)==='string'){
-      cb = function(){
+      if (!scope.hasOwnProperty('$events')) scope.$events = {};
+      cb = scope.$events[fn];
+      if (cb) return cb;
+      scope.$events[fn] = cb = function(){
         return scope[fn].apply(scope,arguments);
         return scope[fn].apply(scope,arguments);
       };
       };
     } else {
     } else {
@@ -243,32 +246,38 @@ var rtl = {
   },
   },
 
 
   createSafeCallback: function(scope, fn){
   createSafeCallback: function(scope, fn){
-    var cb = function(){
-      try{
-        if (typeof(fn)==='string'){
+    var cb;
+    if (typeof(fn)==='string'){
+      if (!scope.hasOwnProperty('$events')) scope.$events = {};
+      cb = scope.$events[fn];
+      if (cb) return cb;
+      scope.$events[fn] = cb = function(){
+        try{
           return scope[fn].apply(scope,arguments);
           return scope[fn].apply(scope,arguments);
-        } else {
+        } catch (err) {
+          if (!rtl.handleUncaughtException(err)) throw err;
+        }
+      };
+    } else {
+      cb = function(){
+        try{
           return fn.apply(scope,arguments);
           return fn.apply(scope,arguments);
-        };
-      } catch (err) {
-        if (!rtl.handleUncaughtException(err)) throw err;
-      }
+        } catch (err) {
+          if (!rtl.handleUncaughtException(err)) throw err;
+        }
+      };
     };
     };
     cb.scope = scope;
     cb.scope = scope;
     cb.fn = fn;
     cb.fn = fn;
     return cb;
     return cb;
   },
   },
 
 
-  cloneCallback: function(cb){
-    return rtl.createCallback(cb.scope,cb.fn);
-  },
-
   eqCallback: function(a,b){
   eqCallback: function(a,b){
     // can be a function or a function wrapper
     // can be a function or a function wrapper
-    if (a==b){
+    if (a===b){
       return true;
       return true;
     } else {
     } else {
-      return (a!=null) && (b!=null) && (a.fn) && (a.scope===b.scope) && (a.fn==b.fn);
+      return (a!=null) && (b!=null) && (a.fn) && (a.scope===b.scope) && (a.fn===b.fn);
     }
     }
   },
   },