Explorar el Código

* synchronized with trunk

git-svn-id: branches/wasm@47588 -
nickysn hace 4 años
padre
commit
f9daec43ef
Se han modificado 61 ficheros con 2905 adiciones y 1233 borrados
  1. 6 0
      .gitattributes
  2. 12 0
      compiler/aarch64/aasmcpu.pas
  3. 26 0
      compiler/aarch64/aoptcpu.pas
  4. 30 1
      compiler/aarch64/ncpuinl.pas
  5. 460 452
      compiler/arm/aoptcpu.pas
  6. 60 50
      compiler/armgen/aoptarm.pas
  7. 3 55
      compiler/comphook.pas
  8. 172 0
      compiler/comptty.pas
  9. 5 1
      compiler/globals.pas
  10. 4 4
      compiler/llvm/agllvm.pas
  11. 55 39
      compiler/llvm/llvmdef.pas
  12. 41 60
      compiler/m68k/ra68kmot.pas
  13. 3 0
      compiler/msg/errore.msg
  14. 1 1
      compiler/msgidx.inc
  15. 26 22
      compiler/msgtxt.inc
  16. 71 37
      compiler/options.pas
  17. 0 5
      compiler/rautils.pas
  18. 4 1
      compiler/riscv/agrvgas.pas
  19. 1 1
      compiler/systems/i_sinclairql.pas
  20. 5 0
      compiler/systems/t_amiga.pas
  21. 6 1
      compiler/systems/t_atari.pas
  22. 69 28
      compiler/systems/t_sinclairql.pas
  23. 7 1
      compiler/systems/t_zxspectrum.pas
  24. 1 1
      compiler/utils/Makefile
  25. 1 1
      compiler/utils/Makefile.fpc
  26. 16 14
      compiler/xtensa/agcpugas.pas
  27. 10 4
      compiler/xtensa/cgcpu.pas
  28. 8 0
      compiler/xtensa/ncpuadd.pas
  29. 83 0
      compiler/xtensa/ncpuinl.pas
  30. 1 1
      packages/fcl-sound/src/fpwavreader.pas
  31. BIN
      packages/fcl-sound/tests/data/wav/reader/valid/odd_fmt_size.wav
  32. 1 0
      packages/fcl-sound/tests/data/wav/reader/valid/odd_fmt_size.wav.info.txt
  33. 0 0
      packages/fcl-sound/tests/data/wav/reader/valid/odd_fmt_size.wav.raw
  34. 1 0
      packages/fcl-sound/tests/tcwavreader.pas
  35. 5 5
      packages/qlunits/examples/qlcube.pas
  36. 12 9
      rtl/emx/sysutils.pp
  37. 13 0
      rtl/go32v2/sysutils.pp
  38. 1 4
      rtl/go32v2/v2prt0.as
  39. 1 1
      rtl/linux/riscv64/si_c.inc
  40. 1 1
      rtl/linux/riscv64/si_prc.inc
  41. 1 1
      rtl/linux/xtensa/si_c.inc
  42. 1 1
      rtl/linux/xtensa/si_prc.inc
  43. 13 0
      rtl/msdos/sysutils.pp
  44. 99 99
      rtl/objpas/sysutils/syssb.inc
  45. 51 51
      rtl/objpas/sysutils/syssbh.inc
  46. 4 4
      rtl/objpas/sysutils/sysstr.inc
  47. 4 4
      rtl/objpas/sysutils/sysstrh.inc
  48. 926 0
      rtl/objpas/sysutils/tzenv.inc
  49. 82 1
      rtl/os2/sysutils.pp
  50. 140 8
      rtl/sinclairql/qdos.inc
  51. 10 1
      rtl/sinclairql/qdosfuncs.inc
  52. 20 38
      rtl/sinclairql/si_prc.pp
  53. 37 7
      rtl/sinclairql/sysfile.inc
  54. 43 56
      rtl/sinclairql/system.pp
  55. 17 0
      rtl/watcom/sysutils.pp
  56. 12 0
      rtl/x86_64/math.inc
  57. 3 0
      tests/test/tfma1.inc
  58. 30 0
      tests/test/tfma1xtensa.pp
  59. 21 29
      utils/fpdoc/dw_html.pp
  60. 42 2
      utils/fpdoc/fpclasschart.pp
  61. 127 131
      utils/fpdoc/fpdocclasstree.pp

+ 6 - 0
.gitattributes

@@ -167,6 +167,7 @@ compiler/comphook.pas svneol=native#text/plain
 compiler/compiler.pas svneol=native#text/plain
 compiler/compiler.pas svneol=native#text/plain
 compiler/compinnr.pas svneol=native#text/plain
 compiler/compinnr.pas svneol=native#text/plain
 compiler/comprsrc.pas svneol=native#text/plain
 compiler/comprsrc.pas svneol=native#text/plain
+compiler/comptty.pas svneol=native#text/plain
 compiler/constexp.pas svneol=native#text/x-pascal
 compiler/constexp.pas svneol=native#text/x-pascal
 compiler/cprofile.pas svneol=native#text/pascal
 compiler/cprofile.pas svneol=native#text/pascal
 compiler/crefs.pas svneol=native#text/plain
 compiler/crefs.pas svneol=native#text/plain
@@ -4398,6 +4399,9 @@ packages/fcl-sound/tests/data/wav/reader/valid/44k_stereo_8.wav.raw -text svneol
 packages/fcl-sound/tests/data/wav/reader/valid/euphoric_tape.wav -text svneol=unset#audio/x-wav
 packages/fcl-sound/tests/data/wav/reader/valid/euphoric_tape.wav -text svneol=unset#audio/x-wav
 packages/fcl-sound/tests/data/wav/reader/valid/euphoric_tape.wav.info.txt svneol=native#text/plain
 packages/fcl-sound/tests/data/wav/reader/valid/euphoric_tape.wav.info.txt svneol=native#text/plain
 packages/fcl-sound/tests/data/wav/reader/valid/euphoric_tape.wav.raw -text svneol=unset#application/octet-stream
 packages/fcl-sound/tests/data/wav/reader/valid/euphoric_tape.wav.raw -text svneol=unset#application/octet-stream
+packages/fcl-sound/tests/data/wav/reader/valid/odd_fmt_size.wav -text svneol=unset#audio/x-wav
+packages/fcl-sound/tests/data/wav/reader/valid/odd_fmt_size.wav.info.txt svneol=native#text/plain
+packages/fcl-sound/tests/data/wav/reader/valid/odd_fmt_size.wav.raw -text svneol=unset#application/octet-stream
 packages/fcl-sound/tests/tcwavreader.pas svneol=native#text/plain
 packages/fcl-sound/tests/tcwavreader.pas svneol=native#text/plain
 packages/fcl-sound/tests/testfclsound.lpi svneol=native#text/plain
 packages/fcl-sound/tests/testfclsound.lpi svneol=native#text/plain
 packages/fcl-sound/tests/testfclsound.lpr svneol=native#text/plain
 packages/fcl-sound/tests/testfclsound.lpr svneol=native#text/plain
@@ -11785,6 +11789,7 @@ rtl/objpas/sysutils/sysutilh.inc svneol=native#text/plain
 rtl/objpas/sysutils/sysutils.inc svneol=native#text/plain
 rtl/objpas/sysutils/sysutils.inc svneol=native#text/plain
 rtl/objpas/sysutils/syswide.inc svneol=native#text/plain
 rtl/objpas/sysutils/syswide.inc svneol=native#text/plain
 rtl/objpas/sysutils/syswideh.inc svneol=native#text/plain
 rtl/objpas/sysutils/syswideh.inc svneol=native#text/plain
+rtl/objpas/sysutils/tzenv.inc svneol=native#text/plain
 rtl/objpas/types.pp svneol=native#text/plain
 rtl/objpas/types.pp svneol=native#text/plain
 rtl/objpas/typinfo.pp svneol=native#text/plain
 rtl/objpas/typinfo.pp svneol=native#text/plain
 rtl/objpas/unicodedata.inc svneol=native#text/pascal
 rtl/objpas/unicodedata.inc svneol=native#text/pascal
@@ -14980,6 +14985,7 @@ tests/test/tfma1.inc svneol=native#text/plain
 tests/test/tfma1a64.pp svneol=native#text/pascal
 tests/test/tfma1a64.pp svneol=native#text/pascal
 tests/test/tfma1arm.pp svneol=native#text/pascal
 tests/test/tfma1arm.pp svneol=native#text/pascal
 tests/test/tfma1x86.pp svneol=native#text/pascal
 tests/test/tfma1x86.pp svneol=native#text/pascal
+tests/test/tfma1xtensa.pp svneol=native#text/pascal
 tests/test/tforin1.pp svneol=native#text/pascal
 tests/test/tforin1.pp svneol=native#text/pascal
 tests/test/tforin10.pp svneol=native#text/plain
 tests/test/tforin10.pp svneol=native#text/plain
 tests/test/tforin11.pp svneol=native#text/plain
 tests/test/tforin11.pp svneol=native#text/plain

+ 12 - 0
compiler/aarch64/aasmcpu.pas

@@ -188,6 +188,8 @@ uses
          constructor op_reg_reg_reg_shifterop(op : tasmop;_op1,_op2,_op3 : tregister; const _op4 : tshifterop);
          constructor op_reg_reg_reg_shifterop(op : tasmop;_op1,_op2,_op3 : tregister; const _op4 : tshifterop);
          constructor op_reg_reg_reg_cond(op : tasmop;_op1,_op2,_op3 : tregister; const _op4: tasmcond);
          constructor op_reg_reg_reg_cond(op : tasmop;_op1,_op2,_op3 : tregister; const _op4: tasmcond);
 
 
+         constructor op_const_ref(op:tasmop; _op1: aint; _op2: treference);
+
          { this is for Jmp instructions }
          { this is for Jmp instructions }
          constructor op_cond_sym(op : tasmop;cond:TAsmCond;_op1 : tasmsymbol);
          constructor op_cond_sym(op : tasmop;cond:TAsmCond;_op1 : tasmsymbol);
 
 
@@ -544,6 +546,15 @@ implementation
        end;
        end;
 
 
 
 
+     constructor taicpu.op_const_ref(op : tasmop; _op1 : aint; _op2 : treference);
+      begin
+         inherited create(op);
+         ops:=2;
+         loadconst(0,_op1);
+         loadref(1,_op2);
+      end;
+
+
     constructor taicpu.op_cond_sym(op : tasmop;cond:TAsmCond;_op1 : tasmsymbol);
     constructor taicpu.op_cond_sym(op : tasmop;cond:TAsmCond;_op1 : tasmsymbol);
       begin
       begin
          inherited create(op);
          inherited create(op);
@@ -552,6 +563,7 @@ implementation
          loadsymbol(0,_op1,0);
          loadsymbol(0,_op1,0);
       end;
       end;
 
 
+
     constructor taicpu.op_regset_reg_ref(op: tasmop; basereg: tregister; nregs: byte; const ref: treference);
     constructor taicpu.op_regset_reg_ref(op: tasmop; basereg: tregister; nregs: byte; const ref: treference);
       begin
       begin
         inherited create(op);
         inherited create(op);

+ 26 - 0
compiler/aarch64/aoptcpu.pas

@@ -538,6 +538,27 @@ Implementation
           DebugMsg(SPeepholeOptimization + 'FMovFMov2FMov done', p);
           DebugMsg(SPeepholeOptimization + 'FMovFMov2FMov done', p);
           Result:=true;
           Result:=true;
         end;
         end;
+      { not enabled as apparently not happening
+      if MatchOpType(taicpu(p),top_reg,top_reg) and
+        GetNextInstructionUsingReg(p,hp1,taicpu(p).oper[0]^.reg) and
+        MatchInstruction(hp1, [A_FSUB,A_FADD,A_FNEG,A_FMUL,A_FSQRT,A_FDIV,A_FABS], [PF_None]) and
+        (MatchOperand(taicpu(p).oper[0]^,taicpu(hp1).oper[1]^) or
+         ((taicpu(hp1).ops=3) and MatchOperand(taicpu(p).oper[0]^,taicpu(hp1).oper[2]^))
+        ) and
+        RegEndofLife(taicpu(p).oper[0]^.reg,taicpu(hp1)) and
+        not(RegUsedBetween(taicpu(p).oper[0]^.reg,p,hp1)) then
+        begin
+          DebugMsg(SPeepholeOptimization + 'FMovFOp2FOp done', hp1);
+          AllocRegBetween(taicpu(hp1).oper[1]^.reg,p,hp1,UsedRegs);
+          if MatchOperand(taicpu(p).oper[0]^,taicpu(hp1).oper[1]^) then
+            taicpu(hp1).oper[1]^.reg:=taicpu(p).oper[1]^.reg;
+          if (taicpu(hp1).ops=3) and MatchOperand(taicpu(p).oper[0]^,taicpu(hp1).oper[2]^) then
+            taicpu(hp1).oper[2]^.reg:=taicpu(p).oper[1]^.reg;
+          RemoveCurrentP(p);
+          Result:=true;
+          exit;
+        end;
+      }
     end;
     end;
 
 
 
 
@@ -772,6 +793,11 @@ Implementation
             A_SXTH:
             A_SXTH:
               Result:=OptPass1SXTH(p);
               Result:=OptPass1SXTH(p);
 //            A_VLDR,
 //            A_VLDR,
+            A_FMADD,
+            A_FMSUB,
+            A_FNMADD,
+            A_FNMSUB,
+            A_FNMUL,
             A_FADD,
             A_FADD,
             A_FMUL,
             A_FMUL,
             A_FDIV,
             A_FDIV,

+ 30 - 1
compiler/aarch64/ncpuinl.pas

@@ -44,6 +44,7 @@ interface
         procedure second_trunc_real; override;
         procedure second_trunc_real; override;
         procedure second_get_frame; override;
         procedure second_get_frame; override;
         procedure second_fma; override;
         procedure second_fma; override;
+        procedure second_prefetch; override;
       private
       private
         procedure load_fpu_location;
         procedure load_fpu_location;
       end;
       end;
@@ -55,7 +56,7 @@ implementation
       globtype,verbose,globals,
       globtype,verbose,globals,
       cpuinfo, defutil,symdef,aasmdata,aasmcpu,
       cpuinfo, defutil,symdef,aasmdata,aasmcpu,
       cgbase,cgutils,pass_1,pass_2,
       cgbase,cgutils,pass_1,pass_2,
-      ncal,
+      ncal,nutils,
       cpubase,ncgutil,cgobj,cgcpu, hlcgobj;
       cpubase,ncgutil,cgobj,cgcpu, hlcgobj;
 
 
 {*****************************************************************************
 {*****************************************************************************
@@ -272,6 +273,34 @@ implementation
       end;
       end;
 
 
 
 
+    procedure taarch64inlinenode.second_prefetch;
+      var
+        ref : treference;
+        r : tregister;
+        checkpointer_used : boolean;
+      begin
+        { do not call Checkpointer for left node }
+        checkpointer_used:=(cs_checkpointer in current_settings.localswitches);
+        if checkpointer_used then
+          node_change_local_switch(left,cs_checkpointer,false);
+        secondpass(left);
+        if checkpointer_used then
+          node_change_local_switch(left,cs_checkpointer,false);
+       case left.location.loc of
+         LOC_CREFERENCE,
+         LOC_REFERENCE:
+           begin
+             r:=cg.getintregister(current_asmdata.CurrAsmList,OS_ADDR);
+             cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,left.location.reference,r);
+             reference_reset_base(ref,r,0,location.reference.temppos,left.location.reference.alignment,location.reference.volatility);
+             current_asmdata.CurrAsmList.concat(taicpu.op_const_ref(A_PRFM,0,ref));
+           end;
+         else
+           { nothing to prefetch };
+       end;
+      end;
+
+
 begin
 begin
   cinlinenode:=taarch64inlinenode;
   cinlinenode:=taarch64inlinenode;
 end.
 end.

+ 460 - 452
compiler/arm/aoptcpu.pas

@@ -1284,504 +1284,512 @@ Implementation
 
 
       { All the optimisations from this point on require GetNextInstructionUsingReg
       { All the optimisations from this point on require GetNextInstructionUsingReg
         to return True }
         to return True }
-      if not (
+      while (
         GetNextInstructionUsingReg(p, hpfar1, taicpu(p).oper[0]^.reg) and
         GetNextInstructionUsingReg(p, hpfar1, taicpu(p).oper[0]^.reg) and
         (hpfar1.typ = ait_instruction)
         (hpfar1.typ = ait_instruction)
-      ) then
-        Exit;
+      ) do
+        begin
 
 
-      { Change the common
-        mov r0, r0, lsr #xxx
-        and r0, r0, #yyy/bic r0, r0, #xxx
+          { Change the common
+            mov r0, r0, lsr #xxx
+            and r0, r0, #yyy/bic r0, r0, #xxx
 
 
-        and remove the superfluous and/bic if possible
+            and remove the superfluous and/bic if possible
 
 
-        This could be extended to handle more cases.
-      }
+            This could be extended to handle more cases.
+          }
 
 
-      { Change
-        mov rx, ry, lsr/ror #xxx
-        uxtb/uxth rz,rx/and rz,rx,0xFF
-        dealloc rx
+          { Change
+            mov rx, ry, lsr/ror #xxx
+            uxtb/uxth rz,rx/and rz,rx,0xFF
+            dealloc rx
 
 
-        to
+            to
 
 
-        uxtb/uxth rz,ry,ror #xxx
-      }
-      if (GenerateThumb2Code) and
-         (taicpu(p).ops=3) and
-         (taicpu(p).oper[2]^.typ = top_shifterop) and
-         (taicpu(p).oper[2]^.shifterop^.rs = NR_NO) and
-         (taicpu(p).oper[2]^.shifterop^.shiftmode in [SM_LSR,SM_ROR]) and
-         RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hpfar1)) then
-         begin
-           if MatchInstruction(hpfar1, A_UXTB, [C_None], [PF_None]) and
-             (taicpu(hpfar1).ops = 2) and
-             (taicpu(p).oper[2]^.shifterop^.shiftimm in [8,16,24]) and
-             MatchOperand(taicpu(hpfar1).oper[1]^, taicpu(p).oper[0]^.reg) then
-             begin
-               taicpu(hpfar1).oper[1]^.reg := taicpu(p).oper[1]^.reg;
-               taicpu(hpfar1).loadshifterop(2,taicpu(p).oper[2]^.shifterop^);
-               taicpu(hpfar1).oper[2]^.shifterop^.shiftmode:=SM_ROR;
-               taicpu(hpfar1).ops := 3;
-
-               if not Assigned(hp1) then
-                 GetNextInstruction(p,hp1);
-
-               RemoveCurrentP(p, hp1);
-
-               result:=true;
-               exit;
-             end
-           else if MatchInstruction(hpfar1, A_UXTH, [C_None], [PF_None]) and
-             (taicpu(hpfar1).ops=2) and
-             (taicpu(p).oper[2]^.shifterop^.shiftimm in [16]) and
-             MatchOperand(taicpu(hpfar1).oper[1]^, taicpu(p).oper[0]^.reg) then
-             begin
-               taicpu(hpfar1).oper[1]^.reg := taicpu(p).oper[1]^.reg;
-               taicpu(hpfar1).loadshifterop(2,taicpu(p).oper[2]^.shifterop^);
-               taicpu(hpfar1).oper[2]^.shifterop^.shiftmode:=SM_ROR;
-               taicpu(hpfar1).ops := 3;
-
-               if not Assigned(hp1) then
-                 GetNextInstruction(p,hp1);
-
-               RemoveCurrentP(p, hp1);
-
-               result:=true;
-               exit;
-             end
-           else if MatchInstruction(hpfar1, A_AND, [C_None], [PF_None]) and
-             (taicpu(hpfar1).ops = 3) and
-             (taicpu(hpfar1).oper[2]^.typ = top_const) and
-             (taicpu(hpfar1).oper[2]^.val = $FF) and
-             (taicpu(p).oper[2]^.shifterop^.shiftimm in [8,16,24]) and
-             MatchOperand(taicpu(hpfar1).oper[1]^, taicpu(p).oper[0]^.reg) then
+            uxtb/uxth rz,ry,ror #xxx
+          }
+          if (GenerateThumb2Code) and
+             (taicpu(p).ops=3) and
+             (taicpu(p).oper[2]^.typ = top_shifterop) and
+             (taicpu(p).oper[2]^.shifterop^.rs = NR_NO) and
+             (taicpu(p).oper[2]^.shifterop^.shiftmode in [SM_LSR,SM_ROR]) and
+             RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hpfar1)) then
              begin
              begin
-               taicpu(hpfar1).ops := 3;
-               taicpu(hpfar1).opcode := A_UXTB;
-               taicpu(hpfar1).oper[1]^.reg := taicpu(p).oper[1]^.reg;
-               taicpu(hpfar1).loadshifterop(2,taicpu(p).oper[2]^.shifterop^);
-               taicpu(hpfar1).oper[2]^.shifterop^.shiftmode:=SM_ROR;
-
-               if not Assigned(hp1) then
-                 GetNextInstruction(p,hp1);
-
-               RemoveCurrentP(p, hp1);
-
-               result:=true;
-               exit;
+               if MatchInstruction(hpfar1, A_UXTB, [C_None], [PF_None]) and
+                 (taicpu(hpfar1).ops = 2) and
+                 (taicpu(p).oper[2]^.shifterop^.shiftimm in [8,16,24]) and
+                 MatchOperand(taicpu(hpfar1).oper[1]^, taicpu(p).oper[0]^.reg) then
+                 begin
+                   taicpu(hpfar1).oper[1]^.reg := taicpu(p).oper[1]^.reg;
+                   taicpu(hpfar1).loadshifterop(2,taicpu(p).oper[2]^.shifterop^);
+                   taicpu(hpfar1).oper[2]^.shifterop^.shiftmode:=SM_ROR;
+                   taicpu(hpfar1).ops := 3;
+
+                   if not Assigned(hp1) then
+                     GetNextInstruction(p,hp1);
+
+                   RemoveCurrentP(p, hp1);
+
+                   result:=true;
+                   exit;
+                 end
+               else if MatchInstruction(hpfar1, A_UXTH, [C_None], [PF_None]) and
+                 (taicpu(hpfar1).ops=2) and
+                 (taicpu(p).oper[2]^.shifterop^.shiftimm in [16]) and
+                 MatchOperand(taicpu(hpfar1).oper[1]^, taicpu(p).oper[0]^.reg) then
+                 begin
+                   taicpu(hpfar1).oper[1]^.reg := taicpu(p).oper[1]^.reg;
+                   taicpu(hpfar1).loadshifterop(2,taicpu(p).oper[2]^.shifterop^);
+                   taicpu(hpfar1).oper[2]^.shifterop^.shiftmode:=SM_ROR;
+                   taicpu(hpfar1).ops := 3;
+
+                   if not Assigned(hp1) then
+                     GetNextInstruction(p,hp1);
+
+                   RemoveCurrentP(p, hp1);
+
+                   result:=true;
+                   exit;
+                 end
+               else if MatchInstruction(hpfar1, A_AND, [C_None], [PF_None]) and
+                 (taicpu(hpfar1).ops = 3) and
+                 (taicpu(hpfar1).oper[2]^.typ = top_const) and
+                 (taicpu(hpfar1).oper[2]^.val = $FF) and
+                 (taicpu(p).oper[2]^.shifterop^.shiftimm in [8,16,24]) and
+                 MatchOperand(taicpu(hpfar1).oper[1]^, taicpu(p).oper[0]^.reg) then
+                 begin
+                   taicpu(hpfar1).ops := 3;
+                   taicpu(hpfar1).opcode := A_UXTB;
+                   taicpu(hpfar1).oper[1]^.reg := taicpu(p).oper[1]^.reg;
+                   taicpu(hpfar1).loadshifterop(2,taicpu(p).oper[2]^.shifterop^);
+                   taicpu(hpfar1).oper[2]^.shifterop^.shiftmode:=SM_ROR;
+
+                   if not Assigned(hp1) then
+                     GetNextInstruction(p,hp1);
+
+                   RemoveCurrentP(p, hp1);
+
+                   result:=true;
+                   exit;
+                 end;
              end;
              end;
-         end;
 
 
-      { 2-operald mov optimisations }
-      if (taicpu(p).ops = 2) then
-        begin
-          {
-            This removes the mul from
-            mov rX,0
-            ...
-            mul ...,rX,...
-          }
-          if (taicpu(p).oper[1]^.typ = top_const) then
+          { 2-operald mov optimisations }
+          if (taicpu(p).ops = 2) then
             begin
             begin
-(*          if false and
-            (taicpu(p).oper[1]^.val=0) and
-            MatchInstruction(hpfar1, [A_MUL,A_MLA], [taicpu(p).condition], [taicpu(p).oppostfix]) and
-            (((taicpu(hpfar1).oper[1]^.typ=top_reg) and MatchOperand(taicpu(p).oper[0]^, taicpu(hpfar1).oper[1]^)) or
-             ((taicpu(hpfar1).oper[2]^.typ=top_reg) and MatchOperand(taicpu(p).oper[0]^, taicpu(hpfar1).oper[2]^))) then
-              begin
-                TransferUsedRegs(TmpUsedRegs);
-                UpdateUsedRegs(TmpUsedRegs, tai(p.next));
-                UpdateUsedRegs(TmpUsedRegs, tai(hpfar1.next));
-                DebugMsg('Peephole Optimization: MovMUL/MLA2Mov0 done', p);
-                if taicpu(hpfar1).opcode=A_MUL then
-                  taicpu(hpfar1).loadconst(1,0)
-                else
-                  taicpu(hpfar1).loadreg(1,taicpu(hpfar1).oper[3]^.reg);
-                taicpu(hpfar1).ops:=2;
-                taicpu(hpfar1).opcode:=A_MOV;
-                if not(RegUsedAfterInstruction(taicpu(p).oper[0]^.reg,hpfar1,TmpUsedRegs)) then
-                  RemoveCurrentP(p);
-                Result:=true;
-                exit;
-              end
-          else*) if (taicpu(p).oper[1]^.val=0) and
-              MatchInstruction(hpfar1, A_MLA, [taicpu(p).condition], [taicpu(p).oppostfix]) and
-              MatchOperand(taicpu(p).oper[0]^, taicpu(hpfar1).oper[3]^) then
+              {
+                This removes the mul from
+                mov rX,0
+                ...
+                mul ...,rX,...
+              }
+              if (taicpu(p).oper[1]^.typ = top_const) then
                 begin
                 begin
-                  TransferUsedRegs(TmpUsedRegs);
-                  UpdateUsedRegs(TmpUsedRegs, tai(p.next));
-                  UpdateUsedRegs(TmpUsedRegs, tai(hpfar1.next));
-                  DebugMsg('Peephole Optimization: MovMLA2MUL 1 done', p);
-                  taicpu(hpfar1).ops:=3;
-                  taicpu(hpfar1).opcode:=A_MUL;
-                  if not(RegUsedAfterInstruction(taicpu(p).oper[0]^.reg,hpfar1,TmpUsedRegs)) then
-                    begin
+    (*          if false and
+                (taicpu(p).oper[1]^.val=0) and
+                MatchInstruction(hpfar1, [A_MUL,A_MLA], [taicpu(p).condition], [taicpu(p).oppostfix]) and
+                (((taicpu(hpfar1).oper[1]^.typ=top_reg) and MatchOperand(taicpu(p).oper[0]^, taicpu(hpfar1).oper[1]^)) or
+                 ((taicpu(hpfar1).oper[2]^.typ=top_reg) and MatchOperand(taicpu(p).oper[0]^, taicpu(hpfar1).oper[2]^))) then
+                  begin
+                    TransferUsedRegs(TmpUsedRegs);
+                    UpdateUsedRegs(TmpUsedRegs, tai(p.next));
+                    UpdateUsedRegs(TmpUsedRegs, tai(hpfar1.next));
+                    DebugMsg('Peephole Optimization: MovMUL/MLA2Mov0 done', p);
+                    if taicpu(hpfar1).opcode=A_MUL then
+                      taicpu(hpfar1).loadconst(1,0)
+                    else
+                      taicpu(hpfar1).loadreg(1,taicpu(hpfar1).oper[3]^.reg);
+                    taicpu(hpfar1).ops:=2;
+                    taicpu(hpfar1).opcode:=A_MOV;
+                    if not(RegUsedAfterInstruction(taicpu(p).oper[0]^.reg,hpfar1,TmpUsedRegs)) then
                       RemoveCurrentP(p);
                       RemoveCurrentP(p);
-                      Result:=true;
-                    end;
-                  exit;
-                end
-            {
-              This changes the very common
-              mov r0, #0
-              str r0, [...]
-              mov r0, #0
-              str r0, [...]
-
-              and removes all superfluous mov instructions
-            }
-            else if (taicpu(hpfar1).opcode=A_STR) then
-              begin
-                hp1 := hpfar1;
-                while MatchInstruction(hp1, A_STR, [taicpu(p).condition], []) and
-                      MatchOperand(taicpu(p).oper[0]^, taicpu(hpfar1).oper[0]^) and
-                      GetNextInstruction(hp1, hp2) and
-                      MatchInstruction(hp2, A_MOV, [taicpu(p).condition], [PF_None]) and
-                      (taicpu(hp2).ops = 2) and
-                      MatchOperand(taicpu(hp2).oper[0]^, taicpu(p).oper[0]^) and
-                      MatchOperand(taicpu(hp2).oper[1]^, taicpu(p).oper[1]^) do
+                    Result:=true;
+                    exit;
+                  end
+              else*) if (taicpu(p).oper[1]^.val=0) and
+                  MatchInstruction(hpfar1, A_MLA, [taicpu(p).condition], [taicpu(p).oppostfix]) and
+                  MatchOperand(taicpu(p).oper[0]^, taicpu(hpfar1).oper[3]^) then
+                    begin
+                      TransferUsedRegs(TmpUsedRegs);
+                      UpdateUsedRegs(TmpUsedRegs, tai(p.next));
+                      UpdateUsedRegs(TmpUsedRegs, tai(hpfar1.next));
+                      DebugMsg('Peephole Optimization: MovMLA2MUL 1 done', p);
+                      taicpu(hpfar1).ops:=3;
+                      taicpu(hpfar1).opcode:=A_MUL;
+                      if not(RegUsedAfterInstruction(taicpu(p).oper[0]^.reg,hpfar1,TmpUsedRegs)) then
+                        begin
+                          RemoveCurrentP(p);
+                          Result:=true;
+                        end;
+                      exit;
+                    end
+                {
+                  This changes the very common
+                  mov r0, #0
+                  str r0, [...]
+                  mov r0, #0
+                  str r0, [...]
+
+                  and removes all superfluous mov instructions
+                }
+                else if (taicpu(hpfar1).opcode=A_STR) then
                   begin
                   begin
-                    DebugMsg('Peephole Optimization: MovStrMov done', hp2);
-                    GetNextInstruction(hp2,hp1);
-                    asml.remove(hp2);
-                    hp2.free;
-                    result:=true;
-                    if not assigned(hp1) then break;
-                  end;
+                    hp1 := hpfar1;
+                    while MatchInstruction(hp1, A_STR, [taicpu(p).condition], []) and
+                          MatchOperand(taicpu(p).oper[0]^, taicpu(hpfar1).oper[0]^) and
+                          GetNextInstruction(hp1, hp2) and
+                          MatchInstruction(hp2, A_MOV, [taicpu(p).condition], [PF_None]) and
+                          (taicpu(hp2).ops = 2) and
+                          MatchOperand(taicpu(hp2).oper[0]^, taicpu(p).oper[0]^) and
+                          MatchOperand(taicpu(hp2).oper[1]^, taicpu(p).oper[1]^) do
+                      begin
+                        DebugMsg('Peephole Optimization: MovStrMov done', hp2);
+                        GetNextInstruction(hp2,hp1);
+                        asml.remove(hp2);
+                        hp2.free;
+                        result:=true;
+                        if not assigned(hp1) then break;
+                      end;
 
 
-                if Result then
-                  Exit;
-              end;
-            end;
-          {
-            This removes the first mov from
-            mov rX,...
-            mov rX,...
-          }
-          if taicpu(hpfar1).opcode=A_MOV then
-            begin
-              hp1 := p;
-              while MatchInstruction(hpfar1, A_MOV, [taicpu(hp1).condition], [taicpu(hp1).oppostfix]) and
-                    (taicpu(hpfar1).ops = 2) and
-                    MatchOperand(taicpu(hp1).oper[0]^, taicpu(hpfar1).oper[0]^) and
-                    { don't remove the first mov if the second is a mov rX,rX }
-                    not(MatchOperand(taicpu(hpfar1).oper[0]^, taicpu(hpfar1).oper[1]^)) do
+                    if Result then
+                      Exit;
+                  end;
+                end;
+              {
+                This removes the first mov from
+                mov rX,...
+                mov rX,...
+              }
+              if taicpu(hpfar1).opcode=A_MOV then
                 begin
                 begin
-                  { Defer removing the first p until after the while loop }
-                  if p <> hp1 then
+                  hp1 := p;
+                  while MatchInstruction(hpfar1, A_MOV, [taicpu(hp1).condition], [taicpu(hp1).oppostfix]) and
+                        (taicpu(hpfar1).ops = 2) and
+                        MatchOperand(taicpu(hp1).oper[0]^, taicpu(hpfar1).oper[0]^) and
+                        { don't remove the first mov if the second is a mov rX,rX }
+                        not(MatchOperand(taicpu(hpfar1).oper[0]^, taicpu(hpfar1).oper[1]^)) do
                     begin
                     begin
-                      DebugMsg('Peephole Optimization: MovMov done', hp1);
-                      asml.remove(hp1);
-                      hp1.free;
+                      { Defer removing the first p until after the while loop }
+                      if p <> hp1 then
+                        begin
+                          DebugMsg('Peephole Optimization: MovMov done', hp1);
+                          asml.remove(hp1);
+                          hp1.free;
+                        end;
+                      hp1:=hpfar1;
+                      GetNextInstruction(hpfar1,hpfar1);
+                      result:=true;
+                      if not assigned(hpfar1) then
+                        Break;
+                    end;
+
+                  if Result then
+                    begin
+                      DebugMsg('Peephole Optimization: MovMov done', p);
+                      RemoveCurrentp(p);
+                      Exit;
                     end;
                     end;
-                  hp1:=hpfar1;
-                  GetNextInstruction(hpfar1,hpfar1);
-                  result:=true;
-                  if not assigned(hpfar1) then
-                    Break;
                 end;
                 end;
 
 
-              if Result then
+              if RedundantMovProcess(p,hpfar1) then
                 begin
                 begin
-                  DebugMsg('Peephole Optimization: MovMov done', p);
-                  RemoveCurrentp(p);
-                  Exit;
+                  Result:=true;
+                  { p might not point at a mov anymore }
+                  exit;
                 end;
                 end;
-            end;
 
 
-          if RedundantMovProcess(p,hpfar1) then
-            begin
-              Result:=true;
-              { p might not point at a mov anymore }
-              exit;
-            end;
+              { If hpfar1 is nil after the call to RedundantMovProcess, it is
+                because it would have become a dangling pointer, so reinitialise it. }
+              if not Assigned(hpfar1) then
+                Continue;
 
 
-          { Fold the very common sequence
-              mov  regA, regB
-              ldr* regA, [regA]
-            to
-              ldr* regA, [regB]
-            CAUTION! If this one is successful p might not be a mov instruction anymore!
-          }
-          if
-             // Make sure that Thumb code doesn't propagate a high register into a reference
-             (
-               (
-                 GenerateThumbCode and
-                 (getsupreg(taicpu(p).oper[1]^.reg) < RS_R8)
-               ) or (not GenerateThumbCode)
-             ) and
-             (taicpu(p).oper[1]^.typ = top_reg) and
-             (taicpu(p).oppostfix = PF_NONE) and
-             MatchInstruction(hpfar1, [A_LDR, A_STR], [taicpu(p).condition], []) and
-             (taicpu(hpfar1).oper[1]^.typ = top_ref) and
-             { We can change the base register only when the instruction uses AM_OFFSET }
-             ((taicpu(hpfar1).oper[1]^.ref^.index = taicpu(p).oper[0]^.reg) or
-               ((taicpu(hpfar1).oper[1]^.ref^.addressmode = AM_OFFSET) and
-                (taicpu(hpfar1).oper[1]^.ref^.base = taicpu(p).oper[0]^.reg))
-             ) and
-             not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hpfar1)) and
-             RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hpfar1)) then
-            begin
-              DebugMsg('Peephole Optimization: MovLdr2Ldr done', hpfar1);
-              if (taicpu(hpfar1).oper[1]^.ref^.addressmode = AM_OFFSET) and
-                 (taicpu(hpfar1).oper[1]^.ref^.base = taicpu(p).oper[0]^.reg) then
-                taicpu(hpfar1).oper[1]^.ref^.base := taicpu(p).oper[1]^.reg;
-
-              if taicpu(hpfar1).oper[1]^.ref^.index = taicpu(p).oper[0]^.reg then
-                taicpu(hpfar1).oper[1]^.ref^.index := taicpu(p).oper[1]^.reg;
-
-              dealloc:=FindRegDeAlloc(taicpu(p).oper[1]^.reg, tai(p.Next));
-              if Assigned(dealloc) then
+              { Fold the very common sequence
+                  mov  regA, regB
+                  ldr* regA, [regA]
+                to
+                  ldr* regA, [regB]
+                CAUTION! If this one is successful p might not be a mov instruction anymore!
+              }
+              if
+                 // Make sure that Thumb code doesn't propagate a high register into a reference
+                 (
+                   (
+                     GenerateThumbCode and
+                     (getsupreg(taicpu(p).oper[1]^.reg) < RS_R8)
+                   ) or (not GenerateThumbCode)
+                 ) and
+                 (taicpu(p).oper[1]^.typ = top_reg) and
+                 (taicpu(p).oppostfix = PF_NONE) and
+                 MatchInstruction(hpfar1, [A_LDR, A_STR], [taicpu(p).condition], []) and
+                 (taicpu(hpfar1).oper[1]^.typ = top_ref) and
+                 { We can change the base register only when the instruction uses AM_OFFSET }
+                 ((taicpu(hpfar1).oper[1]^.ref^.index = taicpu(p).oper[0]^.reg) or
+                   ((taicpu(hpfar1).oper[1]^.ref^.addressmode = AM_OFFSET) and
+                    (taicpu(hpfar1).oper[1]^.ref^.base = taicpu(p).oper[0]^.reg))
+                 ) and
+                 not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hpfar1)) and
+                 RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hpfar1)) then
                 begin
                 begin
-                  asml.remove(dealloc);
-                  asml.InsertAfter(dealloc,hpfar1);
-                end;
+                  DebugMsg('Peephole Optimization: MovLdr2Ldr done', hpfar1);
+                  if (taicpu(hpfar1).oper[1]^.ref^.addressmode = AM_OFFSET) and
+                     (taicpu(hpfar1).oper[1]^.ref^.base = taicpu(p).oper[0]^.reg) then
+                    taicpu(hpfar1).oper[1]^.ref^.base := taicpu(p).oper[1]^.reg;
 
 
-              if not Assigned(hp1) then
-                GetNextInstruction(p, hp1);
+                  if taicpu(hpfar1).oper[1]^.ref^.index = taicpu(p).oper[0]^.reg then
+                    taicpu(hpfar1).oper[1]^.ref^.index := taicpu(p).oper[1]^.reg;
 
 
-              RemoveCurrentP(p, hp1);
+                  dealloc:=FindRegDeAlloc(taicpu(p).oper[1]^.reg, tai(p.Next));
+                  if Assigned(dealloc) then
+                    begin
+                      asml.remove(dealloc);
+                      asml.InsertAfter(dealloc,hpfar1);
+                    end;
 
 
-              result:=true;
-              Exit;
-            end
-        end
+                  if not Assigned(hp1) then
+                    GetNextInstruction(p, hp1);
 
 
-      { 3-operald mov optimisations }
-      else if (taicpu(p).ops = 3) then
-        begin
+                  RemoveCurrentP(p, hp1);
 
 
-          if (taicpu(p).oper[2]^.typ = top_shifterop) and
-            (taicpu(p).oper[2]^.shifterop^.rs = NR_NO) and
-            (taicpu(p).oper[2]^.shifterop^.shiftmode = SM_LSR) and
-            (taicpu(hpfar1).ops>=1) and
-            (taicpu(hpfar1).oper[0]^.typ=top_reg) and
-            (not RegModifiedBetween(taicpu(hpfar1).oper[0]^.reg, p, hpfar1)) and
-            RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hpfar1)) then
-            begin
-              if (taicpu(p).oper[2]^.shifterop^.shiftimm >= 24 ) and
-                MatchInstruction(hpfar1, A_AND, [taicpu(p).condition], [taicpu(p).oppostfix]) and
-                (taicpu(hpfar1).ops=3) and
-                MatchOperand(taicpu(p).oper[0]^, taicpu(hpfar1).oper[1]^) and
-                (taicpu(hpfar1).oper[2]^.typ = top_const) and
-                { Check if the AND actually would only mask out bits being already zero because of the shift
-                }
-                ((($ffffffff shr taicpu(p).oper[2]^.shifterop^.shiftimm) and taicpu(hpfar1).oper[2]^.val) =
-                  ($ffffffff shr taicpu(p).oper[2]^.shifterop^.shiftimm)) then
-                begin
-                  DebugMsg('Peephole Optimization: LsrAnd2Lsr done', hpfar1);
-                  taicpu(p).oper[0]^.reg:=taicpu(hpfar1).oper[0]^.reg;
-                  asml.remove(hpfar1);
-                  hpfar1.free;
                   result:=true;
                   result:=true;
                   Exit;
                   Exit;
                 end
                 end
-              else if MatchInstruction(hpfar1, A_BIC, [taicpu(p).condition], [taicpu(p).oppostfix]) and
-                (taicpu(hpfar1).ops=3) and
-                MatchOperand(taicpu(p).oper[0]^, taicpu(hpfar1).oper[1]^) and
-                (taicpu(hpfar1).oper[2]^.typ = top_const) and
-                { Check if the BIC actually would only mask out bits beeing already zero because of the shift }
-                (taicpu(hpfar1).oper[2]^.val<>0) and
-                (BsfDWord(taicpu(hpfar1).oper[2]^.val)>=32-taicpu(p).oper[2]^.shifterop^.shiftimm) then
-                begin
-                  DebugMsg('Peephole Optimization: LsrBic2Lsr done', hpfar1);
-                  taicpu(p).oper[0]^.reg:=taicpu(hpfar1).oper[0]^.reg;
-                  asml.remove(hpfar1);
-                  hpfar1.free;
-                  result:=true;
-                  Exit;
-                end;
-            end;
-          { This folds shifterops into following instructions
-            mov r0, r1, lsl #8
-            add r2, r3, r0
+            end
 
 
-            to
+          { 3-operald mov optimisations }
+          else if (taicpu(p).ops = 3) then
+            begin
 
 
-            add r2, r3, r1, lsl #8
-            CAUTION! If this one is successful p might not be a mov instruction anymore!
-          }
-          if (taicpu(p).oper[1]^.typ = top_reg) and
-           (taicpu(p).oper[2]^.typ = top_shifterop) and
-           (taicpu(p).oppostfix = PF_NONE) and
-           MatchInstruction(hpfar1, [A_ADD, A_ADC, A_RSB, A_RSC, A_SUB, A_SBC,
-                                  A_AND, A_BIC, A_EOR, A_ORR, A_TEQ, A_TST,
-                                  A_CMP, A_CMN],
-                            [taicpu(p).condition], [PF_None]) and
-           (not ((GenerateThumb2Code) and
-                 (taicpu(hpfar1).opcode in [A_SBC]) and
-                 (((taicpu(hpfar1).ops=3) and
-                   MatchOperand(taicpu(p).oper[0]^, taicpu(hpfar1).oper[1]^.reg)) or
-                  ((taicpu(hpfar1).ops=2) and
-                   MatchOperand(taicpu(p).oper[0]^, taicpu(hpfar1).oper[0]^.reg))))) and
-           RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hpfar1)) and
-           (taicpu(hpfar1).ops >= 2) and
-           {Currently we can't fold into another shifterop}
-           (taicpu(hpfar1).oper[taicpu(hpfar1).ops-1]^.typ = top_reg) and
-           {Folding rrx is problematic because of the C-Flag, as we currently can't check
-            NR_DEFAULTFLAGS for modification}
-           (
-             {Everything is fine if we don't use RRX}
-             (taicpu(p).oper[2]^.shifterop^.shiftmode <> SM_RRX) or
-             (
-               {If it is RRX, then check if we're just accessing the next instruction}
-               Assigned(hp1) and
-               (hpfar1 = hp1)
-             )
-           ) and
-           { reg1 might not be modified inbetween }
-           not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hpfar1)) and
-           { The shifterop can contain a register, might not be modified}
-           (
-             (taicpu(p).oper[2]^.shifterop^.rs = NR_NO) or
-             not(RegModifiedBetween(taicpu(p).oper[2]^.shifterop^.rs, p, hpfar1))
-           ) and
-           (
-             {Only ONE of the two src operands is allowed to match}
-             MatchOperand(taicpu(p).oper[0]^, taicpu(hpfar1).oper[taicpu(hpfar1).ops-2]^) xor
-             MatchOperand(taicpu(p).oper[0]^, taicpu(hpfar1).oper[taicpu(hpfar1).ops-1]^)
-           ) then
-          begin
-            if taicpu(hpfar1).opcode in [A_TST, A_TEQ, A_CMN] then
-              I2:=0
-            else
-              I2:=1;
-            for I:=I2 to taicpu(hpfar1).ops-1 do
-              if MatchOperand(taicpu(p).oper[0]^, taicpu(hpfar1).oper[I]^.reg) then
+              if (taicpu(p).oper[2]^.typ = top_shifterop) and
+                (taicpu(p).oper[2]^.shifterop^.rs = NR_NO) and
+                (taicpu(p).oper[2]^.shifterop^.shiftmode = SM_LSR) and
+                (taicpu(hpfar1).ops>=1) and
+                (taicpu(hpfar1).oper[0]^.typ=top_reg) and
+                (not RegModifiedBetween(taicpu(hpfar1).oper[0]^.reg, p, hpfar1)) and
+                RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hpfar1)) then
                 begin
                 begin
-                  { If the parameter matched on the second op from the RIGHT
-                    we have to switch the parameters, this will not happen for CMP
-                    were we're only evaluating the most right parameter
-                  }
-                  if I <> taicpu(hpfar1).ops-1 then
+                  if (taicpu(p).oper[2]^.shifterop^.shiftimm >= 24 ) and
+                    MatchInstruction(hpfar1, A_AND, [taicpu(p).condition], [taicpu(p).oppostfix]) and
+                    (taicpu(hpfar1).ops=3) and
+                    MatchOperand(taicpu(p).oper[0]^, taicpu(hpfar1).oper[1]^) and
+                    (taicpu(hpfar1).oper[2]^.typ = top_const) and
+                    { Check if the AND actually would only mask out bits being already zero because of the shift
+                    }
+                    ((($ffffffff shr taicpu(p).oper[2]^.shifterop^.shiftimm) and taicpu(hpfar1).oper[2]^.val) =
+                      ($ffffffff shr taicpu(p).oper[2]^.shifterop^.shiftimm)) then
                     begin
                     begin
-                      {The SUB operators need to be changed when we swap parameters}
-                      case taicpu(hpfar1).opcode of
-                        A_SUB: tempop:=A_RSB;
-                        A_SBC: tempop:=A_RSC;
-                        A_RSB: tempop:=A_SUB;
-                        A_RSC: tempop:=A_SBC;
-                        else tempop:=taicpu(hpfar1).opcode;
-                      end;
-                      if taicpu(hpfar1).ops = 3 then
-                        hp2:=taicpu.op_reg_reg_reg_shifterop(tempop,
-                             taicpu(hpfar1).oper[0]^.reg, taicpu(hpfar1).oper[2]^.reg,
-                             taicpu(p).oper[1]^.reg, taicpu(p).oper[2]^.shifterop^)
-                      else
-                        hp2:=taicpu.op_reg_reg_shifterop(tempop,
-                             taicpu(hpfar1).oper[0]^.reg, taicpu(p).oper[1]^.reg,
-                             taicpu(p).oper[2]^.shifterop^);
+                      DebugMsg('Peephole Optimization: LsrAnd2Lsr done', hpfar1);
+                      taicpu(p).oper[0]^.reg:=taicpu(hpfar1).oper[0]^.reg;
+                      asml.remove(hpfar1);
+                      hpfar1.free;
+                      result:=true;
+                      Exit;
                     end
                     end
-                  else
-                    if taicpu(hpfar1).ops = 3 then
-                      hp2:=taicpu.op_reg_reg_reg_shifterop(taicpu(hpfar1).opcode,
-                           taicpu(hpfar1).oper[0]^.reg, taicpu(hpfar1).oper[1]^.reg,
-                           taicpu(p).oper[1]^.reg, taicpu(p).oper[2]^.shifterop^)
-                    else
-                      hp2:=taicpu.op_reg_reg_shifterop(taicpu(hpfar1).opcode,
-                           taicpu(hpfar1).oper[0]^.reg, taicpu(p).oper[1]^.reg,
-                           taicpu(p).oper[2]^.shifterop^);
-                  if taicpu(p).oper[2]^.shifterop^.rs<>NR_NO then
-                    AllocRegBetween(taicpu(p).oper[2]^.shifterop^.rs,p,hpfar1,UsedRegs);
-                  AllocRegBetween(taicpu(p).oper[1]^.reg,p,hpfar1,UsedRegs);
-                  asml.insertbefore(hp2, hpfar1);
-                  asml.remove(hpfar1);
-                  hpfar1.free;
-                  DebugMsg('Peephole Optimization: FoldShiftProcess done', hp2);
+                  else if MatchInstruction(hpfar1, A_BIC, [taicpu(p).condition], [taicpu(p).oppostfix]) and
+                    (taicpu(hpfar1).ops=3) and
+                    MatchOperand(taicpu(p).oper[0]^, taicpu(hpfar1).oper[1]^) and
+                    (taicpu(hpfar1).oper[2]^.typ = top_const) and
+                    { Check if the BIC actually would only mask out bits beeing already zero because of the shift }
+                    (taicpu(hpfar1).oper[2]^.val<>0) and
+                    (BsfDWord(taicpu(hpfar1).oper[2]^.val)>=32-taicpu(p).oper[2]^.shifterop^.shiftimm) then
+                    begin
+                      DebugMsg('Peephole Optimization: LsrBic2Lsr done', hpfar1);
+                      taicpu(p).oper[0]^.reg:=taicpu(hpfar1).oper[0]^.reg;
+                      asml.remove(hpfar1);
+                      hpfar1.free;
+                      result:=true;
+                      Exit;
+                    end;
+                end;
+              { This folds shifterops into following instructions
+                mov r0, r1, lsl #8
+                add r2, r3, r0
 
 
-                  if not Assigned(hp1) then
-                    GetNextInstruction(p, hp1)
-                  else if hp1 = hpfar1 then
-                    { If hp1 = hpfar1, then it's a dangling pointer }
-                    hp1 := hp2;
+                to
 
 
-                  RemoveCurrentP(p, hp1);
-                  Result:=true;
-                  Exit;
-                end;
-          end;
-        {
-          Fold
-            mov r1, r1, lsl #2
-            ldr/ldrb r0, [r0, r1]
-          to
-            ldr/ldrb r0, [r0, r1, lsl #2]
-
-          XXX: This still needs some work, as we quite often encounter something like
-                 mov r1, r2, lsl #2
-                 add r2, r3, #imm
-                 ldr r0, [r2, r1]
-               which can't be folded because r2 is overwritten between the shift and the ldr.
-               We could try to shuffle the registers around and fold it into.
-                 add r1, r3, #imm
-                 ldr r0, [r1, r2, lsl #2]
-        }
-        if (not(GenerateThumbCode)) and
-          { thumb2 allows only lsl #0..#3 }
-          (not(GenerateThumb2Code) or
-           ((taicpu(p).oper[2]^.shifterop^.shiftimm in [0..3]) and
-            (taicpu(p).oper[2]^.shifterop^.shiftmode=SM_LSL)
-           )
-          ) and
-           (taicpu(p).oper[1]^.typ = top_reg) and
-           (taicpu(p).oper[2]^.typ = top_shifterop) and
-           { RRX is tough to handle, because it requires tracking the C-Flag,
-             it is also extremly unlikely to be emitted this way}
-           (taicpu(p).oper[2]^.shifterop^.shiftmode <> SM_RRX) and
-           (taicpu(p).oper[2]^.shifterop^.shiftimm <> 0) and
-           (taicpu(p).oppostfix = PF_NONE) and
-           {Only LDR, LDRB, STR, STRB can handle scaled register indexing}
-           (MatchInstruction(hpfar1, [A_LDR, A_STR], [taicpu(p).condition], [PF_None, PF_B]) or
-            (GenerateThumb2Code and
-             MatchInstruction(hpfar1, [A_LDR, A_STR], [taicpu(p).condition], [PF_None, PF_B, PF_SB, PF_H, PF_SH]))
-           ) and
-           (
-             {If this is address by offset, one of the two registers can be used}
-             ((taicpu(hpfar1).oper[1]^.ref^.addressmode=AM_OFFSET) and
+                add r2, r3, r1, lsl #8
+                CAUTION! If this one is successful p might not be a mov instruction anymore!
+              }
+              if (taicpu(p).oper[1]^.typ = top_reg) and
+               (taicpu(p).oper[2]^.typ = top_shifterop) and
+               (taicpu(p).oppostfix = PF_NONE) and
+               MatchInstruction(hpfar1, [A_ADD, A_ADC, A_RSB, A_RSC, A_SUB, A_SBC,
+                                      A_AND, A_BIC, A_EOR, A_ORR, A_TEQ, A_TST,
+                                      A_CMP, A_CMN],
+                                [taicpu(p).condition], [PF_None]) and
+               (not ((GenerateThumb2Code) and
+                     (taicpu(hpfar1).opcode in [A_SBC]) and
+                     (((taicpu(hpfar1).ops=3) and
+                       MatchOperand(taicpu(p).oper[0]^, taicpu(hpfar1).oper[1]^.reg)) or
+                      ((taicpu(hpfar1).ops=2) and
+                       MatchOperand(taicpu(p).oper[0]^, taicpu(hpfar1).oper[0]^.reg))))) and
+               RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hpfar1)) and
+               (taicpu(hpfar1).ops >= 2) and
+               {Currently we can't fold into another shifterop}
+               (taicpu(hpfar1).oper[taicpu(hpfar1).ops-1]^.typ = top_reg) and
+               {Folding rrx is problematic because of the C-Flag, as we currently can't check
+                NR_DEFAULTFLAGS for modification}
+               (
+                 {Everything is fine if we don't use RRX}
+                 (taicpu(p).oper[2]^.shifterop^.shiftmode <> SM_RRX) or
+                 (
+                   {If it is RRX, then check if we're just accessing the next instruction}
+                   Assigned(hp1) and
+                   (hpfar1 = hp1)
+                 )
+               ) and
+               { reg1 might not be modified inbetween }
+               not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hpfar1)) and
+               { The shifterop can contain a register, might not be modified}
+               (
+                 (taicpu(p).oper[2]^.shifterop^.rs = NR_NO) or
+                 not(RegModifiedBetween(taicpu(p).oper[2]^.shifterop^.rs, p, hpfar1))
+               ) and
                (
                (
-                 (taicpu(hpfar1).oper[1]^.ref^.index = taicpu(p).oper[0]^.reg) xor
-                 (taicpu(hpfar1).oper[1]^.ref^.base = taicpu(p).oper[0]^.reg)
+                 {Only ONE of the two src operands is allowed to match}
+                 MatchOperand(taicpu(p).oper[0]^, taicpu(hpfar1).oper[taicpu(hpfar1).ops-2]^) xor
+                 MatchOperand(taicpu(p).oper[0]^, taicpu(hpfar1).oper[taicpu(hpfar1).ops-1]^)
+               ) then
+              begin
+                if taicpu(hpfar1).opcode in [A_TST, A_TEQ, A_CMN] then
+                  I2:=0
+                else
+                  I2:=1;
+                for I:=I2 to taicpu(hpfar1).ops-1 do
+                  if MatchOperand(taicpu(p).oper[0]^, taicpu(hpfar1).oper[I]^.reg) then
+                    begin
+                      { If the parameter matched on the second op from the RIGHT
+                        we have to switch the parameters, this will not happen for CMP
+                        were we're only evaluating the most right parameter
+                      }
+                      if I <> taicpu(hpfar1).ops-1 then
+                        begin
+                          {The SUB operators need to be changed when we swap parameters}
+                          case taicpu(hpfar1).opcode of
+                            A_SUB: tempop:=A_RSB;
+                            A_SBC: tempop:=A_RSC;
+                            A_RSB: tempop:=A_SUB;
+                            A_RSC: tempop:=A_SBC;
+                            else tempop:=taicpu(hpfar1).opcode;
+                          end;
+                          if taicpu(hpfar1).ops = 3 then
+                            hp2:=taicpu.op_reg_reg_reg_shifterop(tempop,
+                                 taicpu(hpfar1).oper[0]^.reg, taicpu(hpfar1).oper[2]^.reg,
+                                 taicpu(p).oper[1]^.reg, taicpu(p).oper[2]^.shifterop^)
+                          else
+                            hp2:=taicpu.op_reg_reg_shifterop(tempop,
+                                 taicpu(hpfar1).oper[0]^.reg, taicpu(p).oper[1]^.reg,
+                                 taicpu(p).oper[2]^.shifterop^);
+                        end
+                      else
+                        if taicpu(hpfar1).ops = 3 then
+                          hp2:=taicpu.op_reg_reg_reg_shifterop(taicpu(hpfar1).opcode,
+                               taicpu(hpfar1).oper[0]^.reg, taicpu(hpfar1).oper[1]^.reg,
+                               taicpu(p).oper[1]^.reg, taicpu(p).oper[2]^.shifterop^)
+                        else
+                          hp2:=taicpu.op_reg_reg_shifterop(taicpu(hpfar1).opcode,
+                               taicpu(hpfar1).oper[0]^.reg, taicpu(p).oper[1]^.reg,
+                               taicpu(p).oper[2]^.shifterop^);
+                      if taicpu(p).oper[2]^.shifterop^.rs<>NR_NO then
+                        AllocRegBetween(taicpu(p).oper[2]^.shifterop^.rs,p,hpfar1,UsedRegs);
+                      AllocRegBetween(taicpu(p).oper[1]^.reg,p,hpfar1,UsedRegs);
+                      asml.insertbefore(hp2, hpfar1);
+                      asml.remove(hpfar1);
+                      hpfar1.free;
+                      DebugMsg('Peephole Optimization: FoldShiftProcess done', hp2);
+
+                      if not Assigned(hp1) then
+                        GetNextInstruction(p, hp1)
+                      else if hp1 = hpfar1 then
+                        { If hp1 = hpfar1, then it's a dangling pointer }
+                        hp1 := hp2;
+
+                      RemoveCurrentP(p, hp1);
+                      Result:=true;
+                      Exit;
+                    end;
+              end;
+            {
+              Fold
+                mov r1, r1, lsl #2
+                ldr/ldrb r0, [r0, r1]
+              to
+                ldr/ldrb r0, [r0, r1, lsl #2]
+
+              XXX: This still needs some work, as we quite often encounter something like
+                     mov r1, r2, lsl #2
+                     add r2, r3, #imm
+                     ldr r0, [r2, r1]
+                   which can't be folded because r2 is overwritten between the shift and the ldr.
+                   We could try to shuffle the registers around and fold it into.
+                     add r1, r3, #imm
+                     ldr r0, [r1, r2, lsl #2]
+            }
+            if (not(GenerateThumbCode)) and
+              { thumb2 allows only lsl #0..#3 }
+              (not(GenerateThumb2Code) or
+               ((taicpu(p).oper[2]^.shifterop^.shiftimm in [0..3]) and
+                (taicpu(p).oper[2]^.shifterop^.shiftmode=SM_LSL)
                )
                )
-             ) or
-             {For post and preindexed only the index register can be used}
-             ((taicpu(hpfar1).oper[1]^.ref^.addressmode in [AM_POSTINDEXED, AM_PREINDEXED]) and
+              ) and
+               (taicpu(p).oper[1]^.typ = top_reg) and
+               (taicpu(p).oper[2]^.typ = top_shifterop) and
+               { RRX is tough to handle, because it requires tracking the C-Flag,
+                 it is also extremly unlikely to be emitted this way}
+               (taicpu(p).oper[2]^.shifterop^.shiftmode <> SM_RRX) and
+               (taicpu(p).oper[2]^.shifterop^.shiftimm <> 0) and
+               (taicpu(p).oppostfix = PF_NONE) and
+               {Only LDR, LDRB, STR, STRB can handle scaled register indexing}
+               (MatchInstruction(hpfar1, [A_LDR, A_STR], [taicpu(p).condition], [PF_None, PF_B]) or
+                (GenerateThumb2Code and
+                 MatchInstruction(hpfar1, [A_LDR, A_STR], [taicpu(p).condition], [PF_None, PF_B, PF_SB, PF_H, PF_SH]))
+               ) and
                (
                (
-                 (taicpu(hpfar1).oper[1]^.ref^.index = taicpu(p).oper[0]^.reg) and
-                 (taicpu(hpfar1).oper[1]^.ref^.base <> taicpu(p).oper[0]^.reg)
+                 {If this is address by offset, one of the two registers can be used}
+                 ((taicpu(hpfar1).oper[1]^.ref^.addressmode=AM_OFFSET) and
+                   (
+                     (taicpu(hpfar1).oper[1]^.ref^.index = taicpu(p).oper[0]^.reg) xor
+                     (taicpu(hpfar1).oper[1]^.ref^.base = taicpu(p).oper[0]^.reg)
+                   )
+                 ) or
+                 {For post and preindexed only the index register can be used}
+                 ((taicpu(hpfar1).oper[1]^.ref^.addressmode in [AM_POSTINDEXED, AM_PREINDEXED]) and
+                   (
+                     (taicpu(hpfar1).oper[1]^.ref^.index = taicpu(p).oper[0]^.reg) and
+                     (taicpu(hpfar1).oper[1]^.ref^.base <> taicpu(p).oper[0]^.reg)
+                   ) and
+                   (not GenerateThumb2Code)
+                 )
                ) and
                ) and
-               (not GenerateThumb2Code)
-             )
-           ) and
-           { Only fold if both registers are used. Otherwise we are folding p with itself }
-           (taicpu(hpfar1).oper[1]^.ref^.index<>NR_NO) and
-           (taicpu(hpfar1).oper[1]^.ref^.base<>NR_NO) and
-           { Only fold if there isn't another shifterop already, and offset is zero. }
-           (taicpu(hpfar1).oper[1]^.ref^.offset = 0) and
-           (taicpu(hpfar1).oper[1]^.ref^.shiftmode = SM_None) and
-           not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hpfar1)) and
-           RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hpfar1)) then
-           begin
-             { If the register we want to do the shift for resides in base, we need to swap that}
-             if (taicpu(hpfar1).oper[1]^.ref^.base = taicpu(p).oper[0]^.reg) then
-               taicpu(hpfar1).oper[1]^.ref^.base := taicpu(hpfar1).oper[1]^.ref^.index;
-             taicpu(hpfar1).oper[1]^.ref^.index := taicpu(p).oper[1]^.reg;
-             taicpu(hpfar1).oper[1]^.ref^.shiftmode := taicpu(p).oper[2]^.shifterop^.shiftmode;
-             taicpu(hpfar1).oper[1]^.ref^.shiftimm := taicpu(p).oper[2]^.shifterop^.shiftimm;
-             DebugMsg('Peephole Optimization: FoldShiftLdrStr done', hpfar1);
-             RemoveCurrentP(p);
-             Result:=true;
-             Exit;
-           end;
+               { Only fold if both registers are used. Otherwise we are folding p with itself }
+               (taicpu(hpfar1).oper[1]^.ref^.index<>NR_NO) and
+               (taicpu(hpfar1).oper[1]^.ref^.base<>NR_NO) and
+               { Only fold if there isn't another shifterop already, and offset is zero. }
+               (taicpu(hpfar1).oper[1]^.ref^.offset = 0) and
+               (taicpu(hpfar1).oper[1]^.ref^.shiftmode = SM_None) and
+               not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hpfar1)) and
+               RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hpfar1)) then
+               begin
+                 { If the register we want to do the shift for resides in base, we need to swap that}
+                 if (taicpu(hpfar1).oper[1]^.ref^.base = taicpu(p).oper[0]^.reg) then
+                   taicpu(hpfar1).oper[1]^.ref^.base := taicpu(hpfar1).oper[1]^.ref^.index;
+                 taicpu(hpfar1).oper[1]^.ref^.index := taicpu(p).oper[1]^.reg;
+                 taicpu(hpfar1).oper[1]^.ref^.shiftmode := taicpu(p).oper[2]^.shifterop^.shiftmode;
+                 taicpu(hpfar1).oper[1]^.ref^.shiftimm := taicpu(p).oper[2]^.shifterop^.shiftimm;
+                 DebugMsg('Peephole Optimization: FoldShiftLdrStr done', hpfar1);
+                 RemoveCurrentP(p);
+                 Result:=true;
+                 Exit;
+               end;
+            end;
+          {
+            Often we see shifts and then a superfluous mov to another register
+            In the future this might be handled in RedundantMovProcess when it uses RegisterTracking
+          }
+          if RemoveSuperfluousMove(p, hpfar1, 'MovMov2Mov') then
+            Result:=true;
+
+          Exit;
         end;
         end;
-      {
-        Often we see shifts and then a superfluous mov to another register
-        In the future this might be handled in RedundantMovProcess when it uses RegisterTracking
-      }
-      if RemoveSuperfluousMove(p, hpfar1, 'MovMov2Mov') then
-        Result:=true;
     end;
     end;
 
 
 
 

+ 60 - 50
compiler/armgen/aoptarm.pas

@@ -40,7 +40,7 @@ Type
     procedure DebugMsg(const s : string; p : tai);
     procedure DebugMsg(const s : string; p : tai);
 
 
     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; 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; reg: TRegister): Boolean;
 
 
     function OptPass1UXTB(var p: tai): Boolean;
     function OptPass1UXTB(var p: tai): Boolean;
@@ -292,10 +292,10 @@ Implementation
     end;
     end;
 
 
 
 
-  function TARMAsmOptimizer.RedundantMovProcess(var p: tai;hp1: tai):boolean;
+  function TARMAsmOptimizer.RedundantMovProcess(var p: tai; var hp1: tai):boolean;
     var
     var
       I: Integer;
       I: Integer;
-      current_hp: tai;
+      current_hp, next_hp: tai;
       LDRChange: Boolean;
       LDRChange: Boolean;
     begin
     begin
       Result:=false;
       Result:=false;
@@ -390,80 +390,80 @@ Implementation
               TransferUsedRegs(TmpUsedRegs);
               TransferUsedRegs(TmpUsedRegs);
 
 
               { Search local instruction block }
               { Search local instruction block }
-              while GetNextInstruction(current_hp, hp1) and (hp1 <> BlockEnd) and (hp1.typ = ait_instruction) do
+              while GetNextInstruction(current_hp, next_hp) and (next_hp <> BlockEnd) and (next_hp.typ = ait_instruction) do
                 begin
                 begin
                   UpdateUsedRegs(TmpUsedRegs, tai(current_hp.Next));
                   UpdateUsedRegs(TmpUsedRegs, tai(current_hp.Next));
                   LDRChange := False;
                   LDRChange := False;
 
 
-                  if (taicpu(hp1).opcode in [A_LDR,A_STR]) and (taicpu(hp1).ops = 2) then
+                  if (taicpu(next_hp).opcode in [A_LDR,A_STR]) and (taicpu(next_hp).ops = 2) then
                     begin
                     begin
 
 
                       { Change the registers from r1 to r0 }
                       { Change the registers from r1 to r0 }
-                      if (taicpu(hp1).oper[1]^.ref^.base = taicpu(p).oper[0]^.reg) and
+                      if (taicpu(next_hp).oper[1]^.ref^.base = taicpu(p).oper[0]^.reg) and
 {$ifdef ARM}
 {$ifdef ARM}
                         { This optimisation conflicts with something and raises
                         { This optimisation conflicts with something and raises
                           an access violation - needs further investigation. [Kit] }
                           an access violation - needs further investigation. [Kit] }
-                        (taicpu(hp1).opcode <> A_LDR) and
+                        (taicpu(next_hp).opcode <> A_LDR) and
 {$endif ARM}
 {$endif ARM}
                         { Don't mess around with the base register if the
                         { Don't mess around with the base register if the
                           reference is pre- or post-indexed }
                           reference is pre- or post-indexed }
-                        (taicpu(hp1).oper[1]^.ref^.addressmode = AM_OFFSET) then
+                        (taicpu(next_hp).oper[1]^.ref^.addressmode = AM_OFFSET) then
                         begin
                         begin
-                          taicpu(hp1).oper[1]^.ref^.base := taicpu(p).oper[1]^.reg;
+                          taicpu(next_hp).oper[1]^.ref^.base := taicpu(p).oper[1]^.reg;
                           LDRChange := True;
                           LDRChange := True;
                         end;
                         end;
 
 
-                      if taicpu(hp1).oper[1]^.ref^.index = taicpu(p).oper[0]^.reg then
+                      if taicpu(next_hp).oper[1]^.ref^.index = taicpu(p).oper[0]^.reg then
                         begin
                         begin
-                          taicpu(hp1).oper[1]^.ref^.index := taicpu(p).oper[1]^.reg;
+                          taicpu(next_hp).oper[1]^.ref^.index := taicpu(p).oper[1]^.reg;
                           LDRChange := True;
                           LDRChange := True;
                         end;
                         end;
 
 
                       if LDRChange then
                       if LDRChange then
-                        DebugMsg('Peephole Optimization: ' + std_regname(taicpu(p).oper[0]^.reg) + ' = ' + std_regname(taicpu(p).oper[1]^.reg) + ' (MovLdr2Ldr 1)', hp1);
+                        DebugMsg('Peephole Optimization: ' + std_regname(taicpu(p).oper[0]^.reg) + ' = ' + std_regname(taicpu(p).oper[1]^.reg) + ' (MovLdr2Ldr 1)', next_hp);
 
 
                       { Drop out if we're dealing with pre-indexed references }
                       { Drop out if we're dealing with pre-indexed references }
-                      if (taicpu(hp1).oper[1]^.ref^.addressmode = AM_PREINDEXED) and
+                      if (taicpu(next_hp).oper[1]^.ref^.addressmode = AM_PREINDEXED) and
                         (
                         (
-                          RegInRef(taicpu(p).oper[0]^.reg, taicpu(hp1).oper[1]^.ref^) or
-                          RegInRef(taicpu(p).oper[1]^.reg, taicpu(hp1).oper[1]^.ref^)
+                          RegInRef(taicpu(p).oper[0]^.reg, taicpu(next_hp).oper[1]^.ref^) or
+                          RegInRef(taicpu(p).oper[1]^.reg, taicpu(next_hp).oper[1]^.ref^)
                         ) then
                         ) then
                         begin
                         begin
                           { Remember to update register allocations }
                           { Remember to update register allocations }
                           if LDRChange then
                           if LDRChange then
-                            AllocRegBetween(taicpu(p).oper[1]^.reg, p, hp1, UsedRegs);
+                            AllocRegBetween(taicpu(p).oper[1]^.reg, p, next_hp, UsedRegs);
 
 
                           Break;
                           Break;
                         end;
                         end;
 
 
                       { The register being stored can be potentially changed (as long as it's not the stack pointer) }
                       { The register being stored can be potentially changed (as long as it's not the stack pointer) }
-                      if (taicpu(hp1).opcode = A_STR) and (getsupreg(taicpu(p).oper[1]^.reg) <> RS_STACK_POINTER_REG) and
-                        MatchOperand(taicpu(hp1).oper[0]^, taicpu(p).oper[0]^.reg) then
+                      if (taicpu(next_hp).opcode = A_STR) and (getsupreg(taicpu(p).oper[1]^.reg) <> RS_STACK_POINTER_REG) and
+                        MatchOperand(taicpu(next_hp).oper[0]^, taicpu(p).oper[0]^.reg) then
                         begin
                         begin
-                          DebugMsg('Peephole Optimization: ' + std_regname(taicpu(p).oper[0]^.reg) + ' = ' + std_regname(taicpu(p).oper[1]^.reg) + ' (MovLdr2Ldr 2)', hp1);
-                          taicpu(hp1).oper[0]^.reg := taicpu(p).oper[1]^.reg;
+                          DebugMsg('Peephole Optimization: ' + std_regname(taicpu(p).oper[0]^.reg) + ' = ' + std_regname(taicpu(p).oper[1]^.reg) + ' (MovLdr2Ldr 2)', next_hp);
+                          taicpu(next_hp).oper[0]^.reg := taicpu(p).oper[1]^.reg;
                           LDRChange := True;
                           LDRChange := True;
                         end;
                         end;
 
 
                       if LDRChange and (getsupreg(taicpu(p).oper[1]^.reg) <> RS_STACK_POINTER_REG) then
                       if LDRChange and (getsupreg(taicpu(p).oper[1]^.reg) <> RS_STACK_POINTER_REG) then
                         begin
                         begin
-                          AllocRegBetween(taicpu(p).oper[1]^.reg, p, hp1, UsedRegs);
+                          AllocRegBetween(taicpu(p).oper[1]^.reg, p, next_hp, UsedRegs);
                           if (taicpu(p).oppostfix = PF_None) and
                           if (taicpu(p).oppostfix = PF_None) and
                             (
                             (
                               (
                               (
-                                (taicpu(hp1).opcode = A_LDR) and
-                                MatchOperand(taicpu(hp1).oper[0]^, taicpu(p).oper[0]^.reg)
+                                (taicpu(next_hp).opcode = A_LDR) and
+                                MatchOperand(taicpu(next_hp).oper[0]^, taicpu(p).oper[0]^.reg)
                               ) or
                               ) or
-                              not RegUsedAfterInstruction(taicpu(p).oper[0]^.reg, hp1, TmpUsedRegs)
+                              not RegUsedAfterInstruction(taicpu(p).oper[0]^.reg, next_hp, TmpUsedRegs)
                             ) and
                             ) and
                             { Double-check to see if the old registers were actually
                             { Double-check to see if the old registers were actually
                               changed (e.g. if the super registers matched, but not
                               changed (e.g. if the super registers matched, but not
                               the sizes, they won't be changed). }
                               the sizes, they won't be changed). }
                             (
                             (
-                              (taicpu(hp1).opcode = A_LDR) or
-                              not RegInOp(taicpu(p).oper[0]^.reg, taicpu(hp1).oper[0]^)
+                              (taicpu(next_hp).opcode = A_LDR) or
+                              not RegInOp(taicpu(p).oper[0]^.reg, taicpu(next_hp).oper[0]^)
                             ) and
                             ) and
-                            not RegInRef(taicpu(p).oper[0]^.reg, taicpu(hp1).oper[1]^.ref^) then
+                            not RegInRef(taicpu(p).oper[0]^.reg, taicpu(next_hp).oper[1]^.ref^) then
                             begin
                             begin
                               DebugMsg('Peephole Optimization: RedundantMovProcess 2a done', p);
                               DebugMsg('Peephole Optimization: RedundantMovProcess 2a done', p);
                               RemoveCurrentP(p);
                               RemoveCurrentP(p);
@@ -472,23 +472,28 @@ Implementation
                             end;
                             end;
                         end;
                         end;
                     end
                     end
-                  else if (taicpu(hp1).opcode = A_MOV) and (taicpu(hp1).oppostfix = PF_None) and
-                    (taicpu(hp1).ops = 2) then
+                  else if (taicpu(next_hp).opcode = A_MOV) and (taicpu(next_hp).oppostfix = PF_None) and
+                    (taicpu(next_hp).ops = 2) then
                     begin
                     begin
-                      if MatchOperand(taicpu(hp1).oper[0]^, taicpu(p).oper[0]^.reg) then
+                      if MatchOperand(taicpu(next_hp).oper[0]^, taicpu(p).oper[0]^.reg) then
                         begin
                         begin
                           { Found another mov that writes entirely to the register }
                           { Found another mov that writes entirely to the register }
-                          if RegUsedBetween(taicpu(p).oper[0]^.reg, p, hp1) then
+                          if RegUsedBetween(taicpu(p).oper[0]^.reg, p, next_hp) then
                             begin
                             begin
                               { Register was used beforehand }
                               { Register was used beforehand }
-                              if MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[1]^.reg) then
+                              if MatchOperand(taicpu(next_hp).oper[1]^, taicpu(p).oper[1]^.reg) then
                                 begin
                                 begin
                                   { This MOV is exactly the same as the first one.
                                   { This MOV is exactly the same as the first one.
                                     Since none of the registers have changed value
                                     Since none of the registers have changed value
                                     at this point, we can remove it. }
                                     at this point, we can remove it. }
-                                  DebugMsg('Peephole Optimization: RedundantMovProcess 3a done', hp1);
-                                  asml.Remove(hp1);
-                                  hp1.Free;
+                                  DebugMsg('Peephole Optimization: RedundantMovProcess 3a done', next_hp);
+
+                                  if (next_hp = hp1) then
+                                    { Don't let hp1 become a dangling pointer }
+                                    hp1 := nil;
+
+                                  asml.Remove(next_hp);
+                                  next_hp.Free;
 
 
                                   { We still have the original p, so we can continue optimising;
                                   { We still have the original p, so we can continue optimising;
                                    if it was -O2 or below, this instruction appeared immediately
                                    if it was -O2 or below, this instruction appeared immediately
@@ -504,7 +509,7 @@ Implementation
                           { We can delete the first MOV (only if the second MOV is unconditional) }
                           { We can delete the first MOV (only if the second MOV is unconditional) }
 {$ifdef ARM}
 {$ifdef ARM}
                           if (taicpu(p).oppostfix = PF_None) and
                           if (taicpu(p).oppostfix = PF_None) and
-                            (taicpu(hp1).condition = C_None) then
+                            (taicpu(next_hp).condition = C_None) then
 {$endif ARM}
 {$endif ARM}
                             begin
                             begin
                               DebugMsg('Peephole Optimization: RedundantMovProcess 2b done', p);
                               DebugMsg('Peephole Optimization: RedundantMovProcess 2b done', p);
@@ -513,9 +518,9 @@ Implementation
                             end;
                             end;
                           Exit;
                           Exit;
                         end
                         end
-                      else if MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[0]^.reg) then
+                      else if MatchOperand(taicpu(next_hp).oper[1]^, taicpu(p).oper[0]^.reg) then
                         begin
                         begin
-                          if MatchOperand(taicpu(hp1).oper[0]^, taicpu(p).oper[1]^.reg)
+                          if MatchOperand(taicpu(next_hp).oper[0]^, taicpu(p).oper[1]^.reg)
                             { Be careful - if the entire register is not used, removing this
                             { Be careful - if the entire register is not used, removing this
                               instruction will leave the unused part uninitialised }
                               instruction will leave the unused part uninitialised }
 {$ifdef AARCH64}
 {$ifdef AARCH64}
@@ -524,9 +529,14 @@ Implementation
                             then
                             then
                             begin
                             begin
                               { Instruction will become mov r1,r1 }
                               { Instruction will become mov r1,r1 }
-                              DebugMsg('Peephole Optimization: Mov2None 2 done', hp1);
-                              asml.Remove(hp1);
-                              hp1.Free;
+                              DebugMsg('Peephole Optimization: Mov2None 2 done', next_hp);
+
+                              if (next_hp = hp1) then
+                                { Don't let hp1 become a dangling pointer }
+                                hp1 := nil;
+
+                              asml.Remove(next_hp);
+                              next_hp.Free;
                               Continue;
                               Continue;
                             end;
                             end;
 
 
@@ -534,12 +544,12 @@ Implementation
                             forces it to be left alone if the full register is not
                             forces it to be left alone if the full register is not
                             used, lest mov w1,w1 gets optimised out by mistake. [Kit] }
                             used, lest mov w1,w1 gets optimised out by mistake. [Kit] }
 {$ifdef AARCH64}
 {$ifdef AARCH64}
-                          if not MatchOperand(taicpu(hp1).oper[0]^, taicpu(p).oper[1]^.reg) then
+                          if not MatchOperand(taicpu(next_hp).oper[0]^, taicpu(p).oper[1]^.reg) then
 {$endif AARCH64}
 {$endif AARCH64}
                             begin
                             begin
-                              DebugMsg('Peephole Optimization: ' + std_regname(taicpu(p).oper[0]^.reg) + ' = ' + std_regname(taicpu(p).oper[1]^.reg) + ' (MovMov2Mov 2)', hp1);
-                              taicpu(hp1).oper[1]^.reg := taicpu(p).oper[1]^.reg;
-                              AllocRegBetween(taicpu(p).oper[1]^.reg, p, hp1, UsedRegs);
+                              DebugMsg('Peephole Optimization: ' + std_regname(taicpu(p).oper[0]^.reg) + ' = ' + std_regname(taicpu(p).oper[1]^.reg) + ' (MovMov2Mov 2)', next_hp);
+                              taicpu(next_hp).oper[1]^.reg := taicpu(p).oper[1]^.reg;
+                              AllocRegBetween(taicpu(p).oper[1]^.reg, p, next_hp, UsedRegs);
 
 
                               { If this was the only reference to the old register,
                               { If this was the only reference to the old register,
                                 then we can remove the original MOV now }
                                 then we can remove the original MOV now }
@@ -551,7 +561,7 @@ Implementation
                                   register). [Kit] }
                                   register). [Kit] }
                                 (getsupreg(taicpu(p).oper[1]^.reg) <> RS_STACK_POINTER_REG) and
                                 (getsupreg(taicpu(p).oper[1]^.reg) <> RS_STACK_POINTER_REG) and
                                 RegInUsedRegs(taicpu(p).oper[0]^.reg, UsedRegs) and
                                 RegInUsedRegs(taicpu(p).oper[0]^.reg, UsedRegs) and
-                                not RegUsedAfterInstruction(taicpu(p).oper[0]^.reg, hp1, TmpUsedRegs) then
+                                not RegUsedAfterInstruction(taicpu(p).oper[0]^.reg, next_hp, TmpUsedRegs) then
                                 begin
                                 begin
                                   DebugMsg('Peephole Optimization: RedundantMovProcess 2c done', p);
                                   DebugMsg('Peephole Optimization: RedundantMovProcess 2c done', p);
                                   RemoveCurrentP(p);
                                   RemoveCurrentP(p);
@@ -565,14 +575,14 @@ Implementation
                   { On low optimisation settions, don't search more than one instruction ahead }
                   { On low optimisation settions, don't search more than one instruction ahead }
                   if not(cs_opt_level3 in current_settings.optimizerswitches) or
                   if not(cs_opt_level3 in current_settings.optimizerswitches) or
                     { Stop at procedure calls and jumps }
                     { Stop at procedure calls and jumps }
-                    is_calljmp(taicpu(hp1).opcode) or
+                    is_calljmp(taicpu(next_hp).opcode) or
                     { If the read register has changed value, or the MOV
                     { If the read register has changed value, or the MOV
                       destination register has been used, drop out }
                       destination register has been used, drop out }
-                    RegInInstruction(taicpu(p).oper[0]^.reg, hp1) or
-                    RegModifiedByInstruction(taicpu(p).oper[1]^.reg, hp1) then
+                    RegInInstruction(taicpu(p).oper[0]^.reg, next_hp) or
+                    RegModifiedByInstruction(taicpu(p).oper[1]^.reg, next_hp) then
                     Break;
                     Break;
 
 
-                  current_hp := hp1;
+                  current_hp := next_hp;
                 end;
                 end;
             end;
             end;
         end;
         end;

+ 3 - 55
compiler/comphook.pas

@@ -169,14 +169,7 @@ const
 implementation
 implementation
 
 
   uses
   uses
-   cutils, systems, globals
-{$ifdef linux}
-   ,termio
-{$endif linux}
-{$ifdef mswindows}
-   ,windows
-{$endif mswindows}
-   ;
+   cutils, systems, globals, comptty;
 
 
 {****************************************************************************
 {****************************************************************************
                           Helper Routines
                           Helper Routines
@@ -214,51 +207,9 @@ end;
 type
 type
   TOutputColor = (oc_black,oc_red,oc_green,oc_orange,og_blue,oc_magenta,oc_cyan,oc_lightgray);
   TOutputColor = (oc_black,oc_red,oc_green,oc_orange,og_blue,oc_magenta,oc_cyan,oc_lightgray);
 
 
-{$if defined(linux) or defined(MSWINDOWS)}
-const
-  CachedIsATTY : Boolean = false;
-  IsATTYValue : Boolean = false;
-
-{$ifdef linux}
-function IsATTY(var t : text) : Boolean;
-  begin
-    if not(CachedIsATTY) then
-      begin
-        IsATTYValue:=termio.IsATTY(t)=1;
-        CachedIsATTY:=true;
-      end;
-    Result:=IsATTYValue;
-  end;
-{$endif linux}
-
-{$ifdef MSWINDOWS}
-const ENABLE_VIRTUAL_TERMINAL_PROCESSING = $0004;
-
-function IsATTY(var t : text) : Boolean;
-  const dwMode: dword = 0;
-  begin
-    if not(CachedIsATTY) then
-      begin
-        IsATTYValue := false;
-        if GetConsoleMode(TextRec(t).handle, dwMode) then
-        begin
-          dwMode := dwMode or ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-          if SetConsoleMode(TextRec(t).handle, dwMode) then
-            IsATTYValue := true;
-        end;
-        CachedIsATTY:=true;
-      end;
-    Result:=IsATTYValue;
-  end;
-{$endif MSWINDOWS}
-
-{$endif defined(linux) or defined(MSWINDOWS)}
-
-
 procedure WriteColoredOutput(var t: Text;color: TOutputColor;const s : AnsiString);
 procedure WriteColoredOutput(var t: Text;color: TOutputColor;const s : AnsiString);
   begin
   begin
-{$if defined(linux) or defined(mswindows)}
-     if IsATTY(t) then
+     if TTYCheckSupported and IsATTY(t) then
        begin
        begin
          case color of
          case color of
            oc_black:
            oc_black:
@@ -279,12 +230,9 @@ procedure WriteColoredOutput(var t: Text;color: TOutputColor;const s : AnsiStrin
              write(t,#27'[1m'#27'[37m');
              write(t,#27'[1m'#27'[37m');
          end;
          end;
        end;
        end;
-{$endif linux or mswindows}
     write(t,s);
     write(t,s);
-{$if defined(linux) or defined(mswindows)}
-    if IsATTY(t) then
+    if TTYCheckSupported and IsATTY(t) then
       write(t,#27'[0m');
       write(t,#27'[0m');
-{$endif linux}
   end;
   end;
 {****************************************************************************
 {****************************************************************************
                           Stopping the compiler
                           Stopping the compiler

+ 172 - 0
compiler/comptty.pas

@@ -0,0 +1,172 @@
+{
+    This file is part of the Free Pascal compiler.
+    Copyright (c) 2020 by the Free Pascal development team
+
+    This unit contains platform-specific code for checking TTY output
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    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.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit comptty;
+
+{$i fpcdefs.inc}
+
+interface
+
+function IsATTY(var t : text) : Boolean;
+
+const
+(* This allows compile-time removal of the colouring functionality under not supported platforms *)
+{$if defined(linux) or defined(MSWINDOWS) or defined(OS2) or defined(GO32V2) or defined(WATCOM)}
+  TTYCheckSupported = true;
+{$else defined(linux) or defined(MSWINDOWS) or defined(OS2) or defined(GO32V2) or defined(WATCOM)}
+  TTYCheckSupported = false;
+{$endif defined(linux) or defined(MSWINDOWS) or defined(OS2) or defined(GO32V2) or defined(WATCOM)}
+
+
+implementation
+
+{$ifdef linux}
+  uses
+   termio;
+{$endif linux}
+{$ifdef mswindows}
+  uses
+   windows;
+{$endif mswindows}
+{$ifdef os2}
+  uses
+   doscalls;
+{$endif os2}
+{$if defined(GO32V2) or defined(WATCOM)}
+  uses
+   dos;
+{$endif defined(GO32V2) or defined(WATCOM)}
+
+const
+  CachedIsATTY : Boolean = false;
+  IsATTYValue : Boolean = false;
+
+{$ifdef linux}
+function LinuxIsATTY(var t : text) : Boolean; inline;
+begin
+  LinuxIsATTY:=termio.IsATTY(t)=1;
+end;
+{$endif linux}
+
+{$ifdef MSWINDOWS}
+const
+  ENABLE_VIRTUAL_TERMINAL_PROCESSING = $0004;
+
+function WindowsIsATTY(var t : text) : Boolean; inline;
+const
+  dwMode: dword = 0;
+begin
+  WindowsIsATTY := false;
+  if GetConsoleMode(TextRec(t).handle, dwMode) then
+   begin
+    dwMode := dwMode or ENABLE_VIRTUAL_TERMINAL_PROCESSING;
+    if SetConsoleMode(TextRec(t).handle, dwMode) then
+                                     WindowsIsATTY := true;
+   end;
+end;
+{$endif MSWINDOWS}
+
+{$IFDEF OS2}
+function OS2IsATTY(var t : text) : Boolean; inline;
+var
+  HT, Attr: cardinal;
+ {$IFDEF EMX}
+  OK: boolean;
+ {$ENDIF EMX}
+const
+  dhDevice = 1;
+begin
+ {$IFDEF EMX}
+  if os_mode = osOS2 then
+    begin
+ {$ENDIF EMX}
+      OS2IsATTY := (DosQueryHType (TextRec (T).Handle, HT, Attr) = 0)
+                                                           and (HT = dhDevice);
+ {$IFDEF EMX}
+    end
+  else
+    begin
+      OK := false;
+{$ASMMODE INTEL}
+      asm
+        mov ebx, TextRec (T).Handle
+        mov eax, 4400h
+        call syscall
+        jc @IsDevEnd
+        test edx, 80h           { bit 7 is set if it is a device or a pipe }
+        jz @IsDevEnd
+        mov eax, 1A00h          { Check ANSI.SYS availability }
+        int 2Fh
+        inc al                  { If it was FFh, then OK }
+        jnz @IsDevEnd
+        mov OK, true
+@IsDevEnd:
+      end;
+    OS2IsATTY := OK;
+  end;
+ {$ENDIF EMX}
+end;
+{$ENDIF OS2}
+
+{$if defined(GO32V2) or defined(WATCOM)}
+function DosIsATTY(var t : text) : Boolean; inline;
+var
+  Regs: Registers;
+begin
+  Regs.EBX := TextRec (T).Handle;
+  Regs.EAX := $4400;
+  MsDos (Regs);
+  if (Regs.Flags and FCarry <> 0) or (Regs.EDX and $80 = 0) then
+{ bit 7 is set if it is a device or a pipe }
+    DosIsATTY := false
+  else
+    begin
+      Regs.EAX := $1A00;             { Check ANSI.SYS availability }
+      Intr ($2F, Regs);
+      DosIsATTY := Regs.AL = $FF;    { If it was FFh, then OK }
+    end;
+end;
+{$endif defined(GO32V2) or defined(WATCOM)}
+
+function IsATTY(var t : text) : Boolean;
+begin
+  if not(CachedIsATTY) then
+    begin
+(* If none of the supported values is defined, false is returned by default. *)
+{$ifdef linux}
+      IsATTYValue:=LinuxIsATTY(t);
+{$endif linux}
+{$ifdef MSWINDOWS}
+      IsATTYValue:=WindowsIsATTY(t);
+{$endif MSWINDOWS}
+{$ifdef OS2}
+      IsATTYValue:=OS2IsATTY(t);
+{$endif OS2}
+{$if defined(GO32V2) or defined(WATCOM)}
+      IsATTYValue:=DosIsATTY(t);
+{$endif defined(GO32V2) or defined(WATCOM)}
+      CachedIsATTY:=true;
+    end;
+  Result:=IsATTYValue;
+end;
+
+end.

+ 5 - 1
compiler/globals.pas

@@ -413,6 +413,10 @@ interface
        palmos_applicationname : string = 'FPC Application';
        palmos_applicationname : string = 'FPC Application';
        palmos_applicationid : string[4] = 'FPCA';
        palmos_applicationid : string[4] = 'FPCA';
 {$endif defined(m68k) or defined(arm)}
 {$endif defined(m68k) or defined(arm)}
+{$if defined(m68k)}
+       { Sinclair QL specific }
+       sinclairql_metadata_format: string[4] = 'QHDR';
+{$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 }
        { (this will be prefixed with the target_info.cprefix)                }
        { (this will be prefixed with the target_info.cprefix)                }
@@ -1516,7 +1520,7 @@ implementation
        if localexepath='' then
        if localexepath='' then
         begin
         begin
           hs1 := ExtractFileName(exeName);
           hs1 := ExtractFileName(exeName);
-	  hs1 := ChangeFileExt(hs1,source_info.exeext);
+          hs1 := ChangeFileExt(hs1,source_info.exeext);
 {$ifdef macos}
 {$ifdef macos}
           FindFile(hs1,GetEnvironmentVariable('Commands'),false,localExepath);
           FindFile(hs1,GetEnvironmentVariable('Commands'),false,localExepath);
 {$else macos}
 {$else macos}

+ 4 - 4
compiler/llvm/agllvm.pas

@@ -407,7 +407,7 @@ implementation
      end;
      end;
 
 
 
 
-{$if defined(cpuextended) and defined(FPC_HAS_TYPE_EXTENDED)}
+{$if defined(cpuextended) and (defined(FPC_HAS_TYPE_EXTENDED) or defined(FPC_SOFT_FPUX80))}
     function llvmextendedtostr(const e: extended): TSymStr;
     function llvmextendedtostr(const e: extended): TSymStr;
       var
       var
         extendedval: record
         extendedval: record
@@ -502,7 +502,7 @@ implementation
                end;
                end;
              result:='';
              result:='';
            end;
            end;
-{$if defined(cpuextended) and defined(FPC_HAS_TYPE_EXTENDED)}
+{$if defined(cpuextended) and (defined(FPC_HAS_TYPE_EXTENDED) or defined(FPC_SOFT_FPUX80))}
          top_extended80:
          top_extended80:
            begin
            begin
              result:=llvmextendedtostr(o.eval);
              result:=llvmextendedtostr(o.eval);
@@ -875,7 +875,7 @@ implementation
                 writer.AsmWriteLn(asminfo^.comment+'value: '+single2str(tai_realconst(hp).value.s32val));
                 writer.AsmWriteLn(asminfo^.comment+'value: '+single2str(tai_realconst(hp).value.s32val));
               aitrealconst_s64bit:
               aitrealconst_s64bit:
                 writer.AsmWriteLn(asminfo^.comment+'value: '+double2str(tai_realconst(hp).value.s64val));
                 writer.AsmWriteLn(asminfo^.comment+'value: '+double2str(tai_realconst(hp).value.s64val));
-{$if defined(cpuextended) and defined(FPC_HAS_TYPE_EXTENDED)}
+{$if defined(cpuextended) and (defined(FPC_HAS_TYPE_EXTENDED) or defined(FPC_SOFT_FPUX80))}
               { can't write full 80 bit floating point constants yet on non-x86 }
               { can't write full 80 bit floating point constants yet on non-x86 }
               aitrealconst_s80bit:
               aitrealconst_s80bit:
                 writer.AsmWriteLn(asminfo^.comment+'value: '+extended2str(tai_realconst(hp).value.s80val));
                 writer.AsmWriteLn(asminfo^.comment+'value: '+extended2str(tai_realconst(hp).value.s80val));
@@ -892,7 +892,7 @@ implementation
             writer.AsmWrite(llvmdoubletostr(hp.value.s32val));
             writer.AsmWrite(llvmdoubletostr(hp.value.s32val));
           aitrealconst_s64bit:
           aitrealconst_s64bit:
             writer.AsmWriteln(llvmdoubletostr(hp.value.s64val));
             writer.AsmWriteln(llvmdoubletostr(hp.value.s64val));
-{$if defined(cpuextended) and defined(FPC_HAS_TYPE_EXTENDED)}
+{$if defined(cpuextended) and (defined(FPC_HAS_TYPE_EXTENDED) or defined(FPC_SOFT_FPUX80))}
           aitrealconst_s80bit:
           aitrealconst_s80bit:
             writer.AsmWrite(llvmextendedtostr(hp.value.s80val));
             writer.AsmWrite(llvmextendedtostr(hp.value.s80val));
 {$endif defined(cpuextended)}
 {$endif defined(cpuextended)}

+ 55 - 39
compiler/llvm/llvmdef.pas

@@ -898,56 +898,72 @@ implementation
 
 
 
 
     function llvmgettemprecorddef(const fieldtypes: array of tdef; packrecords, recordalignmin: shortint): trecorddef;
     function llvmgettemprecorddef(const fieldtypes: array of tdef; packrecords, recordalignmin: shortint): trecorddef;
+
+      procedure addtypename(var typename: TSymStr; hdef: tdef);
+        begin
+          case hdef.typ of
+            orddef:
+              case torddef(hdef).ordtype of
+                s8bit,
+                u8bit,
+                pasbool1,
+                pasbool8:
+                  typename:=typename+'i8';
+                s16bit,
+                u16bit:
+                  typename:=typename+'i16';
+                s32bit,
+                u32bit:
+                  typename:=typename+'i32';
+                s64bit,
+                u64bit:
+                  typename:=typename+'i64';
+                customint:
+                  typename:=typename+'i'+tostr(torddef(hdef).packedbitsize);
+                else
+                  { other types should not appear currently, add as needed }
+                  internalerror(2014012001);
+              end;
+            floatdef:
+              case tfloatdef(hdef).floattype of
+                s32real:
+                  typename:=typename+'f32';
+                s64real:
+                  typename:=typename+'f64';
+                else
+                  { other types should not appear currently, add as needed }
+                  internalerror(2014012008);
+              end;
+            arraydef:
+              begin
+                if not is_special_array(hdef) and
+                   not is_packed_array(hdef) then
+                  begin
+                    typename:=typename+'['+tostr(tarraydef(hdef).elecount)+'x';
+                    addtypename(typename,tarraydef(hdef).elementdef);
+                    typename:=typename+']';
+                  end
+                else
+                  typename:=typename+'d'+hdef.unique_id_str;
+              end
+            else
+              typename:=typename+'d'+hdef.unique_id_str;
+          end;
+        end;
+
       var
       var
         i: longint;
         i: longint;
         res: PHashSetItem;
         res: PHashSetItem;
         oldsymtablestack: tsymtablestack;
         oldsymtablestack: tsymtablestack;
         hrecst: trecordsymtable;
         hrecst: trecordsymtable;
-        hdef: tdef;
         hrecdef: trecorddef;
         hrecdef: trecorddef;
         sym: tfieldvarsym;
         sym: tfieldvarsym;
-        typename: string;
+        typename: TSymStr;
       begin
       begin
         typename:=internaltypeprefixName[itp_llvmstruct];
         typename:=internaltypeprefixName[itp_llvmstruct];
         for i:=low(fieldtypes) to high(fieldtypes) do
         for i:=low(fieldtypes) to high(fieldtypes) do
           begin
           begin
-            hdef:=fieldtypes[i];
-            case hdef.typ of
-              orddef:
-                case torddef(hdef).ordtype of
-                  s8bit,
-                  u8bit,
-                  pasbool1,
-                  pasbool8:
-                    typename:=typename+'i8';
-                  s16bit,
-                  u16bit:
-                    typename:=typename+'i16';
-                  s32bit,
-                  u32bit:
-                    typename:=typename+'i32';
-                  s64bit,
-                  u64bit:
-                    typename:=typename+'i64';
-                  customint:
-                    typename:=typename+'i'+tostr(torddef(hdef).packedbitsize);
-                  else
-                    { other types should not appear currently, add as needed }
-                    internalerror(2014012001);
-                end;
-              floatdef:
-                case tfloatdef(hdef).floattype of
-                  s32real:
-                    typename:=typename+'f32';
-                  s64real:
-                    typename:=typename+'f64';
-                  else
-                    { other types should not appear currently, add as needed }
-                    internalerror(2014012008);
-                end;
-              else
-                typename:=typename+'d'+hdef.unique_id_str;
-            end;
+            addtypename(typename,fieldtypes[i]);
           end;
           end;
         if not assigned(current_module) then
         if not assigned(current_module) then
           internalerror(2014012002);
           internalerror(2014012002);

+ 41 - 60
compiler/m68k/ra68kmot.pas

@@ -83,7 +83,7 @@ unit ra68kmot;
          procedure consume_all_until(tokens : tasmtokenset);
          procedure consume_all_until(tokens : tasmtokenset);
          function findopcode(const s: string; var opsize: topsize): tasmop;
          function findopcode(const s: string; var opsize: topsize): tasmop;
          Function BuildExpression(allow_symbol : boolean; asmsym : pshortstring) : tcgint;
          Function BuildExpression(allow_symbol : boolean; asmsym : pshortstring) : tcgint;
-         Procedure BuildConstant(maxvalue: tcgint);
+         Procedure BuildConstant(constsize: tcgint);
          Procedure BuildRealConstant(typ : tfloattype);
          Procedure BuildRealConstant(typ : tfloattype);
          Procedure BuildScaling(const oper:tm68koperand);
          Procedure BuildScaling(const oper:tm68koperand);
          Function BuildRefExpression: tcgint;
          Function BuildRefExpression: tcgint;
@@ -932,72 +932,53 @@ const
   end;
   end;
 
 
 
 
-  Procedure tm68kmotreader.BuildConstant(maxvalue: tcgint);
+  procedure tm68kmotreader.BuildConstant(constsize: tcgint);
   {*********************************************************************}
   {*********************************************************************}
   { PROCEDURE BuildConstant                                             }
   { PROCEDURE BuildConstant                                             }
   {  Description: This routine takes care of parsing a DB,DD,or DW      }
   {  Description: This routine takes care of parsing a DB,DD,or DW      }
   {  line and adding those to the assembler node. Expressions, range-   }
   {  line and adding those to the assembler node. Expressions, range-   }
-  {  checking are fullly taken care of.                                 }
-  {   maxvalue: $ff -> indicates that this is a DB node.                }
-  {             $ffff -> indicates that this is a DW node.              }
-  {             $ffffffff -> indicates that this is a DD node.          }
+  {  checking are fully taken care of.                                  }
   {*********************************************************************}
   {*********************************************************************}
   { EXIT CONDITION:  On exit the routine should point to AS_SEPARATOR.  }
   { EXIT CONDITION:  On exit the routine should point to AS_SEPARATOR.  }
   {*********************************************************************}
   {*********************************************************************}
   var
   var
-   expr: string;
-   value : tcgint;
+    expr: string;
+    value : tcgint;
   begin
   begin
-      Repeat
-        Case actasmtoken of
-          AS_STRING: begin
-                      if maxvalue <> $ff then
-                         Message(asmr_e_string_not_allowed_as_const);
-                      expr := actasmpattern;
-                      if length(expr) > 1 then
-                        Message(asmr_e_string_not_allowed_as_const);
-                      Consume(AS_STRING);
-                      Case actasmtoken of
-                       AS_COMMA: Consume(AS_COMMA);
-                       AS_SEPARATOR: ;
-                      else
-                       Message(asmr_e_invalid_string_expression);
-                      end; { end case }
-                      ConcatString(curlist,expr);
-                    end;
-          AS_INTNUM,AS_BINNUM,
-          AS_OCTALNUM,AS_HEXNUM:
-                    begin
-                      value:=BuildExpression(false,nil);
-                      ConcatConstant(curlist,value,maxvalue);
-                    end;
-          AS_ID:
-                     begin
-                      value:=BuildExpression(false,nil);
-                      if value > maxvalue then
-                      begin
-                         Message(asmr_e_constant_out_of_bounds);
-                         { assuming a value of maxvalue }
-                         value := maxvalue;
-                      end;
-                      ConcatConstant(curlist,value,maxvalue);
-                  end;
-          { These terms can start an assembler expression }
-          AS_PLUS,AS_MINUS,AS_LPAREN,AS_NOT: begin
-                                          value := BuildExpression(false,nil);
-                                          ConcatConstant(curlist,value,maxvalue);
-                                         end;
-          AS_COMMA:  begin
-                       Consume(AS_COMMA);
-                     END;
-          AS_SEPARATOR: ;
+    repeat
+      case actasmtoken of
+        AS_STRING:
+            begin
+              expr:=actasmpattern;
+              Consume(AS_STRING);
+              if (constsize <> 1) or (length(expr) > 1) then
+                Message(asmr_e_string_not_allowed_as_const);
 
 
-        else
-         begin
-           Message(asmr_e_syntax_error);
-         end;
-    end; { end case }
-   Until actasmtoken = AS_SEPARATOR;
+              if not (actasmtoken in [AS_COMMA, AS_SEPARATOR]) then
+                Message(asmr_e_invalid_string_expression);
+
+              ConcatString(curlist,expr);
+            end;
+        AS_ID,
+        AS_INTNUM,AS_BINNUM,
+        AS_OCTALNUM,AS_HEXNUM,
+        { These terms can start an assembler expression }
+        AS_PLUS,AS_MINUS,AS_LPAREN,AS_NOT:
+            begin
+              value:=BuildExpression(false,nil);
+              ConcatConstant(curlist,value,constsize);
+            end;
+        AS_COMMA:
+            begin
+              Consume(AS_COMMA);
+            end;
+        AS_SEPARATOR: ;
+      else
+        begin
+          Message(asmr_e_syntax_error);
+        end;
+      end; { end case }
+    until actasmtoken = AS_SEPARATOR;
   end;
   end;
 
 
 
 
@@ -1713,17 +1694,17 @@ const
               AS_DW:
               AS_DW:
                 begin
                 begin
                   Consume(AS_DW);
                   Consume(AS_DW);
-                  BuildConstant($ffff);
+                  BuildConstant(sizeof(word));
                 end;
                 end;
               AS_DB:
               AS_DB:
                 begin
                 begin
                   Consume(AS_DB);
                   Consume(AS_DB);
-                  BuildConstant($ff);
+                  BuildConstant(sizeof(byte));
                 end;
                 end;
               AS_DD:
               AS_DD:
                 begin
                 begin
                   Consume(AS_DD);
                   Consume(AS_DD);
-                  BuildConstant(tcgint($ffffffff));
+                  BuildConstant(sizeof(dword));
                 end;
                 end;
               AS_XDEF:
               AS_XDEF:
                 begin
                 begin

+ 3 - 0
compiler/msg/errore.msg

@@ -4319,6 +4319,9 @@ A*2WR_Generate relocation code (Windows)
 8*3Wtexe_Create a DOS .EXE file (default)
 8*3Wtexe_Create a DOS .EXE file (default)
 8*3Wtcom_Create a DOS .COM file (requires tiny memory model)
 8*3Wtcom_Create a DOS .COM file (requires tiny memory model)
 P*2WT_Specify MPW tool type application (Classic Mac OS)
 P*2WT_Specify MPW tool type application (Classic Mac OS)
+6*2WQ<x>_Set executable metadata format (Sinclair QL)
+6*3WQqhdr_Set metadata to QDOS File Header style (default)
+6*3WQxtcc_Set metadata to XTcc style
 **2WX_Enable executable stack (Linux)
 **2WX_Enable executable stack (Linux)
 **1X_Executable options:
 **1X_Executable options:
 **2X9_Generate linkerscript for GNU Binutils ld older than version 2.19.1 (Linux)
 **2X9_Generate linkerscript for GNU Binutils ld older than version 2.19.1 (Linux)

+ 1 - 1
compiler/msgidx.inc

@@ -1135,7 +1135,7 @@ const
   option_info=11024;
   option_info=11024;
   option_help_pages=11025;
   option_help_pages=11025;
 
 
-  MsgTxtSize = 86604;
+  MsgTxtSize = 86754;
 
 
   MsgIdxMax : array[1..20] of longint=(
   MsgIdxMax : array[1..20] of longint=(
     28,107,360,130,99,63,145,36,223,68,
     28,107,360,130,99,63,145,36,223,68,

+ 26 - 22
compiler/msgtxt.inc

@@ -1,8 +1,8 @@
 const msgtxt_codepage=20127;
 const msgtxt_codepage=20127;
 {$ifdef Delphi}
 {$ifdef Delphi}
-const msgtxt : array[0..000360] of string[240]=(
+const msgtxt : array[0..000361] of string[240]=(
 {$else Delphi}
 {$else Delphi}
-const msgtxt : array[0..000360,1..240] of char=(
+const msgtxt : array[0..000361,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+
@@ -1960,42 +1960,46 @@ const msgtxt : array[0..000360,1..240] of char=(
   '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 model)'#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*3WQqhdr_Set metad','ata to QDOS File Header style (default)'#010+
+  '6*3WQxtcc_Set metadata to XTcc style'#010+
   '**2WX_Enable executable stack (Linux)'#010+
   '**2WX_Enable executable stack (Linux)'#010+
   '**1X_Executable options:'#010+
   '**1X_Executable options:'#010+
-  '**2X9_Gene','rate linkerscript for GNU Binutils ld older than version 2'+
-  '.19.1 (Linux)'#010+
-  '**2Xc_Pass --shared/-dynamic to the linker (BeOS, Darwin, FreeBSD, Lin'+
-  'ux)'#010+
+  '**2X9_Generate linkerscript for GNU Binutils ld older than version 2.1'+
+  '9.1 (Linux)'#010+
+  '**2Xc_Pass --share','d/-dynamic to the linker (BeOS, Darwin, FreeBSD, L'+
+  'inux)'#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 usin','g -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+
   '**2Xf_Substitute pthread library 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+
+  '*','*2Xg_Create debuginfo in a separate file and add a debuglink sectio'+
+  'n to executable'#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+
+  '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+
   '**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'+
   '**2XM<x>_Set the name of the '#039'main'#039' program routine (default i'+
-  's '#039'main'#039')'#010+
+  's '#039'mai','n'#039')'#010+
   '**2Xn_Use target system native linker instead of GNU ld (Solaris, AIX)'+
   '**2Xn_Use target system native linker instead of GNU ld (Solaris, AIX)'+
   #010+
   #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+
-  '**2Xr<x>_Set the linker'#039's rlink-path to <x> (needed for cross comp'+
-  'ile, see the ld manual for more information) (BeOS, Linux)'#010+
-  '**2XR<x>_Prepend <x> to all linker search paths (BeOS, Darwin, Free','B'+
-  'SD, Linux, Mac OS, Solaris)'#010+
+  '**2XP<x>_Prepend the binutils names with the prefix <x>'#010+
+  '**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+
+  '**2XR<x>_Prepend <x> to all linker search paths (BeOS, Darwin, FreeBSD'+
+  ', Linux, Mac OS, Solaris)'#010+
   '**2Xs_Strip all symbols from executable'#010+
   '**2Xs_Strip all symbols from executable'#010+
-  '**2XS_Try to link units statically (default, defines FPC_LINK_STATIC)'#010+
+  '**2XS_Try to link uni','ts 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+
-  '**2Xv_Generate table for Virtual Entry',' calls'#010+
+  '**2Xv_Generate table for Virtual Entry calls'#010+
   '**2XV_Use VLink as external linker       (default on Amiga, MorphOS)'#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 s','martlink units             (defines FPC_LINK_SMART)'#010+
   '**1*_'#010+
   '**1*_'#010+
   '**1?_Show this help'#010+
   '**1?_Show this help'#010+
   '**1h_Shows this help without waiting'
   '**1h_Shows this help without waiting'

+ 71 - 37
compiler/options.pas

@@ -2601,6 +2601,23 @@ begin
                         else
                         else
                           IllegalPara(opt);
                           IllegalPara(opt);
                       end;
                       end;
+{$if defined(m68k)}
+                    'Q':
+                      begin
+                        if (target_info.system in [system_m68k_sinclairql]) then
+                          begin
+                            sinclairql_metadata_format:=Upper(Copy(More,j+1,255));
+                            case sinclairql_metadata_format of
+                              'QHDR', 'XTCC': ; { allowed formats }
+                              else
+                                IllegalPara(opt);
+                            end;
+                            break;
+                          end
+                        else
+                          IllegalPara(opt);
+                      end;
+{$endif defined(m68k)}
                     'R':
                     'R':
                       begin
                       begin
                         if target_info.system in systems_all_windows then
                         if target_info.system in systems_all_windows then
@@ -4394,44 +4411,61 @@ begin
       ;
       ;
   end;
   end;
 
 
-  { ARMHF defaults }
-  if (target_info.abi = abi_eabihf) then
-    { set default cpu type to ARMv7a for ARMHF unless specified otherwise }
-    begin
-    {$ifdef CPUARMV6}
-      { if the compiler is built for armv6, then
-        inherit this setting, e.g. Raspian is armhf but
-        only armv6, this makes rebuilds of the compiler
-        easier }
-      if not option.CPUSetExplicitly then
-        init_settings.cputype:=cpu_armv6;
-      if not option.OptCPUSetExplicitly then
-        init_settings.optimizecputype:=cpu_armv6;
-    {$else CPUARMV6}
-      if not option.CPUSetExplicitly then
-        init_settings.cputype:=cpu_armv7a;
-      if not option.OptCPUSetExplicitly then
-        init_settings.optimizecputype:=cpu_armv7a;
-    {$endif CPUARMV6}
+  { set ABI defaults }
+  case target_info.abi of
+    abi_eabihf:
+      { set default cpu type to ARMv7a for ARMHF unless specified otherwise }
+      begin
+{$ifdef CPUARMV6}
+        { if the compiler is built for armv6, then
+          inherit this setting, e.g. Raspian is armhf but
+          only armv6, this makes rebuilds of the compiler
+          easier }
+        if not option.CPUSetExplicitly then
+          init_settings.cputype:=cpu_armv6;
+        if not option.OptCPUSetExplicitly then
+          init_settings.optimizecputype:=cpu_armv6;
+{$else CPUARMV6}
+        if not option.CPUSetExplicitly then
+          init_settings.cputype:=cpu_armv7a;
+        if not option.OptCPUSetExplicitly then
+          init_settings.optimizecputype:=cpu_armv7a;
+{$endif CPUARMV6}
 
 
-      { Set FPU type }
-      if not(option.FPUSetExplicitly) then
-        begin
-          if init_settings.cputype < cpu_armv7 then
-            init_settings.fputype:=fpu_vfpv2
-          else
-            init_settings.fputype:=fpu_vfpv3_d16;
-        end
-      else
-        begin
-          if (not(FPUARM_HAS_VFP_EXTENSION in fpu_capabilities[init_settings.fputype]))
-	     or (target_info.system = system_arm_ios) then
-            begin
-              Message(option_illegal_fpu_eabihf);
-              StopOptions(1);
-            end;
-        end;
-    end;
+        { Set FPU type }
+        if not(option.FPUSetExplicitly) then
+          begin
+            if init_settings.cputype < cpu_armv7 then
+              init_settings.fputype:=fpu_vfpv2
+            else
+              init_settings.fputype:=fpu_vfpv3_d16;
+          end
+        else
+          begin
+            if (not(FPUARM_HAS_VFP_EXTENSION in fpu_capabilities[init_settings.fputype]))
+	       or (target_info.system = system_arm_ios) then
+              begin
+                Message(option_illegal_fpu_eabihf);
+                StopOptions(1);
+              end;
+          end;
+      end;
+    abi_eabi:
+      begin
+        if target_info.system=system_arm_linux then
+          begin
+            { this is what Debian uses }
+            if not option.CPUSetExplicitly then
+              init_settings.cputype:=cpu_armv4t;
+            if not option.OptCPUSetExplicitly then
+              init_settings.optimizecputype:=cpu_armv4t;
+            if not(option.FPUSetExplicitly) then
+              init_settings.fputype:=fpu_soft;
+          end;
+      end;
+    else
+      ;
+  end;
 
 
   if (init_settings.instructionset=is_thumb) and not(CPUARM_HAS_THUMB2 in cpu_capabilities[init_settings.cputype]) then
   if (init_settings.instructionset=is_thumb) and not(CPUARM_HAS_THUMB2 in cpu_capabilities[init_settings.cputype]) then
     begin
     begin

+ 0 - 5
compiler/rautils.pas

@@ -1795,13 +1795,8 @@ end;
 
 
 Procedure ConcatConstant(p: TAsmList; value: tcgint; constsize:byte);
 Procedure ConcatConstant(p: TAsmList; value: tcgint; constsize:byte);
 {*********************************************************************}
 {*********************************************************************}
-{ PROCEDURE ConcatConstant(value: aint; maxvalue: aint);        }
 {  Description: This routine adds the value constant to the current   }
 {  Description: This routine adds the value constant to the current   }
 {  instruction linked list.                                           }
 {  instruction linked list.                                           }
-{   maxvalue -> indicates the size of the data to initialize:         }
-{                  $ff -> create a byte node.                         }
-{                  $ffff -> create a word node.                       }
-{                  $ffffffff -> create a dword node.                  }
 {*********************************************************************}
 {*********************************************************************}
 var
 var
   rangelo,rangehi : int64;
   rangelo,rangehi : int64;

+ 4 - 1
compiler/riscv/agrvgas.pas

@@ -247,7 +247,10 @@ unit agrvgas;
         Replace(result,'$ABI','ilp32');
         Replace(result,'$ABI','ilp32');
 {$endif RISCV32}
 {$endif RISCV32}
 {$ifdef RISCV64}
 {$ifdef RISCV64}
-        Replace(result,'$ABI','lp64');
+        if target_info.abi=abi_riscv_hf then
+          Replace(result,'$ABI','lp64d')
+        else
+          Replace(result,'$ABI','lp64');
 {$endif RISCV64}
 {$endif RISCV64}
       end;
       end;
 
 

+ 1 - 1
compiler/systems/i_sinclairql.pas

@@ -39,7 +39,7 @@ unit i_sinclairql;
             cpu          : cpu_m68k;
             cpu          : cpu_m68k;
             unit_env     : '';
             unit_env     : '';
             extradefines : '';
             extradefines : '';
-            exeext       : '.bin';
+            exeext       : '.exe';
             defext       : '';
             defext       : '';
             scriptext    : '';
             scriptext    : '';
             smartext     : '.sl';
             smartext     : '.sl';

+ 5 - 0
compiler/systems/t_amiga.pas

@@ -385,11 +385,15 @@ var
   StripStr: string[40];
   StripStr: string[40];
   DynLinkStr : string;
   DynLinkStr : string;
   GCSectionsStr : string;
   GCSectionsStr : string;
+  MapStr: string;
 begin
 begin
   StripStr:='';
   StripStr:='';
   GCSectionsStr:='';
   GCSectionsStr:='';
   DynLinkStr:='';
   DynLinkStr:='';
+  MapStr:='';
 
 
+  if UseVlink and (cs_link_map in current_settings.globalswitches) then
+    MapStr:='-M'+Unix2AmigaPath(maybequoted(ScriptFixFilename(current_module.mapfilename)));
   if (cs_link_strip in current_settings.globalswitches) then
   if (cs_link_strip in current_settings.globalswitches) then
     StripStr:='-s';
     StripStr:='-s';
   if rlinkpath<>'' Then
   if rlinkpath<>'' Then
@@ -406,6 +410,7 @@ begin
   Replace(cmdstr,'$OPT',Info.ExtraOptions);
   Replace(cmdstr,'$OPT',Info.ExtraOptions);
   Replace(cmdstr,'$EXE',Unix2AmigaPath(maybequoted(ScriptFixFileName(current_module.exefilename))));
   Replace(cmdstr,'$EXE',Unix2AmigaPath(maybequoted(ScriptFixFileName(current_module.exefilename))));
   Replace(cmdstr,'$RES',Unix2AmigaPath(maybequoted(ScriptFixFileName(outputexedir+Info.ResName))));
   Replace(cmdstr,'$RES',Unix2AmigaPath(maybequoted(ScriptFixFileName(outputexedir+Info.ResName))));
+  Replace(cmdstr,'$MAP',MapStr);
   Replace(cmdstr,'$STRIP',StripStr);
   Replace(cmdstr,'$STRIP',StripStr);
   Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
   Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
   Replace(cmdstr,'$DYNLINK',DynLinkStr);
   Replace(cmdstr,'$DYNLINK',DynLinkStr);

+ 6 - 1
compiler/systems/t_atari.pas

@@ -73,7 +73,7 @@ begin
      end
      end
     else
     else
      begin
      begin
-      ExeCmd[1]:='vlink -b ataritos $FLAGS $GCSECTIONS $OPT $STRIP -o $EXE -T $RES';
+      ExeCmd[1]:='vlink -b ataritos $FLAGS $GCSECTIONS $OPT $STRIP $MAP -o $EXE -T $RES';
      end;
      end;
    end;
    end;
 end;
 end;
@@ -215,13 +215,17 @@ var
   DynLinkStr : string;
   DynLinkStr : string;
   GCSectionsStr : string;
   GCSectionsStr : string;
   FlagsStr : string;
   FlagsStr : string;
+  MapStr: string;
   ExeName: string;
   ExeName: string;
 begin
 begin
   StripStr:='';
   StripStr:='';
   GCSectionsStr:='';
   GCSectionsStr:='';
   DynLinkStr:='';
   DynLinkStr:='';
+  MapStr:='';
   FlagsStr:='-tos-flags fastload,fastram';
   FlagsStr:='-tos-flags fastload,fastram';
 
 
+  if UseVlink and (cs_link_map in current_settings.globalswitches) then
+    MapStr:='-M'+maybequoted(ScriptFixFileName(current_module.mapfilename));
   if (cs_link_strip in current_settings.globalswitches) then
   if (cs_link_strip in current_settings.globalswitches) then
     StripStr:='-s';
     StripStr:='-s';
   if rlinkpath<>'' then
   if rlinkpath<>'' then
@@ -242,6 +246,7 @@ begin
   Replace(cmdstr,'$OPT',Info.ExtraOptions);
   Replace(cmdstr,'$OPT',Info.ExtraOptions);
   Replace(cmdstr,'$EXE',maybequoted(ScriptFixFileName(ExeName)));
   Replace(cmdstr,'$EXE',maybequoted(ScriptFixFileName(ExeName)));
   Replace(cmdstr,'$RES',maybequoted(ScriptFixFileName(outputexedir+Info.ResName)));
   Replace(cmdstr,'$RES',maybequoted(ScriptFixFileName(outputexedir+Info.ResName)));
+  Replace(cmdstr,'$MAP',MapStr);
   Replace(cmdstr,'$FLAGS',FlagsStr);
   Replace(cmdstr,'$FLAGS',FlagsStr);
   Replace(cmdstr,'$STRIP',StripStr);
   Replace(cmdstr,'$STRIP',StripStr);
   Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
   Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);

+ 69 - 28
compiler/systems/t_sinclairql.pas

@@ -35,7 +35,6 @@ type
     private
     private
       Origin: DWord;
       Origin: DWord;
       UseVLink: boolean;
       UseVLink: boolean;
-      ExeLength: longint;
       function WriteResponseFile(isdll: boolean): boolean;
       function WriteResponseFile(isdll: boolean): boolean;
       procedure SetSinclairQLInfo;
       procedure SetSinclairQLInfo;
       function MakeSinclairQLExe: boolean;
       function MakeSinclairQLExe: boolean;
@@ -53,6 +52,37 @@ implementation
        sysutils,cutils,cfileutl,cclasses,aasmbase,
        sysutils,cutils,cfileutl,cclasses,aasmbase,
        globtype,globals,systems,verbose,cscript,fmodule,i_sinclairql;
        globtype,globals,systems,verbose,cscript,fmodule,i_sinclairql;
 
 
+    type
+      TQLHeader = packed record
+        hdr_id: array[0..17] of char;
+        hdr_reserved: byte;
+        hdr_length: byte;
+        hdr_access: byte;
+        hdr_type: byte;
+        hdr_data: dword;
+        hdr_extra: dword;
+      end;
+
+      TXTccData = packed record
+        xtcc_id: array[0..3] of char;
+        xtcc_data: dword;
+      end;
+
+    const
+      DefaultQLHeader: TQLHeader = (
+        hdr_id: ']!QDOS File Header';
+        hdr_reserved: 0;
+        hdr_length: $f;
+        hdr_access: 0;
+        hdr_type: 1;
+        hdr_data: 0;
+        hdr_extra: 0;
+      );
+
+      DefaultXTccData: TXTCCData = (
+        xtcc_id: 'XTcc';
+        xtcc_data: 0;
+      );
 
 
     const
     const
        DefaultOrigin = $0;
        DefaultOrigin = $0;
@@ -85,7 +115,7 @@ begin
      end
      end
     else
     else
      begin
      begin
-      ExeCmd[1]:='vlink -b rawseg -q $FLAGS $GCSECTIONS $OPT $STRIP -o $EXE -T $RES';
+      ExeCmd[1]:='vlink -b rawseg -q $FLAGS $GCSECTIONS $OPT $STRIP $MAP -o $EXE -T $RES';
      end;
      end;
    end;
    end;
 end;
 end;
@@ -213,6 +243,7 @@ var
   DynLinkStr : string;
   DynLinkStr : string;
   GCSectionsStr : string;
   GCSectionsStr : string;
   FlagsStr : string;
   FlagsStr : string;
+  MapStr : string;
   ExeName: string;
   ExeName: string;
   fd,fs: file;
   fd,fs: file;
   fhdr: text;
   fhdr: text;
@@ -222,12 +253,19 @@ var
   HeaderLine: string;
   HeaderLine: string;
   HeaderSize: longint;
   HeaderSize: longint;
   code: word;
   code: word;
+  QLHeader: TQLHeader;
+  XTccData: TXTccData;
+  BinSize: longint;
+  DataSpace: DWord;
 begin
 begin
   StripStr:='';
   StripStr:='';
   GCSectionsStr:='';
   GCSectionsStr:='';
   DynLinkStr:='';
   DynLinkStr:='';
   FlagsStr:='';
   FlagsStr:='';
+  MapStr:='';
 
 
+  if (cs_link_map in current_settings.globalswitches) then
+    MapStr:='-M'+maybequoted(ScriptFixFilename(current_module.mapfilename));
   if (cs_link_strip in current_settings.globalswitches) then
   if (cs_link_strip in current_settings.globalswitches) then
     StripStr:='-s';
     StripStr:='-s';
   if rlinkpath<>'' then
   if rlinkpath<>'' then
@@ -247,6 +285,7 @@ begin
   Replace(cmdstr,'$OPT',Info.ExtraOptions);
   Replace(cmdstr,'$OPT',Info.ExtraOptions);
   Replace(cmdstr,'$EXE',maybequoted(ScriptFixFileName(ExeName)));
   Replace(cmdstr,'$EXE',maybequoted(ScriptFixFileName(ExeName)));
   Replace(cmdstr,'$RES',maybequoted(ScriptFixFileName(outputexedir+Info.ResName)));
   Replace(cmdstr,'$RES',maybequoted(ScriptFixFileName(outputexedir+Info.ResName)));
+  Replace(cmdstr,'$MAP',MapStr);
   Replace(cmdstr,'$FLAGS',FlagsStr);
   Replace(cmdstr,'$FLAGS',FlagsStr);
   Replace(cmdstr,'$STRIP',StripStr);
   Replace(cmdstr,'$STRIP',StripStr);
   Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
   Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
@@ -259,7 +298,10 @@ begin
       and the relocation info. Here we copy the two together. (KB) }
       and the relocation info. Here we copy the two together. (KB) }
   if MakeSinclairQLExe then
   if MakeSinclairQLExe then
     begin
     begin
-      ExeLength:=0;
+      QLHeader:=DefaultQLHeader;
+      XTccData:=DefaultXTccData;
+
+      BinSize:=0;
       bufsize:=16384;
       bufsize:=16384;
 {$push}
 {$push}
 {$i-}
 {$i-}
@@ -279,6 +321,19 @@ begin
 
 
       assign(fs,ExeName+'.'+ProgramHeaderName);
       assign(fs,ExeName+'.'+ProgramHeaderName);
       reset(fs,1);
       reset(fs,1);
+      BinSize := FileSize(fs);
+
+      { We assume .bss size is total size indicated by linker minus emmited binary.
+        DataSpace size is .bss + stack space }
+      DataSpace := NToBE(DWord(HeaderSize - BinSize + StackSize));
+
+      { Option: prepend QEmuLator and QPC2 v5 compatible header to EXE }
+      if sinclairql_metadata_format='QHDR' then
+        begin
+          QLHeader.hdr_data:=DataSpace;
+          blockwrite(fd, QLHeader, sizeof(QLHeader));
+        end;
+
       repeat
       repeat
         blockread(fs,buf^,bufsize,bufread);
         blockread(fs,buf^,bufsize,bufread);
         blockwrite(fd,buf^,bufread);
         blockwrite(fd,buf^,bufread);
@@ -295,25 +350,29 @@ begin
       close(fs);
       close(fs);
       // erase(fs);
       // erase(fs);
 
 
-      ExeLength:=FileSize(fd);
+      { Option: append cross compilation data space marker, this can be picked up by
+        a special version of InfoZIP (compiled with -DQLZIP and option -Q) or by any
+        of the XTcc unpack utilities }
+      if sinclairql_metadata_format='XTCC' then
+        begin
+          XTccData.xtcc_data:=DataSpace;
+          blockwrite(fd, XTccData, sizeof(XTccData));
+        end;
+
       close(fd);
       close(fd);
 {$pop}
 {$pop}
       FreeMem(buf);
       FreeMem(buf);
-      if HeaderSize > ExeLength then
-        ExeLength:=HeaderSize;
-      MakeSinclairQLExe:=(code = 0) and not (ExeLength = 0);
+
+      MakeSinclairQLExe:=(code = 0) and not (BinSize = 0) and (IOResult = 0);
     end;
     end;
 end;
 end;
 
 
 
 
 function TLinkerSinclairQL.MakeExecutable:boolean;
 function TLinkerSinclairQL.MakeExecutable:boolean;
-const
-  DefaultBootString = '10 $SYM=RESPR($BINSIZE):LBYTES"win1_$EXENAME",$SYM:CALL $SYM';
 var
 var
   success : boolean;
   success : boolean;
   bootfile : TScript;
   bootfile : TScript;
   ExeName: String;
   ExeName: String;
-  BootStr: String;
 begin
 begin
   if not(cs_link_nolink in current_settings.globalswitches) then
   if not(cs_link_nolink in current_settings.globalswitches) then
     Message1(exec_i_linking,current_module.exefilename);
     Message1(exec_i_linking,current_module.exefilename);
@@ -327,24 +386,6 @@ begin
   if (success) and not(cs_link_nolink in current_settings.globalswitches) then
   if (success) and not(cs_link_nolink in current_settings.globalswitches) then
     DeleteFile(outputexedir+Info.ResName);
     DeleteFile(outputexedir+Info.ResName);
 
 
-  if (success) then
-    begin
-      ExeName:=current_module.exefilename;
-      BootStr:=DefaultBootString;
-
-      Replace(BootStr,'$BINSIZE',tostr(ExeLength));
-      Replace(BootStr,'$EXENAME',ExeName);
-
-      Replace(ExeName,target_info.exeext,'');
-      Replace(BootStr,'$SYM',ExeName);
-
-      { Write bootfile }
-      bootfile:=TScript.Create(outputexedir+ExeName);
-      bootfile.Add(BootStr);
-      bootfile.writetodisk;
-      bootfile.Free;
-    end;
-
   MakeExecutable:=success;   { otherwise a recursive call to link method }
   MakeExecutable:=success;   { otherwise a recursive call to link method }
 end;
 end;
 
 

+ 7 - 1
compiler/systems/t_zxspectrum.pas

@@ -210,7 +210,7 @@ procedure TLinkerZXSpectrum.SetDefaultInfo_Vlink;
       FOrigin:=DefaultOrigin;
       FOrigin:=DefaultOrigin;
     with Info do
     with Info do
      begin
      begin
-       ExeCmd[1]:=ExeName+' -bihex $GCSECTIONS -e $STARTSYMBOL $STRIP $OPT -o $EXE -T $RES'
+       ExeCmd[1]:=ExeName+' -bihex $GCSECTIONS -e $STARTSYMBOL $STRIP $OPT $MAP -o $EXE -T $RES'
      end;
      end;
   end;
   end;
 
 
@@ -280,13 +280,18 @@ function TLinkerZXSpectrum.MakeExecutable_Vlink: boolean;
     GCSectionsStr,
     GCSectionsStr,
     StripStr,
     StripStr,
     StartSymbolStr,
     StartSymbolStr,
+    MapStr,
     FixedExeFilename: string;
     FixedExeFilename: string;
   begin
   begin
     GCSectionsStr:='-gc-all -mtype';
     GCSectionsStr:='-gc-all -mtype';
     StripStr:='';
     StripStr:='';
+    MapStr:='';
     StartSymbolStr:='start';
     StartSymbolStr:='start';
     FixedExeFileName:=maybequoted(ScriptFixFileName(ChangeFileExt(current_module.exefilename,'.ihx')));
     FixedExeFileName:=maybequoted(ScriptFixFileName(ChangeFileExt(current_module.exefilename,'.ihx')));
 
 
+    if (cs_link_map in current_settings.globalswitches) then
+      MapStr:='-M'+maybequoted(ScriptFixFileName(current_module.mapfilename));
+
   { Write used files and libraries }
   { Write used files and libraries }
     WriteResponseFile_Vlink();
     WriteResponseFile_Vlink();
 
 
@@ -296,6 +301,7 @@ function TLinkerZXSpectrum.MakeExecutable_Vlink: boolean;
 
 
     Replace(cmdstr,'$EXE',FixedExeFileName);
     Replace(cmdstr,'$EXE',FixedExeFileName);
     Replace(cmdstr,'$RES',(maybequoted(ScriptFixFileName(outputexedir+Info.ResName))));
     Replace(cmdstr,'$RES',(maybequoted(ScriptFixFileName(outputexedir+Info.ResName))));
+    Replace(cmdstr,'$MAP',MapStr);
     Replace(cmdstr,'$STRIP',StripStr);
     Replace(cmdstr,'$STRIP',StripStr);
     Replace(cmdstr,'$STARTSYMBOL',StartSymbolStr);
     Replace(cmdstr,'$STARTSYMBOL',StartSymbolStr);
     Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
     Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);

+ 1 - 1
compiler/utils/Makefile

@@ -3283,7 +3283,7 @@ ppumove$(EXEEXT): ppumove.pp ppu$(PPUEXT)
 	$(MAKE) ppumove$(EXEEXT) NOCPUDEF=1
 	$(MAKE) ppumove$(EXEEXT) NOCPUDEF=1
 else
 else
 ppu$(PPUEXT): ../ppu.pas
 ppu$(PPUEXT): ../ppu.pas
-	$(COMPILER) ../ppu.pas -Fu../generic -dGENERIC_CPU -Fi..
+	$(COMPILER) ../ppu.pas -Fu../llvm -Fu../generic -dGENERIC_CPU -Fi..
 ppudump$(EXEEXT): ppuutils/ppudump.pp ppu$(PPUEXT)
 ppudump$(EXEEXT): ppuutils/ppudump.pp ppu$(PPUEXT)
 	$(COMPILER) ppuutils/ppudump.pp -Fu../llvm -Fu../generic -dGENERIC_CPU -Fi..
 	$(COMPILER) ppuutils/ppudump.pp -Fu../llvm -Fu../generic -dGENERIC_CPU -Fi..
 ppufiles$(EXEEXT): ppufiles.pp ppu$(PPUEXT)
 ppufiles$(EXEEXT): ppufiles.pp ppu$(PPUEXT)

+ 1 - 1
compiler/utils/Makefile.fpc

@@ -57,7 +57,7 @@ ppumove$(EXEEXT): ppumove.pp ppu$(PPUEXT)
 
 
 else
 else
 ppu$(PPUEXT): ../ppu.pas
 ppu$(PPUEXT): ../ppu.pas
-        $(COMPILER) ../ppu.pas -Fu../generic -dGENERIC_CPU -Fi..
+        $(COMPILER) ../ppu.pas -Fu../llvm -Fu../generic -dGENERIC_CPU -Fi..
 
 
 ppudump$(EXEEXT): ppuutils/ppudump.pp ppu$(PPUEXT)
 ppudump$(EXEEXT): ppuutils/ppudump.pp ppu$(PPUEXT)
         $(COMPILER) ppuutils/ppudump.pp -Fu../llvm -Fu../generic -dGENERIC_CPU -Fi..
         $(COMPILER) ppuutils/ppudump.pp -Fu../llvm -Fu../generic -dGENERIC_CPU -Fi..

+ 16 - 14
compiler/xtensa/agcpugas.pas

@@ -78,30 +78,32 @@ unit agcpugas;
       begin
       begin
          with ref do
          with ref do
           begin
           begin
-{$ifdef extdebug}
-            // if base=NR_NO then
-            //   internalerror(200308292);
-
-            // if ((index<>NR_NO) or (shiftmode<>SM_None)) and ((offset<>0) or (symbol<>nil)) then
-            //   internalerror(200308293);
-{$endif extdebug}
-
             if assigned(symbol) then
             if assigned(symbol) then
               begin
               begin
                 s:=symbol.name;
                 s:=symbol.name;
                 if offset<>0 then
                 if offset<>0 then
                   s:=s+tostr_with_plus(offset);
                   s:=s+tostr_with_plus(offset);
-                if refaddr=addr_pic then
-                  s:=s+'(PLT)'
-                {else if refaddr=addr_tlscall then
-                  s:=s+'(tlscall)'};
+                case refaddr of
+                  addr_pic:
+                    s:=s+'(PLT)';
+                  addr_full,
+                  addr_no:
+                    ;
+                  else
+                    Internalerror(2020112403);
+                end;
               end
               end
             else
             else
               begin
               begin
                 s:=gas_regname(base);
                 s:=gas_regname(base);
                 if index<>NR_NO then
                 if index<>NR_NO then
-                  Internalerror(2020030802);
-                s:=s+','+tostr(offset);
+                  begin
+                    s:=s+','+gas_regname(index);
+                    if offset<>0 then
+                      Internalerror(2020112402);
+                  end
+                else
+                  s:=s+','+tostr(offset);
               end;
               end;
           end;
           end;
         getreferencestring:=s;
         getreferencestring:=s;

+ 10 - 4
compiler/xtensa/cgcpu.pas

@@ -1179,11 +1179,14 @@ implementation
            InternalError(2020032602);
            InternalError(2020032602);
          href:=ref;
          href:=ref;
          if assigned(href.symbol) or
          if assigned(href.symbol) or
-           (href.index<>NR_NO) or
+           ((href.index<>NR_NO) and (href.offset<>0)) or
            (((href.offset<0) or (href.offset>1020) or (href.offset mod 4<>0))) then
            (((href.offset<0) or (href.offset>1020) or (href.offset mod 4<>0))) then
            fixref(list,href);
            fixref(list,href);
 
 
-         list.concat(taicpu.op_reg_ref(A_LSI,reg,href));
+         if (href.base<>NR_NO) and (href.index<>NR_NO) then
+           list.concat(taicpu.op_reg_ref(A_LSX,reg,href))
+         else
+           list.concat(taicpu.op_reg_ref(A_LSI,reg,href));
 
 
          if fromsize<>tosize then
          if fromsize<>tosize then
            a_loadfpu_reg_reg(list,fromsize,tosize,reg,reg);
            a_loadfpu_reg_reg(list,fromsize,tosize,reg,reg);
@@ -1198,11 +1201,14 @@ implementation
            InternalError(2020032604);
            InternalError(2020032604);
          href:=ref;
          href:=ref;
          if assigned(href.symbol) or
          if assigned(href.symbol) or
-           (href.index<>NR_NO) or
+           ((href.index<>NR_NO) and (href.offset<>0)) or
            (((href.offset<0) or (href.offset>1020) or (href.offset mod 4<>0))) then
            (((href.offset<0) or (href.offset>1020) or (href.offset mod 4<>0))) then
            fixref(list,href);
            fixref(list,href);
 
 
-         list.concat(taicpu.op_reg_ref(A_SSI,reg,href));
+         if (href.base<>NR_NO) and (href.index<>NR_NO) then
+           list.concat(taicpu.op_reg_ref(A_SSX,reg,href))
+         else
+           list.concat(taicpu.op_reg_ref(A_SSI,reg,href));
        end;
        end;
 
 
 
 

+ 8 - 0
compiler/xtensa/ncpuadd.pas

@@ -47,6 +47,7 @@ interface
          procedure second_cmpfloat;override;
          procedure second_cmpfloat;override;
          procedure second_addfloat;override;
          procedure second_addfloat;override;
          procedure second_cmp;
          procedure second_cmp;
+         function use_fma: boolean;override;
        end;
        end;
 
 
   implementation
   implementation
@@ -67,6 +68,13 @@ interface
                                TCPUAddNode
                                TCPUAddNode
 *****************************************************************************}
 *****************************************************************************}
 
 
+    function TCPUAddNode.use_fma : boolean;
+      begin
+        Result:=is_single(left.resultdef) and is_single(right.resultdef) and
+          (FPUXTENSA_SINGLE in fpu_capabilities[current_settings.fputype]);
+      end;
+
+
     procedure TCPUAddNode.second_addordinal;
     procedure TCPUAddNode.second_addordinal;
       var
       var
         ophigh: tasmop;
         ophigh: tasmop;

+ 83 - 0
compiler/xtensa/ncpuinl.pas

@@ -33,6 +33,8 @@ unit ncpuinl;
         function first_abs_real: tnode; override;
         function first_abs_real: tnode; override;
         procedure second_abs_long; override;
         procedure second_abs_long; override;
         procedure second_abs_real; override;
         procedure second_abs_real; override;
+        function first_fma: tnode; override;
+        procedure second_fma; override;
       end;
       end;
 
 
   implementation
   implementation
@@ -48,6 +50,7 @@ unit ncpuinl;
       hlcgobj,
       hlcgobj,
       pass_2,
       pass_2,
       cgbase, cgobj, cgutils,
       cgbase, cgobj, cgutils,
+      ncal,
       cpubase;
       cpubase;
 
 
     procedure tcpuinlinenode.second_abs_long;
     procedure tcpuinlinenode.second_abs_long;
@@ -84,6 +87,86 @@ unit ncpuinl;
       end;
       end;
 
 
 
 
+    function tcpuinlinenode.first_fma : tnode;
+      begin
+        if is_single(resultdef) then
+          begin
+            expectloc:=LOC_FPUREGISTER;
+            Result:=nil;
+          end
+        else
+          Result:=inherited first_fma;
+      end;
+
+
+    procedure tcpuinlinenode.second_fma;
+      const
+        op : array[false..true] of TAsmOp =
+          (A_MADD,
+           A_MSUB);
+
+      var
+        paraarray : array[1..3] of tnode;
+        i : integer;
+        negproduct : boolean;
+        oppostfix : TOpPostfix;
+        ai: taicpu;
+      begin
+         if is_single(resultdef)and
+           (FPUXTENSA_SINGLE in fpu_capabilities[current_settings.fputype]) then
+           begin
+             negproduct:=false;
+             paraarray[1]:=tcallparanode(tcallparanode(tcallparanode(parameters).nextpara).nextpara).paravalue;
+             paraarray[2]:=tcallparanode(tcallparanode(parameters).nextpara).paravalue;
+             paraarray[3]:=tcallparanode(parameters).paravalue;
+
+             { check if a neg. node can be removed
+               this is possible because changing the sign of
+               a floating point number does not affect its absolute
+               value in any way
+             }
+             if paraarray[1].nodetype=unaryminusn then
+               begin
+                 paraarray[1]:=tunarynode(paraarray[1]).left;
+                 { do not release the unused unary minus node, it is kept and release together with the other nodes,
+                   only no code is generated for it }
+                 negproduct:=not(negproduct);
+               end;
+
+             if paraarray[2].nodetype=unaryminusn then
+               begin
+                 paraarray[2]:=tunarynode(paraarray[2]).left;
+                 { do not release the unused unary minus node, it is kept and release together with the other nodes,
+                   only no code is generated for it }
+                 negproduct:=not(negproduct);
+               end;
+              for i:=1 to 3 do
+               secondpass(paraarray[i]);
+
+             { no memory operand is allowed }
+             for i:=1 to 3 do
+               begin
+                 if not(paraarray[i].location.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER]) then
+                   hlcg.location_force_fpureg(current_asmdata.CurrAsmList,paraarray[i].location,paraarray[i].resultdef,true);
+               end;
+
+             location_reset(location,LOC_FPUREGISTER,paraarray[1].location.size);
+             location.register:=cg.getfpuregister(current_asmdata.CurrAsmList,location.size);
+
+             hlcg.a_loadfpu_reg_reg(current_asmdata.CurrAsmList,paraarray[3].resultdef,resultdef,
+               paraarray[3].location.register,location.register);
+
+             ai:=taicpu.op_reg_reg_reg(op[negproduct],
+               location.register,paraarray[1].location.register,paraarray[2].location.register);
+             ai.oppostfix:=PF_S;
+             current_asmdata.CurrAsmList.concat(ai);
+
+             cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
+           end
+         else
+           internalerror(2020112401);
+      end;
+
 
 
 begin
 begin
   cinlinenode:=tcpuinlinenode;
   cinlinenode:=tcpuinlinenode;

+ 1 - 1
packages/fcl-sound/src/fpwavreader.pas

@@ -96,7 +96,7 @@ begin
   LEtoN(fmt);
   LEtoN(fmt);
   Result := Result and (fmt.ChunkHeader.ID = AUDIO_CHUNK_ID_fmt) and ((fmt.ChunkHeader.Size + 8) >= sizeof(fmt));
   Result := Result and (fmt.ChunkHeader.ID = AUDIO_CHUNK_ID_fmt) and ((fmt.ChunkHeader.Size + 8) >= sizeof(fmt));
   if Result and ((fmt.ChunkHeader.Size + 8) > sizeof(fmt)) then
   if Result and ((fmt.ChunkHeader.Size + 8) > sizeof(fmt)) then
-    fStream.Seek((fmt.ChunkHeader.Size + 8) - sizeof(fmt), soCurrent);
+    fStream.Seek(Align((fmt.ChunkHeader.Size + 8) - sizeof(fmt), 2), soCurrent);
 end;
 end;
 
 
 function Min(a, b: Integer): Integer;
 function Min(a, b: Integer): Integer;

BIN
packages/fcl-sound/tests/data/wav/reader/valid/odd_fmt_size.wav


+ 1 - 0
packages/fcl-sound/tests/data/wav/reader/valid/odd_fmt_size.wav.info.txt

@@ -0,0 +1 @@
+4800 1 8 1

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
packages/fcl-sound/tests/data/wav/reader/valid/odd_fmt_size.wav.raw


+ 1 - 0
packages/fcl-sound/tests/tcwavreader.pas

@@ -91,6 +91,7 @@ begin
   TestValidFile('44k_stereo_64float.wav');
   TestValidFile('44k_stereo_64float.wav');
   TestValidFile('44k_mono_16_tag.wav');
   TestValidFile('44k_mono_16_tag.wav');
   TestValidFile('euphoric_tape.wav');
   TestValidFile('euphoric_tape.wav');
+  TestValidFile('odd_fmt_size.wav');
 end;
 end;
 
 
 
 

+ 5 - 5
packages/qlunits/examples/qlcube.pas

@@ -154,7 +154,7 @@ end;
 
 
 procedure draw_line(x1,y1,x2,y2: smallint);
 procedure draw_line(x1,y1,x2,y2: smallint);
 begin
 begin
-  sd_line(QCON,-1,x1,y1,x2,y2);
+  sd_line(stdOutputHandle,-1,x1,y1,x2,y2);
 end;
 end;
 
 
 procedure cube_redraw;
 procedure cube_redraw;
@@ -182,14 +182,14 @@ begin
       longint_to_qlfp(@fcubey[i],cy + sarlongint(mulfp(vy,scale),16));
       longint_to_qlfp(@fcubey[i],cy + sarlongint(mulfp(vy,scale),16));
     end;
     end;
 
 
-  sd_clear(QCON,-1);
+  sd_clear(stdOutputHandle,-1);
   for i:=0 to 3 do 
   for i:=0 to 3 do 
     begin
     begin
       e:=(i+1) and 3;
       e:=(i+1) and 3;
-      sd_line(QCON,-1,@fcubex[i],@fcubey[i],@fcubex[e],@fcubey[e]);
+      sd_line(stdOutputHandle,-1,@fcubex[i],@fcubey[i],@fcubex[e],@fcubey[e]);
       s:=i+4; e:=e+4;
       s:=i+4; e:=e+4;
-      sd_line(QCON,-1,@fcubex[s],@fcubey[s],@fcubex[e],@fcubey[e]);
-      sd_line(QCON,-1,@fcubex[i],@fcubey[i],@fcubex[s],@fcubey[s]);
+      sd_line(stdOutputHandle,-1,@fcubex[s],@fcubey[s],@fcubex[e],@fcubey[e]);
+      sd_line(stdOutputHandle,-1,@fcubex[i],@fcubey[i],@fcubex[s],@fcubey[s]);
     end;
     end;
 end;
 end;
 
 

+ 12 - 9
rtl/emx/sysutils.pp

@@ -1097,30 +1097,33 @@ asm
  mov ah, 2Ah
  mov ah, 2Ah
  call syscall
  call syscall
 {$IFDEF REGCALL}
 {$IFDEF REGCALL}
- pop eax
+ pop edi
 {$ELSE REGCALL}
 {$ELSE REGCALL}
  mov edi, SystemTime
  mov edi, SystemTime
 {$ENDIF REGCALL}
 {$ENDIF REGCALL}
- mov ax, cx
- stosw
- xor eax, eax
- mov al, 10
- mul dl
+ xchg ax, cx
  shl eax, 16
  shl eax, 16
  mov al, dh
  mov al, dh
  stosd
  stosd
+ mov al, dl
+ shl eax, 16
+ mov al, cl
+ stosd
  push edi
  push edi
  mov ah, 2Ch
  mov ah, 2Ch
  call syscall
  call syscall
  pop edi
  pop edi
  xor eax, eax
  xor eax, eax
- mov al, cl
- shl eax, 16
  mov al, ch
  mov al, ch
+ shl eax, 16
+ mov al, cl
  stosd
  stosd
- mov al, dl
+ xor eax, eax
+ mov al, 10
+ mul dl
  shl eax, 16
  shl eax, 16
  mov al, dh
  mov al, dh
+ rol eax, 16
  stosd
  stosd
  pop edi
  pop edi
 end {['eax', 'ecx', 'edx', 'edi']};
 end {['eax', 'ecx', 'edx', 'edi']};

+ 13 - 0
rtl/go32v2/sysutils.pp

@@ -47,6 +47,7 @@ implementation
 
 
 {$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
 {$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
 {$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *)
 {$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *)
+{$DEFINE HAS_LOCALTIMEZONEOFFSET}
 
 
 { Include platform independent implementation part }
 { Include platform independent implementation part }
 {$i sysutils.inc}
 {$i sysutils.inc}
@@ -644,6 +645,8 @@ end;
                               Time Functions
                               Time Functions
 ****************************************************************************}
 ****************************************************************************}
 
 
+{$I tzenv.inc}
+
 Procedure GetLocalTime(var SystemTime: TSystemTime);
 Procedure GetLocalTime(var SystemTime: TSystemTime);
 var
 var
   Regs: Registers;
   Regs: Registers;
@@ -659,6 +662,7 @@ begin
   SystemTime.Year := Regs.Cx;
   SystemTime.Year := Regs.Cx;
   SystemTime.Month := Regs.Dh;
   SystemTime.Month := Regs.Dh;
   SystemTime.Day := Regs.Dl;
   SystemTime.Day := Regs.Dl;
+  SystemTime.DayOfWeek := Regs.Al;
 end ;
 end ;
 
 
 
 
@@ -666,8 +670,16 @@ end ;
                               Misc Functions
                               Misc Functions
 ****************************************************************************}
 ****************************************************************************}
 
 
+const
+  BeepChars: array [1..2] of char = #7'$';
+
 procedure sysBeep;
 procedure sysBeep;
+var
+  Regs: Registers;
 begin
 begin
+  Regs.dx := Ofs (BeepChars);
+  Regs.ah := 9;
+  MsDos (Regs);
 end;
 end;
 
 
 
 
@@ -915,6 +927,7 @@ end;
 Initialization
 Initialization
   InitExceptions;       { Initialize exceptions. OS independent }
   InitExceptions;       { Initialize exceptions. OS independent }
   InitInternational;    { Initialize internationalization settings }
   InitInternational;    { Initialize internationalization settings }
+  InitTZ;
   OnBeep:=@SysBeep;
   OnBeep:=@SysBeep;
 Finalization
 Finalization
   FreeTerminateProcs;
   FreeTerminateProcs;

+ 1 - 4
rtl/go32v2/v2prt0.as

@@ -38,6 +38,7 @@
         .comm   __stubinfo, 4
         .comm   __stubinfo, 4
         .comm   ___djgpp_base_address, 4
         .comm   ___djgpp_base_address, 4
         .comm   ___djgpp_selector_limit, 4
         .comm   ___djgpp_selector_limit, 4
+        .comm   __crt0_startup_flags, 4
         .comm   ___djgpp_stack_limit, 4
         .comm   ___djgpp_stack_limit, 4
         .lcomm  sel_buf, 8
         .lcomm  sel_buf, 8
 
 
@@ -921,10 +922,6 @@ ___v2prt0_start_fs:
 ___bs_count:
 ___bs_count:
         .long   1
         .long   1
 
 
-        .globl  __crt0_startup_flags
-__crt0_startup_flags:
-        .long   0
-
         .globl  __dos_ds
         .globl  __dos_ds
 __dos_ds:
 __dos_ds:
         .long   0
         .long   0

+ 1 - 1
rtl/linux/riscv64/si_c.inc

@@ -39,7 +39,7 @@ procedure _FPC_rv_enter(at_exit: TProcedure; sp: pptruint);
     initialstkptr:=sp;
     initialstkptr:=sp;
     operatingsystem_parameter_argc:=argc;
     operatingsystem_parameter_argc:=argc;
     operatingsystem_parameter_argv:=argv;
     operatingsystem_parameter_argv:=argv;
-    operatingsystem_parameter_envp:=@sp[1+argc];
+    operatingsystem_parameter_envp:=@sp[argc+2];
 
 
     libc_start_main(@PascalMain, argc, argv, libc_init_proc, libc_fini_proc, at_exit, sp);
     libc_start_main(@PascalMain, argc, argv, libc_init_proc, libc_fini_proc, at_exit, sp);
   end;
   end;

+ 1 - 1
rtl/linux/riscv64/si_prc.inc

@@ -31,7 +31,7 @@ procedure _FPC_rv_enter(sp: pptruint);
     initialstkptr:=sp;
     initialstkptr:=sp;
     operatingsystem_parameter_argc:=argc;
     operatingsystem_parameter_argc:=argc;
     operatingsystem_parameter_argv:=@sp[1];
     operatingsystem_parameter_argv:=@sp[1];
-    operatingsystem_parameter_envp:=@sp[1+argc];
+    operatingsystem_parameter_envp:=@sp[argc+2];
 
 
     PascalMain;
     PascalMain;
   end;
   end;

+ 1 - 1
rtl/linux/xtensa/si_c.inc

@@ -39,7 +39,7 @@ procedure _FPC_xtensa_enter(at_exit: TProcedure; sp: pptruint);
     initialstkptr:=sp;
     initialstkptr:=sp;
     operatingsystem_parameter_argc:=argc;
     operatingsystem_parameter_argc:=argc;
     operatingsystem_parameter_argv:=argv;
     operatingsystem_parameter_argv:=argv;
-    operatingsystem_parameter_envp:=@sp[1+argc];
+    operatingsystem_parameter_envp:=@sp[argc+2];
 
 
     libc_start_main(@PascalMain, argc, argv, libc_init_proc, libc_fini_proc, at_exit, sp);
     libc_start_main(@PascalMain, argc, argv, libc_init_proc, libc_fini_proc, at_exit, sp);
   end;
   end;

+ 1 - 1
rtl/linux/xtensa/si_prc.inc

@@ -31,7 +31,7 @@ procedure _FPC_xtensa_enter(sp: pptruint);
     initialstkptr:=sp;
     initialstkptr:=sp;
     operatingsystem_parameter_argc:=argc;
     operatingsystem_parameter_argc:=argc;
     operatingsystem_parameter_argv:=@sp[1];
     operatingsystem_parameter_argv:=@sp[1];
-    operatingsystem_parameter_envp:=@sp[1+argc];
+    operatingsystem_parameter_envp:=@sp[argc+2];
 
 
     PascalMain;
     PascalMain;
   end;
   end;

+ 13 - 0
rtl/msdos/sysutils.pp

@@ -48,6 +48,7 @@ implementation
 
 
 {$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
 {$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
 {$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *)
 {$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *)
+{$DEFINE HAS_LOCALTIMEZONEOFFSET}
 
 
 {$DEFINE executeprocuni} (* Only 1 byte version of ExecuteProcess is provided by the OS *)
 {$DEFINE executeprocuni} (* Only 1 byte version of ExecuteProcess is provided by the OS *)
 
 
@@ -629,6 +630,8 @@ end;
                               Time Functions
                               Time Functions
 ****************************************************************************}
 ****************************************************************************}
 
 
+{$I tzenv.inc}
+
 Procedure GetLocalTime(var SystemTime: TSystemTime);
 Procedure GetLocalTime(var SystemTime: TSystemTime);
 var
 var
   Regs: Registers;
   Regs: Registers;
@@ -644,6 +647,7 @@ begin
   SystemTime.Year := Regs.Cx;
   SystemTime.Year := Regs.Cx;
   SystemTime.Month := Regs.Dh;
   SystemTime.Month := Regs.Dh;
   SystemTime.Day := Regs.Dl;
   SystemTime.Day := Regs.Dl;
+  SystemTime.DayOfWeek := Regs.Al;
 end ;
 end ;
 
 
 
 
@@ -651,8 +655,16 @@ end ;
                               Misc Functions
                               Misc Functions
 ****************************************************************************}
 ****************************************************************************}
 
 
+const
+  BeepChars: array [1..2] of char = #7'$';
+
 procedure sysBeep;
 procedure sysBeep;
+var
+  Regs: Registers;
 begin
 begin
+  Regs.dx := Ofs (BeepChars);
+  Regs.ah := 9;
+  MsDos (Regs);
 end;
 end;
 
 
 
 
@@ -926,6 +938,7 @@ Initialization
   InitExceptions;       { Initialize exceptions. OS independent }
   InitExceptions;       { Initialize exceptions. OS independent }
   InitInternational;    { Initialize internationalization settings }
   InitInternational;    { Initialize internationalization settings }
   OnBeep:=@SysBeep;
   OnBeep:=@SysBeep;
+  InitTZ;
 Finalization
 Finalization
   FreeTerminateProcs;
   FreeTerminateProcs;
   DoneExceptions;
   DoneExceptions;

+ 99 - 99
rtl/objpas/sysutils/syssb.inc

@@ -1,11 +1,11 @@
-{ TStringBuilder }
+{ TGenericStringBuilder }
 
 
-constructor TStringBuilder.Create;
+constructor TGenericStringBuilder.Create;
 begin
 begin
   Create(DefaultCapacity,Maxint);
   Create(DefaultCapacity,Maxint);
 end;
 end;
 
 
-constructor TStringBuilder.Create(const AValue: SBString; aCapacity: Integer);
+constructor TGenericStringBuilder.Create(const AValue: SBString; aCapacity: Integer);
 begin
 begin
   Create(aCapacity,Maxint);
   Create(aCapacity,Maxint);
   if (system.Length(AValue)>0) then
   if (system.Length(AValue)>0) then
@@ -13,25 +13,25 @@ begin
 end;
 end;
 
 
 
 
-constructor TStringBuilder.Create(const AValue: SBString; StartIndex, Alength,
+constructor TGenericStringBuilder.Create(const AValue: SBString; StartIndex, Alength,
   aCapacity: Integer);
   aCapacity: Integer);
 begin
 begin
   Create(Copy(AValue,StartIndex+1,Alength), aCapacity);
   Create(Copy(AValue,StartIndex+1,Alength), aCapacity);
 end;
 end;
 
 
-constructor TStringBuilder.Create(aCapacity, aMaxCapacity: Integer);
+constructor TGenericStringBuilder.Create(aCapacity, aMaxCapacity: Integer);
 begin
 begin
   FMaxCapacity:=aMaxCapacity;
   FMaxCapacity:=aMaxCapacity;
   Capacity:=aCapacity;
   Capacity:=aCapacity;
   FLength:=0;
   FLength:=0;
 end;
 end;
 
 
-constructor TStringBuilder.Create(aCapacity: Integer);
+constructor TGenericStringBuilder.Create(aCapacity: Integer);
 begin
 begin
   Create(aCapacity,MaxInt);
   Create(aCapacity,MaxInt);
 end;
 end;
 
 
-constructor TStringBuilder.Create(const AValue: SBString);
+constructor TGenericStringBuilder.Create(const AValue: SBString);
 begin
 begin
   Create(aValue,DefaultCapacity);
   Create(aValue,DefaultCapacity);
 end;
 end;
@@ -39,31 +39,31 @@ end;
 
 
 { Property getter/setter }
 { Property getter/setter }
 
 
-function TStringBuilder.GetLength: Integer;
+function TGenericStringBuilder.GetLength: Integer;
 begin
 begin
   Result:=FLength;
   Result:=FLength;
 end;
 end;
 
 
-function TStringBuilder.GetCapacity: Integer;
+function TGenericStringBuilder.GetCapacity: Integer;
 begin
 begin
   Result:=System.Length(FData);
   Result:=System.Length(FData);
 end;
 end;
 
 
-function TStringBuilder.GetC(Index: Integer): SBChar;
+function TGenericStringBuilder.GetC(Index: Integer): SBChar;
 begin
 begin
   CheckNegative(Index,'Index');
   CheckNegative(Index,'Index');
   CheckRange(Index,0,Length);
   CheckRange(Index,0,Length);
   Result:=FData[Index];
   Result:=FData[Index];
 end;
 end;
 
 
-procedure TStringBuilder.SetC(Index: Integer; AValue: SBChar);
+procedure TGenericStringBuilder.SetC(Index: Integer; AValue: SBChar);
 begin
 begin
   CheckNegative(Index,'Index');
   CheckNegative(Index,'Index');
   CheckRange(Index,0,Length-1);
   CheckRange(Index,0,Length-1);
   FData[Index]:=AValue;
   FData[Index]:=AValue;
 end;
 end;
 
 
-procedure TStringBuilder.SetLength(AValue: Integer);
+procedure TGenericStringBuilder.SetLength(AValue: Integer);
 
 
 begin
 begin
   CheckNegative(AValue,'AValue');
   CheckNegative(AValue,'AValue');
@@ -77,7 +77,7 @@ end;
 
 
 
 
 
 
-procedure TStringBuilder.CheckRange(Idx, Count, MaxLen: Integer);
+procedure TGenericStringBuilder.CheckRange(Idx, Count, MaxLen: Integer);
 
 
 begin
 begin
   if (Idx<0) or (Idx+Count>MaxLen) then
   if (Idx<0) or (Idx+Count>MaxLen) then
@@ -85,7 +85,7 @@ begin
 end;
 end;
 
 
 
 
-procedure TStringBuilder.CheckNegative(const AValue: Integer;
+procedure TGenericStringBuilder.CheckNegative(const AValue: Integer;
   const AName: SBString);
   const AName: SBString);
 
 
 begin
 begin
@@ -95,7 +95,7 @@ end;
 
 
 {  These do the actual Appending/Inserting }
 {  These do the actual Appending/Inserting }
 
 
-procedure TStringBuilder.DoAppend(const S: {$IFDEF SBUNICODE}SBString{$ELSE}RawByteString{$ENDIF});
+procedure TGenericStringBuilder.DoAppend(const S: {$IFDEF SBUNICODE}SBString{$ELSE}RawByteString{$ENDIF});
 
 
 Var
 Var
   L,SL : Integer;
   L,SL : Integer;
@@ -110,7 +110,7 @@ begin
     end;
     end;
 end;
 end;
 
 
-procedure TStringBuilder.DoAppend(const AValue: TSBCharArray; Idx, aCount: Integer
+procedure TGenericStringBuilder.DoAppend(const AValue: TSBCharArray; Idx, aCount: Integer
   );
   );
 
 
 Var
 Var
@@ -123,7 +123,7 @@ begin
   Move(AValue[Idx],FData[L],aCount*SizeOf(SBChar));
   Move(AValue[Idx],FData[L],aCount*SizeOf(SBChar));
 end;
 end;
 
 
-procedure TStringBuilder.DoInsert(Index: Integer; const AValue: SBString);
+procedure TGenericStringBuilder.DoInsert(Index: Integer; const AValue: SBString);
 
 
 Var
 Var
   ShiftLen,LV : Integer;
   ShiftLen,LV : Integer;
@@ -137,7 +137,7 @@ begin
   Move(AValue[1],FData[Index],LV*SizeOf(SBChar));
   Move(AValue[1],FData[Index],LV*SizeOf(SBChar));
 end;
 end;
 
 
-procedure TStringBuilder.DoInsert(Index: Integer; const AValue: TSBCharArray;
+procedure TGenericStringBuilder.DoInsert(Index: Integer; const AValue: TSBCharArray;
   StartIndex, SBCharCount: Integer);
   StartIndex, SBCharCount: Integer);
 
 
 Var
 Var
@@ -157,13 +157,13 @@ end;
 
 
 { Public routines for appending }
 { Public routines for appending }
 
 
-function TStringBuilder.Append(const AValue: UInt64): TStringBuilder;
+function TGenericStringBuilder.Append(const AValue: UInt64): TGenericStringBuilder;
 begin
 begin
   DoAppend(IntToStr(AValue));
   DoAppend(IntToStr(AValue));
   Result:=self;
   Result:=self;
 end;
 end;
 
 
-function TStringBuilder.Append(const AValue: TSBCharArray): TStringBuilder;
+function TGenericStringBuilder.Append(const AValue: TSBCharArray): TGenericStringBuilder;
 
 
 var
 var
   I,L: Integer;
   I,L: Integer;
@@ -180,100 +180,100 @@ begin
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.Append(const AValue: Single): TStringBuilder;
+function TGenericStringBuilder.Append(const AValue: Single): TGenericStringBuilder;
 begin
 begin
   DoAppend(FloatToStr(AValue));
   DoAppend(FloatToStr(AValue));
   Result:=self;
   Result:=self;
 end;
 end;
 
 
-function TStringBuilder.Append(const AValue: Word): TStringBuilder;
+function TGenericStringBuilder.Append(const AValue: Word): TGenericStringBuilder;
 begin
 begin
   Append(IntToStr(AValue));
   Append(IntToStr(AValue));
   Result:=self;
   Result:=self;
 end;
 end;
 
 
-function TStringBuilder.Append(const AValue: Cardinal): TStringBuilder;
+function TGenericStringBuilder.Append(const AValue: Cardinal): TGenericStringBuilder;
 begin
 begin
   DoAppend(IntToStr(AValue));
   DoAppend(IntToStr(AValue));
   Result:=self;
   Result:=self;
 end;
 end;
 
 
-function TStringBuilder.Append(const AValue: SBChar; RepeatCount: Integer
-  ): TStringBuilder;
+function TGenericStringBuilder.Append(const AValue: SBChar; RepeatCount: Integer
+  ): TGenericStringBuilder;
 begin
 begin
   DoAppend(StringOfChar(AValue,RepeatCount));
   DoAppend(StringOfChar(AValue,RepeatCount));
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
 
 
-function TStringBuilder.Append(const AValue: Shortint): TStringBuilder;
+function TGenericStringBuilder.Append(const AValue: Shortint): TGenericStringBuilder;
 begin
 begin
   DoAppend(IntToStr(AValue));
   DoAppend(IntToStr(AValue));
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.Append(const AValue: SBChar): TStringBuilder;
+function TGenericStringBuilder.Append(const AValue: SBChar): TGenericStringBuilder;
 begin
 begin
   DoAppend(AValue);
   DoAppend(AValue);
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.Append(const AValue: Currency): TStringBuilder;
+function TGenericStringBuilder.Append(const AValue: Currency): TGenericStringBuilder;
 begin
 begin
   DoAppend(CurrToStr(AValue));
   DoAppend(CurrToStr(AValue));
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.Append(const AValue: Boolean): TStringBuilder;
+function TGenericStringBuilder.Append(const AValue: Boolean): TGenericStringBuilder;
 begin
 begin
   DoAppend(BoolToStr(AValue, True));
   DoAppend(BoolToStr(AValue, True));
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.Append(const AValue: Byte): TStringBuilder;
+function TGenericStringBuilder.Append(const AValue: Byte): TGenericStringBuilder;
 begin
 begin
   DoAppend(IntToStr(AValue));
   DoAppend(IntToStr(AValue));
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.Append(const AValue: Double): TStringBuilder;
+function TGenericStringBuilder.Append(const AValue: Double): TGenericStringBuilder;
 begin
 begin
   DoAppend(FloatToStr(AValue));
   DoAppend(FloatToStr(AValue));
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.Append(const AValue: Int64): TStringBuilder;
+function TGenericStringBuilder.Append(const AValue: Int64): TGenericStringBuilder;
 begin
 begin
   DoAppend(IntToStr(AValue));
   DoAppend(IntToStr(AValue));
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.Append(const AValue: TObject): TStringBuilder;
+function TGenericStringBuilder.Append(const AValue: TObject): TGenericStringBuilder;
 begin
 begin
   DoAppend(AValue.ToString);
   DoAppend(AValue.ToString);
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.Append(const AValue: Smallint): TStringBuilder;
+function TGenericStringBuilder.Append(const AValue: Smallint): TGenericStringBuilder;
 begin
 begin
   DoAppend(IntToStr(AValue));
   DoAppend(IntToStr(AValue));
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.Append(const AValue: LongInt): TStringBuilder;
+function TGenericStringBuilder.Append(const AValue: LongInt): TGenericStringBuilder;
 begin
 begin
   DoAppend(IntToStr(AValue));
   DoAppend(IntToStr(AValue));
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-Function TStringBuilder.Append(const AValue: TSBCharArray; StartIndex, SBCharCount: Integer): TStringBuilder;
+Function TGenericStringBuilder.Append(const AValue: TSBCharArray; StartIndex, SBCharCount: Integer): TGenericStringBuilder;
 
 
 begin
 begin
   DoAppend(AValue,StartIndex,SBCharCount);
   DoAppend(AValue,StartIndex,SBCharCount);
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-Function TStringBuilder.Append(const AValue: SBString; StartIndex, Count: Integer): TStringBuilder;
+Function TGenericStringBuilder.Append(const AValue: SBString; StartIndex, Count: Integer): TGenericStringBuilder;
 
 
 begin
 begin
   CheckRange(StartIndex,Count,System.Length(AValue));
   CheckRange(StartIndex,Count,System.Length(AValue));
@@ -281,21 +281,21 @@ begin
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.Append(const AValue: PSBChar): TStringBuilder;
+function TGenericStringBuilder.Append(const AValue: PSBChar): TGenericStringBuilder;
 begin
 begin
   DoAppend(AnsiString(AValue));
   DoAppend(AnsiString(AValue));
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
 {$IFDEF SBUNICODE}
 {$IFDEF SBUNICODE}
-function TStringBuilder.Append(const AValue: SBString): TStringBuilder;
+function TGenericStringBuilder.Append(const AValue: SBString): TGenericStringBuilder;
 begin
 begin
   DoAppend(AValue);
   DoAppend(AValue);
   Result:=Self;
   Result:=Self;
 end;
 end;
 {$ENDIF}
 {$ENDIF}
 
 
-function TStringBuilder.Append(const AValue: RawByteString): TStringBuilder;
+function TGenericStringBuilder.Append(const AValue: RawByteString): TGenericStringBuilder;
 begin
 begin
   {$IFDEF SBUNICODE}
   {$IFDEF SBUNICODE}
   DoAppend(SBString(AValue));
   DoAppend(SBString(AValue));
@@ -305,40 +305,40 @@ begin
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.AppendFormat(const Fmt: SBString;
-  const Args: array of const): TStringBuilder;
+function TGenericStringBuilder.AppendFormat(const Fmt: SBString;
+  const Args: array of const): TGenericStringBuilder;
 begin
 begin
   DoAppend(Format(Fmt,Args));
   DoAppend(Format(Fmt,Args));
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.Append(const Fmt: SBString;
-  const Args: array of const): TStringBuilder;
+function TGenericStringBuilder.Append(const Fmt: SBString;
+  const Args: array of const): TGenericStringBuilder;
 begin
 begin
   DoAppend(Format(Fmt,Args));
   DoAppend(Format(Fmt,Args));
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.AppendLine: TStringBuilder;
+function TGenericStringBuilder.AppendLine: TGenericStringBuilder;
 begin
 begin
   DoAppend(sLineBreak);
   DoAppend(sLineBreak);
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.AppendLine(const AValue: RawByteString): TStringBuilder;
+function TGenericStringBuilder.AppendLine(const AValue: RawByteString): TGenericStringBuilder;
 begin
 begin
   DoAppend(AValue);
   DoAppend(AValue);
   Result:=AppendLine();
   Result:=AppendLine();
 end;
 end;
 
 
-procedure TStringBuilder.Clear;
+procedure TGenericStringBuilder.Clear;
 begin
 begin
   Length:=0;
   Length:=0;
   Capacity:=DefaultCapacity;
   Capacity:=DefaultCapacity;
 end;
 end;
 
 
 
 
-procedure TStringBuilder.CopyTo(SourceIndex: Integer;
+procedure TGenericStringBuilder.CopyTo(SourceIndex: Integer;
   Var Destination: TSBCharArray; DestinationIndex: Integer; Count: Integer);
   Var Destination: TSBCharArray; DestinationIndex: Integer; Count: Integer);
 
 
 begin
 begin
@@ -353,7 +353,7 @@ begin
 end;
 end;
 
 
 
 
-function TStringBuilder.EnsureCapacity(aCapacity: Integer): Integer;
+function TGenericStringBuilder.EnsureCapacity(aCapacity: Integer): Integer;
 begin
 begin
   CheckRange(aCapacity,0,MaxCapacity);
   CheckRange(aCapacity,0,MaxCapacity);
   if Capacity<aCapacity then
   if Capacity<aCapacity then
@@ -361,7 +361,7 @@ begin
   Result:=Capacity;
   Result:=Capacity;
 end;
 end;
 
 
-function TStringBuilder.Equals(StringBuilder: TStringBuilder): Boolean;
+function TGenericStringBuilder.Equals(StringBuilder: TGenericStringBuilder): Boolean;
 begin
 begin
   Result:=(StringBuilder<>nil);
   Result:=(StringBuilder<>nil);
   if Result then
   if Result then
@@ -370,7 +370,7 @@ begin
              and CompareMem(@FData[0],@StringBuilder.FData[0],Length*SizeOf(SBChar));
              and CompareMem(@FData[0],@StringBuilder.FData[0],Length*SizeOf(SBChar));
 end;
 end;
 
 
-procedure TStringBuilder.Grow;
+procedure TGenericStringBuilder.Grow;
 
 
 var
 var
   NewCapacity: SizeInt;
   NewCapacity: SizeInt;
@@ -382,101 +382,101 @@ begin
   Capacity:=NewCapacity;
   Capacity:=NewCapacity;
 end;
 end;
 
 
-function TStringBuilder.Insert(Index: Integer; const AValue: TObject
-  ): TStringBuilder;
+function TGenericStringBuilder.Insert(Index: Integer; const AValue: TObject
+  ): TGenericStringBuilder;
 begin
 begin
   DoInsert(Index,AValue.ToString());
   DoInsert(Index,AValue.ToString());
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.Insert(Index: Integer; const AValue: Int64
-  ): TStringBuilder;
+function TGenericStringBuilder.Insert(Index: Integer; const AValue: Int64
+  ): TGenericStringBuilder;
 begin
 begin
   DoInsert(Index,IntToStr(AValue));
   DoInsert(Index,IntToStr(AValue));
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.Insert(Index: Integer; const AValue: Single
-  ): TStringBuilder;
+function TGenericStringBuilder.Insert(Index: Integer; const AValue: Single
+  ): TGenericStringBuilder;
 begin
 begin
   DoInsert(Index,FloatToStr(AValue));
   DoInsert(Index,FloatToStr(AValue));
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.Insert(Index: Integer; const AValue: SBString
-  ): TStringBuilder;
+function TGenericStringBuilder.Insert(Index: Integer; const AValue: SBString
+  ): TGenericStringBuilder;
 
 
 begin
 begin
   DoInsert(Index,AValue);
   DoInsert(Index,AValue);
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.Insert(Index: Integer; const AValue: Word
-  ): TStringBuilder;
+function TGenericStringBuilder.Insert(Index: Integer; const AValue: Word
+  ): TGenericStringBuilder;
 begin
 begin
   DoInsert(Index,IntToStr(AValue));
   DoInsert(Index,IntToStr(AValue));
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.Insert(Index: Integer; const AValue: Shortint
-  ): TStringBuilder;
+function TGenericStringBuilder.Insert(Index: Integer; const AValue: Shortint
+  ): TGenericStringBuilder;
 begin
 begin
   DoInsert(Index, IntToStr(AValue));
   DoInsert(Index, IntToStr(AValue));
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
 
 
-function TStringBuilder.Insert(Index: Integer; const AValue: Currency
-  ): TStringBuilder;
+function TGenericStringBuilder.Insert(Index: Integer; const AValue: Currency
+  ): TGenericStringBuilder;
 begin
 begin
   DoInsert(Index,CurrToStr(AValue));
   DoInsert(Index,CurrToStr(AValue));
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.Insert(Index: Integer; const AValue: SBChar
-  ): TStringBuilder;
+function TGenericStringBuilder.Insert(Index: Integer; const AValue: SBChar
+  ): TGenericStringBuilder;
 begin
 begin
   DoInsert(Index,AValue);
   DoInsert(Index,AValue);
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.Insert(Index: Integer; const AValue: Byte
-  ): TStringBuilder;
+function TGenericStringBuilder.Insert(Index: Integer; const AValue: Byte
+  ): TGenericStringBuilder;
 begin
 begin
   DoInsert(Index,IntToStr(AValue));
   DoInsert(Index,IntToStr(AValue));
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.Insert(Index: Integer; const AValue: Double
-  ): TStringBuilder;
+function TGenericStringBuilder.Insert(Index: Integer; const AValue: Double
+  ): TGenericStringBuilder;
 begin
 begin
   DoInsert(Index,FloatToStr(AValue));
   DoInsert(Index,FloatToStr(AValue));
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.Insert(Index: Integer; const AValue: LongInt
-  ): TStringBuilder;
+function TGenericStringBuilder.Insert(Index: Integer; const AValue: LongInt
+  ): TGenericStringBuilder;
 begin
 begin
   DoInsert(Index,IntToStr(AValue));
   DoInsert(Index,IntToStr(AValue));
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.Insert(Index: Integer; const AValue: Smallint
-  ): TStringBuilder;
+function TGenericStringBuilder.Insert(Index: Integer; const AValue: Smallint
+  ): TGenericStringBuilder;
 begin
 begin
   DoInsert(Index,IntToStr(AValue));
   DoInsert(Index,IntToStr(AValue));
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.Insert(Index: Integer; const AValue: Boolean
-  ): TStringBuilder;
+function TGenericStringBuilder.Insert(Index: Integer; const AValue: Boolean
+  ): TGenericStringBuilder;
 begin
 begin
   DoInsert(Index,BoolToStr(AValue,True));
   DoInsert(Index,BoolToStr(AValue,True));
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.Insert(Index: Integer; const AValue: SBString;
-  const aRepeatCount: Integer): TStringBuilder;
+function TGenericStringBuilder.Insert(Index: Integer; const AValue: SBString;
+  const aRepeatCount: Integer): TGenericStringBuilder;
 var
 var
   I: Integer;
   I: Integer;
 begin
 begin
@@ -485,43 +485,43 @@ begin
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.Insert(Index: Integer; const AValue: TSBCharArray
-  ): TStringBuilder;
+function TGenericStringBuilder.Insert(Index: Integer; const AValue: TSBCharArray
+  ): TGenericStringBuilder;
 begin
 begin
   DoInsert(Index,AValue,0,System.Length(AValue));
   DoInsert(Index,AValue,0,System.Length(AValue));
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.Insert(Index: Integer; const AValue: TSBCharArray;
-  startIndex: Integer; SBCharCount: Integer): TStringBuilder;
+function TGenericStringBuilder.Insert(Index: Integer; const AValue: TSBCharArray;
+  startIndex: Integer; SBCharCount: Integer): TGenericStringBuilder;
 begin
 begin
   DoInsert(Index,AValue,StartIndex,SBCharCount);
   DoInsert(Index,AValue,StartIndex,SBCharCount);
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-function TStringBuilder.Insert(Index: Integer; const AValue: Cardinal
-  ): TStringBuilder;
+function TGenericStringBuilder.Insert(Index: Integer; const AValue: Cardinal
+  ): TGenericStringBuilder;
 begin
 begin
   DoInsert(Index,IntToStr(AValue));
   DoInsert(Index,IntToStr(AValue));
   Result:=self;
   Result:=self;
 end;
 end;
 
 
-function TStringBuilder.Insert(Index: Integer; const AValue: UInt64
-  ): TStringBuilder;
+function TGenericStringBuilder.Insert(Index: Integer; const AValue: UInt64
+  ): TGenericStringBuilder;
 begin
 begin
   DoInsert(Index,IntToStr(AValue));
   DoInsert(Index,IntToStr(AValue));
   Result:=self;
   Result:=self;
 end;
 end;
 
 
-procedure TStringBuilder.Shrink;
+procedure TGenericStringBuilder.Shrink;
 
 
 begin
 begin
   if (Capacity div 4)>=Length then
   if (Capacity div 4)>=Length then
     Capacity:=Capacity div 2;
     Capacity:=Capacity div 2;
 end;
 end;
 
 
-function TStringBuilder.Remove(StartIndex: Integer; RemLength: Integer
-  ): TStringBuilder;
+function TGenericStringBuilder.Remove(StartIndex: Integer; RemLength: Integer
+  ): TGenericStringBuilder;
 
 
 Var
 Var
   MoveIndex : Integer;
   MoveIndex : Integer;
@@ -540,7 +540,7 @@ begin
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-Function TStringBuilder.Replace(const OldValue, NewValue: SBRawString; StartIndex, Count: Integer): TStringBuilder;
+Function TGenericStringBuilder.Replace(const OldValue, NewValue: SBRawString; StartIndex, Count: Integer): TGenericStringBuilder;
 
 
 var
 var
   Cur : PSBChar;
   Cur : PSBChar;
@@ -587,8 +587,8 @@ begin
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-Function TStringBuilder.Replace(const OldChar, NewChar: SBChar; StartIndex,
-  Count: Integer): TStringBuilder;
+Function TGenericStringBuilder.Replace(const OldChar, NewChar: SBChar; StartIndex,
+  Count: Integer): TGenericStringBuilder;
 var
 var
   I : Integer;
   I : Integer;
   Cur : PSBChar;
   Cur : PSBChar;
@@ -609,18 +609,18 @@ begin
   Result:=Self;
   Result:=Self;
 end;
 end;
 
 
-Function TStringBuilder.Replace(const OldChar, NewChar: SBChar): TStringBuilder;
+Function TGenericStringBuilder.Replace(const OldChar, NewChar: SBChar): TGenericStringBuilder;
 
 
 begin
 begin
   Result:=Replace(OldChar,NewChar,0,Length);
   Result:=Replace(OldChar,NewChar,0,Length);
 end;
 end;
 
 
-Function TStringBuilder.Replace(const OldValue, NewValue: SBRawString): TStringBuilder;
+Function TGenericStringBuilder.Replace(const OldValue, NewValue: SBRawString): TGenericStringBuilder;
 begin
 begin
   Result:=Replace(OldValue,NewValue,0,Length);
   Result:=Replace(OldValue,NewValue,0,Length);
 end;
 end;
 
 
-procedure TStringBuilder.SetCapacity(AValue: Integer);
+procedure TGenericStringBuilder.SetCapacity(AValue: Integer);
 begin
 begin
   if (AValue>FMaxCapacity) then
   if (AValue>FMaxCapacity) then
     Raise ERangeError.CreateFmt(SListCapacityError,[AValue]);
     Raise ERangeError.CreateFmt(SListCapacityError,[AValue]);
@@ -630,12 +630,12 @@ begin
 end;
 end;
 
 
 
 
-function TStringBuilder.ToString: SBString;
+function TGenericStringBuilder.ToString: SBString;
 begin
 begin
   Result:=ToString(0,Length);
   Result:=ToString(0,Length);
 end;
 end;
 
 
-function TStringBuilder.ToString(aStartIndex: Integer; aLength: Integer
+function TGenericStringBuilder.ToString(aStartIndex: Integer; aLength: Integer
   ): SBString;
   ): SBString;
 begin
 begin
   if (aLength=0) then
   if (aLength=0) then
@@ -650,7 +650,7 @@ begin
     end;
     end;
 end;
 end;
 
 
-procedure TStringBuilder.DoReplace(Index: Integer; const Old, New: SBString);
+procedure TGenericStringBuilder.DoReplace(Index: Integer; const Old, New: SBString);
 
 
 var
 var
   NVLen,OVLen,OLen,Delta,TailStart: Integer;
   NVLen,OVLen,OLen,Delta,TailStart: Integer;

+ 51 - 51
rtl/objpas/sysutils/syssbh.inc

@@ -1,7 +1,7 @@
 
 
-  { TStringBuilder }
+  { TGenericStringBuilder }
 
 
-  TStringBuilder = class
+  TGenericStringBuilder = class
   private
   private
     const
     const
       DefaultCapacity = 64;
       DefaultCapacity = 64;
@@ -36,66 +36,66 @@
     Constructor Create(const AValue: SBString; aCapacity: Integer);
     Constructor Create(const AValue: SBString; aCapacity: Integer);
     Constructor Create(const AValue: SBString; StartIndex: Integer; aLength: Integer; aCapacity: Integer);
     Constructor Create(const AValue: SBString; StartIndex: Integer; aLength: Integer; aCapacity: Integer);
 
 
-    Function Append(const AValue: Boolean): TStringBuilder;
-    Function Append(const AValue: Byte): TStringBuilder;
-    Function Append(const AValue: SBChar): TStringBuilder;
-    Function Append(const AValue: Currency): TStringBuilder;
-    Function Append(const AValue: Double): TStringBuilder;
-    Function Append(const AValue: Smallint): TStringBuilder;
-    Function Append(const AValue: LongInt): TStringBuilder;
-    Function Append(const AValue: Int64): TStringBuilder;
-    Function Append(const AValue: TObject): TStringBuilder;
-    Function Append(const AValue: Shortint): TStringBuilder;
-    Function Append(const AValue: Single): TStringBuilder;
-    Function Append(const AValue: UInt64): TStringBuilder;
-    Function Append(const AValue: TSBCharArray): TStringBuilder;
-    Function Append(const AValue: Word): TStringBuilder;
-    Function Append(const AValue: Cardinal): TStringBuilder;
-    Function Append(const AValue: PSBChar): TStringBuilder;
+    Function Append(const AValue: Boolean): TGenericStringBuilder;
+    Function Append(const AValue: Byte): TGenericStringBuilder;
+    Function Append(const AValue: SBChar): TGenericStringBuilder;
+    Function Append(const AValue: Currency): TGenericStringBuilder;
+    Function Append(const AValue: Double): TGenericStringBuilder;
+    Function Append(const AValue: Smallint): TGenericStringBuilder;
+    Function Append(const AValue: LongInt): TGenericStringBuilder;
+    Function Append(const AValue: Int64): TGenericStringBuilder;
+    Function Append(const AValue: TObject): TGenericStringBuilder;
+    Function Append(const AValue: Shortint): TGenericStringBuilder;
+    Function Append(const AValue: Single): TGenericStringBuilder;
+    Function Append(const AValue: UInt64): TGenericStringBuilder;
+    Function Append(const AValue: TSBCharArray): TGenericStringBuilder;
+    Function Append(const AValue: Word): TGenericStringBuilder;
+    Function Append(const AValue: Cardinal): TGenericStringBuilder;
+    Function Append(const AValue: PSBChar): TGenericStringBuilder;
 {$IFDEF SBUNICODE}
 {$IFDEF SBUNICODE}
     // Do not use SBRawstring, we need 2 versions in case of unicode
     // Do not use SBRawstring, we need 2 versions in case of unicode
-    Function Append(const AValue: SBString): TStringBuilder;
+    Function Append(const AValue: SBString): TGenericStringBuilder;
 {$ENDIF}
 {$ENDIF}
-    Function Append(const AValue: RawByteString): TStringBuilder;
-    Function Append(const AValue: SBChar; RepeatCount: Integer): TStringBuilder;
-    Function Append(const AValue: TSBCharArray; StartIndex: Integer; SBCharCount: Integer): TStringBuilder;
-    Function Append(const AValue: SBString; StartIndex: Integer; Count: Integer): TStringBuilder;
+    Function Append(const AValue: RawByteString): TGenericStringBuilder;
+    Function Append(const AValue: SBChar; RepeatCount: Integer): TGenericStringBuilder;
+    Function Append(const AValue: TSBCharArray; StartIndex: Integer; SBCharCount: Integer): TGenericStringBuilder;
+    Function Append(const AValue: SBString; StartIndex: Integer; Count: Integer): TGenericStringBuilder;
 
 
-    Function Append(const Fmt: SBString; const Args: array of const): TStringBuilder;
-    Function AppendFormat(const Fmt: SBString; const Args: array of const): TStringBuilder;
-    Function AppendLine: TStringBuilder;
-    Function AppendLine(const AValue: RawByteString): TStringBuilder;
+    Function Append(const Fmt: SBString; const Args: array of const): TGenericStringBuilder;
+    Function AppendFormat(const Fmt: SBString; const Args: array of const): TGenericStringBuilder;
+    Function AppendLine: TGenericStringBuilder;
+    Function AppendLine(const AValue: RawByteString): TGenericStringBuilder;
 
 
     Procedure Clear;
     Procedure Clear;
     Procedure CopyTo(SourceIndex: Integer; Var Destination: TSBCharArray; DestinationIndex: Integer; Count: Integer);
     Procedure CopyTo(SourceIndex: Integer; Var Destination: TSBCharArray; DestinationIndex: Integer; Count: Integer);
     Function EnsureCapacity(aCapacity: Integer): Integer;
     Function EnsureCapacity(aCapacity: Integer): Integer;
-    Function Equals(StringBuilder: TStringBuilder): Boolean; reintroduce;
+    Function Equals(StringBuilder: TGenericStringBuilder): Boolean; reintroduce;
 
 
-    Function Insert(Index: Integer; const AValue: Boolean): TStringBuilder;
-    Function Insert(Index: Integer; const AValue: Byte): TStringBuilder;
-    Function Insert(Index: Integer; const AValue: SBChar): TStringBuilder;
-    Function Insert(Index: Integer; const AValue: Currency): TStringBuilder;
-    Function Insert(Index: Integer; const AValue: Double): TStringBuilder;
-    Function Insert(Index: Integer; const AValue: Smallint): TStringBuilder;
-    Function Insert(Index: Integer; const AValue: LongInt): TStringBuilder;
-    Function Insert(Index: Integer; const AValue: TSBCharArray): TStringBuilder;
-    Function Insert(Index: Integer; const AValue: Int64): TStringBuilder;
-    Function Insert(Index: Integer; const AValue: TObject): TStringBuilder;
-    Function Insert(Index: Integer; const AValue: Shortint): TStringBuilder;
-    Function Insert(Index: Integer; const AValue: Single): TStringBuilder;
-    Function Insert(Index: Integer; const AValue: SBString): TStringBuilder;
-    Function Insert(Index: Integer; const AValue: Word): TStringBuilder;
-    Function Insert(Index: Integer; const AValue: Cardinal): TStringBuilder;
-    Function Insert(Index: Integer; const AValue: UInt64): TStringBuilder;
-    Function Insert(Index: Integer; const AValue: SBString; const aRepeatCount: Integer): TStringBuilder;
-    Function Insert(Index: Integer; const AValue: TSBCharArray; startIndex: Integer; SBCharCount: Integer): TStringBuilder;
+    Function Insert(Index: Integer; const AValue: Boolean): TGenericStringBuilder;
+    Function Insert(Index: Integer; const AValue: Byte): TGenericStringBuilder;
+    Function Insert(Index: Integer; const AValue: SBChar): TGenericStringBuilder;
+    Function Insert(Index: Integer; const AValue: Currency): TGenericStringBuilder;
+    Function Insert(Index: Integer; const AValue: Double): TGenericStringBuilder;
+    Function Insert(Index: Integer; const AValue: Smallint): TGenericStringBuilder;
+    Function Insert(Index: Integer; const AValue: LongInt): TGenericStringBuilder;
+    Function Insert(Index: Integer; const AValue: TSBCharArray): TGenericStringBuilder;
+    Function Insert(Index: Integer; const AValue: Int64): TGenericStringBuilder;
+    Function Insert(Index: Integer; const AValue: TObject): TGenericStringBuilder;
+    Function Insert(Index: Integer; const AValue: Shortint): TGenericStringBuilder;
+    Function Insert(Index: Integer; const AValue: Single): TGenericStringBuilder;
+    Function Insert(Index: Integer; const AValue: SBString): TGenericStringBuilder;
+    Function Insert(Index: Integer; const AValue: Word): TGenericStringBuilder;
+    Function Insert(Index: Integer; const AValue: Cardinal): TGenericStringBuilder;
+    Function Insert(Index: Integer; const AValue: UInt64): TGenericStringBuilder;
+    Function Insert(Index: Integer; const AValue: SBString; const aRepeatCount: Integer): TGenericStringBuilder;
+    Function Insert(Index: Integer; const AValue: TSBCharArray; startIndex: Integer; SBCharCount: Integer): TGenericStringBuilder;
 
 
-    Function Remove(StartIndex: Integer; RemLength: Integer): TStringBuilder;
+    Function Remove(StartIndex: Integer; RemLength: Integer): TGenericStringBuilder;
 
 
-    Function Replace(const OldChar, NewChar: SBChar): TStringBuilder;
-    Function Replace(const OldChar, NewChar: SBChar; StartIndex: Integer; Count: Integer): TStringBuilder;
-    Function Replace(const OldValue, NewValue: SBRawString): TStringBuilder;
-    Function Replace(const OldValue, NewValue: SBRawString; StartIndex: Integer; Count: Integer): TStringBuilder;
+    Function Replace(const OldChar, NewChar: SBChar): TGenericStringBuilder;
+    Function Replace(const OldChar, NewChar: SBChar; StartIndex: Integer; Count: Integer): TGenericStringBuilder;
+    Function Replace(const OldValue, NewValue: SBRawString): TGenericStringBuilder;
+    Function Replace(const OldValue, NewValue: SBRawString; StartIndex: Integer; Count: Integer): TGenericStringBuilder;
 {$IFDEF SBUNICODE}
 {$IFDEF SBUNICODE}
     Function ToString: SBString;
     Function ToString: SBString;
 {$ELSE}
 {$ELSE}

+ 4 - 4
rtl/objpas/sysutils/sysstr.inc

@@ -2805,7 +2805,7 @@ function sscanf(const s: string; const fmt : string;const Pointers : array of Po
 {$define TSBCharArray:=Array of SBChar}
 {$define TSBCharArray:=Array of SBChar}
 {$define PSBChar:=PAnsiChar}
 {$define PSBChar:=PAnsiChar}
 {$define SBRAWString:=RawByteString}
 {$define SBRAWString:=RawByteString}
-{$define TStringBuilder:=TAnsiStringBuilder}
+{$define TGenericStringBuilder:=TAnsiStringBuilder}
 
 
 {$i syssb.inc}
 {$i syssb.inc}
 {$undef SBChar}
 {$undef SBChar}
@@ -2813,7 +2813,7 @@ function sscanf(const s: string; const fmt : string;const Pointers : array of Po
 {$undef TSBCharArray}
 {$undef TSBCharArray}
 {$undef PSBChar}
 {$undef PSBChar}
 {$undef SBRAWString}
 {$undef SBRAWString}
-{$undef TStringBuilder}
+{$undef TGenericStringBuilder}
 
 
 // Unicode version declaration
 // Unicode version declaration
 
 
@@ -2823,14 +2823,14 @@ function sscanf(const s: string; const fmt : string;const Pointers : array of Po
 {$define TSBCharArray:=Array of SBChar}
 {$define TSBCharArray:=Array of SBChar}
 {$define PSBChar:=PWideChar}
 {$define PSBChar:=PWideChar}
 {$define SBRAWString:=UnicodeString}
 {$define SBRAWString:=UnicodeString}
-{$define TStringBuilder:=TUnicodeStringBuilder}
+{$define TGenericStringBuilder:=TUnicodeStringBuilder}
 {$i syssb.inc}
 {$i syssb.inc}
 {$undef SBChar}
 {$undef SBChar}
 {$undef SBString}
 {$undef SBString}
 {$undef TSBCharArray}
 {$undef TSBCharArray}
 {$undef PSBChar}
 {$undef PSBChar}
 {$undef SBRAWString}
 {$undef SBRAWString}
-{$undef TStringBuilder}
+{$undef TGenericStringBuilder}
 {$undef SBUNICODE}
 {$undef SBUNICODE}
 
 
 
 

+ 4 - 4
rtl/objpas/sysutils/sysstrh.inc

@@ -307,7 +307,7 @@ Type
 {$define TSBCharArray:=Array of SBChar}
 {$define TSBCharArray:=Array of SBChar}
 {$define PSBChar:=PAnsiChar}
 {$define PSBChar:=PAnsiChar}
 {$define SBRAWString:=RawByteString}
 {$define SBRAWString:=RawByteString}
-{$define TStringBuilder:=TAnsiStringBuilder}
+{$define TGenericStringBuilder:=TAnsiStringBuilder}
 
 
 {$i syssbh.inc}
 {$i syssbh.inc}
 {$undef SBChar}
 {$undef SBChar}
@@ -315,7 +315,7 @@ Type
 {$undef TSBCharArray}
 {$undef TSBCharArray}
 {$undef PSBChar}
 {$undef PSBChar}
 {$undef SBRAWString}
 {$undef SBRAWString}
-{$undef TStringBuilder}
+{$undef TGenericStringBuilder}
 
 
 // Unicode version implementation
 // Unicode version implementation
 
 
@@ -325,14 +325,14 @@ Type
 {$define TSBCharArray:=Array of SBChar}
 {$define TSBCharArray:=Array of SBChar}
 {$define PSBChar:=PWideChar}
 {$define PSBChar:=PWideChar}
 {$define SBRAWString:=UnicodeString}
 {$define SBRAWString:=UnicodeString}
-{$define TStringBuilder:=TUnicodeStringBuilder}
+{$define TGenericStringBuilder:=TUnicodeStringBuilder}
 {$i syssbh.inc}
 {$i syssbh.inc}
 {$undef SBChar}
 {$undef SBChar}
 {$undef SBString}
 {$undef SBString}
 {$undef TSBCharArray}
 {$undef TSBCharArray}
 {$undef PSBChar}
 {$undef PSBChar}
 {$undef SBRAWString}
 {$undef SBRAWString}
-{$undef TStringBuilder}
+{$undef TGenericStringBuilder}
 {$undef SBUNICODE}
 {$undef SBUNICODE}
 
 
 Type
 Type

+ 926 - 0
rtl/objpas/sysutils/tzenv.inc

@@ -0,0 +1,926 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2020 by Tomas Hajny,
+    member of the Free Pascal development team.
+
+    Support routines for calculation of local timezone and DST time
+    offset based on information provided in the environment variable TZ.
+
+    There are various ways for specifying the timezone details using the
+    TZ variable. The more information is provided, the better results.
+    As an example, the following setting provides full information
+    including details for DST on/off switching date and time:
+    TZ=CET-1CEST,3,-1,0,7200,10,-1,0,10800,3600
+    (CET timezone is 1 hour in advance from UTC, there is DST called CEST,
+    DST starts on the last Sunday of March at 2am and finishes on the last
+    Sunday of October at 3am, the DST difference is 1 hour).
+    However, this is by no means the only supported syntax.
+
+    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.
+
+ **********************************************************************}
+
+
+type
+ DSTSpecType = (DSTMonthWeekDay, DSTMonthDay, DSTJulian, DSTJulianX);
+
+const
+  TZEnvName = 'TZ';
+{$IFDEF OS2}
+  EMXTZEnvName = 'EMXTZ';
+{$ENDIF OS2}
+  MaxSecond = 86399;
+(* The following values differing from the defaults *)
+(* below are not used at the moment. *)
+  USDSTStartMonth = 3;
+  USDSTStartWeek = 2;
+  USDSTEndMonth = 11;
+  USDSTEndWeek = 1;
+  EUDSTStartMonth = 3;
+  EUDSTStartWeek = -1;
+(* Initialized to default values, updated after a call to InitTZ *)
+  TZName: string = '';
+  TZDSTName: string = '';
+  TZOffset: longint = 0;
+  TZOffsetMin: longint = 0;
+  DSTOffset: longint = 0;
+  DSTOffsetMin: longint = 0;
+  DSTStartMonth: byte = 4;
+  DSTStartWeek: shortint = 1;
+  DSTStartDay: word = 0;
+  DSTStartSec: cardinal = 7200;
+  DSTEndMonth: byte = 10;
+  DSTEndWeek: shortint = -1;
+  DSTEndDay: word = 0;
+  DSTEndSec: cardinal = 10800;
+  DSTStartSpecType: DSTSpecType = DSTMonthWeekDay;
+  DSTEndSpecType: DSTSpecType = DSTMonthWeekDay;
+
+(* The following variables are initialized after a call to InitTZ. *)
+var
+  RealDSTStartMonth, RealDSTStartDay, RealDSTEndMonth, RealDSTEndDay: byte;
+
+const
+  MonthEnds: array [1..12] of word =
+                     (31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365);
+
+
+function LeapDay (Year: word): byte; inline;
+begin
+  if IsLeapYear (Year) then
+   LeapDay := 1
+  else
+   LeapDay := 0;
+end;
+
+
+function FirstDay (MM: byte; Y: word; Mo: word; D: word; WD: word): byte;
+                                                                        inline;
+var
+  DD: longint;
+begin
+  if MM < Mo then
+   begin
+    DD := D + MonthEnds [Pred (Mo)];
+    if MM > 1 then
+     Dec (DD, MonthEnds [Pred (MM)]);
+    if (MM <= 2) and (Mo > 2) then
+     Inc (DD, LeapDay (Y));
+   end
+  else
+   if MM > Mo then
+    begin
+     DD := - MonthDays [false, Mo] + D - MonthEnds [Pred (MM)]
+                                                              + MonthEnds [Mo];
+     if (Mo <= 2) and (MM > 2) then
+      Dec (DD, LeapDay (Y));
+    end
+   else
+(* M = MM *)
+    DD := D;
+  DD := WD - DD mod 7 + 1;
+  if DD < 0 then
+   FirstDay := DD + 7
+  else
+   FirstDay := DD mod 7;
+end;
+
+
+procedure UpdateTimeWithOffset (var SystemTime: TSystemTime; Offset: longint);
+                                                                        inline;
+var
+  Y: longint;
+  Mo: longint;
+  D: longint;
+  WD: word;
+  H: longint;
+  Mi: longint;
+begin
+  with SystemTime do
+   begin
+    Y := Year;
+    Mo := Month;
+    D := Day;
+    WD := DayOfWeek;
+    H := Hour;
+    Mi := Minute;
+   end;
+  Mi := Mi + (Offset mod 60);
+  H := H + (Offset div 60);
+  if Mi < 0 then
+   begin
+    Inc (Mi, 60);
+    Dec (H);
+   end;
+  if H < 0 then
+   begin
+    Inc (H, 24);
+    if WD = 0 then
+     WD := 6
+    else
+     Dec (WD);
+    if D = 1 then
+     begin
+      if Mo = 1 then
+       begin
+        Dec (Y);
+        Mo := 12;
+       end
+      else
+       Dec (Mo);
+      D := MonthDays [IsLeapYear (Y), Mo];
+     end
+    else
+     Dec (D);
+   end
+  else
+   begin
+    if Mi > 59 then
+     begin
+      Dec (Mi, 60);
+      Inc (H);
+     end;
+    if H > 23 then
+     begin
+      Dec (H, 24);
+      if WD = 6 then
+       WD := 0
+      else
+       Inc (WD);
+      if D = MonthDays [IsLeapYear (Y), Mo] then
+       begin
+        D := 1;
+        if Mo = 12 then
+         begin
+          Inc (Y);
+          Mo := 1;
+         end
+        else
+         Inc (Mo);
+       end
+      else
+       Inc (D);
+     end;
+   end;
+  with SystemTime do
+   begin
+    Year := Y;
+    Month := Mo;
+    Day := D;
+    DayOfWeek := WD;
+    Hour := H;
+    Minute := Mi;
+   end;
+end;
+
+
+function InDST (const Time: TSystemTime; const InputIsUTC: boolean): boolean;
+var
+  AfterDSTStart, BeforeDSTEnd: boolean;
+  Y: longint;
+  Mo: longint;
+  D: longint;
+  WD: longint;
+  Second: longint;
+begin
+ InDST := false;
+ if DSTOffset <> TZOffset then
+  begin
+   Second := longint (Time.Hour) * 3600 + Time.Minute * 60 + Time.Second;
+   Y := Time.Year;
+   Mo := Time.Month;
+   D := Time.Day;
+   if InputIsUTC and (TZOffset <> 0) then
+    begin
+     Second := Second - TZOffset;
+     if Second < 0 then
+      begin
+       Second := Second + MaxSecond + 1;
+       if D = 1 then
+        begin
+         if Mo = 1 then
+          begin
+           Dec (Y);
+           Mo := 12;
+          end
+         else
+          Dec (Mo);
+         D := MonthDays [IsLeapYear (Y), Mo];
+        end
+       else
+        Dec (D);
+      end
+     else
+      if Second > MaxSecond then
+       begin
+        Second := Second - MaxSecond - 1;
+        if D = MonthDays [IsLeapYear (Y), Mo] then
+         begin
+          D := 1;
+          if Mo = 12 then
+           begin
+            Inc (Y);
+            Mo := 1;
+           end
+          else
+           Inc (Mo);
+         end
+        else
+         Inc (D);
+       end;
+    end;
+   if Mo < RealDSTStartMonth then
+    AfterDSTStart := false
+   else
+    if Mo > RealDSTStartMonth then
+     AfterDSTStart := true
+    else
+     if D < RealDSTStartDay then
+      AfterDSTStart := false
+     else
+      if D > RealDSTStartDay then
+       AfterDSTStart := true
+      else
+       AfterDSTStart := Second > DSTStartSec;
+   if Mo > RealDSTEndMonth then
+    BeforeDSTEnd := false
+   else
+    if Mo < RealDSTEndMonth then
+     BeforeDSTEnd := true
+    else
+     if D > RealDSTEndDay then
+      BeforeDSTEnd := false
+     else
+      if D < RealDSTEndDay then
+       BeforeDSTEnd := true
+      else
+       BeforeDSTEnd := Second < DSTEndSec;
+   InDST := AfterDSTStart and BeforeDSTEnd;
+  end;
+end;
+
+
+function InDST: boolean; inline;
+var
+  SystemTime: TSystemTime;
+begin
+ InDST := false;
+ if DSTOffset <> TZOffset then
+  begin
+   GetLocalTime (SystemTime);
+   InDST := InDST (SystemTime, false);
+  end;
+end;
+
+
+procedure InitTZ0; inline;
+var
+  TZ, S: string;
+  I, J: byte;
+  Err: longint;
+  GnuFmt: boolean;
+  ADSTStartMonth: byte;
+  ADSTStartWeek: shortint;
+  ADSTStartDay: word;
+  ADSTStartSec: cardinal;
+  ADSTEndMonth: byte;
+  ADSTEndWeek: shortint;
+  ADSTEndDay: word;
+  ADSTEndSec: cardinal;
+  ADSTStartSpecType: DSTSpecType;
+  ADSTEndSpecType: DSTSpecType;
+  ADSTChangeSec: cardinal;
+
+  function ParseOffset (OffStr: string): longint;
+  (* Parse time offset given as [-|+]HH[:MI[:SS]] and return in seconds *)
+  var
+    TZShiftHH, TZShiftDir: shortint;
+    TZShiftMI, TZShiftSS: byte;
+    N1, N2: byte;
+  begin
+    TZShiftHH := 0;
+    TZShiftMI := 0;
+    TZShiftSS := 0;
+    TZShiftDir := 1;
+    N1 := 1;
+    while (N1 <= Length (OffStr)) and (OffStr [N1] <> ':') do
+     Inc (N1);
+    Val (Copy (OffStr, 1, Pred (N1)), TZShiftHH, Err);
+    if (Err = 0) and (TZShiftHH >= -24) and (TZShiftHH <= 23) then
+     begin
+(* Normalize the hour offset to -12..11 if necessary *)
+      if TZShiftHH > 11 then
+       Dec (TZShiftHH, 24) else
+      if TZShiftHH < -12 then
+       Inc (TZShiftHH, 24);
+      if TZShiftHH < 0 then
+       TZShiftDir := -1;
+      if (N1 <= Length (OffStr)) then
+       begin
+        N2 := Succ (N1);
+        while (N2 <= Length (OffStr)) and (OffStr [N2] <> ':') do
+         Inc (N2);
+        Val (Copy (OffStr, Succ (N1), N2 - N1), TZShiftMI, Err);
+         if (Err = 0) and (TZShiftMI <= 59) then
+          begin
+           if (N2 <= Length (OffStr)) then
+            begin
+             Val (Copy (OffStr, Succ (N2), Length (OffStr) - N2), TZShiftSS, Err);
+             if (Err <> 0) or (TZShiftSS > 59) then
+              TZShiftSS := 0;
+            end
+          end
+         else
+          TZShiftMI := 0;
+       end;
+     end
+    else
+     TZShiftHH := 0;
+    ParseOffset := longint (TZShiftHH) * 3600 +
+                           TZShiftDir * (longint (TZShiftMI) * 60 + TZShiftSS);
+  end;
+
+begin
+  TZ := GetEnvironmentVariable (TZEnvName);
+{$IFDEF OS2}
+  if TZ = '' then
+   TZ := GetEnvironmentVariable (EMXTZEnvName);
+{$ENDIF OS2}
+  if TZ <> '' then
+   begin
+    TZ := Upcase (TZ);
+(* Timezone name *)
+    I := 1;
+    while (I <= Length (TZ)) and (TZ [I] in ['A'..'Z']) do
+     Inc (I);
+    TZName := Copy (TZ, 1, Pred (I));
+    if I <= Length (TZ) then
+     begin
+(* Timezone shift *)
+      J := Succ (I);
+      while (J <= Length (TZ)) and not (TZ [J] in ['A'..'Z']) do
+       Inc (J);
+      TZOffset := ParseOffset (Copy (TZ, I, J - I));
+(* DST timezone name *)
+      I := J;
+      while (J <= Length (TZ)) and (TZ [J] in ['A'..'Z']) do
+       Inc (J);
+      if J > I then
+       begin
+        TZDSTName := Copy (TZ, I, J - I);
+(* DST timezone name provided; if equal to the standard timezone  *)
+(* name then DSTOffset is set to be equal to TZOffset by default, *)
+(* otherwise it is set to TZOffset - 3600 seconds.                *)
+        if TZDSTName <> TZName then
+         DSTOffset := -3600 + TZOffset
+        else
+         DSTOffset := TZOffset;
+       end
+      else
+       begin
+        TZDSTName := TZName;
+(* No DST timezone name provided => DSTOffset is equal to TZOffset *)
+        DSTOffset := TZOffset;
+       end;
+      if J <= Length (TZ) then
+       begin
+(* Check if DST offset is specified here;   *)
+(* if not, default value set above is used. *)
+        if TZ [J] <> ',' then
+         begin
+          I := J;
+          Inc (J);
+          while (J <= Length (TZ)) and (TZ [J] <> ',') do
+           Inc (J);
+          DSTOffset := ParseOffset (Copy (TZ, I, J - I));
+         end;
+        if J < Length (TZ) then
+         begin
+          Inc (J);
+(* DST switching details *)
+          case TZ [J] of
+           'M':
+            begin
+(* Mmonth.week.dayofweek[/StartHour] *)
+             ADSTStartSpecType := DSTMonthWeekDay;
+             if J >= Length (TZ) then
+              Exit;
+             Inc (J);
+             I := J;
+             while (J <= Length (TZ)) and not (TZ [J] in ['.', ',', '/']) do
+              Inc (J);
+             if (J >= Length (TZ)) or (TZ [J] <> '.') then
+              Exit;
+             Val (Copy (TZ, I, J - I), ADSTStartMonth, Err);
+             if (Err > 0) or (ADSTStartMonth > 12) then
+              Exit;
+             Inc (J);
+             I := J;
+             while (J <= Length (TZ)) and not (TZ [J] in ['.', ',', '/']) do
+              Inc (J);
+             if (J >= Length (TZ)) or (TZ [J] <> '.') then
+              Exit;
+             Val (Copy (TZ, I, J - I), ADSTStartWeek, Err);
+             if (Err > 0) or (ADSTStartWeek < 1) or (ADSTStartWeek > 5) then
+              Exit;
+             Inc (J);
+             I := J;
+             while (J <= Length (TZ)) and not (TZ [J] in [',', '/']) do
+              Inc (J);
+             Val (Copy (TZ, I, J - I), ADSTStartDay, Err);
+             if (Err > 0) or (ADSTStartDay > 6) or (J >= Length (TZ)) then
+              Exit;
+             if TZ [J] = '/' then
+              begin
+               Inc (J);
+               I := J;
+               while (J <= Length (TZ)) and (TZ [J] <> ',') do
+                Inc (J);
+               Val (Copy (TZ, I, J - I), ADSTStartSec, Err);
+               if (Err > 0) or (ADSTStartSec > MaxSecond) or (J >= Length (TZ))
+                                                                           then
+                Exit
+               else
+                ADSTStartSec := ADSTStartSec * 3600;
+              end
+             else
+              (* Use the preset default *)
+              ADSTStartSec := DSTStartSec;
+             Inc (J);
+            end;
+           'J':
+            begin
+(* Jjulianday[/StartHour] *)
+             ADSTStartSpecType := DSTJulianX;
+             if J >= Length (TZ) then
+              Exit;
+             Inc (J);
+             I := J;
+             while (J <= Length (TZ)) and not (TZ [J] in [',', '/']) do
+              Inc (J);
+             Val (Copy (TZ, I, J - I), ADSTStartDay, Err);
+             if (Err > 0) or (ADSTStartDay = 0) or (ADSTStartDay > 365)
+                                                     or (J >= Length (TZ)) then
+              Exit;
+             if TZ [J] = '/' then
+              begin
+               Inc (J);
+               I := J;
+               while (J <= Length (TZ)) and (TZ [J] <> ',') do
+                Inc (J);
+               Val (Copy (TZ, I, J - I), ADSTStartSec, Err);
+               if (Err > 0) or (ADSTStartSec > MaxSecond) or (J >= Length (TZ))
+                                                                           then
+                Exit
+               else
+                ADSTStartSec := ADSTStartSec * 3600;
+              end
+             else
+              (* Use the preset default *)
+              ADSTStartSec := DSTStartSec;
+             Inc (J);
+            end
+          else
+           begin
+(* Check the used format first - GNU libc / GCC / EMX expect                 *)
+(* "NameOffsetDstname[Dstoffset],Start[/StartHour],End[/EndHour]";           *)
+(* if more than one comma (',') is found, the following format is assumed:   *)
+(* "NameOffsetDstname[Dstoffset],StartMonth,StartWeek,StartDay,StartSecond,  *)
+(*                         EndMonth,EndWeek,EndDay,EndSecond,DSTDifference". *)
+            I := J;
+            while (J <= Length (TZ)) and (TZ [J] <> ',') do
+             Inc (J);
+            S := Copy (TZ, I, J - I);
+            if J < Length (TZ) then
+             begin
+              Inc (J);
+              I := J;
+              while (J <= Length (TZ)) and (TZ [J] <> ',') do
+               Inc (J);
+              GnuFmt := J > Length (TZ);
+             end
+            else
+             Exit;
+            if GnuFmt then
+             begin
+              ADSTStartSpecType := DSTJulian;
+              J := Pos ('/', S);
+              if J = 0 then
+               begin
+                Val (S, ADSTStartDay, Err);
+                if (Err > 0) or (ADSTStartDay > 365) then
+                 Exit;
+                (* Use the preset default *)
+                ADSTStartSec := DSTStartSec;
+               end
+              else
+               begin
+                if J = Length (S) then
+                 Exit;
+                Val (Copy (S, 1, Pred (J)), ADSTStartDay, Err);
+                if (Err > 0) or (ADSTStartDay > 365) then
+                 Exit;
+                Val (Copy (S, Succ (J), Length (S) - J), ADSTStartSec, Err);
+                if (Err > 0) or (ADSTStartSec > MaxSecond) then
+                 Exit
+                else
+                 ADSTStartSec := ADSTStartSec * 3600;
+               end;
+              J := I;
+             end
+            else
+             begin
+              Val (S, ADSTStartMonth, Err);
+              if (Err > 0) or (ADSTStartMonth > 12) then
+               Exit;
+              Val (Copy (TZ, I, J - I), ADSTStartWeek, Err);
+              if (Err > 0) or (ADSTStartWeek < -1) or (ADSTStartWeek > 5) or
+                                                        (J >= Length (TZ)) then
+               Exit;
+              Inc (J);
+              I := J;
+              while (J <= Length (TZ)) and (TZ [J] <> ',') do
+               Inc (J);
+              Val (Copy (TZ, I, J - I), ADSTStartDay, Err);
+              if (DSTStartWeek = 0) then
+               begin
+                if (Err > 0) or (ADSTStartDay < 1) or (ADSTStartDay > 31)
+                  or (ADSTStartDay > 30) and (ADSTStartMonth in [4, 6, 9, 11])
+                           or (ADSTStartMonth = 2) and (ADSTStartDay > 29) then
+                 Exit;
+                ADSTStartSpecType := DSTMonthDay;
+               end
+              else
+               begin
+                if (Err > 0) or (ADSTStartDay > 6) then
+                 Exit;
+                ADSTStartSpecType := DSTMonthWeekDay;
+               end;
+              if J >= Length (TZ) then
+               Exit;
+              Inc (J);
+              I := J;
+              while (J <= Length (TZ)) and (TZ [J] <> ',') do
+               Inc (J);
+              Val (Copy (TZ, I, J - I), ADSTStartSec, Err);
+              if (Err > 0) or (ADSTStartSec > MaxSecond) or
+                                                        (J >= Length (TZ)) then
+               Exit;
+              Inc (J);
+              I := J;
+              while (J <= Length (TZ)) and (TZ [J] <> ',') do
+               Inc (J);
+              Val (Copy (TZ, I, J - I), ADSTEndMonth, Err);
+              if (Err > 0) or (ADSTEndMonth > 12) or (J >= Length (TZ)) then
+               Exit;
+              Inc (J);
+              I := J;
+              while (J <= Length (TZ)) and (TZ [J] <> ',') do
+               Inc (J);
+              Val (Copy (TZ, I, J - I), ADSTEndWeek, Err);
+              if (Err > 0) or (ADSTEndWeek < -1) or (ADSTEndWeek > 5)
+                                                     or (J >= Length (TZ)) then
+               Exit;
+              Inc (J);
+              I := J;
+              while (J <= Length (TZ)) and (TZ [J] <> ',') do
+               Inc (J);
+              Val (Copy (TZ, I, J - I), ADSTEndDay, Err);
+              if (DSTEndWeek = 0) then
+               begin
+                if (Err > 0) or (ADSTEndDay < 1) or (ADSTEndDay > 31)
+                   or (ADSTEndDay > 30) and (ADSTEndMonth in [4, 6, 9, 11])
+                               or (ADSTEndMonth = 2) and (ADSTEndDay > 29) then
+                 Exit;
+                ADSTEndSpecType := DSTMonthDay;
+               end
+              else
+               begin
+                if (Err > 0) or (ADSTEndDay > 6) then
+                 Exit;
+                ADSTEndSpecType := DSTMonthWeekDay;
+               end;
+              if J >= Length (TZ) then
+               Exit;
+              Inc (J);
+              I := J;
+              while (J <= Length (TZ)) and (TZ [J] <> ',') do
+               Inc (J);
+              Val (Copy (TZ, I, J - I), ADSTEndSec, Err);
+              if (Err > 0) or (ADSTEndSec > MaxSecond) or
+                                                        (J >= Length (TZ)) then
+               Exit;
+              Val (Copy (TZ, Succ (J), Length (TZ) - J), ADSTChangeSec, Err);
+              if (Err = 0) and (ADSTChangeSec < 86400) then
+               begin
+(* Format complete, all checks successful => accept the parsed values. *)
+                DSTStartMonth := ADSTStartMonth;
+                DSTStartWeek := ADSTStartWeek;
+                DSTStartDay := ADSTStartDay;
+                DSTStartSec := ADSTStartSec;
+                DSTEndMonth := ADSTEndMonth;
+                DSTEndWeek := ADSTEndWeek;
+                DSTEndDay := ADSTEndDay;
+                DSTEndSec := ADSTEndSec;
+                DSTStartSpecType := ADSTStartSpecType;
+                DSTEndSpecType := ADSTEndSpecType;
+                DSTOffset := TZOffset - ADSTChangeSec;
+               end;
+(* Parsing finished *)
+              Exit;
+             end;
+           end;
+          end;
+(* GnuFmt - DST end specification *)
+          if TZ [J] = 'M' then
+           begin
+(* Mmonth.week.dayofweek *)
+            ADSTEndSpecType := DSTMonthWeekDay;
+            if J >= Length (TZ) then
+             Exit;
+            Inc (J);
+            I := J;
+            while (J <= Length (TZ)) and not (TZ [J] in ['.', ',', '/']) do
+             Inc (J);
+            if (J >= Length (TZ)) or (TZ [J] <> '.') then
+             Exit;
+            Val (Copy (TZ, I, J - I), ADSTEndMonth, Err);
+            if (Err > 0) or (ADSTEndMonth > 12) then
+             Exit;
+            Inc (J);
+            I := J;
+            while (J <= Length (TZ)) and not (TZ [J] in ['.', ',', '/']) do
+             Inc (J);
+            if (J >= Length (TZ)) or (TZ [J] <> '.') then
+             Exit;
+            Val (Copy (TZ, I, J - I), ADSTEndWeek, Err);
+            if (Err > 0) or (ADSTEndWeek < 1) or (ADSTEndWeek > 5) then
+             Exit;
+            Inc (J);
+            I := J;
+            while (J <= Length (TZ)) and (TZ [J] <> '/') do
+             Inc (J);
+            Val (Copy (TZ, I, J - I), ADSTEndDay, Err);
+            if (Err > 0) or (ADSTEndDay > 6) then
+             Exit;
+           end
+          else
+           begin
+            if TZ [J] = 'J' then
+             begin
+(* Jjulianday *)
+              if J = Length (TZ) then
+               Exit;
+              Inc (J);
+              ADSTEndSpecType := DSTJulianX
+             end
+            else
+             ADSTEndSpecType := DSTJulian;
+            if J >= Length (TZ) then
+             Exit;
+            Inc (J);
+            I := J;
+            while (J <= Length (TZ)) and (TZ [J] <> '/') do
+             Inc (J);
+            Val (Copy (TZ, I, J - I), ADSTEndDay, Err);
+            if (Err > 0) or (ADSTEndDay = 0) and (ADSTEndSpecType = DSTJulianX)
+                                                     or (ADSTEndDay > 365) then
+             Exit;
+           end;
+          if (J <= Length (TZ)) and (TZ [J] = '/') then
+           begin
+            if J = Length (TZ) then
+             Exit;
+            Val (Copy (TZ, Succ (J), Length (TZ) - J), ADSTEndSec, Err);
+            if (Err > 0) or (ADSTEndSec > MaxSecond) then
+             Exit
+            else
+             ADSTEndSec := ADSTEndSec * 3600;
+           end
+          else
+           (* Use the preset default *)
+           ADSTEndSec := DSTEndSec;
+
+(* Format complete, all checks successful => accept the parsed values. *)
+         if ADSTStartSpecType = DSTMonthWeekDay then
+          begin
+           DSTStartMonth := ADSTStartMonth;
+           DSTStartWeek := ADSTStartWeek;
+          end;
+         DSTStartDay := ADSTStartDay;
+         DSTStartSec := ADSTStartSec;
+         if ADSTStartSpecType = DSTMonthWeekDay then
+          begin
+           DSTEndMonth := ADSTEndMonth;
+           DSTEndWeek := ADSTEndWeek;
+          end;
+          DSTEndDay := ADSTEndDay;
+          DSTEndSec := ADSTEndSec;
+          DSTStartSpecType := ADSTStartSpecType;
+          DSTEndSpecType := ADSTEndSpecType;
+         end;
+       end
+      else
+       DSTOffset := -3600 + TZOffset;
+     end;
+   end;
+end;
+
+procedure InitTZ;
+var
+  L: longint;
+  SystemTime: TSystemTime;
+  Y: word absolute SystemTime.Year;
+  Mo: word absolute SystemTime.Month;
+  D: word absolute SystemTime.Day;
+  WD: word absolute SystemTime.DayOfWeek;
+begin
+  InitTZ0;
+  TZOffsetMin := TZOffset div 60;
+  DSTOffsetMin := DSTOffset div 60;
+
+  if DSTOffset <> TZOffset then
+   begin
+    GetLocalTime (SystemTime);
+    if (DSTStartSpecType = DSTMonthWeekDay) or (DSTStartSpecType = DSTMonthDay)
+                                                                           then
+     begin
+      RealDSTStartMonth := DSTStartMonth;
+      if DSTStartSpecType = DSTMonthDay then
+       RealDSTStartDay := DSTStartDay
+      else
+       begin
+        RealDSTStartDay := FirstDay (DSTStartMonth, Y, Mo, D, WD);
+        if (DSTStartWeek >= 1) and (DSTStartWeek <= 4) then
+         if DSTStartDay < RealDSTStartDay then
+          RealDSTStartDay := DSTStartWeek * 7 + DSTStartDay - RealDSTStartDay
+                                                                            + 1
+         else
+          RealDSTStartDay := Pred (DSTStartWeek) * 7 + DSTStartDay
+                                                          - RealDSTStartDay + 1
+        else
+(* Last week in month *)
+         begin
+          RealDSTStartDay := RealDSTStartDay
+                                    + MonthDays [false, RealDSTStartMonth] - 1;
+          if RealDSTStartMonth = 2 then
+           Inc (RealDSTStartDay, LeapDay (Y));
+          RealDSTStartDay := RealDSTStartDay mod 7;
+          if RealDSTStartDay < DSTStartDay then
+           RealDSTStartDay := RealDSTStartDay + 7 - DSTStartDay
+          else
+           RealDSTStartDay := RealDSTStartDay - DSTStartDay;
+          RealDSTStartDay := MonthDays [false, RealDSTStartMonth]
+                                                             - RealDSTStartDay;
+         end;
+       end;
+     end
+    else
+     begin
+(* Julian day *)
+      L := DSTStartDay;
+      if (DSTStartSpecType = DSTJulian) then
+(* 0-based *)
+       if (L + LeapDay (Y) <= 59) then
+        Inc (L)
+       else
+        L := L + 1 - LeapDay (Y);
+      if L <= 31 then
+       begin
+        RealDSTStartMonth := 1;
+        RealDSTStartDay := L;
+       end
+      else
+       if (L <= 59) or
+                (DSTStartSpecType = DSTJulian) and (L - LeapDay (Y) <= 59) then
+        begin
+         RealDSTStartMonth := 2;
+         RealDSTStartDay := DSTStartDay - 31;
+        end
+       else
+        begin
+         RealDSTStartMonth := 3;
+         while (RealDSTStartMonth < 12) and (MonthEnds [RealDSTStartMonth] > L)
+                                                                             do
+          Inc (RealDSTStartMonth);
+         RealDSTStartDay := L - MonthEnds [Pred (RealDSTStartMonth)];
+        end;
+     end;
+
+    if (DSTEndSpecType = DSTMonthWeekDay) or (DSTEndSpecType = DSTMonthDay) then
+     begin
+      RealDSTEndMonth := DSTEndMonth;
+      if DSTEndSpecType = DSTMonthDay then
+       RealDSTEndDay := DSTEndDay
+      else
+       begin
+        RealDSTEndDay := FirstDay (DSTEndMonth, Y, Mo, D, WD);
+        if (DSTEndWeek >= 1) and (DSTEndWeek <= 4) then
+         if DSTEndDay < RealDSTEndDay then
+          RealDSTEndDay := DSTEndWeek * 7 + DSTEndDay - RealDSTEndDay + 1
+         else
+          RealDSTEndDay := Pred (DSTEndWeek) * 7 + DSTEndDay - RealDSTEndDay
+                                                                            + 1
+        else
+(* Last week in month *)
+         begin
+          RealDSTEndDay := RealDSTEndDay + MonthDays [false, RealDSTEndMonth]
+                                                                           - 1;
+          if RealDSTEndMonth = 2 then
+           Inc (RealDSTEndDay, LeapDay (Y));
+          RealDSTEndDay := RealDSTEndDay mod 7;
+          if RealDSTEndDay < DSTEndDay then
+           RealDSTEndDay := RealDSTEndDay + 7 - DSTEndDay
+          else
+           RealDSTEndDay := RealDSTEndDay - DSTEndDay;
+          RealDSTEndDay := MonthDays [false, RealDSTEndMonth] - RealDSTEndDay;
+         end;
+       end;
+     end
+    else
+     begin
+(* Julian day *)
+      L := DSTEndDay;
+      if (DSTEndSpecType = DSTJulian) then
+(* 0-based *)
+       if (L + LeapDay (Y) <= 59) then
+        Inc (L)
+       else
+        L := L + 1 - LeapDay (Y);
+      if L <= 31 then
+       begin
+        RealDSTEndMonth := 1;
+        RealDSTEndDay := L;
+       end
+      else
+       if (L <= 59) or
+                  (DSTEndSpecType = DSTJulian) and (L - LeapDay (Y) <= 59) then
+        begin
+         RealDSTEndMonth := 2;
+         RealDSTEndDay := DSTEndDay - 31;
+        end
+       else
+        begin
+         RealDSTEndMonth := 3;
+         while (RealDSTEndMonth < 12) and (MonthEnds [RealDSTEndMonth] > L) do
+          Inc (RealDSTEndMonth);
+         RealDSTEndDay := L - MonthEnds [Pred (RealDSTEndMonth)];
+        end;
+     end;
+   end;
+end;
+
+{$IFNDEF HAS_DUAL_TZHANDLING}
+function GetUniversalTime (var SystemTime: TSystemTime): boolean;
+begin
+  GetLocalTime (SystemTime);
+  UpdateTimeWithOffset (SystemTime, GetLocalTimeOffset);
+  GetUniversalTime := true;
+end;
+
+function GetLocalTimeOffset: integer;
+begin
+  if InDST then
+   GetLocalTimeOffset := DSTOffsetMin
+  else
+   GetLocalTimeOffset := TZOffsetMin;
+end;
+{$ENDIF HAS_DUAL_TZHANDLING}
+
+
+function GetLocalTimeOffset(const DateTime: TDateTime; const InputIsUTC: boolean; out Offset: integer): boolean;
+var
+  SystemTime: TSystemTime;
+begin
+  DateTimeToSystemTime (DateTime, SystemTime);
+  if InDST (SystemTime, InputIsUTC) then
+   Offset := DSTOffsetMin
+  else
+   Offset := TZOffsetMin;
+  GetLocalTimeOffset := true;
+end;

+ 82 - 1
rtl/os2/sysutils.pp

@@ -56,6 +56,7 @@ threadvar
 {$DEFINE FPC_FEXPAND_GETENV_PCHAR}
 {$DEFINE FPC_FEXPAND_GETENV_PCHAR}
 {$DEFINE HAS_GETTICKCOUNT}
 {$DEFINE HAS_GETTICKCOUNT}
 {$DEFINE HAS_GETTICKCOUNT64}
 {$DEFINE HAS_GETTICKCOUNT64}
+{$DEFINE HAS_LOCALTIMEZONEOFFSET}
 
 
 { Include platform independent implementation part }
 { Include platform independent implementation part }
 {$i sysutils.inc}
 {$i sysutils.inc}
@@ -549,6 +550,21 @@ end;
                               Time Functions
                               Time Functions
 ****************************************************************************}
 ****************************************************************************}
 
 
+{$DEFINE HAS_DUAL_TZHANDLING}
+{$I tzenv.inc}
+
+var
+  TZAlwaysFromEnv: boolean;
+
+procedure InitTZ2; inline;
+var
+  DT: DosCalls.TDateTime;
+begin
+  DosGetDateTime (DT);
+  TZAlwaysFromEnv := DT.TimeZone = -1;
+end;
+
+
 procedure GetLocalTime (var SystemTime: TSystemTime);
 procedure GetLocalTime (var SystemTime: TSystemTime);
 var
 var
   DT: DosCalls.TDateTime;
   DT: DosCalls.TDateTime;
@@ -559,13 +575,76 @@ begin
     Year:=DT.Year;
     Year:=DT.Year;
     Month:=DT.Month;
     Month:=DT.Month;
     Day:=DT.Day;
     Day:=DT.Day;
+    DayOfWeek:=DT.WeekDay;
     Hour:=DT.Hour;
     Hour:=DT.Hour;
     Minute:=DT.Minute;
     Minute:=DT.Minute;
     Second:=DT.Second;
     Second:=DT.Second;
-    MilliSecond:=DT.Sec100;
+    MilliSecond:=DT.Sec100 * 10;
   end;
   end;
 end;
 end;
 
 
+
+function GetUniversalTime (var SystemTime: TSystemTime): boolean;
+var
+  DT: DosCalls.TDateTime;
+  Offset: longint;
+begin
+  if TZAlwaysFromEnv then
+   begin
+    GetLocalTime (SystemTime);
+    Offset := GetLocalTimeOffset;
+   end
+  else
+   begin
+    DosGetDateTime (DT);
+    with SystemTime do
+     begin
+      Year := DT.Year;
+      Month := DT.Month;
+      Day := DT.Day;
+      DayOfWeek := DT.WeekDay;
+      Hour := DT.Hour;
+      Minute := DT.Minute;
+      Second := DT.Second;
+      MilliSecond := DT.Sec100 * 10;
+     end;
+    if DT.TimeZone = -1 then
+     Offset := GetLocalTimeOffset
+    else
+     Offset := DT.TimeZone;
+   end;
+  UpdateTimeWithOffset (SystemTime, Offset);
+  GetUniversalTime := true;
+end;
+
+
+function GetLocalTimeOffset: integer;
+var
+  DT: DosCalls.TDateTime;
+begin
+  if TZAlwaysFromEnv then
+   begin
+    if InDST then
+     GetLocalTimeOffset := DSTOffsetMin
+    else
+     GetLocalTimeOffset := TZOffsetMin;
+   end
+  else
+   begin
+    DosGetDateTime (DT);
+    if DT.TimeZone <> -1 then
+     GetLocalTimeOffset := DT.TimeZone
+    else
+     begin
+      if InDST then
+       GetLocalTimeOffset := DSTOffsetMin
+      else
+       GetLocalTimeOffset := TZOffsetMin;
+     end;
+   end;
+end;
+
+
 {****************************************************************************
 {****************************************************************************
                               Misc Functions
                               Misc Functions
 ****************************************************************************}
 ****************************************************************************}
@@ -997,6 +1076,8 @@ Initialization
   OnBeep:=@SysBeep;
   OnBeep:=@SysBeep;
   LastOSError := 0;
   LastOSError := 0;
   OrigOSErrorWatch := TOSErrorWatch (SetOSErrorTracking (@TrackLastOSError));
   OrigOSErrorWatch := TOSErrorWatch (SetOSErrorTracking (@TrackLastOSError));
+  InitTZ;
+  InitTZ2;
 Finalization
 Finalization
   FreeTerminateProcs;
   FreeTerminateProcs;
   DoneExceptions;
   DoneExceptions;

+ 140 - 8
rtl/sinclairql/qdos.inc

@@ -17,10 +17,21 @@
 
 
 const
 const
   _MT_INF   = $00;
   _MT_INF   = $00;
+  _MT_FRJOB = $05;
   _MT_DMODE = $10;
   _MT_DMODE = $10;
   _MT_ALCHP = $18;
   _MT_ALCHP = $18;
   _MT_RECHP = $19;
   _MT_RECHP = $19;
 
 
+procedure mt_frjob(jobID: Tjobid; exitCode: longint); assembler; nostackframe; public name '_mt_frjob';
+asm
+  movem.l d2-d3,-(sp)
+  move.l  exitCode,d3
+  move.l  jobID,d1
+  moveq   #_MT_FRJOB,d0
+  trap    #1
+  movem.l (sp)+,d2-d3
+end;
+
 function mt_inf(sys_vars: ppchar; ver_ascii: plongint): Tjobid; assembler; nostackframe; public name '_mt_inf';
 function mt_inf(sys_vars: ppchar; ver_ascii: plongint): Tjobid; assembler; nostackframe; public name '_mt_inf';
 asm
 asm
   move.l  d2,-(sp)
   move.l  d2,-(sp)
@@ -28,10 +39,16 @@ asm
   move.l  ver_ascii,-(sp)
   move.l  ver_ascii,-(sp)
   moveq.l #_MT_INF,d0
   moveq.l #_MT_INF,d0
   trap #1
   trap #1
-  move.l  (sp)+,a1
+  move.l  (sp)+,d0
+  beq.s   @skip_vars
+  move.l  d0,a1
   move.l  d2,(a1)   { ver_ascii }
   move.l  d2,(a1)   { ver_ascii }
-  move.l  (sp)+,a1
+@skip_vars:
+  move.l  (sp)+,d0
+  beq.s   @skip_ver
+  move.l  d0,a1
   move.l  a0,(a1)   { sys_vars }
   move.l  a0,(a1)   { sys_vars }
+@skip_ver:
   move.l  (sp)+,d2
   move.l  (sp)+,d2
   move.l  d1,d0     { jobid }
   move.l  d1,d0     { jobid }
 end;
 end;
@@ -44,7 +61,7 @@ asm
   moveq.l #_MT_DMODE,d0
   moveq.l #_MT_DMODE,d0
   trap #1
   trap #1
   move.w d1,(a0)
   move.w d1,(a0)
-  move.w d2,(a1) 
+  move.w d2,(a1)
   movem.l (sp)+,d2/a3-a4
   movem.l (sp)+,d2/a3-a4
 end;
 end;
 
 
@@ -90,7 +107,8 @@ asm
   move.l mode,d3
   move.l mode,d3
   moveq.l #_IO_OPEN,d0
   moveq.l #_IO_OPEN,d0
   trap #2
   trap #2
-  bne @quit
+  tst.l d0
+  bne.s @quit
   move.l a0,d0
   move.l a0,d0
 @quit:
 @quit:
   movem.l (sp)+,d2-d3
   movem.l (sp)+,d2-d3
@@ -120,10 +138,67 @@ end;
 
 
 
 
 const
 const
+  _IO_FBYTE = $01;
+  _IO_FLINE = $02;
+  _IO_FSTRG = $03;
   _IO_SBYTE = $05;
   _IO_SBYTE = $05;
   _IO_SSTRG = $07;
   _IO_SSTRG = $07;
   _SD_WDEF = $0D;
   _SD_WDEF = $0D;
   _SD_CLEAR = $20;
   _SD_CLEAR = $20;
+  _FS_POSAB = $42;
+  _FS_POSRE = $43;
+  _FS_HEADR = $47;
+  _FS_TRUNCATE = $4B;
+
+function io_fbyte(chan: Tchanid; timeout: Ttimeout): longint; assembler; nostackframe; public name '_io_fbyte';
+asm
+  move.l d3,-(sp)
+  move.w timeout,d3
+  clr.l d1
+  move.l chan,a0
+  moveq.l #_IO_FBYTE,d0
+  trap #3
+  tst.l d0
+  bne @quit
+  move.l d1,d0
+@quit:
+  move.l (sp)+,d3
+end;
+
+function io_fetch(chan: Tchanid; timeout: Ttimeout; buf: pointer; len: word; trap_no: longint): longint; assembler;
+asm
+  movem.l d2-d3,-(sp)
+  move.w len,d2
+  move.l buf,a1
+  move.w timeout,d3
+  move.l chan,a0
+  move.l trap_no,d0
+  trap #3
+  tst.l d0
+  beq @ok
+  cmp.w	#ERR_EF,d0
+  beq @eof
+  cmp.w #ERR_NC,d0
+  bne @quit
+@eof:
+  tst.w d1
+  beq @quit
+@ok:
+  clr.l d0
+  move.w d1,d0
+@quit:
+  movem.l (sp)+,d2-d3
+end;
+
+function io_fline(chan: Tchanid; timeout: Ttimeout; buf: pointer; len: word): longint; public name '_io_fline';
+begin
+  io_fline := io_fetch(chan, timeout, buf, len, _IO_FLINE);
+end;
+
+function io_fstrg(chan: Tchanid; timeout: Ttimeout; buf: pointer; len: word): longint; public name '_io_fstrg';
+begin
+  io_fstrg := io_fetch(chan, timeout, buf, len, _IO_FSTRG);
+end;
 
 
 function io_sbyte(chan: Tchanid; timeout: Ttimeout; c: char): longint; assembler; public name '_io_sbyte';
 function io_sbyte(chan: Tchanid; timeout: Ttimeout; c: char): longint; assembler; public name '_io_sbyte';
 asm
 asm
@@ -137,7 +212,7 @@ asm
   move.l (sp)+,d3
   move.l (sp)+,d3
 end;
 end;
 
 
-function io_sstrg(chan: Tchanid; timeout: Ttimeout; buf: pointer; len: smallint): smallint; assembler; public name '_io_sstrg';
+function io_sstrg(chan: Tchanid; timeout: Ttimeout; buf: pointer; len: word): longint; assembler; public name '_io_sstrg';
 asm
 asm
   movem.l d2-d3,-(sp)
   movem.l d2-d3,-(sp)
   move.w len,d2
   move.w len,d2
@@ -171,20 +246,75 @@ asm
   move.b border_colour,d1
   move.b border_colour,d1
   move.l chan,a0
   move.l chan,a0
   moveq.l #_SD_WDEF,d0
   moveq.l #_SD_WDEF,d0
-  trap #3 
+  trap #3
   movem.l (sp)+,d2-d3
   movem.l (sp)+,d2-d3
 end;
 end;
 
 
-function sd_clear(chan: Tchanid; timeout: Ttimeout): longint; assembler; public name '_sd_clear';
+function sd_clear(chan: Tchanid; timeout: Ttimeout): longint; assembler; nostackframe; public name '_sd_clear';
 asm
 asm
   move.l d3,-(sp)
   move.l d3,-(sp)
   move.w timeout,d3
   move.w timeout,d3
   move.l chan,a0
   move.l chan,a0
   moveq.l #_SD_CLEAR,d0
   moveq.l #_SD_CLEAR,d0
-  trap #3 
+  trap #3
+  move.l (sp)+,d3
+end;
+
+
+function fs_posab(chan: Tchanid; new_pos: dword):longint; assembler; nostackframe; public name '_fs_posab';
+asm
+  move.l d3,-(sp)
+  moveq #_FS_POSAB,d0
+  move.l new_pos,d1
+  moveq #-1,d3
+  move.l chan,a0
+  trap #3
+  tst.l d0
+  bne.s  @quit
+  move.l d1,d0
+@quit:
+  move.l (sp)+,d3
+end;
+
+function fs_posre(chan: Tchanid; new_pos: dword): longint; assembler; nostackframe; public name '_fs_posre';
+asm
+  move.l d3,-(sp)
+  moveq #_FS_POSRE,d0
+  move.l new_pos,d1
+  moveq #-1,d3
+  move.l chan,a0
+  trap #3
+  tst.l d0
+  bne.s  @quit
+  move.l d1,d0
+@quit:
   move.l (sp)+,d3
   move.l (sp)+,d3
 end;
 end;
 
 
+function fs_headr(chan: Tchanid; buf: pointer; buf_size: word): longint; assembler; nostackframe; public name '_fs_headr';
+asm
+  movem.l d2-d3,-(sp)
+  moveq #_FS_HEADR,d0
+  move.l buf_size,d2
+  moveq #-1,d3
+  move.l chan,a0
+  trap #3
+  tst.l d0
+  bne.s  @quit
+  move.l d1,d0
+@quit:
+  movem.l (sp)+,d2-d3
+end;
+
+function fs_truncate(chan: Tchanid): longint; assembler; nostackframe; public name '_fs_truncate';
+asm
+  move.l d3,-(sp)
+  moveq #_FS_TRUNCATE,d0
+  moveq #-1,d3
+  move.l chan, a0
+  trap #3
+  move.l (sp)+,d3
+end;
 
 
 const
 const
   _UT_CON = $c6;
   _UT_CON = $c6;
@@ -196,6 +326,7 @@ asm
   move.l params,a1
   move.l params,a1
   move.w _UT_CON,a2
   move.w _UT_CON,a2
   jsr (a2)
   jsr (a2)
+  tst.l d0
   bne @quit
   bne @quit
   move.l a0,d0
   move.l a0,d0
 @quit:
 @quit:
@@ -208,6 +339,7 @@ asm
   move.l params,a1
   move.l params,a1
   move.w _UT_SCR,a2
   move.w _UT_SCR,a2
   jsr (a2)
   jsr (a2)
+  tst.l d0
   bne @quit
   bne @quit
   move.l a0,d0
   move.l a0,d0
 @quit:
 @quit:

+ 10 - 1
rtl/sinclairql/qdosfuncs.inc

@@ -15,6 +15,7 @@
 
 
 {$i qdosh.inc}
 {$i qdosh.inc}
 
 
+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';
 
 
 procedure mt_dmode(s_mode: pword; d_type: pword); external name '_mt_dmode';
 procedure mt_dmode(s_mode: pword; d_type: pword); external name '_mt_dmode';
@@ -26,8 +27,16 @@ function io_open_qlstr(name_qlstr: pointer; mode: longint): Tchanid; external na
 function io_open(name: pchar; mode: longint): Tchanid; external name '_io_open';
 function io_open(name: pchar; mode: longint): Tchanid; external name '_io_open';
 function io_close(chan: Tchanid): longint; external name '_io_close';
 function io_close(chan: Tchanid): longint; external name '_io_close';
 
 
+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_sbyte(chan: Tchanid; timeout: Ttimeout; c: char): longint; external name '_io_sbyte';
-function io_sstrg(chan: Tchanid; timeout: Ttimeout; buf: pointer; len: smallint): smallint; external name '_io_sstrg';
+function io_sstrg(chan: Tchanid; timeout: Ttimeout; buf: pointer; len: word): longint; external name '_io_sstrg';
+
+function fs_posab(chan: Tchanid; new_pos: dword): longint; external name '_fs_posab';
+function fs_posre(chan: Tchanid; new_pos: dword): longint; external name '_fs_posre';
+function fs_headr(chan: Tchanid; buf: pointer; buf_size: word): longint; external name '_fs_headr';
+function fs_truncate(chan: Tchanid): longint; external name '_fs_truncate';
 
 
 function sd_wdef(chan: Tchanid; timeout: Ttimeout; border_colour: byte; border_width: word; window: PQLRect): longint; external name '_sd_wdef'; 
 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 sd_clear(chan: Tchanid; timeout: Ttimeout): longint; external name '_sd_clear';

+ 20 - 38
rtl/sinclairql/si_prc.pp

@@ -22,29 +22,25 @@ implementation
 {$i qdosfuncs.inc}
 {$i qdosfuncs.inc}
 
 
 var
 var
-  stacktop: pointer;
-  setjmpbuf: jmp_buf;
-  stklen: longint; external name '__stklen';
   binstart: byte; external name '_stext';
   binstart: byte; external name '_stext';
   binend: byte; external name '_etext';
   binend: byte; external name '_etext';
   bssstart: byte; external name '_sbss';
   bssstart: byte; external name '_sbss';
   bssend: byte; external name '_ebss';
   bssend: byte; external name '_ebss';
 
 
-{ this is const, so it will go into the .data section, not .bss }
-const
-  stackorig: pointer = nil;
-
 procedure PascalMain; external name 'PASCALMAIN';
 procedure PascalMain; external name 'PASCALMAIN';
+procedure PascalStart; forward;
 
 
 { this function must be the first in this unit which contains code }
 { this function must be the first in this unit which contains code }
 {$OPTIMIZATION OFF}
 {$OPTIMIZATION OFF}
-function _FPC_proc_start: longint; cdecl; public name '_start';
-var
-  newstack: pointer;
-begin
-  _FPC_proc_start:=0;
-  asm
-    move.l d7,-(sp)
+function _FPC_proc_start: longint; cdecl; assembler; nostackframe; public name '_start';
+asm
+    bra   @start
+    dc.l  $0
+    dc.w  $4afb
+    dc.w  3
+    dc.l  $46504300   { Job name, just FPC for now }
+
+@start:
     { relocation code }
     { relocation code }
 
 
     { get our actual position in RAM }
     { get our actual position in RAM }
@@ -80,36 +76,22 @@ begin
     bne @relocloop
     bne @relocloop
 
 
 @noreloc:
 @noreloc:
-    move.l (sp)+,d7
+    jsr PascalStart
+end;
 
 
-    { save the original stack pointer }
-    move.l a7,stackorig
-  end;
+procedure _FPC_proc_halt(_ExitCode: longint); public name '_haltproc';
+begin
+  mt_frjob(-1, _ExitCode);
+end;
 
 
+procedure PascalStart;
+begin
   { initialize .bss }
   { initialize .bss }
   FillChar(bssstart,PtrUInt(@bssend)-PtrUInt(@bssstart),#0);
   FillChar(bssstart,PtrUInt(@bssend)-PtrUInt(@bssstart),#0);
 
 
-  newstack:=mt_alchp(stklen,nil,-1);
-  if not assigned(newstack) then
-    _FPC_proc_start:=ERR_OM
-  else
-    begin
-      stacktop:=pbyte(newstack)+stklen;
-      asm
-        move.l stacktop,sp
-      end;
-      if setjmp(setjmpbuf) = 0 then
-        PascalMain;
-      asm
-        move.l stackorig,sp
-      end;
-      mt_rechp(newstack);
-   end;
-end;
+  PascalMain;
 
 
-procedure _FPC_proc_halt(_ExitCode: longint); public name '_haltproc';
-begin
-  longjmp(setjmpbuf,1); 
+  Halt; { this should never be reached }
 end;
 end;
 
 
 
 

+ 37 - 7
rtl/sinclairql/sysfile.inc

@@ -50,37 +50,67 @@ end;
 
 
 
 
 function do_read(h: longint; addr: pointer; len: longint) : longint;
 function do_read(h: longint; addr: pointer; len: longint) : longint;
+var
+  res: longint;
 begin
 begin
-  do_read:=-1;
+  do_read := 0;
+  res := io_fline(h, -1, addr, len);
+  if res < 0 then
+    Error2InOutRes(res)
+  else
+    do_read := res;
 end;
 end;
 
 
 
 
-function do_filepos(handle: longint) : longint;
+function do_filepos(handle: longint): longint;
+var
+  res: longint;
 begin
 begin
-  do_filepos:=-1;
+  do_filepos := 0;
+  res := fs_posre(handle, 0);
+  if res < 0 then
+    Error2InOutRes(res)
+  else
+    do_filepos := res;
 end;
 end;
 
 
 
 
 procedure do_seek(handle, pos: longint);
 procedure do_seek(handle, pos: longint);
+var
+  res: longint;
 begin
 begin
+  res := fs_posab(handle, pos);
+  if res < 0 then
+    Error2InOutRes(res);
 end;
 end;
 
 
 
 
-function do_seekend(handle: longint):longint;
+function do_seekend(handle: longint): longint;
 begin
 begin
-  do_seekend:=-1;
+  do_seek(handle, -1);
+  do_seekend := do_filepos(handle);
 end;
 end;
 
 
 
 
-function do_filesize(handle : THandle) : longint;
+function do_filesize(handle: longint): longint;
+var
+  res: longint;
+  header: array [0..$39] of byte;
 begin
 begin
-  do_filesize:=-1;
+  do_filesize := 0;
+  res := fs_headr(handle, @header, $40);
+  if res < 0 then
+    Error2InOutRes(res)
+  else
+    do_filesize := plongint(@header[0])^;
 end;
 end;
 
 
 
 
 { truncate at a given position }
 { truncate at a given position }
 procedure do_truncate(handle, pos: longint);
 procedure do_truncate(handle, pos: longint);
 begin
 begin
+  do_seek(handle, pos);
+  fs_truncate(handle);
 end;
 end;
 
 
 
 

+ 43 - 56
rtl/sinclairql/system.pp

@@ -51,7 +51,7 @@ const
     DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsLF;
     DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsLF;
 
 
 const
 const
-    UnusedHandle    = $ffff;
+    UnusedHandle    = -1;
     StdInputHandle: longint = UnusedHandle;
     StdInputHandle: longint = UnusedHandle;
     StdOutputHandle: longint = UnusedHandle;
     StdOutputHandle: longint = UnusedHandle;
     StdErrorHandle: longint = UnusedHandle;
     StdErrorHandle: longint = UnusedHandle;
@@ -62,8 +62,6 @@ var
     argv: PPChar;
     argv: PPChar;
     envp: PPChar;
     envp: PPChar;
 
 
-    QCON: longint; // QDOS console
-    QSCR: longint; // QDOS screen
     heapStart: pointer;
     heapStart: pointer;
 
 
 
 
@@ -76,71 +74,61 @@ var
     {$endif defined(FPUSOFT)}
     {$endif defined(FPUSOFT)}
 
 
 
 
-  implementation
+implementation
 
 
-    {$if defined(FPUSOFT)}
-
-    {$define fpc_softfpu_implementation}
-    {$define softfpu_compiler_mul32to64}
-    {$define softfpu_inline}
-    {$i softfpu.pp}
-    {$undef fpc_softfpu_implementation}
-
-    { we get these functions and types from the softfpu code }
-    {$define FPC_SYSTEM_HAS_float64}
-    {$define FPC_SYSTEM_HAS_float32}
-    {$define FPC_SYSTEM_HAS_flag}
-    {$define FPC_SYSTEM_HAS_extractFloat64Frac0}
-    {$define FPC_SYSTEM_HAS_extractFloat64Frac1}
-    {$define FPC_SYSTEM_HAS_extractFloat64Exp}
-    {$define FPC_SYSTEM_HAS_extractFloat64Sign}
-    {$define FPC_SYSTEM_HAS_ExtractFloat32Frac}
-    {$define FPC_SYSTEM_HAS_extractFloat32Exp}
-    {$define FPC_SYSTEM_HAS_extractFloat32Sign}
-
-    {$endif defined(FPUSOFT)}
+  {$if defined(FPUSOFT)}
 
 
-    {$i system.inc}
-    {$ifdef FPC_QL_USE_TINYHEAP}
-    {$i tinyheap.inc}
-    {$endif FPC_QL_USE_TINYHEAP}
+  {$define fpc_softfpu_implementation}
+  {$define softfpu_compiler_mul32to64}
+  {$define softfpu_inline}
+  {$i softfpu.pp}
+  {$undef fpc_softfpu_implementation}
 
 
+  { we get these functions and types from the softfpu code }
+  {$define FPC_SYSTEM_HAS_float64}
+  {$define FPC_SYSTEM_HAS_float32}
+  {$define FPC_SYSTEM_HAS_flag}
+  {$define FPC_SYSTEM_HAS_extractFloat64Frac0}
+  {$define FPC_SYSTEM_HAS_extractFloat64Frac1}
+  {$define FPC_SYSTEM_HAS_extractFloat64Exp}
+  {$define FPC_SYSTEM_HAS_extractFloat64Sign}
+  {$define FPC_SYSTEM_HAS_ExtractFloat32Frac}
+  {$define FPC_SYSTEM_HAS_extractFloat32Exp}
+  {$define FPC_SYSTEM_HAS_extractFloat32Sign}
 
 
-  function GetProcessID:SizeUInt;
-  begin
-    GetProcessID := 1;
-  end;
+  {$endif defined(FPUSOFT)}
 
 
+  {$i system.inc}
+  {$ifdef FPC_QL_USE_TINYHEAP}
+  {$i tinyheap.inc}
+  {$endif FPC_QL_USE_TINYHEAP}
 
 
-  procedure SysInitParamsAndEnv;
-  begin
-  end;
 
 
+function GetProcessID:SizeUInt;
+begin
+  GetProcessID := mt_inf(nil, nil);
+end;
 
 
-  procedure randomize;
-  begin
-    {$WARNING: randseed is uninitialized}
-    randseed:=0;
-  end;
+procedure SysInitParamsAndEnv;
+begin
+end;
 
 
-procedure PrintStr(ch: longint; const s: shortstring);
+procedure randomize;
 begin
 begin
-  io_sstrg(ch,-1,@s[1],ord(s[0]));
+  {$WARNING: randseed is uninitialized}
+  randseed:=0;
 end;
 end;
 
 
-procedure PrintStr2(ch: longint; const s: shortstring);
-var
-  i: smallint;
+procedure PrintStr(ch: longint; const s: shortstring);
 begin
 begin
-  for i:=1 to ord(s[0]) do
-    io_sbyte(ch,-1,s[i]);
+  io_sstrg(ch,-1,@s[1],ord(s[0]));
 end;
 end;
 
 
 procedure DebugStr(const s: shortstring); public name '_dbgstr';
 procedure DebugStr(const s: shortstring); public name '_dbgstr';
 var
 var
   i: longint;
   i: longint;
 begin
 begin
-  PrintStr($00010001,s);
+  PrintStr(stdOutputHandle,s);
   for i:=0 to 10000 do begin end;
   for i:=0 to 10000 do begin end;
 end;
 end;
 
 
@@ -165,17 +153,14 @@ begin
   stdInputHandle:=io_open('con_',Q_OPEN);
   stdInputHandle:=io_open('con_',Q_OPEN);
   stdOutputHandle:=stdInputHandle;
   stdOutputHandle:=stdInputHandle;
   stdErrorHandle:=stdInputHandle;
   stdErrorHandle:=stdInputHandle;
-  QCON:=stdInputHandle;
 
 
   r.q_width:=512;
   r.q_width:=512;
   r.q_height:=256;
   r.q_height:=256;
   r.q_x:=0;
   r.q_x:=0;
   r.q_y:=0;
   r.q_y:=0;
 
 
-  sd_wdef(stdInputHandle,-1,0,16,@r);
+  sd_wdef(stdInputHandle,-1,2,1,@r);
   sd_clear(stdInputHandle,-1);
   sd_clear(stdInputHandle,-1);
-
-//  QSCR:=io_open('scr_',Q_OPEN);
 end;
 end;
 
 
 {*****************************************************************************
 {*****************************************************************************
@@ -185,13 +170,15 @@ end;
 procedure haltproc(e:longint); external name '_haltproc';
 procedure haltproc(e:longint); external name '_haltproc';
 
 
 procedure system_exit;
 procedure system_exit;
+const
+  anyKey: string = 'Press any key to exit';
 begin
 begin
-//  io_close(QCON);
-//  io_close(QSCR);
+  io_sstrg(stdOutputHandle, -1, @anyKey[1], ord(anyKey[0]));
+  io_fbyte(stdInputHandle, -1);
+
   stdInputHandle:=UnusedHandle;
   stdInputHandle:=UnusedHandle;
   stdOutputHandle:=UnusedHandle;
   stdOutputHandle:=UnusedHandle;
   stdErrorHandle:=UnusedHandle;
   stdErrorHandle:=UnusedHandle;
-
   haltproc(exitcode);
   haltproc(exitcode);
 end;
 end;
 
 

+ 17 - 0
rtl/watcom/sysutils.pp

@@ -49,6 +49,7 @@ implementation
 
 
 {$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
 {$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
 {$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *)
 {$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *)
+{$DEFINE HAS_LOCALTIMEZONEOFFSET}
 
 
 { Include platform independent implementation part }
 { Include platform independent implementation part }
 {$i sysutils.inc}
 {$i sysutils.inc}
@@ -635,6 +636,8 @@ end;
                               Time Functions
                               Time Functions
 ****************************************************************************}
 ****************************************************************************}
 
 
+{$I tzenv.inc}
+
 Procedure GetLocalTime(var SystemTime: TSystemTime);
 Procedure GetLocalTime(var SystemTime: TSystemTime);
 var
 var
   Regs: Registers;
   Regs: Registers;
@@ -650,6 +653,7 @@ begin
   SystemTime.Year := Regs.Cx;
   SystemTime.Year := Regs.Cx;
   SystemTime.Month := Regs.Dh;
   SystemTime.Month := Regs.Dh;
   SystemTime.Day := Regs.Dl;
   SystemTime.Day := Regs.Dl;
+  SystemTime.DayOfWeek := Regs.Al;
 end ;
 end ;
 
 
 
 
@@ -657,6 +661,17 @@ end ;
                               Misc Functions
                               Misc Functions
 ****************************************************************************}
 ****************************************************************************}
 
 
+const
+  BeepChars: array [1..2] of char = #7'$';
+
+procedure sysBeep;
+var
+  Regs: Registers;
+begin
+  Regs.dx := Ofs (BeepChars);
+  Regs.ah := 9;
+  MsDos (Regs);
+end;
 
 
 {****************************************************************************
 {****************************************************************************
                               Locale Functions
                               Locale Functions
@@ -901,6 +916,8 @@ Initialization
   InitExceptions;       { Initialize exceptions. OS independent }
   InitExceptions;       { Initialize exceptions. OS independent }
   InitInternational;    { Initialize internationalization settings }
   InitInternational;    { Initialize internationalization settings }
   InitDelay;
   InitDelay;
+  OnBeep:=@SysBeep;
+  InitTZ;
 Finalization
 Finalization
   FreeTerminateProcs;
   FreeTerminateProcs;
   DoneExceptions;
   DoneExceptions;

+ 12 - 0
rtl/x86_64/math.inc

@@ -104,19 +104,31 @@ const
     {$ifndef FPC_SYSTEM_HAS_ABS}
     {$ifndef FPC_SYSTEM_HAS_ABS}
     {$define FPC_SYSTEM_HAS_ABS}
     {$define FPC_SYSTEM_HAS_ABS}
     function fpc_abs_real(d : ValReal) : ValReal;compilerproc;
     function fpc_abs_real(d : ValReal) : ValReal;compilerproc;
+{$ifndef cpullvm}
     begin
     begin
       { Function is handled internal in the compiler }
       { Function is handled internal in the compiler }
       runerror(207);
       runerror(207);
       result:=0;
       result:=0;
+{$else not cpullvm}
+    assembler;
+    asm
+      fldt d
+      fabs
+{$endif not cpullvm}
     end;
     end;
     {$endif FPC_SYSTEM_HAS_ABS}
     {$endif FPC_SYSTEM_HAS_ABS}
     {$ifndef FPC_SYSTEM_HAS_SQR}
     {$ifndef FPC_SYSTEM_HAS_SQR}
     {$define FPC_SYSTEM_HAS_SQR}
     {$define FPC_SYSTEM_HAS_SQR}
     function fpc_sqr_real(d : ValReal) : ValReal;compilerproc;
     function fpc_sqr_real(d : ValReal) : ValReal;compilerproc;
+{$ifndef cpullvm}
     begin
     begin
       { Function is handled internal in the compiler }
       { Function is handled internal in the compiler }
       runerror(207);
       runerror(207);
       result:=0;
       result:=0;
+{$else not cpullvm}
+    begin
+      fpc_sqr_real:=d*d;
+{$endif not cpullvm}
     end;
     end;
     {$endif FPC_SYSTEM_HAS_SQR}
     {$endif FPC_SYSTEM_HAS_SQR}
     {$ifndef FPC_SYSTEM_HAS_SQRT}
     {$ifndef FPC_SYSTEM_HAS_SQRT}

+ 3 - 0
tests/test/tfma1.inc

@@ -241,6 +241,7 @@ procedure testsingle;
       halt(1);
       halt(1);
   end;
   end;
 
 
+{$ifndef NODOUBLE}
 
 
 procedure testdouble;
 procedure testdouble;
   var
   var
@@ -480,3 +481,5 @@ procedure testdouble;
     if l0<>-10.0 then
     if l0<>-10.0 then
       halt(1);
       halt(1);
   end;
   end;
+
+{$endif NODOUBLE}

+ 30 - 0
tests/test/tfma1xtensa.pp

@@ -0,0 +1,30 @@
+{ %CPU=xtensa }
+
+{$define NODOUBLE}
+
+{$i tfma1.inc}
+
+begin
+  {
+  d1:=2;
+  d2:=3;
+  d3:=4;
+  d0:=FMADouble(d1,d2,d3);
+  writeln(d0);
+  if d0<>10.0 then
+    halt(1);
+  }
+
+  s1:=2;
+  s2:=3;
+  s3:=4;
+  s0:=FMASingle(s1,s2,s3);
+  writeln(s0);
+  if s0<>10.0 then
+    halt(1);
+
+  testsingle;
+  // testdouble;
+
+  writeln('ok');
+end.

+ 21 - 29
utils/fpdoc/dw_html.pp

@@ -2412,17 +2412,21 @@ procedure THTMLWriter.CreateClassHierarchyPage(AList : TStringList; AddUnit : Bo
     PushOutputNode(h);
     PushOutputNode(h);
   end;
   end;
 
 
-  Procedure AppendClass(E : TDomElement);
+  Procedure AppendClass(E : TPasElementNode);
 
 
   Var
   Var
     N : TDomNode;
     N : TDomNode;
-    P,PM : TPasElement;
+    P,PM,M : TPasElement;
     EN : String;
     EN : String;
     LL : TstringList;
     LL : TstringList;
     I,J : Integer;
     I,J : Integer;
 
 
   begin
   begin
-    EN:=Package.Name+'.'+UTF8Encode(E['unit'])+'.'+UTF8Encode(E.NodeName);
+    M:=E.Element.GetModule;
+    if (M<>Nil) then
+      EN:=Package.Name+'.'+UTF8Encode(M.Name)+'.'+UTF8Encode(E.Element.Name)
+    else
+      EN:=UTF8Encode(E.Element.Name);
     J:=AList.IndexOf(EN);
     J:=AList.IndexOf(EN);
     If J<>-1 then
     If J<>-1 then
       P:=AList.Objects[J] as TPasElement
       P:=AList.Objects[J] as TPasElement
@@ -2442,30 +2446,17 @@ procedure THTMLWriter.CreateClassHierarchyPage(AList : TStringList; AddUnit : Bo
           end
           end
         end
         end
       else
       else
-        AppendText(CurOutputNode,E.Nodename);
-      LL:=TStringList.Create;
-      try
-        N:=E.FirstChild;
-        While (N<>Nil) do
-          begin
-          if (N.NodeType=ELEMENT_NODE) then
-            LL.AddObject(UTF8Encode(N.NodeName),N);
-          N:=N.NextSibling;
-          end;
-        if (LL.Count>0) then
-          begin
-          LL.Sorted:=true;
-          PushClassList;
-          try
-            For I:=0 to LL.Count-1 do
-              AppendClass(LL.Objects[i] as TDomElement);
-          finally
-            PopOutputNode;
-          end;
-          end;
-      finally
-        LL.Free;
-      end;
+        AppendText(CurOutputNode,E.Element.Name);
+      if E.ChildCount>0 then
+        begin
+        PushClassList;
+        try
+          For I:=0 to E.ChildCount-1 do
+            AppendClass(E.Children[i] as TPasElementNode);
+        finally
+          PopOutputNode;
+        end;
+        end;
     Finally
     Finally
       PopOutputNode;
       PopOutputNode;
     end;
     end;
@@ -2473,7 +2464,8 @@ procedure THTMLWriter.CreateClassHierarchyPage(AList : TStringList; AddUnit : Bo
 
 
 Var
 Var
   B : TClassTreeBuilder;
   B : TClassTreeBuilder;
-  E : TDomElement;
+  E : TPasElementNode;
+
 begin
 begin
   PushOutputNode(BodyElement);
   PushOutputNode(BodyElement);
   try
   try
@@ -2483,7 +2475,7 @@ begin
       // Classes
       // Classes
       // WriteXMLFile(B.ClassTree,'tree.xml');
       // WriteXMLFile(B.ClassTree,'tree.xml');
       // Dummy TObject
       // Dummy TObject
-      E:=B.ClassTree.DocumentElement;
+      E:=B.RootNode;
       PushClassList;
       PushClassList;
       try
       try
         AppendClass(E);
         AppendClass(E);

+ 42 - 2
utils/fpdoc/fpclasschart.pp

@@ -509,7 +509,47 @@ begin
   else
   else
     Writeln(StdErr,Format(SSkipMerge,[S.NodeName,D.NodeName]));
     Writeln(StdErr,Format(SSkipMerge,[S.NodeName,D.NodeName]));
 end;
 end;
-  
+
+Function MergeTrees (Dest : TXMLDocument; aRootNode : TPasElementNode) : Integer;
+
+Var
+  aSrc : TXMLDocument;
+
+  Procedure AppendChildClasses(aParent : TDomElement; aNode : TPasElementNode);
+
+  Var
+    El : TDomElement;
+    aChild : TPasElementNode;
+    I : Integer;
+    M : TPasModule;
+
+  begin
+    If (ANode=Nil) or (aNode.ChildCount=0)  then exit;
+    for I:=0 to aNode.ChildCount-1 do
+      begin
+      aChild:=aNode.Children[I];
+      El:=aSrc.CreateElement(UTF8Decode(aChild.Element.Name));
+      M:=aChild.Element.GetModule;
+      If M<>Nil then
+        EL['unit']:=UTF8Decode(M.Name);
+      aParent.AppendChild(El);
+      AppendChildClasses(El,aChild);
+      end;
+  end;
+
+begin
+  aSrc:=TXMLDocument.Create();
+  try
+    aSrc.AppendChild(aSrc.CreateElement('TObject'));
+    AppendChildClasses(aSrc.DocumentElement,aRootNode);
+    MergeTrees(Dest,aSrc);
+  finally
+    aSrc.Free;
+  end;
+end;
+
+
+
 Function AnalyseFiles(Const AOutputName : String; InputFiles,MergeFiles : TStrings; AObjectKind : TPasObjKind) : String;
 Function AnalyseFiles(Const AOutputName : String; InputFiles,MergeFiles : TStrings; AObjectKind : TPasObjKind) : String;
 
 
 
 
@@ -542,7 +582,7 @@ begin
       Try
       Try
         ParseSource(Engine,InputFiles[I],OSTarget,CPUTarget);
         ParseSource(Engine,InputFiles[I],OSTarget,CPUTarget);
         Engine.Ftree.BuildTree(Engine.FObjects);
         Engine.Ftree.BuildTree(Engine.FObjects);
-        ACount:=ACount+MergeTrees(XML,Engine.FTree.ClassTree);
+        ACount:=ACount+MergeTrees(XML,Engine.FTree.RootNode);
       Finally
       Finally
         FreeAndNil(Engine);
         FreeAndNil(Engine);
       end;
       end;

+ 127 - 131
utils/fpdoc/fpdocclasstree.pp

@@ -5,188 +5,184 @@ unit fpdocclasstree;
 interface
 interface
 
 
 uses
 uses
-  Classes, SysUtils, DOM, pastree;
+  Classes, SysUtils, DOM, pastree, contnrs;
 
 
 Type
 Type
+
+  { TPasElementNode }
+
+  TPasElementNode = Class
+  Private
+    FElement : TPasElement;
+    FChildren : TFPObjectList;
+    function GetChild(aIndex : Integer): TPasElementNode;
+    function GetChildCount: Integer;
+  Public
+    Constructor Create (aElement : TPaselement);
+    Destructor Destroy; override;
+    Procedure AddChild(C : TPasElementNode);
+    Procedure SortChildren;
+    Property Element : TPasElement Read FElement;
+    Property Children [aIndex : Integer] : TPasElementNode Read GetChild;
+    Property ChildCount : Integer Read GetChildCount;
+  end;
+
+  { TClassTreeBuilder }
+
   TClassTreeBuilder = Class
   TClassTreeBuilder = Class
   Private
   Private
-    FClassTree : TXMLDocument;
-    FTreeStart : TDomElement;
+    // Full name -> TDomElement;
+    FElementList : TFPObjectHashTable;
     FObjectKind : TPasObjKind;
     FObjectKind : TPasObjKind;
     FPackage: TPasPackage;
     FPackage: TPasPackage;
     FParentObject : TPasClassType;
     FParentObject : TPasClassType;
+    FRootNode : TPasElementNode;
+    FRootObjectName : string;
   Protected
   Protected
-    function LookForElement(PE: TDomElement; AElement: TPasElement; NoPath : Boolean): TDomNode;
-    function NodeMatch(N: TDomNode; AElement: TPasElement; NoPath : Boolean): Boolean;
-    Function AddToClassTree(AElement : TPasElement; Var ACount : Integer) : TDomElement;
+    function AddToList(aElement: TPasClassType): TPasElementNode;
   Public
   Public
     Constructor Create(APackage : TPasPackage; AObjectKind : TPasObjKind = okClass);
     Constructor Create(APackage : TPasPackage; AObjectKind : TPasObjKind = okClass);
     Destructor Destroy; override;
     Destructor Destroy; override;
     Function BuildTree(AObjects : TStringList) : Integer;
     Function BuildTree(AObjects : TStringList) : Integer;
-    Property ClassTree : TXMLDocument Read FClassTree;
+    Property RootNode : TPasElementNode Read FRootNode;
   end;
   end;
 
 
 implementation
 implementation
 
 
+{ TPasElementNode }
+
+function SortOnElementName(Item1, Item2: Pointer): Integer;
+begin
+  Result:=CompareText(TPasElementNode(Item1).Element.Name,TPasElementNode(Item2).Element.Name);
+end;
+
+function TPasElementNode.GetChild(aIndex : Integer): TPasElementNode;
+begin
+  if Assigned(FChildren) then
+    Result:=TPasElementNode(FChildren[aIndex])
+  else
+    Raise EListError.Create('Index out of range');
+end;
+
+function TPasElementNode.GetChildCount: Integer;
+begin
+  if Assigned(FChildren) then
+    Result:=FChildren.Count
+  else
+    Result:=0
+end;
+
+constructor TPasElementNode.Create(aElement: TPaselement);
+begin
+  FElement:=aElement;
+end;
+
+destructor TPasElementNode.Destroy;
+begin
+  FreeAndNil(FChildren);
+  inherited Destroy;
+end;
+
+procedure TPasElementNode.AddChild(C: TPasElementNode);
+begin
+  if FChildren=Nil then
+    FChildren:=TFPObjectList.Create(True);
+  FChildren.Add(C);
+end;
+
+procedure TPasElementNode.SortChildren;
+begin
+  if Assigned(FChildren) then
+    FChildren.Sort(@SortOnElementName);
+end;
+
 constructor TClassTreeBuilder.Create(APackage : TPasPackage;
 constructor TClassTreeBuilder.Create(APackage : TPasPackage;
   AObjectKind: TPasObjKind);
   AObjectKind: TPasObjKind);
 
 
 begin
 begin
-  FCLassTree:=TXMLDocument.Create;
   FPackage:=APAckage;
   FPackage:=APAckage;
   FObjectKind:=AObjectKind;
   FObjectKind:=AObjectKind;
   Case FObjectkind of
   Case FObjectkind of
-    okObject    : FParentObject:=TPasClassType.Create('System.TObject',FPackage);
-    okClass     : FParentObject:=TPasClassType.Create('System.TObject',FPackage);
-    okInterface : FParentObject:=TPasClassType.Create('System.IInterface',FPackage);
+    okInterface : FRootObjectName:='#rtl.System.IInterface';
+    okObject,
+    okClass    : FRootObjectName:='#rtl.System.TObject';
+  else
+    FRootObjectName:='#rtl.System.TObject';
   end;
   end;
+  FParentObject:=TPasClassType.Create(FRootObjectName,FPackage);
   FParentObject.ObjKind:=FObjectKind;
   FParentObject.ObjKind:=FObjectKind;
-  FTreeStart:=FClassTree.CreateElement('TObject');
-  FTreeStart['unit']:='System';
-  ClassTree.AppendChild(FTreeStart);
+  FRootNode:=TPasElementNode.Create(FParentObject);
+  FElementList:=TFPObjectHashTable.Create(False);
+  FElementList.Add(FRootObjectName,FRootNode);
 end;
 end;
 
 
 destructor TClassTreeBuilder.Destroy;
 destructor TClassTreeBuilder.Destroy;
 begin
 begin
   FreeAndNil(FParentObject);
   FreeAndNil(FParentObject);
-  FreeAndNil(FClassTree);
+  FreeAndNil(FRootNode);
+  FreeAndNil(FElementList);
   Inherited;
   Inherited;
 end;
 end;
 
 
-Function TClassTreeBuilder.BuildTree(AObjects : TStringList) : Integer;
+Function TClassTreeBuilder.AddToList(aElement : TPasClassType) : TPasElementNode;
 
 
 Var
 Var
-  I : Integer;
-  PC : TPasClassType;
+  aParentNode : TPasElementNode;
+  aName : String;
 
 
 begin
 begin
-  Result:=0;
-  AObjects.Sorted:=True;
-  For I:=0 to AObjects.Count-1 do
-    // Advanced records
-    if AObjects.Objects[i] is TPasClassType then
-      begin
-      PC:=AObjects.Objects[i] as TPasClassType;
-      If (PC.ObjKind=FObjectKind) and Not PC.IsForward then
-        AddToClassTree(PC,Result);
-      end;
-end;
-
-Function TClassTreeBuilder.NodeMatch(N : TDomNode; AElement : TPasElement; NoPath : Boolean) : Boolean;
-
-Var
-  PN,S,EN : String;
-
-begin
-  EN:=AELement.Name;
-  Result:=(N.NodeType=ELEMENT_NODE);
-  if Result then
+  if aElement=Nil then
+    aName:=FRootObjectName
+  else
+    begin
+    aName:=aElement.PathName;
+    end;
+  Result:=TPasElementNode(FElementList.Items[aName]);
+  if (Result=Nil) then
     begin
     begin
-    S:=UTF8Encode(N.NodeName);
-    if NoPath then
-      Begin
-      Result:=CompareText(S,EN)=0;
-      end
+    if aElement.AncestorType is TPasClassType then
+      aParentNode:=AddToList(aElement.AncestorType as TPasClassType)
     else
     else
-      begin
-      IF Assigned(Aelement.GetModule) then
-        PN:=Aelement.GetModule.PackageName
-      else
-        PN:=FPackage.Name;
-      S:=PN+'.'+UTF8Encode(TDomElement(N)['unit'])+'.'+S;
-      Result:=(CompareText(S,AElement.PathName)=0);
-      end;
-   end;
+      aParentNode:=FRootNode;
+    Result:=TPasElementNode.Create(aElement);
+    aParentNode.AddChild(Result);
+    FElementList.Add(aName,Result);
+    end;
 end;
 end;
 
 
-Function TClassTreeBuilder.LookForElement(PE : TDomElement; AElement : TPasElement; NoPath : boolean) : TDomNode;
 
 
-Var
-  N : TDomNode;
+Function TClassTreeBuilder.BuildTree(AObjects : TStringList) : Integer;
 
 
-begin
-//  Writeln('Enter TClassTreeBuilderLookForElement');
-  Result:=PE;
-  While (Result<>Nil) and Not NodeMatch(Result,AElement,NoPath) do
-    Result:=Result.NextSibling;
-  If (Result=Nil) then
-    if  Assigned(PE) then
-      begin
-      N:=PE.FirstChild;
-      While (Result=Nil) and (N<>Nil) do
-        begin
-        if (N.NodeType=ELEMENT_NODE) then
-          begin
-          Result:=LookForElement(N as TDomElement,AElement,NoPath);
-          end;
-        N:=N.NextSibling;
-        end;
-      end;
-//  Writeln('Exit TClassTreeBuilderLookForElement');
-end;
+(*
+Procedure DumpNode(Prefix : String; N : TPasElementNode);
+
+  Var
+    I : Integer;
+
+  begin
+    Writeln(Prefix,N.FElement.Name);
+    if Assigned(N.FChildren) then
+       For I:=0 to N.FChildren.Count-1 do
+         DumpNode(Prefix+'  ',TPasElementNode(N.FChildren[i]));
+  end;
+*)
 
 
-Function TClassTreeBuilder.AddToClassTree(AElement : TPasElement; Var ACount : Integer) : TDomElement;
-// there are several codepaths that use uninitialized variables. (N,PE)
-// I initialized them to nil to at least make failures deterministic.
 Var
 Var
+  I : Integer;
   PC : TPasClassType;
   PC : TPasClassType;
-  PE : TDomElement;
-  M : TPasModule;
-  N : TDomNode;
 
 
 begin
 begin
-
-//  Writeln('Enter TClassTreeBuilder.AddToClassTree');
-  //if Assigned(AElement) then
-    //Writeln('Addtoclasstree : ',aElement.Name);
-  Result:=Nil; M:=Nil; N:=Nil;PE:=NIL;PC:=Nil;
-  If (AElement=Nil) then
-    begin
-    Result:=FTreeStart;
-    Exit;
-    end
-  else If (AElement is TPasUnresolvedTypeRef) then
-    begin
-    N:=LookForElement(FTreeStart,AElement,True);
-    If (N=Nil) then
-      PE:=FTreeStart;
-    end
-  else If (AElement is TPasClassType) then
-    begin
-    if (AElement=FParentObject) then
-      Result:=FTreeStart
-    else
-      begin
-      PC:=AElement as TPasClassType;
-      PE:=AddToClassTree(PC.AncestorType,ACount);
-      if PE=Nil then
-        PE:=FTreeStart;
-      N:=LookForElement(PE,PC,False);
-      end
-    end;
-  If (N<>Nil) then
-    begin
-    Result:=N as TDomElement
-    end
-  else if AElement.Name<>'' then
-    begin // N=NIL, PE might be nil.
-    Inc(ACount);
-    Result:=FClassTree.CreateElement(UTF8Decode(AElement.Name));
-    If Not (AElement is TPasUnresolvedTypeRef) then
-      begin
-      M:=AElement.GetModule;
-      if Assigned(M) then
-        Result['unit']:=UTF8Decode(M.Name);
-      end;
-    if PE=Nil then
+  Result:=0;
+  For I:=0 to AObjects.Count-1 do
+    // Advanced records
+    if AObjects.Objects[i] is TPasClassType then
       begin
       begin
-      PE:=FTreeStart
+      PC:=AObjects.Objects[i] as TPasClassType;
+      AddToList(PC);
       end;
       end;
-    // if not assigned, probably needs to be assigned to something else.
-    if assigned(PE) then
-      PE.AppendChild(Result);
-    end;
 end;
 end;
 
 
+
+
 end.
 end.
 
 

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio