Browse Source

Merge branch 'main' into basemath

florian 1 year ago
parent
commit
19fe97c02c
100 changed files with 5673 additions and 1708 deletions
  1. 1064 8
      compiler/aarch64/aoptcpu.pas
  2. 3 1
      compiler/aarch64/cgcpu.pas
  3. 8 0
      compiler/aarch64/cpubase.pas
  4. 5 5
      compiler/aarch64/naarch64util.pas
  5. 15 2
      compiler/aarch64/ncpuadd.pas
  6. 44 10
      compiler/aarch64/ncpuinl.pas
  7. 10 0
      compiler/aarch64/ncpumat.pas
  8. 2 1
      compiler/aasmcnst.pas
  9. 19 4
      compiler/aasmdata.pas
  10. 82 3
      compiler/aoptobj.pas
  11. 99 48
      compiler/arm/aoptcpu.pas
  12. 18 0
      compiler/arm/aoptcpub.pas
  13. 2 3
      compiler/arm/cgcpu.pas
  14. 4 0
      compiler/arm/narmadd.pas
  15. 41 10
      compiler/arm/narminl.pas
  16. 5 5
      compiler/arm/narmutil.pas
  17. 247 0
      compiler/armgen/aoptarm.pas
  18. 73 27
      compiler/assemble.pas
  19. 9 7
      compiler/avr/aoptcpu.pas
  20. 5 4
      compiler/avr/navrutil.pas
  21. 2 0
      compiler/browcol.pas
  22. 24 0
      compiler/cgutils.pas
  23. 19 1
      compiler/compiler.pas
  24. 4 0
      compiler/compinnr.pas
  25. 1 1
      compiler/cresstr.pas
  26. 401 0
      compiler/ctask.pas
  27. 2 0
      compiler/dbgdwarf.pas
  28. 4 2
      compiler/defcmp.pas
  29. 9 0
      compiler/defutil.pas
  30. 23 9
      compiler/finput.pas
  31. 123 37
      compiler/fmodule.pas
  32. 353 242
      compiler/fppu.pas
  33. 0 2
      compiler/globals.pas
  34. 173 74
      compiler/globstat.pas
  35. 52 9
      compiler/hlcgobj.pas
  36. 18 7
      compiler/htypechk.pas
  37. 10 0
      compiler/i386/aoptcpu.pas
  38. 4 0
      compiler/i386/cpuinfo.pas
  39. 9 0
      compiler/i386/n386inl.pas
  40. 1 1
      compiler/i386/n386mem.pas
  41. 1 1
      compiler/i8086/n8086add.pas
  42. 15 0
      compiler/i8086/n8086inl.pas
  43. 1 1
      compiler/i8086/n8086mem.pas
  44. 1 1
      compiler/jvm/njvmcnv.pas
  45. 13 10
      compiler/jvm/njvmutil.pas
  46. 2 2
      compiler/llvm/nllvmbas.pas
  47. 1 1
      compiler/loongarch64/cgcpu.pas
  48. 13 0
      compiler/loongarch64/ncpuadd.pas
  49. 9 0
      compiler/loongarch64/ncpuinl.pas
  50. 4 1
      compiler/msg/errore.msg
  51. 3 2
      compiler/msgidx.inc
  52. 355 353
      compiler/msgtxt.inc
  53. 227 80
      compiler/nadd.pas
  54. 47 13
      compiler/nbas.pas
  55. 5 5
      compiler/ncal.pas
  56. 1 1
      compiler/ncgadd.pas
  57. 4 4
      compiler/ncgbas.pas
  58. 4 0
      compiler/ncginl.pas
  59. 3 3
      compiler/ncgld.pas
  60. 3 3
      compiler/ncgmem.pas
  61. 25 13
      compiler/ncgrtti.pas
  62. 1 1
      compiler/ncgutil.pas
  63. 117 124
      compiler/ncnv.pas
  64. 1 1
      compiler/ncon.pas
  65. 21 8
      compiler/nflw.pas
  66. 42 26
      compiler/ngenutil.pas
  67. 1 1
      compiler/ngtcon.pas
  68. 332 9
      compiler/ninl.pas
  69. 101 11
      compiler/nld.pas
  70. 88 7
      compiler/nmat.pas
  71. 125 6
      compiler/nmem.pas
  72. 63 61
      compiler/node.pas
  73. 4 4
      compiler/nopt.pas
  74. 18 6
      compiler/nutils.pas
  75. 28 0
      compiler/ogbase.pas
  76. 37 1
      compiler/ogelf.pas
  77. 1 1
      compiler/optbase.pas
  78. 1 1
      compiler/optconstprop.pas
  79. 11 4
      compiler/optcse.pas
  80. 0 1
      compiler/optdeadstore.pas
  81. 10 11
      compiler/optdfa.pas
  82. 2 2
      compiler/options.pas
  83. 1 1
      compiler/optloop.pas
  84. 1 1
      compiler/optvirt.pas
  85. 114 112
      compiler/parser.pas
  86. 11 12
      compiler/pass_1.pas
  87. 5 5
      compiler/pass_2.pas
  88. 20 1
      compiler/pbase.pas
  89. 1 2
      compiler/pdecl.pas
  90. 63 18
      compiler/pdecobj.pas
  91. 8 3
      compiler/pdecvar.pas
  92. 17 8
      compiler/pexpr.pas
  93. 17 5
      compiler/pgenutil.pas
  94. 1 1
      compiler/pinline.pas
  95. 589 230
      compiler/pmodules.pas
  96. 2 0
      compiler/pparautl.pas
  97. 1 1
      compiler/ppcgen/ngppcadd.pas
  98. 87 0
      compiler/ppcloongarch64.lpi
  99. 2 1
      compiler/ppu.pas
  100. 5 4
      compiler/pstatmnt.pas

+ 1064 - 8
compiler/aarch64/aoptcpu.pas

@@ -35,7 +35,7 @@ Interface
       globtype, globals,
       globtype, globals,
       cutils,
       cutils,
       cgbase, cpubase, aasmtai, aasmcpu,
       cgbase, cpubase, aasmtai, aasmcpu,
-      aopt, aoptcpub, aoptarm;
+      aopt, aoptcpub, aoptarm, aoptobj;
 
 
     Type
     Type
       TCpuAsmOptimizer = class(TARMAsmOptimizer)
       TCpuAsmOptimizer = class(TARMAsmOptimizer)
@@ -54,8 +54,6 @@ Interface
       private
       private
         function RemoveSuperfluousFMov(const p: tai; movp: tai; const optimizer: string): boolean;
         function RemoveSuperfluousFMov(const p: tai; movp: tai; const optimizer: string): boolean;
         function OptPass1Shift(var p: tai): boolean;
         function OptPass1Shift(var p: tai): boolean;
-        function OptPostCMP(var p: tai): boolean;
-        function OptPostAnd(var p: tai): Boolean;
         function OptPass1Data(var p: tai): boolean;
         function OptPass1Data(var p: tai): boolean;
         function OptPass1FData(var p: tai): Boolean;
         function OptPass1FData(var p: tai): Boolean;
         function OptPass1STP(var p: tai): boolean;
         function OptPass1STP(var p: tai): boolean;
@@ -65,15 +63,33 @@ Interface
         function OptPass1B(var p: tai): boolean;
         function OptPass1B(var p: tai): boolean;
         function OptPass1SXTW(var p: tai): Boolean;
         function OptPass1SXTW(var p: tai): Boolean;
 
 
+        function OptPass2CSEL(var p: tai): Boolean;
+        function OptPass2B(var p: tai): Boolean;
         function OptPass2LDRSTR(var p: tai): boolean;
         function OptPass2LDRSTR(var p: tai): boolean;
+        function OptPass2MOV(var p: tai): Boolean;
+
+        function PostPeepholeOptAND(var p: tai): Boolean;
+        function PostPeepholeOptCMP(var p: tai): boolean;
+        function PostPeepholeOptTST(var p: tai): Boolean;
+      protected
+        { Like UpdateUsedRegs, but ignores deallocations }
+        class procedure UpdateIntRegsNoDealloc(var AUsedRegs: TAllUsedRegs; p: Tai); static;
+
+        { Attempts to allocate a volatile integer register for use between p and hp,
+          using AUsedRegs for the current register usage information.  Returns NR_NO
+          if no free register could be found }
+        function GetIntRegisterBetween(RegSize: TSubRegister; var AUsedRegs: TAllUsedRegs; p, hp: tai; DontAlloc: Boolean = False): TRegister;
       End;
       End;
 
 
 Implementation
 Implementation
 
 
   uses
   uses
     aasmbase,
     aasmbase,
+    aoptbase,
     aoptutils,
     aoptutils,
     cgutils,
     cgutils,
+    procinfo,
+    paramgr,
     verbose;
     verbose;
 
 
 {$ifdef DEBUG_AOPTCPU}
 {$ifdef DEBUG_AOPTCPU}
@@ -86,6 +102,60 @@ Implementation
       SPeepholeOptimization = '';
       SPeepholeOptimization = '';
 {$endif DEBUG_AOPTCPU}
 {$endif DEBUG_AOPTCPU}
 
 
+      MAX_CSEL_INSTRUCTIONS = 8;
+      MAX_CSEL_REGISTERS = 30;
+
+    type
+      TCSELTrackingState = (tsInvalid, tsSimple, tsDetour, tsBranching,
+        tsDouble, tsDoubleBranchSame, tsDoubleBranchDifferent, tsDoubleSecondBranching,
+        tsProcessed);
+
+      { For OptPass2Jcc }
+      TCSELTracking = object
+      private
+        CSELScore, ConstCount: LongInt;
+
+        RegWrites: array[0..MAX_CSEL_INSTRUCTIONS*2 - 1] of TRegister;
+
+        ConstRegs: array[0..MAX_CSEL_REGISTERS - 1] of TRegister;
+        ConstVals: array[0..MAX_CSEL_REGISTERS - 1] of TCGInt;
+        ConstSizes: array[0..MAX_CSEL_REGISTERS - 1] of TSubRegister; { May not match ConstRegs if one is shared over multiple CSELs. }
+        ConstMovs: array[0..MAX_CSEL_REGISTERS - 1] of tai; { Location of initialisation instruction }
+
+        ConstWriteSizes: array[0..first_int_imreg - 1] of TSubRegister; { Largest size of register written. }
+
+        fOptimizer: TCpuAsmOptimizer;
+
+        fLabel: TAsmSymbol;
+
+        fInsertionPoint,
+        fCondition,
+        fInitialJump,
+        fFirstMovBlock,
+        fFirstMovBlockStop,
+        fSecondJump,
+        fThirdJump,
+        fSecondMovBlock,
+        fSecondMovBlockStop,
+        fMidLabel,
+        fEndLabel,
+        fAllocationRange: tai;
+
+        fState: TCSELTrackingState;
+
+        function TryCSELConst(p, start, stop: tai; var Count: LongInt): Boolean;
+        function InitialiseBlock(BlockStart, OneBeforeBlock: tai; out BlockStop: tai; out EndJump: tai): Boolean;
+        function AnalyseMOVBlock(BlockStart, BlockStop, SearchStart: tai): LongInt;
+      public
+        RegisterTracking: TAllUsedRegs;
+        constructor Init(Optimizer: TCpuAsmOptimizer; var p_initialjump, p_initialmov: tai; var AFirstLabel: TAsmLabel);
+        destructor Done;
+        procedure Process(out new_p: tai);
+        property State: TCSELTrackingState read fState;
+      end;
+
+      PCSELTracking = ^TCSELTracking;
+
   function CanBeCond(p : tai) : boolean;
   function CanBeCond(p : tai) : boolean;
     begin
     begin
       result:=(p.typ=ait_instruction) and (taicpu(p).condition=C_None);
       result:=(p.typ=ait_instruction) and (taicpu(p).condition=C_None);
@@ -921,6 +991,97 @@ Implementation
     end;
     end;
 
 
 
 
+  function TCpuAsmOptimizer.OptPass2B(var p: tai): Boolean;
+    var
+      hp1: tai;
+      LabelSym: TAsmLabel;
+      CSELTracking: PCSELTracking;
+    begin
+      Result := False;
+      if (taicpu(p).condition = C_None) and
+        IsJumpToLabel(taicpu(p)) then
+        begin
+          { Check for:
+                B   @lbl
+                ...
+              @Lbl:
+                RET
+
+            Change to:
+                RET (and reduce reference count on label)
+          }
+
+          LabelSym := TAsmLabel(JumpTargetOp(taicpu(p))^.ref^.symbol);
+          hp1 := GetLabelWithSym(LabelSym);
+          if Assigned(hp1) and
+            GetNextInstruction(hp1, hp1) and
+            (hp1.typ = ait_instruction) and
+            (taicpu(hp1).opcode = A_RET) then
+            begin
+              DebugMsg(SPeepholeOptimization + 'B -> RET since a RET immediately follows the destination label (B2Ret)', p);
+              taicpu(p).ops := 0;
+              taicpu(p).clearop(0);
+              taicpu(p).is_jmp := false;
+              taicpu(p).opcode := A_RET;
+
+              { Make sure the label is dereferenced now }
+              LabelSym.decrefs;
+
+              Result := True;
+              Exit;
+            end;
+        end;
+
+
+      if (taicpu(p).condition <> C_None) and
+        IsJumpToLabel(taicpu(p)) and
+        GetNextInstruction(p, hp1) and
+        (hp1.typ = ait_instruction) and
+        (taicpu(hp1).opcode = A_MOV) then
+        begin
+          { check for
+                jCC   xxx
+                <several movs>
+             xxx:
+
+           Also spot:
+                Jcc   xxx
+                <several movs>
+                jmp   xxx
+
+           Change to:
+                <several csets with inverted condition>
+                jmp   xxx  (only for the 2nd case)
+          }
+          CSELTracking := New(PCSELTracking, Init(Self, p, hp1, TAsmLabel(JumpTargetOp(taicpu(p))^.ref^.symbol)));
+
+          if CSELTracking^.State <> tsInvalid then
+            begin
+              CSELTracking^.Process(p);
+              Result := True;
+            end;
+
+          CSELTracking^.Done;
+        end;
+    end;
+
+
+  function TCpuAsmOptimizer.OptPass2CSEL(var p: tai): Boolean;
+    begin
+      Result := False;
+
+      { Csel r0,r1,r1,cond -> mov r0,r1 }
+      if (taicpu(p).oper[1]^.reg = taicpu(p).oper[2]^.reg) then
+        begin
+          DebugMsg(SPeepholeOptimization + 'CSel2Mov (identical true/false registers)', p);
+          taicpu(p).opcode := A_MOV;
+          taicpu(p).ops := 2;
+          Result := True;
+          Exit;
+        end;
+    end;
+
+
   function TCpuAsmOptimizer.OptPass2LDRSTR(var p: tai): boolean;
   function TCpuAsmOptimizer.OptPass2LDRSTR(var p: tai): boolean;
     var
     var
       hp1, hp1_last: tai;
       hp1, hp1_last: tai;
@@ -1076,7 +1237,55 @@ Implementation
     end;
     end;
 
 
 
 
-  function TCpuAsmOptimizer.OptPostAnd(var p: tai): Boolean;
+  function TCpuAsmOptimizer.OptPass2MOV(var p: tai): Boolean;
+    var
+      hp1: tai;
+      X: Integer;
+    begin
+      Result := False;
+
+      { Merge MOV and CSEL instructions left behind by OptPass2B - that is,
+        change:
+
+          mov  r0,r1
+          csel r0,r2,r0,cond
+
+        To:
+          csel r0,r2,r1,cond
+
+        (Also if r0 is the second operand)
+      }
+      if (taicpu(p).oper[1]^.typ = top_reg) and
+        GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
+        (hp1.typ = ait_instruction) and
+        (taicpu(hp1).opcode = A_CSEL) and
+        (taicpu(hp1).oper[0]^.reg = taicpu(p).oper[0]^.reg) and
+        not RegModifiedBetween(taicpu(p).oper[1]^.reg, p, hp1) then
+        begin
+          { Use "Result" to note if a change was made so we only have to do
+            expensive register allocation once }
+          for X := 1 to 2 do
+            if (taicpu(hp1).oper[X]^.reg = taicpu(p).oper[0]^.reg) then
+              begin
+                taicpu(hp1).oper[X]^.reg := taicpu(p).oper[1]^.reg;
+                Result := True;
+              end;
+
+          if Result then
+            begin
+              DebugMSg(SPeepholeOptimization + 'MovCSel2CSel', p);
+              { Don't need to allocate the zero register - so save time by
+                skipping it in this case }
+              if getsupreg(taicpu(p).oper[1]^.reg) <> RS_XZR then
+                AllocRegBetween(taicpu(p).oper[1]^.reg, p, hp1, UsedRegs);
+              RemoveCurrentP(p);
+              Exit;
+            end;
+        end;
+    end;
+
+
+  function TCpuAsmOptimizer.PostPeepholeOptAND(var p: tai): Boolean;
     var
     var
       hp1, hp2: tai;
       hp1, hp2: tai;
       hp3: taicpu;
       hp3: taicpu;
@@ -1126,7 +1335,7 @@ Implementation
     end;
     end;
 
 
 
 
-  function TCpuAsmOptimizer.OptPostCMP(var p : tai): boolean;
+  function TCpuAsmOptimizer.PostPeepholeOptCMP(var p : tai): boolean;
     var
     var
      hp1,hp2: tai;
      hp1,hp2: tai;
     begin
     begin
@@ -1168,6 +1377,46 @@ Implementation
     end;
     end;
 
 
 
 
+  function TCpuAsmOptimizer.PostPeepholeOptTST(var p : tai): boolean;
+    var
+      hp1: tai;
+      hp3: taicpu;
+      bitval : cardinal;
+    begin
+      Result:=false;
+      {
+        tst reg1,<const=power of 2>
+        b.e/b.ne label
+
+        into
+
+        tb(n)z reg0,<power of 2>,label
+      }
+      if MatchOpType(taicpu(p),top_reg,top_const) and
+        (PopCnt(QWord(taicpu(p).oper[1]^.val))=1) and
+        GetNextInstruction(p,hp1) and
+        MatchInstruction(hp1,A_B,[C_EQ,C_NE],[PF_None]) then
+        begin
+           bitval:=BsfQWord(qword(taicpu(p).oper[1]^.val));
+           case taicpu(hp1).condition of
+            C_NE:
+              hp3:=taicpu.op_reg_const_ref(A_TBNZ,taicpu(p).oper[0]^.reg,bitval,taicpu(hp1).oper[0]^.ref^);
+            C_EQ:
+              hp3:=taicpu.op_reg_const_ref(A_TBZ,taicpu(p).oper[0]^.reg,bitval,taicpu(hp1).oper[0]^.ref^);
+            else
+              Internalerror(2021100210);
+          end;
+          taicpu(hp3).fileinfo:=taicpu(p).fileinfo;
+          asml.insertafter(hp3, p);
+
+          RemoveInstruction(hp1);
+          RemoveCurrentP(p, hp3);
+          DebugMsg(SPeepholeOptimization + 'TST; B(E/NE) -> TB(Z/NZ) done', p);
+          Result:=true;
+        end;
+    end;
+
+
   function TCpuAsmOptimizer.PrePeepHoleOptsCpu(var p: tai): boolean;
   function TCpuAsmOptimizer.PrePeepHoleOptsCpu(var p: tai): boolean;
     begin
     begin
       result := false;
       result := false;
@@ -1260,9 +1509,19 @@ Implementation
       if p.typ=ait_instruction then
       if p.typ=ait_instruction then
         begin
         begin
           case taicpu(p).opcode of
           case taicpu(p).opcode of
+            A_AND:
+              Result := OptPass2AND(p);
+            A_B:
+              Result := OptPass2B(p);
+            A_CSEL:
+              Result := OptPass2CSEL(p);
+            A_MOV:
+              Result := OptPass2MOV(p);
             A_LDR,
             A_LDR,
             A_STR:
             A_STR:
-              Result:=OptPass2LDRSTR(p);
+              Result := OptPass2LDRSTR(p);
+            A_TST:
+              Result := OptPass2TST(p);
             else
             else
               ;
               ;
           end;
           end;
@@ -1277,15 +1536,812 @@ Implementation
         begin
         begin
           case taicpu(p).opcode of
           case taicpu(p).opcode of
             A_CMP:
             A_CMP:
-              Result:=OptPostCMP(p);
+              Result:=PostPeepholeOptCMP(p);
             A_AND:
             A_AND:
-              Result:=OptPostAnd(p);
+              Result:=PostPeepholeOptAND(p);
+            A_TST:
+              Result:=PostPeepholeOptTST(p);
             else
             else
               ;
               ;
           end;
           end;
         end;
         end;
     end;
     end;
 
 
+
+  class procedure TCpuAsmOptimizer.UpdateIntRegsNoDealloc(var AUsedRegs: TAllUsedRegs; p: Tai);
+    begin
+      { Update integer registers, ignoring deallocations }
+      repeat
+        while assigned(p) and
+              ((p.typ in (SkipInstr - [ait_RegAlloc])) or
+               (p.typ = ait_label) or
+               ((p.typ = ait_marker) and
+                (tai_Marker(p).Kind in [mark_AsmBlockEnd,mark_NoLineInfoStart,mark_NoLineInfoEnd]))) do
+             p := tai(p.next);
+        while assigned(p) and
+              (p.typ=ait_RegAlloc) Do
+          begin
+            if (getregtype(tai_regalloc(p).reg) = R_INTREGISTER) then
+              begin
+                case tai_regalloc(p).ratype of
+                  ra_alloc :
+                    IncludeRegInUsedRegs(tai_regalloc(p).reg, AUsedRegs);
+                  else
+                    ;
+                end;
+              end;
+            p := tai(p.next);
+          end;
+      until not(assigned(p)) or
+            (not(p.typ in SkipInstr) and
+             not((p.typ = ait_label) and
+                 labelCanBeSkipped(tai_label(p))));
+    end;
+
+  { Attempts to allocate a volatile integer register for use between p and hp,
+    using AUsedRegs for the current register usage information.  Returns NR_NO
+    if no free register could be found }
+  function TCpuAsmOptimizer.GetIntRegisterBetween(RegSize: TSubRegister; var AUsedRegs: TAllUsedRegs; p, hp: tai; DontAlloc: Boolean = False): TRegister;
+    var
+      RegSet: TCPURegisterSet;
+      CurrentSuperReg: Integer;
+      CurrentReg: TRegister;
+      Currentp: tai;
+      Breakout: Boolean;
+    begin
+      Result := NR_NO;
+      RegSet :=
+        paramanager.get_volatile_registers_int(current_procinfo.procdef.proccalloption) +
+        current_procinfo.saved_regs_int;
+(*
+      { Don't use the frame register unless explicitly allowed (fixes i40111) }
+      if ([cs_useebp, cs_userbp] * current_settings.optimizerswitches) = [] then
+        Exclude(RegSet, RS_FRAME_POINTER_REG);
+*)
+      for CurrentSuperReg in RegSet do
+        begin
+          CurrentReg := newreg(R_INTREGISTER, TSuperRegister(CurrentSuperReg), RegSize);
+          if not AUsedRegs[R_INTREGISTER].IsUsed(CurrentReg)
+            then
+            begin
+              Currentp := p;
+              Breakout := False;
+              while not Breakout and GetNextInstruction(Currentp, Currentp) and (Currentp <> hp) do
+                begin
+                  case Currentp.typ of
+                    ait_instruction:
+                      begin
+                        if RegInInstruction(CurrentReg, Currentp) then
+                          begin
+                            Breakout := True;
+                            Break;
+
+                          end;
+                        { Cannot allocate across an unconditional jump }
+                        if is_calljmpmaybeuncondret(taicpu(Currentp).opcode) and (taicpu(Currentp).condition = C_None) then
+                          Exit;
+                      end;
+                    ait_marker:
+                      { Don't try anything more if a marker is hit }
+                      Exit;
+                    ait_regalloc:
+                      if (tai_regalloc(Currentp).ratype <> ra_dealloc) and SuperRegistersEqual(CurrentReg, tai_regalloc(Currentp).reg) then
+                        begin
+                          Breakout := True;
+                          Break;
+                        end;
+                    else
+                      ;
+                  end;
+                end;
+
+              if Breakout then
+                { Try the next register }
+                Continue;
+
+              { We have a free register available }
+              Result := CurrentReg;
+              if not DontAlloc then
+                AllocRegBetween(CurrentReg, p, hp, AUsedRegs);
+              Exit;
+            end;
+        end;
+    end;
+
+
+  function TCSELTracking.InitialiseBlock(BlockStart, OneBeforeBlock: tai; out BlockStop: tai; out EndJump: tai): Boolean;
+    begin
+      Result := False;
+      EndJump := nil;
+      BlockStop := nil;
+
+      while (BlockStart <> fOptimizer.BlockEnd) and
+        { stop on labels }
+        (BlockStart.typ <> ait_label) do
+        begin
+          { Keep track of all integer registers that are used }
+          fOptimizer.UpdateIntRegsNoDealloc(RegisterTracking, tai(OneBeforeBlock.Next));
+          if BlockStart.typ = ait_instruction then
+            begin
+              if MatchInstruction(BlockStart, A_B, [C_None], []) then
+                begin
+                  if not IsJumpToLabel(taicpu(BlockStart)) or
+                    (JumpTargetOp(taicpu(BlockStart))^.ref^.index <> NR_NO) then
+                    Exit;
+
+                  EndJump := BlockStart;
+                  Break;
+                end
+              { Check to see if we have a valid MOV instruction instead }
+              else if (taicpu(BlockStart).opcode <> A_MOV) or
+                { Can't include the stack pointer in CSEL }
+                fOptimizer.RegInInstruction(NR_SP, BlockStart) then
+                begin
+                  Exit;
+                end
+              else
+                { This will be a valid MOV }
+                fAllocationRange := BlockStart;
+            end;
+
+          OneBeforeBlock := BlockStart;
+          fOptimizer.GetNextInstruction(BlockStart, BlockStart);
+        end;
+
+      if (BlockStart = fOptimizer.BlockEnd) then
+        Exit;
+
+      BlockStop := BlockStart;
+      Result := True;
+    end;
+
+
+  function TCSELTracking.AnalyseMOVBlock(BlockStart, BlockStop, SearchStart: tai): LongInt;
+    var
+      hp1: tai;
+      RefModified: Boolean;
+    begin
+      Result := 0;
+      hp1 := BlockStart;
+      RefModified := False; { As long as the condition is inverted, this can be reset }
+
+      while assigned(hp1) and
+        (hp1 <> BlockStop) do
+        begin
+          case hp1.typ of
+            ait_instruction:
+              if MatchInstruction(hp1, A_MOV, []) then
+                begin
+                  Inc(Result);
+                  if taicpu(hp1).oper[1]^.typ = top_reg then
+                    begin
+                      Inc(Result);
+                    end
+                  else if not (cs_opt_size in current_settings.optimizerswitches) and
+                    { CSEL with constants grows the code size }
+                    TryCSELConst(hp1, SearchStart, BlockStop, Result) then
+                    begin
+                      { Register was reserved by TryCSELConst and
+                        stored on ConstRegs }
+                    end
+                  else
+                    begin
+                      Result := -1;
+                      Exit;
+                    end;
+                end
+              else
+                begin
+                  Result := -1;
+                  Exit;
+                end;
+            else
+              { Most likely an align };
+          end;
+          fOptimizer.GetNextInstruction(hp1, hp1);
+        end;
+    end;
+
+
+  constructor TCSELTracking.Init(Optimizer: TCpuAsmOptimizer; var p_initialjump, p_initialmov: tai; var AFirstLabel: TAsmLabel);
+
+    { For the tsBranching type, increase the weighting score to account for the new conditional jump
+      (this is done as a separate stage because the double types are extensions of the branching type,
+      but we can't discount the conditional jump until the last step) }
+    procedure EvaluateBranchingType;
+      begin
+        Inc(CSELScore);
+        if (CSELScore > MAX_CSEL_INSTRUCTIONS) then
+          { Too many instructions to be worthwhile }
+          fState := tsInvalid;
+      end;
+
+    var
+      hp1: tai;
+      Count: Integer;
+    begin
+      { Table of valid CSEL block types
+
+        Block type                  2nd Jump    Mid-label   2nd MOVs    3rd Jump    End-label
+        ----------                  ---------   ---------   ---------   ---------   ---------
+        tsSimple                        X          Yes          X           X           X
+        tsDetour                      = 1st         X           X           X           X
+        tsBranching                  <> Mid        Yes          X           X           X
+        tsDouble                    End-label      Yes *       Yes          X          Yes
+        tsDoubleBranchSame           <> Mid        Yes *       Yes        = 2nd         X
+        tsDoubleBranchDifferent      <> Mid        Yes *       Yes       <> 2nd         X
+        tsDoubleSecondBranching     End-label      Yes *       Yes       <> 2nd        Yes
+
+        * Only one reference allowed
+      }
+
+      hp1 := nil; { To prevent compiler warnings }
+
+      Optimizer.CopyUsedRegs(RegisterTracking);
+      fOptimizer := Optimizer;
+      fLabel := AFirstLabel;
+
+      CSELScore := 0;
+      ConstCount := 0;
+
+      { Initialise RegWrites, ConstRegs, ConstVals, ConstSizes, ConstWriteSizes and ConstMovs }
+      FillChar(RegWrites[0], MAX_CSEL_INSTRUCTIONS * 2 * SizeOf(TRegister), 0);
+      FillChar(ConstRegs[0], MAX_CSEL_REGISTERS * SizeOf(TRegister), 0);
+      FillChar(ConstVals[0], MAX_CSEL_REGISTERS * SizeOf(TCGInt), 0);
+      FillChar(ConstSizes[0], MAX_CSEL_REGISTERS * SizeOf(TSubRegister), 0);
+      FillChar(ConstWriteSizes[0], first_int_imreg * SizeOf(TOpSize), 0);
+      FillChar(ConstMovs[0], MAX_CSEL_REGISTERS * SizeOf(taicpu), 0);
+
+      fInsertionPoint := p_initialjump;
+      fCondition := nil;
+      fInitialJump := p_initialjump;
+      fFirstMovBlock := p_initialmov;
+      fFirstMovBlockStop := nil;
+
+      fSecondJump := nil;
+      fSecondMovBlock := nil;
+      fSecondMovBlockStop := nil;
+
+      fMidLabel := nil;
+
+      fSecondJump := nil;
+      fSecondMovBlock := nil;
+
+      fEndLabel := nil;
+
+      fAllocationRange := nil;
+
+      { Assume it all goes horribly wrong! }
+      fState := tsInvalid;
+
+      { Look backwards at the comparisons to get an accurate picture of register usage and a better position for any MOV const,reg insertions }
+      if Optimizer.GetLastInstruction(p_initialjump, fCondition) and
+        (
+          MatchInstruction(fCondition, [A_CMP, A_CMN, A_TST], []) or
+          (
+            (fCondition.typ = ait_instruction) and
+            (taicpu(fCondition).opcode = A_AND) and
+            (taicpu(fCondition).oppostfix = PF_S)
+          )
+        ) then
+        begin
+          { Mark all the registers in the comparison as 'in use', even if they've just been deallocated }
+          for Count := 0 to taicpu(fCondition).ops - 1 do
+            with taicpu(fCondition).oper[Count]^ do
+              case typ of
+                top_reg:
+                  if getregtype(reg) = R_INTREGISTER then
+                    Optimizer.IncludeRegInUsedRegs(reg, RegisterTracking);
+                top_ref:
+                  begin
+                    if
+                      (ref^.base <> NR_NO) then
+                      Optimizer.IncludeRegInUsedRegs(ref^.base, RegisterTracking);
+
+                    if (ref^.index <> NR_NO) then
+                      Optimizer.IncludeRegInUsedRegs(ref^.index, RegisterTracking);
+                  end
+                else
+                  ;
+              end;
+
+          { When inserting instructions before hp_prev, try to insert them
+            before the allocation of the FLAGS register }
+          if not SetAndTest(Optimizer.FindRegAllocBackward(NR_DEFAULTFLAGS, tai(fCondition.Previous)), fInsertionPoint) or
+            (tai_regalloc(fInsertionPoint).ratype = ra_dealloc) then
+            { If not found, set it equal to the condition so it's something sensible }
+            fInsertionPoint := fCondition;
+
+        end
+      else
+        fCondition := nil;
+
+      { When inserting instructions, try to insert them before the allocation of the FLAGS register }
+      if SetAndTest(Optimizer.FindRegAllocBackward(NR_DEFAULTFLAGS, tai(p_initialjump.Previous)), hp1) and
+        (tai_regalloc(hp1).ratype <> ra_dealloc) then
+        { If not found, set it equal to p so it's something sensible }
+        fInsertionPoint := hp1;
+
+      hp1 := p_initialmov;
+
+      if not InitialiseBlock(p_initialmov, p_initialjump, fFirstMovBlockStop, fSecondJump) then
+        Exit;
+
+      hp1 := fFirstMovBlockStop; { Will either be on a label or a jump }
+
+      if (hp1.typ <> ait_label) then { should be on a jump }
+        begin
+          if not Optimizer.GetNextInstruction(hp1, fMidLabel) or (fMidLabel.typ <> ait_label) then
+            { Need a label afterwards }
+            Exit;
+        end
+      else
+        fMidLabel := hp1;
+
+      if tai_label(fMidLabel).labsym <> AFirstLabel then
+        { Not the correct label }
+        fMidLabel := nil;
+
+      if not Assigned(fSecondJump) and not Assigned(fMidLabel) then
+        { If there's neither a 2nd jump nor correct label, then it's invalid
+          (see above table) }
+        Exit;
+
+      { Analyse the first block of MOVs more closely }
+      CSELScore := AnalyseMOVBlock(fFirstMovBlock, fFirstMovBlockStop, fInsertionPoint);
+
+      if Assigned(fSecondJump) then
+        begin
+          if (JumpTargetOp(taicpu(fSecondJump))^.ref^.symbol = AFirstLabel) then
+            begin
+              fState := tsDetour
+            end
+          else
+            begin
+              { Need the correct mid-label for this one }
+              if not Assigned(fMidLabel) then
+                Exit;
+
+              fState := tsBranching;
+            end;
+        end
+      else
+        { No jump. but mid-label is present }
+        fState := tsSimple;
+
+      if (CSELScore > MAX_CSEL_INSTRUCTIONS) or (CSELScore <= 0) then
+        begin
+          { Invalid or too many instructions to be worthwhile }
+          fState := tsInvalid;
+          Exit;
+        end;
+
+
+      { check further for
+             b     xxx
+             <several movs 1>
+             bl    yyy
+         xxx:
+             <several movs 2>
+         yyy:
+
+        etc.
+      }
+      if (fState = tsBranching) and
+        { Estimate for required savings for extra jump }
+        (CSELScore <= MAX_CSEL_INSTRUCTIONS - 1) and
+        { Only one reference is allowed for double blocks }
+        (AFirstLabel.getrefs = 1) then
+        begin
+          Optimizer.GetNextInstruction(fMidLabel, hp1);
+          fSecondMovBlock := hp1;
+
+          if not InitialiseBlock(fSecondMovBlock, fMidLabel, fSecondMovBlockStop, fThirdJump) then
+            begin
+              EvaluateBranchingType;
+              Exit;
+            end;
+
+          hp1 := fSecondMovBlockStop; { Will either be on a label or a jump }
+
+          if (hp1.typ <> ait_label) then { should be on a jump }
+            begin
+              if not Optimizer.GetNextInstruction(hp1, fEndLabel) or (fEndLabel.typ <> ait_label) then
+                begin
+                  { Need a label afterwards }
+                  EvaluateBranchingType;
+                  Exit;
+                end;
+            end
+          else
+            fEndLabel := hp1;
+
+          if tai_label(fEndLabel).labsym <> JumpTargetOp(taicpu(fSecondJump))^.ref^.symbol then
+            { Second jump doesn't go to the end }
+            fEndLabel := nil;
+
+          if not Assigned(fThirdJump) and not Assigned(fEndLabel) then
+            begin
+            { If there's neither a 3rd jump nor correct end label, then it's
+              not a invalid double block, but is a valid single branching
+              block (see above table) }
+              EvaluateBranchingType;
+              Exit;
+            end;
+
+          Count := AnalyseMOVBlock(fSecondMovBlock, fSecondMovBlockStop, fMidLabel);
+
+          if (Count > MAX_CSEL_INSTRUCTIONS) or (Count <= 0) then
+            { Invalid or too many instructions to be worthwhile }
+            Exit;
+
+          Inc(CSELScore, Count);
+
+          if Assigned(fThirdJump) then
+            begin
+              if not Assigned(fSecondJump) then
+                fState := tsDoubleSecondBranching
+              else if (JumpTargetOp(taicpu(fSecondJump))^.ref^.symbol = JumpTargetOp(taicpu(fThirdJump))^.ref^.symbol) then
+                fState := tsDoubleBranchSame
+              else
+                fState := tsDoubleBranchDifferent;
+            end
+          else
+            fState := tsDouble;
+        end;
+
+      if fState = tsBranching then
+        EvaluateBranchingType;
+    end;
+
+  { Tries to convert a mov const,%reg instruction into a CSEL by reserving a
+    new register to store the constant }
+  function TCSELTracking.TryCSELConst(p, start, stop: tai; var Count: LongInt): Boolean;
+    var
+      RegSize: TSubRegister;
+      CurrentVal: TCGInt;
+      ANewReg: TRegister;
+      X: ShortInt;
+    begin
+      Result := False;
+
+      if not MatchOpType(taicpu(p), top_reg, top_const) then
+        Exit;
+
+      if ConstCount >= MAX_CSEL_REGISTERS then
+        { Arrays are full }
+        Exit;
+
+      { See if the value has already been reserved for another CSEL instruction }
+      CurrentVal := taicpu(p).oper[1]^.val;
+      RegSize := getsubreg(taicpu(p).oper[0]^.reg);
+      for X := 0 to ConstCount - 1 do
+        if ConstVals[X] = CurrentVal then
+          begin
+            ConstRegs[ConstCount] := ConstRegs[X];
+            ConstSizes[ConstCount] := RegSize;
+            ConstVals[ConstCount] := CurrentVal;
+
+            Inc(ConstCount);
+            Inc(Count);
+
+            Result := True;
+            Exit;
+          end;
+
+      ANewReg := fOptimizer.GetIntRegisterBetween(R_SUBWHOLE, RegisterTracking, start, stop, True);
+      if ANewReg = NR_NO then
+        { No free registers }
+        Exit;
+
+      { Reserve the register so subsequent TryCSELConst calls don't all end
+        up vying for the same register }
+      fOptimizer.IncludeRegInUsedRegs(ANewReg, RegisterTracking);
+
+      ConstRegs[ConstCount] := ANewReg;
+      ConstSizes[ConstCount] := RegSize;
+      ConstVals[ConstCount] := CurrentVal;
+
+      Inc(ConstCount);
+      Inc(Count);
+
+      Result := True;
+    end;
+
+  destructor TCSELTracking.Done;
+    begin
+      TAOptObj.ReleaseUsedRegs(RegisterTracking);
+    end;
+
+  procedure TCSELTracking.Process(out new_p: tai);
+    var
+      Count, Writes: LongInt;
+      RegMatch: Boolean;
+      hp1, hp_new: tai;
+      inverted_condition, condition: TAsmCond;
+    begin
+      if (fState in [tsInvalid, tsProcessed]) then
+        InternalError(2023110702);
+
+      { Repurpose RegisterTracking to mark registers that we've defined }
+      RegisterTracking[R_INTREGISTER].Clear;
+
+      Count := 0;
+      Writes := 0;
+      condition := taicpu(fInitialJump).condition;
+      inverted_condition := inverse_cond(condition);
+
+      { Exclude tsDoubleBranchDifferent from this check, as the second block
+        doesn't get CSELs in this case }
+      if (fState in [tsDouble, tsDoubleBranchSame, tsDoubleSecondBranching]) then
+        begin
+          { Include the jump in the flag tracking }
+          if Assigned(fThirdJump) then
+            begin
+              if (fState = tsDoubleBranchSame) then
+                begin
+                  { Will be an unconditional jump, so track to the instruction before it }
+                  if not fOptimizer.GetLastInstruction(fThirdJump, hp1) then
+                    InternalError(2023110712);
+                end
+              else
+                hp1 := fThirdJump;
+            end
+          else
+            hp1 := fSecondMovBlockStop;
+        end
+      else
+        begin
+          { Include a conditional jump in the flag tracking }
+          if Assigned(fSecondJump) then
+            begin
+              if (fState = tsDetour) then
+                begin
+                  { Will be an unconditional jump, so track to the instruction before it }
+                  if not fOptimizer.GetLastInstruction(fSecondJump, hp1) then
+                    InternalError(2023110713);
+                end
+              else
+                hp1 := fSecondJump;
+            end
+          else
+            hp1 := fFirstMovBlockStop;
+        end;
+
+      fOptimizer.AllocRegBetween(NR_DEFAULTFLAGS, fInitialJump, hp1, fOptimizer.UsedRegs);
+
+      { Process the second set of MOVs first, because if a destination
+        register is shared between the first and second MOV sets, it is more
+        efficient to turn the first one into a MOV instruction and place it
+        before the CMP if possible, but we won't know which registers are
+        shared until we've processed at least one list, so we might as well
+        make it the second one since that won't be modified again. }
+
+      if (fState in [tsDouble, tsDoubleBranchSame, tsDoubleBranchDifferent, tsDoubleSecondBranching]) then
+        begin
+          hp1 := fSecondMovBlock;
+          repeat
+            if not Assigned(hp1) then
+              InternalError(2018062902);
+
+            if (hp1.typ = ait_instruction) then
+              begin
+                { Extra safeguard }
+                if (taicpu(hp1).opcode <> A_MOV) then
+                  InternalError(2018062903);
+
+                { Note: tsDoubleBranchDifferent is essentially identical to
+                  tsBranching and the 2nd block is best left largely
+                  untouched, but we need to evaluate which registers the MOVs
+                  write to in order to track what would be complementary CSEL
+                  pairs that can be further optimised. [Kit] }
+                if fState <> tsDoubleBranchDifferent then
+                  begin
+                    if taicpu(hp1).oper[1]^.typ = top_const then
+                      begin
+                        RegMatch := False;
+
+                        for Count := 0 to ConstCount - 1 do
+                          if (ConstVals[Count] = taicpu(hp1).oper[1]^.val) and
+                            (getsubreg(taicpu(hp1).oper[0]^.reg) = ConstSizes[Count]) then
+                            begin
+                              RegMatch := True;
+
+                              { If it's in RegisterTracking, then this register
+                                is being used more than once and hence has
+                                already had its value defined (it gets added to
+                                UsedRegs through AllocRegBetween below) }
+                              if not RegisterTracking[R_INTREGISTER].IsUsed(ConstRegs[Count]) then
+                                begin
+                                  hp_new := tai(hp1.getcopy);
+                                  taicpu(hp_new).oper[0]^.reg := ConstRegs[Count];
+                                  taicpu(hp_new).fileinfo := taicpu(fInitialJump).fileinfo;
+
+                                  fOptimizer.asml.InsertBefore(hp_new, fInsertionPoint);
+                                  fOptimizer.IncludeRegInUsedRegs(ConstRegs[Count], RegisterTracking);
+
+                                  ConstMovs[Count] := hp_new;
+                                end
+                              else
+                                { We just need an instruction between hp_prev and hp1
+                                  where we know the register is marked as in use }
+                                hp_new := fSecondMovBlock;
+
+                              { Keep track of largest write for this register so it can be optimised later }
+                              if (getsubreg(taicpu(hp1).oper[0]^.reg) > ConstWriteSizes[getsupreg(ConstRegs[Count])]) then
+                                ConstWriteSizes[getsupreg(ConstRegs[Count])] := getsubreg(taicpu(hp1).oper[0]^.reg);
+
+                              fOptimizer.AllocRegBetween(ConstRegs[Count], hp_new, hp1, fOptimizer.UsedRegs);
+                              taicpu(hp1).loadreg(1, newreg(R_INTREGISTER, getsupreg(ConstRegs[Count]), ConstSizes[Count]));
+                              Break;
+                            end;
+
+                        if not RegMatch then
+                          InternalError(2021100413);
+                      end;
+
+                    taicpu(hp1).opcode := A_CSEL;
+                    taicpu(hp1).ops := 4;
+                    taicpu(hp1).loadreg(2, taicpu(hp1).oper[0]^.reg);
+                    taicpu(hp1).loadconditioncode(3, condition);
+                  end;
+
+                { Store these writes to search for duplicates later on }
+                RegWrites[Writes] := taicpu(hp1).oper[0]^.reg;
+                Inc(Writes);
+              end;
+
+            fOptimizer.GetNextInstruction(hp1, hp1);
+          until (hp1 = fSecondMovBlockStop);
+        end;
+
+      { Now do the first set of MOVs }
+      hp1 := fFirstMovBlock;
+      repeat
+        if not Assigned(hp1) then
+          InternalError(2018062904);
+
+        if (hp1.typ = ait_instruction) then
+          begin
+            RegMatch := False;
+
+            { Extra safeguard }
+            if (taicpu(hp1).opcode <> A_MOV) then
+              InternalError(2018062905);
+
+            { Search through the RegWrites list to see if there are any
+              opposing CSEL pairs that write to the same register }
+            for Count := 0 to Writes - 1 do
+              if (RegWrites[Count] = taicpu(hp1).oper[0]^.reg) then
+                begin
+                  { We have a match.  Keep this as a MOV }
+
+                  { Move ahead in preparation }
+                  fOptimizer.GetNextInstruction(hp1, hp1);
+
+                  RegMatch := True;
+                  Break;
+                end;
+
+            if RegMatch then
+              Continue;
+
+            if taicpu(hp1).oper[1]^.typ = top_const then
+              begin
+                for Count := 0 to ConstCount - 1 do
+                  if (ConstVals[Count] = taicpu(hp1).oper[1]^.val) and
+                    (getsubreg(taicpu(hp1).oper[0]^.reg) = ConstSizes[Count]) then
+                    begin
+                      RegMatch := True;
+
+                      { If it's in RegisterTracking, then this register is
+                        being used more than once and hence has already had
+                        its value defined (it gets added to UsedRegs through
+                        AllocRegBetween below) }
+                      if not RegisterTracking[R_INTREGISTER].IsUsed(ConstRegs[Count]) then
+                        begin
+                          hp_new := tai(hp1.getcopy);
+                          taicpu(hp_new).oper[0]^.reg := ConstRegs[Count];
+                          taicpu(hp_new).fileinfo := taicpu(fInitialJump).fileinfo;
+
+                          fOptimizer.asml.InsertBefore(hp_new, fInsertionPoint);
+                          fOptimizer.IncludeRegInUsedRegs(ConstRegs[Count], RegisterTracking);
+
+                          ConstMovs[Count] := hp_new;
+                        end
+                      else
+                        { We just need an instruction between hp_prev and hp1
+                          where we know the register is marked as in use }
+                          hp_new := fFirstMovBlock;
+
+                      { Keep track of largest write for this register so it can be optimised later }
+                      if (getsubreg(taicpu(hp1).oper[0]^.reg) > ConstWriteSizes[getsupreg(ConstRegs[Count])]) then
+                        ConstWriteSizes[getsupreg(ConstRegs[Count])] := getsubreg(taicpu(hp1).oper[0]^.reg);
+
+                      fOptimizer.AllocRegBetween(ConstRegs[Count], hp_new, hp1, fOptimizer.UsedRegs);
+                      taicpu(hp1).loadreg(1, newreg(R_INTREGISTER, getsupreg(ConstRegs[Count]), ConstSizes[Count]));
+                      Break;
+                    end;
+
+                if not RegMatch then
+                  InternalError(2021100412);
+              end;
+
+              taicpu(hp1).opcode := A_CSEL;
+              taicpu(hp1).ops := 4;
+              taicpu(hp1).loadreg(2, taicpu(hp1).oper[0]^.reg);
+              taicpu(hp1).loadconditioncode(3, inverted_condition);
+
+            if (fState = tsDoubleBranchDifferent) then
+              begin
+                { Store these writes to search for duplicates later on }
+                RegWrites[Writes] := taicpu(hp1).oper[0]^.reg;
+                Inc(Writes);
+              end;
+          end;
+
+        fOptimizer.GetNextInstruction(hp1, hp1);
+      until (hp1 = fFirstMovBlockStop);
+
+      { Update initialisation MOVs to the smallest possible size }
+      for Count := 0 to ConstCount - 1 do
+        if Assigned(ConstMovs[Count]) then
+          setsubreg(taicpu(ConstMovs[Count]).oper[0]^.reg, ConstWriteSizes[Word(ConstRegs[Count])]);
+
+      case fState of
+        tsSimple:
+          begin
+            fOptimizer.DebugMsg(SPeepholeOptimization + 'CSEL Block (Simple type)', fInitialJump);
+            { No branch to delete }
+          end;
+        tsDetour:
+          begin
+            fOptimizer.DebugMsg(SPeepholeOptimization + 'CSEL Block (Detour type)', fInitialJump);
+            { Preserve jump }
+          end;
+        tsBranching, tsDoubleBranchDifferent:
+          begin
+            if (fState = tsBranching) then
+              fOptimizer.DebugMsg(SPeepholeOptimization + 'CSEL Block (Branching type)', fInitialJump)
+            else
+              fOptimizer.DebugMsg(SPeepholeOptimization + 'CSEL Block (Double branching (different) type)', fInitialJump);
+            taicpu(fSecondJump).condition := inverted_condition;
+          end;
+        tsDouble, tsDoubleBranchSame:
+          begin
+            if (fState = tsDouble) then
+              fOptimizer.DebugMsg(SPeepholeOptimization + 'CSEL Block (Double type)', fInitialJump)
+            else
+              fOptimizer.DebugMsg(SPeepholeOptimization + 'CSEL Block (Double branching (same) type)', fInitialJump);
+            { Delete second jump }
+            JumpTargetOp(taicpu(fSecondJump))^.ref^.symbol.decrefs;
+            fOptimizer.RemoveInstruction(fSecondJump);
+          end;
+        tsDoubleSecondBranching:
+          begin
+            fOptimizer.DebugMsg(SPeepholeOptimization + 'CSEL Block (Double, second branching type)', fInitialJump);
+            { Delete second jump, preserve third jump as conditional }
+            JumpTargetOp(taicpu(fSecondJump))^.ref^.symbol.decrefs;
+            fOptimizer.RemoveInstruction(fSecondJump);
+            taicpu(fThirdJump).condition := condition;
+          end;
+        else
+          InternalError(2023110721);
+      end;
+
+      { Now we can safely decrement the reference count }
+      tasmlabel(fLabel).decrefs;
+
+      fOptimizer.UpdateUsedRegs(tai(fInitialJump.next));
+
+      { Remove the original jump }
+      fOptimizer.RemoveInstruction(fInitialJump); { Note, the choice to not use RemoveCurrentp is deliberate }
+
+      new_p := fFirstMovBlock; { Appears immediately after the initial jump }
+
+      fState := tsProcessed;
+    end;
+
 begin
 begin
   casmoptimizer:=TCpuAsmOptimizer;
   casmoptimizer:=TCpuAsmOptimizer;
 End.
 End.

+ 3 - 1
compiler/aarch64/cgcpu.pas

@@ -1436,7 +1436,9 @@ implementation
       begin
       begin
         { add/sub instructions have only positive immediate operands }
         { add/sub instructions have only positive immediate operands }
         if (op in [OP_ADD,OP_SUB]) and
         if (op in [OP_ADD,OP_SUB]) and
-           (a<0) then
+           (a<0) and
+           { this might result in a false positive overflow in case of a+0 }
+           (a<>$8000000000000000) then
           begin
           begin
             if op=OP_ADD then
             if op=OP_ADD then
               op:=op_SUB
               op:=op_SUB

+ 8 - 0
compiler/aarch64/cpubase.pas

@@ -324,6 +324,7 @@ unit cpubase;
     function reg_cgsize(const reg: tregister) : tcgsize;
     function reg_cgsize(const reg: tregister) : tcgsize;
     function cgsize2subreg(regtype: tregistertype; s:Tcgsize):Tsubregister;
     function cgsize2subreg(regtype: tregistertype; s:Tcgsize):Tsubregister;
     function is_calljmp(o:tasmop):boolean;{$ifdef USEINLINE}inline;{$endif USEINLINE}
     function is_calljmp(o:tasmop):boolean;{$ifdef USEINLINE}inline;{$endif USEINLINE}
+    function is_calljmpmaybeuncondret(o:tasmop):boolean;{$ifdef USEINLINE}inline;{$endif USEINLINE}
     procedure inverse_flags(var f: TResFlags);
     procedure inverse_flags(var f: TResFlags);
     function flags_to_cond(const f: TResFlags) : TAsmCond;
     function flags_to_cond(const f: TResFlags) : TAsmCond;
     function findreg_by_number(r:Tregister):tregisterindex;
     function findreg_by_number(r:Tregister):tregisterindex;
@@ -451,6 +452,13 @@ unit cpubase;
       end;
       end;
 
 
 
 
+    function is_calljmpmaybeuncondret(o:tasmop):boolean;{$ifdef USEINLINE}inline;{$endif USEINLINE}
+      begin
+        { Note that the caller still has to check the instruction's condition }
+        is_calljmpmaybeuncondret:=(o in [A_B,A_BL,A_BLR,A_RET]);
+      end;
+
+
     procedure inverse_flags(var f: TResFlags);
     procedure inverse_flags(var f: TResFlags);
       const
       const
         inv_flags: array[TResFlags] of TResFlags =
         inv_flags: array[TResFlags] of TResFlags =

+ 5 - 5
compiler/aarch64/naarch64util.pas

@@ -26,12 +26,12 @@ unit naarch64util;
 interface
 interface
 
 
 uses
 uses
-    cclasses, ngenutil;
+    cclasses, ngenutil, fmodule;
 
 
 type
 type
     TAArch64NodeUtils = class(TNodeUtils)
     TAArch64NodeUtils = class(TNodeUtils)
         class procedure InsertObjectInfo; override;
         class procedure InsertObjectInfo; override;
-        class procedure Insert_Init_Final_Table(Entries: TFPList); override;
+        class procedure Insert_Init_Final_Table(main: tmodule; Entries: TFPList); override;
     end;
     end;
 
 
 implementation
 implementation
@@ -54,7 +54,7 @@ end;
     TODO: This is a simple skeleton, not nearly as complex as the
     TODO: This is a simple skeleton, not nearly as complex as the
     ARM (32-bit) version in compiler/arm/narmutil.pas
     ARM (32-bit) version in compiler/arm/narmutil.pas
 }
 }
-class procedure TAArch64NodeUtils.Insert_Init_Final_Table(Entries: TFPList);
+class procedure TAArch64NodeUtils.Insert_Init_Final_Table(main: tmodule; Entries: TFPList);
 
 
     procedure GenEntry(List: TAsmList);
     procedure GenEntry(List: TAsmList);
     var
     var
@@ -113,7 +113,7 @@ var
 begin
 begin
     if not(tf_init_final_units_by_calls in target_info.flags) then
     if not(tf_init_final_units_by_calls in target_info.flags) then
     begin
     begin
-        inherited insert_init_final_table(Entries);
+        inherited insert_init_final_table(main,Entries);
         exit;
         exit;
     end;
     end;
 
 
@@ -156,7 +156,7 @@ begin
     InitList.Free;
     InitList.Free;
     FinalList.Free;
     FinalList.Free;
 
 
-    inherited Insert_Init_Final_Table(entries);
+    inherited Insert_Init_Final_Table(main,entries);
 end;
 end;
 
 
 begin
 begin

+ 15 - 2
compiler/aarch64/ncpuadd.pas

@@ -45,12 +45,13 @@ interface
           procedure second_cmp64bit; override;
           procedure second_cmp64bit; override;
        public
        public
           function use_generic_mul32to64: boolean; override;
           function use_generic_mul32to64: boolean; override;
+          function pass_1 : tnode;override;
        end;
        end;
 
 
   implementation
   implementation
 
 
     uses
     uses
-      systems,symtype,symdef,
+      systems,symconst,symtype,symdef,
       globals,globtype,
       globals,globtype,
       cutils,verbose,
       cutils,verbose,
       paramgr,procinfo,
       paramgr,procinfo,
@@ -414,7 +415,7 @@ interface
                 secondpass(left);
                 secondpass(left);
 
 
                 { Skip the not node completely }
                 { Skip the not node completely }
-                Include(right.flags, nf_do_not_execute);
+                Include(right.transientflags, tnf_do_not_execute);
                 secondpass(tnotnode(right).left);
                 secondpass(tnotnode(right).left);
 
 
                 { allocate registers }
                 { allocate registers }
@@ -485,6 +486,18 @@ interface
         result:=false;
         result:=false;
       end;
       end;
 
 
+    function taarch64addnode.pass_1: tnode;
+      begin
+        Result:=inherited pass_1;
+        { if the result is not nil, a new node has been generated and the current node will be discarted }
+        if Result=nil then
+          begin
+            if left.resultdef.typ=floatdef then
+              if needs_check_for_fpu_exceptions then
+                Include(current_procinfo.flags,pi_do_call);
+          end;
+      end;
+
 
 
 begin
 begin
   caddnode:=taarch64addnode;
   caddnode:=taarch64addnode;

+ 44 - 10
compiler/aarch64/ncpuinl.pas

@@ -61,10 +61,11 @@ implementation
     uses
     uses
       globtype,verbose,globals,
       globtype,verbose,globals,
       compinnr,
       compinnr,
-      cpuinfo, defutil,symdef,aasmdata,aasmcpu,
+      cpuinfo, defutil,symdef,aasmbase,aasmdata,aasmcpu,
       cgbase,cgutils,pass_1,pass_2,
       cgbase,cgutils,pass_1,pass_2,
+      procinfo,
       ncal,nutils,
       ncal,nutils,
-      cpubase,ncgutil,cgobj,cgcpu, hlcgobj;
+      cpubase,ncgutil,cgobj,cgcpu,hlcgobj;
 
 
 {*****************************************************************************
 {*****************************************************************************
                               taarch64inlinenode
                               taarch64inlinenode
@@ -84,6 +85,8 @@ implementation
       begin
       begin
         expectloc:=LOC_MMREGISTER;
         expectloc:=LOC_MMREGISTER;
         result:=nil;
         result:=nil;
+        if needs_check_for_fpu_exceptions then
+          Include(current_procinfo.flags,pi_do_call);
       end;
       end;
 
 
 
 
@@ -91,6 +94,8 @@ implementation
       begin
       begin
         expectloc:=LOC_MMREGISTER;
         expectloc:=LOC_MMREGISTER;
         result:=nil;
         result:=nil;
+        if needs_check_for_fpu_exceptions then
+          Include(current_procinfo.flags,pi_do_call);
       end;
       end;
 
 
 
 
@@ -98,6 +103,8 @@ implementation
       begin
       begin
         expectloc:=LOC_MMREGISTER;
         expectloc:=LOC_MMREGISTER;
         result:=nil;
         result:=nil;
+        if needs_check_for_fpu_exceptions then
+          Include(current_procinfo.flags,pi_do_call);
       end;
       end;
 
 
 
 
@@ -105,6 +112,8 @@ implementation
       begin
       begin
         expectloc:=LOC_MMREGISTER;
         expectloc:=LOC_MMREGISTER;
         result:=nil;
         result:=nil;
+        if needs_check_for_fpu_exceptions then
+          Include(current_procinfo.flags,pi_do_call);
       end;
       end;
 
 
 
 
@@ -112,6 +121,8 @@ implementation
       begin
       begin
         expectloc:=LOC_MMREGISTER;
         expectloc:=LOC_MMREGISTER;
         result:=nil;
         result:=nil;
+        if needs_check_for_fpu_exceptions then
+          Include(current_procinfo.flags,pi_do_call);
       end;
       end;
 
 
 
 
@@ -119,6 +130,8 @@ implementation
       begin
       begin
         expectloc:=LOC_MMREGISTER;
         expectloc:=LOC_MMREGISTER;
         result:=nil;
         result:=nil;
+        if needs_check_for_fpu_exceptions then
+          Include(current_procinfo.flags,pi_do_call);
       end;
       end;
 
 
 
 
@@ -126,6 +139,8 @@ implementation
       begin
       begin
         expectloc:=LOC_MMREGISTER;
         expectloc:=LOC_MMREGISTER;
         result:=nil;
         result:=nil;
+        if needs_check_for_fpu_exceptions then
+          Include(current_procinfo.flags,pi_do_call);
       end;
       end;
 
 
 
 
@@ -168,6 +183,7 @@ implementation
     procedure taarch64inlinenode.second_abs_long;
     procedure taarch64inlinenode.second_abs_long;
       var
       var
         opsize : tcgsize;
         opsize : tcgsize;
+        hl: TAsmLabel;
       begin
       begin
         secondpass(left);
         secondpass(left);
         opsize:=def_cgsize(left.resultdef);
         opsize:=def_cgsize(left.resultdef);
@@ -175,6 +191,15 @@ implementation
         location:=left.location;
         location:=left.location;
         location.register:=cg.getintregister(current_asmdata.CurrAsmList,opsize);
         location.register:=cg.getintregister(current_asmdata.CurrAsmList,opsize);
 
 
+        if cs_check_overflow in current_settings.localswitches then
+          begin
+            current_asmdata.getjumplabel(hl);
+            hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,resultdef,OC_NE,torddef(resultdef).low.svalue,left.location.register,hl);
+            hlcg.a_reg_dealloc(current_asmdata.CurrAsmList, NR_DEFAULTFLAGS);
+            hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_overflow',[],nil).resetiftemp;
+            hlcg.a_label(current_asmdata.CurrAsmList,hl);
+          end;
+
         current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_NEG,location.register,left.location.register),PF_S));
         current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_NEG,location.register,left.location.register),PF_S));
         current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_cond(A_CSEL,location.register,location.register,left.location.register,C_GE));
         current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_cond(A_CSEL,location.register,location.register,left.location.register,C_GE));
       end;
       end;
@@ -356,8 +381,10 @@ implementation
           begin
           begin
             expectloc:=LOC_MMREGISTER;
             expectloc:=LOC_MMREGISTER;
             Result:=nil;
             Result:=nil;
+            if needs_check_for_fpu_exceptions then
+              Include(current_procinfo.flags,pi_do_call);
           end
           end
-        else if is_32bitint(resultdef) then
+        else if is_32bitint(resultdef) or is_64bitint(resultdef) then
           begin
           begin
             expectloc:=LOC_REGISTER;
             expectloc:=LOC_REGISTER;
             Result:=nil;
             Result:=nil;
@@ -373,6 +400,7 @@ implementation
         i: Integer;
         i: Integer;
         ai: taicpu;
         ai: taicpu;
         op: TAsmOp;
         op: TAsmOp;
+        cond: TAsmCond;
       begin
       begin
         paraarray[1]:=tcallparanode(tcallparanode(parameters).nextpara).paravalue;
         paraarray[1]:=tcallparanode(tcallparanode(parameters).nextpara).paravalue;
           paraarray[2]:=tcallparanode(parameters).paravalue;
           paraarray[2]:=tcallparanode(parameters).paravalue;
@@ -411,7 +439,7 @@ implementation
 
 
              cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
              cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
            end
            end
-         else if is_32bitint(resultdef) then
+         else if is_32bitint(resultdef) or is_64bitint(resultdef) then
            begin
            begin
              { no memory operand is allowed }
              { no memory operand is allowed }
              for i:=low(paraarray) to high(paraarray) do
              for i:=low(paraarray) to high(paraarray) do
@@ -428,17 +456,23 @@ implementation
                paraarray[1].location.register,paraarray[2].location.register));
                paraarray[1].location.register,paraarray[2].location.register));
 
 
              case inlinenumber of
              case inlinenumber of
+               in_min_longint,
+               in_min_int64:
+                 cond := C_LT;
                in_min_dword,
                in_min_dword,
-               in_min_longint:
-                current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_cond(A_CSEL,
-                  location.register,paraarray[1].location.register,paraarray[2].location.register,C_LT));
+               in_min_qword:
+                 cond := C_LO;
+               in_max_longint,
+               in_max_int64:
+                 cond := C_GT;
                in_max_dword,
                in_max_dword,
-               in_max_longint:
-                current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_cond(A_CSEL,
-                  location.register,paraarray[1].location.register,paraarray[2].location.register,C_GT));
+               in_max_qword:
+                 cond := C_HI;
                else
                else
                  Internalerror(2021121901);
                  Internalerror(2021121901);
              end;
              end;
+             current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_cond(A_CSEL,
+               location.register,paraarray[1].location.register,paraarray[2].location.register,cond));
            end
            end
          else
          else
            internalerror(2021121801);
            internalerror(2021121801);

+ 10 - 0
compiler/aarch64/ncpumat.pas

@@ -39,6 +39,7 @@ interface
       end;
       end;
 
 
       taarch64unaryminusnode = class(tcgunaryminusnode)
       taarch64unaryminusnode = class(tcgunaryminusnode)
+         function pass_1: tnode; override;
          procedure second_float; override;
          procedure second_float; override;
       end;
       end;
 
 
@@ -482,6 +483,15 @@ implementation
                                    taarch64unaryminusnode
                                    taarch64unaryminusnode
 *****************************************************************************}
 *****************************************************************************}
 
 
+    function taarch64unaryminusnode.pass_1: tnode;
+      begin
+        Result:=inherited pass_1;
+        if Result=nil then
+          if needs_check_for_fpu_exceptions then
+            Include(current_procinfo.flags,pi_do_call);
+      end;
+
+
     procedure taarch64unaryminusnode.second_float;
     procedure taarch64unaryminusnode.second_float;
       begin
       begin
         secondpass(left);
         secondpass(left);

+ 2 - 1
compiler/aasmcnst.pas

@@ -2208,12 +2208,13 @@ implementation
      var
      var
        resourcestrrec: trecorddef;
        resourcestrrec: trecorddef;
      begin
      begin
-       if cs.consttyp<>constresourcestring then
+       if not (cs.consttyp in [constresourcestring,constwresourcestring]) then
          internalerror(2014062102);
          internalerror(2014062102);
        if fqueue_offset<>0 then
        if fqueue_offset<>0 then
          internalerror(2014062103);
          internalerror(2014062103);
        { warning: update if/when the type of resource strings changes }
        { warning: update if/when the type of resource strings changes }
        case cs.consttyp of
        case cs.consttyp of
+         constwresourcestring,
          constresourcestring:
          constresourcestring:
            begin
            begin
              resourcestrrec:=trecorddef(search_system_type('TRESOURCESTRINGRECORD').typedef);
              resourcestrrec:=trecorddef(search_system_type('TRESOURCESTRINGRECORD').typedef);

+ 19 - 4
compiler/aasmdata.pas

@@ -214,7 +214,9 @@ interface
         function  DefineAsmSymbolByClass(symclass: TAsmSymbolClass; const s : TSymStr;_bind:TAsmSymBind;_typ:Tasmsymtype; def: tdef) : TAsmSymbol; virtual;
         function  DefineAsmSymbolByClass(symclass: TAsmSymbolClass; const s : TSymStr;_bind:TAsmSymBind;_typ:Tasmsymtype; def: tdef) : TAsmSymbol; virtual;
         function  DefineAsmSymbol(const s : TSymStr;_bind:TAsmSymBind;_typ:Tasmsymtype; def: tdef) : TAsmSymbol;
         function  DefineAsmSymbol(const s : TSymStr;_bind:TAsmSymBind;_typ:Tasmsymtype; def: tdef) : TAsmSymbol;
         function  DefineProcAsmSymbol(pd: tdef; const s: TSymStr; global: boolean): TAsmSymbol;
         function  DefineProcAsmSymbol(pd: tdef; const s: TSymStr; global: boolean): TAsmSymbol;
+        function  WeakRefAsmSymbolByClass(symclass: TAsmSymbolClass; const s : TSymStr;_typ:Tasmsymtype) : TAsmSymbol;
         function  WeakRefAsmSymbol(const s : TSymStr;_typ:Tasmsymtype) : TAsmSymbol;
         function  WeakRefAsmSymbol(const s : TSymStr;_typ:Tasmsymtype) : TAsmSymbol;
+        function  RefAsmSymbolByClass(symclass: TAsmSymbolClass; const s : TSymStr;_typ:Tasmsymtype;indirect:boolean=false) : TAsmSymbol;
         function  RefAsmSymbol(const s : TSymStr;_typ:Tasmsymtype;indirect:boolean=false) : TAsmSymbol;
         function  RefAsmSymbol(const s : TSymStr;_typ:Tasmsymtype;indirect:boolean=false) : TAsmSymbol;
         function  GetAsmSymbol(const s : TSymStr) : TAsmSymbol;
         function  GetAsmSymbol(const s : TSymStr) : TAsmSymbol;
         { create new assembler label }
         { create new assembler label }
@@ -609,7 +611,8 @@ implementation
           result:=DefineAsmSymbol(s,AB_LOCAL,AT_FUNCTION,pd);
           result:=DefineAsmSymbol(s,AB_LOCAL,AT_FUNCTION,pd);
       end;
       end;
 
 
-    function TAsmData.RefAsmSymbol(const s : TSymStr;_typ:Tasmsymtype;indirect:boolean) : TAsmSymbol;
+
+    function TAsmData.RefAsmSymbolByClass(symclass: TAsmSymbolClass; const s : TSymStr;_typ:Tasmsymtype;indirect:boolean) : TAsmSymbol;
       var
       var
         namestr : TSymStr;
         namestr : TSymStr;
         bind : tasmsymbind;
         bind : tasmsymbind;
@@ -626,18 +629,30 @@ implementation
           end;
           end;
         result:=TAsmSymbol(FAsmSymbolDict.Find(namestr));
         result:=TAsmSymbol(FAsmSymbolDict.Find(namestr));
         if not assigned(result) then
         if not assigned(result) then
-          result:=TAsmSymbol.create(AsmSymbolDict,namestr,bind,_typ)
+          result:=symclass.create(AsmSymbolDict,namestr,bind,_typ)
         { one normal reference removes the "weak" character of a symbol }
         { one normal reference removes the "weak" character of a symbol }
         else if (result.bind=AB_WEAK_EXTERNAL) then
         else if (result.bind=AB_WEAK_EXTERNAL) then
           result.bind:=bind;
           result.bind:=bind;
       end;
       end;
 
 
 
 
-    function TAsmData.WeakRefAsmSymbol(const s : TSymStr;_typ:Tasmsymtype) : TAsmSymbol;
+    function TAsmData.RefAsmSymbol(const s : TSymStr;_typ:Tasmsymtype;indirect:boolean) : TAsmSymbol;
+      begin
+        result:=RefAsmSymbolByClass(TAsmSymbol,s,_typ,indirect);
+      end;
+
+
+    function TAsmData.WeakRefAsmSymbolByClass(symclass: TAsmSymbolClass; const s : TSymStr;_typ:Tasmsymtype) : TAsmSymbol;
       begin
       begin
         result:=TAsmSymbol(FAsmSymbolDict.Find(s));
         result:=TAsmSymbol(FAsmSymbolDict.Find(s));
         if not assigned(result) then
         if not assigned(result) then
-          result:=TAsmSymbol.create(AsmSymbolDict,s,AB_WEAK_EXTERNAL,_typ);
+          result:=symclass.create(AsmSymbolDict,s,AB_WEAK_EXTERNAL,_typ);
+      end;
+
+
+    function TAsmData.WeakRefAsmSymbol(const s : TSymStr;_typ:Tasmsymtype) : TAsmSymbol;
+      begin
+        result:=WeakRefAsmSymbolByClass(TAsmSymbol,s,_typ);
       end;
       end;
 
 
 
 

+ 82 - 3
compiler/aoptobj.pas

@@ -426,6 +426,11 @@ Unit AoptObj;
         { Jump/label optimisation entry method }
         { Jump/label optimisation entry method }
         function DoJumpOptimizations(var p: tai; var stoploop: Boolean): Boolean;
         function DoJumpOptimizations(var p: tai; var stoploop: Boolean): Boolean;
 
 
+        { Attempts to reconfigure the Regallocs and Regdeallocs before p1 and
+          after p2 so Reg is no longer allocated between them.  Returns True if
+          the register is no longer allocated at p1 }
+        function TryRemoveRegAlloc(const Reg: TRegister; p1, p2: tai): Boolean;
+
         { insert debug comments about which registers are read and written by
         { insert debug comments about which registers are read and written by
           each instruction. Useful for debugging the InstructionLoadsFromReg and
           each instruction. Useful for debugging the InstructionLoadsFromReg and
           other similar functions. }
           other similar functions. }
@@ -1382,10 +1387,11 @@ Unit AoptObj;
           If Assigned(StartPai) And
           If Assigned(StartPai) And
              (StartPai.typ = ait_regAlloc) Then
              (StartPai.typ = ait_regAlloc) Then
             Begin
             Begin
-              if (tai_regalloc(StartPai).ratype=ra_alloc) and
-                SuperRegistersEqual(tai_regalloc(StartPai).Reg,Reg) then
+              if SuperRegistersEqual(tai_regalloc(StartPai).Reg,Reg) then
                begin
                begin
-                 Result:=tai_regalloc(StartPai);
+                 { If we find a dealloc first, say, return nil }
+                 if (tai_regalloc(StartPai).ratype<>ra_dealloc) then
+                   Result:=tai_regalloc(StartPai);
                  exit;
                  exit;
                end;
                end;
               StartPai := Tai(StartPai.Previous);
               StartPai := Tai(StartPai.Previous);
@@ -2566,6 +2572,79 @@ Unit AoptObj;
       end;
       end;
 
 
 
 
+    { Attempts to reconfigure the Regallocs and Regdeallocs before p1 and
+      after p2 so Reg is no longer allocated between them.  Returns True if the
+      register is no longer allocated at p1 }
+    function TAOptObj.TryRemoveRegAlloc(const Reg: TRegister; p1, p2: tai): Boolean;
+      var
+        CurrentAlloc: tai;
+      begin
+        Result := False;
+        if RegInInstruction(Reg, p1) then
+          { Register is definitely in use }
+          Exit;
+
+        { Search for the first de/alloc before p1 that relates to Reg }
+        CurrentAlloc := tai(p1.Previous);
+        repeat
+          while Assigned(CurrentAlloc) and
+                ((CurrentAlloc.typ in (SkipInstr - [ait_regAlloc])) or
+                 ((CurrentAlloc.typ = ait_label) and
+                  not(Tai_Label(CurrentAlloc).labsym.Is_Used))) do
+            CurrentAlloc := Tai(CurrentAlloc.Previous);
+          if Assigned(CurrentAlloc) and
+            (CurrentAlloc.typ = ait_regalloc) then
+            begin
+              if (getregtype(tai_regalloc(CurrentAlloc).Reg) = getregtype(Reg)) and
+                (getsupreg(tai_regalloc(CurrentAlloc).Reg) = getsupreg(Reg)) then
+               begin
+                 Break;
+               end;
+              CurrentAlloc := Tai(CurrentAlloc.Previous);
+            end
+          else
+            begin
+              CurrentAlloc := nil;
+              Break;
+            end;
+        until false;
+
+        { Remove any register allocation prior to p1 }
+        if Assigned(CurrentAlloc) and (CurrentAlloc.typ = ait_regalloc) and
+          (tai_regalloc(CurrentAlloc).ratype = ra_alloc) then
+          begin
+            RemoveInstruction(CurrentAlloc);
+            Result := True;
+          end
+        else if not Assigned(CurrentAlloc) or (CurrentAlloc.typ <> ait_regalloc) or
+          (tai_regalloc(CurrentAlloc).ratype <> ra_dealloc) then
+          begin
+            AsmL.InsertBefore(tai_regalloc.dealloc(Reg, nil), p1);
+            Result := True;
+          end;
+
+        if (p1 <> p2) and RegInInstruction(Reg, p2) then
+          begin
+            { Reg is in use, so insert allocation before it }
+            AsmL.InsertBefore(tai_regalloc.alloc(Reg, nil), p2);
+            Exit;
+          end;
+
+        { If a deallocation exists, remove it since the register will no longer be allocated by this time }
+        CurrentAlloc := FindRegDealloc(Reg, tai(p2.Next));
+        if Assigned(CurrentAlloc) and (CurrentAlloc.typ = ait_regalloc) and
+          (tai_regalloc(CurrentAlloc).ratype = ra_dealloc) then
+          begin
+            RemoveInstruction(CurrentAlloc);
+          end
+        else
+          begin
+            { Since no deallocation was found, Register may end up being used afterwards, so add a new alloc to play safe }
+            AsmL.InsertAfter(tai_regalloc.alloc(Reg, nil), p2);
+          end;
+      end;
+
+
     procedure TAOptObj.PrePeepHoleOpts;
     procedure TAOptObj.PrePeepHoleOpts;
       var
       var
         p: tai;
         p: tai;

+ 99 - 48
compiler/arm/aoptcpu.pas

@@ -86,6 +86,7 @@ Type
     function OptPass1Push(var p: tai): Boolean;
     function OptPass1Push(var p: tai): Boolean;
 
 
     function OptPass2Bcc(var p: tai): Boolean;
     function OptPass2Bcc(var p: tai): Boolean;
+    function OptPass2CMP(var p: tai): Boolean;
     function OptPass2STM(var p: tai): Boolean;
     function OptPass2STM(var p: tai): Boolean;
     function OptPass2STR(var p: tai): Boolean;
     function OptPass2STR(var p: tai): Boolean;
   End;
   End;
@@ -853,53 +854,6 @@ Implementation
                 else
                 else
                   hp1 := hp2;
                   hp1 := hp2;
             end;
             end;
-
-          {
-            change
-            <op> reg,x,y
-            cmp reg,#0
-            into
-            <op>s reg,x,y
-          }
-          if (taicpu(p).oppostfix = PF_None) and
-            (taicpu(p).oper[1]^.val = 0) and
-            { be careful here, following instructions could use other flags
-              however after a jump fpc never depends on the value of flags }
-            { All above instructions set Z and N according to the following
-              Z := result = 0;
-              N := result[31];
-              EQ = Z=1; NE = Z=0;
-              MI = N=1; PL = N=0; }
-            (MatchInstruction(hp1, A_B, [C_EQ,C_NE,C_MI,C_PL], []) or
-            { mov is also possible, but only if there is no shifter operand, it could be an rxx,
-              we are too lazy to check if it is rxx or something else }
-            (MatchInstruction(hp1, A_MOV, [C_EQ,C_NE,C_MI,C_PL], []) and (taicpu(hp1).ops=2))) and
-            GetLastInstruction(p, hp_last) and
-            MatchInstruction(hp_last, [A_ADC,A_ADD,A_BIC,A_SUB,A_MUL,A_MVN,A_MOV,A_ORR,
-              A_EOR,A_AND,A_RSB,A_RSC,A_SBC,A_MLA], [C_None], [PF_None]) and
-            (
-              { mlas is only allowed in arm mode }
-              (taicpu(hp_last).opcode<>A_MLA) or
-              (current_settings.instructionset<>is_thumb)
-            ) and
-            (taicpu(hp_last).oper[0]^.reg = taicpu(p).oper[0]^.reg) and
-            assigned(FindRegDealloc(NR_DEFAULTFLAGS,tai(hp1.Next))) then
-            begin
-              DebugMsg(SPeepholeOptimization + 'OpCmp2OpS done', hp_last);
-
-              taicpu(hp_last).oppostfix:=PF_S;
-
-              { move flag allocation if possible }
-              hp1:=FindRegAlloc(NR_DEFAULTFLAGS,tai(hp_last.Next));
-              if assigned(hp1) then
-                begin
-                  asml.Remove(hp1);
-                  asml.insertbefore(hp1, hp_last);
-                end;
-
-              RemoveCurrentP(p);
-              Result:=true;
-            end;
         end;
         end;
     end;
     end;
 
 
@@ -2135,6 +2089,80 @@ Implementation
     end;
     end;
 
 
 
 
+  function TCpuAsmOptimizer.OptPass2CMP(var p: tai): Boolean;
+    var
+      hp1, hp_last: tai;
+    begin
+      Result := False;
+      if not GetNextInstructionUsingReg(p, hp1, NR_DEFAULTFLAGS) then
+        Exit;
+
+      if (hp1.typ = ait_label) or
+        (
+          (hp1.typ = ait_instruction) and
+          (taicpu(hp1).condition = C_None) and
+          (
+            RegModifiedByInstruction(NR_DEFAULTFLAGS, hp1) or
+            is_calljmp(taicpu(hp1).opcode)
+          )
+        ) then
+        begin
+          { The comparison is a null operation }
+          DebugMsg(SPeepholeOptimization + 'CMP -> nop', p);
+          RemoveCurrentP(p);
+          Result := True;
+          Exit;
+        end;
+
+      {
+        change
+        <op> reg,x,y
+        cmp reg,#0
+        into
+        <op>s reg,x,y
+      }
+      if (taicpu(p).oppostfix = PF_None) and
+        (taicpu(p).oper[1]^.val = 0) and
+        { be careful here, following instructions could use other flags
+          however after a jump fpc never depends on the value of flags }
+        { All above instructions set Z and N according to the following
+          Z := result = 0;
+          N := result[31];
+          EQ = Z=1; NE = Z=0;
+          MI = N=1; PL = N=0; }
+        (MatchInstruction(hp1, [A_B, A_CMP, A_CMN, A_TST, A_TEQ], [C_EQ,C_NE,C_MI,C_PL], []) or
+        { mov is also possible, but only if there is no shifter operand, it could be an rxx,
+          we are too lazy to check if it is rxx or something else }
+        (MatchInstruction(hp1, A_MOV, [C_EQ,C_NE,C_MI,C_PL], []) and (taicpu(hp1).ops=2))) and
+        GetLastInstruction(p, hp_last) and
+        MatchInstruction(hp_last, [A_ADC,A_ADD,A_BIC,A_SUB,A_MUL,A_MVN,A_MOV,A_ORR,
+          A_EOR,A_AND,A_RSB,A_RSC,A_SBC,A_MLA], [C_None], [PF_None]) and
+        (
+          { mlas is only allowed in arm mode }
+          (taicpu(hp_last).opcode<>A_MLA) or
+          (current_settings.instructionset<>is_thumb)
+        ) and
+        (taicpu(hp_last).oper[0]^.reg = taicpu(p).oper[0]^.reg) and
+        assigned(FindRegDealloc(NR_DEFAULTFLAGS,tai(hp1.Next))) then
+        begin
+          DebugMsg(SPeepholeOptimization + 'OpCmp2OpS done', hp_last);
+
+          taicpu(hp_last).oppostfix:=PF_S;
+
+          { move flag allocation if possible }
+          hp1:=FindRegAlloc(NR_DEFAULTFLAGS,tai(hp_last.Next));
+          if assigned(hp1) then
+            begin
+              asml.Remove(hp1);
+              asml.insertbefore(hp1, hp_last);
+            end;
+
+          RemoveCurrentP(p);
+          Result:=true;
+        end;
+    end;
+
+
   function TCpuAsmOptimizer.OptPass2STR(var p: tai): Boolean;
   function TCpuAsmOptimizer.OptPass2STR(var p: tai): Boolean;
     var
     var
       hp1: tai;
       hp1: tai;
@@ -2388,12 +2416,18 @@ Implementation
       if p.typ = ait_instruction then
       if p.typ = ait_instruction then
         begin
         begin
           case taicpu(p).opcode of
           case taicpu(p).opcode of
+            A_AND:
+              Result := OptPass2AND(p);
+            A_CMP:
+              Result := OptPass2CMP(p);
             A_B:
             A_B:
               Result := OptPass2Bcc(p);
               Result := OptPass2Bcc(p);
             A_STM:
             A_STM:
               Result := OptPass2STM(p);
               Result := OptPass2STM(p);
             A_STR:
             A_STR:
               Result := OptPass2STR(p);
               Result := OptPass2STR(p);
+            A_TST:
+              Result := OptPass2TST(p);
             else
             else
               ;
               ;
           end;
           end;
@@ -2418,7 +2452,24 @@ Implementation
               (getsupreg(taicpu(p1).oper[0]^.reg)+1=getsupreg(reg)) then
               (getsupreg(taicpu(p1).oper[0]^.reg)+1=getsupreg(reg)) then
         Result:=true
         Result:=true
       else
       else
-        Result:=inherited RegInInstruction(Reg, p1);
+        begin
+          if SuperRegistersEqual(Reg, NR_DEFAULTFLAGS) and (p1.typ = ait_instruction) then
+            begin
+              { Conditional instruction reads CPSR register }
+              if (taicpu(p1).condition <> C_None) then
+                Exit(True);
+
+              { Comparison instructions (and procedural jump) }
+              if (taicpu(p1).opcode in [A_BL, A_CMP, A_CMN, A_TST, A_TEQ]) then
+                Exit(True);
+
+              { Instruction sets CPSR register due to S suffix (floating-point
+                instructios won't raise false positives) }
+              if (taicpu(p1).oppostfix = PF_S) then
+                Exit(True)
+            end;
+          Result:=inherited RegInInstruction(Reg, p1);
+        end;
     end;
     end;
 
 
   const
   const

+ 18 - 0
compiler/arm/aoptcpub.pas

@@ -119,6 +119,24 @@ Implementation
       i : Longint;
       i : Longint;
     begin
     begin
       result:=false;
       result:=false;
+      if (p1.typ <> ait_instruction) then
+        Exit;
+
+      if SuperRegistersEqual(Reg, NR_DEFAULTFLAGS) then
+        begin
+          { Comparison instructions (and procedural jump) }
+          if (taicpu(p1).opcode in [A_BL, A_CMP, A_CMN, A_TST, A_TEQ]) then
+            Exit(True);
+
+          { Instruction sets CPSR register due to S suffix (floating-point
+            instructios won't raise false positives) }
+          if (taicpu(p1).oppostfix = PF_S) then
+            Exit(True);
+
+          { Everything else (conditional instructions only read CPSR) }
+          Exit;
+        end;
+
       case taicpu(p1).opcode of
       case taicpu(p1).opcode of
         A_LDR:
         A_LDR:
           begin
           begin

+ 2 - 3
compiler/arm/cgcpu.pas

@@ -1780,9 +1780,8 @@ unit cgcpu;
         ai: taicpu;
         ai: taicpu;
         l: TAsmLabel;
         l: TAsmLabel;
       begin
       begin
-        if ((cs_check_fpu_exceptions in current_settings.localswitches) and
-            not(FPUARM_HAS_EXCEPTION_TRAPPING in fpu_capabilities[current_settings.fputype]) and
-            (force or current_procinfo.FPUExceptionCheckNeeded)) then
+        if needs_check_for_fpu_exceptions and
+          (force or current_procinfo.FPUExceptionCheckNeeded) then
           begin
           begin
             r:=getintregister(list,OS_INT);
             r:=getintregister(list,OS_INT);
             list.concat(taicpu.op_reg_reg(A_FMRX,r,NR_FPSCR));
             list.concat(taicpu.op_reg_reg(A_FMRX,r,NR_FPSCR));

+ 4 - 0
compiler/arm/narmadd.pas

@@ -573,6 +573,10 @@ interface
                (unsigned and (nodetype in [ltn,lten,gtn,gten]))
                (unsigned and (nodetype in [ltn,lten,gtn,gten]))
               ) then
               ) then
               expectloc:=LOC_FLAGS;
               expectloc:=LOC_FLAGS;
+            if (left.resultdef.typ=floatdef) and
+              ([FPUARM_HAS_VFP_EXTENSION,FPUARM_HAS_VFP_DOUBLE]*fpu_capabilities[current_settings.fputype]<>[]) and
+              needs_check_for_fpu_exceptions then
+              Include(current_procinfo.flags,pi_do_call);
           end;
           end;
       end;
       end;
 
 

+ 41 - 10
compiler/arm/narminl.pas

@@ -61,6 +61,7 @@ implementation
 
 
     uses
     uses
       globtype,verbose,globals,
       globtype,verbose,globals,
+      procinfo,
       cpuinfo, defutil,symdef,aasmdata,aasmcpu,
       cpuinfo, defutil,symdef,aasmdata,aasmcpu,
       cgbase,cgutils,pass_1,pass_2,
       cgbase,cgutils,pass_1,pass_2,
       cpubase,ncgutil,cgobj,cgcpu, hlcgobj,
       cpubase,ncgutil,cgobj,cgcpu, hlcgobj,
@@ -135,6 +136,9 @@ implementation
               else
               else
                 internalerror(2009112401);
                 internalerror(2009112401);
             end;
             end;
+            if ([FPUARM_HAS_VFP_EXTENSION,FPUARM_HAS_VFP_DOUBLE]*fpu_capabilities[current_settings.fputype]<>[]) and
+              needs_check_for_fpu_exceptions then
+              Include(current_procinfo.flags,pi_do_call);
             first_abs_real:=nil;
             first_abs_real:=nil;
           end;
           end;
       end;
       end;
@@ -163,6 +167,9 @@ implementation
               else
               else
                 internalerror(2009112402);
                 internalerror(2009112402);
             end;
             end;
+            if ([FPUARM_HAS_VFP_EXTENSION,FPUARM_HAS_VFP_DOUBLE]*fpu_capabilities[current_settings.fputype]<>[]) and
+              needs_check_for_fpu_exceptions then
+              Include(current_procinfo.flags,pi_do_call);
             first_sqr_real:=nil;
             first_sqr_real:=nil;
           end;
           end;
       end;
       end;
@@ -191,6 +198,9 @@ implementation
               else
               else
                 internalerror(2009112403);
                 internalerror(2009112403);
             end;
             end;
+            if ([FPUARM_HAS_VFP_EXTENSION,FPUARM_HAS_VFP_DOUBLE]*fpu_capabilities[current_settings.fputype]<>[]) and
+              needs_check_for_fpu_exceptions then
+              Include(current_procinfo.flags,pi_do_call);
             first_sqrt_real := nil;
             first_sqrt_real := nil;
           end;
           end;
       end;
       end;
@@ -198,11 +208,13 @@ implementation
 
 
      function tarminlinenode.first_fma : tnode;
      function tarminlinenode.first_fma : tnode;
        begin
        begin
-         if (true) and
-           ((is_double(resultdef)) or (is_single(resultdef))) then
+         if ((is_double(resultdef)) or (is_single(resultdef))) then
            begin
            begin
              expectloc:=LOC_MMREGISTER;
              expectloc:=LOC_MMREGISTER;
              Result:=nil;
              Result:=nil;
+             if ([FPUARM_HAS_VFP_EXTENSION,FPUARM_HAS_VFP_DOUBLE]*fpu_capabilities[current_settings.fputype]<>[]) and
+               needs_check_for_fpu_exceptions then
+               Include(current_procinfo.flags,pi_do_call);
            end
            end
          else
          else
            Result:=inherited first_fma;
            Result:=inherited first_fma;
@@ -400,6 +412,7 @@ implementation
     procedure tarminlinenode.second_abs_long;
     procedure tarminlinenode.second_abs_long;
       var
       var
         opsize : tcgsize;
         opsize : tcgsize;
+        ovloc: tlocation;
       begin
       begin
         if GenerateThumbCode then
         if GenerateThumbCode then
           begin
           begin
@@ -409,17 +422,35 @@ implementation
 
 
         secondpass(left);
         secondpass(left);
         opsize:=def_cgsize(left.resultdef);
         opsize:=def_cgsize(left.resultdef);
-        hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true);
-        location:=left.location;
-        location.register:=cg.getintregister(current_asmdata.CurrAsmList,opsize);
+        if is_64bitint(left.resultdef) then
+          begin
+            hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false);
+            location:=left.location;
+            location.register64.reglo:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
+            location.register64.reghi:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
+            cg64.a_load64_reg_reg(current_asmdata.CurrAsmList,left.location.register64,location.register64);
+            cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_SAR,OS_32,31,left.location.register64.reghi);
+            cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_XOR,OS_32,left.location.register64.reghi,location.register64.reglo);
+            cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_XOR,OS_32,left.location.register64.reghi,location.register64.reghi);
+            current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,location.register64.reglo,location.register64.reglo,left.location.register64.reghi), PF_S));
+            current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,location.register64.reghi,location.register64.reghi,left.location.register64.reghi), PF_S));
+          end
+        else
+          begin
+            hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true);
+            location:=left.location;
+            location.register:=cg.getintregister(current_asmdata.CurrAsmList,opsize);
 
 
-        cg.a_reg_alloc(current_asmdata.CurrAsmList,NR_DEFAULTFLAGS);
-        current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_MOV,location.register,left.location.register), PF_S));
+            cg.a_reg_alloc(current_asmdata.CurrAsmList,NR_DEFAULTFLAGS);
+            current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_MOV,location.register,left.location.register), PF_S));
 
 
-        if GenerateThumb2Code then
-          current_asmdata.CurrAsmList.concat(taicpu.op_cond(A_IT,C_MI));
+            if GenerateThumb2Code then
+              current_asmdata.CurrAsmList.concat(taicpu.op_cond(A_IT,C_MI));
 
 
-        current_asmdata.CurrAsmList.concat(setcondition(taicpu.op_reg_reg_const(A_RSB,location.register,location.register, 0), C_MI));
+            current_asmdata.CurrAsmList.concat(setoppostfix(setcondition(taicpu.op_reg_reg_const(A_RSB,location.register,location.register, 0), C_MI),PF_S));
+          end;
+        location_reset(ovloc,LOC_VOID,opsize);
+        cg.g_overflowCheck_loc(current_asmdata.CurrAsmList,ovloc,resultdef,ovloc);
 
 
         cg.a_reg_dealloc(current_asmdata.CurrAsmList,NR_DEFAULTFLAGS);
         cg.a_reg_dealloc(current_asmdata.CurrAsmList,NR_DEFAULTFLAGS);
       end;
       end;

+ 5 - 5
compiler/arm/narmutil.pas

@@ -26,12 +26,12 @@ unit narmutil;
 interface
 interface
 
 
   uses
   uses
-    cclasses,ngenutil;
+    cclasses,ngenutil,fmodule;
 
 
   type
   type
     tarmnodeutils = class(tnodeutils)
     tarmnodeutils = class(tnodeutils)
       class procedure InsertObjectInfo; override;
       class procedure InsertObjectInfo; override;
-      class procedure insert_init_final_table(entries: tfplist); override;
+      class procedure insert_init_final_table(main : tmodule; entries: tfplist); override;
     end;
     end;
 
 
 
 
@@ -251,7 +251,7 @@ interface
           end;
           end;
       end;
       end;
 
 
-    class procedure tarmnodeutils.insert_init_final_table(entries:tfplist);
+    class procedure tarmnodeutils.insert_init_final_table(main : tmodule; entries:tfplist);
 
 
       procedure genentry(list : TAsmList);
       procedure genentry(list : TAsmList);
         var
         var
@@ -290,7 +290,7 @@ interface
       begin
       begin
         if not(tf_init_final_units_by_calls in target_info.flags) then
         if not(tf_init_final_units_by_calls in target_info.flags) then
           begin
           begin
-            inherited insert_init_final_table(entries);
+            inherited insert_init_final_table(main,entries);
             exit;
             exit;
           end;
           end;
         initList:=TAsmList.create;
         initList:=TAsmList.create;
@@ -332,7 +332,7 @@ interface
         initList.Free;
         initList.Free;
         finalList.Free;
         finalList.Free;
 
 
-        inherited insert_init_final_table(entries);
+        inherited insert_init_final_table(main,entries);
       end;
       end;
 
 
   begin
   begin

+ 247 - 0
compiler/armgen/aoptarm.pas

@@ -57,6 +57,9 @@ Type
     function OptPass1LDR(var p: tai): Boolean; virtual;
     function OptPass1LDR(var p: tai): Boolean; virtual;
     function OptPass1STR(var p: tai): Boolean; virtual;
     function OptPass1STR(var p: tai): Boolean; virtual;
     function OptPass1And(var p: tai): Boolean; virtual;
     function OptPass1And(var p: tai): Boolean; virtual;
+
+    function OptPass2AND(var p: tai): Boolean;
+    function OptPass2TST(var p: tai): Boolean;
   End;
   End;
 
 
   function MatchInstruction(const instr: tai; const op: TCommonAsmOps; const cond: TAsmConds; const postfix: TOpPostfixes): boolean;
   function MatchInstruction(const instr: tai; const op: TCommonAsmOps; const cond: TAsmConds; const postfix: TOpPostfixes): boolean;
@@ -538,6 +541,22 @@ Implementation
                     begin
                     begin
                       if MatchOperand(taicpu(next_hp).oper[0]^, taicpu(p).oper[0]^.reg) then
                       if MatchOperand(taicpu(next_hp).oper[0]^, taicpu(p).oper[0]^.reg) then
                         begin
                         begin
+                          { mov r0,r1; mov r1,r1 - remove second MOV here so
+                            so "RedundantMovProcess 2b" doesn't get erroneously
+                            applied }
+                          if MatchOperand(taicpu(next_hp).oper[0]^, taicpu(next_hp).oper[1]^.reg) then
+                            begin
+                              DebugMsg(SPeepholeOptimization + 'Mov2None 2a 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;
+                            end;
+
                           { 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, next_hp) then
                           if RegUsedBetween(taicpu(p).oper[0]^.reg, p, next_hp) then
                             begin
                             begin
@@ -1582,6 +1601,7 @@ Implementation
                 end
                 end
             end;
             end;
         end;
         end;
+
       {
       {
         change
         change
         and reg1, ...
         and reg1, ...
@@ -1595,5 +1615,232 @@ Implementation
         Result:=true;
         Result:=true;
     end;
     end;
 
 
+
+  function TARMAsmOptimizer.OptPass2AND(var p: tai): Boolean;
+    var
+      hp1, hp2: tai;
+      WorkingReg: TRegister;
+    begin
+      Result := False;
+      {
+        change
+        and  reg1, ...
+        ...
+        cmp  reg1, #0
+        b<ne/eq> @Lbl
+        to
+        ands reg1, ...
+
+        Also:
+
+        and  reg1, ...
+        ...
+        cmp  reg1, #0
+        (reg1 end of life)
+        b<ne/eq> @Lbl
+        to
+        tst  reg1, ...
+      }
+      if (taicpu(p).condition = C_None) and
+        (taicpu(p).ops>=3) and
+        GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
+        MatchInstruction(hp1, A_CMP, [C_None], [PF_None]) and
+        MatchOperand(taicpu(hp1).oper[1]^, 0) and
+{$ifdef AARCH64}
+        (SuperRegistersEqual(taicpu(hp1).oper[0]^.reg, taicpu(p).oper[0]^.reg)) and
+        (
+          (getsubreg(taicpu(hp1).oper[0]^.reg) = getsubreg(taicpu(p).oper[0]^.reg))
+          or
+          (
+            (taicpu(p).oper[2]^.typ = top_const) and
+            (taicpu(p).oper[2]^.val >= 0) and
+            (taicpu(p).oper[2]^.val <= $FFFFFFFF)
+          )
+        ) and
+{$else AARCH64}
+        (taicpu(hp1).oper[0]^.reg = taicpu(p).oper[0]^.reg) and
+{$endif AARCH64}
+
+        not RegModifiedBetween(NR_DEFAULTFLAGS, p, hp1) and
+        GetNextInstruction(hp1, hp2) then
+        begin
+          if MatchInstruction(hp2, [A_B, A_CMP, A_CMN, A_TST{$ifndef AARCH64}, A_TEQ{$endif not AARCH64}], [C_EQ, C_NE], [PF_None]) then
+            begin
+              AllocRegBetween(NR_DEFAULTFLAGS, p, hp1, UsedRegs);
+
+              WorkingReg := taicpu(p).oper[0]^.reg;
+
+              if RegEndOfLife(WorkingReg, taicpu(hp1)) then
+                begin
+                  taicpu(p).opcode := A_TST;
+                  taicpu(p).oppostfix := PF_None;
+                  taicpu(p).loadreg(0, taicpu(p).oper[1]^.reg);
+                  taicpu(p).loadoper(1, taicpu(p).oper[2]^);
+                  if (taicpu(p).ops = 4) then
+                    begin
+                      { Make sure any shifter operator is also transferred }
+                      taicpu(p).loadshifterop(2, taicpu(p).oper[3]^.shifterop^);
+                      taicpu(p).ops := 3;
+                    end
+                  else
+                    taicpu(p).ops := 2;
+
+                  DebugMsg(SPeepholeOptimization + 'AND; CMP -> TST', p);
+                end
+              else
+                begin
+                  taicpu(p).oppostfix := PF_S;
+                  DebugMsg(SPeepholeOptimization + 'AND; CMP -> ANDS', p);
+                end;
+
+              RemoveInstruction(hp1);
+
+              { If a temporary register was used for and/cmp before, we might be
+                able to deallocate the register so it can be used for other
+                optimisations later }
+              if (taicpu(p).opcode = A_TST) and TryRemoveRegAlloc(WorkingReg, p, p) then
+                ExcludeRegFromUsedRegs(WorkingReg, UsedRegs);
+
+              Result := True;
+              Exit;
+            end
+          else if
+            (hp2.typ = ait_label) or
+            { Conditional comparison instructions have already been covered }
+            RegModifiedByInstruction(NR_DEFAULTFLAGS, hp2) then
+            begin
+              { The comparison is a null operation }
+              if RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hp1)) then
+                begin
+                  DebugMsg(SPeepholeOptimization + 'AND; CMP -> nop', p);
+                  RemoveInstruction(hp1);
+                  RemoveCurrentP(p);
+                end
+              else
+                begin
+                  DebugMsg(SPeepholeOptimization + 'CMP -> nop', hp1);
+                  RemoveInstruction(hp1);
+                end;
+              Result := True;
+              Exit;
+            end;
+        end;
+    end;
+
+
+  function TARMAsmOptimizer.OptPass2TST(var p: tai): Boolean;
+    var
+      hp1, hp2: tai;
+    begin
+      Result := False;
+      if
+{$ifndef AARCH64}
+        (taicpu(p).condition = C_None) and
+{$endif AARCH64}
+        GetNextInstruction(p, hp1) and
+        MatchInstruction(hp1, A_B, [C_EQ, C_NE], [PF_None]) and
+        GetNextInstructionUsingReg(hp1, hp2, taicpu(p).oper[0]^.reg) then
+        begin
+          case taicpu(hp2).opcode of
+            A_AND:
+              { Change:
+                 tst  r1,##
+                 (r2 not in use, or r2 = r1)
+                 b.c  .Lbl
+                 ...
+                 and  r2,r1,##
+
+               Optimise to:
+                 ands r2,r1,##
+                 b.c  .Lbl
+                 ...
+              }
+              if (taicpu(hp2).oppostfix in [PF_None, PF_S]) and
+{$ifndef AARCH64}
+                (taicpu(hp2).condition = C_None) and
+{$endif AARCH64}
+                (taicpu(hp2).ops = taicpu(p).ops + 1) and
+                  not RegInUsedRegs(taicpu(hp2).oper[0]^.reg, UsedRegs) and
+                  MatchOperand(taicpu(hp2).oper[1]^, taicpu(p).oper[0]^.reg) and
+                  MatchOperand(taicpu(hp2).oper[2]^, taicpu(p).oper[1]^) and
+                  (
+                    (taicpu(hp2).ops = 3) or
+                    MatchOperand(taicpu(hp2).oper[3]^, taicpu(p).oper[2]^)
+                  ) and
+                  (
+                    not (cs_opt_level3 in current_settings.optimizerswitches) or
+                    (
+                      { Make sure the target register isn't used in between }
+                      not RegUsedBetween(taicpu(hp2).oper[0]^.reg, hp1, hp2) and
+                      (
+                        { If the second operand is a register, make sure it isn't modified in between }
+                        (taicpu(p).oper[1]^.typ <> top_reg) or
+                        not RegModifiedBetween(taicpu(p).oper[1]^.reg, hp1, hp2)
+                      )
+                    )
+                  ) then
+                  begin
+                    AllocRegBetween(taicpu(hp2).oper[0]^.reg, p, hp2, UsedRegs);
+
+                    if (taicpu(hp2).oppostfix = PF_S) then
+                      AllocRegBetween(NR_DEFAULTFLAGS, p, hp2, UsedRegs);
+
+                    DebugMsg(SPeepholeOptimization + 'TST; B.c; AND -> ANDS; B.c (TstBcAnd2AndsBc)', p);
+                    taicpu(hp2).oppostfix := PF_S;
+
+                    Asml.Remove(hp2);
+                    Asml.InsertAfter(hp2, p);
+
+                    RemoveCurrentP(p, hp2);
+                    Result := True;
+
+                    Exit;
+                  end;
+            A_TST:
+              { Change:
+                 tst  r1,##
+                 b.c  .Lbl
+                 ... (flags not modified)
+                 tst  r1,##
+
+                Remove second tst
+              }
+              if
+{$ifndef AARCH64}
+                (taicpu(hp2).condition = C_None) and
+{$endif AARCH64}
+                (taicpu(hp2).ops = taicpu(p).ops) and
+                MatchOperand(taicpu(hp2).oper[0]^, taicpu(p).oper[0]^.reg) and
+                MatchOperand(taicpu(hp2).oper[1]^, taicpu(p).oper[1]^) and
+                (
+                  (taicpu(hp2).ops = 2) or
+                  MatchOperand(taicpu(hp2).oper[2]^, taicpu(p).oper[2]^)
+                ) and
+                (
+                  not (cs_opt_level3 in current_settings.optimizerswitches) or
+                  (
+                    { Make sure the flags aren't modified in between }
+                    not RegModifiedBetween(NR_DEFAULTFLAGS, hp1, hp2) and
+                    (
+                      { If the second operand is a register, make sure it isn't modified in between }
+                      (taicpu(p).oper[1]^.typ <> top_reg) or
+                      not RegModifiedBetween(taicpu(p).oper[1]^.reg, hp1, hp2)
+                    )
+                  )
+                ) then
+                begin
+                  DebugMsg(SPeepholeOptimization + 'TST; B.c; TST -> TST; B.c (TstBcTst2TstBc)', p);
+
+                  AllocRegBetween(NR_DEFAULTFLAGS, hp1, hp2, UsedRegs);
+                  RemoveInstruction(hp2);
+                  Result := True;
+                  Exit;
+                end;
+            else
+              ;
+          end;
+        end;
+    end;
+
 end.
 end.
 
 

+ 73 - 27
compiler/assemble.pas

@@ -1127,22 +1127,22 @@ Implementation
         ssingle: single;
         ssingle: single;
         ddouble: double;
         ddouble: double;
 {$ifdef FPC_COMP_IS_INT64}
 {$ifdef FPC_COMP_IS_INT64}
-	ccomp: int64;
+        ccomp: int64;
 {$else}
 {$else}
         ccomp: comp;
         ccomp: comp;
 {$endif}
 {$endif}
-	comp_data_size : byte;
+        comp_data_size : byte;
 {$if defined(cpuextended) and defined(FPC_HAS_TYPE_EXTENDED)}
 {$if defined(cpuextended) and defined(FPC_HAS_TYPE_EXTENDED)}
         eextended: extended;
         eextended: extended;
 {$else}
 {$else}
 {$ifdef FPC_SOFT_FPUX80}
 {$ifdef FPC_SOFT_FPUX80}
 {$define USE_SOFT_FLOATX80}
 {$define USE_SOFT_FLOATX80}
-	f32 : float32;
-	f64 : float64;
-	eextended: floatx80;
-	gap_ofs_low,gap_ofs_high : byte;
-	gap_index, gap_size : byte;
-	has_gap : boolean;
+        f32 : float32;
+        f64 : float64;
+        eextended: floatx80;
+        gap_ofs_low,gap_ofs_high : byte;
+        gap_index, gap_size : byte;
+        has_gap : boolean;
 {$endif}
 {$endif}
 {$endif cpuextended}
 {$endif cpuextended}
       begin
       begin
@@ -1167,20 +1167,20 @@ Implementation
 {$push}{$warn 6018 off} { Unreachable code due to compile time evaluation }
 {$push}{$warn 6018 off} { Unreachable code due to compile time evaluation }
              aitrealconst_s80bit:
              aitrealconst_s80bit:
                begin
                begin
-     	         if sizeof(tai_realconst(hp).value.s80val) = sizeof(double) then
+                      if sizeof(tai_realconst(hp).value.s80val) = sizeof(double) then
                    writer.AsmWriteLn(asminfo^.comment+'Emulated s80bit real value (on s64bit): '+double2str(tai_realconst(hp).value.s80val))
                    writer.AsmWriteLn(asminfo^.comment+'Emulated s80bit real value (on s64bit): '+double2str(tai_realconst(hp).value.s80val))
-     	         else if sizeof(tai_realconst(hp).value.s80val) = sizeof(single) then
+                      else if sizeof(tai_realconst(hp).value.s80val) = sizeof(single) then
                    writer.AsmWriteLn(asminfo^.comment+'Emulated s80bit real value (on s32bit): '+single2str(tai_realconst(hp).value.s80val))
                    writer.AsmWriteLn(asminfo^.comment+'Emulated s80bit real value (on s32bit): '+single2str(tai_realconst(hp).value.s80val))
                 else
                 else
-     	         internalerror(2017091901);
-       	      end;
+                      internalerror(2017091901);
+                     end;
 {$pop}
 {$pop}
 {$endif}
 {$endif}
 {$endif cpuextended}
 {$endif cpuextended}
               aitrealconst_s64comp:
               aitrealconst_s64comp:
                 begin
                 begin
                   writer.AsmWriteLn(asminfo^.comment+'s64comp real value: '+extended2str(tai_realconst(hp).value.s64compval));
                   writer.AsmWriteLn(asminfo^.comment+'s64comp real value: '+extended2str(tai_realconst(hp).value.s64compval));
-	          comp_data_size:=sizeof(comp);
+                  comp_data_size:=sizeof(comp);
                   if (comp_data_size<>tai_realconst(hp).datasize) then
                   if (comp_data_size<>tai_realconst(hp).datasize) then
                     writer.AsmWriteLn(asminfo^.comment+'s64comp value type size is '+tostr(comp_data_size)+' but datasize is '+tostr(tai_realconst(hp).datasize));
                     writer.AsmWriteLn(asminfo^.comment+'s64comp value type size is '+tostr(comp_data_size)+' but datasize is '+tostr(tai_realconst(hp).datasize));
                 end
                 end
@@ -1215,7 +1215,7 @@ Implementation
 {$push}{$warn 6018 off} { Unreachable code due to compile time evaluation }
 {$push}{$warn 6018 off} { Unreachable code due to compile time evaluation }
           aitrealconst_s80bit:
           aitrealconst_s80bit:
             begin
             begin
-	      if sizeof(tai_realconst(hp).value.s80val) = sizeof(double) then
+              if sizeof(tai_realconst(hp).value.s80val) = sizeof(double) then
                 begin
                 begin
                   f64:=float64(double(tai_realconst(hp).value.s80val));
                   f64:=float64(double(tai_realconst(hp).value.s80val));
                   if float64_is_signaling_nan(f64)<>0 then
                   if float64_is_signaling_nan(f64)<>0 then
@@ -1225,23 +1225,23 @@ Implementation
                     end;
                     end;
                   eextended:=float64_to_floatx80(f64);
                   eextended:=float64_to_floatx80(f64);
                 end
                 end
-	      else if sizeof(tai_realconst(hp).value.s80val) = sizeof(single) then
+              else if sizeof(tai_realconst(hp).value.s80val) = sizeof(single) then
                 begin
                 begin
                   f32:=float32(single(tai_realconst(hp).value.s80val));
                   f32:=float32(single(tai_realconst(hp).value.s80val));
                   if float32_is_signaling_nan(f32)<>0 then
                   if float32_is_signaling_nan(f32)<>0 then
                     begin
                     begin
                       f32 := longword($ffc00000);
                       f32 := longword($ffc00000);
-	            end;
+                    end;
                   eextended:=float32_to_floatx80(f32);
                   eextended:=float32_to_floatx80(f32);
                 end
                 end
-	      else
-	        internalerror(2017091902);
+              else
+                internalerror(2017091902);
               pdata:=@eextended;
               pdata:=@eextended;
               if sizeof(eextended)>10 then
               if sizeof(eextended)>10 then
                 begin
                 begin
                   gap_ofs_high:=(pbyte(@eextended.high) - pbyte(@eextended));
                   gap_ofs_high:=(pbyte(@eextended.high) - pbyte(@eextended));
                   gap_ofs_low:=(pbyte(@eextended.low) - pbyte(@eextended));
                   gap_ofs_low:=(pbyte(@eextended.low) - pbyte(@eextended));
-		  if (gap_ofs_low<gap_ofs_high) then
+                  if (gap_ofs_low<gap_ofs_high) then
                     begin
                     begin
                       gap_index:=gap_ofs_low+sizeof(eextended.low);
                       gap_index:=gap_ofs_low+sizeof(eextended.low);
                       gap_size:=gap_ofs_high-gap_index;
                       gap_size:=gap_ofs_high-gap_index;
@@ -1252,7 +1252,7 @@ Implementation
                       gap_size:=gap_ofs_low-gap_index;
                       gap_size:=gap_ofs_low-gap_index;
                     end;
                     end;
                   if source_info.endian<>target_info.endian then
                   if source_info.endian<>target_info.endian then
-		      gap_index:=gap_index+gap_size-1;
+                      gap_index:=gap_index+gap_size-1;
                   has_gap:=gap_size <> 0;
                   has_gap:=gap_size <> 0;
                 end
                 end
               else
               else
@@ -1680,7 +1680,7 @@ Implementation
               write a the value field with relocation }
               write a the value field with relocation }
             oldsec:=ObjData.CurrObjSec;
             oldsec:=ObjData.CurrObjSec;
             ObjData.SetSection(ObjData.StabsSec);
             ObjData.SetSection(ObjData.StabsSec);
-	    MaybeSwapStab(stab);
+            MaybeSwapStab(stab);
             ObjData.Writebytes(stab,sizeof(TObjStabEntry)-4);
             ObjData.Writebytes(stab,sizeof(TObjStabEntry)-4);
             ObjData.Writereloc(stab.nvalue,4,relocsym,RELOC_ABSOLUTE32);
             ObjData.Writereloc(stab.nvalue,4,relocsym,RELOC_ABSOLUTE32);
             ObjData.setsection(oldsec);
             ObjData.setsection(oldsec);
@@ -2169,17 +2169,26 @@ Implementation
         ddouble : double;
         ddouble : double;
         {$if defined(cpuextended) and defined(FPC_HAS_TYPE_EXTENDED)}
         {$if defined(cpuextended) and defined(FPC_HAS_TYPE_EXTENDED)}
         eextended : extended;
         eextended : extended;
-	{$else}
+        {$else}
         {$ifdef FPC_SOFT_FPUX80}
         {$ifdef FPC_SOFT_FPUX80}
-	f32 : float32;
-	f64 : float64;
-	eextended : floatx80;
+        f32 : float32;
+        f64 : float64;
+        eextended : floatx80;
         {$endif}
         {$endif}
         {$endif}
         {$endif}
-        ccomp : comp;
+{$ifdef FPC_COMP_IS_INT64}
+        ccomp: int64;
+{$else}
+        ccomp: comp;
+{$endif}
+        comp_data_size : byte;
         tmp    : word;
         tmp    : word;
         cpu: tcputype;
         cpu: tcputype;
         ddword : dword;
         ddword : dword;
+        b : byte;
+        w : word;
+        d : dword;
+        q : qword;
         eabi_section: TObjSection;
         eabi_section: TObjSection;
         s: String;
         s: String;
         TmpDataPos: TObjSectionOfs;
         TmpDataPos: TObjSectionOfs;
@@ -2286,12 +2295,22 @@ Implementation
          {$endif cpuextended}
          {$endif cpuextended}
                    aitrealconst_s64comp:
                    aitrealconst_s64comp:
                      begin
                      begin
+{$ifdef FPC_COMP_IS_INT64}
+                       ccomp:=system.trunc(tai_realconst(hp).value.s64compval);
+{$else}
                        ccomp:=comp(tai_realconst(hp).value.s64compval);
                        ccomp:=comp(tai_realconst(hp).value.s64compval);
+{$endif}
                        pdata:=@ccomp;
                        pdata:=@ccomp;
                      end;
                      end;
                    else
                    else
                      internalerror(2015030501);
                      internalerror(2015030501);
                  end;
                  end;
+                 if source_info.endian<>target_info.endian then
+                   begin
+                     for d:=0 to tai_realconst(hp).datasize-1 do
+                       lebbuf[d]:=pbyte(pdata)[tai_realconst(hp).datasize-1-d];
+                     pdata:=@lebbuf;
+                   end;
                  ObjData.writebytes(pdata^,tai_realconst(hp).datasize);
                  ObjData.writebytes(pdata^,tai_realconst(hp).datasize);
                  ObjData.writebytes(zerobuf,tai_realconst(hp).savesize-tai_realconst(hp).datasize);
                  ObjData.writebytes(zerobuf,tai_realconst(hp).savesize-tai_realconst(hp).datasize);
                end;
                end;
@@ -2346,7 +2365,34 @@ Implementation
                        else if relative_reloc then
                        else if relative_reloc then
                          ObjData.writereloc(ObjData.CurrObjSec.size+tai_const(hp).size-objsym.address+tai_const(hp).symofs,tai_const(hp).size,objsymend,RELOC_RELATIVE)
                          ObjData.writereloc(ObjData.CurrObjSec.size+tai_const(hp).size-objsym.address+tai_const(hp).symofs,tai_const(hp).size,objsymend,RELOC_RELATIVE)
                        else
                        else
-                         ObjData.writebytes(Tai_const(hp).value,tai_const(hp).size);
+                         if source_info.endian<>target_info.endian then
+                           begin
+                             case tai_const(hp).size of
+                                1 : begin
+                                      b:=byte(Tai_const(hp).value);
+                                      ObjData.writebytes(b,1);
+                                    end;
+                                2 : begin
+                                      w:=word(Tai_const(hp).value);
+                                      w:=swapendian(w);
+                                      ObjData.writebytes(w,2);
+                                    end;
+                                4 : begin
+                                      d:=dword(Tai_const(hp).value);
+                                      d:=swapendian(d);
+                                      ObjData.writebytes(d,4);
+                                    end;
+                                8 : begin
+                                      q:=qword(Tai_const(hp).value);
+                                      q:=swapendian(q);
+                                      ObjData.writebytes(q,8);
+                                    end;
+                             else
+                               internalerror(2024012502);
+                             end;
+                           end
+                         else
+                           ObjData.writebytes(Tai_const(hp).value,tai_const(hp).size);
                      end;
                      end;
                    aitconst_rva_symbol :
                    aitconst_rva_symbol :
                      begin
                      begin

+ 9 - 7
compiler/avr/aoptcpu.pas

@@ -444,12 +444,16 @@ Implementation
       }
       }
       else if not(cs_opt_level3 in current_settings.optimizerswitches) and
       else if not(cs_opt_level3 in current_settings.optimizerswitches) and
       (taicpu(p).oper[0]^.typ=top_reg) and
       (taicpu(p).oper[0]^.typ=top_reg) and
+      assigned(FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous))) and
       (GetNextInstruction(p,hp1)) and MatchInstruction(hp1,A_LDS) and
       (GetNextInstruction(p,hp1)) and MatchInstruction(hp1,A_LDS) and
       (taicpu(hp1).oper[0]^.typ=top_reg) and
       (taicpu(hp1).oper[0]^.typ=top_reg) and
+      assigned(FindRegAllocBackward(taicpu(hp1).oper[0]^.reg,tai(hp1.Previous))) and
       (GetNextInstruction(hp1, hp2)) and MatchInstruction(hp2,A_MOV) and
       (GetNextInstruction(hp1, hp2)) and MatchInstruction(hp2,A_MOV) and
       (taicpu(hp2).oper[1]^.reg=taicpu(p).oper[0]^.reg) and
       (taicpu(hp2).oper[1]^.reg=taicpu(p).oper[0]^.reg) and
+      assigned(FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp2.Next))) and
       (GetNextInstruction(hp2, hp3)) and MatchInstruction(hp3,A_MOV) and
       (GetNextInstruction(hp2, hp3)) and MatchInstruction(hp3,A_MOV) and
-      (taicpu(hp3).oper[1]^.reg=taicpu(hp1).oper[0]^.reg) then
+      (taicpu(hp3).oper[1]^.reg=taicpu(hp1).oper[0]^.reg) and
+      assigned(FindRegDeAlloc(taicpu(hp1).oper[0]^.reg,tai(hp3.Next))) then
       begin
       begin
         DebugMsg('Peephole LdsLdsMovMov2LdsLds performed', p);
         DebugMsg('Peephole LdsLdsMovMov2LdsLds performed', p);
 
 
@@ -498,21 +502,19 @@ Implementation
       (not RegModifiedBetween(taicpu(p).oper[0]^.reg, p, hp1)) and
       (not RegModifiedBetween(taicpu(p).oper[0]^.reg, p, hp1)) and
       (not RegUsedBetween(taicpu(hp1).oper[0]^.reg, p, hp1)) then
       (not RegUsedBetween(taicpu(hp1).oper[0]^.reg, p, hp1)) then
       begin
       begin
-        DebugMsg('Peephole LdsMov2Lds performed', p);
-
         alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
         alloc:=FindRegAllocBackward(taicpu(p).oper[0]^.reg,tai(p.Previous));
         dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next));
         dealloc:=FindRegDeAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next));
         if assigned(alloc) and assigned(dealloc) then
         if assigned(alloc) and assigned(dealloc) then
           begin
           begin
+            DebugMsg('Peephole LdsMov2Lds performed', p);
             asml.Remove(alloc);
             asml.Remove(alloc);
             alloc.Free;
             alloc.Free;
             asml.Remove(dealloc);
             asml.Remove(dealloc);
             dealloc.Free;
             dealloc.Free;
+            taicpu(p).oper[0]^.reg:=taicpu(hp1).oper[0]^.reg;
+            RemoveInstruction(hp1);
+            result:=true;
           end;
           end;
-
-        taicpu(p).oper[0]^.reg:=taicpu(hp1).oper[0]^.reg;
-        RemoveInstruction(hp1);
-        result:=true;
       end;
       end;
     end;
     end;
 
 

+ 5 - 4
compiler/avr/navrutil.pas

@@ -27,6 +27,7 @@ interface
 
 
   uses
   uses
     cclasses,
     cclasses,
+    fmodule,
     node,nbas,
     node,nbas,
     ngenutil,
     ngenutil,
     symtype,symconst,symsym,symdef;
     symtype,symconst,symsym,symdef;
@@ -35,13 +36,13 @@ interface
   type
   type
     tavrnodeutils = class(tnodeutils)
     tavrnodeutils = class(tnodeutils)
     protected
     protected
-      class procedure insert_init_final_table(entries:tfplist); override;
+      class procedure insert_init_final_table(main: tmodule; entries:tfplist); override;
     end;
     end;
 
 
 implementation
 implementation
 
 
     uses
     uses
-      verbose,cutils,globtype,globals,constexp,fmodule,
+      verbose,cutils,globtype,globals,constexp,
       aasmdata,aasmtai,aasmcpu,aasmcnst,aasmbase,
       aasmdata,aasmtai,aasmcpu,aasmcnst,aasmbase,
       cpubase,
       cpubase,
       symbase,symcpu,symtable,defutil,
       symbase,symcpu,symtable,defutil,
@@ -52,7 +53,7 @@ implementation
       pass_1;
       pass_1;
 
 
 
 
-  class procedure tavrnodeutils.insert_init_final_table(entries:tfplist);
+  class procedure tavrnodeutils.insert_init_final_table(main: tmodule; entries:tfplist);
     var
     var
       op : TAsmOp;
       op : TAsmOp;
       initList, finalList, header: TAsmList;
       initList, finalList, header: TAsmList;
@@ -104,7 +105,7 @@ implementation
       initList.Free;
       initList.Free;
       finalList.Free;
       finalList.Free;
 
 
-      inherited insert_init_final_table(entries);
+      inherited insert_init_final_table(main,entries);
     end;
     end;
 
 
 begin
 begin

+ 2 - 0
compiler/browcol.pas

@@ -1778,9 +1778,11 @@ begin
            name:=GetStr(T.Name);
            name:=GetStr(T.Name);
            msource:=hp.mainsource;
            msource:=hp.mainsource;
            New(UnitS, Init(Name,msource));
            New(UnitS, Init(Name,msource));
+{          // A unit can be loaded from many other places, so a single loaded_from is misleading.
            if Assigned(hp.loaded_from) then
            if Assigned(hp.loaded_from) then
              if assigned(hp.loaded_from.globalsymtable) then
              if assigned(hp.loaded_from.globalsymtable) then
                UnitS^.SetLoadedFrom(tsymtable(hp.loaded_from.globalsymtable).name^);
                UnitS^.SetLoadedFrom(tsymtable(hp.loaded_from.globalsymtable).name^);
+               }
 {           pimportlist(current_module^.imports^.first);}
 {           pimportlist(current_module^.imports^.first);}
 
 
            if assigned(hp.sourcefiles) then
            if assigned(hp.sourcefiles) then

+ 24 - 0
compiler/cgutils.pas

@@ -224,11 +224,17 @@ unit cgutils;
       WARNING: d must not be a power of 2 (including 2^0 = 1) }
       WARNING: d must not be a power of 2 (including 2^0 = 1) }
     procedure calc_mul_inverse(N: byte; d: aWord; out reciprocal: aWord; out shift: Byte);
     procedure calc_mul_inverse(N: byte; d: aWord; out reciprocal: aWord; out shift: Byte);
 
 
+    { returns true if the CPU architecture we are currently compiling for needs
+      software checks for fpu exceptions }
+    function needs_check_for_fpu_exceptions : boolean;
+
 implementation
 implementation
 
 
 uses
 uses
   systems,
   systems,
   verbose,
   verbose,
+  globals,
+  cpuinfo,
   cgobj;
   cgobj;
 
 
 {****************************************************************************
 {****************************************************************************
@@ -570,6 +576,24 @@ uses
           reciprocal:=swap_r;
           reciprocal:=swap_r;
         until d<=1;
         until d<=1;
       end;
       end;
+
+
+    function needs_check_for_fpu_exceptions: boolean;
+      begin
+{$if defined(AARCH64)}
+        result:=cs_check_fpu_exceptions in current_settings.localswitches;
+{$elseif defined(ARM)}
+        result:=(cs_check_fpu_exceptions in current_settings.localswitches) and
+          not(FPUARM_HAS_EXCEPTION_TRAPPING in fpu_capabilities[current_settings.fputype]);
+{$elseif defined(RISCV)}
+        result:=cs_check_fpu_exceptions in current_settings.localswitches;
+{$elseif defined(XTENSA)}
+        result:=cs_check_fpu_exceptions in current_settings.localswitches;
+{$else}
+        result:=false;
+{$endif}
+      end;
+
 {$pop}
 {$pop}
 
 
 end.
 end.

+ 19 - 1
compiler/compiler.pas

@@ -152,6 +152,7 @@ uses
 {$ifdef aix}
 {$ifdef aix}
   ,i_aix
   ,i_aix
 {$endif aix}
 {$endif aix}
+  ,ctask
   ,globtype;
   ,globtype;
 
 
 function Compile(const cmd:TCmdStr):longint;
 function Compile(const cmd:TCmdStr):longint;
@@ -159,6 +160,8 @@ function Compile(const cmd:TCmdStr):longint;
 implementation
 implementation
 
 
 uses
 uses
+  finput,
+  fppu,
   aasmcpu;
   aasmcpu;
 
 
 {$if defined(MEMDEBUG)}
 {$if defined(MEMDEBUG)}
@@ -196,6 +199,7 @@ begin
   DoneGlobals;
   DoneGlobals;
   DoneFileUtils;
   DoneFileUtils;
   donetokens;
   donetokens;
+  DoneTaskHandler;
 end;
 end;
 
 
 
 
@@ -233,6 +237,7 @@ begin
   InitAsm;
   InitAsm;
   InitWpo;
   InitWpo;
 
 
+  InitTaskHandler;
   CompilerInitedAfterArgs:=true;
   CompilerInitedAfterArgs:=true;
 end;
 end;
 
 
@@ -261,6 +266,8 @@ var
 {$endif SHOWUSEDMEM}
 {$endif SHOWUSEDMEM}
   ExceptionMask : TFPUExceptionMask;
   ExceptionMask : TFPUExceptionMask;
   totaltime : real;
   totaltime : real;
+  m : tppumodule;
+
 begin
 begin
   try
   try
     try
     try
@@ -291,7 +298,18 @@ begin
         parser.preprocess(inputfilepath+inputfilename)
         parser.preprocess(inputfilepath+inputfilename)
        else
        else
   {$endif PREPROCWRITE}
   {$endif PREPROCWRITE}
-        parser.compile(inputfilepath+inputfilename);
+         begin
+         m:=tppumodule.create(Nil,'',inputfilepath+inputfilename,false);
+         m.state:=ms_compile;
+         m.is_initial:=true;
+         { We need to add the initial module manually to the list of units }
+         addloadedunit(m);
+         main_module:=m;
+         m.state:=ms_compile;
+         task_handler.addmodule(m);
+         task_handler.processqueue;
+         end;
+
 
 
        { Show statistics }
        { Show statistics }
        if status.errorcount=0 then
        if status.errorcount=0 then

+ 4 - 0
compiler/compinnr.pas

@@ -172,6 +172,10 @@ type
      in_min_longint      = 142,
      in_min_longint      = 142,
      in_max_dword        = 143,
      in_max_dword        = 143,
      in_max_longint      = 144,
      in_max_longint      = 144,
+     in_min_qword        = 145,
+     in_min_int64        = 146,
+     in_max_qword        = 147,
+     in_max_int64        = 148,
 
 
 { MMX functions }
 { MMX functions }
 { these contants are used by the mmx unit }
 { these contants are used by the mmx unit }

+ 1 - 1
compiler/cresstr.pas

@@ -338,7 +338,7 @@ uses
     procedure Tresourcestrings.ConstSym_Register(p:TObject;arg:pointer);
     procedure Tresourcestrings.ConstSym_Register(p:TObject;arg:pointer);
       begin
       begin
         if (tsym(p).typ=constsym) and
         if (tsym(p).typ=constsym) and
-           (tconstsym(p).consttyp=constresourcestring) then
+           (tconstsym(p).consttyp in [constresourcestring,constwresourcestring]) then
           List.Concat(TResourceStringItem.Create(TConstsym(p)));
           List.Concat(TResourceStringItem.Create(TConstsym(p)));
       end;
       end;
 
 

+ 401 - 0
compiler/ctask.pas

@@ -0,0 +1,401 @@
+{
+    Copyright (c) 2024- by Michael Van Canneyt
+
+    This unit handles the compiler tasks.
+
+    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 ctask;
+
+{$mode ObjFPC}
+
+{ $DEFINE DEBUG_CTASK}
+
+interface
+
+uses
+  fmodule, cclasses, globstat;
+
+type
+  { ttask_list }
+
+  ttask_list = class(tlinkedlistitem)
+     module : tmodule;
+     state : tglobalstate;
+     constructor create(_m : tmodule);
+     destructor destroy; override;
+     procedure SaveState;
+     Procedure RestoreState;
+     procedure DiscardState;
+     function nexttask : ttask_list; inline;
+  end;
+
+  ttasklinkedlist = class(tlinkedlist)
+    function firsttask : ttask_list; inline;
+  end;
+
+  { ttask_handler }
+
+
+  ttask_handler = class
+  private
+    list : ttasklinkedlist;
+    hash : TFPHashList;
+    main : tmodule;
+    procedure rebuild_hash;
+  public
+    constructor create;
+    destructor destroy; override;
+    // Find the task for module m
+    function findtask(m : tmodule) : ttask_list;
+    // Can we continue processing this module ? If not, firstwaiting contains first module that m is waiting for.
+    function cancontinue(m : tmodule; checksub : boolean; out firstwaiting: tmodule): boolean;
+    // Overload of cancontinue, based on task.
+    function cancontinue(t: ttask_list; out firstwaiting: tmodule): boolean; inline;
+    // Continue processing this module. Return true if the module is done and can be removed.
+    function continue(t : ttask_list): Boolean;
+    // process the queue. Note that while processing the queue, elements will be added.
+    procedure processqueue;
+    // add a module to the queue. If a module is already in the queue, we do not add it again.
+    procedure addmodule(m : tmodule);
+  end;
+
+
+var
+  task_handler : TTask_handler;
+
+procedure InitTaskHandler;
+procedure DoneTaskHandler;
+
+implementation
+
+uses verbose, fppu, finput, globtype, sysutils, scanner, parser, pmodules;
+
+procedure InitTaskHandler;
+begin
+  task_handler:=ttask_handler.create;
+end;
+
+procedure DoneTaskHandler;
+begin
+  freeandnil(task_handler);
+end;
+
+{ ttasklinkedlist }
+
+function ttasklinkedlist.firsttask: ttask_list;
+begin
+  Result:=ttask_list(first);
+end;
+
+{ ttask_list }
+
+constructor ttask_list.create(_m: tmodule);
+begin
+  inherited create;
+  module:=_m;
+  state:=nil;
+end;
+
+
+destructor ttask_list.destroy;
+begin
+  DiscardState;
+  Inherited;
+end;
+
+procedure ttask_list.DiscardState;
+
+begin
+  FreeAndNil(state);
+end;
+
+function ttask_list.nexttask: ttask_list;
+begin
+  Result:=ttask_list(next);
+end;
+
+procedure ttask_list.SaveState;
+begin
+  if State=Nil then
+    State:=tglobalstate.Create(true)
+  else
+    State.save(true);
+end;
+
+procedure ttask_list.RestoreState;
+begin
+  if not module.is_reset then
+    state.restore(true);
+  if assigned(current_scanner) and assigned(current_scanner.inputfile) then
+      if current_scanner.inputfile.closed then
+      begin
+      current_scanner.tempopeninputfile;
+      current_scanner.gettokenpos;
+      end;
+end;
+
+{ ttask_handler }
+
+constructor ttask_handler.create;
+begin
+  list:=ttasklinkedlist.Create;
+  hash:=TFPHashList.Create;
+end;
+
+destructor ttask_handler.destroy;
+begin
+  hash.free;
+  List.Clear;
+  FreeAndNil(list);
+  inherited destroy;
+end;
+
+function ttask_handler.findtask(m: tmodule): ttask_list;
+
+begin
+  result:=list.FirstTask;
+  while result<>nil do
+    begin
+    if result.module=m then
+      exit;
+    result:=result.nexttask;
+    end;
+  {$IFDEF DEBUG_CTASK}Writeln('No task found for '+m.ToString);{$ENDIF}
+end;
+
+function ttask_handler.cancontinue(m: tmodule; checksub : boolean; out firstwaiting: tmodule): boolean;
+
+  procedure CheckUsed(out acandidate : tmodule);
+
+  var
+    itm : TLinkedListItem;
+    iscandidate : boolean;
+    m2 : tmodule;
+
+  begin
+    acandidate:=nil;
+    itm:=m.used_units.First;
+    while (acandidate=Nil) and assigned(itm) do
+      begin
+      iscandidate:=Not (tused_unit(itm).u.state in [ms_processed,ms_compiled]);
+      if iscandidate then
+        begin
+        acandidate:=tused_unit(itm).u;
+        if not cancontinue(acandidate,false,m2) then
+          acandidate:=nil;
+        end;
+      itm:=itm.Next;
+      end;
+   end;
+
+var
+  m2 : tmodule;
+
+begin
+  firstwaiting:=nil;
+  // We do not need to consider the program as long as there are units that need to be treated.
+  if (m.is_initial and not m.is_unit) and (list.count>1) then
+    exit(False);
+  case m.state of
+    ms_unknown : cancontinue:=true;
+    ms_registered : cancontinue:=true;
+    ms_compile : cancontinue:=true;
+    ms_compiling_waitimpl : cancontinue:=m.usedunitsloaded(false,firstwaiting);
+    ms_compiling_waitfinish : cancontinue:=m.nowaitingforunits(firstwaiting);
+    ms_compiling_waitintf : cancontinue:=m.usedunitsloaded(true,firstwaiting);
+    ms_compiling_wait : cancontinue:=m.usedunitsloaded(true,firstwaiting);
+    ms_compiled : cancontinue:=true;
+    ms_processed : cancontinue:=true;
+    ms_moduleerror : cancontinue:=true;
+  else
+    InternalError(2024011802);
+  end;
+  if (not cancontinue) and checksub then
+    begin
+    checkused(m2);
+    if m2<>nil then
+      firstwaiting:=m2;
+    end;
+  {$IFDEF DEBUG_CTASK}
+  Write(m.ToString,' state: ',m.state,', can continue: ',Result);
+  if result then
+    Writeln
+  else
+    begin
+    Write(' (First waiting: ');
+    If Assigned(FirstWaiting) then
+      Writeln(FirstWaiting.ToString,' )')
+    else
+      Writeln('<none>)');
+    end;
+  {$ENDIF}
+end;
+
+function ttask_handler.cancontinue(t : ttask_list; out firstwaiting : tmodule): boolean;
+
+begin
+  Result:=cancontinue(t.module,true,firstwaiting);
+end;
+
+function ttask_handler.continue(t : ttask_list) : Boolean;
+
+var
+  m : tmodule;
+  orgname : shortstring;
+
+begin
+  m:=t.module;
+  orgname:=m.modulename^;
+  {$IFDEF DEBUG_CTASK}Writeln(m.ToString,' Continues. State: ',m.state);{$ENDIF}
+  if Assigned(t.state) then
+    t.RestoreState;
+  case m.state of
+    ms_registered : parser.compile_module(m);
+    ms_compile : parser.compile_module(m);
+    ms_compiled : if (not m.is_initial) or m.is_unit  then
+                   (m as tppumodule).post_load_or_compile(m,m.compilecount>1);
+    ms_compiling_waitintf : pmodules.parse_unit_interface_declarations(m);
+    ms_compiling_waitimpl : pmodules.proc_unit_implementation(m);
+    ms_compiling_waitfinish : pmodules.finish_unit(m);
+    ms_compiling_wait : pmodules.proc_program_declarations(m,m.islibrary);
+    ms_processed : ;
+  else
+    InternalError(2024011801);
+  end;
+  if m.state=ms_compiled then
+    begin
+    parsing_done(m);
+    if m.is_initial and not m.is_unit then
+      m.state:=ms_processed;
+    end;
+  Result:=m.state=ms_processed;
+  {$IFDEF DEBUG_CTASK}
+  Write(m.ToString,' done: ',Result);
+  if Result then
+    Writeln
+  else
+    Writeln(', state is now: ',m.state);
+  {$ENDIF}
+  if not result then
+    // Not done, save state
+    t.SaveState;
+  {
+    the name can change as a result of processing, e.g. PROGRAM -> TB0406
+    Normally only for the initial module, but we'll do a generic check.
+  }
+  if m.modulename^<>orgname then
+    rebuild_hash;
+end;
+
+procedure ttask_handler.rebuild_hash;
+
+var
+  t : ttask_list;
+
+begin
+  Hash.Clear;
+  t:=list.firsttask;
+  While assigned(t) do
+    begin
+    Hash.Add(t.module.modulename^,t);
+    t:=t.nexttask;
+    end;
+end;
+
+procedure ttask_handler.processqueue;
+
+var
+  t,t2 : ttask_list;
+  process : boolean;
+  dummy,firstwaiting : tmodule;
+
+begin
+  t:=list.firsttask;
+  While t<>nil do
+    begin
+    process:=cancontinue(t,firstwaiting);
+    if process then
+      begin
+      if continue(t) then
+        begin
+        {$IFDEF DEBUG_CTASK}Writeln(t.module.ToString,' is finished, removing from task list');{$ENDIF}
+        hash.Remove(t.module);
+        list.Remove(t);
+        end;
+      // maybe the strategy can be improved.
+      t:=list.firsttask;
+      end
+    else if assigned(firstwaiting) and cancontinue(firstwaiting,true, dummy) then
+      begin
+      t2:=findtask(firstwaiting);
+      if t2=nil then
+        t2:=t.nexttask;
+      t:=t2;
+      end
+    else
+      begin
+      t:=t.nexttask;
+      end;
+    if t=nil then
+      t:=list.firsttask;
+    end;
+end;
+
+procedure ttask_handler.addmodule(m: tmodule);
+
+var
+  n : TSymStr;
+  e, t : ttask_list;
+
+begin
+  {$IFDEF DEBUG_CTASK}Writeln(m.ToString,' added to task scheduler. State: ',m.state);{$ENDIF}
+  n:=m.modulename^;
+  e:=ttask_list(Hash.Find(n));
+  if e=nil then
+    begin
+    // Clear reset flag.
+    // This can happen when during load, reset is done and unit is added to task list.
+    m.is_reset:=false;
+    t:=ttask_list.create(m);
+    list.insert(t);
+    hash.Add(n,t);
+    if list.count=1 then
+      main:=m;
+    end
+  else
+    begin
+    // We have a task, if it was reset, then clear the state and move the task to the start.
+    if m.is_reset then
+      begin
+      {$IFDEF DEBUG_CTASK}Writeln(m.ToString,' was reset, resetting flag. State: ',m.state);{$ENDIF}
+      m.is_reset:=false;
+      t:=findtask(m);
+      if assigned(t) then
+        begin
+        t.DiscardState;
+        list.Remove(t);
+        list.insertbefore(t,list.First);
+        end;
+      end;
+    end;
+end;
+
+
+
+end.
+

+ 2 - 0
compiler/dbgdwarf.pas

@@ -2703,6 +2703,7 @@ implementation
                 usedef:=clongstringtype;
                 usedef:=clongstringtype;
             end;
             end;
           constresourcestring,
           constresourcestring,
+          constwresourcestring,
           constwstring:
           constwstring:
             usedef:=nil;
             usedef:=nil;
           else
           else
@@ -2753,6 +2754,7 @@ implementation
                 end;
                 end;
             end;
             end;
           constwstring,
           constwstring,
+          constwresourcestring,
           constresourcestring:
           constresourcestring:
             begin
             begin
               { write dummy for now }
               { write dummy for now }

+ 4 - 2
compiler/defcmp.pas

@@ -473,11 +473,13 @@ implementation
          if (
          if (
                (df_generic in def_to.defoptions) and
                (df_generic in def_to.defoptions) and
                (df_specialization in def_from.defoptions) and
                (df_specialization in def_from.defoptions) and
-               (tstoreddef(def_from).genericdef=def_to)
+               (tstoreddef(def_from).genericdef=def_to) and
+               assigned(tstoreddef(def_to).genericparas)
              ) or (
              ) or (
                (df_generic in def_from.defoptions) and
                (df_generic in def_from.defoptions) and
                (df_specialization in def_to.defoptions) and
                (df_specialization in def_to.defoptions) and
-               (tstoreddef(def_to).genericdef=def_from)
+               (tstoreddef(def_to).genericdef=def_from) and
+               assigned(tstoreddef(def_from).genericparas)
              ) then
              ) then
            begin
            begin
              if tstoreddef(def_from).genericdef=def_to then
              if tstoreddef(def_from).genericdef=def_to then

+ 9 - 0
compiler/defutil.pas

@@ -283,6 +283,9 @@ interface
     {# Returns true, if def is a 64 bit signed integer type }
     {# Returns true, if def is a 64 bit signed integer type }
     function is_s64bitint(def : tdef) : boolean;
     function is_s64bitint(def : tdef) : boolean;
 
 
+    {# Returns true, if def is a qword type }
+    function is_u64bitint(def : tdef) : boolean;
+
     {# Returns true, if def is a 64 bit ordinal type }
     {# Returns true, if def is a 64 bit ordinal type }
     function is_64bit(def : tdef) : boolean;
     function is_64bit(def : tdef) : boolean;
 
 
@@ -1149,6 +1152,12 @@ implementation
       end;
       end;
 
 
 
 
+    function is_u64bitint(def: tdef): boolean;
+      begin
+        is_u64bitint:=(def.typ=orddef) and (torddef(def).ordtype=u64bit)
+      end;
+
+
     { true, if def is a 64 bit type }
     { true, if def is a 64 bit type }
     function is_64bit(def : tdef) : boolean;
     function is_64bit(def : tdef) : boolean;
       begin
       begin

+ 23 - 9
compiler/finput.pas

@@ -117,17 +117,31 @@ interface
      type
      type
         tmodulestate = (ms_unknown,
         tmodulestate = (ms_unknown,
           ms_registered,
           ms_registered,
-          ms_load,ms_compile,
-          ms_second_load,ms_second_compile,
-          ms_compiled
+          ms_load,
+          ms_compile,
+          ms_compiling_waitintf,
+          ms_compiling_waitimpl,
+          ms_compiling_waitfinish,
+          ms_compiling_wait,
+          ms_compiled,
+          ms_processed,
+          ms_moduleerror
         );
         );
+        tmodulestates = set of tmodulestate;
+
      const
      const
-        ModuleStateStr : array[TModuleState] of string[20] = (
+        ModuleStateStr : array[TModuleState] of string[32] = (
           'Unknown',
           'Unknown',
           'Registered',
           'Registered',
-          'Load','Compile',
-          'Second_Load','Second_Compile',
-          'Compiled'
+          'Load',
+          'Compile',
+          'Compiling_Waiting_interface',
+          'Compiling_Waiting_implementation',
+          'Compiling_Waiting_finish',
+          'Compiling_Waiting',
+          'Compiled',
+          'Processed',
+          'Error'
         );
         );
 
 
      type
      type
@@ -162,6 +176,7 @@ interface
 {$ifdef DEBUG_NODE_XML}
 {$ifdef DEBUG_NODE_XML}
           ppxfilefail: Boolean;     { If the ppxfile could not be accessed, flag it }
           ppxfilefail: Boolean;     { If the ppxfile could not be accessed, flag it }
 {$endif DEBUG_NODE_XML}
 {$endif DEBUG_NODE_XML}
+          is_initial : boolean;     { is this the initial module, i.e. the one specified on the command-line ?}
           constructor create(const s:string);
           constructor create(const s:string);
           destructor destroy;override;
           destructor destroy;override;
           procedure setfilename(const fn:TPathStr;allowoutput:boolean);
           procedure setfilename(const fn:TPathStr;allowoutput:boolean);
@@ -627,8 +642,7 @@ uses
            p:=path;
            p:=path;
 
 
          { lib and exe could be loaded with a file specified with -o }
          { lib and exe could be loaded with a file specified with -o }
-         if AllowOutput and
-            (compile_level=1) and
+         if AllowOutput and is_initial and
             (OutputFileName<>'')then
             (OutputFileName<>'')then
            begin
            begin
              exefilename:=p+OutputFileName;
              exefilename:=p+OutputFileName;

+ 123 - 37
compiler/fmodule.pas

@@ -57,6 +57,10 @@ interface
         rr_noppu,rr_sourcenewer,rr_build,rr_crcchanged
         rr_noppu,rr_sourcenewer,rr_build,rr_crcchanged
       );
       );
 
 
+{$ifdef VER3_2}
+      RTLString = ansistring;
+{$endif VER3_2}
+
       { unit options }
       { unit options }
       tmoduleoption = (mo_none,
       tmoduleoption = (mo_none,
         mo_hint_deprecated,
         mo_hint_deprecated,
@@ -107,6 +111,7 @@ interface
       private
       private
         FImportLibraryList : TFPHashObjectList;
         FImportLibraryList : TFPHashObjectList;
       public
       public
+        is_reset,                 { has reset been called ? }
         do_reload,                { force reloading of the unit }
         do_reload,                { force reloading of the unit }
         do_compile,               { need to compile the sources }
         do_compile,               { need to compile the sources }
         sources_avail,            { if all sources are reachable }
         sources_avail,            { if all sources are reachable }
@@ -163,6 +168,7 @@ interface
         localsymtable : TSymtable;{ pointer to the local symtable of this unit }
         localsymtable : TSymtable;{ pointer to the local symtable of this unit }
         globalmacrosymtable,           { pointer to the global macro symtable of this unit }
         globalmacrosymtable,           { pointer to the global macro symtable of this unit }
         localmacrosymtable : TSymtable;{ pointer to the local macro symtable of this unit }
         localmacrosymtable : TSymtable;{ pointer to the local macro symtable of this unit }
+        mainscanner   : TObject;  { scanner object used }
         scanner       : TObject;  { scanner object used }
         scanner       : TObject;  { scanner object used }
         procinfo      : TObject;  { current procedure being compiled }
         procinfo      : TObject;  { current procedure being compiled }
         asmdata       : TObject;  { Assembler data }
         asmdata       : TObject;  { Assembler data }
@@ -171,7 +177,6 @@ interface
         externasmsyms : TFPHashObjectList; { contains the assembler symbols which are imported from another unit }
         externasmsyms : TFPHashObjectList; { contains the assembler symbols which are imported from another unit }
         unitimportsyms : tfpobjectlist; { list of symbols that are imported from other units }
         unitimportsyms : tfpobjectlist; { list of symbols that are imported from other units }
         debuginfo     : TObject;
         debuginfo     : TObject;
-        loaded_from   : tmodule;
         _exports      : tlinkedlist;
         _exports      : tlinkedlist;
         dllscannerinputlist : TFPHashList;
         dllscannerinputlist : TFPHashList;
         localnamespacelist,
         localnamespacelist,
@@ -198,6 +203,10 @@ interface
 
 
         moduleoptions: tmoduleoptions;
         moduleoptions: tmoduleoptions;
         deprecatedmsg: pshortstring;
         deprecatedmsg: pshortstring;
+        loadcount : integer;
+        compilecount : integer;
+        consume_semicolon_after_uses : Boolean;
+        initfinalchecked : boolean;
 
 
         { contains a list of types that are extended by helper types; the key is
         { contains a list of types that are extended by helper types; the key is
           the full name of the type and the data is a TFPObjectList of
           the full name of the type and the data is a TFPObjectList of
@@ -224,7 +233,6 @@ interface
         waitingunits: tfpobjectlist;
         waitingunits: tfpobjectlist;
 
 
         finishstate: pointer;
         finishstate: pointer;
-        globalstate: pointer;
 
 
         namespace: pshortstring; { for JVM target: corresponds to Java package name }
         namespace: pshortstring; { for JVM target: corresponds to Java package name }
 
 
@@ -246,10 +254,13 @@ interface
         destructor destroy;override;
         destructor destroy;override;
         procedure reset;virtual;
         procedure reset;virtual;
         procedure loadlocalnamespacelist;
         procedure loadlocalnamespacelist;
-        procedure adddependency(callermodule:tmodule);
+        procedure adddependency(callermodule:tmodule; frominterface : boolean);
         procedure flagdependent(callermodule:tmodule);
         procedure flagdependent(callermodule:tmodule);
         procedure addimportedsym(sym:TSymEntry);
         procedure addimportedsym(sym:TSymEntry);
         function  addusedunit(hp:tmodule;inuses:boolean;usym:tunitsym):tused_unit;
         function  addusedunit(hp:tmodule;inuses:boolean;usym:tunitsym):tused_unit;
+        function  usesmodule_in_interface(m : tmodule) : boolean;
+        function usedunitsloaded(interface_units: boolean; out firstwaiting : tmodule): boolean;
+        function nowaitingforunits(out firstwaiting : tmodule) : Boolean;
         procedure updatemaps;
         procedure updatemaps;
         function  derefidx_unit(id:longint):longint;
         function  derefidx_unit(id:longint):longint;
         function  resolve_unit(id:longint):tmodule;
         function  resolve_unit(id:longint):tmodule;
@@ -261,7 +272,9 @@ interface
         procedure add_public_asmsym(const name:TSymStr;bind:TAsmsymbind;typ:Tasmsymtype);
         procedure add_public_asmsym(const name:TSymStr;bind:TAsmsymbind;typ:Tasmsymtype);
         procedure add_extern_asmsym(sym:TAsmSymbol);
         procedure add_extern_asmsym(sym:TAsmSymbol);
         procedure add_extern_asmsym(const name:TSymStr;bind:TAsmsymbind;typ:Tasmsymtype);
         procedure add_extern_asmsym(const name:TSymStr;bind:TAsmsymbind;typ:Tasmsymtype);
+        procedure remove_from_waitingforunits(amodule : tmodule);
         property ImportLibraryList : TFPHashObjectList read FImportLibraryList;
         property ImportLibraryList : TFPHashObjectList read FImportLibraryList;
+        function ToString: RTLString; override;
       end;
       end;
 
 
        tused_unit = class(tlinkedlistitem)
        tused_unit = class(tlinkedlistitem)
@@ -278,7 +291,8 @@ interface
 
 
        tdependent_unit = class(tlinkedlistitem)
        tdependent_unit = class(tlinkedlistitem)
           u : tmodule;
           u : tmodule;
-          constructor create(_u : tmodule);
+          in_interface : boolean;
+          constructor create(_u : tmodule; frominterface : boolean);
        end;
        end;
 
 
     var
     var
@@ -334,6 +348,7 @@ implementation
       end;
       end;
 
 
     procedure set_current_module(p:tmodule);
     procedure set_current_module(p:tmodule);
+
       begin
       begin
         { save the state of the scanner }
         { save the state of the scanner }
         if assigned(current_scanner) then
         if assigned(current_scanner) then
@@ -347,7 +362,7 @@ implementation
             current_asmdata:=tasmdata(current_module.asmdata);
             current_asmdata:=tasmdata(current_module.asmdata);
             current_debuginfo:=tdebuginfo(current_module.debuginfo);
             current_debuginfo:=tdebuginfo(current_module.debuginfo);
             { restore scanner and file positions }
             { restore scanner and file positions }
-            current_scanner:=tscannerfile(current_module.scanner);
+            set_current_scanner(tscannerfile(current_module.scanner));
             if assigned(current_scanner) then
             if assigned(current_scanner) then
               begin
               begin
                 current_scanner.tempopeninputfile;
                 current_scanner.tempopeninputfile;
@@ -363,7 +378,7 @@ implementation
         else
         else
           begin
           begin
             current_asmdata:=nil;
             current_asmdata:=nil;
-            current_scanner:=nil;
+            set_current_scanner(nil);
             current_debuginfo:=nil;
             current_debuginfo:=nil;
           end;
           end;
       end;
       end;
@@ -494,7 +509,7 @@ implementation
         in_interface:=intface;
         in_interface:=intface;
         in_uses:=inuses;
         in_uses:=inuses;
         unitsym:=usym;
         unitsym:=usym;
-        if _u.state=ms_compiled then
+        if _u.state in [ms_compiled,ms_processed] then
          begin
          begin
            checksum:=u.crc;
            checksum:=u.crc;
            interface_checksum:=u.interface_crc;
            interface_checksum:=u.interface_crc;
@@ -534,9 +549,10 @@ implementation
                             TDENPENDENT_UNIT
                             TDENPENDENT_UNIT
  ****************************************************************************}
  ****************************************************************************}
 
 
-    constructor tdependent_unit.create(_u : tmodule);
+    constructor tdependent_unit.create(_u: tmodule; frominterface: boolean);
       begin
       begin
          u:=_u;
          u:=_u;
+         in_interface:=frominterface;
       end;
       end;
 
 
 
 
@@ -630,7 +646,6 @@ implementation
         localsymtable:=nil;
         localsymtable:=nil;
         globalmacrosymtable:=nil;
         globalmacrosymtable:=nil;
         localmacrosymtable:=nil;
         localmacrosymtable:=nil;
-        loaded_from:=LoadedFrom;
         do_reload:=false;
         do_reload:=false;
         do_compile:=false;
         do_compile:=false;
         sources_avail:=true;
         sources_avail:=true;
@@ -660,7 +675,7 @@ implementation
       end;
       end;
 
 
 
 
-    destructor tmodule.Destroy;
+    destructor tmodule.destroy;
       var
       var
         i : longint;
         i : longint;
         current_debuginfo_reset : boolean;
         current_debuginfo_reset : boolean;
@@ -682,8 +697,9 @@ implementation
             { also update current_scanner if it was pointing
             { also update current_scanner if it was pointing
               to this module }
               to this module }
             if current_scanner=tscannerfile(scanner) then
             if current_scanner=tscannerfile(scanner) then
-             current_scanner:=nil;
-            tscannerfile(scanner).free;
+              set_current_scanner(nil);
+            freeandnil(scanner);
+
          end;
          end;
         if assigned(asmdata) then
         if assigned(asmdata) then
           begin
           begin
@@ -779,14 +795,14 @@ implementation
         i   : longint;
         i   : longint;
         current_debuginfo_reset : boolean;
         current_debuginfo_reset : boolean;
       begin
       begin
+        is_reset:=true;
         if assigned(scanner) then
         if assigned(scanner) then
           begin
           begin
             { also update current_scanner if it was pointing
             { also update current_scanner if it was pointing
               to this module }
               to this module }
             if current_scanner=tscannerfile(scanner) then
             if current_scanner=tscannerfile(scanner) then
-             current_scanner:=nil;
-            tscannerfile(scanner).free;
-            scanner:=nil;
+              set_current_scanner(nil);
+            freeandnil(scanner);
           end;
           end;
         if assigned(procinfo) then
         if assigned(procinfo) then
           begin
           begin
@@ -954,32 +970,32 @@ implementation
 
 
     procedure tmodule.loadlocalnamespacelist;
     procedure tmodule.loadlocalnamespacelist;
 
 
-    var
-      nsitem : TCmdStrListItem;
+      var
+        nsitem : TCmdStrListItem;
 
 
-    begin
-      // Copying local namespace list
-      if premodule_namespacelist.Count>0 then
-        begin
-        nsitem:=TCmdStrListItem(premodule_namespacelist.First);
-        while assigned(nsItem) do
+      begin
+        // Copying local namespace list
+        if premodule_namespacelist.Count>0 then
           begin
           begin
-          localnamespacelist.Concat(nsitem.Str);
-          nsItem:=TCmdStrListItem(nsitem.Next);
+          nsitem:=TCmdStrListItem(premodule_namespacelist.First);
+          while assigned(nsItem) do
+            begin
+            localnamespacelist.Concat(nsitem.Str);
+            nsItem:=TCmdStrListItem(nsitem.Next);
+            end;
+          premodule_namespacelist.Clear;
           end;
           end;
-        premodule_namespacelist.Clear;
-        end;
-      current_namespacelist:=localnamespacelist;
-    end;
+        current_namespacelist:=localnamespacelist;
+      end;
 
 
 
 
-    procedure tmodule.adddependency(callermodule:tmodule);
+    procedure tmodule.adddependency(callermodule: tmodule; frominterface: boolean);
       begin
       begin
         { This is not needed for programs }
         { This is not needed for programs }
         if not callermodule.is_unit then
         if not callermodule.is_unit then
           exit;
           exit;
         Message2(unit_u_add_depend_to,callermodule.modulename^,modulename^);
         Message2(unit_u_add_depend_to,callermodule.modulename^,modulename^);
-        dependent_units.concat(tdependent_unit.create(callermodule));
+        dependent_units.concat(tdependent_unit.create(callermodule,frominterface));
       end;
       end;
 
 
 
 
@@ -995,10 +1011,10 @@ implementation
              this unit, unless this unit is already compiled during
              this unit, unless this unit is already compiled during
              the loading }
              the loading }
            if (pm.u=callermodule) and
            if (pm.u=callermodule) and
-              (pm.u.state<>ms_compiled) then
+              (pm.u.state<ms_compiled) then
              Message1(unit_u_no_reload_is_caller,pm.u.modulename^)
              Message1(unit_u_no_reload_is_caller,pm.u.modulename^)
            else
            else
-            if pm.u.state=ms_second_compile then
+            if (pm.u.state=ms_compile) and (pm.u.compilecount>1) then
               Message1(unit_u_no_reload_in_second_compile,pm.u.modulename^)
               Message1(unit_u_no_reload_in_second_compile,pm.u.modulename^)
            else
            else
             begin
             begin
@@ -1026,6 +1042,59 @@ implementation
       end;
       end;
 
 
 
 
+    function tmodule.usedunitsloaded(interface_units : boolean; out firstwaiting : tmodule): boolean;
+
+      const
+        statesneeded : array[boolean] of tmodulestates = ([ms_processed, ms_compiled,ms_compiling_waitimpl, ms_compiling_waitfinish],
+                                                          [ms_processed, ms_compiled,ms_compiling_waitimpl, ms_compiling_waitfinish]);
+
+      var
+        itm : TLinkedListItem;
+        states : set of tmodulestate;
+
+      begin
+        Result:=True;
+        States:=statesneeded[interface_units];
+        itm:=self.used_units.First;
+        firstwaiting:=Nil;
+        while Result and assigned(itm) do
+          begin
+          result:=tused_unit(itm).u.state in states;
+          {$IFDEF DEBUG_CTASK}writeln('  ',ToString,' checking state of ', tused_unit(itm).u.ToString,' : ',tused_unit(itm).u.state,' : ',Result);{$ENDIF}
+          if not result then
+             begin
+             if firstwaiting=Nil then
+                firstwaiting:=tused_unit(itm).u;
+             end;
+          itm:=itm.Next;
+          end;
+      end;
+
+    function tmodule.nowaitingforunits(out firstwaiting : tmodule): Boolean;
+
+      begin
+        firstwaiting:=nil;
+        Result:=waitingforunit.count=0;
+        If not Result then
+          firstwaiting:=tmodule(waitingforunit[0]);
+      end;
+
+    function tmodule.usesmodule_in_interface(m: tmodule): boolean;
+
+      var
+        u : tused_unit;
+
+      begin
+        result:=False;
+        u:=tused_unit(used_units.First);
+        while assigned(u) do
+          begin
+          if (u.u=m) then
+            exit(u.in_interface) ;
+          u:=tused_unit(u.next);
+          end;
+      end;
+
     procedure tmodule.updatemaps;
     procedure tmodule.updatemaps;
       var
       var
         oldmapsize : longint;
         oldmapsize : longint;
@@ -1152,8 +1221,8 @@ implementation
         if assigned(scanner) then
         if assigned(scanner) then
           begin
           begin
             if current_scanner=tscannerfile(scanner) then
             if current_scanner=tscannerfile(scanner) then
-              current_scanner:=nil;
-            tscannerfile(scanner).free;
+              set_current_scanner(nil);
+            FreeAndNil(scanner);
             scanner:=nil;
             scanner:=nil;
           end;
           end;
 
 
@@ -1210,8 +1279,8 @@ implementation
       end;
       end;
 
 
 
 
-    procedure TModule.AddExternalImport(const libname,symname,symmangledname:string;
-              OrdNr: longint;isvar:boolean;ImportByOrdinalOnly:boolean);
+    procedure tmodule.AddExternalImport(const libname, symname, symmangledname: string; OrdNr: longint; isvar: boolean;
+      ImportByOrdinalOnly: boolean);
       var
       var
         ImportLibrary,OtherIL : TImportLibrary;
         ImportLibrary,OtherIL : TImportLibrary;
         ImportSymbol  : TImportSymbol;
         ImportSymbol  : TImportSymbol;
@@ -1291,6 +1360,23 @@ implementation
         tasmsymbol.create(externasmsyms,name,bind,typ);
         tasmsymbol.create(externasmsyms,name,bind,typ);
       end;
       end;
 
 
+    procedure tmodule.remove_from_waitingforunits(amodule: tmodule);
+    begin
+      // It can be nil after when this is called after end_of_parsing was called.
+      if assigned(waitingforunit) then
+        waitingforunit.remove(amodule);
+    end;
+
+    function tmodule.ToString: RTLString;
+      begin
+        // Assigned self so we can detect nil.
+        if assigned(modulename) then
+          Result:='('+ModuleName^+')'
+        else
+         Result:='(<'+inttostr(ptrint(self))+'>)';
+        // Possibly add some state ?
+      end;
+
 
 
 initialization
 initialization
 {$ifdef MEMDEBUG}
 {$ifdef MEMDEBUG}

+ 353 - 242
compiler/fppu.pas

@@ -64,11 +64,14 @@ interface
           constructor create(LoadedFrom:TModule;const amodulename: string; const afilename:TPathStr;_is_unit:boolean);
           constructor create(LoadedFrom:TModule;const amodulename: string; const afilename:TPathStr;_is_unit:boolean);
           destructor destroy;override;
           destructor destroy;override;
           procedure reset;override;
           procedure reset;override;
+          procedure re_resolve(loadfrom: tmodule);
           function  openppufile:boolean;
           function  openppufile:boolean;
           function  openppustream(strm:TCStream):boolean;
           function  openppustream(strm:TCStream):boolean;
           procedure getppucrc;
           procedure getppucrc;
           procedure writeppu;
           procedure writeppu;
-          procedure loadppu;
+          function loadppu(from_module : tmodule) : boolean;
+          procedure post_load_or_compile(from_module : tmodule; second_time: boolean);
+          procedure discardppu;
           function  needrecompile:boolean;
           function  needrecompile:boolean;
           procedure setdefgeneration;
           procedure setdefgeneration;
           procedure reload_flagged_units;
           procedure reload_flagged_units;
@@ -82,9 +85,13 @@ interface
            avoid endless resolving loops in case of cyclic dependencies. }
            avoid endless resolving loops in case of cyclic dependencies. }
           defsgeneration : longint;
           defsgeneration : longint;
 
 
+          function check_loadfrompackage: boolean;
+          procedure check_reload(from_module: tmodule; var do_load: boolean);
           function  openppu(ppufiletime:longint):boolean;
           function  openppu(ppufiletime:longint):boolean;
-          function  search_unit_files(onlysource:boolean):boolean;
-          function  search_unit(onlysource,shortname:boolean):boolean;
+          procedure prepare_second_load(from_module: tmodule);
+          procedure recompile_from_sources(from_module: tmodule);
+          function  search_unit_files(loaded_from : tmodule; onlysource:boolean):boolean;
+          function  search_unit(loaded_from : tmodule; onlysource,shortname:boolean):boolean;
           function  loadfrompackage:boolean;
           function  loadfrompackage:boolean;
           procedure load_interface;
           procedure load_interface;
           procedure load_implementation;
           procedure load_implementation;
@@ -94,6 +101,7 @@ interface
           procedure buildderefunitimportsyms;
           procedure buildderefunitimportsyms;
           procedure derefunitimportsyms;
           procedure derefunitimportsyms;
           procedure freederefunitimportsyms;
           procedure freederefunitimportsyms;
+          procedure try_load_ppufile(from_module: tmodule);
           procedure writesourcefiles;
           procedure writesourcefiles;
           procedure writeusedunit(intf:boolean);
           procedure writeusedunit(intf:boolean);
           procedure writelinkcontainer(var p:tlinkcontainer;id:byte;strippath:boolean);
           procedure writelinkcontainer(var p:tlinkcontainer;id:byte;strippath:boolean);
@@ -124,7 +132,7 @@ interface
 {$ENDIF}
 {$ENDIF}
        end;
        end;
 
 
-    function registerunit(callermodule:tmodule;const s : TIDString;const fn:string) : tppumodule;
+    function registerunit(callermodule:tmodule;const s : TIDString;const fn:string; out is_new:boolean) : tppumodule;
 
 
 
 
 implementation
 implementation
@@ -158,11 +166,9 @@ var
       end;
       end;
 
 
 
 
-    destructor tppumodule.Destroy;
+    destructor tppumodule.destroy;
       begin
       begin
-        if assigned(ppufile) then
-         ppufile.free;
-        ppufile:=nil;
+        discardppu;
         comments.free;
         comments.free;
         comments:=nil;
         comments:=nil;
         { all derefs allocated with new
         { all derefs allocated with new
@@ -177,17 +183,50 @@ var
     procedure tppumodule.reset;
     procedure tppumodule.reset;
       begin
       begin
         inc(currentdefgeneration);
         inc(currentdefgeneration);
-        if assigned(ppufile) then
-         begin
-           ppufile.free;
-           ppufile:=nil;
-         end;
+        discardppu;
         freederefunitimportsyms;
         freederefunitimportsyms;
         unitimportsymsderefs.free;
         unitimportsymsderefs.free;
         unitimportsymsderefs:=tfplist.create;
         unitimportsymsderefs:=tfplist.create;
         inherited reset;
         inherited reset;
       end;
       end;
 
 
+    procedure tppumodule.re_resolve(loadfrom: tmodule);
+
+      begin
+        Message1(unit_u_reresolving_unit,modulename^);
+        if tstoredsymtable(globalsymtable).is_deref_built then
+          tstoredsymtable(globalsymtable).deref(false);
+        if tstoredsymtable(globalsymtable).is_derefimpl_built then
+          tstoredsymtable(globalsymtable).derefimpl(false);
+        if assigned(localsymtable) then
+          begin
+            { we have only builderef(impl)'d the registered symbols of
+              the localsymtable -> also only deref those again }
+            if tstoredsymtable(localsymtable).is_deref_built then
+              tstoredsymtable(localsymtable).deref(true);
+            if tstoredsymtable(localsymtable).is_derefimpl_built then
+              tstoredsymtable(localsymtable).derefimpl(true);
+          end;
+        if assigned(wpoinfo) then
+          begin
+            tunitwpoinfo(wpoinfo).deref;
+            tunitwpoinfo(wpoinfo).derefimpl;
+          end;
+
+        { We have to flag the units that depend on this unit even
+          though it didn't change, because they might also
+          indirectly depend on the unit that did change (e.g.,
+          in case rgobj, rgx86 and rgcpu have been compiled
+          already, and then rgobj is recompiled for some reason
+          -> rgx86 is re-reresolved, but the vmtentries of trgcpu
+          must also be re-resolved, because they will also contain
+          pointers to procdefs in the old trgobj (in case of a
+          recompile, all old defs are freed) }
+        flagdependent(loadfrom);
+        reload_flagged_units;
+      end;
+
+
     procedure tppumodule.queuecomment(const s:TMsgStr;v,w:longint);
     procedure tppumodule.queuecomment(const s:TMsgStr;v,w:longint);
     begin
     begin
       if comments = nil then
       if comments = nil then
@@ -225,8 +264,7 @@ var
         ppufile:=tcompilerppufile.create(ppufilename);
         ppufile:=tcompilerppufile.create(ppufilename);
         if not ppufile.openfile then
         if not ppufile.openfile then
          begin
          begin
-           ppufile.free;
-           ppufile:=nil;
+           discardppu;
            Message(unit_u_ppu_file_too_short);
            Message(unit_u_ppu_file_too_short);
            exit;
            exit;
          end;
          end;
@@ -242,8 +280,7 @@ var
         ppufile:=tcompilerppufile.create(ppufilename);
         ppufile:=tcompilerppufile.create(ppufilename);
         if not ppufile.openstream(strm) then
         if not ppufile.openstream(strm) then
          begin
          begin
-           ppufile.free;
-           ppufile:=nil;
+           discardppu;
            Message(unit_u_ppu_file_too_short);
            Message(unit_u_ppu_file_too_short);
            exit;
            exit;
          end;
          end;
@@ -380,8 +417,7 @@ var
         if not checkheader or
         if not checkheader or
            not checkextraheader then
            not checkextraheader then
           begin
           begin
-            ppufile.free;
-            ppufile:=nil;
+            discardppu;
             exit;
             exit;
           end;
           end;
 
 
@@ -407,23 +443,23 @@ var
       end;
       end;
 
 
 
 
-    function tppumodule.search_unit_files(onlysource:boolean):boolean;
+    function tppumodule.search_unit_files(loaded_from : tmodule; onlysource:boolean):boolean;
       var
       var
         found : boolean;
         found : boolean;
       begin
       begin
         found:=false;
         found:=false;
-        if search_unit(onlysource,false) then
+        if search_unit(loaded_from,onlysource,false) then
           found:=true;
           found:=true;
         if (not found) and
         if (not found) and
            (ft83 in AllowedFilenameTransFormations) and
            (ft83 in AllowedFilenameTransFormations) and
            (length(modulename^)>8) and
            (length(modulename^)>8) and
-           search_unit(onlysource,true) then
+           search_unit(loaded_from,onlysource,true) then
           found:=true;
           found:=true;
         search_unit_files:=found;
         search_unit_files:=found;
       end;
       end;
 
 
 
 
-    function tppumodule.search_unit(onlysource,shortname:boolean):boolean;
+    function tppumodule.search_unit(loaded_from : tmodule; onlysource,shortname:boolean):boolean;
       var
       var
          singlepathstring,
          singlepathstring,
          filename : TCmdStr;
          filename : TCmdStr;
@@ -1270,6 +1306,8 @@ var
         indchecksum,
         indchecksum,
         intfchecksum,
         intfchecksum,
         checksum : cardinal;
         checksum : cardinal;
+        isnew : boolean;
+
       begin
       begin
         while not ppufile.endofentry do
         while not ppufile.endofentry do
          begin
          begin
@@ -1279,7 +1317,10 @@ var
            indchecksum:=cardinal(ppufile.getlongint);
            indchecksum:=cardinal(ppufile.getlongint);
            { set the state of this unit before registering, this is
            { set the state of this unit before registering, this is
              needed for a correct circular dependency check }
              needed for a correct circular dependency check }
-           hp:=registerunit(self,hs,'');
+           hp:=registerunit(self,hs,'',isnew);
+           if isnew then
+             usedunits.Concat(tused_unit.create(hp,in_interface,true,nil));
+
            pu:=addusedunit(hp,false,nil);
            pu:=addusedunit(hp,false,nil);
            pu.checksum:=checksum;
            pu.checksum:=checksum;
            pu.interface_checksum:=intfchecksum;
            pu.interface_checksum:=intfchecksum;
@@ -1775,9 +1816,7 @@ var
          close(ppufile.CRCFile);
          close(ppufile.CRCFile);
 {$endif Test_Double_checksum_write}
 {$endif Test_Double_checksum_write}
 
 
-         ppufile.closefile;
-         ppufile.free;
-         ppufile:=nil;
+         discardppu;
       end;
       end;
 
 
 
 
@@ -1886,9 +1925,7 @@ var
          ppufile.header.common.flags:=headerflags;
          ppufile.header.common.flags:=headerflags;
          ppufile.writeheader;
          ppufile.writeheader;
 
 
-         ppufile.closefile;
-         ppufile.free;
-         ppufile:=nil;
+         discardppu;
       end;
       end;
 
 
 
 
@@ -1906,12 +1943,12 @@ var
          begin
          begin
            if pu.in_interface then
            if pu.in_interface then
             begin
             begin
-              tppumodule(pu.u).loadppu;
+              tppumodule(pu.u).loadppu(self);
               { if this unit is compiled we can stop }
               { if this unit is compiled we can stop }
-              if state=ms_compiled then
+              if state in [ms_compiled,ms_processed] then
                exit;
                exit;
               { add this unit to the dependencies }
               { add this unit to the dependencies }
-              pu.u.adddependency(self);
+              pu.u.adddependency(self,true);
               { need to recompile the current unit, check the interface
               { need to recompile the current unit, check the interface
                 crc. And when not compiled with -Ur then check the complete
                 crc. And when not compiled with -Ur then check the complete
                 crc }
                 crc }
@@ -1938,7 +1975,6 @@ var
             end;
             end;
            pu:=tused_unit(pu.next);
            pu:=tused_unit(pu.next);
          end;
          end;
-
         { ok, now load the interface of this unit }
         { ok, now load the interface of this unit }
         if current_module<>self then
         if current_module<>self then
          internalerror(200208187);
          internalerror(200208187);
@@ -1968,12 +2004,12 @@ var
          begin
          begin
            if (not pu.in_interface) then
            if (not pu.in_interface) then
             begin
             begin
-              tppumodule(pu.u).loadppu;
+              tppumodule(pu.u).loadppu(self);
               { if this unit is compiled we can stop }
               { if this unit is compiled we can stop }
               if state=ms_compiled then
               if state=ms_compiled then
                exit;
                exit;
               { add this unit to the dependencies }
               { add this unit to the dependencies }
-              pu.u.adddependency(self);
+              pu.u.adddependency(self,false);
               { need to recompile the current unit ? }
               { need to recompile the current unit ? }
               if (pu.u.interface_crc<>pu.interface_checksum) or
               if (pu.u.interface_crc<>pu.interface_checksum) or
                  (pu.u.indirect_crc<>pu.indirect_checksum) then
                  (pu.u.indirect_crc<>pu.indirect_checksum) then
@@ -2070,7 +2106,7 @@ var
               (hp.defsgeneration<defsgeneration) then
               (hp.defsgeneration<defsgeneration) then
              begin
              begin
                hp.defsgeneration:=defsgeneration;
                hp.defsgeneration:=defsgeneration;
-               hp.loadppu
+               hp.loadppu(self)
              end
              end
            else
            else
              hp.do_reload:=false;
              hp.do_reload:=false;
@@ -2084,258 +2120,322 @@ var
         state:=ms_compiled;
         state:=ms_compiled;
 
 
         { free ppu }
         { free ppu }
-        if assigned(ppufile) then
-          begin
-            ppufile.free;
-            ppufile:=nil;
-          end;
+        discardppu;
 
 
         inherited end_of_parsing;
         inherited end_of_parsing;
       end;
       end;
 
 
+    procedure tppumodule.check_reload(from_module : tmodule; var do_load : boolean);
 
 
-    procedure tppumodule.loadppu;
-      const
-        ImplIntf : array[boolean] of string[15]=('implementation','interface');
-      var
-        do_load,
-        second_time        : boolean;
-        old_current_module : tmodule;
-        pu : tused_unit;
       begin
       begin
-        old_current_module:=current_module;
-        Message3(unit_u_load_unit,old_current_module.modulename^,
-                 ImplIntf[old_current_module.in_interface],
-                 modulename^);
-
-        { Update loaded_from to detect cycles }
-        loaded_from:=old_current_module;
-
-        { check if the globalsymtable is already available, but
-          we must reload when the do_reload flag is set }
-        if (not do_reload) and
-           assigned(globalsymtable) then
-           exit;
+        { A force reload }
+        if not do_reload then
+          exit;
+        Message(unit_u_forced_reload);
+        do_reload:=false;
+        { When the unit is already loaded or being loaded
+         we can maybe skip a complete reload/recompile }
+        if assigned(globalsymtable) and
+          (not needrecompile) then
+         begin
+           { When we don't have any data stored yet there
+             is nothing to resolve }
+           if interface_compiled and
+             { it makes no sense to re-resolve the unit if it is already finally compiled }
+             not(state=ms_compiled) then
+             begin
+               re_resolve(from_module);
+             end
+           else
+             Message1(unit_u_skipping_reresolving_unit,modulename^);
+           do_load:=false;
+         end;
+      end;
 
 
-        { reset }
-        do_load:=true;
-        second_time:=false;
-        set_current_module(self);
+    { Returns true if the module was loaded from package }
+    function tppumodule.check_loadfrompackage : boolean;
 
 
+      begin
         { try to load it as a package unit first }
         { try to load it as a package unit first }
-        if (packagelist.count>0) and loadfrompackage then
+        Result:=(packagelist.count>0) and loadfrompackage;
+        if Result then
           begin
           begin
-            do_load:=false;
             do_reload:=false;
             do_reload:=false;
             state:=ms_compiled;
             state:=ms_compiled;
             { PPU is not needed anymore }
             { PPU is not needed anymore }
             if assigned(ppufile) then
             if assigned(ppufile) then
              begin
              begin
-                ppufile.closefile;
-                ppufile.free;
-                ppufile:=nil;
+               discardppu;
              end;
              end;
             { add the unit to the used units list of the program }
             { add the unit to the used units list of the program }
             usedunits.concat(tused_unit.create(self,true,false,nil));
             usedunits.concat(tused_unit.create(self,true,false,nil));
           end;
           end;
+      end;
 
 
-        { A force reload }
-        if do_reload then
+      procedure tppumodule.prepare_second_load(from_module: tmodule);
+
+      const
+         CompileStates  = [ms_compile, ms_compiling_waitintf, ms_compiling_waitimpl,
+                           ms_compiling_waitfinish, ms_compiling_wait, ms_compiled,
+                           ms_processed];
+
+
+        begin
+          { try to load the unit a second time first }
+          Message1(unit_u_second_load_unit,modulename^);
+          Message2(unit_u_previous_state,modulename^,ModuleStateStr[state]);
+          { Flag modules to reload }
+          flagdependent(from_module);
+          { Reset the module }
+          reset;
+          if state in CompileStates then
+            begin
+              Message1(unit_u_second_compile_unit,modulename^);
+              state:=ms_compile;
+              do_compile:=true;
+            end
+          else
+            state:=ms_load;
+        end;
+
+    procedure tppumodule.try_load_ppufile(from_module : tmodule);
+
+      begin
+        Message1(unit_u_loading_unit,modulename^);
+        search_unit_files(from_module,false);
+        if not do_compile then
          begin
          begin
-           Message(unit_u_forced_reload);
-           do_reload:=false;
-           { When the unit is already loaded or being loaded
-             we can maybe skip a complete reload/recompile }
-           if assigned(globalsymtable) and
-              (not needrecompile) then
-             begin
-               { When we don't have any data stored yet there
-                 is nothing to resolve }
-               if interface_compiled and
-                 { it makes no sense to re-resolve the unit if it is already finally compiled }
-                 not(state=ms_compiled) then
-                 begin
-                   Message1(unit_u_reresolving_unit,modulename^);
-                   tstoredsymtable(globalsymtable).deref(false);
-                   tstoredsymtable(globalsymtable).derefimpl(false);
-                   if assigned(localsymtable) then
-                    begin
-                      { we have only builderef(impl)'d the registered symbols of
-                        the localsymtable -> also only deref those again }
-                      tstoredsymtable(localsymtable).deref(true);
-                      tstoredsymtable(localsymtable).derefimpl(true);
-                    end;
-                   if assigned(wpoinfo) then
-                     begin
-                       tunitwpoinfo(wpoinfo).deref;
-                       tunitwpoinfo(wpoinfo).derefimpl;
-                     end;
-
-                   { We have to flag the units that depend on this unit even
-                     though it didn't change, because they might also
-                     indirectly depend on the unit that did change (e.g.,
-                     in case rgobj, rgx86 and rgcpu have been compiled
-                     already, and then rgobj is recompiled for some reason
-                     -> rgx86 is re-reresolved, but the vmtentries of trgcpu
-                     must also be re-resolved, because they will also contain
-                     pointers to procdefs in the old trgobj (in case of a
-                     recompile, all old defs are freed) }
-                   flagdependent(old_current_module);
-                   reload_flagged_units;
-                 end
-               else
-                 Message1(unit_u_skipping_reresolving_unit,modulename^);
-               do_load:=false;
-             end;
+           load_interface;
+           setdefgeneration;
+           if not do_compile then
+            begin
+              load_usedunits;
+              if not do_compile then
+                Message1(unit_u_finished_loading_unit,modulename^);
+            end;
          end;
          end;
+        { PPU is not needed anymore }
+        if assigned(ppufile) then
+            discardppu;
+      end;
+
+    procedure tppumodule.recompile_from_sources(from_module : tmodule);
 
 
-        if do_load then
+      var
+        pu : tused_unit;
+      begin
+        { recompile the unit or give a fatal error if sources not available }
+        if not(sources_avail) then
          begin
          begin
-           { loading the unit for a second time? }
-           if state=ms_registered then
-            state:=ms_load
-           else
+           search_unit_files(from_module,true);
+           if not(sources_avail) then
             begin
             begin
-              { try to load the unit a second time first }
-              Message1(unit_u_second_load_unit,modulename^);
-              Message2(unit_u_previous_state,modulename^,ModuleStateStr[state]);
-              { Flag modules to reload }
-              flagdependent(old_current_module);
-              { Reset the module }
-              reset;
-              if state in [ms_compile,ms_second_compile] then
+              printcomments;
+              if recompile_reason=rr_noppu then
                 begin
                 begin
-                  Message1(unit_u_second_compile_unit,modulename^);
-                  state:=ms_second_compile;
-                  do_compile:=true;
+                  pu:=tused_unit(from_module.used_units.first);
+                  while assigned(pu) do
+                    begin
+                      if pu.u=self then
+                        break;
+                      pu:=tused_unit(pu.next);
+                    end;
+                  if assigned(pu) and assigned(pu.unitsym) then
+                    MessagePos2(pu.unitsym.fileinfo,unit_f_cant_find_ppu,realmodulename^,from_module.realmodulename^)
+                  else
+                    Message2(unit_f_cant_find_ppu,realmodulename^,from_module.realmodulename^);
                 end
                 end
               else
               else
-                state:=ms_second_load;
-              second_time:=true;
+                Message1(unit_f_cant_compile_unit,realmodulename^);
             end;
             end;
+         end;
+        { we found the sources, we do not need the verbose messages anymore }
+        if comments <> nil then
+        begin
+          comments.free;
+          comments:=nil;
+        end;
+        { Flag modules to reload }
+        flagdependent(from_module);
+        { Reset the module }
+        reset;
+        { mark this module for recompilation }
+        if not (state in [ms_compile]) then
+          state:=ms_compile;
+        setdefgeneration;
+      end;
+
+    procedure tppumodule.post_load_or_compile(from_module : tmodule; second_time : boolean);
+
+    begin
+      if current_module<>self then
+        internalerror(200212282);
 
 
-           { close old_current_ppu on system that are
-             short on file handles like DOS PM }
+      if in_interface then
+        internalerror(200212283);
+
+      { for a second_time recompile reload all dependent units,
+        for a first time compile register the unit _once_ }
+      if second_time then
+        reload_flagged_units;
+
+      { reopen the old module }
 {$ifdef SHORT_ON_FILE_HANDLES}
 {$ifdef SHORT_ON_FILE_HANDLES}
-           if old_current_module.is_unit and
-              assigned(tppumodule(old_current_module).ppufile) then
-             tppumodule(old_current_module).ppufile.tempclose;
+      if from_module.is_unit and
+          assigned(tppumodule(from_module).ppufile) then
+         tppumodule(from_module).ppufile.tempopen;
 {$endif SHORT_ON_FILE_HANDLES}
 {$endif SHORT_ON_FILE_HANDLES}
+      state:=ms_processed;
+    end;
 
 
-           { try to opening ppu, skip this when we already
-             know that we need to compile the unit }
-           if not do_compile then
-            begin
-              Message1(unit_u_loading_unit,modulename^);
-              search_unit_files(false);
-              if not do_compile then
-               begin
-                 load_interface;
-                 setdefgeneration;
-                 if not do_compile then
-                  begin
-                    load_usedunits;
-                    if not do_compile then
-                      Message1(unit_u_finished_loading_unit,modulename^);
-                  end;
-               end;
-              { PPU is not needed anymore }
-              if assigned(ppufile) then
-               begin
-                  ppufile.closefile;
-                  ppufile.free;
-                  ppufile:=nil;
-               end;
-            end;
+    function tppumodule.loadppu(from_module : tmodule) : boolean;
+      const
+        ImplIntf : array[boolean] of string[15]=('implementation','interface');
+      var
+        do_load,
+        second_time        : boolean;
 
 
-           { Do we need to recompile the unit }
-           if do_compile then
-            begin
-              { recompile the unit or give a fatal error if sources not available }
-              if not(sources_avail) then
-               begin
-                 search_unit_files(true);
-                 if not(sources_avail) then
-                  begin
-                    printcomments;
-                    if recompile_reason=rr_noppu then
-                      begin
-                        pu:=tused_unit(loaded_from.used_units.first);
-                        while assigned(pu) do
-                          begin
-                            if pu.u=self then
-                              break;
-                            pu:=tused_unit(pu.next);
-                          end;
-                        if assigned(pu) and assigned(pu.unitsym) then
-                          MessagePos2(pu.unitsym.fileinfo,unit_f_cant_find_ppu,realmodulename^,loaded_from.realmodulename^)
-                        else
-                          Message2(unit_f_cant_find_ppu,realmodulename^,loaded_from.realmodulename^);
-                      end
-                    else
-                      Message1(unit_f_cant_compile_unit,realmodulename^);
-                  end;
-               end;
-              { we found the sources, we do not need the verbose messages anymore }
-              if comments <> nil then
-              begin
-                comments.free;
-                comments:=nil;
-              end;
-              { Flag modules to reload }
-              flagdependent(old_current_module);
-              { Reset the module }
-              reset;
-              { compile this module }
-              if not(state in [ms_compile,ms_second_compile]) then
-                state:=ms_compile;
-              compile(mainsource);
-              setdefgeneration;
-            end
-           else
-            state:=ms_compiled;
+      begin
+        Result:=false;
+        Message3(unit_u_load_unit,from_module.modulename^,
+                 ImplIntf[from_module.in_interface],
+                 modulename^);
 
 
-           if current_module<>self then
-             internalerror(200212282);
+        { check if the globalsymtable is already available, but
+          we must reload when the do_reload flag is set }
+        if (not do_reload) and
+           assigned(globalsymtable) then
+           exit(True);
 
 
-           if in_interface then
-             internalerror(200212283);
+        { reset }
+        do_load:=true;
+        second_time:=false;
+        set_current_module(self);
 
 
-           { for a second_time recompile reload all dependent units,
-             for a first time compile register the unit _once_ }
-           if second_time then
-            reload_flagged_units
-           else
-            usedunits.concat(tused_unit.create(self,true,false,nil));
+        do_load:=not check_loadfrompackage;
+
+        { A force reload }
+        check_reload(from_module, do_load);
+
+        if not do_load then
+          begin
+            // No need to do anything, restore situation and exit.
+            set_current_module(from_module);
+            exit(state=ms_compiled);
+          end;
+
+        { loading the unit for a second time? }
+        if state=ms_registered then
+          state:=ms_load
+        else
+          begin
+            second_time:=true;
+            prepare_second_load(from_module);
+          end;
 
 
-           { reopen the old module }
+        { close old_current_ppu on system that are
+          short on file handles like DOS PM }
 {$ifdef SHORT_ON_FILE_HANDLES}
 {$ifdef SHORT_ON_FILE_HANDLES}
-           if old_current_module.is_unit and
-              assigned(tppumodule(old_current_module).ppufile) then
-             tppumodule(old_current_module).ppufile.tempopen;
+        if from_module.is_unit and
+           assigned(tppumodule(from_module).ppufile) then
+          tppumodule(from_module).ppufile.tempclose;
 {$endif SHORT_ON_FILE_HANDLES}
 {$endif SHORT_ON_FILE_HANDLES}
-         end;
+
+        { try to opening ppu, skip this when we already
+          know that we need to compile the unit }
+        if not do_compile then
+          try_load_ppufile(from_module);
+
+        { Do we need to recompile the unit }
+        if do_compile then
+          recompile_from_sources(from_module)
+        else
+          state:=ms_compiled;
+
+        Result:=(state=ms_compiled);
+
+        // We cannot do this here, the order is all messed up...
+        // if not second_time then
+        //   usedunits.concat(tused_unit.create(self,true,false,nil));
+
+        if result then
+          post_load_or_compile(from_module,second_time);
 
 
         { we are back, restore current_module }
         { we are back, restore current_module }
-        set_current_module(old_current_module);
+        set_current_module(from_module);
       end;
       end;
 
 
+    procedure tppumodule.discardppu;
+      begin
+        { PPU is not needed anymore }
+        if not assigned(ppufile) then
+          exit;
+        ppufile.closefile;
+        ppufile.free;
+        ppufile:=nil;
+      end;
 
 
 {*****************************************************************************
 {*****************************************************************************
                                RegisterUnit
                                RegisterUnit
 *****************************************************************************}
 *****************************************************************************}
 
 
 
 
-    function registerunit(callermodule:tmodule;const s : TIDString;const fn:string) : tppumodule;
+    function registerunit(callermodule:tmodule;const s : TIDString;const fn:string; out is_new:boolean) : tppumodule;
+
+
+          function FindCycle(aFile, SearchFor: TModule; var Cycle: TFPList): boolean;
+          // Note: when traversing, add every search file to Cycle, to avoid running in circles.
+          // When a cycle is detected, clear the Cycle list and build the cycle path
+          var
+
+            aParent: tdependent_unit;
+          begin
+            Cycle.Add(aFile);
+            aParent:=tdependent_unit(afile.dependent_units.First);
+            While Assigned(aParent) do
+              begin
+              if aParent.in_interface then
+                begin
+                // writeln('Registering ',Callermodule.get_modulename,': checking cyclic dependency of ',aFile.get_modulename, ' on ',aparent.u.get_modulename);
+                if aParent.u=SearchFor then
+                begin
+                  // unit cycle found
+                  Cycle.Clear;
+                  Cycle.Add(aParent.u);
+                  Cycle.Add(aFile);
+                  // Writeln('exit at ',aParent.u.get_modulename);
+                  exit(true);
+                end;
+                if Cycle.IndexOf(aParent.u)<0 then
+                  if FindCycle(aParent.u,SearchFor,Cycle) then
+                    begin
+                    // Writeln('Cycle found, exit at ',aParent.u.get_modulename);
+                    Cycle.Add(aFile);
+                    exit(true);
+                    end;
+                end;
+              aParent:=tdependent_unit(aParent.Next);
+              end;
+           Result:=false;
+          end;
+
+
       var
       var
         ups   : TIDString;
         ups   : TIDString;
         hp    : tppumodule;
         hp    : tppumodule;
         hp2   : tmodule;
         hp2   : tmodule;
+        cycle : TFPList;
+        havecycle: boolean;
+{$IFDEF DEBUGCYCLE}
+        cyclepath : ansistring
+{$ENDIF}
+
       begin
       begin
         { Info }
         { Info }
         ups:=upper(s);
         ups:=upper(s);
         { search all loaded units }
         { search all loaded units }
         hp:=tppumodule(loaded_units.first);
         hp:=tppumodule(loaded_units.first);
+        hp2:=nil;
         while assigned(hp) do
         while assigned(hp) do
          begin
          begin
            if hp.modulename^=ups then
            if hp.modulename^=ups then
@@ -2346,18 +2446,29 @@ var
               if hp.is_unit then
               if hp.is_unit then
                begin
                begin
                  { both units in interface ? }
                  { both units in interface ? }
-                 if callermodule.in_interface and
-                    hp.in_interface then
+                 if hp.in_interface and callermodule.in_interface then
                   begin
                   begin
                     { check for a cycle }
                     { check for a cycle }
-                    hp2:=callermodule.loaded_from;
-                    while assigned(hp2) and (hp2<>hp) do
-                     begin
-                       if hp2.in_interface then
-                         hp2:=hp2.loaded_from
-                       else
-                         hp2:=nil;
-                     end;
+                    Cycle:=TFPList.Create;
+                    try
+                      HaveCycle:=FindCycle(CallerModule,hp,Cycle);
+                      if HaveCycle then
+                      begin
+                      {$IFDEF DEBUGCYCLE}
+                         Writeln('Done cycle check');
+                        CyclePath:='';
+                        hp2:=TModule(Cycle[Cycle.Count-1]);
+                        for i:=0 to Cycle.Count-1 do begin
+                          if i>0 then CyclePath:=CyclePath+',';
+                          CyclePath:=CyclePath+TModule(Cycle[i]).realmodulename^;
+                        end;
+                        Writeln('Unit cycle detected: ',CyclePath);
+                        {$ENDIF}
+                        Message2(unit_f_circular_unit_reference,callermodule.realmodulename^,hp.realmodulename^);
+                      end;
+                    finally
+                      Cycle.Free;
+                    end;
                     if assigned(hp2) then
                     if assigned(hp2) then
                       Message2(unit_f_circular_unit_reference,callermodule.realmodulename^,hp.realmodulename^);
                       Message2(unit_f_circular_unit_reference,callermodule.realmodulename^,hp.realmodulename^);
                   end;
                   end;
@@ -2369,11 +2480,11 @@ var
          end;
          end;
         { the unit is not in the loaded units,
         { the unit is not in the loaded units,
           we create an entry and register the unit }
           we create an entry and register the unit }
-        if not assigned(hp) then
+        is_new:=not assigned(hp);
+        if is_new then
          begin
          begin
            Message1(unit_u_registering_new_unit,ups);
            Message1(unit_u_registering_new_unit,ups);
            hp:=tppumodule.create(callermodule,s,fn,true);
            hp:=tppumodule.create(callermodule,s,fn,true);
-           hp.loaded_from:=callermodule;
            addloadedunit(hp);
            addloadedunit(hp);
          end;
          end;
         { return }
         { return }

+ 0 - 2
compiler/globals.pas

@@ -405,7 +405,6 @@ Const
 
 
        block_type : tblock_type;         { type of currently parsed block }
        block_type : tblock_type;         { type of currently parsed block }
 
 
-       compile_level : word;
        exceptblockcounter    : integer;  { each except block gets a unique number check gotos      }
        exceptblockcounter    : integer;  { each except block gets a unique number check gotos      }
        current_exceptblock        : integer;  { the exceptblock number of the current block (0 if none) }
        current_exceptblock        : integer;  { the exceptblock number of the current block (0 if none) }
        LinkLibraryAliases : TLinkStrMap;
        LinkLibraryAliases : TLinkStrMap;
@@ -1702,7 +1701,6 @@ implementation
         do_build:=false;
         do_build:=false;
         do_release:=false;
         do_release:=false;
         do_make:=true;
         do_make:=true;
-        compile_level:=0;
         codegenerror:=false;
         codegenerror:=false;
 
 
         { Output }
         { Output }

+ 173 - 74
compiler/globstat.pas

@@ -37,8 +37,8 @@ uses
 
 
 
 
 type
 type
-  pglobalstate=^tglobalstate;
-  tglobalstate=record
+
+  tglobalstate = class
   { scanner }
   { scanner }
     oldidtoken,
     oldidtoken,
     oldtoken       : ttoken;
     oldtoken       : ttoken;
@@ -67,95 +67,194 @@ type
     old_debuginfo : tdebuginfo;
     old_debuginfo : tdebuginfo;
     old_scanner : tscannerfile;
     old_scanner : tscannerfile;
     old_parser_file : string;
     old_parser_file : string;
+    constructor create(savefull : boolean);
+    destructor destroy; override;
+    procedure clearscanner;
+    class procedure remove_scanner_from_states(scanner : tscannerfile); static;
+    procedure save(full : boolean);
+    procedure restore(full : boolean);
   end;
   end;
 
 
-procedure save_global_state(out state:tglobalstate;full:boolean);
-procedure restore_global_state(const state:tglobalstate;full:boolean);
+procedure save_global_state(state:tglobalstate;full:boolean);
+procedure restore_global_state(state:tglobalstate;full:boolean);
 
 
 implementation
 implementation
 
 
 uses
 uses
-  pbase,comphook;
+  switches, verbose, pbase,comphook;
+
+var
+  states : array of tglobalstate;
+  statecount : integer = 0;
+
+
+
+  class procedure tglobalstate.remove_scanner_from_states(scanner : tscannerfile);
+
+  var
+    i : integer;
+
+  begin
+    for I:=0 to statecount-1 do
+      if (states[i].old_scanner=scanner) then
+        states[i].clearscanner;
+  end;
+
+  procedure addstate(astate : tglobalstate);
+
+  var
+    l : integer;
+
+  begin
+    l:=length(states);
+    if l=statecount then
+      setlength(states,l+10);
+    states[statecount]:=astate;
+    inc(statecount);
+  end;
+
+  procedure removestate(astate : tglobalstate);
+
+  var
+    l : integer;
 
 
-  procedure save_global_state(out state:tglobalstate;full:boolean);
+  begin
+    l:=statecount-1;
+    While (l>=0) and (states[l]<>astate) do
+      dec(l);
+    if l<0 then
+      exit;
+    if l<>statecount-1 then
+      states[l]:=states[statecount-1];
+    states[statecount-1]:=Nil;
+    Dec(Statecount);
+  end;
+
+  procedure save_global_state(state:tglobalstate;full:boolean);
     begin
     begin
-      with state do
+      state.save(full);
+    end;
+
+  procedure restore_global_state(state:tglobalstate;full:boolean);
+
+  begin
+    state.restore(full);
+  end;
+
+  procedure tglobalstate.save(full: boolean);
+
+    begin
+      old_current_module:=current_module;
+
+      { save symtable state }
+      oldsymtablestack:=symtablestack;
+      oldmacrosymtablestack:=macrosymtablestack;
+      oldcurrent_procinfo:=current_procinfo;
+
+      { save scanner state }
+      oldc:=c;
+      oldpattern:=pattern;
+      oldorgpattern:=orgpattern;
+      oldtoken:=token;
+      oldidtoken:=idtoken;
+      old_block_type:=block_type;
+      oldtokenpos:=current_tokenpos;
+      {
+        consuming the semicolon after a uses clause can add to the
+        pending state if the first directives change warning state.
+        So we must flush before context switch. See for example:
+        ppcgen/cgppc.pas
+        line 144 has a WARN 6018 OFF...
+      }
+      flushpendingswitchesstate;
+      old_switchesstatestack:=switchesstatestack;
+      old_switchesstatestackpos:=switchesstatestackpos;
+
+      { save cg }
+      oldparse_only:=parse_only;
+
+      { save akt... state }
+      { handle the postponed case first }
+      oldcurrent_filepos:=current_filepos;
+      old_settings:=current_settings;
+      old_verbosity:=status.verbosity;
+
+      if full then
         begin
         begin
-          old_current_module:=current_module;
-
-          { save symtable state }
-          oldsymtablestack:=symtablestack;
-          oldmacrosymtablestack:=macrosymtablestack;
-          oldcurrent_procinfo:=current_procinfo;
-
-          { save scanner state }
-          oldc:=c;
-          oldpattern:=pattern;
-          oldorgpattern:=orgpattern;
-          oldtoken:=token;
-          oldidtoken:=idtoken;
-          old_block_type:=block_type;
-          oldtokenpos:=current_tokenpos;
-          old_switchesstatestack:=switchesstatestack;
-          old_switchesstatestackpos:=switchesstatestackpos;
-
-          { save cg }
-          oldparse_only:=parse_only;
-
-          { save akt... state }
-          { handle the postponed case first }
-          //flushpendingswitchesstate;
-          oldcurrent_filepos:=current_filepos;
-          old_settings:=current_settings;
-          old_verbosity:=status.verbosity;
-
-          if full then
-            begin
-              old_asmdata:=current_asmdata;
-              old_debuginfo:=current_debuginfo;
-              old_parser_file:=parser_current_file;
-              old_scanner:=current_scanner;
-            end;
+          old_asmdata:=current_asmdata;
+          old_debuginfo:=current_debuginfo;
+          old_parser_file:=parser_current_file;
+          old_scanner:=current_scanner;
         end;
         end;
     end;
     end;
 
 
+  procedure tglobalstate.restore(full: boolean);
 
 
-  procedure restore_global_state(const state:tglobalstate;full:boolean);
     begin
     begin
-      with state do
+      { restore scanner }
+      c:=oldc;
+      pattern:=oldpattern;
+      orgpattern:=oldorgpattern;
+      token:=oldtoken;
+      idtoken:=oldidtoken;
+      current_tokenpos:=oldtokenpos;
+      block_type:=old_block_type;
+      switchesstatestack:=old_switchesstatestack;
+      switchesstatestackpos:=old_switchesstatestackpos;
+
+      { restore cg }
+      parse_only:=oldparse_only;
+
+      { restore symtable state }
+      symtablestack:=oldsymtablestack;
+      macrosymtablestack:=oldmacrosymtablestack;
+      current_procinfo:=oldcurrent_procinfo;
+      current_filepos:=oldcurrent_filepos;
+      current_settings:=old_settings;
+      status.verbosity:=old_verbosity;
+      { restore message settings which were recorded prior to unit switch }
+
+      RestoreLocalVerbosity(current_settings.pmessage);
+
+      if full then
         begin
         begin
-          { restore scanner }
-          c:=oldc;
-          pattern:=oldpattern;
-          orgpattern:=oldorgpattern;
-          token:=oldtoken;
-          idtoken:=oldidtoken;
-          current_tokenpos:=oldtokenpos;
-          block_type:=old_block_type;
-          switchesstatestack:=old_switchesstatestack;
-          switchesstatestackpos:=old_switchesstatestackpos;
-
-          { restore cg }
-          parse_only:=oldparse_only;
-
-          { restore symtable state }
-          symtablestack:=oldsymtablestack;
-          macrosymtablestack:=oldmacrosymtablestack;
-          current_procinfo:=oldcurrent_procinfo;
-          current_filepos:=oldcurrent_filepos;
-          current_settings:=old_settings;
-          status.verbosity:=old_verbosity;
-
-          if full then
-            begin
-              current_module:=old_current_module; {!}
-              current_asmdata:=old_asmdata;
-              current_debuginfo:=old_debuginfo;
-              current_scanner:=old_scanner;
-              parser_current_file:=old_parser_file;
-            end;
+          set_current_module(old_current_module);
+          // These can be different
+          current_asmdata:=old_asmdata;
+          current_debuginfo:=old_debuginfo;
         end;
         end;
     end;
     end;
 
 
+    constructor tglobalstate.create(savefull: boolean);
+
+    begin
+      addstate(self);
+      save(savefull);
+    end;
+
+  destructor tglobalstate.destroy;
+
+    begin
+      removestate(self);
+      inherited destroy;
+    end;
+
+  procedure tglobalstate.clearscanner;
+
+  begin
+    old_scanner:=nil;
+    oldidtoken:=NOTOKEN;
+    oldtoken:=NOTOKEN;
+    oldtokenpos:=Default(tfileposinfo);
+    oldc:=#0;
+    oldpattern:='';
+    oldorgpattern:='';
+    old_block_type:=bt_none;
+  end;
+
+initialization
+  onfreescanner:[email protected]_scanner_from_states;
+finalization
+  onfreescanner:=Nil;
 end.
 end.
 
 

+ 52 - 9
compiler/hlcgobj.pas

@@ -2257,19 +2257,32 @@ implementation
               { zero the bits we have to insert }
               { zero the bits we have to insert }
               if (slopt<>SL_SETMAX) then
               if (slopt<>SL_SETMAX) then
                 begin
                 begin
-                  maskreg:=getintregister(list,osuinttype);
-                  if (target_info.endian = endian_big) then
+                  if (slopt=SL_SETZERO) and (sref.bitlen=1) and (target_info.endian=endian_little) then
                     begin
                     begin
-                      a_load_const_reg(list,osuinttype,tcgint((aword(1) shl sref.bitlen)-1) shl (loadbitsize-sref.bitlen),maskreg);
-                      a_op_reg_reg(list,OP_SHR,osuinttype,sref.bitindexreg,maskreg);
+                      a_bit_set_reg_reg(list,false,osuinttype,osuinttype,sref.bitindexreg,valuereg);
+
+                      { store back to memory }
+                      tmpreg:=getintregister(list,loadsize);
+                      a_load_reg_reg(list,osuinttype,loadsize,valuereg,tmpreg);
+                      a_load_reg_ref(list,loadsize,loadsize,tmpreg,sref.ref);
+                      exit;
                     end
                     end
                   else
                   else
                     begin
                     begin
-                      a_load_const_reg(list,osuinttype,tcgint((aword(1) shl sref.bitlen)-1),maskreg);
-                      a_op_reg_reg(list,OP_SHL,osuinttype,sref.bitindexreg,maskreg);
+                      maskreg:=getintregister(list,osuinttype);
+                      if (target_info.endian = endian_big) then
+                        begin
+                          a_load_const_reg(list,osuinttype,tcgint((aword(1) shl sref.bitlen)-1) shl (loadbitsize-sref.bitlen),maskreg);
+                          a_op_reg_reg(list,OP_SHR,osuinttype,sref.bitindexreg,maskreg);
+                        end
+                      else
+                        begin
+                          a_load_const_reg(list,osuinttype,tcgint((aword(1) shl sref.bitlen)-1),maskreg);
+                          a_op_reg_reg(list,OP_SHL,osuinttype,sref.bitindexreg,maskreg);
+                        end;
+                      a_op_reg_reg(list,OP_NOT,osuinttype,maskreg,maskreg);
+                      a_op_reg_reg(list,OP_AND,osuinttype,maskreg,valuereg);
                     end;
                     end;
-                  a_op_reg_reg(list,OP_NOT,osuinttype,maskreg,maskreg);
-                  a_op_reg_reg(list,OP_AND,osuinttype,maskreg,valuereg);
                 end;
                 end;
 
 
               { insert the value }
               { insert the value }
@@ -2278,6 +2291,18 @@ implementation
                   tmpreg:=getintregister(list,osuinttype);
                   tmpreg:=getintregister(list,osuinttype);
                   if (slopt<>SL_SETMAX) then
                   if (slopt<>SL_SETMAX) then
                     a_load_reg_reg(list,fromsize,osuinttype,fromreg,tmpreg)
                     a_load_reg_reg(list,fromsize,osuinttype,fromreg,tmpreg)
+                  { setting of a single bit?
+                    then we might take advantage of the CPU's bit set instruction }
+                  else if (sref.bitlen=1) and (target_info.endian=endian_little) then
+                    begin
+                      a_bit_set_reg_reg(list,true,osuinttype,osuinttype,sref.bitindexreg,valuereg);
+
+                      { store back to memory }
+                      tmpreg:=getintregister(list,loadsize);
+                      a_load_reg_reg(list,osuinttype,loadsize,valuereg,tmpreg);
+                      a_load_reg_ref(list,loadsize,loadsize,tmpreg,sref.ref);
+                      exit;
+                    end
                   else if (sref.bitlen<>AIntBits) then
                   else if (sref.bitlen<>AIntBits) then
                     a_load_const_reg(list,osuinttype,tcgint((aword(1) shl sref.bitlen)-1), tmpreg)
                     a_load_const_reg(list,osuinttype,tcgint((aword(1) shl sref.bitlen)-1), tmpreg)
                   else
                   else
@@ -4298,6 +4323,7 @@ implementation
       r : treference;
       r : treference;
       forcesize: aint;
       forcesize: aint;
       hregister: TRegister;
       hregister: TRegister;
+      hl: TAsmLabel;
     begin
     begin
       case l.loc of
       case l.loc of
         LOC_FPUREGISTER,
         LOC_FPUREGISTER,
@@ -4331,6 +4357,23 @@ implementation
             l.reference:=r;
             l.reference:=r;
           end;
           end;
 {$endif cpuflags}
 {$endif cpuflags}
+        LOC_JUMP :
+          begin
+            a_label(list,l.truelabel);
+            tg.gethltemp(list,size,size.size,tt_normal,r);
+            if is_cbool(size) then
+              a_load_const_ref(list,size,-1,r)
+            else
+              a_load_const_ref(list,size,1,r);
+            current_asmdata.getjumplabel(hl);
+            a_jmp_always(list,hl);
+            a_label(list,l.falselabel);
+            a_load_const_ref(list,size,0,r);
+            a_label(list,hl);
+
+            location_reset_ref(l,LOC_REFERENCE,l.size,size.alignment,[]);
+            l.reference:=r;
+          end;
         LOC_CONSTANT,
         LOC_CONSTANT,
         LOC_REGISTER,
         LOC_REGISTER,
         LOC_CREGISTER,
         LOC_CREGISTER,
@@ -4460,7 +4503,7 @@ implementation
     var
     var
       storepos : tfileposinfo;
       storepos : tfileposinfo;
     begin
     begin
-       if nf_error in p.flags then
+       if tnf_error in p.transientflags then
          exit;
          exit;
        storepos:=current_filepos;
        storepos:=current_filepos;
        current_filepos:=p.fileinfo;
        current_filepos:=p.fileinfo;

+ 18 - 7
compiler/htypechk.pas

@@ -1403,7 +1403,7 @@ implementation
            case p.nodetype of
            case p.nodetype of
              vecn:
              vecn:
                begin
                begin
-                 include(p.flags,nf_callunique);
+                 include(tvecnode(p).vecnodeflags,vnf_callunique);
                  break;
                  break;
                end;
                end;
              typeconvn,
              typeconvn,
@@ -1939,7 +1939,7 @@ implementation
                      end;
                      end;
                    constsym:
                    constsym:
                      begin
                      begin
-                       if (tconstsym(tloadnode(hp).symtableentry).consttyp=constresourcestring) and
+                       if (tconstsym(tloadnode(hp).symtableentry).consttyp in [constresourcestring,constwresourcestring]) and
                          (valid_addr in opts) then
                          (valid_addr in opts) then
                          result:=true
                          result:=true
                        else
                        else
@@ -2913,7 +2913,7 @@ implementation
         convtype : tconverttype;
         convtype : tconverttype;
         pdtemp,
         pdtemp,
         pdoper   : tprocdef;
         pdoper   : tprocdef;
-        releasecurrpt : boolean;
+        releasecurrpt, check_valid_var : boolean;
         cdoptions : tcompare_defs_options;
         cdoptions : tcompare_defs_options;
         n : tnode;
         n : tnode;
 
 
@@ -2946,6 +2946,8 @@ implementation
                 is passed. This is to prevent that the change is permanent }
                 is passed. This is to prevent that the change is permanent }
               currpt:=pt;
               currpt:=pt;
               releasecurrpt:=false;
               releasecurrpt:=false;
+              { Should we check if the callparanode.left is valid for var }
+              check_valid_var:=true;
               { retrieve current parameter definitions to compares }
               { retrieve current parameter definitions to compares }
               eq:=te_incompatible;
               eq:=te_incompatible;
               def_from:=currpt.resultdef;
               def_from:=currpt.resultdef;
@@ -3101,6 +3103,7 @@ implementation
                   def_is_related(tobjectdef(def_from),tobjectdef(def_to)) then
                   def_is_related(tobjectdef(def_from),tobjectdef(def_to)) then
                  begin
                  begin
                    eq:=te_convert_l1;
                    eq:=te_convert_l1;
+                   check_valid_var:=false;
                    { resolve anonymous external class definitions }
                    { resolve anonymous external class definitions }
                    obj_from:=find_real_class_definition(tobjectdef(def_from),false);
                    obj_from:=find_real_class_definition(tobjectdef(def_from),false);
                    obj_to:=find_real_class_definition(tobjectdef(def_to),false);
                    obj_to:=find_real_class_definition(tobjectdef(def_to),false);
@@ -3121,6 +3124,7 @@ implementation
                    n:=currpt.left.getcopy;
                    n:=currpt.left.getcopy;
                    arrayconstructor_to_set(n);
                    arrayconstructor_to_set(n);
                    eq:=compare_defs_ext(n.resultdef,def_to,n.nodetype,convtype,pdoper,cdoptions);
                    eq:=compare_defs_ext(n.resultdef,def_to,n.nodetype,convtype,pdoper,cdoptions);
+                   check_valid_var:=false;
                    n.free;
                    n.free;
                  end
                  end
               else if is_open_array(def_to) and
               else if is_open_array(def_to) and
@@ -3146,6 +3150,7 @@ implementation
                     n:=tarrayconstructornode(n).right;
                     n:=tarrayconstructornode(n).right;
                   until not assigned(n);
                   until not assigned(n);
                   eq:=mineq;
                   eq:=mineq;
+                  check_valid_var:=false;
                 end
                 end
               else
               else
               { generic type comparision }
               { generic type comparision }
@@ -3155,7 +3160,10 @@ implementation
                     is_ansistring(def_to) and
                     is_ansistring(def_to) and
                     (tstringdef(def_from).encoding<>tstringdef(def_to).encoding) and
                     (tstringdef(def_from).encoding<>tstringdef(def_to).encoding) and
                     (currpara.varspez in [vs_var,vs_out]) then
                     (currpara.varspez in [vs_var,vs_out]) then
-                    eq:=te_convert_l1 // don't allow to pass different ansistring types to each-other
+                    begin
+                      eq:=te_convert_l1; // don't allow to pass different ansistring types to each-other
+                      check_valid_var:=false;
+                    end
                  else
                  else
                    eq:=compare_defs_ext(def_from,def_to,currpt.left.nodetype,convtype,pdoper,cdoptions);
                    eq:=compare_defs_ext(def_from,def_to,currpt.left.nodetype,convtype,pdoper,cdoptions);
 
 
@@ -3168,9 +3176,8 @@ implementation
                         { para requires an equal type so the previous found
                         { para requires an equal type so the previous found
                           match was not good enough, reset to incompatible }
                           match was not good enough, reset to incompatible }
                         eq:=te_incompatible;
                         eq:=te_incompatible;
-                        { var_para_allowed will return te_equal and te_convert_l1 to
-                          make a difference for best matching }
-                        var_para_allowed(eq,currpt.resultdef,currpara.vardef,currpt.left)
+                        var_para_allowed(eq,currpt.resultdef,currpara.vardef,currpt.left);
+                        check_valid_var:=false;
                       end
                       end
                     else
                     else
                       para_allowed(eq,currpt,def_to);
                       para_allowed(eq,currpt,def_to);
@@ -3191,6 +3198,10 @@ implementation
                 procvar is choosen. See tb0471 (PFV) }
                 procvar is choosen. See tb0471 (PFV) }
               if (pt<>currpt) and (eq=te_exact) then
               if (pt<>currpt) and (eq=te_exact) then
                 eq:=te_equal;
                 eq:=te_equal;
+              { if var or out parameter type but paranode not is_valid_for_var }
+              if check_valid_var and (currpara.varspez in [vs_var,vs_out]) and not valid_for_var(currpt.left,false)
+                 and (def_to.typ<>formaldef) and not is_open_array(def_to) then
+                eq:=te_incompatible;
 
 
               { increase correct counter }
               { increase correct counter }
               case eq of
               case eq of

+ 10 - 0
compiler/i386/aoptcpu.pas

@@ -161,6 +161,8 @@ unit aoptcpu;
                   Result:=OptPass1ADD(p);
                   Result:=OptPass1ADD(p);
                 A_AND:
                 A_AND:
                   Result:=OptPass1And(p);
                   Result:=OptPass1And(p);
+                A_CMOVcc:
+                  Result:=OptPass1CMOVcc(p);
                 A_IMUL:
                 A_IMUL:
                   Result:=OptPass1Imul(p);
                   Result:=OptPass1Imul(p);
                 A_CMP:
                 A_CMP:
@@ -255,6 +257,9 @@ unit aoptcpu;
                 A_VCVTSS2SD,
                 A_VCVTSS2SD,
                 A_CVTSS2SD:
                 A_CVTSS2SD:
                   Result:=OptPass1_V_Cvtss2sd(p);
                   Result:=OptPass1_V_Cvtss2sd(p);
+                A_CLC,
+                A_STC:
+                  Result:=OptPass1STCCLC(p);
                 else
                 else
                   ;
                   ;
               end;
               end;
@@ -291,6 +296,8 @@ unit aoptcpu;
               case taicpu(p).opcode Of
               case taicpu(p).opcode Of
                 A_ADD:
                 A_ADD:
                   Result:=OptPass2ADD(p);
                   Result:=OptPass2ADD(p);
+                A_CMOVcc:
+                  Result:=OptPass2CMOVcc(p);
                 A_CMP:
                 A_CMP:
                   Result:=OptPass2CMP(p);
                   Result:=OptPass2CMP(p);
                 A_TEST:
                 A_TEST:
@@ -313,6 +320,9 @@ unit aoptcpu;
                   Result:=OptPass2SUB(p);
                   Result:=OptPass2SUB(p);
                 A_SETcc:
                 A_SETcc:
                   Result:=OptPass2SETcc(p);
                   Result:=OptPass2SETcc(p);
+                A_CLC,
+                A_STC:
+                  Result:=OptPass2STCCLC(p);
                 else
                 else
                   ;
                   ;
               end;
               end;

+ 4 - 0
compiler/i386/cpuinfo.pas

@@ -62,6 +62,7 @@ Type
        cpu_core_avx2,
        cpu_core_avx2,
        cpu_zen,
        cpu_zen,
        cpu_zen2,
        cpu_zen2,
+       cpu_skylake_x,
        cpu_icelake,
        cpu_icelake,
        cpu_icelake_client,
        cpu_icelake_client,
        cpu_icelake_server,
        cpu_icelake_server,
@@ -140,6 +141,7 @@ Const
      'COREAVX2',
      'COREAVX2',
      'ZEN',
      'ZEN',
      'ZEN2',
      'ZEN2',
+     'SKYLAKE-X',
      'ICELAKE',
      'ICELAKE',
      'ICELAKE-CLIENT',
      'ICELAKE-CLIENT',
      'ICELAKE-SERVER',
      'ICELAKE-SERVER',
@@ -250,6 +252,7 @@ type
      { cpu_core_avx2 } [CPUX86_HAS_BSWAP,CPUX86_HAS_BTX,CPUX86_HAS_CMOV,CPUX86_HAS_SSEUNIT,CPUX86_HAS_SSE2,CPUX86_HAS_POPCNT,CPUX86_HAS_BMI1,CPUX86_HAS_BMI2,CPUX86_HAS_LZCNT,CPUX86_HAS_MOVBE],
      { cpu_core_avx2 } [CPUX86_HAS_BSWAP,CPUX86_HAS_BTX,CPUX86_HAS_CMOV,CPUX86_HAS_SSEUNIT,CPUX86_HAS_SSE2,CPUX86_HAS_POPCNT,CPUX86_HAS_BMI1,CPUX86_HAS_BMI2,CPUX86_HAS_LZCNT,CPUX86_HAS_MOVBE],
      { cpu_zen       } [CPUX86_HAS_BSWAP,CPUX86_HAS_BTX,CPUX86_HAS_CMOV,CPUX86_HAS_SSEUNIT,CPUX86_HAS_SSE2,CPUX86_HAS_POPCNT,CPUX86_HAS_BMI1,CPUX86_HAS_BMI2,CPUX86_HAS_LZCNT,CPUX86_HAS_MOVBE],
      { cpu_zen       } [CPUX86_HAS_BSWAP,CPUX86_HAS_BTX,CPUX86_HAS_CMOV,CPUX86_HAS_SSEUNIT,CPUX86_HAS_SSE2,CPUX86_HAS_POPCNT,CPUX86_HAS_BMI1,CPUX86_HAS_BMI2,CPUX86_HAS_LZCNT,CPUX86_HAS_MOVBE],
      { cpu_zen2      } [CPUX86_HAS_BSWAP,CPUX86_HAS_BTX,CPUX86_HAS_CMOV,CPUX86_HAS_SSEUNIT,CPUX86_HAS_SSE2,CPUX86_HAS_POPCNT,CPUX86_HAS_BMI1,CPUX86_HAS_BMI2,CPUX86_HAS_LZCNT,CPUX86_HAS_MOVBE],
      { cpu_zen2      } [CPUX86_HAS_BSWAP,CPUX86_HAS_BTX,CPUX86_HAS_CMOV,CPUX86_HAS_SSEUNIT,CPUX86_HAS_SSE2,CPUX86_HAS_POPCNT,CPUX86_HAS_BMI1,CPUX86_HAS_BMI2,CPUX86_HAS_LZCNT,CPUX86_HAS_MOVBE],
+     { cpu_skylake_x } [CPUX86_HAS_BSWAP,CPUX86_HAS_BTX,CPUX86_HAS_CMOV,CPUX86_HAS_SSEUNIT,CPUX86_HAS_SSE2,CPUX86_HAS_POPCNT,CPUX86_HAS_BMI1,CPUX86_HAS_BMI2,CPUX86_HAS_LZCNT,CPUX86_HAS_MOVBE],
      { cpu_icelake   } [CPUX86_HAS_BSWAP,CPUX86_HAS_BTX,CPUX86_HAS_CMOV,CPUX86_HAS_SSEUNIT,CPUX86_HAS_SSE2,CPUX86_HAS_POPCNT,CPUX86_HAS_BMI1,CPUX86_HAS_BMI2,CPUX86_HAS_LZCNT,CPUX86_HAS_MOVBE],
      { cpu_icelake   } [CPUX86_HAS_BSWAP,CPUX86_HAS_BTX,CPUX86_HAS_CMOV,CPUX86_HAS_SSEUNIT,CPUX86_HAS_SSE2,CPUX86_HAS_POPCNT,CPUX86_HAS_BMI1,CPUX86_HAS_BMI2,CPUX86_HAS_LZCNT,CPUX86_HAS_MOVBE],
      { cpu_icelake_client } [CPUX86_HAS_BSWAP,CPUX86_HAS_BTX,CPUX86_HAS_CMOV,CPUX86_HAS_SSEUNIT,CPUX86_HAS_SSE2,CPUX86_HAS_POPCNT,CPUX86_HAS_BMI1,CPUX86_HAS_BMI2,CPUX86_HAS_LZCNT,CPUX86_HAS_MOVBE],
      { cpu_icelake_client } [CPUX86_HAS_BSWAP,CPUX86_HAS_BTX,CPUX86_HAS_CMOV,CPUX86_HAS_SSEUNIT,CPUX86_HAS_SSE2,CPUX86_HAS_POPCNT,CPUX86_HAS_BMI1,CPUX86_HAS_BMI2,CPUX86_HAS_LZCNT,CPUX86_HAS_MOVBE],
      { cpu_icelake_server } [CPUX86_HAS_BSWAP,CPUX86_HAS_BTX,CPUX86_HAS_CMOV,CPUX86_HAS_SSEUNIT,CPUX86_HAS_SSE2,CPUX86_HAS_POPCNT,CPUX86_HAS_BMI1,CPUX86_HAS_BMI2,CPUX86_HAS_LZCNT,CPUX86_HAS_MOVBE],
      { cpu_icelake_server } [CPUX86_HAS_BSWAP,CPUX86_HAS_BTX,CPUX86_HAS_CMOV,CPUX86_HAS_SSEUNIT,CPUX86_HAS_SSE2,CPUX86_HAS_POPCNT,CPUX86_HAS_BMI1,CPUX86_HAS_BMI2,CPUX86_HAS_LZCNT,CPUX86_HAS_MOVBE],
@@ -289,6 +292,7 @@ type
      { cpu_core_avx2 } [CPUX86_HINT_FAST_BT_REG_IMM,CPUX86_HINT_FAST_BTX_REG_IMM,CPUX86_HINT_FAST_XCHG,CPUX86_HINT_FAST_PDEP_PEXT],
      { cpu_core_avx2 } [CPUX86_HINT_FAST_BT_REG_IMM,CPUX86_HINT_FAST_BTX_REG_IMM,CPUX86_HINT_FAST_XCHG,CPUX86_HINT_FAST_PDEP_PEXT],
      { cpu_zen       } [CPUX86_HINT_FAST_BT_REG_IMM,CPUX86_HINT_FAST_BTX_REG_IMM,CPUX86_HINT_FAST_BT_MEM_IMM,CPUX86_HINT_FAST_XCHG,CPUX86_HINT_FAST_3COMP_ADDR],
      { cpu_zen       } [CPUX86_HINT_FAST_BT_REG_IMM,CPUX86_HINT_FAST_BTX_REG_IMM,CPUX86_HINT_FAST_BT_MEM_IMM,CPUX86_HINT_FAST_XCHG,CPUX86_HINT_FAST_3COMP_ADDR],
      { cpu_zen2      } [CPUX86_HINT_FAST_BT_REG_IMM,CPUX86_HINT_FAST_BTX_REG_IMM,CPUX86_HINT_FAST_BT_MEM_IMM,CPUX86_HINT_FAST_XCHG,CPUX86_HINT_FAST_3COMP_ADDR],
      { cpu_zen2      } [CPUX86_HINT_FAST_BT_REG_IMM,CPUX86_HINT_FAST_BTX_REG_IMM,CPUX86_HINT_FAST_BT_MEM_IMM,CPUX86_HINT_FAST_XCHG,CPUX86_HINT_FAST_3COMP_ADDR],
+     { cpu_skylake_x } [CPUX86_HINT_FAST_BT_REG_IMM,CPUX86_HINT_FAST_BTX_REG_IMM,CPUX86_HINT_FAST_BT_MEM_IMM,CPUX86_HINT_FAST_XCHG,CPUX86_HINT_FAST_PDEP_PEXT,CPUX86_HINT_FAST_3COMP_ADDR],
      { cpu_icelake   } [CPUX86_HINT_FAST_BT_REG_IMM,CPUX86_HINT_FAST_BTX_REG_IMM,CPUX86_HINT_FAST_BT_MEM_IMM,CPUX86_HINT_FAST_XCHG,CPUX86_HINT_FAST_PDEP_PEXT,CPUX86_HINT_FAST_3COMP_ADDR],
      { cpu_icelake   } [CPUX86_HINT_FAST_BT_REG_IMM,CPUX86_HINT_FAST_BTX_REG_IMM,CPUX86_HINT_FAST_BT_MEM_IMM,CPUX86_HINT_FAST_XCHG,CPUX86_HINT_FAST_PDEP_PEXT,CPUX86_HINT_FAST_3COMP_ADDR],
      { cpu_icelake_client } [CPUX86_HINT_FAST_BT_REG_IMM,CPUX86_HINT_FAST_BTX_REG_IMM,CPUX86_HINT_FAST_BT_MEM_IMM,CPUX86_HINT_FAST_XCHG,CPUX86_HINT_FAST_PDEP_PEXT,CPUX86_HINT_FAST_3COMP_ADDR],
      { cpu_icelake_client } [CPUX86_HINT_FAST_BT_REG_IMM,CPUX86_HINT_FAST_BTX_REG_IMM,CPUX86_HINT_FAST_BT_MEM_IMM,CPUX86_HINT_FAST_XCHG,CPUX86_HINT_FAST_PDEP_PEXT,CPUX86_HINT_FAST_3COMP_ADDR],
      { cpu_icelake_server } [CPUX86_HINT_FAST_BT_REG_IMM,CPUX86_HINT_FAST_BTX_REG_IMM,CPUX86_HINT_FAST_BT_MEM_IMM,CPUX86_HINT_FAST_XCHG,CPUX86_HINT_FAST_PDEP_PEXT,CPUX86_HINT_FAST_3COMP_ADDR],
      { cpu_icelake_server } [CPUX86_HINT_FAST_BT_REG_IMM,CPUX86_HINT_FAST_BTX_REG_IMM,CPUX86_HINT_FAST_BT_MEM_IMM,CPUX86_HINT_FAST_XCHG,CPUX86_HINT_FAST_PDEP_PEXT,CPUX86_HINT_FAST_3COMP_ADDR],

+ 9 - 0
compiler/i386/n386inl.pas

@@ -123,6 +123,8 @@ implementation
 
 
 
 
   procedure ti386inlinenode.second_abs_long;
   procedure ti386inlinenode.second_abs_long;
+    var
+      hl: TAsmLabel;
     begin
     begin
       if is_64bitint(left.resultdef) then
       if is_64bitint(left.resultdef) then
         begin
         begin
@@ -137,6 +139,13 @@ implementation
           cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_XOR,OS_32,left.location.register64.reghi,location.register64.reghi);
           cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_XOR,OS_32,left.location.register64.reghi,location.register64.reghi);
           emit_reg_reg(A_SUB,S_L,left.location.register64.reghi,location.register64.reglo);
           emit_reg_reg(A_SUB,S_L,left.location.register64.reghi,location.register64.reglo);
           emit_reg_reg(A_SBB,S_L,left.location.register64.reghi,location.register64.reghi);
           emit_reg_reg(A_SBB,S_L,left.location.register64.reghi,location.register64.reghi);
+          if cs_check_overflow in current_settings.localswitches then
+            begin
+              current_asmdata.getjumplabel(hl);
+              cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NO,hl);
+              cg.a_call_name(current_asmdata.CurrAsmList,'FPC_OVERFLOW',false);
+              cg.a_label(current_asmdata.CurrAsmList,hl);
+            end;
         end
         end
       else
       else
         inherited second_abs_long;
         inherited second_abs_long;

+ 1 - 1
compiler/i386/n386mem.pas

@@ -81,7 +81,7 @@ implementation
     procedure ti386vecnode.pass_generate_code;
     procedure ti386vecnode.pass_generate_code;
       begin
       begin
         inherited pass_generate_code;
         inherited pass_generate_code;
-        if nf_memseg in flags then
+        if vnf_memseg in vecnodeflags then
           location.reference.segment:=NR_FS;
           location.reference.segment:=NR_FS;
       end;
       end;
 
 

+ 1 - 1
compiler/i8086/n8086add.pas

@@ -137,7 +137,7 @@ interface
                     { pointer-pointer results in an integer }
                     { pointer-pointer results in an integer }
                     if (rt=pointerconstn) then
                     if (rt=pointerconstn) then
                       begin
                       begin
-                        if not(nf_has_pointerdiv in flags) then
+                        if not(anf_has_pointerdiv in addnodeflags) then
                           internalerror(2008030102);
                           internalerror(2008030102);
                         { todo: implement pointer-pointer as well }
                         { todo: implement pointer-pointer as well }
                         internalerror(2014040607);
                         internalerror(2014040607);

+ 15 - 0
compiler/i8086/n8086inl.pas

@@ -387,6 +387,7 @@ implementation
      procedure ti8086inlinenode.second_abs_long;
      procedure ti8086inlinenode.second_abs_long;
        var
        var
          opsize: TCgSize;
          opsize: TCgSize;
+         hl: TAsmLabel;
        begin
        begin
          opsize:=def_cgsize(left.resultdef);
          opsize:=def_cgsize(left.resultdef);
          if opsize in [OS_64,OS_S64] then
          if opsize in [OS_64,OS_S64] then
@@ -406,6 +407,13 @@ implementation
             emit_reg_reg(A_SBB,S_W,cg.GetNextReg(left.location.register64.reghi),cg.GetNextReg(location.register64.reglo));
             emit_reg_reg(A_SBB,S_W,cg.GetNextReg(left.location.register64.reghi),cg.GetNextReg(location.register64.reglo));
             emit_reg_reg(A_SBB,S_W,cg.GetNextReg(left.location.register64.reghi),location.register64.reghi);
             emit_reg_reg(A_SBB,S_W,cg.GetNextReg(left.location.register64.reghi),location.register64.reghi);
             emit_reg_reg(A_SBB,S_W,cg.GetNextReg(left.location.register64.reghi),cg.GetNextReg(location.register64.reghi));
             emit_reg_reg(A_SBB,S_W,cg.GetNextReg(left.location.register64.reghi),cg.GetNextReg(location.register64.reghi));
+            if cs_check_overflow in current_settings.localswitches then
+              begin
+                current_asmdata.getjumplabel(hl);
+                cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NO,hl);
+                cg.a_call_name(current_asmdata.CurrAsmList,'FPC_OVERFLOW',false);
+                cg.a_label(current_asmdata.CurrAsmList,hl);
+              end;
            end
            end
          else if opsize in [OS_32,OS_S32] then
          else if opsize in [OS_32,OS_S32] then
            begin
            begin
@@ -419,6 +427,13 @@ implementation
             cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_XOR,OS_16,cg.GetNextReg(left.location.register),cg.GetNextReg(location.register));
             cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_XOR,OS_16,cg.GetNextReg(left.location.register),cg.GetNextReg(location.register));
             emit_reg_reg(A_SUB,S_W,cg.GetNextReg(left.location.register),location.register);
             emit_reg_reg(A_SUB,S_W,cg.GetNextReg(left.location.register),location.register);
             emit_reg_reg(A_SBB,S_W,cg.GetNextReg(left.location.register),cg.GetNextReg(location.register));
             emit_reg_reg(A_SBB,S_W,cg.GetNextReg(left.location.register),cg.GetNextReg(location.register));
+            if cs_check_overflow in current_settings.localswitches then
+              begin
+                current_asmdata.getjumplabel(hl);
+                cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NO,hl);
+                cg.a_call_name(current_asmdata.CurrAsmList,'FPC_OVERFLOW',false);
+                cg.a_label(current_asmdata.CurrAsmList,hl);
+              end;
            end
            end
          else
          else
            inherited second_abs_long;
            inherited second_abs_long;

+ 1 - 1
compiler/i8086/n8086mem.pas

@@ -160,7 +160,7 @@ implementation
    {$ifdef x86}
    {$ifdef x86}
                (tcpupointerdef(left.resultdef).x86pointertyp = tcpupointerdefclass(cpointerdef).default_x86_data_pointer_type) and
                (tcpupointerdef(left.resultdef).x86pointertyp = tcpupointerdefclass(cpointerdef).default_x86_data_pointer_type) and
    {$endif x86}
    {$endif x86}
-               not(nf_no_checkpointer in flags) and
+               not(drnf_no_checkpointer in derefnodeflags) and
                { can be NR_NO in case of LOC_CONSTANT }
                { can be NR_NO in case of LOC_CONSTANT }
                (location.reference.base<>NR_NO) then
                (location.reference.base<>NR_NO) then
              begin
              begin

+ 1 - 1
compiler/jvm/njvmcnv.pas

@@ -502,7 +502,7 @@ implementation
           end;
           end;
         if not assigned(procdefparas) then
         if not assigned(procdefparas) then
           procdefparas:=carrayconstructornode.create(nil,nil);
           procdefparas:=carrayconstructornode.create(nil,nil);
-        procdefparas.allow_array_constructor:=true;
+        Include(procdefparas.arrayconstructornodeflags, acnf_allow_array_constructor);
         constrparas:=ccallparanode.create(procdefparas,constrparas);
         constrparas:=ccallparanode.create(procdefparas,constrparas);
         result:=ccallnode.createinternmethod(cloadvmtaddrnode.create(ctypenode.create(tcpuprocvardef(resultdef).classdef)),'CREATE',constrparas);
         result:=ccallnode.createinternmethod(cloadvmtaddrnode.create(ctypenode.create(tcpuprocvardef(resultdef).classdef)),'CREATE',constrparas);
         { typecast to the procvar type }
         { typecast to the procvar type }

+ 13 - 10
compiler/jvm/njvmutil.pas

@@ -55,7 +55,7 @@ interface
       class procedure InsertResStrInits; override;
       class procedure InsertResStrInits; override;
       class procedure InsertMemorySizes; override;
       class procedure InsertMemorySizes; override;
      protected
      protected
-       class procedure insert_init_final_table(entries:tfplist); override;
+       class procedure insert_init_final_table(main: tmodule; entries:tfplist); override;
      strict protected
      strict protected
        class procedure add_main_procdef_paras(pd: tdef); override;
        class procedure add_main_procdef_paras(pd: tdef); override;
     end;
     end;
@@ -387,24 +387,27 @@ implementation
         inherited;
         inherited;
     end;
     end;
 
 
-  class procedure tjvmnodeutils.insert_init_final_table(entries:tfplist);
+  class procedure tjvmnodeutils.insert_init_final_table(main: tmodule; entries:tfplist);
+
     var
     var
       hp : tused_unit;
       hp : tused_unit;
       unitinits : TAsmList;
       unitinits : TAsmList;
       unitclassname: string;
       unitclassname: string;
       mainpsym: tsym;
       mainpsym: tsym;
       mainpd: tprocdef;
       mainpd: tprocdef;
-    begin
-      { JVM does not use the entries list }
+      m : tmodule;
+      i : integer;
 
 
+    begin
       unitinits:=TAsmList.Create;
       unitinits:=TAsmList.Create;
-      hp:=tused_unit(usedunits.first);
-      while assigned(hp) do
+      for I:=0 to entries.Count-1 do
         begin
         begin
+          hp:=tused_unit(entries[i]);
+          m:=hp.u;
           { class constructors are automatically handled by the JVM }
           { class constructors are automatically handled by the JVM }
 
 
-          { call the unit init code and make it external }
-          if (hp.u.moduleflags*[mf_init,mf_finalize])<>[] then
+          { for non-main module, call the unit init code and make it external }
+          if (m<>main) and ((m.moduleflags*[mf_init,mf_finalize])<>[]) then
             begin
             begin
               { trigger init code by referencing the class representing the
               { trigger init code by referencing the class representing the
                 unit; if necessary, it will register the fini code to run on
                 unit; if necessary, it will register the fini code to run on
@@ -419,10 +422,10 @@ implementation
               unitinits.concat(taicpu.op_sym(a_new,current_asmdata.RefAsmSymbol(unitclassname,AT_METADATA)));
               unitinits.concat(taicpu.op_sym(a_new,current_asmdata.RefAsmSymbol(unitclassname,AT_METADATA)));
               unitinits.concat(taicpu.op_none(a_pop));
               unitinits.concat(taicpu.op_none(a_pop));
             end;
             end;
-          hp:=tused_unit(hp.next);
         end;
         end;
+
       { insert in main program routine }
       { insert in main program routine }
-      mainpsym:=tsym(current_module.localsymtable.find(mainaliasname));
+      mainpsym:=tsym(main.localsymtable.find(mainaliasname));
       if not assigned(mainpsym) or
       if not assigned(mainpsym) or
          (mainpsym.typ<>procsym) then
          (mainpsym.typ<>procsym) then
         internalerror(2011041901);
         internalerror(2011041901);

+ 2 - 2
compiler/llvm/nllvmbas.pas

@@ -201,7 +201,7 @@ interface
       begin
       begin
         oldasmlist:=nil;
         oldasmlist:=nil;
         if not(po_assembler in current_procinfo.procdef.procoptions) and
         if not(po_assembler in current_procinfo.procdef.procoptions) and
-           not(nf_get_asm_position in flags) then
+           not(asmnf_get_asm_position in asmnodeflags) then
           begin
           begin
             { store the assembler code in a separate list, so we can make it
             { store the assembler code in a separate list, so we can make it
               the argument of an asmblock instruction }
               the argument of an asmblock instruction }
@@ -214,7 +214,7 @@ interface
           end;
           end;
         inherited;
         inherited;
         if not(po_assembler in current_procinfo.procdef.procoptions) and
         if not(po_assembler in current_procinfo.procdef.procoptions) and
-           not(nf_get_asm_position in flags) then
+           not(asmnf_get_asm_position in asmnodeflags) then
           begin
           begin
             asmai:=taillvm.asm_paras(current_asmdata.CurrAsmList,fsymboldata);
             asmai:=taillvm.asm_paras(current_asmdata.CurrAsmList,fsymboldata);
             fsymboldata:=nil;
             fsymboldata:=nil;

+ 1 - 1
compiler/loongarch64/cgcpu.pas

@@ -462,7 +462,7 @@ implementation
         utosize:=tcgsize2unsigned[tosize];
         utosize:=tcgsize2unsigned[tosize];
         ufrom:=ufromsize=fromsize;
         ufrom:=ufromsize=fromsize;
         uto:=utosize=tosize;
         uto:=utosize=tosize;
-        if (fromsize=tosize) or ((ufromsize=OS_INT) and (utosize=OS_INT)) then
+        if (ufromsize=OS_INT) and (utosize=OS_INT) then
           begin
           begin
             ai:=taicpu.op_reg_reg(A_MOVE,reg2,reg1);
             ai:=taicpu.op_reg_reg(A_MOVE,reg2,reg1);
             list.concat(ai);
             list.concat(ai);

+ 13 - 0
compiler/loongarch64/ncpuadd.pas

@@ -47,6 +47,7 @@ unit ncpuadd;
         procedure second_cmpfloat;override;
         procedure second_cmpfloat;override;
       public
       public
         function use_generic_mul32to64: boolean; override;
         function use_generic_mul32to64: boolean; override;
+        function pass_1 : tnode;override;
       end;
       end;
 
 
 
 
@@ -396,6 +397,18 @@ implementation
         result:=false;
         result:=false;
       end;
       end;
 
 
+    function tloongarch64addnode.pass_1: tnode;
+      begin
+        Result:=inherited pass_1;
+        { if the result is not nil, a new node has been generated and the current node will be discarted }
+        if Result=nil then
+          begin
+            if left.resultdef.typ=floatdef then
+              if needs_check_for_fpu_exceptions then
+                Include(current_procinfo.flags,pi_do_call);
+          end;
+      end;
+
 begin
 begin
   caddnode := tloongarch64addnode;
   caddnode := tloongarch64addnode;
 end.
 end.

+ 9 - 0
compiler/loongarch64/ncpuinl.pas

@@ -59,6 +59,7 @@ implementation
       aasmtai,aasmdata,aasmcpu,
       aasmtai,aasmdata,aasmcpu,
       symconst,symdef,
       symconst,symdef,
       defutil,
       defutil,
+      procinfo,
       cgbase,pass_2,
       cgbase,pass_2,
       cpuinfo,ncgutil,
       cpuinfo,ncgutil,
       hlcgobj,cgutils,cgobj,rgobj,tgobj;
       hlcgobj,cgutils,cgobj,rgobj,tgobj;
@@ -72,6 +73,8 @@ implementation
        begin
        begin
          expectloc:=LOC_FPUREGISTER;
          expectloc:=LOC_FPUREGISTER;
          first_sqrt_real := nil;
          first_sqrt_real := nil;
+         if needs_check_for_fpu_exceptions then
+           Include(current_procinfo.flags,pi_do_call);
        end;
        end;
 
 
 
 
@@ -86,6 +89,8 @@ implementation
        begin
        begin
          expectloc:=LOC_FPUREGISTER;
          expectloc:=LOC_FPUREGISTER;
          first_sqr_real := nil;
          first_sqr_real := nil;
+         if needs_check_for_fpu_exceptions then
+           Include(current_procinfo.flags,pi_do_call);
        end;
        end;
 
 
 
 
@@ -93,6 +98,8 @@ implementation
        begin
        begin
          expectloc:=LOC_FPUREGISTER;
          expectloc:=LOC_FPUREGISTER;
          first_round_real := nil;
          first_round_real := nil;
+         if needs_check_for_fpu_exceptions then
+           Include(current_procinfo.flags,pi_do_call);
        end;
        end;
 
 
 
 
@@ -100,6 +107,8 @@ implementation
        begin
        begin
          expectloc:=LOC_FPUREGISTER;
          expectloc:=LOC_FPUREGISTER;
          first_trunc_real := nil;
          first_trunc_real := nil;
+         if needs_check_for_fpu_exceptions then
+           Include(current_procinfo.flags,pi_do_call);
        end;
        end;
 
 
 
 

+ 4 - 1
compiler/msg/errore.msg

@@ -1671,9 +1671,12 @@ parser_e_suspending_externals_not_supported_on_current_platform=03368_E_Declarin
 parser_w_widechar_set_reduced=03369_W_Reducing Widechar set to single-byte AnsiChar set.
 parser_w_widechar_set_reduced=03369_W_Reducing Widechar set to single-byte AnsiChar set.
 % The base type of a set can only have 255 elements. Sets of wide characters
 % The base type of a set can only have 255 elements. Sets of wide characters
 % are reduced to sets of 1-byte characters.
 % are reduced to sets of 1-byte characters.
-parser_e_nostringaliasinsystem=03370_e_Using 'string' alias is not allowed in the system unit. Use short-,ansi- or unicodestring.
+parser_e_nostringaliasinsystem=03370_E_Using 'string' alias is not allowed in the system unit. Use short-,ansi- or unicodestring.
 % As a safeguard, the system unit may only use basic string types, not the
 % As a safeguard, the system unit may only use basic string types, not the
 % string alias which is dependent on the mode in which a unit is compiled.
 % string alias which is dependent on the mode in which a unit is compiled.
+parser_e_coperators_off=03371_E_C styled assignment operators are turned off
+% By default, c style assignment operators (+=, -=, *=, /=) are turn off. Either turn them on by the command line
+% parameter -Sc or in the source code by {\$COPERATORS ON}
 %
 %
 % \end{description}
 % \end{description}
 %
 %

+ 3 - 2
compiler/msgidx.inc

@@ -490,6 +490,7 @@ const
   parser_e_suspending_externals_not_supported_on_current_platform=03368;
   parser_e_suspending_externals_not_supported_on_current_platform=03368;
   parser_w_widechar_set_reduced=03369;
   parser_w_widechar_set_reduced=03369;
   parser_e_nostringaliasinsystem=03370;
   parser_e_nostringaliasinsystem=03370;
+  parser_e_coperators_off=03371;
   type_e_mismatch=04000;
   type_e_mismatch=04000;
   type_e_incompatible_types=04001;
   type_e_incompatible_types=04001;
   type_e_not_equal_types=04002;
   type_e_not_equal_types=04002;
@@ -1177,9 +1178,9 @@ const
   option_info=11024;
   option_info=11024;
   option_help_pages=11025;
   option_help_pages=11025;
 
 
-  MsgTxtSize = 92723;
+  MsgTxtSize = 92776;
 
 
   MsgIdxMax : array[1..20] of longint=(
   MsgIdxMax : array[1..20] of longint=(
-    29,114,371,134,102,63,148,38,224,71,
+    29,114,372,134,102,63,148,38,224,71,
     69,20,30,1,1,1,1,1,1,1
     69,20,30,1,1,1,1,1,1,1
   );
   );

File diff suppressed because it is too large
+ 355 - 353
compiler/msgtxt.inc


+ 227 - 80
compiler/nadd.pas

@@ -32,12 +32,21 @@ interface
       node,symtype;
       node,symtype;
 
 
     type
     type
+       TAddNodeFlag = (
+         anf_has_pointerdiv,
+         { the node shall be short boolean evaluated, this flag has priority over localswitches }
+         anf_short_bool
+       );
+
+       TAddNodeFlags = set of TAddNodeFlag;
+
        taddnode = class(tbinopnode)
        taddnode = class(tbinopnode)
        private
        private
           resultrealdefderef: tderef;
           resultrealdefderef: tderef;
           function pass_typecheck_internal:tnode;
           function pass_typecheck_internal:tnode;
        public
        public
           resultrealdef : tdef;
           resultrealdef : tdef;
+          addnodeflags : TAddNodeFlags;
           constructor create(tt : tnodetype;l,r : tnode);override;
           constructor create(tt : tnodetype;l,r : tnode);override;
           constructor create_internal(tt:tnodetype;l,r:tnode);
           constructor create_internal(tt:tnodetype;l,r:tnode);
           constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
           constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
@@ -52,6 +61,9 @@ interface
     {$ifdef state_tracking}
     {$ifdef state_tracking}
           function track_state_pass(exec_known:boolean):boolean;override;
           function track_state_pass(exec_known:boolean):boolean;override;
     {$endif}
     {$endif}
+    {$ifdef DEBUG_NODE_XML}
+          procedure XMLPrintNodeInfo(var T: Text); override;
+    {$endif DEBUG_NODE_XML}
          protected
          protected
           { override the following if you want to implement }
           { override the following if you want to implement }
           { parts explicitely in the code generator (JM)    }
           { parts explicitely in the code generator (JM)    }
@@ -140,7 +152,8 @@ implementation
       {$ifdef state_tracking}
       {$ifdef state_tracking}
       nstate,
       nstate,
       {$endif}
       {$endif}
-      cpuinfo;
+      cpuinfo,
+      ppu;
 
 
 
 
 {*****************************************************************************
 {*****************************************************************************
@@ -179,9 +192,9 @@ implementation
     constructor taddnode.create(tt : tnodetype;l,r : tnode);
     constructor taddnode.create(tt : tnodetype;l,r : tnode);
       begin
       begin
          inherited create(tt,l,r);
          inherited create(tt,l,r);
+         addnodeflags:=[];
       end;
       end;
 
 
-
     constructor taddnode.create_internal(tt:tnodetype;l,r:tnode);
     constructor taddnode.create_internal(tt:tnodetype;l,r:tnode);
       begin
       begin
         create(tt,l,r);
         create(tt,l,r);
@@ -192,6 +205,7 @@ implementation
     constructor taddnode.ppuload(t: tnodetype; ppufile: tcompilerppufile);
     constructor taddnode.ppuload(t: tnodetype; ppufile: tcompilerppufile);
       begin
       begin
         inherited ppuload(t, ppufile);
         inherited ppuload(t, ppufile);
+        ppufile.getset(tppuset1(addnodeflags));
         ppufile.getderef(resultrealdefderef);
         ppufile.getderef(resultrealdefderef);
       end;
       end;
 
 
@@ -199,7 +213,8 @@ implementation
     procedure taddnode.ppuwrite(ppufile: tcompilerppufile);
     procedure taddnode.ppuwrite(ppufile: tcompilerppufile);
       begin
       begin
         inherited ppuwrite(ppufile);
         inherited ppuwrite(ppufile);
-         ppufile.putderef(resultrealdefderef);
+        ppufile.putset(tppuset1(addnodeflags));
+        ppufile.putderef(resultrealdefderef);
       end;
       end;
 
 
 
 
@@ -392,10 +407,12 @@ implementation
       function is_range_test(nodel, noder: taddnode; out value: tnode; var cl,cr: Tconstexprint): boolean;
       function is_range_test(nodel, noder: taddnode; out value: tnode; var cl,cr: Tconstexprint): boolean;
         const
         const
           is_upper_test: array[ltn..gten] of boolean = (true,true,false,false);
           is_upper_test: array[ltn..gten] of boolean = (true,true,false,false);
-          inclusive_adjust: array[boolean,ltn..gten] of integer = ((-1,0,1,0),
-                                                                   (1,0,-1,0));
+          inclusive_adjust: array[boolean,boolean,ltn..gten] of integer = (((-1,0,1,0),
+                                                                            (1,0,-1,0)),
+                                                                           ((0,-1,0,1),
+                                                                            (0,1,0,-1)));
         var
         var
-          swapl, swapr: Boolean;
+          swapl, swapr, inverted_range: Boolean;
           valuer: tnode;
           valuer: tnode;
           t: Tconstexprint;
           t: Tconstexprint;
         begin
         begin
@@ -434,12 +451,21 @@ implementation
           if not value.isequal(valuer) then
           if not value.isequal(valuer) then
             exit;
             exit;
 
 
+          { This is based on De Morgan's theorem, namely that
+            "A and B" = "not ((not A) or (not B))" }
+          inverted_range:=(nodetype=orn);
+          if inverted_range then
+            begin
+              swapl:=not swapl;
+              swapr:=not swapr;
+            end;
+
           { this could be simplified too, but probably never happens }
           { this could be simplified too, but probably never happens }
           if (is_upper_test[nodel.nodetype] xor swapl)=(is_upper_test[noder.nodetype] xor swapr) then
           if (is_upper_test[nodel.nodetype] xor swapl)=(is_upper_test[noder.nodetype] xor swapr) then
             exit;
             exit;
 
 
-          cl:=cl+inclusive_adjust[swapl,nodel.nodetype];
-          cr:=cr+inclusive_adjust[swapr,noder.nodetype];
+          cl:=cl+inclusive_adjust[inverted_range,swapl,nodel.nodetype];
+          cr:=cr+inclusive_adjust[inverted_range,swapr,noder.nodetype];
 
 
           if is_upper_test[nodel.nodetype] xor swapl then
           if is_upper_test[nodel.nodetype] xor swapl then
             begin
             begin
@@ -736,15 +762,15 @@ implementation
                      { pointer-pointer results in an integer }
                      { pointer-pointer results in an integer }
                      if (rt=pointerconstn) then
                      if (rt=pointerconstn) then
                        begin
                        begin
-                         if not(nf_has_pointerdiv in flags) then
+                         if not(anf_has_pointerdiv in addnodeflags) then
                            internalerror(2008030101);
                            internalerror(2008030101);
-                         t := cpointerconstnode.create(qword(v),resultdef)
+                         t:=cpointerconstnode.create(qword(v),resultdef)
                        end
                        end
                      else
                      else
-                       t := cpointerconstnode.create(qword(v),resultdef)
+                       t:=cpointerconstnode.create(qword(v),resultdef)
                    else
                    else
                      if is_integer(ld) then
                      if is_integer(ld) then
-                       t := create_simplified_ord_const(v,resultdef,forinline,cs_check_overflow in localswitches)
+                       t:=create_simplified_ord_const(v,resultdef,forinline,cs_check_overflow in localswitches)
                      else
                      else
                        t:=cordconstnode.create(v,resultdef,(ld.typ<>enumdef));
                        t:=cordconstnode.create(v,resultdef,(ld.typ<>enumdef));
                  end;
                  end;
@@ -901,8 +927,15 @@ implementation
         { Deal with anti-commutative subtraction }
         { Deal with anti-commutative subtraction }
         if (nodetype = subn) then
         if (nodetype = subn) then
           begin
           begin
+            { transform -1-x into not(x) }
+            if is_signed(rd) and is_constintnode(left) and (tordconstnode(left).value=-1)  then
+              begin
+                result:=cnotnode.create(right.getcopy);
+                exit;
+              end
+
             { change "0 - val" to "-val" }
             { change "0 - val" to "-val" }
-            if is_constintnode(left) and (is_integer(right.resultdef) or is_pointer(right.resultdef)) then
+            else if is_constintnode(left) and (is_integer(right.resultdef) or is_pointer(right.resultdef)) then
               begin
               begin
                 if (tordconstnode(left).value = 0) then
                 if (tordconstnode(left).value = 0) then
                   result := ctypeconvnode.create_internal(cunaryminusnode.create(right.getcopy),right.resultdef);
                   result := ctypeconvnode.create_internal(cunaryminusnode.create(right.getcopy),right.resultdef);
@@ -917,6 +950,13 @@ implementation
                 left:=nil;
                 left:=nil;
                 tmoddivnode(right).right:=nil;
                 tmoddivnode(right).right:=nil;
                 exit;
                 exit;
+              end
+
+            { transform -x-1 into not(x) }
+            else if is_signed(ld) and is_constintnode(right) and (tordconstnode(right).value=1) and (left.nodetype=unaryminusn) then
+              begin
+                result:=cnotnode.create(tunaryminusnode(left).left.getcopy);
+                exit;
               end;
               end;
           end;
           end;
 
 
@@ -1540,7 +1580,7 @@ implementation
                 { transform unsigned comparisons of (v>=x) and (v<=y)
                 { transform unsigned comparisons of (v>=x) and (v<=y)
                   into (v-x)<=(y-x)
                   into (v-x)<=(y-x)
                 }
                 }
-                if (nodetype=andn) and
+                if (nodetype in [andn,orn]) and
                    (left.nodetype in [ltn,lten,gtn,gten]) and
                    (left.nodetype in [ltn,lten,gtn,gten]) and
                    (right.nodetype in [ltn,lten,gtn,gten]) and
                    (right.nodetype in [ltn,lten,gtn,gten]) and
                    (not might_have_sideeffects(left)) and
                    (not might_have_sideeffects(left)) and
@@ -1552,9 +1592,19 @@ implementation
                     hdef:=get_unsigned_inttype(vl.resultdef);
                     hdef:=get_unsigned_inttype(vl.resultdef);
                     vl:=ctypeconvnode.create_internal(vl.getcopy,hdef);
                     vl:=ctypeconvnode.create_internal(vl.getcopy,hdef);
 
 
-                    result:=caddnode.create_internal(lten,
+                    { If the condition is of the inverted form (v<x) or (v>y),
+                      we have to invert the conditional result as well, since
+                      the above nodes return True for if v is within the range
+                      (we're merging "not ((v-x)<=(y-x))" into "(v-x)>(y-x)") }
+                    if (nodetype=orn) then
+                      nt:=gtn
+                    else
+                      nt:=lten;
+
+                    result:=caddnode.create_internal(nt,
                               ctypeconvnode.create_internal(caddnode.create_internal(subn,vl,cordconstnode.create(cl,hdef,false)),hdef),
                               ctypeconvnode.create_internal(caddnode.create_internal(subn,vl,cordconstnode.create(cl,hdef,false)),hdef),
                               cordconstnode.create(cr-cl,hdef,false));
                               cordconstnode.create(cr-cl,hdef,false));
+
                     exit;
                     exit;
                   end;
                   end;
 
 
@@ -1657,7 +1707,7 @@ implementation
                             begin
                             begin
                               { we need to copy the whole tree to force another pass_1 }
                               { we need to copy the whole tree to force another pass_1 }
                               include(localswitches,cs_full_boolean_eval);
                               include(localswitches,cs_full_boolean_eval);
-                              exclude(flags,nf_short_bool);
+                              exclude(addnodeflags,anf_short_bool);
                               result:=getcopy;
                               result:=getcopy;
                               exit;
                               exit;
                             end;
                             end;
@@ -1856,7 +1906,7 @@ implementation
                         else
                         else
                           nt:=equaln;
                           nt:=equaln;
                         result:=caddnode.create(nt,t,cordconstnode.create(0,vl.resultdef,false));
                         result:=caddnode.create(nt,t,cordconstnode.create(0,vl.resultdef,false));
-                        Include(flags, nf_do_not_execute);
+                        Include(transientflags,tnf_do_not_execute);
                         if t=left then
                         if t=left then
                           left:=nil
                           left:=nil
                         else
                         else
@@ -1874,6 +1924,7 @@ implementation
         n: taddnode;
         n: taddnode;
       begin
       begin
         n:=taddnode(inherited dogetcopy);
         n:=taddnode(inherited dogetcopy);
+        n.addnodeflags:=addnodeflags;
         n.resultrealdef:=resultrealdef;
         n.resultrealdef:=resultrealdef;
         result:=n;
         result:=n;
       end;
       end;
@@ -1985,7 +2036,7 @@ implementation
                         elem,nil)));
                         elem,nil)));
 
 
             result:=cinlinenode.create(in_insert_x_y_z,false,para);
             result:=cinlinenode.create(in_insert_x_y_z,false,para);
-            include(aktassignmentnode.flags,nf_assign_done_in_right);
+            include(aktassignmentnode.assignmentnodeflags,anf_assign_done_in_right);
           end;
           end;
 
 
       begin
       begin
@@ -2237,7 +2288,7 @@ implementation
            begin
            begin
               { set for & and | operations in macpas mode: they only work on }
               { set for & and | operations in macpas mode: they only work on }
               { booleans, and always short circuit evaluation                }
               { booleans, and always short circuit evaluation                }
-              if (nf_short_bool in flags) then
+              if (anf_short_bool in addnodeflags) then
                 begin
                 begin
                   if not is_boolean(ld) then
                   if not is_boolean(ld) then
                     begin
                     begin
@@ -2759,11 +2810,11 @@ implementation
                     else
                     else
                       CGMessage3(type_e_operator_not_supported_for_types,node2opstr(nodetype),ld.typename,rd.typename);
                       CGMessage3(type_e_operator_not_supported_for_types,node2opstr(nodetype),ld.typename,rd.typename);
 
 
-                    if not(nf_has_pointerdiv in flags) and
+                    if not(anf_has_pointerdiv in addnodeflags) and
                       (tpointerdef(rd).pointeddef.size>1) then
                       (tpointerdef(rd).pointeddef.size>1) then
                       begin
                       begin
                         hp:=getcopy;
                         hp:=getcopy;
-                        include(hp.flags,nf_has_pointerdiv);
+                        include(taddnode(hp).addnodeflags, anf_has_pointerdiv);
                         result:=cmoddivnode.create(divn,hp,
                         result:=cmoddivnode.create(divn,hp,
                           cordconstnode.create(tpointerdef(rd).pointeddef.size,tpointerdef(rd).pointer_subtraction_result_type,false));
                           cordconstnode.create(tpointerdef(rd).pointeddef.size,tpointerdef(rd).pointer_subtraction_result_type,false));
                       end;
                       end;
@@ -3385,7 +3436,7 @@ implementation
                             'fpc_'+tstringdef(resultdef).stringtypname+'_concat',
                             'fpc_'+tstringdef(resultdef).stringtypname+'_concat',
                             para
                             para
                           );
                           );
-                  include(aktassignmentnode.flags,nf_assign_done_in_right);
+                  include(aktassignmentnode.assignmentnodeflags,anf_assign_done_in_right);
                   firstpass(result);
                   firstpass(result);
                 end
                 end
               else
               else
@@ -3529,7 +3580,7 @@ implementation
               left:=nil;
               left:=nil;
               right:=nil;
               right:=nil;
 
 
-              include(aktassignmentnode.flags,nf_assign_done_in_right);
+              include(aktassignmentnode.assignmentnodeflags,anf_assign_done_in_right);
               firstpass(result);
               firstpass(result);
             end
             end
           else
           else
@@ -3565,8 +3616,10 @@ implementation
         tempn: tnode;
         tempn: tnode;
         newstatement : tstatementnode;
         newstatement : tstatementnode;
         temp    : ttempcreatenode;
         temp    : ttempcreatenode;
+        no_temp: Boolean;
       begin
       begin
         result:=nil;
         result:=nil;
+
         case nodetype of
         case nodetype of
           equaln,unequaln,lten,gten:
           equaln,unequaln,lten,gten:
             begin
             begin
@@ -3600,40 +3653,31 @@ implementation
             end;
             end;
           addn:
           addn:
             begin
             begin
+              { can we directly write into the result? }
+              no_temp:=assigned(aktassignmentnode) and
+                (aktassignmentnode.right=self) and
+                (aktassignmentnode.left.resultdef=self.resultdef) and
+                valid_for_var(aktassignmentnode.left,false);
+
               { optimize first loading of a set }
               { optimize first loading of a set }
               if (right.nodetype=setelementn) and
               if (right.nodetype=setelementn) and
                   not(assigned(tsetelementnode(right).right)) and
                   not(assigned(tsetelementnode(right).right)) and
                   is_emptyset(left) then
                   is_emptyset(left) then
                 begin
                 begin
-                  result:=internalstatements(newstatement);
-
-                  { create temp for result }
-                  temp:=ctempcreatenode.create(resultdef,resultdef.size,tt_persistent,true);
-                  addstatement(newstatement,temp);
-
                   { adjust for set base }
                   { adjust for set base }
                   tsetelementnode(right).left:=caddnode.create(subn,
                   tsetelementnode(right).left:=caddnode.create(subn,
                     ctypeconvnode.create_internal(tsetelementnode(right).left,sinttype),
                     ctypeconvnode.create_internal(tsetelementnode(right).left,sinttype),
                     cordconstnode.create(tsetdef(resultdef).setbase,sinttype,false));
                     cordconstnode.create(tsetdef(resultdef).setbase,sinttype,false));
 
 
-                  addstatement(newstatement,ccallnode.createintern('fpc_varset_create_element',
-                    ccallparanode.create(ctemprefnode.create(temp),
-                    ccallparanode.create(cordconstnode.create(resultdef.size,sinttype,false),
-                    ccallparanode.create(tsetelementnode(right).left,nil))))
-                  );
-
-                  { the last statement should return the value as
-                    location and type, this is done be referencing the
-                    temp and converting it first from a persistent temp to
-                    normal temp }
-                  addstatement(newstatement,ctempdeletenode.create_normal_temp(temp));
-                  addstatement(newstatement,ctemprefnode.create(temp));
-
-                  tsetelementnode(right).left := nil;
-                end
-              else
-                begin
-                  if right.nodetype=setelementn then
+                  if no_temp then
+                    begin
+                      result:=ccallnode.createintern('fpc_varset_create_element',
+                        ccallparanode.create(aktassignmentnode.left.getcopy,
+                        ccallparanode.create(cordconstnode.create(resultdef.size,sinttype,false),
+                        ccallparanode.create(tsetelementnode(right).left,nil))));
+                      include(aktassignmentnode.assignmentnodeflags,anf_assign_done_in_right);
+                    end
+                  else
                     begin
                     begin
                       result:=internalstatements(newstatement);
                       result:=internalstatements(newstatement);
 
 
@@ -3641,43 +3685,116 @@ implementation
                       temp:=ctempcreatenode.create(resultdef,resultdef.size,tt_persistent,true);
                       temp:=ctempcreatenode.create(resultdef,resultdef.size,tt_persistent,true);
                       addstatement(newstatement,temp);
                       addstatement(newstatement,temp);
 
 
-                      { adjust for set base }
-                      tsetelementnode(right).left:=caddnode.create(subn,
-                        ctypeconvnode.create_internal(tsetelementnode(right).left,sinttype),
-                        cordconstnode.create(tsetdef(resultdef).setbase,sinttype,false));
+                      addstatement(newstatement,ccallnode.createintern('fpc_varset_create_element',
+                        ccallparanode.create(ctemprefnode.create(temp),
+                        ccallparanode.create(cordconstnode.create(resultdef.size,sinttype,false),
+                        ccallparanode.create(tsetelementnode(right).left,nil))))
+                      );
 
 
-                      { add a range or a single element? }
-                      if assigned(tsetelementnode(right).right) then
+                      { the last statement should return the value as
+                        location and type, this is done be referencing the
+                        temp and converting it first from a persistent temp to
+                        normal temp }
+                      addstatement(newstatement,ctempdeletenode.create_normal_temp(temp));
+                      addstatement(newstatement,ctemprefnode.create(temp));
+                    end;
+                  tsetelementnode(right).left:=nil;
+                end
+              else
+                begin
+                  if right.nodetype=setelementn then
+                    begin
+                      if no_temp then
                         begin
                         begin
-                          { adjust for set base }
-                          tsetelementnode(right).right:=caddnode.create(subn,
-                            ctypeconvnode.create_internal(tsetelementnode(right).right,sinttype),
-                            cordconstnode.create(tsetdef(resultdef).setbase,sinttype,false));
-                          addstatement(newstatement,ccallnode.createintern('fpc_varset_set_range',
-                            ccallparanode.create(cordconstnode.create(resultdef.size,sinttype,false),
-                            ccallparanode.create(tsetelementnode(right).right,
-                            ccallparanode.create(tsetelementnode(right).left,
-                            ccallparanode.create(ctemprefnode.create(temp),
-                            ccallparanode.create(left,nil))))))
-                          );
+                          { add a range or a single element? }
+                          if assigned(tsetelementnode(right).right) then
+                            begin
+                              { adjust for set base }
+                              tsetelementnode(right).left:=caddnode.create(subn,
+                                ctypeconvnode.create_internal(tsetelementnode(right).left,sinttype),
+                                cordconstnode.create(tsetdef(resultdef).setbase,sinttype,false));
+
+                              { adjust for set base }
+                              tsetelementnode(right).right:=caddnode.create(subn,
+                                ctypeconvnode.create_internal(tsetelementnode(right).right,sinttype),
+                                cordconstnode.create(tsetdef(resultdef).setbase,sinttype,false));
+
+                              result:=ccallnode.createintern('fpc_varset_set_range',
+                                ccallparanode.create(cordconstnode.create(resultdef.size,sinttype,false),
+                                ccallparanode.create(tsetelementnode(right).right,
+                                ccallparanode.create(tsetelementnode(right).left,
+                                ccallparanode.create(aktassignmentnode.left.getcopy,
+                                ccallparanode.create(left,nil))))));
+                            end
+                          else
+                            begin
+                              { s:=s+[element]; ? }
+                              if left.isequal(aktassignmentnode.left) then
+                                result:=cinlinenode.createintern(in_include_x_y,false,ccallparanode.create(aktassignmentnode.left.getcopy,
+                                  ccallparanode.create(ctypeconvnode.create_internal(tsetelementnode(right).left,tsetdef(resultdef).elementdef),nil)))
+                              else
+                                begin
+                                  { adjust for set base }
+                                  tsetelementnode(right).left:=caddnode.create(subn,
+                                    ctypeconvnode.create_internal(tsetelementnode(right).left,sinttype),
+                                    cordconstnode.create(tsetdef(resultdef).setbase,sinttype,false));
+
+                                  result:=ccallnode.createintern('fpc_varset_set',
+                                    ccallparanode.create(cordconstnode.create(resultdef.size,sinttype,false),
+                                    ccallparanode.create(ctypeconvnode.create_internal(tsetelementnode(right).left,sinttype),
+                                    ccallparanode.create(aktassignmentnode.left.getcopy,
+                                    ccallparanode.create(left,nil)))));
+                                end;
+                            end;
+
+                          include(aktassignmentnode.assignmentnodeflags,anf_assign_done_in_right);
                         end
                         end
                       else
                       else
-                        addstatement(newstatement,ccallnode.createintern('fpc_varset_set',
-                          ccallparanode.create(cordconstnode.create(resultdef.size,sinttype,false),
-                          ccallparanode.create(ctypeconvnode.create_internal(tsetelementnode(right).left,sinttype),
-                          ccallparanode.create(ctemprefnode.create(temp),
-                          ccallparanode.create(left,nil)))))
-                        );
+                        begin
+                          { adjust for set base }
+                          tsetelementnode(right).left:=caddnode.create(subn,
+                            ctypeconvnode.create_internal(tsetelementnode(right).left,sinttype),
+                            cordconstnode.create(tsetdef(resultdef).setbase,sinttype,false));
+
+                          result:=internalstatements(newstatement);
+
+                          { create temp for result }
+                          temp:=ctempcreatenode.create(resultdef,resultdef.size,tt_persistent,true);
+                          addstatement(newstatement,temp);
+
+                          { add a range or a single element? }
+                          if assigned(tsetelementnode(right).right) then
+                            begin
+                              { adjust for set base }
+                              tsetelementnode(right).right:=caddnode.create(subn,
+                                ctypeconvnode.create_internal(tsetelementnode(right).right,sinttype),
+                                cordconstnode.create(tsetdef(resultdef).setbase,sinttype,false));
+                              addstatement(newstatement,ccallnode.createintern('fpc_varset_set_range',
+                                ccallparanode.create(cordconstnode.create(resultdef.size,sinttype,false),
+                                ccallparanode.create(tsetelementnode(right).right,
+                                ccallparanode.create(tsetelementnode(right).left,
+                                ccallparanode.create(ctemprefnode.create(temp),
+                                ccallparanode.create(left,nil))))))
+                              );
+                            end
+                          else
+                            addstatement(newstatement,ccallnode.createintern('fpc_varset_set',
+                              ccallparanode.create(cordconstnode.create(resultdef.size,sinttype,false),
+                              ccallparanode.create(ctypeconvnode.create_internal(tsetelementnode(right).left,sinttype),
+                              ccallparanode.create(ctemprefnode.create(temp),
+                              ccallparanode.create(left,nil)))))
+                            );
+                          { the last statement should return the value as
+                            location and type, this is done be referencing the
+                            temp and converting it first from a persistent temp to
+                            normal temp }
+                          addstatement(newstatement,ctempdeletenode.create_normal_temp(temp));
+                          addstatement(newstatement,ctemprefnode.create(temp));
+                        end;
                       { remove reused parts from original node }
                       { remove reused parts from original node }
                       tsetelementnode(right).right:=nil;
                       tsetelementnode(right).right:=nil;
                       tsetelementnode(right).left:=nil;
                       tsetelementnode(right).left:=nil;
                       left:=nil;
                       left:=nil;
-                      { the last statement should return the value as
-                        location and type, this is done be referencing the
-                        temp and converting it first from a persistent temp to
-                        normal temp }
-                      addstatement(newstatement,ctempdeletenode.create_normal_temp(temp));
-                      addstatement(newstatement,ctemprefnode.create(temp));
                     end
                     end
                   else
                   else
                     call_varset_helper('fpc_varset_add_sets');
                     call_varset_helper('fpc_varset_add_sets');
@@ -3742,7 +3859,7 @@ implementation
                             'fpc_dynarray_concat',
                             'fpc_dynarray_concat',
                             para
                             para
                           );
                           );
-                  include(aktassignmentnode.flags,nf_assign_done_in_right);
+                  include(aktassignmentnode.assignmentnodeflags,anf_assign_done_in_right);
                   firstpass(result);
                   firstpass(result);
                 end
                 end
               else
               else
@@ -4272,9 +4389,6 @@ implementation
         end;
         end;
 
 
       var
       var
-{$ifdef addstringopt}
-         hp      : tnode;
-{$endif addstringopt}
          rd,ld   : tdef;
          rd,ld   : tdef;
          i,i2    : longint;
          i,i2    : longint;
          lt,rt   : tnodetype;
          lt,rt   : tnodetype;
@@ -4359,6 +4473,17 @@ implementation
                end;
                end;
            end;
            end;
 
 
+        { get rid of adding empty sets generated by set constructors (s+([]+[..]))
+
+          this needs to be done before firstpass, else the set additions get already converted into calls }
+        if (resultdef.typ=setdef) and (nodetype=addn) and (right.nodetype=addn) and (is_emptyset(taddnode(right).left)) then
+          begin
+            result:=caddnode.create(addn,left,taddnode(right).right);
+            left:=nil;
+            taddnode(right).right:=nil;
+            exit;
+          end;
+
          { first do the two subtrees }
          { first do the two subtrees }
          firstpass(left);
          firstpass(left);
          firstpass(right);
          firstpass(right);
@@ -4755,5 +4880,27 @@ implementation
         end;
         end;
     end;
     end;
 {$endif}
 {$endif}
+{$ifdef DEBUG_NODE_XML}
+    procedure TAddNode.XMLPrintNodeInfo(var T: Text);
+      var
+        i: TAddNodeFlag;
+        First: Boolean;
+      begin
+        inherited XMLPrintNodeInfo(T);
+        First := True;
+        for i in addnodeflags do
+          begin
+            if First then
+              begin
+                Write(T, ' addnodeflags="', i);
+                First := False;
+              end
+            else
+              Write(T, ',', i)
+          end;
+        if not First then
+          Write(T, '"');
+      end;
+{$endif DEBUG_NODE_XML}
 
 
 end.
 end.

+ 47 - 13
compiler/nbas.pas

@@ -71,11 +71,18 @@ interface
        end;
        end;
        tfinalizetempsnodeclass = class of tfinalizetempsnode;
        tfinalizetempsnodeclass = class of tfinalizetempsnode;
 
 
+       TAsmNodeFlag = (
+         asmnf_get_asm_position,
+         { Used registers in assembler block }
+         asmnf_has_registerlist
+       );
+
+       TAsmNodeFlags = set of TAsmNodeFlag;
+
        tasmnode = class(tnode)
        tasmnode = class(tnode)
+          asmnodeflags : TAsmNodeFlags;
           p_asm : TAsmList;
           p_asm : TAsmList;
           currenttai : tai;
           currenttai : tai;
-          { Used registers in assembler block }
-          has_registerlist : boolean;
           constructor create(p : TAsmList);virtual;
           constructor create(p : TAsmList);virtual;
           constructor create_get_position;
           constructor create_get_position;
           destructor destroy;override;
           destructor destroy;override;
@@ -88,6 +95,7 @@ interface
           function pass_typecheck:tnode;override;
           function pass_typecheck:tnode;override;
           function docompare(p: tnode): boolean; override;
           function docompare(p: tnode): boolean; override;
 {$ifdef DEBUG_NODE_XML}
 {$ifdef DEBUG_NODE_XML}
+          procedure XMLPrintNodeInfo(var T: Text); override;
           procedure XMLPrintNodeData(var T: Text); override;
           procedure XMLPrintNodeData(var T: Text); override;
 {$endif DEBUG_NODE_XML}
 {$endif DEBUG_NODE_XML}
        end;
        end;
@@ -463,7 +471,7 @@ implementation
     function terrornode.pass_typecheck:tnode;
     function terrornode.pass_typecheck:tnode;
       begin
       begin
          result:=nil;
          result:=nil;
-         include(flags,nf_error);
+         include(transientflags,tnf_error);
          codegenerror:=true;
          codegenerror:=true;
          resultdef:=generrordef;
          resultdef:=generrordef;
       end;
       end;
@@ -864,6 +872,7 @@ implementation
       begin
       begin
         inherited create(asmn);
         inherited create(asmn);
         p_asm:=p;
         p_asm:=p;
+        asmnodeflags:=[];
         currenttai:=nil;
         currenttai:=nil;
       end;
       end;
 
 
@@ -872,7 +881,7 @@ implementation
       begin
       begin
         inherited create(asmn);
         inherited create(asmn);
         p_asm:=nil;
         p_asm:=nil;
-        include(flags,nf_get_asm_position);
+        asmnodeflags:=[asmnf_get_asm_position];
         currenttai:=nil;
         currenttai:=nil;
       end;
       end;
 
 
@@ -880,7 +889,7 @@ implementation
     destructor tasmnode.destroy;
     destructor tasmnode.destroy;
       begin
       begin
         if assigned(p_asm) then
         if assigned(p_asm) then
-         p_asm.free;
+          p_asm.free;
         inherited destroy;
         inherited destroy;
       end;
       end;
 
 
@@ -890,7 +899,8 @@ implementation
         hp : tai;
         hp : tai;
       begin
       begin
         inherited ppuload(t,ppufile);
         inherited ppuload(t,ppufile);
-        if not(nf_get_asm_position in flags) then
+        ppufile.getset(tppuset1(asmnodeflags));
+        if not(asmnf_get_asm_position in asmnodeflags) then
           begin
           begin
             p_asm:=TAsmList.create;
             p_asm:=TAsmList.create;
             repeat
             repeat
@@ -913,8 +923,9 @@ implementation
         hp : tai;
         hp : tai;
       begin
       begin
         inherited ppuwrite(ppufile);
         inherited ppuwrite(ppufile);
+        ppufile.putset(tppuset1(asmnodeflags));
 { TODO: FIXME Add saving of register sets}
 { TODO: FIXME Add saving of register sets}
-        if not(nf_get_asm_position in flags) then
+        if not(asmnf_get_asm_position in asmnodeflags) then
           begin
           begin
             hp:=tai(p_asm.first);
             hp:=tai(p_asm.first);
             while assigned(hp) do
             while assigned(hp) do
@@ -933,7 +944,7 @@ implementation
         hp : tai;
         hp : tai;
       begin
       begin
         inherited buildderefimpl;
         inherited buildderefimpl;
-        if not(nf_get_asm_position in flags) then
+        if not(asmnf_get_asm_position in asmnodeflags) then
           begin
           begin
             hp:=tai(p_asm.first);
             hp:=tai(p_asm.first);
             while assigned(hp) do
             while assigned(hp) do
@@ -950,7 +961,7 @@ implementation
         hp : tai;
         hp : tai;
       begin
       begin
         inherited derefimpl;
         inherited derefimpl;
-        if not(nf_get_asm_position in flags) then
+        if not(asmnf_get_asm_position in asmnodeflags) then
           begin
           begin
             hp:=tai(p_asm.first);
             hp:=tai(p_asm.first);
             while assigned(hp) do
             while assigned(hp) do
@@ -966,15 +977,16 @@ implementation
       var
       var
         n: tasmnode;
         n: tasmnode;
       begin
       begin
-        n := tasmnode(inherited dogetcopy);
+        n:=tasmnode(inherited dogetcopy);
+        n.asmnodeflags:=asmnodeflags;
         if assigned(p_asm) then
         if assigned(p_asm) then
           begin
           begin
             n.p_asm:=TAsmList.create;
             n.p_asm:=TAsmList.create;
             n.p_asm.concatlistcopy(p_asm);
             n.p_asm.concatlistcopy(p_asm);
           end
           end
-        else n.p_asm := nil;
+        else
+          n.p_asm:=nil;
         n.currenttai:=currenttai;
         n.currenttai:=currenttai;
-        n.has_registerlist:=has_registerlist;
         result:=n;
         result:=n;
       end;
       end;
 
 
@@ -983,7 +995,7 @@ implementation
       begin
       begin
         result:=nil;
         result:=nil;
         resultdef:=voidtype;
         resultdef:=voidtype;
-        if not(nf_get_asm_position in flags) then
+        if not(asmnf_get_asm_position in asmnodeflags) then
           include(current_procinfo.flags,pi_has_assembler_block);
           include(current_procinfo.flags,pi_has_assembler_block);
       end;
       end;
 
 
@@ -1002,6 +1014,28 @@ implementation
       end;
       end;
 
 
 {$ifdef DEBUG_NODE_XML}
 {$ifdef DEBUG_NODE_XML}
+    procedure TAsmNode.XMLPrintNodeInfo(var T: Text);
+      var
+        i: TAsmNodeFlag;
+        First: Boolean;
+      begin
+        inherited XMLPrintNodeInfo(T);
+        First := True;
+        for i in asmnodeflags do
+          begin
+            if First then
+              begin
+                Write(T, ' asmnodeflags="', i);
+                First := False;
+              end
+            else
+              Write(T, ',', i)
+          end;
+        if not First then
+          Write(T, '"');
+      end;
+
+
     procedure TAsmNode.XMLPrintNodeData(var T: Text);
     procedure TAsmNode.XMLPrintNodeData(var T: Text);
 
 
       procedure PadString(var S: string; Len: Integer);
       procedure PadString(var S: string; Len: Integer);

+ 5 - 5
compiler/ncal.pas

@@ -1224,11 +1224,11 @@ implementation
                     if is_array_of_const(parasym.vardef) then
                     if is_array_of_const(parasym.vardef) then
                      begin
                      begin
                        { force variant array }
                        { force variant array }
-                       include(left.flags,nf_forcevaria);
+                       include(tarrayconstructornode(left).arrayconstructornodeflags,acnf_forcevaria);
                      end
                      end
                     else
                     else
                      begin
                      begin
-                       include(left.flags,nf_novariaallowed);
+                       include(tarrayconstructornode(left).arrayconstructornodeflags,acnf_novariaallowed);
                        { now that the resultting type is know we can insert the required
                        { now that the resultting type is know we can insert the required
                          typeconvs for the array constructor }
                          typeconvs for the array constructor }
                        if parasym.vardef.typ=arraydef then
                        if parasym.vardef.typ=arraydef then
@@ -3466,7 +3466,7 @@ implementation
                 funcretnode:=aktassignmentnode.left.getcopy;
                 funcretnode:=aktassignmentnode.left.getcopy;
                 include(funcretnode.flags,nf_is_funcret);
                 include(funcretnode.flags,nf_is_funcret);
                 { notify the assignment node that the assignment can be removed }
                 { notify the assignment node that the assignment can be removed }
-                include(aktassignmentnode.flags,nf_assign_done_in_right);
+                include(aktassignmentnode.assignmentnodeflags,anf_assign_done_in_right);
               end
               end
             else
             else
               begin
               begin
@@ -5511,7 +5511,7 @@ implementation
                 if FindUnitSymtable(tloadnode(n).symtable).moduleid<>current_module.moduleid then
                 if FindUnitSymtable(tloadnode(n).symtable).moduleid<>current_module.moduleid then
                   current_module.addimportedsym(sym);
                   current_module.addimportedsym(sym);
               end
               end
-            else if (sym.typ=constsym) and (tconstsym(sym).consttyp=constresourcestring) then
+            else if (sym.typ=constsym) and (tconstsym(sym).consttyp in [constwresourcestring,constresourcestring]) then
               begin
               begin
                 if tloadnode(n).symtableentry.owner.moduleid<>current_module.moduleid then
                 if tloadnode(n).symtableentry.owner.moduleid<>current_module.moduleid then
                   current_module.addimportedsym(sym);
                   current_module.addimportedsym(sym);
@@ -5602,7 +5602,7 @@ implementation
 
 
         typecheckpass(tnode(inlineblock));
         typecheckpass(tnode(inlineblock));
         doinlinesimplify(tnode(inlineblock));
         doinlinesimplify(tnode(inlineblock));
-        node_reset_flags(tnode(inlineblock),[nf_pass1_done]);
+        node_reset_flags(tnode(inlineblock),[],[tnf_pass1_done]);
         firstpass(tnode(inlineblock));
         firstpass(tnode(inlineblock));
         result:=inlineblock;
         result:=inlineblock;
 
 

+ 1 - 1
compiler/ncgadd.pas

@@ -388,7 +388,7 @@ interface
           needed nodes unless full boolean evaluation is enabled }
           needed nodes unless full boolean evaluation is enabled }
         if (nodetype in [orn,andn]) and
         if (nodetype in [orn,andn]) and
            (not(cs_full_boolean_eval in current_settings.localswitches) or
            (not(cs_full_boolean_eval in current_settings.localswitches) or
-            (nf_short_bool in flags)) then
+            (anf_short_bool in addnodeflags)) then
           begin
           begin
             case nodetype of
             case nodetype of
               andn :
               andn :

+ 4 - 4
compiler/ncgbas.pas

@@ -288,7 +288,7 @@ interface
       begin
       begin
          location_reset(location,LOC_VOID,OS_NO);
          location_reset(location,LOC_VOID,OS_NO);
 
 
-         if (nf_get_asm_position in flags) then
+         if (asmnf_get_asm_position in asmnodeflags) then
            begin
            begin
              { Add a marker, to be sure the list is not empty }
              { Add a marker, to be sure the list is not empty }
              current_asmdata.CurrAsmList.concat(tai_marker.create(mark_Position));
              current_asmdata.CurrAsmList.concat(tai_marker.create(mark_Position));
@@ -299,8 +299,8 @@ interface
          current_asmdata.CurrAsmList.Concat(tai_directive.create(asd_cpu,cputypestr[current_settings.asmcputype]));
          current_asmdata.CurrAsmList.Concat(tai_directive.create(asd_cpu,cputypestr[current_settings.asmcputype]));
 
 
          { Allocate registers used in the assembler block }
          { Allocate registers used in the assembler block }
-         { has_registerlist=true means that registers are specified and already allocated }
-         if (not has_registerlist) then
+         { asmnf_has_registerlist means that registers are specified and already allocated }
+         if not (asmnf_has_registerlist in asmnodeflags) then
            cg.allocallcpuregisters(current_asmdata.CurrAsmList);
            cg.allocallcpuregisters(current_asmdata.CurrAsmList);
 
 
          if (po_inline in current_procinfo.procdef.procoptions) then
          if (po_inline in current_procinfo.procdef.procoptions) then
@@ -431,7 +431,7 @@ interface
            end;
            end;
 
 
          { Release register used in the assembler block }
          { Release register used in the assembler block }
-         if (not has_registerlist) then
+         if not (asmnf_has_registerlist in asmnodeflags) then
            cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
            cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
 
 
          { Switch back to the CPU instruction set of the target CPU }
          { Switch back to the CPU instruction set of the target CPU }

+ 4 - 0
compiler/ncginl.pas

@@ -221,6 +221,10 @@ implementation
             in_max_dword,
             in_max_dword,
             in_min_longint,
             in_min_longint,
             in_min_dword,
             in_min_dword,
+            in_min_int64,
+            in_min_qword,
+            in_max_int64,
+            in_max_qword,
             in_min_single,
             in_min_single,
             in_min_double,
             in_min_double,
             in_max_single,
             in_max_single,

+ 3 - 3
compiler/ncgld.pas

@@ -441,7 +441,7 @@ implementation
               end;
               end;
            constsym:
            constsym:
              begin
              begin
-                if tconstsym(symtableentry).consttyp=constresourcestring then
+                if tconstsym(symtableentry).consttyp in [constresourcestring,constwresourcestring] then
                   begin
                   begin
                      location_reset_ref(location,LOC_CREFERENCE,def_cgsize(cansistringtype),cansistringtype.size,[]);
                      location_reset_ref(location,LOC_CREFERENCE,def_cgsize(cansistringtype),cansistringtype.size,[]);
                      indirect:=(tf_supports_packages in target_info.flags) and
                      indirect:=(tf_supports_packages in target_info.flags) and
@@ -807,7 +807,7 @@ implementation
                (right.nodetype in [blockn,calln]) then
                (right.nodetype in [blockn,calln]) then
               begin
               begin
                 { verify that we indeed have nothing to do }
                 { verify that we indeed have nothing to do }
-                if not(nf_assign_done_in_right in flags) then
+                if not(anf_assign_done_in_right in assignmentnodeflags) then
                   internalerror(2015042201);
                   internalerror(2015042201);
               end
               end
             { empty constant string }
             { empty constant string }
@@ -1289,7 +1289,7 @@ implementation
         if is_packed_array(resultdef) then
         if is_packed_array(resultdef) then
           internalerror(200608042);
           internalerror(200608042);
         dovariant:=
         dovariant:=
-          ((nf_forcevaria in flags) or is_variant_array(resultdef)) and
+          ((acnf_forcevaria in arrayconstructornodeflags) or is_variant_array(resultdef)) and
           not(target_info.system in systems_managed_vm);
           not(target_info.system in systems_managed_vm);
         eledef:=tarraydef(resultdef).elementdef;
         eledef:=tarraydef(resultdef).elementdef;
         elesize:=eledef.size;
         elesize:=eledef.size;

+ 3 - 3
compiler/ncgmem.pas

@@ -298,7 +298,7 @@ implementation
             (cs_checkpointer in current_settings.localswitches) and
             (cs_checkpointer in current_settings.localswitches) and
             not(cs_compilesystem in current_settings.moduleswitches) and
             not(cs_compilesystem in current_settings.moduleswitches) and
             tpointerdef(left.resultdef).compatible_with_pointerdef_size(tpointerdef(voidpointertype)) and
             tpointerdef(left.resultdef).compatible_with_pointerdef_size(tpointerdef(voidpointertype)) and
-            not(nf_no_checkpointer in flags) and
+            not(drnf_no_checkpointer in derefnodeflags) and
             { can be NR_NO in case of LOC_CONSTANT }
             { can be NR_NO in case of LOC_CONSTANT }
             (location.reference.base<>NR_NO) then
             (location.reference.base<>NR_NO) then
           begin
           begin
@@ -610,7 +610,7 @@ implementation
 
 
      function tcgvecnode.get_mul_size : asizeint;
      function tcgvecnode.get_mul_size : asizeint;
        begin
        begin
-         if nf_memindex in flags then
+         if vnf_memindex in vecnodeflags then
           get_mul_size:=1
           get_mul_size:=1
          else
          else
           begin
           begin
@@ -892,7 +892,7 @@ implementation
          if is_ansistring(left.resultdef) or
          if is_ansistring(left.resultdef) or
             is_wide_or_unicode_string(left.resultdef) then
             is_wide_or_unicode_string(left.resultdef) then
            begin
            begin
-              if nf_callunique in flags then
+              if vnf_callunique in vecnodeflags then
                 internalerror(200304236);
                 internalerror(200304236);
 
 
               {DM!!!!!}
               {DM!!!!!}

+ 25 - 13
compiler/ncgrtti.pas

@@ -323,6 +323,10 @@ implementation
                             maybe_add_comment(tcb,#9'VMT index');
                             maybe_add_comment(tcb,#9'VMT index');
                             tcb.emit_ord_const(def.extnumber,u16inttype);
                             tcb.emit_ord_const(def.extnumber,u16inttype);
                           end;
                           end;
+                        maybe_add_comment(tcb,#9'Code Address');
+                        tcb.emit_procdef_const(def);
+                        maybe_add_comment(tcb,#9'Attribute table');
+                        write_attribute_data(tcb,def.rtti_attribute_list);
                       end;
                       end;
 
 
                     for k:=0 to def.paras.count-1 do
                     for k:=0 to def.paras.count-1 do
@@ -810,19 +814,20 @@ implementation
 
 
     procedure TRTTIWriter.write_extended_field_table(tcb:ttai_typedconstbuilder;def:tabstractrecorddef;packrecords:longint);
     procedure TRTTIWriter.write_extended_field_table(tcb:ttai_typedconstbuilder;def:tabstractrecorddef;packrecords:longint);
       var
       var
-        i: integer;
-        sym: tsym;
+        i,cnt: integer;
+        asym: tsym;
+        fldsym : tfieldvarsym;
         list: TFPList;
         list: TFPList;
       begin
       begin
         list:=TFPList.Create;
         list:=TFPList.Create;
         { build list of visible fields }
         { build list of visible fields }
         for i:=0 to def.symtable.symlist.Count-1 do
         for i:=0 to def.symtable.symlist.Count-1 do
           begin
           begin
-            sym:=tsym(def.symtable.symlist[i]);
-            if (sym.typ=fieldvarsym) and
-               not(sp_static in sym.symoptions) and
-               def.is_visible_for_rtti(ro_fields, sym.visibility) then
-              list.add(sym);
+            asym:=tsym(def.symtable.symlist[i]);
+            if (asym.typ=fieldvarsym) and
+               not(sp_static in asym.symoptions) and
+               def.is_visible_for_rtti(ro_fields, asym.visibility) then
+              list.add(asym);
           end;
           end;
         {
         {
           TExtendedFieldTable = record
           TExtendedFieldTable = record
@@ -834,24 +839,31 @@ implementation
         tcb.emit_ord_const(list.count,u16inttype);
         tcb.emit_ord_const(list.count,u16inttype);
         for i := 0 to list.count-1 do
         for i := 0 to list.count-1 do
           begin
           begin
-            sym:=tsym(list[i]);
+            fldsym:=tfieldvarsym(list[i]);
             {
             {
               TExtendedFieldInfo = record
               TExtendedFieldInfo = record
                 FieldOffset: SizeUInt;
                 FieldOffset: SizeUInt;
                 FieldType: Pointer;
                 FieldType: Pointer;
                 FieldVisibility: Byte;
                 FieldVisibility: Byte;
                 Name: PShortString;
                 Name: PShortString;
+                Attributes :
               end;
               end;
             }
             }
-            tcb.begin_anonymous_record(internaltypeprefixName[itp_extended_rtti_field]+tostr(tfieldvarsym(sym).fieldoffset),packrecords,min(reqalign,SizeOf(PInt)),targetinfos[target_info.system]^.alignment.recordalignmin);
+            tcb.begin_anonymous_record(internaltypeprefixName[itp_extended_rtti_field]+tostr(fldsym.fieldoffset),packrecords,min(reqalign,SizeOf(PInt)),targetinfos[target_info.system]^.alignment.recordalignmin);
             { FieldOffset }
             { FieldOffset }
-            tcb.emit_tai(Tai_const.Create_sizeint(tfieldvarsym(sym).fieldoffset),sizeuinttype);
+            tcb.emit_tai(Tai_const.Create_sizeint(fldsym.fieldoffset),sizeuinttype);
             { FieldType: PPTypeInfo }
             { FieldType: PPTypeInfo }
-            tcb.emit_tai(Tai_const.Create_sym(RTTIWriter.get_rtti_label(tfieldvarsym(sym).vardef,fullrtti,true)),voidpointertype);
+            tcb.emit_tai(Tai_const.Create_sym(RTTIWriter.get_rtti_label(fldsym.vardef,fullrtti,true)),voidpointertype);
             { FieldVisibility }
             { FieldVisibility }
-            tcb.emit_ord_const(visibility_to_rtti_flags(tfieldvarsym(sym).visibility),u8inttype);
+            tcb.emit_ord_const(visibility_to_rtti_flags(fldsym.visibility),u8inttype);
             { Name }
             { Name }
-            tcb.emit_pooled_shortstring_const_ref(sym.realname);
+            tcb.emit_pooled_shortstring_const_ref(fldsym.realname);
+            { Attribute table }
+            if assigned(fldsym.rtti_attribute_list) and assigned(fldsym.rtti_attribute_list.rtti_attributes) then
+              cnt:=fldsym.rtti_attribute_list.rtti_attributes.count
+            else
+              cnt:=0;
+            write_attribute_data(tcb,fldsym.rtti_attribute_list);
             tcb.end_anonymous_record;
             tcb.end_anonymous_record;
           end;
           end;
         tcb.end_anonymous_record;
         tcb.end_anonymous_record;

+ 1 - 1
compiler/ncgutil.pas

@@ -236,7 +236,7 @@ implementation
         storepos : tfileposinfo;
         storepos : tfileposinfo;
         tmpreg : tregister;
         tmpreg : tregister;
       begin
       begin
-         if nf_error in p.flags then
+         if tnf_error in p.transientflags then
            exit;
            exit;
          storepos:=current_filepos;
          storepos:=current_filepos;
          current_filepos:=p.fileinfo;
          current_filepos:=p.fileinfo;

+ 117 - 124
compiler/ncnv.pas

@@ -503,6 +503,7 @@ implementation
         lr,hr : TConstExprInt;
         lr,hr : TConstExprInt;
         hp : tarrayconstructornode;
         hp : tarrayconstructornode;
         oldfilepos: tfileposinfo;
         oldfilepos: tfileposinfo;
+        first: Boolean;
       begin
       begin
         { keep in sync with arrayconstructor_can_be_set }
         { keep in sync with arrayconstructor_can_be_set }
         if p.nodetype<>arrayconstructorn then
         if p.nodetype<>arrayconstructorn then
@@ -522,10 +523,11 @@ implementation
         hp:=tarrayconstructornode(p);
         hp:=tarrayconstructornode(p);
         if assigned(hp.left) then
         if assigned(hp.left) then
          begin
          begin
+           first:=true;
            while assigned(hp) do
            while assigned(hp) do
             begin
             begin
               p4:=nil; { will contain the tree to create the set }
               p4:=nil; { will contain the tree to create the set }
-            {split a range into p2 and p3 }
+              { split a range into p2 and p3 }
               if hp.left.nodetype=arrayconstructorrangen then
               if hp.left.nodetype=arrayconstructorrangen then
                begin
                begin
                  p2:=tarrayconstructorrangenode(hp.left).left;
                  p2:=tarrayconstructorrangenode(hp.left).left;
@@ -551,130 +553,120 @@ implementation
               oldfilepos:=current_filepos;
               oldfilepos:=current_filepos;
               current_filepos:=p2.fileinfo;
               current_filepos:=p2.fileinfo;
               case p2.resultdef.typ of
               case p2.resultdef.typ of
-                 enumdef,
-                 orddef:
-                   begin
-                      { widechars are not yet supported }
-                      if is_widechar(p2.resultdef) then
-                        begin
+                enumdef,
+                orddef:
+                  begin
+                    { widechars are not yet supported }
+                    if is_widechar(p2.resultdef) then
+                      begin
+                        if block_type<>bt_const then
+                          inserttypeconv(p2,cansichartype);
+                        if (p2.nodetype<>ordconstn) and not (m_default_unicodestring in current_settings.modeswitches) then
+                          incompatibletypes(cwidechartype,cansichartype);
+                      end;
 
 
-                          if block_type<>bt_const then
-                            inserttypeconv(p2,cansichartype);
-                          if (p2.nodetype<>ordconstn) and not (m_default_unicodestring in current_settings.modeswitches) then
-                            incompatibletypes(cwidechartype,cansichartype);
+                    getrange(p2.resultdef,lr,hr);
+                    if assigned(p3) then
+                     begin
+                       if is_widechar(p3.resultdef) then
+                         begin
+                           if block_type<>bt_const then
+                             inserttypeconv(p3,cansichartype);
+                           if (p3.nodetype<>ordconstn) and not (m_default_unicodestring in current_settings.modeswitches) then
+                             begin
+                               current_filepos:=p3.fileinfo;
+                               incompatibletypes(cwidechartype,cansichartype);
+                             end;
+                         end;
+                       { this isn't good, you'll get problems with
+                         type t010 = 0..10;
+                              ts = set of t010;
+                         var  s : ts;b : t010
+                         begin  s:=[1,2,b]; end.
+                       if is_integer(p3^.resultdef) then
+                        begin
+                          inserttypeconv(p3,u8bitdef);
                         end;
                         end;
+                       }
+                       if assigned(hdef) and not(equal_defs(hdef,p3.resultdef)) then
+                         begin
+                            CGMessagePos(p3.fileinfo,type_e_typeconflict_in_set);
+                         end
+                       else
+                         begin
+                           if (p2.nodetype=ordconstn) and (p3.nodetype=ordconstn) then
+                            begin
+                               if not(is_integer(p3.resultdef)) then
+                                 begin
+                                   if not(assigned(hdef)) and first then
+                                     hdef:=p3.resultdef;
+                                 end
+                               else
+                                 begin
+                                   inserttypeconv(p3,u8inttype);
+                                   inserttypeconv(p2,u8inttype);
+                                 end;
+
+                              if tordconstnode(p2).value.svalue>tordconstnode(p3).value.svalue then
+                                CGMessagePos(p2.fileinfo,type_w_empty_constant_range_set);
+                              for l:=tordconstnode(p2).value.svalue to tordconstnode(p3).value.svalue do
+                                do_set(l);
+                              p2.free;
+                              p3.free;
+                            end
+                           else
+                            begin
+                              update_constsethi(p2.resultdef,false);
+                              inserttypeconv(p2,hdef);
+
+                              update_constsethi(p3.resultdef,false);
+                              inserttypeconv(p3,hdef);
+
+                              if assigned(hdef) then
+                                inserttypeconv(p3,hdef)
+                              else if first then
+                                hdef:=p3.resultdef
+                              else
+                                inserttypeconv(p3,u8inttype);
+                              p4:=csetelementnode.create(p2,p3);
+                            end;
+                         end;
+                     end
+                    else
+                     begin
+                       { Single value }
+                       if p2.nodetype=ordconstn then
+                        begin
+                          if assigned(hdef) then
+                            inserttypeconv(p2,hdef)
+                          else if not(is_integer(p2.resultdef)) and first then
+                            hdef:=p2.resultdef
+                          else
+                            inserttypeconv(p2,u8inttype);
 
 
-                      getrange(p2.resultdef,lr,hr);
-                      if assigned(p3) then
-                       begin
-                         if is_widechar(p3.resultdef) then
-                           begin
-                             if block_type<>bt_const then
-                               inserttypeconv(p3,cansichartype);
-                             if (p3.nodetype<>ordconstn) and not (m_default_unicodestring in current_settings.modeswitches) then
-                               begin
-                                 current_filepos:=p3.fileinfo;
-                                 incompatibletypes(cwidechartype,cansichartype);
-                               end;
-                           end;
-                         { this isn't good, you'll get problems with
-                           type t010 = 0..10;
-                                ts = set of t010;
-                           var  s : ts;b : t010
-                           begin  s:=[1,2,b]; end.
-                         if is_integer(p3^.resultdef) then
-                          begin
-                            inserttypeconv(p3,u8bitdef);
-                          end;
-                         }
-                         if assigned(hdef) and not(equal_defs(hdef,p3.resultdef)) then
-                           begin
-                              CGMessagePos(p3.fileinfo,type_e_typeconflict_in_set);
-                           end
-                         else
-                           begin
-                             if (p2.nodetype=ordconstn) and (p3.nodetype=ordconstn) then
-                              begin
-                                 if not(is_integer(p3.resultdef)) then
-                                   hdef:=p3.resultdef
-                                 else
-                                   begin
-                                     inserttypeconv(p3,u8inttype);
-                                     inserttypeconv(p2,u8inttype);
-                                   end;
-
-                                if tordconstnode(p2).value.svalue>tordconstnode(p3).value.svalue then
-                                  CGMessagePos(p2.fileinfo,type_w_empty_constant_range_set);
-                                for l:=tordconstnode(p2).value.svalue to tordconstnode(p3).value.svalue do
-                                  do_set(l);
-                                p2.free;
-                                p3.free;
-                              end
-                             else
-                              begin
-                                update_constsethi(p2.resultdef,false);
-                                inserttypeconv(p2,hdef);
-
-                                update_constsethi(p3.resultdef,false);
-                                inserttypeconv(p3,hdef);
-
-                                if assigned(hdef) then
-                                  inserttypeconv(p3,hdef)
-                                else
-                                  inserttypeconv(p3,u8inttype);
-                                p4:=csetelementnode.create(p2,p3);
-                              end;
-                           end;
-                       end
-                      else
-                       begin
-                         { Single value }
-                         if p2.nodetype=ordconstn then
-                          begin
-                            if not(is_integer(p2.resultdef)) then
-                              update_constsethi(p2.resultdef,true);
-
-                            if assigned(hdef) then
-                              inserttypeconv(p2,hdef)
-                            else
-                              inserttypeconv(p2,u8inttype);
-
-                            do_set(tordconstnode(p2).value.svalue);
-                            p2.free;
-                          end
-                         else
-                          begin
-                            update_constsethi(p2.resultdef,false);
-
-                            if assigned(hdef) then
-                              inserttypeconv(p2,hdef)
-                            else
-                              inserttypeconv(p2,u8inttype);
+                          if not(is_integer(p2.resultdef)) then
+                            update_constsethi(p2.resultdef,true);
 
 
-                            p4:=csetelementnode.create(p2,nil);
-                          end;
-                       end;
-                    end;
+                          do_set(tordconstnode(p2).value.svalue);
+                          p2.free;
+                        end
+                       else
+                        begin
+                          update_constsethi(p2.resultdef,false);
 
 
-                  stringdef :
-                    begin
-                        if (p2.nodetype<>stringconstn) then
-                          Message(parser_e_illegal_expression)
-                        { if we've already set elements which are constants }
-                        { throw an error                                    }
-                        else if ((hdef=nil) and assigned(result)) or
-                          not(is_char(hdef)) then
-                          CGMessage(type_e_typeconflict_in_set)
-                        else
-                         for l:=1 to length(pshortstring(tstringconstnode(p2).value_str)^) do
-                          do_set(ord(pshortstring(tstringconstnode(p2).value_str)^[l]));
-                        if hdef=nil then
-                         hdef:=cansichartype;
-                        p2.free;
-                      end;
+                          if assigned(hdef) then
+                            inserttypeconv(p2,hdef)
+                          else if not(is_integer(p2.resultdef)) and first then
+                            hdef:=p2.resultdef
+                          else
+                            inserttypeconv(p2,u8inttype);
 
 
-                    else
-                      CGMessage(type_e_ordinal_expr_expected);
+                          p4:=csetelementnode.create(p2,nil);
+                        end;
+                     end;
+                  end;
+                else
+                  CGMessage(type_e_ordinal_expr_expected);
               end;
               end;
               { insert the set creation tree }
               { insert the set creation tree }
               if assigned(p4) then
               if assigned(p4) then
@@ -686,8 +678,9 @@ implementation
               if freep then
               if freep then
                 p2.free;
                 p2.free;
               current_filepos:=oldfilepos;
               current_filepos:=oldfilepos;
+              first:=false;
             end;
             end;
-           if (hdef=nil) then
+          if (hdef=nil) then
             hdef:=u8inttype;
             hdef:=u8inttype;
          end
          end
         else
         else
@@ -1842,12 +1835,12 @@ implementation
           CGMessage(type_e_no_addr_of_constant);
           CGMessage(type_e_no_addr_of_constant);
         { a dynamic array is a pointer to an array, so to convert it to }
         { a dynamic array is a pointer to an array, so to convert it to }
         { an open array, we have to dereference it (JM)                 }
         { an open array, we have to dereference it (JM)                 }
-        result := ctypeconvnode.create_internal(left,cpointerdef.getreusable(resultdef));
+        result:=ctypeconvnode.create_internal(left,cpointerdef.getreusable(resultdef));
         typecheckpass(result);
         typecheckpass(result);
         { left is reused }
         { left is reused }
-        left := nil;
-        result := cderefnode.create(result);
-        include(result.flags,nf_no_checkpointer);
+        left:=nil;
+        result:=cderefnode.create(result);
+        include(TDerefNode(result).derefnodeflags,drnf_no_checkpointer);
       end;
       end;
 
 
 
 

+ 1 - 1
compiler/ncon.pas

@@ -305,7 +305,7 @@ implementation
       begin
       begin
         is_constresourcestringnode:=(p.nodetype=loadn) and
         is_constresourcestringnode:=(p.nodetype=loadn) and
           (tloadnode(p).symtableentry.typ=constsym) and
           (tloadnode(p).symtableentry.typ=constsym) and
-          (tconstsym(tloadnode(p).symtableentry).consttyp=constresourcestring);
+          (tconstsym(tloadnode(p).symtableentry).consttyp in [constresourcestring,constwresourcestring]);
       end;
       end;
 
 
 
 

+ 21 - 8
compiler/nflw.pas

@@ -1621,10 +1621,15 @@ implementation
 {$if defined(i386) or defined(x86_64)}
 {$if defined(i386) or defined(x86_64)}
 {$ifdef i386}
 {$ifdef i386}
           (((current_settings.fputype>=fpu_sse) and is_single(tassignmentnode(thenstmnt).left.resultdef)) or
           (((current_settings.fputype>=fpu_sse) and is_single(tassignmentnode(thenstmnt).left.resultdef)) or
-           ((current_settings.fputype>=fpu_sse2) and is_double(tassignmentnode(thenstmnt).left.resultdef))
+           ((current_settings.fputype>=fpu_sse2) and is_double(tassignmentnode(thenstmnt).left.resultdef)) or
+           ((CPUX86_HAS_CMOV in cpu_capabilities[current_settings.cputype]) and is_32bitint(tassignmentnode(thenstmnt).left.resultdef))
           ) and
           ) and
 {$else i386}
 {$else i386}
-          (is_single(tassignmentnode(thenstmnt).left.resultdef) or is_double(tassignmentnode(thenstmnt).left.resultdef)) and
+          (is_single(tassignmentnode(thenstmnt).left.resultdef) or
+           is_double(tassignmentnode(thenstmnt).left.resultdef) or
+           is_32bitint(tassignmentnode(thenstmnt).left.resultdef) or
+           is_64bitint(tassignmentnode(thenstmnt).left.resultdef)
+          ) and
 {$endif i386}
 {$endif i386}
 {$endif defined(i386) or defined(x86_64)}
 {$endif defined(i386) or defined(x86_64)}
 {$if defined(xtensa)}
 {$if defined(xtensa)}
@@ -1632,7 +1637,7 @@ implementation
 {$endif defined(xtensa)}
 {$endif defined(xtensa)}
 {$if defined(aarch64)}
 {$if defined(aarch64)}
           (is_single(tassignmentnode(thenstmnt).left.resultdef) or is_double(tassignmentnode(thenstmnt).left.resultdef) or
           (is_single(tassignmentnode(thenstmnt).left.resultdef) or is_double(tassignmentnode(thenstmnt).left.resultdef) or
-           is_32bitint(tassignmentnode(thenstmnt).right.resultdef)) and
+           is_32bitint(tassignmentnode(thenstmnt).left.resultdef) or is_64bitint(tassignmentnode(thenstmnt).left.resultdef)) and
 {$endif defined(aarch64)}
 {$endif defined(aarch64)}
           (
           (
           { the right size of the assignment in the then clause must either }
           { the right size of the assignment in the then clause must either }
@@ -1679,7 +1684,11 @@ implementation
                 else if is_u32bitint(paratype) then
                 else if is_u32bitint(paratype) then
                   in_nr:=in_max_dword
                   in_nr:=in_max_dword
                 else if is_s32bitint(paratype) then
                 else if is_s32bitint(paratype) then
-                  in_nr:=in_max_longint;
+                  in_nr:=in_max_longint
+                else if is_u64bitint(paratype) then
+                  in_nr:=in_max_qword
+                else if is_s64bitint(paratype) then
+                  in_nr:=in_max_int64;
               end
               end
             else
             else
               begin
               begin
@@ -1690,7 +1699,11 @@ implementation
                 else if is_u32bitint(paratype) then
                 else if is_u32bitint(paratype) then
                   in_nr:=in_min_dword
                   in_nr:=in_min_dword
                 else if is_s32bitint(paratype) then
                 else if is_s32bitint(paratype) then
-                  in_nr:=in_min_longint;
+                  in_nr:=in_min_longint
+                else if is_u64bitint(paratype) then
+                  in_nr:=in_min_qword
+                else if is_s64bitint(paratype) then
+                  in_nr:=in_min_int64;
               end;
               end;
             { for inline nodes, the first parameter is the last one in the linked list
             { for inline nodes, the first parameter is the last one in the linked list
 
 
@@ -1860,7 +1873,7 @@ implementation
            (cs_opt_loopunroll in current_settings.optimizerswitches) and
            (cs_opt_loopunroll in current_settings.optimizerswitches) and
            assigned(t2) and
            assigned(t2) and
            { statements must be error free }
            { statements must be error free }
-           not(nf_error in t2.flags) then
+           not(tnf_error in t2.transientflags) then
            begin
            begin
              typecheckpass(t2);
              typecheckpass(t2);
              res:=t2.simplify(false);
              res:=t2.simplify(false);
@@ -1925,7 +1938,7 @@ implementation
         begin
         begin
           { get rid of nf_write etc. as the left node is now only read }
           { get rid of nf_write etc. as the left node is now only read }
           leftcopy:=left.getcopy;
           leftcopy:=left.getcopy;
-          node_reset_flags(leftcopy,[nf_pass1_done,nf_modify,nf_write]);
+          node_reset_flags(leftcopy,[nf_modify,nf_write],[tnf_pass1_done]);
 
 
           if fw then
           if fw then
             addstatement(s,
             addstatement(s,
@@ -2079,7 +2092,7 @@ implementation
 
 
         { get rid of nf_write etc. as the left node is now only read }
         { get rid of nf_write etc. as the left node is now only read }
         leftcopy:=left.getcopy;
         leftcopy:=left.getcopy;
-        node_reset_flags(leftcopy,[nf_pass1_done,nf_modify,nf_write]);
+        node_reset_flags(leftcopy,[nf_modify,nf_write],[tnf_pass1_done]);
 
 
         if needsifblock then
         if needsifblock then
           begin
           begin

+ 42 - 26
compiler/ngenutil.pas

@@ -113,14 +113,14 @@ interface
       class procedure insertbssdata(sym : tstaticvarsym); virtual;
       class procedure insertbssdata(sym : tstaticvarsym); virtual;
 
 
       class function create_main_procdef(const name: string; potype:tproctypeoption; ps: tprocsym):tdef; virtual;
       class function create_main_procdef(const name: string; potype:tproctypeoption; ps: tprocsym):tdef; virtual;
-      class procedure InsertInitFinalTable;
+      class procedure InsertInitFinalTable(main : tmodule);
      protected
      protected
       class procedure InsertRuntimeInits(const prefix:string;list:TLinkedList;unitflag:tmoduleflag); virtual;
       class procedure InsertRuntimeInits(const prefix:string;list:TLinkedList;unitflag:tmoduleflag); virtual;
       class procedure InsertRuntimeInitsTablesTable(const prefix,tablename:string;unitflag:tmoduleflag); virtual;
       class procedure InsertRuntimeInitsTablesTable(const prefix,tablename:string;unitflag:tmoduleflag); virtual;
 
 
-      class procedure insert_init_final_table(entries:tfplist); virtual;
+      class procedure insert_init_final_table(main: tmodule; entries:tfplist); virtual;
 
 
-      class function get_init_final_list: tfplist;
+      class function get_init_final_list(main : tmodule): tfplist;
       class procedure release_init_final_list(list:tfplist);
       class procedure release_init_final_list(list:tfplist);
      public
      public
       class procedure InsertThreadvarTablesTable; virtual;
       class procedure InsertThreadvarTablesTable; virtual;
@@ -1020,37 +1020,53 @@ implementation
     end;
     end;
 
 
 
 
-  class function tnodeutils.get_init_final_list:tfplist;
+  class function tnodeutils.get_init_final_list(main : tmodule):tfplist;
+
+    procedure addusedunits(m : tmodule);
+
     var
     var
       hp : tused_unit;
       hp : tused_unit;
       entry : pinitfinalentry;
       entry : pinitfinalentry;
     begin
     begin
-      result:=tfplist.create;
-      { Insert initialization/finalization of the used units }
-      hp:=tused_unit(usedunits.first);
+      hp:=tused_unit(m.used_units.first);
       while assigned(hp) do
       while assigned(hp) do
        begin
        begin
-         if (hp.u.moduleflags * [mf_init,mf_finalize])<>[] then
+         if (not hp.u.initfinalchecked) then
            begin
            begin
-             new(entry);
-             entry^.module:=hp.u;
-             entry^.initpd:=nil;
-             entry^.finipd:=nil;
-             if mf_init in hp.u.moduleflags then
-               entry^.initfunc:=make_mangledname('INIT$',hp.u.globalsymtable,'')
-             else
-               entry^.initfunc:='';
-             if mf_finalize in hp.u.moduleflags then
-               entry^.finifunc:=make_mangledname('FINALIZE$',hp.u.globalsymtable,'')
-             else
-               entry^.finifunc:='';
-             result.add(entry);
+           hp.u.initfinalchecked:=True;
+           addusedunits(hp.u);
+           if ((hp.u.moduleflags * [mf_init,mf_finalize])<>[]) then
+             begin
+               new(entry);
+               entry^.module:=hp.u;
+               entry^.initpd:=nil;
+               entry^.finipd:=nil;
+               if mf_init in hp.u.moduleflags then
+                 entry^.initfunc:=make_mangledname('INIT$',hp.u.globalsymtable,'')
+               else
+                 entry^.initfunc:='';
+               if mf_finalize in hp.u.moduleflags then
+                 entry^.finifunc:=make_mangledname('FINALIZE$',hp.u.globalsymtable,'')
+               else
+                 entry^.finifunc:='';
+               result.add(entry);
+             end;
            end;
            end;
          hp:=tused_unit(hp.next);
          hp:=tused_unit(hp.next);
        end;
        end;
 
 
+    end;
+
+    var
+      entry : pinitfinalentry;
+    begin
+      result:=tfplist.create;
+
+      { Insert initialization/finalization of the used units }
+      addusedunits(main);
+
       { Insert initialization/finalization of the program }
       { Insert initialization/finalization of the program }
-      if (current_module.moduleflags * [mf_init,mf_finalize])<>[] then
+      if (main.moduleflags * [mf_init,mf_finalize])<>[] then
         begin
         begin
           new(entry);
           new(entry);
           entry^.module:=current_module;
           entry^.module:=current_module;
@@ -1081,19 +1097,19 @@ implementation
     end;
     end;
 
 
 
 
-  class procedure tnodeutils.InsertInitFinalTable;
+  class procedure tnodeutils.InsertInitFinalTable(main : tmodule);
     var
     var
       entries : tfplist;
       entries : tfplist;
     begin
     begin
-      entries := get_init_final_list;
+      entries := get_init_final_list(main);
 
 
-      insert_init_final_table(entries);
+      insert_init_final_table(main,entries);
 
 
       release_init_final_list(entries);
       release_init_final_list(entries);
     end;
     end;
 
 
 
 
-  class procedure tnodeutils.insert_init_final_table(entries:tfplist);
+  class procedure tnodeutils.insert_init_final_table(main : tmodule; entries:tfplist);
     var
     var
       i : longint;
       i : longint;
       unitinits : ttai_typedconstbuilder;
       unitinits : ttai_typedconstbuilder;

+ 1 - 1
compiler/ngtcon.pas

@@ -1022,7 +1022,7 @@ function get_next_varsym(def: tabstractrecorddef; const SymList:TFPHashObjectLis
                     labelsym :
                     labelsym :
                       ftcb.queue_emit_label(tlabelsym(srsym));
                       ftcb.queue_emit_label(tlabelsym(srsym));
                     constsym :
                     constsym :
-                      if tconstsym(srsym).consttyp=constresourcestring then
+                      if tconstsym(srsym).consttyp in [constresourcestring,constwresourcestring] then
                         ftcb.queue_emit_const(tconstsym(srsym))
                         ftcb.queue_emit_const(tconstsym(srsym))
                       else
                       else
                         Message(type_e_constant_expr_expected);
                         Message(type_e_constant_expr_expected);

+ 332 - 9
compiler/ninl.pas

@@ -29,7 +29,14 @@ interface
        node,htypechk,symtype,compinnr;
        node,htypechk,symtype,compinnr;
 
 
     type
     type
+       TInlineNodeFlag = (
+         inf_inlineconst
+       );
+
+       TInlineNodeFlags = set of TInlineNodeFlag;
+
        tinlinenode = class(tunarynode)
        tinlinenode = class(tunarynode)
+          inlinenodeflags : TInlineNodeFlags;
           inlinenumber : tinlinenumber;
           inlinenumber : tinlinenumber;
           constructor create(number : tinlinenumber;is_const:boolean;l : tnode);virtual;
           constructor create(number : tinlinenumber;is_const:boolean;l : tnode);virtual;
           constructor createintern(number : tinlinenumber;is_const:boolean;l : tnode);virtual;
           constructor createintern(number : tinlinenumber;is_const:boolean;l : tnode);virtual;
@@ -137,7 +144,7 @@ implementation
       globtype,cutils,cclasses,fmodule,
       globtype,cutils,cclasses,fmodule,
       symconst,symdef,symsym,symcpu,symtable,paramgr,defcmp,defutil,symbase,
       symconst,symdef,symsym,symcpu,symtable,paramgr,defcmp,defutil,symbase,
       cpuinfo,cpubase,
       cpuinfo,cpubase,
-      pass_1,
+      pass_1,ppu,
       ncal,ncon,ncnv,nadd,nld,nbas,nflw,nmem,nmat,nutils,ngenutil,
       ncal,ncon,ncnv,nadd,nld,nbas,nflw,nmem,nmat,nutils,ngenutil,
       nobjc,objcdef,
       nobjc,objcdef,
       cgbase,procinfo;
       cgbase,procinfo;
@@ -153,11 +160,12 @@ implementation
 *****************************************************************************}
 *****************************************************************************}
 
 
     constructor tinlinenode.create(number : tinlinenumber;is_const:boolean;l : tnode);
     constructor tinlinenode.create(number : tinlinenumber;is_const:boolean;l : tnode);
-
       begin
       begin
          inherited create(inlinen,l);
          inherited create(inlinen,l);
          if is_const then
          if is_const then
-           include(flags,nf_inlineconst);
+           inlinenodeflags:=[inf_inlineconst]
+         else
+           inlinenodeflags:=[];
          inlinenumber:=number;
          inlinenumber:=number;
       end;
       end;
 
 
@@ -166,6 +174,7 @@ implementation
      l : tnode);
      l : tnode);
       begin
       begin
          create(number,is_const,l);
          create(number,is_const,l);
+         inlinenodeflags:=[];
          include(flags,nf_internal);
          include(flags,nf_internal);
       end;
       end;
 
 
@@ -173,6 +182,7 @@ implementation
     constructor tinlinenode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
     constructor tinlinenode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
       begin
       begin
         inherited ppuload(t,ppufile);
         inherited ppuload(t,ppufile);
+        ppufile.getset(tppuset1(inlinenodeflags));
         inlinenumber:=tinlinenumber(ppufile.getlongint);
         inlinenumber:=tinlinenumber(ppufile.getlongint);
       end;
       end;
 
 
@@ -180,6 +190,7 @@ implementation
     procedure tinlinenode.ppuwrite(ppufile:tcompilerppufile);
     procedure tinlinenode.ppuwrite(ppufile:tcompilerppufile);
       begin
       begin
         inherited ppuwrite(ppufile);
         inherited ppuwrite(ppufile);
+        ppufile.putset(tppuset1(inlinenodeflags));
         ppufile.putlongint(longint(inlinenumber));
         ppufile.putlongint(longint(inlinenumber));
       end;
       end;
 
 
@@ -189,6 +200,7 @@ implementation
          n : tinlinenode;
          n : tinlinenode;
       begin
       begin
          n:=tinlinenode(inherited dogetcopy);
          n:=tinlinenode(inherited dogetcopy);
+         n.inlinenodeflags:=inlinenodeflags;
          n.inlinenumber:=inlinenumber;
          n.inlinenumber:=inlinenumber;
          result:=n;
          result:=n;
       end;
       end;
@@ -202,8 +214,25 @@ implementation
 
 
 {$ifdef DEBUG_NODE_XML}
 {$ifdef DEBUG_NODE_XML}
     procedure TInlineNode.XMLPrintNodeInfo(var T: Text);
     procedure TInlineNode.XMLPrintNodeInfo(var T: Text);
+      var
+        i: TInlineNodeFlag;
+        First: Boolean;
       begin
       begin
-        inherited;
+        inherited XMLPrintNodeInfo(T);
+        First := True;
+        for i in inlinenodeflags do
+          begin
+            if First then
+              begin
+                Write(T, ' inlinenodeflags="', i);
+                First := False;
+              end
+            else
+              Write(T, ',', i)
+          end;
+        if not First then
+          Write(T, '"');
+
         Write(T, ' inlinenumber="', inlinenumber, '"');
         Write(T, ' inlinenumber="', inlinenumber, '"');
       end;
       end;
 {$endif DEBUG_NODE_XML}
 {$endif DEBUG_NODE_XML}
@@ -2330,15 +2359,34 @@ implementation
             end;
             end;
         end;
         end;
 
 
+      function is_minmax_deterministic(var node: tordconstnode; const DoMax: Boolean; out res: Boolean): Boolean;
+        begin
+          Result := False;
+          if not is_integer(resultdef) then
+            InternalError(2024031501);
+
+          if (node.value <= torddef(resultdef).low) then
+            begin
+              res := not DoMax;
+              Exit(True);
+            end
+          else if (node.value >= torddef(resultdef).high) then
+            begin
+              res := DoMax;
+              Exit(True);
+            end
+        end;
+
       var
       var
-        hp        : tnode;
+        hp,hp2    : tnode;
         vl,vl2    : TConstExprInt;
         vl,vl2    : TConstExprInt;
         vr        : bestreal;
         vr        : bestreal;
+        helperres : Boolean;
 
 
       begin { simplify }
       begin { simplify }
          result:=nil;
          result:=nil;
          { handle intern constant functions in separate case }
          { handle intern constant functions in separate case }
-         if nf_inlineconst in flags then
+         if inf_inlineconst in inlinenodeflags then
           begin
           begin
             { no parameters? }
             { no parameters? }
             if not assigned(left) then
             if not assigned(left) then
@@ -2862,6 +2910,262 @@ implementation
                       result:=cordconstnode.create(PopCnt(tordconstnode(left).value),resultdef,false);
                       result:=cordconstnode.create(PopCnt(tordconstnode(left).value),resultdef,false);
                     end;
                     end;
                 end;
                 end;
+              in_min_single,
+              in_min_double:
+                begin
+                  { Check to see if the result is deterministic }
+                  if left.nodetype=callparan then
+                    begin
+                      hp:=tcallparanode(tcallparanode(left).nextpara).paravalue;
+                      hp2:=tcallparanode(left).paravalue;
+
+                      if (hp.nodetype=realconstn) then
+                        begin
+                          if (trealconstnode(hp).value_real = MathQNaN.value) then
+                            { If one of the inputs is NaN, the second parameter
+                              is taken }
+                            result:=hp2.getcopy()
+                          else if (trealconstnode(hp).value_real = MathNegInf.value) then
+                            { Nothing is less than than -oo }
+                            result:=crealconstnode.create(MathNegInf.value,resultdef)
+                          else if (trealconstnode(hp).value_real = MathInf.value) then
+                            { Everything is less than +oo }
+                            result:=hp2.getcopy()
+                          else if (hp2.nodetype=realconstn) then
+                            begin
+                              { Both actual parameters are constants, so take
+                                the smaller of the two right now }
+                              if (trealconstnode(hp).value_real < trealconstnode(hp2).value_real) then
+                                result:=crealconstnode.create(trealconstnode(hp).value_real,resultdef)
+                              else
+                                result:=crealconstnode.create(trealconstnode(hp2).value_real,resultdef);
+                            end;
+                        end
+                      else if (hp2.nodetype=realconstn) then
+                        begin
+                          if (trealconstnode(hp2).value_real = MathQNaN.value) then
+                            { If one of the inputs is NaN, the second parameter
+                              is taken (even if it is NaN) }
+                            result:=crealconstnode.create(MathQNaN.value,resultdef)
+                          else if (trealconstnode(hp2).value_real = MathNegInf.value) then
+                            { Nothing is less than than -oo }
+                            result:=crealconstnode.create(MathNegInf.value,resultdef)
+                          else if (trealconstnode(hp2).value_real = MathInf.value) then
+                            { Everything is less than +oo }
+                            result:=hp.getcopy();
+                        end;
+                    end;
+                end;
+              in_max_single,
+              in_max_double:
+                begin
+                  { Check to see if the result is deterministic }
+                  if left.nodetype=callparan then
+                    begin
+                      hp:=tcallparanode(tcallparanode(left).nextpara).paravalue;
+                      hp2:=tcallparanode(left).paravalue;
+
+                      if (hp.nodetype=realconstn) then
+                        begin
+                          if (trealconstnode(hp).value_real = MathQNaN.value) then
+                            { If one of the inputs is NaN, the second parameter
+                              is taken }
+                            result:=hp2.getcopy()
+                          else if (trealconstnode(hp).value_real = MathNegInf.value) then
+                            { Everything is greater than than -oo }
+                            result:=hp2.getcopy()
+                          else if (trealconstnode(hp).value_real = MathInf.value) then
+                            { Nothing is greater than +oo }
+                            result:=crealconstnode.create(MathInf.value,resultdef)
+                          else if (hp2.nodetype=realconstn) then
+                            begin
+                              { Both actual parameters are constants, so take
+                                the larger of the two right now }
+                              if (trealconstnode(hp).value_real > trealconstnode(hp2).value_real) then
+                                result:=crealconstnode.create(trealconstnode(hp).value_real,resultdef)
+                              else
+                                result:=crealconstnode.create(trealconstnode(hp2).value_real,resultdef)
+                            end;
+                        end
+                      else if (hp2.nodetype=realconstn) then
+                        begin
+                          if (trealconstnode(hp2).value_real = MathQNaN.value) then
+                            { If one of the inputs is NaN, the second parameter
+                              is taken (even if it is NaN) }
+                            result:=crealconstnode.create(MathQNaN.value,resultdef)
+                          else if (trealconstnode(hp2).value_real = MathNegInf.value) then
+                            { Everything is greater than than -oo }
+                            result:=hp.getcopy()
+                          else if (trealconstnode(hp2).value_real = MathInf.value) then
+                            { Nothing is greater than +oo }
+                            result:=crealconstnode.create(MathInf.value,resultdef);
+                        end;
+                    end;
+                end;
+              in_min_longint,
+              in_min_int64:
+                begin
+                  if left.nodetype=callparan then
+                    begin
+                      { Check to see if the result is deterministic }
+                      hp:=tcallparanode(tcallparanode(left).nextpara).paravalue;
+                      hp2:=tcallparanode(left).paravalue;
+
+                      if (hp.nodetype=ordconstn) then
+                        begin
+                          if (hp2.nodetype=ordconstn) then
+                            begin
+                              { Both actual parameters are constants, so take
+                                the smaller of the two right now }
+                              if inlinenumber=in_min_longint then
+                                result:=cordconstnode.create(min(LongInt(tordconstnode(hp).value.svalue),LongInt(tordconstnode(hp2).value.svalue)),resultdef,false)
+                              else
+                                result:=cordconstnode.create(min(tordconstnode(hp).value,tordconstnode(hp2).value),resultdef,false);
+                            end;
+
+                          if is_minmax_deterministic(tordconstnode(hp), False, helperres) then
+                            begin
+                              if helperres then
+                                result:=cordconstnode.create(tordconstnode(hp).value,resultdef,false)
+                              else
+                                result:=hp2.getcopy();
+                            end;
+                        end
+                      else if (hp2.nodetype=ordconstn) then
+                        begin
+                          if is_minmax_deterministic(tordconstnode(hp2), False, helperres) then
+                            begin
+                              if helperres then
+                                result:=cordconstnode.create(tordconstnode(hp2).value,resultdef,false)
+                              else
+                                result:=hp.getcopy();
+                            end;
+                        end;
+                    end;
+                end;
+              in_max_longint,
+              in_max_int64:
+                begin
+                  if left.nodetype=callparan then
+                    begin
+                      { Check to see if the result is deterministic }
+                      hp:=tcallparanode(left).paravalue;
+                      hp2:=tcallparanode(tcallparanode(left).nextpara).paravalue;
+
+                      if (hp.nodetype=ordconstn) then
+                        begin
+                          if (hp2.nodetype=ordconstn) then
+                            begin
+                              { Both actual parameters are constants, so take
+                                the larger of the two right now }
+                              if inlinenumber=in_max_longint then
+                                result:=cordconstnode.create(max(LongInt(tordconstnode(hp).value.svalue),LongInt(tordconstnode(hp2).value.svalue)),resultdef,false)
+                              else
+                                result:=cordconstnode.create(max(tordconstnode(hp).value,tordconstnode(hp2).value),resultdef,false);
+                            end;
+
+                          if is_minmax_deterministic(tordconstnode(hp), True, helperres) then
+                            begin
+                              if helperres then
+                                result:=cordconstnode.create(tordconstnode(hp).value,resultdef,false)
+                              else
+                                result:=hp2.getcopy();
+                            end;
+                        end
+                      else if (hp2.nodetype=ordconstn) then
+                        begin
+                          if is_minmax_deterministic(tordconstnode(hp2), True, helperres) then
+                            begin
+                              if helperres then
+                                result:=cordconstnode.create(tordconstnode(hp2).value,resultdef,false)
+                              else
+                                result:=hp.getcopy();
+                            end;
+                        end;
+                    end;
+                end;
+              in_min_dword,
+              in_min_qword:
+                begin
+                  if left.nodetype=callparan then
+                    begin
+                      { Check to see if the result is deterministic }
+                      hp:=tcallparanode(tcallparanode(left).nextpara).paravalue;
+                      hp2:=tcallparanode(left).paravalue;
+
+                      if (hp.nodetype=ordconstn) then
+                        begin
+                          if (hp2.nodetype=ordconstn) then
+                            begin
+                              { Both actual parameters are constants, so take
+                                the smaller of the two right now }
+                              if inlinenumber=in_min_dword then
+                                result:=cordconstnode.create(min(DWord(tordconstnode(hp).value.uvalue),DWord(tordconstnode(hp2).value.uvalue)),resultdef,false)
+                              else
+                                result:=cordconstnode.create(min(tordconstnode(hp).value,tordconstnode(hp2).value),resultdef,false);
+                            end;
+
+                          if is_minmax_deterministic(tordconstnode(hp), False, helperres) then
+                            begin
+                              if helperres then
+                                result:=cordconstnode.create(tordconstnode(hp).value,resultdef,false)
+                              else
+                                result:=hp2.getcopy();
+                            end;
+                        end
+                      else if (hp2.nodetype=ordconstn) then
+                        begin
+                          if is_minmax_deterministic(tordconstnode(hp2), False, helperres) then
+                            begin
+                              if helperres then
+                                result:=cordconstnode.create(tordconstnode(hp2).value,resultdef,false)
+                              else
+                                result:=hp.getcopy();
+                            end;
+                        end;
+                    end;
+                end;
+              in_max_dword,
+              in_max_qword:
+                begin
+                  if left.nodetype=callparan then
+                    begin
+                      { Check to see if the result is deterministic }
+                      hp:=tcallparanode(left).paravalue;
+                      hp2:=tcallparanode(tcallparanode(left).nextpara).paravalue;
+
+                      if (hp.nodetype=ordconstn) then
+                        begin
+                          if (hp2.nodetype=ordconstn) then
+                            begin
+                              { Both actual parameters are constants, so take
+                                the larger of the two right now }
+                              if inlinenumber=in_max_dword then
+                                result:=cordconstnode.create(max(DWord(tordconstnode(hp).value.uvalue),DWord(tordconstnode(hp2).value.uvalue)),resultdef,false)
+                              else
+                                result:=cordconstnode.create(max(tordconstnode(hp).value,tordconstnode(hp2).value),resultdef,false);
+                            end;
+
+                          if is_minmax_deterministic(tordconstnode(hp), True, helperres) then
+                            begin
+                              if helperres then
+                                result:=cordconstnode.create(tordconstnode(hp).value,resultdef,false)
+                              else
+                                result:=hp2.getcopy();
+                            end;
+                        end
+                      else if (hp2.nodetype=ordconstn) then
+                        begin
+                          if is_minmax_deterministic(tordconstnode(hp2), True, helperres) then
+                            begin
+                              if helperres then
+                                result:=cordconstnode.create(tordconstnode(hp2).value,resultdef,false)
+                              else
+                                result:=hp.getcopy();
+                            end;
+                        end;
+                    end;
+                end;
               else
               else
                 ;
                 ;
             end;
             end;
@@ -3040,7 +3344,7 @@ implementation
               typecheckpass(left);
               typecheckpass(left);
           end;
           end;
 
 
-        if not(nf_inlineconst in flags) then
+        if not(inf_inlineconst in inlinenodeflags) then
           begin
           begin
             case inlinenumber of
             case inlinenumber of
               in_lo_long,
               in_lo_long,
@@ -3860,6 +4164,10 @@ implementation
               in_max_dword,
               in_max_dword,
               in_min_longint,
               in_min_longint,
               in_min_dword,
               in_min_dword,
+              in_max_int64,
+              in_max_qword,
+              in_min_int64,
+              in_min_qword,
               in_max_single,
               in_max_single,
               in_max_double,
               in_max_double,
               in_min_single,
               in_min_single,
@@ -3918,7 +4226,7 @@ implementation
            end;
            end;
 
 
          { intern const should already be handled }
          { intern const should already be handled }
-         if nf_inlineconst in flags then
+         if inf_inlineconst in inlinenodeflags then
           internalerror(200104044);
           internalerror(200104044);
          case inlinenumber of
          case inlinenumber of
           in_lo_qword,
           in_lo_qword,
@@ -4316,6 +4624,10 @@ implementation
          in_max_dword,
          in_max_dword,
          in_min_longint,
          in_min_longint,
          in_min_dword,
          in_min_dword,
+         in_max_int64,
+         in_max_qword,
+         in_min_int64,
+         in_min_qword,
          in_min_single,
          in_min_single,
          in_min_double,
          in_min_double,
          in_max_single,
          in_max_single,
@@ -4771,6 +5083,17 @@ implementation
         { first param must be a string or dynamic array ...}
         { first param must be a string or dynamic array ...}
         if isarray then
         if isarray then
          begin
          begin
+           { SetLength(Arr, 0), Arr := nil, Arr := [] }
+           if (dims=1) and is_constintvalue(tcallparanode(paras).left, 0) then
+             begin
+               ppn.left:=nil; { unlink destppn }
+               result:=ccallparanode.create(ctypeconvnode.create_internal(destppn,voidpointertype),nil);
+               result:=ccallnode.createintern('fpc_dynarray_clear',
+                 ccallparanode.create(caddrnode.create_internal(
+                   crttinode.create(tstoreddef(destppn.resultdef),initrtti,rdt_normal)),
+                 result));
+               exit;
+             end;
            { create statements with call initialize the arguments and
            { create statements with call initialize the arguments and
              call fpc_dynarr_setlength }
              call fpc_dynarr_setlength }
            newblock:=internalstatements(newstatement);
            newblock:=internalstatements(newstatement);
@@ -5436,7 +5759,7 @@ implementation
                      inserttypeconv_internal(n,voidpointertype);
                      inserttypeconv_internal(n,voidpointertype);
                      arrconstr:=carrayconstructornode.create(n,arrconstr);
                      arrconstr:=carrayconstructornode.create(n,arrconstr);
                    end;
                    end;
-                 arrconstr.allow_array_constructor:=true;
+                 Include(arrconstr.arrayconstructornodeflags,acnf_allow_array_constructor);
 
 
                  { based on the code from nopt.genmultistringadd() }
                  { based on the code from nopt.genmultistringadd() }
                  tempnode:=ctempcreatenode.create(arrn.resultdef,arrn.resultdef.size,tt_persistent,true);
                  tempnode:=ctempcreatenode.create(arrn.resultdef,arrn.resultdef.size,tt_persistent,true);

+ 101 - 11
compiler/nld.pas

@@ -85,10 +85,17 @@ interface
        { different assignment types }
        { different assignment types }
        tassigntype = (at_normal,at_plus,at_minus,at_star,at_slash);
        tassigntype = (at_normal,at_plus,at_minus,at_star,at_slash);
 
 
+       TAssignmentNodeFlag = (
+         anf_assign_done_in_right
+       );
+
+       TAssignmentNodeFlags = set of TAssignmentNodeFlag;
+
        tassignmentnode = class(tbinarynode)
        tassignmentnode = class(tbinarynode)
          protected
          protected
           function direct_shortstring_assignment: boolean; virtual;
           function direct_shortstring_assignment: boolean; virtual;
          public
          public
+          assignmentnodeflags : TAssignmentNodeFlags;
           assigntype : tassigntype;
           assigntype : tassigntype;
           constructor create(l,r : tnode);virtual;
           constructor create(l,r : tnode);virtual;
           { no checks for validity of assignment }
           { no checks for validity of assignment }
@@ -104,6 +111,7 @@ interface
        {$endif state_tracking}
        {$endif state_tracking}
           function docompare(p: tnode): boolean; override;
           function docompare(p: tnode): boolean; override;
 {$ifdef DEBUG_NODE_XML}
 {$ifdef DEBUG_NODE_XML}
+          procedure XMLPrintNodeInfo(var T: Text); override;
           procedure XMLPrintNodeData(var T: Text); override;
           procedure XMLPrintNodeData(var T: Text); override;
 {$endif DEBUG_NODE_XML}
 {$endif DEBUG_NODE_XML}
        end;
        end;
@@ -116,14 +124,24 @@ interface
        end;
        end;
        tarrayconstructorrangenodeclass = class of tarrayconstructorrangenode;
        tarrayconstructorrangenodeclass = class of tarrayconstructorrangenode;
 
 
+       TArrayConstructorNodeFlag = (
+         acnf_allow_array_constructor,
+         acnf_forcevaria,
+         acnf_novariaallowed
+       );
+
+       TArrayConstructorNodeFlags = set of TArrayConstructorNodeFlag;
+
        tarrayconstructornode = class(tbinarynode)
        tarrayconstructornode = class(tbinarynode)
-          allow_array_constructor : boolean;
+          arrayconstructornodeflags : TArrayConstructorNodeFlags;
          private
          private
           function has_range_node:boolean;
           function has_range_node:boolean;
          protected
          protected
-          procedure wrapmanagedvarrec(var n: tnode);virtual;abstract;
+          procedure wrapmanagedvarrec(var n : tnode);virtual;abstract;
          public
          public
           constructor create(l,r : tnode);virtual;
           constructor create(l,r : tnode);virtual;
+          constructor ppuload(t : tnodetype;ppufile : tcompilerppufile);override;
+          procedure ppuwrite(ppufile : tcompilerppufile);override;
           function dogetcopy : tnode;override;
           function dogetcopy : tnode;override;
           function pass_1 : tnode;override;
           function pass_1 : tnode;override;
           function pass_typecheck:tnode;override;
           function pass_typecheck:tnode;override;
@@ -131,6 +149,9 @@ interface
           procedure force_type(def:tdef);
           procedure force_type(def:tdef);
           procedure insert_typeconvs;
           procedure insert_typeconvs;
           function isempty : boolean;
           function isempty : boolean;
+{$ifdef DEBUG_NODE_XML}
+          procedure XMLPrintNodeInfo(var t : text);override;
+{$endif DEBUG_NODE_XML}
        end;
        end;
        tarrayconstructornodeclass = class of tarrayconstructornode;
        tarrayconstructornodeclass = class of tarrayconstructornode;
 
 
@@ -350,6 +371,8 @@ implementation
              begin
              begin
                if tconstsym(symtableentry).consttyp=constresourcestring then
                if tconstsym(symtableentry).consttyp=constresourcestring then
                  resultdef:=getansistringdef
                  resultdef:=getansistringdef
+               else if tconstsym(symtableentry).consttyp=constwresourcestring then
+                 resultdef:=cunicodestringtype
                else
                else
                  internalerror(22799);
                  internalerror(22799);
              end;
              end;
@@ -481,7 +504,7 @@ implementation
               ;
               ;
             constsym:
             constsym:
               begin
               begin
-                if tconstsym(symtableentry).consttyp=constresourcestring then
+                if tconstsym(symtableentry).consttyp in [constresourcestring,constwresourcestring] then
                   expectloc:=LOC_CREFERENCE;
                   expectloc:=LOC_CREFERENCE;
               end;
               end;
             staticvarsym,
             staticvarsym,
@@ -614,6 +637,7 @@ implementation
 
 
       begin
       begin
          inherited create(assignn,l,r);
          inherited create(assignn,l,r);
+         assignmentnodeflags:=[];
          assigntype:=at_normal;
          assigntype:=at_normal;
          if r.nodetype = typeconvn then
          if r.nodetype = typeconvn then
            ttypeconvnode(r).warn_pointer_to_signed:=false;
            ttypeconvnode(r).warn_pointer_to_signed:=false;
@@ -630,6 +654,7 @@ implementation
     constructor tassignmentnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
     constructor tassignmentnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
       begin
       begin
         inherited ppuload(t,ppufile);
         inherited ppuload(t,ppufile);
+        ppufile.getset(tppuset1(assignmentnodeflags));
         assigntype:=tassigntype(ppufile.getbyte);
         assigntype:=tassigntype(ppufile.getbyte);
       end;
       end;
 
 
@@ -637,6 +662,7 @@ implementation
     procedure tassignmentnode.ppuwrite(ppufile:tcompilerppufile);
     procedure tassignmentnode.ppuwrite(ppufile:tcompilerppufile);
       begin
       begin
         inherited ppuwrite(ppufile);
         inherited ppuwrite(ppufile);
+        ppufile.putset(tppuset1(assignmentnodeflags));
         ppufile.putbyte(byte(assigntype));
         ppufile.putbyte(byte(assigntype));
       end;
       end;
 
 
@@ -648,6 +674,7 @@ implementation
 
 
       begin
       begin
          n:=tassignmentnode(inherited dogetcopy);
          n:=tassignmentnode(inherited dogetcopy);
+         n.assignmentnodeflags:=assignmentnodeflags;
          n.assigntype:=assigntype;
          n.assigntype:=assigntype;
          result:=n;
          result:=n;
       end;
       end;
@@ -705,7 +732,7 @@ implementation
           exit;
           exit;
 
 
         { just in case the typecheckpass of right optimized something here }
         { just in case the typecheckpass of right optimized something here }
-        if nf_assign_done_in_right in flags then
+        if anf_assign_done_in_right in assignmentnodeflags then
           begin
           begin
             result:=right;
             result:=right;
             right:=nil;
             right:=nil;
@@ -720,7 +747,11 @@ implementation
 
 
         { assignments to formaldefs and open arrays aren't allowed }
         { assignments to formaldefs and open arrays aren't allowed }
         if is_open_array(left.resultdef) then
         if is_open_array(left.resultdef) then
-          CGMessage(type_e_assignment_not_allowed)
+          begin
+            CGMessage(type_e_assignment_not_allowed);
+            result:=cerrornode.create;
+            exit;
+          end
         else if (left.resultdef.typ=formaldef) then
         else if (left.resultdef.typ=formaldef) then
           if not(target_info.system in systems_managed_vm) then
           if not(target_info.system in systems_managed_vm) then
             CGMessage(type_e_assignment_not_allowed)
             CGMessage(type_e_assignment_not_allowed)
@@ -910,7 +941,7 @@ implementation
          aktassignmentnode:=self;
          aktassignmentnode:=self;
          firstpass(right);
          firstpass(right);
          aktassignmentnode:=oldassignmentnode;
          aktassignmentnode:=oldassignmentnode;
-         if nf_assign_done_in_right in flags then
+         if anf_assign_done_in_right in assignmentnodeflags then
            begin
            begin
              result:=right;
              result:=right;
              right:=nil;
              right:=nil;
@@ -1073,6 +1104,28 @@ implementation
 
 
 
 
 {$ifdef DEBUG_NODE_XML}
 {$ifdef DEBUG_NODE_XML}
+    procedure TAssignmentNode.XMLPrintNodeInfo(var T: Text);
+      var
+        i: TAssignmentNodeFlag;
+        First: Boolean;
+      begin
+        inherited XMLPrintNodeInfo(T);
+        First := True;
+        for i in assignmentnodeflags do
+          begin
+            if First then
+              begin
+                Write(T, ' assignmentnodeflags="', i);
+                First := False;
+              end
+            else
+              Write(T, ',', i)
+          end;
+        if not First then
+          Write(T, '"');
+      end;
+
+
     procedure TAssignmentNode.XMLPrintNodeData(var T: Text);
     procedure TAssignmentNode.XMLPrintNodeData(var T: Text);
       begin
       begin
         { For assignments, put the left and right branches on the same level for clarity }
         { For assignments, put the left and right branches on the same level for clarity }
@@ -1121,7 +1174,21 @@ implementation
     constructor tarrayconstructornode.create(l,r : tnode);
     constructor tarrayconstructornode.create(l,r : tnode);
       begin
       begin
          inherited create(arrayconstructorn,l,r);
          inherited create(arrayconstructorn,l,r);
-         allow_array_constructor:=false;
+         arrayconstructornodeflags:=[];
+      end;
+
+
+    constructor tarrayconstructornode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
+      begin
+        inherited ppuload(t,ppufile);
+        ppufile.getset(tppuset1(arrayconstructornodeflags));
+      end;
+
+
+    procedure tarrayconstructornode.ppuwrite(ppufile:tcompilerppufile);
+      begin
+        inherited ppuwrite(ppufile);
+        ppufile.putset(tppuset1(arrayconstructornodeflags));
       end;
       end;
 
 
 
 
@@ -1130,6 +1197,7 @@ implementation
          n : tarrayconstructornode;
          n : tarrayconstructornode;
       begin
       begin
          n:=tarrayconstructornode(inherited dogetcopy);
          n:=tarrayconstructornode(inherited dogetcopy);
+         n.arrayconstructornodeflags:=arrayconstructornodeflags;
          result:=n;
          result:=n;
       end;
       end;
 
 
@@ -1174,7 +1242,7 @@ implementation
         Do this only if we didn't convert the arrayconstructor yet. This
         Do this only if we didn't convert the arrayconstructor yet. This
         is needed for the cases where the resultdef is forced for a second
         is needed for the cases where the resultdef is forced for a second
         run }
         run }
-        if not allow_array_constructor or has_range_node then
+        if not (acnf_allow_array_constructor in arrayconstructornodeflags) or has_range_node then
          begin
          begin
            hp:=tarrayconstructornode(getcopy);
            hp:=tarrayconstructornode(getcopy);
            arrayconstructor_to_set(tnode(hp));
            arrayconstructor_to_set(tnode(hp));
@@ -1230,7 +1298,7 @@ implementation
                            hdef:=hp.left.resultdef;
                            hdef:=hp.left.resultdef;
                        end
                        end
                      else
                      else
-                       if (nf_novariaallowed in flags) then
+                       if (acnf_novariaallowed in arrayconstructornodeflags) then
                          varia:=true;
                          varia:=true;
                    end;
                    end;
                end;
                end;
@@ -1280,7 +1348,7 @@ implementation
         hp        : tarrayconstructornode;
         hp        : tarrayconstructornode;
         dovariant : boolean;
         dovariant : boolean;
       begin
       begin
-        dovariant:=(nf_forcevaria in flags) or (ado_isvariant in tarraydef(resultdef).arrayoptions);
+        dovariant:=(acnf_forcevaria in arrayconstructornodeflags) or (ado_isvariant in tarraydef(resultdef).arrayoptions);
         { only pass left tree, right tree contains next construct if any }
         { only pass left tree, right tree contains next construct if any }
         if assigned(left) then
         if assigned(left) then
          begin
          begin
@@ -1304,7 +1372,7 @@ implementation
         do_variant,
         do_variant,
         do_managed_variant:boolean;
         do_managed_variant:boolean;
       begin
       begin
-        do_variant:=(nf_forcevaria in flags) or (ado_isvariant in tarraydef(resultdef).arrayoptions);
+        do_variant:=(acnf_forcevaria in arrayconstructornodeflags) or (ado_isvariant in tarraydef(resultdef).arrayoptions);
         do_managed_variant:=
         do_managed_variant:=
           do_variant and
           do_variant and
           (target_info.system in systems_managed_vm);
           (target_info.system in systems_managed_vm);
@@ -1347,6 +1415,28 @@ implementation
         docompare:=inherited docompare(p);
         docompare:=inherited docompare(p);
       end;
       end;
 
 
+{$ifdef DEBUG_NODE_XML}
+    procedure TArrayConstructorNode.XMLPrintNodeInfo(var T: Text);
+      var
+        i: TArrayConstructorNodeFlag;
+        First: Boolean;
+      begin
+        inherited XMLPrintNodeInfo(T);
+        First := True;
+        for i in arrayconstructornodeflags do
+          begin
+            if First then
+              begin
+                Write(T, ' arrayconstructornodeflags="', i);
+                First := False;
+              end
+            else
+              Write(T, ',', i)
+          end;
+        if not First then
+          Write(T, '"');
+      end;
+{$endif DEBUG_NODE_XML}
 
 
 {*****************************************************************************
 {*****************************************************************************
                               TTYPENODE
                               TTYPENODE

+ 88 - 7
compiler/nmat.pas

@@ -26,13 +26,27 @@ unit nmat;
 interface
 interface
 
 
     uses
     uses
-       node;
+       node,symtype;
 
 
     type
     type
+       TModDivNodeFlag = (
+         mdnf_isomod
+       );
+
+       TModDivNodeFlags = set of TModDivNodeFlag;
+
        tmoddivnode = class(tbinopnode)
        tmoddivnode = class(tbinopnode)
+          moddivnodeflags : TModDivNodeFlags;
+          constructor create(t:tnodetype;l,r : tnode); override;
+          constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
+          procedure ppuwrite(ppufile:tcompilerppufile);override;
           function pass_1 : tnode;override;
           function pass_1 : tnode;override;
           function pass_typecheck:tnode;override;
           function pass_typecheck:tnode;override;
           function simplify(forinline : boolean) : tnode;override;
           function simplify(forinline : boolean) : tnode;override;
+          function dogetcopy : tnode;override;
+    {$ifdef DEBUG_NODE_XML}
+          procedure XMLPrintNodeInfo(var T: Text); override;
+    {$endif DEBUG_NODE_XML}
          protected
          protected
           { override the following if you want to implement }
           { override the following if you want to implement }
           { parts explicitely in the code generator (JM)    }
           { parts explicitely in the code generator (JM)    }
@@ -97,17 +111,39 @@ implementation
       systems,
       systems,
       verbose,globals,cutils,compinnr,
       verbose,globals,cutils,compinnr,
       globtype,constexp,
       globtype,constexp,
-      symconst,symtype,symdef,symcpu,
+      symconst,symdef,symcpu,
       defcmp,defutil,
       defcmp,defutil,
       htypechk,pass_1,
       htypechk,pass_1,
       cgbase,
       cgbase,
       ncon,ncnv,ncal,nadd,nld,nbas,nflw,ninl,
       ncon,ncnv,ncal,nadd,nld,nbas,nflw,ninl,
-      nutils;
+      nutils,ppu;
 
 
 {****************************************************************************
 {****************************************************************************
                               TMODDIVNODE
                               TMODDIVNODE
  ****************************************************************************}
  ****************************************************************************}
 
 
+
+    constructor tmoddivnode.create(t:tnodetype;l,r : tnode);
+      begin
+        inherited create(t, l, r);
+        moddivnodeflags:=[];
+      end;
+
+
+    constructor tmoddivnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
+      begin
+        inherited ppuload(t, ppufile);
+        ppufile.getset(tppuset1(moddivnodeflags));
+      end;
+
+
+    procedure tmoddivnode.ppuwrite(ppufile:tcompilerppufile);
+      begin
+        inherited ppuwrite(ppufile);
+        ppufile.putset(tppuset1(moddivnodeflags));
+      end;
+
+
     function tmoddivnode.simplify(forinline : boolean):tnode;
     function tmoddivnode.simplify(forinline : boolean):tnode;
       var
       var
         rv,lv : tconstexprint;
         rv,lv : tconstexprint;
@@ -149,7 +185,7 @@ implementation
                 left:=nil;
                 left:=nil;
                 exit;
                 exit;
               end;
               end;
-            if (nf_isomod in flags) and
+            if (mdnf_isomod in moddivnodeflags) and
               (rv<=0) then
               (rv<=0) then
                begin
                begin
                  Message(cg_e_mod_only_defined_for_pos_quotient);
                  Message(cg_e_mod_only_defined_for_pos_quotient);
@@ -186,7 +222,7 @@ implementation
 
 
                 case nodetype of
                 case nodetype of
                   modn:
                   modn:
-                    if nf_isomod in flags then
+                    if mdnf_isomod in moddivnodeflags then
                       begin
                       begin
                         if lv>=0 then
                         if lv>=0 then
                           result:=create_simplified_ord_const(lv mod rv,resultdef,forinline,false)
                           result:=create_simplified_ord_const(lv mod rv,resultdef,forinline,false)
@@ -208,6 +244,16 @@ implementation
       end;
       end;
 
 
 
 
+    function tmoddivnode.dogetcopy: tnode;
+      var
+        n: tmoddivnode;
+      begin
+        n:=tmoddivnode(inherited dogetcopy);
+        n.moddivnodeflags:=moddivnodeflags;
+        result:=n;
+      end;
+
+
     function tmoddivnode.use_moddiv64bitint_helper: boolean;
     function tmoddivnode.use_moddiv64bitint_helper: boolean;
       begin
       begin
         { not with an ifdef around the call to this routine, because e.g. the
         { not with an ifdef around the call to this routine, because e.g. the
@@ -412,7 +458,7 @@ implementation
             result:=hp;
             result:=hp;
           end;
           end;
 
 
-         if (nodetype=modn) and (nf_isomod in flags) then
+         if (nodetype=modn) and (mdnf_isomod in moddivnodeflags) then
            begin
            begin
              result:=internalstatements(statements);
              result:=internalstatements(statements);
              else_block:=internalstatements(else_statements);
              else_block:=internalstatements(else_statements);
@@ -722,7 +768,28 @@ implementation
          expectloc:=LOC_REGISTER;
          expectloc:=LOC_REGISTER;
       end;
       end;
 
 
-
+{$ifdef DEBUG_NODE_XML}
+    procedure TModDivNode.XMLPrintNodeInfo(var T: Text);
+      var
+        i: TModDivNodeFlag;
+        First: Boolean;
+      begin
+        inherited XMLPrintNodeInfo(T);
+        First := True;
+        for i in moddivnodeflags do
+          begin
+            if First then
+              begin
+                Write(T, ' moddivnodeflags="', i);
+                First := False;
+              end
+            else
+              Write(T, ',', i)
+          end;
+        if not First then
+          Write(T, '"');
+      end;
+{$endif DEBUG_NODE_XML}
 
 
 {****************************************************************************
 {****************************************************************************
                               TSHLSHRNODE
                               TSHLSHRNODE
@@ -1025,6 +1092,20 @@ implementation
                 result:=tunarynode(left).left.getcopy;
                 result:=tunarynode(left).left.getcopy;
                 exit;
                 exit;
               end;
               end;
+          end
+        { transform -(x+1) or -(1+x) into not(x) }
+        else if is_integer(left.resultdef) and is_signed(left.resultdef) and (left.nodetype=addn) and ((localswitches*[cs_check_overflow,cs_check_range])=[]) then
+          begin
+            if is_constintnode(taddnode(left).right) and (tordconstnode(taddnode(left).right).value=1) then
+              begin
+                result:=cnotnode.create(taddnode(left).left.getcopy);
+                exit;
+              end
+            else if is_constintnode(taddnode(left).left) and (tordconstnode(taddnode(left).left).value=1) then
+              begin
+                result:=cnotnode.create(taddnode(left).right.getcopy);
+                exit;
+              end;
           end;
           end;
       end;
       end;
 
 

+ 125 - 6
compiler/nmem.pas

@@ -103,11 +103,24 @@ interface
        end;
        end;
        taddrnodeclass = class of taddrnode;
        taddrnodeclass = class of taddrnode;
 
 
+       TDerefNodeFlag = (
+         drnf_no_checkpointer
+       );
+
+       TDerefNodeFlags = set of TDerefNodeFlag;
+
        tderefnode = class(tunarynode)
        tderefnode = class(tunarynode)
+          derefnodeflags : TDerefNodeFlags;
           constructor create(l : tnode);virtual;
           constructor create(l : tnode);virtual;
+          constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
+          procedure ppuwrite(ppufile:tcompilerppufile);override;
+          function dogetcopy : tnode;override;
           function pass_1 : tnode;override;
           function pass_1 : tnode;override;
           function pass_typecheck:tnode;override;
           function pass_typecheck:tnode;override;
           procedure mark_write;override;
           procedure mark_write;override;
+{$ifdef DEBUG_NODE_XML}
+          procedure XMLPrintNodeInfo(var T: Text); override;
+{$endif DEBUG_NODE_XML}
        end;
        end;
        tderefnodeclass = class of tderefnode;
        tderefnodeclass = class of tderefnode;
 
 
@@ -131,17 +144,30 @@ interface
        end;
        end;
        tsubscriptnodeclass = class of tsubscriptnode;
        tsubscriptnodeclass = class of tsubscriptnode;
 
 
+       TVecNodeFlag = (
+         vnf_memindex,
+         vnf_memseg,
+         vnf_callunique
+       );
+
+       TVecNodeFlags = set of TVecNodeFlag;
+
        tvecnode = class(tbinarynode)
        tvecnode = class(tbinarynode)
        protected
        protected
-          function first_arraydef: tnode; virtual;
+          function first_arraydef : tnode; virtual;
           function gen_array_rangecheck: tnode; virtual;
           function gen_array_rangecheck: tnode; virtual;
        public
        public
-          constructor create(l,r : tnode);virtual;
+          vecnodeflags: TVecNodeFlags;
+          constructor  create(l,r : tnode);virtual;
+          constructor ppuload(t : tnodetype;ppufile : tcompilerppufile);override;
+          procedure ppuwrite(ppufile : tcompilerppufile);override;
           function pass_1 : tnode;override;
           function pass_1 : tnode;override;
           function pass_typecheck:tnode;override;
           function pass_typecheck:tnode;override;
           function simplify(forinline : boolean) : tnode; override;
           function simplify(forinline : boolean) : tnode; override;
+          function dogetcopy : tnode;override;
           procedure mark_write;override;
           procedure mark_write;override;
 {$ifdef DEBUG_NODE_XML}
 {$ifdef DEBUG_NODE_XML}
+          procedure XMLPrintNodeInfo(var T: Text); override;
           procedure XMLPrintNodeData(var T: Text); override;
           procedure XMLPrintNodeData(var T: Text); override;
 {$endif DEBUG_NODE_XML}
 {$endif DEBUG_NODE_XML}
        end;
        end;
@@ -837,6 +863,30 @@ implementation
       end;
       end;
 
 
 
 
+    constructor tderefnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
+      begin
+        inherited ppuload(t, ppufile);
+        ppufile.getset(tppuset1(derefnodeflags));
+      end;
+
+
+    procedure tderefnode.ppuwrite(ppufile:tcompilerppufile);
+      begin
+        inherited ppuwrite(ppufile);
+        ppufile.putset(tppuset1(derefnodeflags));
+      end;
+
+
+    function tderefnode.dogetcopy : tnode;
+      var
+        n: TDerefNode;
+      begin
+        n := TDerefNode(inherited dogetcopy);
+        n.derefnodeflags := derefnodeflags;
+        Result := n;
+      end;
+
+
     function tderefnode.pass_typecheck:tnode;
     function tderefnode.pass_typecheck:tnode;
       begin
       begin
          result:=nil;
          result:=nil;
@@ -872,6 +922,28 @@ implementation
          expectloc:=LOC_REFERENCE;
          expectloc:=LOC_REFERENCE;
       end;
       end;
 
 
+{$ifdef DEBUG_NODE_XML}
+    procedure TDerefNode.XMLPrintNodeInfo(var T: Text);
+      var
+        i: TDerefNodeFlag;
+        First: Boolean;
+      begin
+        inherited XMLPrintNodeInfo(T);
+        First := True;
+        for i in derefnodeflags do
+          begin
+            if First then
+              begin
+                Write(T, ' derefnodeflags="', i);
+                First := False;
+              end
+            else
+              Write(T, ',', i)
+          end;
+        if not First then
+          Write(T, '"');
+      end;
+{$endif DEBUG_NODE_XML}
 
 
 {*****************************************************************************
 {*****************************************************************************
                             TSUBSCRIPTNODE
                             TSUBSCRIPTNODE
@@ -1012,9 +1084,23 @@ implementation
 *****************************************************************************}
 *****************************************************************************}
 
 
     constructor tvecnode.create(l,r : tnode);
     constructor tvecnode.create(l,r : tnode);
-
       begin
       begin
          inherited create(vecn,l,r);
          inherited create(vecn,l,r);
+         vecnodeflags:=[];
+      end;
+
+
+    constructor tvecnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
+      begin
+        inherited ppuload(t, ppufile);
+        ppufile.getset(tppuset1(vecnodeflags));
+      end;
+
+
+    procedure tvecnode.ppuwrite(ppufile:tcompilerppufile);
+      begin
+        inherited ppuwrite(ppufile);
+        ppufile.putset(tppuset1(vecnodeflags));
       end;
       end;
 
 
 
 
@@ -1312,7 +1398,7 @@ implementation
          if codegenerror then
          if codegenerror then
            exit;
            exit;
 
 
-         if (nf_callunique in flags) and
+         if (vnf_callunique in vecnodeflags) and
             (is_ansistring(left.resultdef) or
             (is_ansistring(left.resultdef) or
              is_unicodestring(left.resultdef) or
              is_unicodestring(left.resultdef) or
             (is_widestring(left.resultdef) and not(tf_winlikewidestring in target_info.flags))) then
             (is_widestring(left.resultdef) and not(tf_winlikewidestring in target_info.flags))) then
@@ -1324,10 +1410,10 @@ implementation
              firstpass(left);
              firstpass(left);
              { double resultdef passes somwhere else may cause this to be }
              { double resultdef passes somwhere else may cause this to be }
              { reset though :/                                             }
              { reset though :/                                             }
-             exclude(flags,nf_callunique);
+             exclude(vecnodeflags,vnf_callunique);
            end
            end
          else if is_widestring(left.resultdef) and (tf_winlikewidestring in target_info.flags) then
          else if is_widestring(left.resultdef) and (tf_winlikewidestring in target_info.flags) then
-           exclude(flags,nf_callunique);
+           exclude(vecnodeflags,vnf_callunique);
 
 
          { a range node as array index can only appear in function calls, and
          { a range node as array index can only appear in function calls, and
            those convert the range node into something else in
            those convert the range node into something else in
@@ -1393,6 +1479,16 @@ implementation
       end;
       end;
 
 
 
 
+    function tvecnode.dogetcopy: tnode;
+      var
+        n: tvecnode;
+      begin
+        n:=tvecnode(inherited dogetcopy);
+        n.vecnodeflags:=vecnodeflags;
+        result:=n;
+      end;
+
+
     function tvecnode.first_arraydef: tnode;
     function tvecnode.first_arraydef: tnode;
       begin
       begin
         result:=nil;
         result:=nil;
@@ -1409,6 +1505,7 @@ implementation
             expectloc:=LOC_SUBSETREF;
             expectloc:=LOC_SUBSETREF;
       end;
       end;
 
 
+
     function tvecnode.gen_array_rangecheck: tnode;
     function tvecnode.gen_array_rangecheck: tnode;
     var
     var
       htype: tdef;
       htype: tdef;
@@ -1486,6 +1583,28 @@ implementation
 
 
 
 
 {$ifdef DEBUG_NODE_XML}
 {$ifdef DEBUG_NODE_XML}
+    procedure TVecNode.XMLPrintNodeInfo(var T: Text);
+      var
+        i: TVecNodeFlag;
+        First: Boolean;
+      begin
+        inherited XMLPrintNodeInfo(T);
+        First := True;
+        for i in vecnodeflags do
+          begin
+            if First then
+              begin
+                Write(T, ' vecnodeflags="', i);
+                First := False;
+              end
+            else
+              Write(T, ',', i)
+          end;
+        if not First then
+          Write(T, '"');
+      end;
+
+
     procedure TVecNode.XMLPrintNodeData(var T: Text);
     procedure TVecNode.XMLPrintNodeData(var T: Text);
       begin
       begin
         XMLPrintNode(T, Left);
         XMLPrintNode(T, Left);

+ 63 - 61
compiler/node.pas

@@ -208,14 +208,10 @@ interface
     type
     type
        { all boolean field of ttree are now collected in flags }
        { all boolean field of ttree are now collected in flags }
        tnodeflag = (
        tnodeflag = (
-         { tbinop operands can be swaped }
-         nf_swapable,
          { tbinop operands are swaped    }
          { tbinop operands are swaped    }
          nf_swapped,
          nf_swapped,
-         nf_error,
 
 
          { general }
          { general }
-         nf_pass1_done,
          { Node is written to    }
          { Node is written to    }
          nf_write,
          nf_write,
          { Node is modified      }
          { Node is modified      }
@@ -224,40 +220,20 @@ interface
          nf_address_taken,
          nf_address_taken,
          nf_is_funcret,
          nf_is_funcret,
          nf_isproperty,
          nf_isproperty,
-         nf_processing,
          { Node cannot be assigned to }
          { Node cannot be assigned to }
          nf_no_lvalue,
          nf_no_lvalue,
          { this node is the user code entry, if a node with this flag is removed
          { this node is the user code entry, if a node with this flag is removed
-           during simplify, the flag must be moved to another node }
+           during simplify, the flag must be moved to another node.  Though
+           normally applicable to block nodes, they can also appear on asm nodes
+           in the case of pure assembly routines }
          nf_usercode_entry,
          nf_usercode_entry,
 
 
-         { tderefnode }
-         nf_no_checkpointer,
-
-         { tvecnode }
-         nf_memindex,
-         nf_memseg,
-         nf_callunique,
-
          { tloadnode/ttypeconvnode }
          { tloadnode/ttypeconvnode }
          nf_absolute,
          nf_absolute,
 
 
-         { taddnode }
+         { taddnode, but appears in typeconv nodes as well among other places }
          { if the result type of a node is currency, then this flag denotes, that the value is already mulitplied by 10000 }
          { if the result type of a node is currency, then this flag denotes, that the value is already mulitplied by 10000 }
          nf_is_currency,
          nf_is_currency,
-         nf_has_pointerdiv,
-         { the node shall be short boolean evaluated, this flag has priority over localswitches }
-         nf_short_bool,
-
-         { tmoddivnode }
-         nf_isomod,
-
-         { tassignmentnode }
-         nf_assign_done_in_right,
-
-         { tarrayconstructnode }
-         nf_forcevaria,
-         nf_novariaallowed,
 
 
          { ttypeconvnode, and the first one also treal/ord/pointerconstn }
          { ttypeconvnode, and the first one also treal/ord/pointerconstn }
          { second one also for subtractions of u32-u32 implicitly upcasted to s64 }
          { second one also for subtractions of u32-u32 implicitly upcasted to s64 }
@@ -266,32 +242,42 @@ interface
          nf_internal,  { no warnings/hints generated }
          nf_internal,  { no warnings/hints generated }
          nf_load_procvar,
          nf_load_procvar,
 
 
-         { tinlinenode }
-         nf_inlineconst,
-
-         { tasmnode }
-         nf_get_asm_position,
-
-         { tblocknode }
+         { tblocknode / this is not node-specific because it can also appear on
+           implicit try/finally nodes }
          nf_block_with_exit,
          nf_block_with_exit,
 
 
-         { tloadvmtaddrnode }
+         { tloadvmtaddrnode / tisnode }
          nf_ignore_for_wpo, { we know that this loadvmtaddrnode cannot be used to construct a class instance }
          nf_ignore_for_wpo, { we know that this loadvmtaddrnode cannot be used to construct a class instance }
 
 
          { node is derived from generic parameter }
          { node is derived from generic parameter }
-         nf_generic_para,
+         nf_generic_para
+       );
+
+       tnodeflags = set of tnodeflag;
+
+       TTransientNodeFlag = (
+         { general }
+         tnf_pass1_done,
+         tnf_error,
+
+         { tbinop operands can be swaped }
+         tnf_swapable,
+
+         tnf_processing,
 
 
          { internal flag to indicate that this node has been removed from the tree or must otherwise not be
          { internal flag to indicate that this node has been removed from the tree or must otherwise not be
            execute.  Running it through firstpass etc. will raise an internal error }
            execute.  Running it through firstpass etc. will raise an internal error }
-         nf_do_not_execute
+         tnf_do_not_execute
        );
        );
 
 
-       tnodeflags = set of tnodeflag;
+       TTransientNodeFlags = set of TTransientNodeFlag;
+
 
 
     const
     const
        { contains the flags which must be equal for the equality }
        { contains the flags which must be equal for the equality }
        { of nodes                                                }
        { of nodes                                                }
-       flagsequal : tnodeflags = [nf_error];
+       flagsequal : tnodeflags = [];
+       transientflagsequal : TTransientNodeFlags = [tnf_error];
 
 
     type
     type
        tnodelist = class
        tnodelist = class
@@ -320,6 +306,7 @@ interface
          successor : tnode;
          successor : tnode;
          { there are some properties about the node stored }
          { there are some properties about the node stored }
          flags  : tnodeflags;
          flags  : tnodeflags;
+         transientflags : TTransientNodeFlags;
          resultdef     : tdef;
          resultdef     : tdef;
          resultdefderef : tderef;
          resultdefderef : tderef;
          fileinfo      : tfileposinfo;
          fileinfo      : tfileposinfo;
@@ -783,7 +770,7 @@ implementation
         ppufile.getset(tppuset5(localswitches));
         ppufile.getset(tppuset5(localswitches));
         verbosity:=ppufile.getlongint;
         verbosity:=ppufile.getlongint;
         ppufile.getderef(resultdefderef);
         ppufile.getderef(resultdefderef);
-        ppufile.getset(tppuset5(flags));
+        ppufile.getset(tppuset2(flags));
         { updated by firstpass }
         { updated by firstpass }
         expectloc:=LOC_INVALID;
         expectloc:=LOC_INVALID;
         { updated by secondpass }
         { updated by secondpass }
@@ -798,7 +785,7 @@ implementation
         ppufile.putset(tppuset5(localswitches));
         ppufile.putset(tppuset5(localswitches));
         ppufile.putlongint(verbosity);
         ppufile.putlongint(verbosity);
         ppufile.putderef(resultdefderef);
         ppufile.putderef(resultdefderef);
-        ppufile.putset(tppuset5(flags));
+        ppufile.putset(tppuset2(flags));
       end;
       end;
 
 
 
 
@@ -891,7 +878,7 @@ implementation
               write(t, i);
               write(t, i);
             end;
             end;
         write(t,']');
         write(t,']');
-        if (nf_pass1_done in flags) then
+        if (tnf_pass1_done in transientflags) then
           write(t,', cmplx = ',node_complexity(self));
           write(t,', cmplx = ',node_complexity(self));
         if assigned(optinfo) then
         if assigned(optinfo) then
           write(t,', optinfo = ',HexStr(optinfo));
           write(t,', optinfo = ',HexStr(optinfo));
@@ -919,7 +906,8 @@ implementation
       instead call XMLPrintNode to write a complete tree }
       instead call XMLPrintNode to write a complete tree }
     procedure tnode.XMLPrintNodeInfo(var T: Text);
     procedure tnode.XMLPrintNodeInfo(var T: Text);
       var
       var
-        i: TNodeFlag;
+        i_nf: TNodeFlag;
+        i_tnf: TTransientNodeFlag;
         first: Boolean;
         first: Boolean;
       begin
       begin
         if Assigned(resultdef) then
         if Assigned(resultdef) then
@@ -928,19 +916,31 @@ implementation
         Write(T,' pos="',fileinfo.line,',',fileinfo.column);
         Write(T,' pos="',fileinfo.line,',',fileinfo.column);
 
 
         First := True;
         First := True;
-        for i := Low(TNodeFlag) to High(TNodeFlag) do
-          if i in flags then
-            begin
-              if First then
-                begin
-                  Write(T, '" flags="', i);
-                  First := False;
-                end
-              else
-                Write(T, ',', i)
-            end;
-        write(t,'"');
-        if (nf_pass1_done in flags) then
+        for i_nf in flags do
+          begin
+            if First then
+              begin
+                Write(T, '" flags="', i_nf);
+                First := False;
+              end
+            else
+              Write(T, ',', i_nf)
+          end;
+
+        First := True;
+        for i_tnf in transientflags do
+          begin
+            if First then
+              begin
+                Write(T, '" transientflags="', i_tnf);
+                First := False;
+              end
+            else
+              Write(T, ',', i_tnf)
+          end;
+        write(T,'"');
+
+        if (tnf_pass1_done in transientflags) then
           write(t,' complexity="',node_complexity(self),'"');
           write(t,' complexity="',node_complexity(self),'"');
       end;
       end;
 
 
@@ -971,6 +971,7 @@ implementation
             (p.classtype=classtype) and
             (p.classtype=classtype) and
             (p.nodetype=nodetype) and
             (p.nodetype=nodetype) and
             (flags*flagsequal=p.flags*flagsequal) and
             (flags*flagsequal=p.flags*flagsequal) and
+            (transientflags*transientflagsequal=p.transientflags*transientflagsequal) and
             docompare(p));
             docompare(p));
       end;
       end;
 
 
@@ -1024,6 +1025,7 @@ implementation
          p.expectloc:=expectloc;
          p.expectloc:=expectloc;
          p.location:=location;
          p.location:=location;
          p.flags:=flags;
          p.flags:=flags;
+         p.transientflags:=transientflags;
          p.resultdef:=resultdef;
          p.resultdef:=resultdef;
          p.fileinfo:=fileinfo;
          p.fileinfo:=fileinfo;
          p.localswitches:=localswitches;
          p.localswitches:=localswitches;
@@ -1152,7 +1154,7 @@ implementation
       begin
       begin
         Result := left;
         Result := left;
         left := nil;
         left := nil;
-        Include(flags, nf_do_not_execute);
+        Include(transientflags, tnf_do_not_execute);
       end;
       end;
 
 
 
 
@@ -1306,7 +1308,7 @@ implementation
       begin
       begin
         Result := right;
         Result := right;
         right := nil;
         right := nil;
-        Include(flags, nf_do_not_execute);
+        Include(transientflags, tnf_do_not_execute);
       end;
       end;
 
 
 
 
@@ -1421,7 +1423,7 @@ implementation
       begin
       begin
         Result := third;
         Result := third;
         third := nil;
         third := nil;
-        Include(flags, nf_do_not_execute);
+        Include(transientflags, tnf_do_not_execute);
       end;
       end;
 
 
 
 
@@ -1439,7 +1441,7 @@ implementation
       begin
       begin
          docompare:=(inherited docompare(p)) or
          docompare:=(inherited docompare(p)) or
            { if that's in the flags, is p then always a tbinopnode (?) (JM) }
            { if that's in the flags, is p then always a tbinopnode (?) (JM) }
-           ((nf_swapable in flags) and
+           ((tnf_swapable in transientflags) and
             left.isequal(tbinopnode(p).right) and
             left.isequal(tbinopnode(p).right) and
             right.isequal(tbinopnode(p).left));
             right.isequal(tbinopnode(p).left));
       end;
       end;

+ 4 - 4
compiler/nopt.pas

@@ -339,7 +339,7 @@ begin
       include(sn.flags,nf_internal);
       include(sn.flags,nf_internal);
     end;
     end;
   arrp:=carrayconstructornode.create(sn,arrp);
   arrp:=carrayconstructornode.create(sn,arrp);
-  arrp.allow_array_constructor:=true;
+  Include(arrp.arrayconstructornodeflags, acnf_allow_array_constructor);
   if assigned(aktassignmentnode) and
   if assigned(aktassignmentnode) and
      (aktassignmentnode.right=p) and
      (aktassignmentnode.right=p) and
      (
      (
@@ -370,7 +370,7 @@ begin
                 'fpc_'+tstringdef(p.resultdef).stringtypname+'_concat_multi',
                 'fpc_'+tstringdef(p.resultdef).stringtypname+'_concat_multi',
                 para
                 para
               );
               );
-      include(aktassignmentnode.flags,nf_assign_done_in_right);
+      include(aktassignmentnode.assignmentnodeflags,anf_assign_done_in_right);
     end
     end
   else
   else
     begin
     begin
@@ -452,7 +452,7 @@ begin
     end;
     end;
   sn:=ctypeconvnode.create_internal(hp.getcopy,voidpointertype);
   sn:=ctypeconvnode.create_internal(hp.getcopy,voidpointertype);
   arrp:=carrayconstructornode.create(sn,arrp);
   arrp:=carrayconstructornode.create(sn,arrp);
-  arrp.allow_array_constructor:=true;
+  Include(arrp.arrayconstructornodeflags, acnf_allow_array_constructor);
   if assigned(aktassignmentnode) and
   if assigned(aktassignmentnode) and
      (aktassignmentnode.right=p) and
      (aktassignmentnode.right=p) and
      (aktassignmentnode.left.resultdef=p.resultdef) and
      (aktassignmentnode.left.resultdef=p.resultdef) and
@@ -469,7 +469,7 @@ begin
                 'fpc_dynarray_concat_multi',
                 'fpc_dynarray_concat_multi',
                 para
                 para
               );
               );
-      include(aktassignmentnode.flags,nf_assign_done_in_right);
+      include(aktassignmentnode.assignmentnodeflags,anf_assign_done_in_right);
     end
     end
   else
   else
     begin
     begin

+ 18 - 6
compiler/nutils.pas

@@ -162,7 +162,7 @@ interface
     function get_open_const_array(p : tnode) : tnode;
     function get_open_const_array(p : tnode) : tnode;
 
 
     { excludes the flags passed in nf from the node tree passed }
     { excludes the flags passed in nf from the node tree passed }
-    procedure node_reset_flags(p : tnode;nf : tnodeflags);
+    procedure node_reset_flags(p : tnode;nf : TNodeFlags; tnf : TTransientNodeFlags);
 
 
     { include or exclude cs from p.localswitches }
     { include or exclude cs from p.localswitches }
     procedure node_change_local_switch(p : tnode;cs : tlocalswitch;enable : boolean);
     procedure node_change_local_switch(p : tnode;cs : tlocalswitch;enable : boolean);
@@ -1565,17 +1565,28 @@ implementation
           result:=get_open_const_array(taddrnode(tderefnode(result).left).left);
           result:=get_open_const_array(taddrnode(tderefnode(result).left).left);
       end;
       end;
 
 
+    type
+      TFlagSet = record
+        nf : TNodeFlags;
+        tnf : TTransientNodeFlags;
+      end;
+
 
 
     function do_node_reset_flags(var n: tnode; arg: pointer): foreachnoderesult;
     function do_node_reset_flags(var n: tnode; arg: pointer): foreachnoderesult;
       begin
       begin
         result:=fen_false;
         result:=fen_false;
-        n.flags:=n.flags-tnodeflags(arg^);
+        n.flags:=n.flags-TFlagSet(arg^).nf;
+        n.transientflags:=n.transientflags-TFlagSet(arg^).tnf;
       end;
       end;
 
 
 
 
-    procedure node_reset_flags(p : tnode; nf : tnodeflags);
+    procedure node_reset_flags(p : tnode; nf : TNodeFlags; tnf : TTransientNodeFlags);
+      var
+        FlagSet: TFlagSet;
       begin
       begin
-        foreachnodestatic(p,@do_node_reset_flags,@nf);
+        FlagSet.nf:=nf;
+        FlagSet.tnf:=tnf;
+        foreachnodestatic(p,@do_node_reset_flags,@FlagSet);
       end;
       end;
 
 
     type
     type
@@ -1608,7 +1619,7 @@ implementation
 
 
     function doshortbooleval(p : tnode) : Boolean;
     function doshortbooleval(p : tnode) : Boolean;
       begin
       begin
-        Result:=(p.nodetype in [orn,andn]) and ((nf_short_bool in taddnode(p).flags) or not(cs_full_boolean_eval in p.localswitches));
+        Result:=(p.nodetype in [orn,andn]) and ((anf_short_bool in taddnode(p).addnodeflags) or not(cs_full_boolean_eval in p.localswitches));
       end;
       end;
 
 
 
 
@@ -1709,7 +1720,8 @@ implementation
      function _node_reset_pass1_write(var n: tnode; arg: pointer): foreachnoderesult;
      function _node_reset_pass1_write(var n: tnode; arg: pointer): foreachnoderesult;
        begin
        begin
          Result := fen_false;
          Result := fen_false;
-         n.flags := n.flags - [nf_pass1_done,nf_write,nf_modify];
+         n.flags := n.flags - [nf_write,nf_modify];
+         n.transientflags := n.transientflags - [tnf_pass1_done];
          if n.nodetype = assignn then
          if n.nodetype = assignn then
            begin
            begin
              { Force re-evaluation of assignments so nf_modify and nf_write
              { Force re-evaluation of assignments so nf_modify and nf_write

+ 28 - 0
compiler/ogbase.pas

@@ -343,12 +343,14 @@ interface
        constructor create(AList:TFPHashObjectList;const Aname:string;Aalign:longint;Aoptions:TObjSectionOptions);virtual;
        constructor create(AList:TFPHashObjectList;const Aname:string;Aalign:longint;Aoptions:TObjSectionOptions);virtual;
        destructor  destroy;override;
        destructor  destroy;override;
        function  write(const d;l:TObjSectionOfs):TObjSectionOfs;
        function  write(const d;l:TObjSectionOfs):TObjSectionOfs;
+       procedure writeInt8(v: int8);
        procedure writeInt16LE(v: int16);
        procedure writeInt16LE(v: int16);
        procedure writeInt16BE(v: int16);
        procedure writeInt16BE(v: int16);
        procedure writeInt32LE(v: int32);
        procedure writeInt32LE(v: int32);
        procedure writeInt32BE(v: int32);
        procedure writeInt32BE(v: int32);
        procedure writeInt64LE(v: int64);
        procedure writeInt64LE(v: int64);
        procedure writeInt64BE(v: int64);
        procedure writeInt64BE(v: int64);
+       procedure writeUInt8(v: uint8);
        procedure writeUInt16LE(v: uint16);
        procedure writeUInt16LE(v: uint16);
        procedure writeUInt16BE(v: uint16);
        procedure writeUInt16BE(v: uint16);
        procedure writeUInt32LE(v: uint32);
        procedure writeUInt32LE(v: uint32);
@@ -456,12 +458,14 @@ interface
        procedure alloc(len:TObjSectionOfs);
        procedure alloc(len:TObjSectionOfs);
        procedure allocalign(len:longint);
        procedure allocalign(len:longint);
        procedure writebytes(const Data;len:TObjSectionOfs);
        procedure writebytes(const Data;len:TObjSectionOfs);
+       procedure writeInt8(v: int8);
        procedure writeInt16LE(v: int16);
        procedure writeInt16LE(v: int16);
        procedure writeInt16BE(v: int16);
        procedure writeInt16BE(v: int16);
        procedure writeInt32LE(v: int32);
        procedure writeInt32LE(v: int32);
        procedure writeInt32BE(v: int32);
        procedure writeInt32BE(v: int32);
        procedure writeInt64LE(v: int64);
        procedure writeInt64LE(v: int64);
        procedure writeInt64BE(v: int64);
        procedure writeInt64BE(v: int64);
+       procedure writeUInt8(v: uint8);
        procedure writeUInt16LE(v: uint16);
        procedure writeUInt16LE(v: uint16);
        procedure writeUInt16BE(v: uint16);
        procedure writeUInt16BE(v: uint16);
        procedure writeUInt32LE(v: uint32);
        procedure writeUInt32LE(v: uint32);
@@ -1075,6 +1079,12 @@ implementation
       end;
       end;
 
 
 
 
+    procedure TObjSection.writeInt8(v: int8);
+      begin
+        write(v,1);
+      end;
+
+
     procedure TObjSection.writeInt16LE(v: int16);
     procedure TObjSection.writeInt16LE(v: int16);
       begin
       begin
 {$ifdef FPC_BIG_ENDIAN}
 {$ifdef FPC_BIG_ENDIAN}
@@ -1129,6 +1139,12 @@ implementation
       end;
       end;
 
 
 
 
+    procedure TObjSection.writeUInt8(v: uint8);
+      begin
+        write(v,1);
+      end;
+
+
     procedure TObjSection.writeUInt16LE(v: uint16);
     procedure TObjSection.writeUInt16LE(v: uint16);
       begin
       begin
 {$ifdef FPC_BIG_ENDIAN}
 {$ifdef FPC_BIG_ENDIAN}
@@ -1709,6 +1725,12 @@ implementation
       end;
       end;
 
 
 
 
+    procedure TObjData.writeInt8(v: int8);
+      begin
+        writebytes(v,1);
+      end;
+
+
     procedure TObjData.writeInt16LE(v: int16);
     procedure TObjData.writeInt16LE(v: int16);
       begin
       begin
 {$ifdef FPC_BIG_ENDIAN}
 {$ifdef FPC_BIG_ENDIAN}
@@ -1763,6 +1785,12 @@ implementation
       end;
       end;
 
 
 
 
+    procedure TObjData.writeUInt8(v: uint8);
+      begin
+        writebytes(v,1);
+      end;
+
+
     procedure TObjData.writeUInt16LE(v: uint16);
     procedure TObjData.writeUInt16LE(v: uint16);
       begin
       begin
 {$ifdef FPC_BIG_ENDIAN}
 {$ifdef FPC_BIG_ENDIAN}

+ 37 - 1
compiler/ogelf.pas

@@ -623,8 +623,20 @@ implementation
 
 
 
 
     procedure TElfObjData.writereloc(data:aint;len:aword;p:TObjSymbol;reltype:TObjRelocationType);
     procedure TElfObjData.writereloc(data:aint;len:aword;p:TObjSymbol;reltype:TObjRelocationType);
+      type 
+        multi = record
+          case integer of
+          0 : (ba : array[0..sizeof(aint)-1] of byte);
+          1 : (b : byte);
+          2 : (w : word);
+          4 : (d : dword);
+          8 : (q : qword);
+        end;
+
       var
       var
         symaddr : aint;
         symaddr : aint;
+        ba : multi;
+        b : byte;
         objreloc: TObjRelocation;
         objreloc: TObjRelocation;
       begin
       begin
         if CurrObjSec=nil then
         if CurrObjSec=nil then
@@ -683,7 +695,31 @@ implementation
                 data:=0;
                 data:=0;
               end;
               end;
           end;
           end;
-        CurrObjSec.write(data,len);
+        if target_info.endian<>source_info.endian then
+          begin
+            ba.q:=0;
+            if (len<=sizeof(data)) then
+              case len of
+                1 : ba.b:=byte(data);
+                2 : begin
+                      ba.w:=word(data);
+                      ba.w:=swapendian(ba.w);
+                    end;
+                4 : begin
+                      ba.d:=dword(data);
+                      ba.d:=swapendian(ba.d);
+                    end;
+                8 : begin
+                      ba.q:=qword(data);
+                      ba.q:=swapendian(ba.q);
+                    end;
+              else
+                internalerror(2024012501);
+              end;
+            CurrObjSec.write(ba,len);
+          end
+        else
+          CurrObjSec.write(data,len);
       end;
       end;
 
 
 
 

+ 1 - 1
compiler/optbase.pas

@@ -35,7 +35,7 @@ unit optbase;
       PDFASet = ^TDFASet;
       PDFASet = ^TDFASet;
 
 
       toptinfo = record
       toptinfo = record
-        { index of the current node inside the dfa sets, aword(-1) if no entry }
+        { index of the current node inside the dfa sets }
         index : aword;
         index : aword;
         { dfa }
         { dfa }
         def : tdfaset;
         def : tdfaset;

+ 1 - 1
compiler/optconstprop.pas

@@ -288,7 +288,7 @@ unit optconstprop;
         if n.nodetype<>callparan then
         if n.nodetype<>callparan then
           begin
           begin
             if tree_modified then
             if tree_modified then
-              exclude(n.flags,nf_pass1_done);
+              exclude(n.transientflags,tnf_pass1_done);
 
 
             do_firstpass(n);
             do_firstpass(n);
           end;
           end;

+ 11 - 4
compiler/optcse.pas

@@ -76,7 +76,8 @@ unit optcse;
                with more than one parameter }
                with more than one parameter }
              in_fma_single,in_fma_double,in_fma_extended,in_fma_float128,
              in_fma_single,in_fma_double,in_fma_extended,in_fma_float128,
              in_min_single,in_min_double,in_max_single,in_max_double,
              in_min_single,in_min_double,in_max_single,in_max_double,
-             in_max_longint,in_max_dword,in_min_longint,in_min_dword
+             in_max_longint,in_max_dword,in_min_longint,in_min_dword,
+             in_max_int64,in_max_qword,in_min_int64,in_min_qword
              ])
              ])
           ) or
           ) or
           ((n.nodetype=callparan) and not(assigned(tcallparanode(n).right))) or
           ((n.nodetype=callparan) and not(assigned(tcallparanode(n).right))) or
@@ -380,8 +381,14 @@ unit optcse;
                                 begin
                                 begin
                                   n.localswitches:=n.localswitches+(tbinarynode(n).left.localswitches*[cs_full_boolean_eval]);
                                   n.localswitches:=n.localswitches+(tbinarynode(n).left.localswitches*[cs_full_boolean_eval]);
                                   exclude(tbinarynode(n).left.localswitches,cs_full_boolean_eval);
                                   exclude(tbinarynode(n).left.localswitches,cs_full_boolean_eval);
-                                  tbinarynode(n).left.flags:=tbinarynode(n).left.flags+(n.flags*[nf_short_bool]);
-                                  exclude(n.Flags,nf_short_bool);
+                                  if (n.nodetype in [orn,andn]) then
+                                    begin
+                                      if (tbinarynode(n).left.nodetype in [orn,andn]) then
+                                        taddnode(tbinarynode(n).left).addnodeflags:=taddnode(tbinarynode(n).left).addnodeflags+
+                                          (taddnode(n).addnodeflags*[anf_short_bool]);
+
+                                      exclude(taddnode(n).addnodeflags,anf_short_bool);
+                                    end;
                                 end;
                                 end;
 
 
                               hp2:=tbinarynode(tbinarynode(n).left).left;
                               hp2:=tbinarynode(tbinarynode(n).left).left;
@@ -392,7 +399,7 @@ unit optcse;
 
 
                               { the transformed tree could result in new possibilities to fold constants
                               { the transformed tree could result in new possibilities to fold constants
                                 so force a firstpass on the root node }
                                 so force a firstpass on the root node }
-                              exclude(tbinarynode(n).right.flags,nf_pass1_done);
+                              exclude(tbinarynode(n).right.transientflags,tnf_pass1_done);
                               do_firstpass(tbinarynode(n).right);
                               do_firstpass(tbinarynode(n).right);
                             end
                             end
                           else
                           else

+ 0 - 1
compiler/optdeadstore.pas

@@ -59,7 +59,6 @@ unit optdeadstore;
 
 
                 { we need to have dfa for the node }
                 { we need to have dfa for the node }
                 if assigned(a.left.optinfo) and
                 if assigned(a.left.optinfo) and
-                   (a.left.optinfo^.index<>aword(-1)) and
                    { node must be either a local or parameter load node }
                    { node must be either a local or parameter load node }
                    (a.left.nodetype=loadn) and
                    (a.left.nodetype=loadn) and
                    { its address cannot have escaped the current routine }
                    { its address cannot have escaped the current routine }

+ 10 - 11
compiler/optdfa.pas

@@ -148,7 +148,7 @@ unit optdfa;
 
 
     function ResetProcessing(var n: tnode; arg: pointer): foreachnoderesult;
     function ResetProcessing(var n: tnode; arg: pointer): foreachnoderesult;
       begin
       begin
-        exclude(n.flags,nf_processing);
+        exclude(n.transientflags,tnf_processing);
         { dfa works only on normalized trees, so do not recurse into expressions, because
         { dfa works only on normalized trees, so do not recurse into expressions, because
           ResetProcessing eats a signififcant amount of time of CheckAndWarn
           ResetProcessing eats a signififcant amount of time of CheckAndWarn
 
 
@@ -188,12 +188,11 @@ unit optdfa;
           life info for the node
           life info for the node
         }
         }
         procedure updatelifeinfo(n : tnode;const l : TDFASet);
         procedure updatelifeinfo(n : tnode;const l : TDFASet);
-          var
-            b : boolean;
           begin
           begin
-            b:=DFASetNotEqual(l,n.optinfo^.life);
+            if not DFASetNotEqual(l,n.optinfo^.life) then
+              exit;
 {$ifdef DEBUG_DFA}
 {$ifdef DEBUG_DFA}
-            if not(changed) and b then
+            if not(changed) then
               begin
               begin
                 writeln('Another DFA pass caused by: ',nodetype2str[n.nodetype],'(',n.fileinfo.line,',',n.fileinfo.column,')');
                 writeln('Another DFA pass caused by: ',nodetype2str[n.nodetype],'(',n.fileinfo.line,',',n.fileinfo.column,')');
                 write('  Life info set was:     ');PrintDFASet(Output,n.optinfo^.life);writeln;
                 write('  Life info set was:     ');PrintDFASet(Output,n.optinfo^.life);writeln;
@@ -201,7 +200,7 @@ unit optdfa;
               end;
               end;
 {$endif DEBUG_DFA}
 {$endif DEBUG_DFA}
 
 
-            changed:=changed or b;
+            changed:=true;
             n.optinfo^.life:=l;
             n.optinfo^.life:=l;
           end;
           end;
 
 
@@ -238,9 +237,9 @@ unit optdfa;
           { ensure we've already optinfo set }
           { ensure we've already optinfo set }
           node.allocoptinfo;
           node.allocoptinfo;
 
 
-          if nf_processing in node.flags then
+          if tnf_processing in node.transientflags then
             exit;
             exit;
-          include(node.flags,nf_processing);
+          include(node.transientflags,tnf_processing);
 
 
           if assigned(node.successor) then
           if assigned(node.successor) then
             CreateInfo(node.successor);
             CreateInfo(node.successor);
@@ -610,7 +609,7 @@ unit optdfa;
           CreateInfo(node);
           CreateInfo(node);
           foreachnodestatic(pm_postprocess,node,@ResetProcessing,nil);
           foreachnodestatic(pm_postprocess,node,@ResetProcessing,nil);
           { the result node is not reached by foreachnodestatic }
           { the result node is not reached by foreachnodestatic }
-          exclude(resultnode.flags,nf_processing);
+          exclude(resultnode.transientflags,tnf_processing);
 {$ifdef DEBUG_DFA}
 {$ifdef DEBUG_DFA}
           PrintIndexedNodeSet(output,map);
           PrintIndexedNodeSet(output,map);
           PrintDFAInfo(output,node);
           PrintDFAInfo(output,node);
@@ -896,9 +895,9 @@ unit optdfa;
           if node=nil then
           if node=nil then
             exit;
             exit;
 
 
-          if nf_processing in node.flags then
+          if tnf_processing in node.transientflags then
             exit;
             exit;
-          include(node.flags,nf_processing);
+          include(node.transientflags,tnf_processing);
 
 
           if not(assigned(node.optinfo)) or not(DFASetIn(node.optinfo^.life,nodetosearch.optinfo^.index)) then
           if not(assigned(node.optinfo)) or not(DFASetIn(node.optinfo^.life,nodetosearch.optinfo^.index)) then
             exit;
             exit;

+ 2 - 2
compiler/options.pas

@@ -4758,9 +4758,9 @@ procedure read_arguments(cmd:TCmdStr);
       {$endif i8086 or avr}
       {$endif i8086 or avr}
       { abs(long) is handled internally on all CPUs }
       { abs(long) is handled internally on all CPUs }
         def_system_macro('FPC_HAS_INTERNAL_ABS_LONG');
         def_system_macro('FPC_HAS_INTERNAL_ABS_LONG');
-      {$if defined(i8086) or defined(i386) or defined(x86_64) or defined(powerpc64) or defined(aarch64)}
+      {$if defined(i8086) or defined(i386) or defined(x86_64) or defined(powerpc64) or defined(aarch64) or defined(arm)}
         def_system_macro('FPC_HAS_INTERNAL_ABS_INT64');
         def_system_macro('FPC_HAS_INTERNAL_ABS_INT64');
-      {$endif i8086 or i386 or x86_64 or powerpc64 or aarch64}
+      {$endif i8086 or i386 or x86_64 or powerpc64 or aarch64 or arm}
 
 
         def_system_macro('FPC_HAS_UNICODESTRING');
         def_system_macro('FPC_HAS_UNICODESTRING');
         def_system_macro('FPC_RTTI_PACKSET1');
         def_system_macro('FPC_RTTI_PACKSET1');

+ 1 - 1
compiler/optloop.pas

@@ -675,7 +675,7 @@ unit optloop;
                   cordconstnode.create(1,tfornode(n).left.resultdef,false));
                   cordconstnode.create(1,tfornode(n).left.resultdef,false));
                 tfornode(n).t1:=cordconstnode.create(1,tfornode(n).left.resultdef,false);
                 tfornode(n).t1:=cordconstnode.create(1,tfornode(n).left.resultdef,false);
                 include(tfornode(n).loopflags,lnf_counter_not_used);
                 include(tfornode(n).loopflags,lnf_counter_not_used);
-                exclude(n.flags,nf_pass1_done);
+                exclude(n.transientflags,tnf_pass1_done);
                 do_firstpass(n);
                 do_firstpass(n);
 {$ifdef DEBUG_OPTFORLOOP}
 {$ifdef DEBUG_OPTFORLOOP}
                 writeln('Loop reverted: ');
                 writeln('Loop reverted: ');

+ 1 - 1
compiler/optvirt.pas

@@ -590,7 +590,7 @@ unit optvirt;
         objparentsymtab:=objdef.symtable;
         objparentsymtab:=objdef.symtable;
         mainsymtab:=objparentsymtab.defowner.owner;
         mainsymtab:=objparentsymtab.defowner.owner;
         classprefix:='';
         classprefix:='';
-        while mainsymtab.symtabletype in [recordsymtable,objectsymtable] do
+        while mainsymtab.symtabletype in [recordsymtable,objectsymtable,localsymtable] do
           begin
           begin
             classprefix:=mainsymtab.name^+'.'+classprefix;
             classprefix:=mainsymtab.name^+'.'+classprefix;
             mainsymtab:=mainsymtab.defowner.owner;
             mainsymtab:=mainsymtab.defowner.owner;

+ 114 - 112
compiler/parser.pas

@@ -25,10 +25,14 @@ unit parser;
 
 
 interface
 interface
 
 
+uses fmodule;
+
 {$ifdef PREPROCWRITE}
 {$ifdef PREPROCWRITE}
     procedure preprocess(const filename:string);
     procedure preprocess(const filename:string);
 {$endif PREPROCWRITE}
 {$endif PREPROCWRITE}
-    procedure compile(const filename:string);
+    function compile(const filename:string) : boolean;
+    function compile_module(module : tmodule) : boolean;
+    procedure parsing_done(module : tmodule);
     procedure initparser;
     procedure initparser;
     procedure doneparser;
     procedure doneparser;
 
 
@@ -43,7 +47,7 @@ implementation
       cclasses,
       cclasses,
       globtype,tokens,systems,globals,verbose,switches,globstat,
       globtype,tokens,systems,globals,verbose,switches,globstat,
       symbase,symtable,symdef,
       symbase,symtable,symdef,
-      finput,fmodule,fppu,
+      finput,fppu,
       aasmdata,
       aasmdata,
       cscript,gendef,
       cscript,gendef,
       comphook,
       comphook,
@@ -51,12 +55,76 @@ implementation
       pbase,psystem,pmodules,psub,ncgrtti,
       pbase,psystem,pmodules,psub,ncgrtti,
       cpuinfo,procinfo;
       cpuinfo,procinfo;
 
 
+    procedure parsing_done(module: tmodule);
+
+    var
+       hp,hp2 :  tmodule;
+
+    begin
+
+       module.end_of_parsing;
+
+       if (module.is_initial) and
+          (status.errorcount=0) then
+         { Write Browser Collections }
+         do_extractsymbolinfo;
+
+       // olddata.restore(false);
+
+       { Restore all locally modified warning messages }
+       RestoreLocalVerbosity(current_settings.pmessage);
+       current_exceptblock:=0;
+       exceptblockcounter:=0;
+
+       { Shut down things when the last file is compiled succesfull }
+       if (module.is_initial) and (module.state=ms_compiled) and
+           (status.errorcount=0) then
+         begin
+           parser_current_file:='';
+           { Close script }
+           if (not AsmRes.Empty) then
+           begin
+             Message1(exec_i_closing_script,AsmRes.Fn);
+             AsmRes.WriteToDisk;
+           end;
+         end;
+
+     { free now what we did not free earlier in
+       proc_program PM }
+     if (module.is_initial) and (module.state=ms_compiled) and needsymbolinfo then
+       begin
+         hp:=tmodule(loaded_units.first);
+         while assigned(hp) do
+          begin
+            hp2:=tmodule(hp.next);
+            if (hp<>module) then
+              begin
+                loaded_units.remove(hp);
+                hp.free;
+              end;
+            hp:=hp2;
+          end;
+         { free also unneeded units we didn't free before }
+         unloaded_units.Clear;
+        end;
+
+      { If used units are compiled current_module is already the same as
+        the stored module. Now if the unit is not finished its scanner is
+        not yet freed and thus set_current_module would reopen the scanned
+        file which will result in pointing to the wrong position in the
+        file. In the normal case current_scanner and current_module.scanner
+        would be Nil, thus nothing bad would happen }
+{           if olddata.old_current_module<>current_module then
+        set_current_module(olddata.old_current_module);}
+
+      FreeLocalVerbosity(current_settings.pmessage);
+
+    end;
 
 
     procedure initparser;
     procedure initparser;
       begin
       begin
          { Current compiled module/proc }
          { Current compiled module/proc }
          set_current_module(nil);
          set_current_module(nil);
-         current_module:=nil;
          current_asmdata:=nil;
          current_asmdata:=nil;
          current_procinfo:=nil;
          current_procinfo:=nil;
          current_structdef:=nil;
          current_structdef:=nil;
@@ -83,7 +151,7 @@ implementation
          pattern:='';
          pattern:='';
          orgpattern:='';
          orgpattern:='';
          cstringpattern:='';
          cstringpattern:='';
-         current_scanner:=nil;
+         set_current_scanner(nil);
          switchesstatestackpos:=0;
          switchesstatestackpos:=0;
 
 
          { register all nodes and tais }
          { register all nodes and tais }
@@ -188,7 +256,6 @@ implementation
          { Reset current compiling info, so destroy routines can't
          { Reset current compiling info, so destroy routines can't
            reference the data that might already be destroyed }
            reference the data that might already be destroyed }
          set_current_module(nil);
          set_current_module(nil);
-         current_module:=nil;
          current_procinfo:=nil;
          current_procinfo:=nil;
          current_asmdata:=nil;
          current_asmdata:=nil;
          current_structdef:=nil;
          current_structdef:=nil;
@@ -217,7 +284,8 @@ implementation
          if assigned(current_scanner) then
          if assigned(current_scanner) then
           begin
           begin
             current_scanner.free;
             current_scanner.free;
-            current_scanner:=nil;
+            set_current_scanner(nil);
+
           end;
           end;
 
 
          { close scanner }
          { close scanner }
@@ -319,26 +387,38 @@ implementation
                              Compile a source file
                              Compile a source file
 *****************************************************************************}
 *****************************************************************************}
 
 
-    procedure compile(const filename:string);
+    function compile(const filename:string) : boolean;
+
+    var
+      m : TModule;
+
+    begin
+      m:=tppumodule.create(nil,'',filename,false);
+      m.state:=ms_compile;
+      result:=compile_module(m);
+    end;
+
+    function compile_module(module : tmodule) : boolean;
+
       var
       var
-         olddata : pglobalstate;
          hp,hp2 : tmodule;
          hp,hp2 : tmodule;
          finished : boolean;
          finished : boolean;
+         sc : tscannerfile;
+
        begin
        begin
+         Result:=True;
          { parsing a procedure or declaration should be finished }
          { parsing a procedure or declaration should be finished }
          if assigned(current_procinfo) then
          if assigned(current_procinfo) then
            internalerror(200811121);
            internalerror(200811121);
          if assigned(current_structdef) then
          if assigned(current_structdef) then
            internalerror(200811122);
            internalerror(200811122);
-         inc(compile_level);
-         parser_current_file:=filename;
+         inc(module.compilecount);
+         parser_current_file:=module.mainsource;
          { Uses heap memory instead of placing everything on the
          { Uses heap memory instead of placing everything on the
            stack. This is needed because compile() can be called
            stack. This is needed because compile() can be called
            recursively }
            recursively }
-         new(olddata);
          { handle the postponed case first }
          { handle the postponed case first }
          flushpendingswitchesstate;
          flushpendingswitchesstate;
-         save_global_state(olddata^,false);
 
 
        { reset parser, a previous fatal error could have left these variables in an unreliable state, this is
        { reset parser, a previous fatal error could have left these variables in an unreliable state, this is
          important for the IDE }
          important for the IDE }
@@ -350,7 +430,7 @@ implementation
          getfuncrefdef:=nil;
          getfuncrefdef:=nil;
 
 
        { show info }
        { show info }
-         Message1(parser_i_compiling,filename);
+         Message1(parser_i_compiling,module.mainsource);
 
 
        { reset symtable }
        { reset symtable }
          symtablestack:=tdefawaresymtablestack.create;
          symtablestack:=tdefawaresymtablestack.create;
@@ -365,33 +445,24 @@ implementation
          { Load current state from the init values }
          { Load current state from the init values }
          current_settings:=init_settings;
          current_settings:=init_settings;
 
 
-       { reset the unit or create a new program }
-         { a unit compiled at command line must be inside the loaded_unit list }
-         if (compile_level=1) then
-           begin
-             if assigned(current_module) then
-               internalerror(200501158);
-             set_current_module(tppumodule.create(nil,'',filename,false));
-             addloadedunit(current_module);
-             main_module:=current_module;
-             current_module.state:=ms_compile;
-           end;
-         if not(assigned(current_module) and
-                (current_module.state in [ms_compile,ms_second_compile])) then
+         set_current_module(module);
+         if not (module.state in [ms_compile]) then
            internalerror(200212281);
            internalerror(200212281);
 
 
          { load current asmdata from current_module }
          { load current asmdata from current_module }
-         current_asmdata:=TAsmData(current_module.asmdata);
+         current_asmdata:=TAsmData(module.asmdata);
 
 
          { startup scanner and load the first file }
          { startup scanner and load the first file }
-         current_scanner:=tscannerfile.Create(filename);
-         current_scanner.firstfile;
-         current_module.scanner:=current_scanner;
+         sc:=tscannerfile.Create(module.mainsource);
+         sc.firstfile;
+         module.scanner:=sc;
+         module.mainscanner:=sc;
+         set_current_scanner(sc);
 
 
          { init macros before anything in the file is parsed.}
          { init macros before anything in the file is parsed.}
-         current_module.localmacrosymtable:= tmacrosymtable.create(false);
+         module.localmacrosymtable:= tmacrosymtable.create(false);
          macrosymtablestack.push(initialmacrosymtable);
          macrosymtablestack.push(initialmacrosymtable);
-         macrosymtablestack.push(current_module.localmacrosymtable);
+         macrosymtablestack.push(module.localmacrosymtable);
 
 
          { read the first token }
          { read the first token }
          current_scanner.readtoken(false);
          current_scanner.readtoken(false);
@@ -403,18 +474,18 @@ implementation
            message if we are trying to use a program as unit.}
            message if we are trying to use a program as unit.}
          try
          try
            try
            try
-             if (token=_UNIT) or (compile_level>1) then
+             if (token=_UNIT) or (not module.is_initial) then
                begin
                begin
-                 current_module.is_unit:=true;
-                 finished:=proc_unit;
+                 module.is_unit:=true;
+                 finished:=proc_unit(module);
                end
                end
              else if (token=_ID) and (idtoken=_PACKAGE) then
              else if (token=_ID) and (idtoken=_PACKAGE) then
                begin
                begin
-                 current_module.IsPackage:=true;
-                 proc_package;
+                 module.IsPackage:=true;
+                 finished:=proc_package(module);
                end
                end
              else
              else
-               proc_program(token=_LIBRARY);
+               finished:=proc_program(module,token=_LIBRARY);
            except
            except
              on ECompilerAbort do
              on ECompilerAbort do
                raise;
                raise;
@@ -431,83 +502,14 @@ implementation
                  raise;
                  raise;
                end;
                end;
            end;
            end;
-
+           Result:=Finished;
            { the program or the unit at the command line should not need to wait
            { the program or the unit at the command line should not need to wait
              for other units }
              for other units }
-           if (compile_level=1) and not finished then
-             internalerror(2012091901);
+           // if (module.is_initial) and not finished then
+           //  internalerror(2012091901);
          finally
          finally
-           if assigned(current_module) then
-             begin
-               if finished then
-                 current_module.end_of_parsing
-               else
-                 begin
-                   { these are saved in the unit's state and thus can be set to
-                     Nil again as would be done by tmodule.end_of_parsing }
-                   macrosymtablestack:=nil;
-                   symtablestack:=nil;
-                   if current_scanner=current_module.scanner then
-                     current_scanner:=nil;
-                 end;
-             end;
-
-            if (compile_level=1) and
-               (status.errorcount=0) then
-              { Write Browser Collections }
-              do_extractsymbolinfo;
-
-            restore_global_state(olddata^,false);
-
-            { Restore all locally modified warning messages }
-            RestoreLocalVerbosity(current_settings.pmessage);
-            current_exceptblock:=0;
-            exceptblockcounter:=0;
-
-            { Shut down things when the last file is compiled succesfull }
-            if (compile_level=1) and
-                (status.errorcount=0) then
-              begin
-                parser_current_file:='';
-                { Close script }
-                if (not AsmRes.Empty) then
-                begin
-                  Message1(exec_i_closing_script,AsmRes.Fn);
-                  AsmRes.WriteToDisk;
-                end;
-              end;
-
-          { free now what we did not free earlier in
-            proc_program PM }
-          if (compile_level=1) and needsymbolinfo then
-            begin
-              hp:=tmodule(loaded_units.first);
-              while assigned(hp) do
-               begin
-                 hp2:=tmodule(hp.next);
-                 if (hp<>current_module) then
-                   begin
-                     loaded_units.remove(hp);
-                     hp.free;
-                   end;
-                 hp:=hp2;
-               end;
-              { free also unneeded units we didn't free before }
-              unloaded_units.Clear;
-             end;
-           dec(compile_level);
-           { If used units are compiled current_module is already the same as
-             the stored module. Now if the unit is not finished its scanner is
-             not yet freed and thus set_current_module would reopen the scanned
-             file which will result in pointing to the wrong position in the
-             file. In the normal case current_scanner and current_module.scanner
-             would be Nil, thus nothing bad would happen }
-           if olddata^.old_current_module<>current_module then
-             set_current_module(olddata^.old_current_module);
-
-           FreeLocalVerbosity(current_settings.pmessage);
-
-           dispose(olddata);
+            if finished then
+              parsing_done(module);
          end;
          end;
     end;
     end;
 
 

+ 11 - 12
compiler/pass_1.pas

@@ -87,7 +87,7 @@ implementation
               assigned(hp.resultdef);
               assigned(hp.resultdef);
         if codegenerror then
         if codegenerror then
           begin
           begin
-            include(p.flags,nf_error);
+            include(p.transientflags,tnf_error);
             { default to errortype if no type is set yet }
             { default to errortype if no type is set yet }
             if p.resultdef=nil then
             if p.resultdef=nil then
               p.resultdef:=generrordef;
               p.resultdef:=generrordef;
@@ -117,7 +117,7 @@ implementation
         else
         else
           begin
           begin
             { update the codegenerror boolean with the previous result of this node }
             { update the codegenerror boolean with the previous result of this node }
-            if (nf_error in p.flags) then
+            if (tnf_error in p.transientflags) then
               codegenerror:=true;
               codegenerror:=true;
           end;
           end;
       end;
       end;
@@ -156,10 +156,10 @@ implementation
          hp : tnode;
          hp : tnode;
          nodechanged : boolean;
          nodechanged : boolean;
       begin
       begin
-         if (nf_pass1_done in p.flags) then
+         if (tnf_pass1_done in p.transientflags) then
            exit;
            exit;
 
 
-         if not(nf_error in p.flags) then
+         if not(tnf_error in p.transientflags) then
            begin
            begin
              oldcodegenerror:=codegenerror;
              oldcodegenerror:=codegenerror;
              oldpos:=current_filepos;
              oldpos:=current_filepos;
@@ -168,8 +168,8 @@ implementation
              codegenerror:=false;
              codegenerror:=false;
              repeat
              repeat
                { The error flag takes precedence over the 'do not execute' flag,
                { The error flag takes precedence over the 'do not execute' flag,
-                 as its assumed the node tree isn't tenable beyond this point }
-               if (nf_do_not_execute in p.flags) then
+                 as it's assumed the node tree isn't tenable beyond this point }
+               if (tnf_do_not_execute in p.transientflags) then
                  InternalError(2022112401);
                  InternalError(2022112401);
 
 
                { checks make always a call }
                { checks make always a call }
@@ -182,7 +182,7 @@ implementation
                  end;
                  end;
 
 
                hp:=nil;
                hp:=nil;
-               if not(nf_error in p.flags) then
+               if not(tnf_error in p.transientflags) then
                  begin
                  begin
                    current_filepos:=p.fileinfo;
                    current_filepos:=p.fileinfo;
                    current_settings.localswitches:=p.localswitches;
                    current_settings.localswitches:=p.localswitches;
@@ -196,19 +196,18 @@ implementation
                    { should the node be replaced? }
                    { should the node be replaced? }
                    if assigned(hp) then
                    if assigned(hp) then
                      begin
                      begin
-                       hp.flags := hp.flags + (p.flags * [nf_usercode_entry]);
                        p.free;
                        p.free;
                        { switch to new node }
                        { switch to new node }
                        p:=hp;
                        p:=hp;
                      end;
                      end;
                    if codegenerror then
                    if codegenerror then
-                     include(p.flags,nf_error);
+                     include(p.transientflags,tnf_error);
                  end;
                  end;
              until not assigned(hp) or
              until not assigned(hp) or
-                   (nf_pass1_done in hp.flags);
-             include(p.flags,nf_pass1_done);
+                   (tnf_pass1_done in hp.transientflags);
+             include(p.transientflags,tnf_pass1_done);
 {$ifdef EXTDEBUG}
 {$ifdef EXTDEBUG}
-             if not(nf_error in p.flags) then
+             if not(tnf_error in p.transientflags) then
                begin
                begin
                  if (p.expectloc=LOC_INVALID) then
                  if (p.expectloc=LOC_INVALID) then
                    Comment(V_Warning,'Expectloc is not set in firstpass: '+nodetype2str[p.nodetype]);
                    Comment(V_Warning,'Expectloc is not set in firstpass: '+nodetype2str[p.nodetype]);

+ 5 - 5
compiler/pass_2.pas

@@ -187,11 +187,11 @@ implementation
       begin
       begin
          if not assigned(p) then
          if not assigned(p) then
           internalerror(200208221);
           internalerror(200208221);
-         if not(nf_error in p.flags) then
+         if not(tnf_error in p.transientflags) then
           begin
           begin
             { The error flag takes precedence over the 'do not execute' flag,
             { The error flag takes precedence over the 'do not execute' flag,
-              as its assumed the node tree isn't tenable beyond this point }
-            if (nf_do_not_execute in p.flags) then
+              as it's assumed the node tree isn't tenable beyond this point }
+            if (tnf_do_not_execute in p.transientflags) then
               InternalError(2022112402);
               InternalError(2022112402);
 
 
             oldcodegenerror:=codegenerror;
             oldcodegenerror:=codegenerror;
@@ -237,7 +237,7 @@ implementation
              end;
              end;
 {$endif EXTDEBUG}
 {$endif EXTDEBUG}
             if codegenerror then
             if codegenerror then
-              include(p.flags,nf_error);
+              include(p.transientflags,tnf_error);
             codegenerror:=codegenerror or oldcodegenerror;
             codegenerror:=codegenerror or oldcodegenerror;
             current_settings.localswitches:=oldlocalswitches;
             current_settings.localswitches:=oldlocalswitches;
             current_filepos:=oldpos;
             current_filepos:=oldpos;
@@ -256,7 +256,7 @@ implementation
 
 
          { clear errors before starting }
          { clear errors before starting }
          codegenerror:=false;
          codegenerror:=false;
-         if not(nf_error in p.flags) then
+         if not(tnf_error in p.transientflags) then
            secondpass(p);
            secondpass(p);
          do_secondpass:=codegenerror;
          do_secondpass:=codegenerror;
       end;
       end;

+ 20 - 1
compiler/pbase.pas

@@ -76,6 +76,10 @@ interface
     { a syntax error is written                           }
     { a syntax error is written                           }
     procedure consume(i : ttoken);
     procedure consume(i : ttoken);
 
 
+    { Same as consume, but will not attempt to read next token if the token is a point }
+
+    procedure consume_last_dot;
+
     {Tries to consume the token i, and returns true if it was consumed:
     {Tries to consume the token i, and returns true if it was consumed:
      if token=i.}
      if token=i.}
     function try_to_consume(i:Ttoken):boolean;
     function try_to_consume(i:Ttoken):boolean;
@@ -144,8 +148,10 @@ implementation
 
 
 
 
     { consumes token i, write error if token is different }
     { consumes token i, write error if token is different }
+
     procedure consume(i : ttoken);
     procedure consume(i : ttoken);
-      begin
+
+    begin
         if (token<>i) and (idtoken<>i) then
         if (token<>i) and (idtoken<>i) then
           if token=_id then
           if token=_id then
             Message2(scan_f_syn_expected,tokeninfo^[i].str,'identifier '+pattern)
             Message2(scan_f_syn_expected,tokeninfo^[i].str,'identifier '+pattern)
@@ -159,6 +165,19 @@ implementation
           end;
           end;
       end;
       end;
 
 
+    procedure consume_last_dot;
+
+    begin
+        if (token<>_POINT) then
+          begin
+          if token=_id then
+            Message2(scan_f_syn_expected,tokeninfo^[_POINT].str,'identifier '+pattern)
+          else
+            Message2(scan_f_syn_expected,tokeninfo^[_POINT].str,tokeninfo^[token].str)
+          end
+        else if c<>#0 then
+          current_scanner.readtoken(true);
+    end;
 
 
     function try_to_consume(i:Ttoken):boolean;
     function try_to_consume(i:Ttoken):boolean;
       begin
       begin

+ 1 - 2
compiler/pdecl.pas

@@ -781,7 +781,6 @@ implementation
                genorgtypename:=orgtypename;
                genorgtypename:=orgtypename;
              end;
              end;
 
 
-
            consume(_EQ);
            consume(_EQ);
 
 
            { support 'ttype=type word' syntax }
            { support 'ttype=type word' syntax }
@@ -1362,7 +1361,7 @@ implementation
                                  changestringtype(cunicodestringtype);
                                  changestringtype(cunicodestringtype);
                                initwidestring(pw);
                                initwidestring(pw);
                                copywidestring(pcompilerwidestring(value_str),pw);
                                copywidestring(pcompilerwidestring(value_str),pw);
-                               sym:=cconstsym.create_wstring(orgname,constresourcestring,pw);
+                               sym:=cconstsym.create_wstring(orgname,constwresourcestring,pw);
                                end;
                                end;
                           end;
                           end;
                       else
                       else

+ 63 - 18
compiler/pdecobj.pas

@@ -589,7 +589,7 @@ implementation
                        end
                        end
                      else
                      else
                        if oo_is_sealed in childof.objectoptions then
                        if oo_is_sealed in childof.objectoptions then
-                         Message1(parser_e_sealed_descendant,childof.typename)
+                         Message1(parser_e_sealed_descendant,childof.typesymbolprettyname)
                        else
                        else
                          childof:=find_real_class_definition(childof,true);
                          childof:=find_real_class_definition(childof,true);
                    odt_interfacecorba,
                    odt_interfacecorba,
@@ -774,6 +774,9 @@ implementation
           Internalerror(2011021103);
           Internalerror(2011021103);
 
 
         consume(_FOR);
         consume(_FOR);
+        { set extendeddef to non-Nil so that potential checks for it won't trigger
+          access violations }
+        current_objectdef.extendeddef:=generrordef;
         single_type(hdef,[stoParseClassParent]);
         single_type(hdef,[stoParseClassParent]);
         if not assigned(hdef) or (hdef.typ=errordef) then
         if not assigned(hdef) or (hdef.typ=errordef) then
           begin
           begin
@@ -837,9 +840,7 @@ implementation
           end;
           end;
 
 
         if assigned(hdef) then
         if assigned(hdef) then
-          current_objectdef.extendeddef:=hdef
-        else
-          current_objectdef.extendeddef:=generrordef;
+          current_objectdef.extendeddef:=hdef;
       end;
       end;
 
 
     procedure parse_guid;
     procedure parse_guid;
@@ -1083,7 +1084,8 @@ implementation
         vdoptions: tvar_dec_options;
         vdoptions: tvar_dec_options;
         fieldlist: tfpobjectlist;
         fieldlist: tfpobjectlist;
         rtti_attrs_def: trtti_attribute_list;
         rtti_attrs_def: trtti_attribute_list;
-
+        attr_element_count,fldCount : Integer;
+        method_def : tprocdef;
 
 
       procedure parse_const;
       procedure parse_const;
         begin
         begin
@@ -1241,7 +1243,6 @@ implementation
               end;
               end;
             _ID :
             _ID :
               begin
               begin
-                check_unbound_attributes;
                 if is_objcprotocol(current_structdef) and
                 if is_objcprotocol(current_structdef) and
                    ((idtoken=_REQUIRED) or
                    ((idtoken=_REQUIRED) or
                     (idtoken=_OPTIONAL)) then
                     (idtoken=_OPTIONAL)) then
@@ -1322,7 +1323,6 @@ implementation
                       begin
                       begin
                         if object_member_blocktype=bt_general then
                         if object_member_blocktype=bt_general then
                           begin
                           begin
-                            rtti_attrs_def := nil;
                             if (idtoken=_GENERIC) and
                             if (idtoken=_GENERIC) and
                                 not (m_delphi in current_settings.modeswitches) and
                                 not (m_delphi in current_settings.modeswitches) and
                                 (
                                 (
@@ -1366,13 +1366,47 @@ implementation
                                   include(vdoptions,vd_final);
                                   include(vdoptions,vd_final);
                                 if threadvar_fields then
                                 if threadvar_fields then
                                   include(vdoptions,vd_threadvar);
                                   include(vdoptions,vd_threadvar);
-                                read_record_fields(vdoptions,fieldlist,nil,hadgeneric);
+                                // Record count
+                                fldCount:=FieldList.Count;
+                                read_record_fields(vdoptions,fieldlist,nil,hadgeneric,attr_element_count);
+                                {
+                                  attr_element_count returns the number of fields to which the attribute must be applied.
+                                  For
+                                  [someattr]
+                                  a : integer;
+                                  b : integer;
+                                  attr_element_count returns 1. For
+                                  [someattr]
+                                  a, b : integer;
+                                  it returns 2.
+                                  Basically the number of variables before the first colon.
+                                }
+                                if assigned(rtti_attrs_def) then
+                                  begin
+                                  { read_record_fields can read a list of fields with the same type.
+                                    for the first fields, we simply copy. for the last one we bind.}
+                                  While (attr_element_count>1) do
+                                    begin
+                                    trtti_attribute_list.copyandbind(rtti_attrs_def,tfieldvarsym(fieldlist[FldCount]).rtti_attribute_list);
+                                    inc(fldcount);
+                                    dec(attr_element_count);
+                                    end;
+                                  if fldCount<FieldList.Count then
+                                    trtti_attribute_list.bind(rtti_attrs_def,tfieldvarsym(fieldlist[FldCount]).rtti_attribute_list)
+                                  else
+                                    rtti_attrs_def.free;
+                                  end;
+                                rtti_attrs_def:=nil;
                               end;
                               end;
                           end
                           end
                         else if object_member_blocktype=bt_type then
                         else if object_member_blocktype=bt_type then
+                          begin
+                          check_unbound_attributes;
                           types_dec(true,hadgeneric, rtti_attrs_def)
                           types_dec(true,hadgeneric, rtti_attrs_def)
+                          end
                         else if object_member_blocktype=bt_const then
                         else if object_member_blocktype=bt_const then
                           begin
                           begin
+                            check_unbound_attributes;
                             typedconstswritable:=false;
                             typedconstswritable:=false;
                             if final_fields then
                             if final_fields then
                               begin
                               begin
@@ -1393,9 +1427,6 @@ implementation
               end;
               end;
             _PROPERTY :
             _PROPERTY :
               begin
               begin
-                { for now attributes are only allowed on published properties }
-                if current_structdef.symtable.currentvisibility<>vis_published then
-                  check_unbound_attributes;
                 struct_property_dec(is_classdef, rtti_attrs_def);
                 struct_property_dec(is_classdef, rtti_attrs_def);
                 fields_allowed:=false;
                 fields_allowed:=false;
                 is_classdef:=false;
                 is_classdef:=false;
@@ -1412,9 +1443,12 @@ implementation
             _CONSTRUCTOR,
             _CONSTRUCTOR,
             _DESTRUCTOR :
             _DESTRUCTOR :
               begin
               begin
-                check_unbound_attributes;
-                rtti_attrs_def := nil;
-                method_dec(current_structdef,is_classdef,hadgeneric);
+                method_def:=method_dec(current_structdef,is_classdef,hadgeneric);
+                if assigned(rtti_attrs_def) then
+                  begin
+                  trtti_attribute_list.bind(rtti_attrs_def,method_def.rtti_attribute_list);
+                  rtti_attrs_def:=nil;
+                  end;
                 fields_allowed:=false;
                 fields_allowed:=false;
                 is_classdef:=false;
                 is_classdef:=false;
                 hadgeneric:=false;
                 hadgeneric:=false;
@@ -1672,6 +1706,14 @@ implementation
             { apply $RTTI directive to current object }
             { apply $RTTI directive to current object }
             current_structdef.apply_rtti_directive(current_module.rtti_directive);
             current_structdef.apply_rtti_directive(current_module.rtti_directive);
 
 
+            { generate TObject VMT space }
+            { We must insert the VMT at the start for system.tobject, and class_tobject was already set.
+              The cs_compilesystem is superfluous, but we add it for safety.
+
+            }
+            if (current_objectdef=class_tobject) and (cs_compilesystem in current_settings.moduleswitches) then
+              current_objectdef.insertvmt;
+
             { parse and insert object members }
             { parse and insert object members }
             parse_object_members;
             parse_object_members;
 
 
@@ -1705,15 +1747,18 @@ implementation
           end;
           end;
 
 
         { generate vmt space if needed }
         { generate vmt space if needed }
+        {
+           Here we only do it for non-classes, all classes have it since they depend on TObject
+           so their vmt is already created when TObject was parsed.
+        }
         if not(oo_has_vmt in current_structdef.objectoptions) and
         if not(oo_has_vmt in current_structdef.objectoptions) and
+           not(current_objectdef.objecttype in [odt_class]) and
            not(oo_is_forward in current_structdef.objectoptions) and
            not(oo_is_forward in current_structdef.objectoptions) and
            not(parse_generic) and
            not(parse_generic) and
            { no vmt for helpers ever }
            { no vmt for helpers ever }
            not is_objectpascal_helper(current_structdef) and
            not is_objectpascal_helper(current_structdef) and
-           (
-            ([oo_has_virtual,oo_has_constructor,oo_has_destructor]*current_structdef.objectoptions<>[]) or
-            (current_objectdef.objecttype in [odt_class])
-           ) then
+            ([oo_has_virtual,oo_has_constructor,oo_has_destructor]*current_structdef.objectoptions<>[])
+           then
           current_objectdef.insertvmt;
           current_objectdef.insertvmt;
 
 
         { for implemented classes with a vmt check if there is a constructor }
         { for implemented classes with a vmt check if there is a constructor }

+ 8 - 3
compiler/pdecvar.pas

@@ -38,7 +38,7 @@ interface
 
 
     procedure read_var_decls(options:Tvar_dec_options;out had_generic:boolean);
     procedure read_var_decls(options:Tvar_dec_options;out had_generic:boolean);
 
 
-    procedure read_record_fields(options:Tvar_dec_options; reorderlist: TFPObjectList; variantdesc: ppvariantrecdesc;out had_generic:boolean);
+    procedure read_record_fields(options:Tvar_dec_options; reorderlist: TFPObjectList; variantdesc: ppvariantrecdesc;out had_generic:boolean; out attr_element_count : integer);
 
 
     procedure read_public_and_external(vs: tabstractvarsym);
     procedure read_public_and_external(vs: tabstractvarsym);
 
 
@@ -1679,7 +1679,7 @@ implementation
       end;
       end;
 
 
 
 
-    procedure read_record_fields(options:Tvar_dec_options; reorderlist: TFPObjectList; variantdesc : ppvariantrecdesc;out had_generic:boolean);
+    procedure read_record_fields(options:Tvar_dec_options; reorderlist: TFPObjectList; variantdesc : ppvariantrecdesc;out had_generic:boolean; out attr_element_count : integer);
       var
       var
          sc : TFPObjectList;
          sc : TFPObjectList;
          i  : longint;
          i  : longint;
@@ -1707,6 +1707,7 @@ implementation
          hadgendummy,
          hadgendummy,
          semicoloneaten,
          semicoloneaten,
          removeclassoption: boolean;
          removeclassoption: boolean;
+         dummyattrelementcount : integer;
 {$if defined(powerpc) or defined(powerpc64)}
 {$if defined(powerpc) or defined(powerpc64)}
          tempdef: tdef;
          tempdef: tdef;
          is_first_type: boolean;
          is_first_type: boolean;
@@ -1727,6 +1728,7 @@ implementation
          sc:=TFPObjectList.create(false);
          sc:=TFPObjectList.create(false);
          removeclassoption:=false;
          removeclassoption:=false;
          had_generic:=false;
          had_generic:=false;
+         attr_element_count:=0;
          while (token=_ID) and
          while (token=_ID) and
             not(((vd_object in options) or
             not(((vd_object in options) or
                  ((vd_record in options) and (m_advanced_records in current_settings.modeswitches))) and
                  ((vd_record in options) and (m_advanced_records in current_settings.modeswitches))) and
@@ -1775,6 +1777,9 @@ implementation
              if had_generic and (sc.count=0) then
              if had_generic and (sc.count=0) then
                break;
                break;
              consume(_COLON);
              consume(_COLON);
+             if attr_element_count=0 then
+               attr_element_count:=sc.Count;
+
              typepos:=current_filepos;
              typepos:=current_filepos;
 
 
              read_anon_type(hdef,false);
              read_anon_type(hdef,false);
@@ -2056,7 +2061,7 @@ implementation
                 consume(_LKLAMMER);
                 consume(_LKLAMMER);
                 inc(variantrecordlevel);
                 inc(variantrecordlevel);
                 if token<>_RKLAMMER then
                 if token<>_RKLAMMER then
-                  read_record_fields([vd_record],nil,@variantdesc^^.branches[high(variantdesc^^.branches)].nestedvariant,hadgendummy);
+                  read_record_fields([vd_record],nil,@variantdesc^^.branches[high(variantdesc^^.branches)].nestedvariant,hadgendummy,dummyattrelementcount);
                 dec(variantrecordlevel);
                 dec(variantrecordlevel);
                 consume(_RKLAMMER);
                 consume(_RKLAMMER);
 
 

+ 17 - 8
compiler/pexpr.pas

@@ -2349,8 +2349,8 @@ implementation
                                     { Support mem[$a000:$0000..$07ff] which returns array [0..$7ff] of memtype.}
                                     { Support mem[$a000:$0000..$07ff] which returns array [0..$7ff] of memtype.}
                                     p2:=crangenode.create(p2,caddnode.create(addn,comp_expr([ef_accept_equal]),p3.getcopy));
                                     p2:=crangenode.create(p2,caddnode.create(addn,comp_expr([ef_accept_equal]),p3.getcopy));
                                   p1:=cvecnode.create(p1,p2);
                                   p1:=cvecnode.create(p1,p2);
-                                  include(tvecnode(p1).flags,nf_memseg);
-                                  include(tvecnode(p1).flags,nf_memindex);
+                                  include(tvecnode(p1).vecnodeflags,vnf_memseg);
+                                  include(tvecnode(p1).vecnodeflags,vnf_memindex);
                                 end
                                 end
                                else
                                else
                                 begin
                                 begin
@@ -2358,7 +2358,7 @@ implementation
                                     { Support mem[$80000000..$80000002] which returns array [0..2] of memtype.}
                                     { Support mem[$80000000..$80000002] which returns array [0..2] of memtype.}
                                     p2:=crangenode.create(p2,comp_expr([ef_accept_equal]));
                                     p2:=crangenode.create(p2,comp_expr([ef_accept_equal]));
                                   p1:=cvecnode.create(p1,p2);
                                   p1:=cvecnode.create(p1,p2);
-                                  include(tvecnode(p1).flags,nf_memindex);
+                                  include(tvecnode(p1).vecnodeflags,vnf_memindex);
                                 end;
                                 end;
 {$else}
 {$else}
                                internalerror(2013053105);
                                internalerror(2013053105);
@@ -3121,7 +3121,7 @@ implementation
 
 
           constsym :
           constsym :
             begin
             begin
-              if tconstsym(srsym).consttyp=constresourcestring then
+              if tconstsym(srsym).consttyp in [constresourcestring,constwresourcestring]then
                 begin
                 begin
                   result:=cloadnode.create(srsym,srsymtable);
                   result:=cloadnode.create(srsym,srsymtable);
                   do_typecheckpass(result);
                   do_typecheckpass(result);
@@ -3639,7 +3639,8 @@ implementation
                end;
                end;
            { there could be more elements }
            { there could be more elements }
            until not try_to_consume(_COMMA);
            until not try_to_consume(_COMMA);
-           buildp.allow_array_constructor:=block_type in [bt_body,bt_except];
+           if block_type in [bt_body,bt_except] then
+             Include(buildp.arrayconstructornodeflags, acnf_allow_array_constructor);
            factor_read_set:=buildp;
            factor_read_set:=buildp;
          end;
          end;
 
 
@@ -4829,14 +4830,14 @@ implementation
                  begin
                  begin
                    p1:=caddnode.create(orn,p1,p2);
                    p1:=caddnode.create(orn,p1,p2);
                    if (oldt = _PIPE) then
                    if (oldt = _PIPE) then
-                     include(p1.flags,nf_short_bool);
+                     include(taddnode(p1).addnodeflags,anf_short_bool);
                  end;
                  end;
                _OP_AND,
                _OP_AND,
                _AMPERSAND {macpas only} :
                _AMPERSAND {macpas only} :
                  begin
                  begin
                    p1:=caddnode.create(andn,p1,p2);
                    p1:=caddnode.create(andn,p1,p2);
                    if (oldt = _AMPERSAND) then
                    if (oldt = _AMPERSAND) then
-                     include(p1.flags,nf_short_bool);
+                     include(taddnode(p1).addnodeflags,anf_short_bool);
                  end;
                  end;
                _OP_DIV :
                _OP_DIV :
                  p1:=cmoddivnode.create(divn,p1,p2);
                  p1:=cmoddivnode.create(divn,p1,p2);
@@ -4846,7 +4847,7 @@ implementation
                  begin
                  begin
                    p1:=cmoddivnode.create(modn,p1,p2);
                    p1:=cmoddivnode.create(modn,p1,p2);
                    if m_isolike_mod in current_settings.modeswitches then
                    if m_isolike_mod in current_settings.modeswitches then
-                     include(p1.flags,nf_isomod);
+                     include(tmoddivnode(p1).moddivnodeflags,mdnf_isomod);
                  end;
                  end;
                _OP_SHL :
                _OP_SHL :
                  p1:=cshlshrnode.create(shln,p1,p2);
                  p1:=cshlshrnode.create(shln,p1,p2);
@@ -4952,24 +4953,32 @@ implementation
              end;
              end;
            _PLUSASN :
            _PLUSASN :
              begin
              begin
+               if not(cs_support_c_operators in current_settings.moduleswitches) then
+                 Message(parser_e_coperators_off);
                consume(_PLUSASN);
                consume(_PLUSASN);
                p2:=sub_expr(opcompare,[ef_accept_equal],nil);
                p2:=sub_expr(opcompare,[ef_accept_equal],nil);
                p1:=gen_c_style_operator(addn,p1,p2);
                p1:=gen_c_style_operator(addn,p1,p2);
             end;
             end;
           _MINUSASN :
           _MINUSASN :
             begin
             begin
+               if not(cs_support_c_operators in current_settings.moduleswitches) then
+                 Message(parser_e_coperators_off);
                consume(_MINUSASN);
                consume(_MINUSASN);
                p2:=sub_expr(opcompare,[ef_accept_equal],nil);
                p2:=sub_expr(opcompare,[ef_accept_equal],nil);
                p1:=gen_c_style_operator(subn,p1,p2);
                p1:=gen_c_style_operator(subn,p1,p2);
             end;
             end;
           _STARASN :
           _STARASN :
             begin
             begin
+               if not(cs_support_c_operators in current_settings.moduleswitches) then
+                 Message(parser_e_coperators_off);
                consume(_STARASN  );
                consume(_STARASN  );
                p2:=sub_expr(opcompare,[ef_accept_equal],nil);
                p2:=sub_expr(opcompare,[ef_accept_equal],nil);
                p1:=gen_c_style_operator(muln,p1,p2);
                p1:=gen_c_style_operator(muln,p1,p2);
             end;
             end;
           _SLASHASN :
           _SLASHASN :
             begin
             begin
+               if not(cs_support_c_operators in current_settings.moduleswitches) then
+                 Message(parser_e_coperators_off);
                consume(_SLASHASN  );
                consume(_SLASHASN  );
                p2:=sub_expr(opcompare,[ef_accept_equal],nil);
                p2:=sub_expr(opcompare,[ef_accept_equal],nil);
                p1:=gen_c_style_operator(slashn,p1,p2);
                p1:=gen_c_style_operator(slashn,p1,p2);

+ 17 - 5
compiler/pgenutil.pas

@@ -269,7 +269,7 @@ uses
         if hmodule=current_module then
         if hmodule=current_module then
           exit;
           exit;
 
 
-        if hmodule.state<>ms_compiled then
+        if not (hmodule.state in [ms_compiled,ms_processed]) then
           begin
           begin
 {$ifdef DEBUG_UNITWAITING}
 {$ifdef DEBUG_UNITWAITING}
             Writeln('Unit ', current_module.modulename^,
             Writeln('Unit ', current_module.modulename^,
@@ -2001,12 +2001,18 @@ uses
                     else
                     else
                       begin
                       begin
                         hadtypetoken:=false;
                         hadtypetoken:=false;
+
+                        { ensure a pretty name for error messages, might be chanced below }
+                        if _prettyname<>'' then
+                          ttypesym(srsym).fprettyname:=_prettyname
+                        else
+                          ttypesym(srsym).fprettyname:=prettyname;
+
                         read_named_type(result,srsym,genericdef,generictypelist,false,hadtypetoken);
                         read_named_type(result,srsym,genericdef,generictypelist,false,hadtypetoken);
                         ttypesym(srsym).typedef:=result;
                         ttypesym(srsym).typedef:=result;
                         result.typesym:=srsym;
                         result.typesym:=srsym;
                       end;
                       end;
 
 
-
                     if _prettyname<>'' then
                     if _prettyname<>'' then
                       ttypesym(result.typesym).fprettyname:=_prettyname
                       ttypesym(result.typesym).fprettyname:=_prettyname
                     else
                     else
@@ -2859,8 +2865,11 @@ uses
                   ) and
                   ) and
                   { may not be assigned in case it's a synthetic procdef that
                   { may not be assigned in case it's a synthetic procdef that
                     still needs to be generated }
                     still needs to be generated }
-                  assigned(tprocdef(hp).genericdef) and
-                  tprocdef(tprocdef(hp).genericdef).forwarddef then
+                  (assigned(tprocdef(hp).genericdef) and
+                  tprocdef(tprocdef(hp).genericdef).forwarddef)
+                  { when the implementation of the module was not yet parsed, it will not yet have a generictokenbuf }
+                  or not assigned(tprocdef(tprocdef(hp).genericdef).generictokenbuf) then
+
                  begin
                  begin
                    result:=false;
                    result:=false;
                    continue;
                    continue;
@@ -2883,6 +2892,8 @@ uses
         def : tstoreddef;
         def : tstoreddef;
         state : tspecializationstate;
         state : tspecializationstate;
         hmodule : tmodule;
         hmodule : tmodule;
+        mstate : tmodulestate;
+
       begin
       begin
         { first copy all entries and then work with that list to ensure that
         { first copy all entries and then work with that list to ensure that
           we don't get an infinite recursion }
           we don't get an infinite recursion }
@@ -2914,7 +2925,8 @@ uses
                   { we need to check for a forward declaration only if the
                   { we need to check for a forward declaration only if the
                     generic was declared in the same unit (otherwise there
                     generic was declared in the same unit (otherwise there
                     should be one) }
                     should be one) }
-                  if ((hmodule=current_module) or (hmodule.state=ms_compile)) and tprocdef(def.genericdef).forwarddef then
+                  mstate:=hmodule.state;
+                  if ((hmodule=current_module) or (hmodule.state<ms_compiling_waitfinish)) and tprocdef(def.genericdef).forwarddef then
                     begin
                     begin
                       readdlist.add(def);
                       readdlist.add(def);
                       continue;
                       continue;

+ 1 - 1
compiler/pinline.pas

@@ -277,7 +277,7 @@ implementation
                 if is_new then
                 if is_new then
                   begin
                   begin
                     p2:=cderefnode.create(p.getcopy);
                     p2:=cderefnode.create(p.getcopy);
-                    include(p2.flags,nf_no_checkpointer);
+                    include(TDerefNode(p2).derefnodeflags,drnf_no_checkpointer);
                   end
                   end
                 else
                 else
                   p2:=cderefnode.create(p);
                   p2:=cderefnode.create(p);

File diff suppressed because it is too large
+ 589 - 230
compiler/pmodules.pas


+ 2 - 0
compiler/pparautl.pas

@@ -369,6 +369,8 @@ implementation
                  hs:=pd.resultname^
                  hs:=pd.resultname^
                else
                else
                  hs:=pd.procsym.name;
                  hs:=pd.procsym.name;
+               if (hs='') then
+                 hs:='$_result';
                sl:=tpropaccesslist.create;
                sl:=tpropaccesslist.create;
                sl.addsym(sl_load,pd.funcretsym);
                sl.addsym(sl_load,pd.funcretsym);
                aliasvs:=cabsolutevarsym.create_ref(hs,pd.returndef,sl);
                aliasvs:=cabsolutevarsym.create_ref(hs,pd.returndef,sl);

+ 1 - 1
compiler/ppcgen/ngppcadd.pas

@@ -223,7 +223,7 @@ implementation
 
 
         if {$ifndef cpu64bitalu}(cgsize<>OS_64) and{$endif}
         if {$ifndef cpu64bitalu}(cgsize<>OS_64) and{$endif}
            (((cs_full_boolean_eval in current_settings.localswitches) and
            (((cs_full_boolean_eval in current_settings.localswitches) and
-             not(nf_short_bool in flags)) or
+             not(anf_short_bool in addnodeflags)) or
             (nodetype in [unequaln,ltn,lten,gtn,gten,equaln,xorn])) then
             (nodetype in [unequaln,ltn,lten,gtn,gten,equaln,xorn])) then
           begin
           begin
             if left.nodetype in [ordconstn,realconstn] then
             if left.nodetype in [ordconstn,realconstn] then

+ 87 - 0
compiler/ppcloongarch64.lpi

@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="12"/>
+    <PathDelim Value="\"/>
+    <General>
+      <Flags>
+        <MainUnitHasUsesSectionForAllUnits Value="False"/>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+        <LRSInOutputDirectory Value="False"/>
+        <CompatibilityMode Value="True"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <Title Value="loongarch64"/>
+    </General>
+    <BuildModes Count="1">
+      <Item1 Name="default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+    </PublishOptions>
+    <RunParams>
+      <local>
+        <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T &apos;Lazarus Run Output&apos; -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/>
+      </local>
+      <FormatVersion Value="2"/>
+      <Modes Count="1">
+        <Mode0 Name="default">
+          <local>
+            <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T &apos;Lazarus Run Output&apos; -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/>
+          </local>
+        </Mode0>
+      </Modes>
+    </RunParams>
+    <Units Count="4">
+      <Unit0>
+        <Filename Value="pp.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit0>
+      <Unit1>
+        <Filename Value="loongarch64\aasmcpu.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit1>
+      <Unit2>
+        <Filename Value="loongarch64\aoptcpu.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit2>
+      <Unit3>
+        <Filename Value="aopt.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit3>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <PathDelim Value="\"/>
+    <Target>
+      <Filename Value="loongarch64\pp"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="loongarch64"/>
+      <OtherUnitFiles Value="loongarch64;systems"/>
+      <UnitOutputDirectory Value="loongarch64\lazbuild"/>
+    </SearchPaths>
+    <Parsing>
+      <SyntaxOptions>
+        <CStyleOperator Value="False"/>
+        <AllowLabel Value="False"/>
+        <CPPInline Value="False"/>
+        <UseAnsiStrings Value="False"/>
+      </SyntaxOptions>
+    </Parsing>
+    <Other>
+      <Verbosity>
+        <ShowWarn Value="False"/>
+        <ShowNotes Value="False"/>
+        <ShowHints Value="False"/>
+      </Verbosity>
+      <ConfigFile>
+        <StopAfterErrCount Value="50"/>
+      </ConfigFile>
+      <CustomOptions Value="-dloongarch64 
+-Sew"/>
+    </Other>
+  </CompilerOptions>
+</CONFIG>

+ 2 - 1
compiler/ppu.pas

@@ -48,7 +48,7 @@ const
   CurrentPPUVersion = 208;
   CurrentPPUVersion = 208;
   { for any other changes to the ppu format, increase this version number
   { for any other changes to the ppu format, increase this version number
     (it's a cardinal) }
     (it's a cardinal) }
-  CurrentPPULongVersion = 21;
+  CurrentPPULongVersion = 24;
 
 
 { unit flags }
 { unit flags }
   uf_big_endian          = $000004;
   uf_big_endian          = $000004;
@@ -174,6 +174,7 @@ implementation
   uses
   uses
 {$ifdef Test_Double_checksum}
 {$ifdef Test_Double_checksum}
     comphook,
     comphook,
+    globals,
 {$endif def Test_Double_checksum}
 {$endif def Test_Double_checksum}
     fpchash;
     fpchash;
 
 

+ 5 - 4
compiler/pstatmnt.pas

@@ -622,7 +622,7 @@ implementation
          do_typecheckpass(p);
          do_typecheckpass(p);
 
 
          if (p.nodetype=vecn) and
          if (p.nodetype=vecn) and
-            (nf_memseg in p.flags) then
+            (vnf_memseg in tvecnode(p).vecnodeflags) then
            CGMessage(parser_e_no_with_for_variable_in_other_segments);
            CGMessage(parser_e_no_with_for_variable_in_other_segments);
 
 
          { "with procvar" can never mean anything, so always try
          { "with procvar" can never mean anything, so always try
@@ -968,7 +968,7 @@ implementation
                                unit_found:=try_consume_unitsym_no_specialize(srsym,srsymtable,t,[],objname);
                                unit_found:=try_consume_unitsym_no_specialize(srsym,srsymtable,t,[],objname);
                                if srsym=nil then
                                if srsym=nil then
                                  begin
                                  begin
-                                   identifier_not_found(orgpattern);
+                                   identifier_not_found(objrealname);
                                    srsym:=generrorsym;
                                    srsym:=generrorsym;
                                  end;
                                  end;
                                if unit_found then
                                if unit_found then
@@ -1099,7 +1099,8 @@ implementation
 
 
          { Force an empty register list for pure assembler routines,
          { Force an empty register list for pure assembler routines,
            so that pass2 won't allocate volatile registers for them. }
            so that pass2 won't allocate volatile registers for them. }
-         asmstat.has_registerlist:=(po_assembler in current_procinfo.procdef.procoptions);
+         if (po_assembler in current_procinfo.procdef.procoptions) then
+           Include(asmstat.asmnodeflags,asmnf_has_registerlist);
 
 
          { END is read, got a list of changed registers? }
          { END is read, got a list of changed registers? }
          if try_to_consume(_LECKKLAMMER) then
          if try_to_consume(_LECKKLAMMER) then
@@ -1139,7 +1140,7 @@ implementation
                   if not try_to_consume(_COMMA) then
                   if not try_to_consume(_COMMA) then
                     break;
                     break;
                 until false;
                 until false;
-                asmstat.has_registerlist:=true;
+                Include(asmstat.asmnodeflags,asmnf_has_registerlist);
               end;
               end;
              consume(_RECKKLAMMER);
              consume(_RECKKLAMMER);
            end;
            end;

Some files were not shown because too many files changed in this diff