Browse Source

* synchronized with trunk

git-svn-id: branches/wasm@46860 -
nickysn 4 years ago
parent
commit
842f400f0d

+ 19 - 1
compiler/cgobj.pas

@@ -282,6 +282,7 @@ unit cgobj;
           procedure a_loadfpu_ref_cgpara(list : TAsmList;size : tcgsize;const ref : treference;const cgpara : TCGPara);virtual;
           procedure a_loadfpu_ref_cgpara(list : TAsmList;size : tcgsize;const ref : treference;const cgpara : TCGPara);virtual;
 
 
           procedure a_loadfpu_intreg_reg(list: TAsmList; fromsize, tosize : tcgsize; intreg, fpureg: tregister); virtual;
           procedure a_loadfpu_intreg_reg(list: TAsmList; fromsize, tosize : tcgsize; intreg, fpureg: tregister); virtual;
+          procedure a_loadfpu_reg_intreg(list: TAsmList; fromsize, tosize: tcgsize; fpureg, intreg: tregister); virtual;
 
 
           { vector register move instructions }
           { vector register move instructions }
           procedure a_loadmm_reg_reg(list: TAsmList; fromsize, tosize : tcgsize;reg1, reg2: tregister;shuffle : pmmshuffle); virtual;
           procedure a_loadmm_reg_reg(list: TAsmList; fromsize, tosize : tcgsize;reg1, reg2: tregister;shuffle : pmmshuffle); virtual;
@@ -1437,7 +1438,9 @@ implementation
              begin
              begin
                case getregtype(reg) of
                case getregtype(reg) of
                  R_FPUREGISTER:
                  R_FPUREGISTER:
-                   a_loadfpu_reg_reg(list,paraloc.size,regsize,paraloc.register,reg)
+                   a_loadfpu_reg_reg(list,paraloc.size,regsize,paraloc.register,reg);
+                 R_INTREGISTER:
+                   a_loadfpu_reg_intreg(list,paraloc.size,regsize,paraloc.register,reg);
                  else
                  else
                    internalerror(2015031401);
                    internalerror(2015031401);
                  end;
                  end;
@@ -1974,6 +1977,21 @@ implementation
       end;
       end;
 
 
 
 
+    procedure tcg.a_loadfpu_reg_intreg(list : TAsmList; fromsize,tosize : tcgsize; fpureg,intreg : tregister);
+      var
+        tmpref: treference;
+      begin
+        if not(tcgsize2size[fromsize] in [4,8]) or
+           not(tcgsize2size[tosize] in [4,8]) or
+           (tcgsize2size[fromsize]<>tcgsize2size[tosize]) then
+          internalerror(2020091201);
+        tg.gettemp(list,tcgsize2size[fromsize],tcgsize2size[fromsize],tt_normal,tmpref);
+        a_loadfpu_reg_ref(list,fromsize,fromsize,fpureg,tmpref);
+        a_load_ref_reg(list,tosize,tosize,tmpref,intreg);
+        tg.ungettemp(list,tmpref);
+      end;
+
+
     procedure tcg.a_op_const_ref(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; const ref: TReference);
     procedure tcg.a_op_const_ref(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; const ref: TReference);
       var
       var
         tmpreg : tregister;
         tmpreg : tregister;

+ 1 - 0
compiler/fpcdefs.inc

@@ -341,6 +341,7 @@
   {$define cpuneedsdivhelper}
   {$define cpuneedsdivhelper}
   {$define cpucapabilities}
   {$define cpucapabilities}
   {$define cpurequiresproperalignment}
   {$define cpurequiresproperalignment}
+  {$define cpufloatintregmov}
 {$endif xtensa}
 {$endif xtensa}
 
 
 { Stabs is not officially supported on 64 bit targets by gdb, except on Mac OS X
 { Stabs is not officially supported on 64 bit targets by gdb, except on Mac OS X

+ 1 - 13
compiler/hlcg2ll.pas

@@ -2019,19 +2019,7 @@ implementation
                   begin
                   begin
                     unget_para(paraloc^);
                     unget_para(paraloc^);
                     gen_alloc_regloc(list,destloc,vardef);
                     gen_alloc_regloc(list,destloc,vardef);
-                    { we can't directly move regular registers into fpu
-                      registers }
-                    if getregtype(paraloc^.register)=R_FPUREGISTER then
-                      begin
-                        { store everything first to memory, then load it in
-                          destloc }
-                        tg.gettemp(list,tcgsize2size[paraloc^.size],para.intsize,tt_persistent,tempref);
-                        cg.a_load_cgparaloc_ref(list,paraloc^,tempref,tcgsize2size[paraloc^.size],tempref.alignment);
-                        cg.a_load_ref_reg(list,int_cgsize(tcgsize2size[paraloc^.size]),destloc.size,tempref,destloc.register);
-                        tg.ungettemp(list,tempref);
-                      end
-                    else
-                      cg.a_load_cgparaloc_anyreg(list,destloc.size,paraloc^,destloc.register,sizeof(aint));
+                    cg.a_load_cgparaloc_anyreg(list,destloc.size,paraloc^,destloc.register,sizeof(aint));
                   end;
                   end;
               end;
               end;
           end;
           end;

+ 13 - 2
compiler/ncgcnv.pas

@@ -806,8 +806,19 @@ interface
             (location.loc=LOC_CONSTANT)
             (location.loc=LOC_CONSTANT)
            ) or
            ) or
            ((resultdef.typ=floatdef) xor (location.loc in [LOC_CFPUREGISTER,LOC_FPUREGISTER,LOC_CMMREGISTER,LOC_MMREGISTER])) then
            ((resultdef.typ=floatdef) xor (location.loc in [LOC_CFPUREGISTER,LOC_FPUREGISTER,LOC_CMMREGISTER,LOC_MMREGISTER])) then
-          hlcg.location_force_mem(current_asmdata.CurrAsmList,location,left.resultdef);
-
+          begin
+            { check if the CPU supports direct moves between int and fpu registers and take advantage of it }
+{$ifdef cpufloatintregmov}
+            if (resultdef.typ<>floatdef) and (location.loc in [LOC_CFPUREGISTER,LOC_FPUREGISTER]) then
+              begin
+                location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
+                location.register:=cg.getintregister(current_asmdata.CurrAsmList,location.size);
+                cg.a_loadfpu_reg_intreg(current_asmdata.CurrAsmList,left.location.size,location.size,left.location.register,location.register);
+              end
+            else
+{$endif cpufloatintregmov}
+              hlcg.location_force_mem(current_asmdata.CurrAsmList,location,left.resultdef);
+          end;
         { but use the new size, but we don't know the size of all arrays }
         { but use the new size, but we don't know the size of all arrays }
         newsize:=def_cgsize(resultdef);
         newsize:=def_cgsize(resultdef);
         location.size:=newsize;
         location.size:=newsize;

+ 8 - 10
compiler/rgobj.pas

@@ -641,10 +641,17 @@ unit rgobj;
           i8086 where indexed memory access instructions allow only
           i8086 where indexed memory access instructions allow only
           few registers as arguments and additionally the calling convention
           few registers as arguments and additionally the calling convention
           provides no general purpose volatile registers.
           provides no general purpose volatile registers.
+          
+          Also spill registers which have the initial memory location
+          and are used only once. This allows to access the memory location
+          directly, without preloading it to a register.
         }
         }
         for i:=first_imaginary to maxreg-1 do
         for i:=first_imaginary to maxreg-1 do
           with reginfo[i] do
           with reginfo[i] do
-            if real_reg_interferences>=usable_registers_cnt then
+            if (real_reg_interferences>=usable_registers_cnt) or
+               { also spill registers which have the initial memory location
+                 and are used only once }
+               ((ri_has_initial_loc in flags) and (weight<=200)) then
               spillednodes.add(i);
               spillednodes.add(i);
         if spillednodes.length<>0 then
         if spillednodes.length<>0 then
           begin
           begin
@@ -1699,15 +1706,6 @@ unit rgobj;
       for i:=selectstack.length downto 1 do
       for i:=selectstack.length downto 1 do
         begin
         begin
           n:=selectstack.buf^[i-1];
           n:=selectstack.buf^[i-1];
-          { Always spill the register if it has the initial memory location
-            and is used only once (weight<=200). This allows to access the
-            memory location directly, without preloading it to a register. }
-          with reginfo[n] do
-            if (ri_has_initial_loc in flags) and (weight<=200) then
-              begin
-                spillednodes.add(n);
-                continue;
-              end;
           {Create a list of colours that we cannot assign to n.}
           {Create a list of colours that we cannot assign to n.}
           adj_colours:=[];
           adj_colours:=[];
           adj:=reginfo[n].adjlist;
           adj:=reginfo[n].adjlist;

+ 2 - 2
compiler/riscv32/nrv32mat.pas

@@ -100,7 +100,7 @@ implementation
         else
         else
           op:=A_DIVU;
           op:=A_DIVU;
 
 
-        current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(op,denum,num,denum));
+        current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(op,num,num,denum));
       end;
       end;
 
 
     procedure trv32moddivnode.emit_mod_reg_reg(signed: boolean; denum, num: tregister);
     procedure trv32moddivnode.emit_mod_reg_reg(signed: boolean; denum, num: tregister);
@@ -112,7 +112,7 @@ implementation
         else
         else
           op:=A_REMU;
           op:=A_REMU;
 
 
-        current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(op,denum,num,denum));
+        current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(op,num,num,denum));
       end;
       end;
 
 
 
 

+ 9 - 0
compiler/xtensa/aasmcpu.pas

@@ -106,6 +106,8 @@ uses
     function spilling_create_load(const ref:treference;r:tregister):Taicpu;
     function spilling_create_load(const ref:treference;r:tregister):Taicpu;
     function spilling_create_store(r:tregister; const ref:treference):Taicpu;
     function spilling_create_store(r:tregister; const ref:treference):Taicpu;
 
 
+    function setoppostfix(i : taicpu;pf : toppostfix) : taicpu;
+
 implementation
 implementation
 
 
 uses cutils, cclasses;
 uses cutils, cclasses;
@@ -495,6 +497,13 @@ uses cutils, cclasses;
       end;
       end;
 
 
 
 
+    function setoppostfix(i : taicpu;pf : toppostfix) : taicpu;
+      begin
+        i.oppostfix:=pf;
+        result:=i;
+      end;
+
+
     procedure InitAsm;
     procedure InitAsm;
       begin
       begin
       end;
       end;

+ 21 - 0
compiler/xtensa/cgcpu.pas

@@ -77,6 +77,9 @@ interface
         procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister);override;
         procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister);override;
         procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);override;
         procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);override;
 
 
+        procedure a_loadfpu_intreg_reg(list: TAsmList; fromsize, tosize: tcgsize; intreg, fpureg: tregister);override;
+        procedure a_loadfpu_reg_intreg(list: TAsmList; fromsize, tosize: tcgsize; fpureg, intreg: tregister);override;
+
         procedure maybeadjustresult(list: TAsmList; op: TOpCg; size: tcgsize; dst: tregister);
         procedure maybeadjustresult(list: TAsmList; op: TOpCg; size: tcgsize; dst: tregister);
 
 
         procedure g_overflowcheck(list: TAsmList; const Loc:tlocation; def:tdef);override;
         procedure g_overflowcheck(list: TAsmList; const Loc:tlocation; def:tdef);override;
@@ -1196,6 +1199,24 @@ implementation
        end;
        end;
 
 
 
 
+    procedure tcgcpu.a_loadfpu_intreg_reg(list : TAsmList; fromsize,tosize : tcgsize; intreg,fpureg : tregister);
+      begin
+        if not(tcgsize2size[fromsize]=4) or
+           not(tcgsize2size[tosize]=4) then
+          internalerror(2020091102);
+        list.concat(taicpu.op_reg_reg(A_WFR,fpureg,intreg));
+      end;
+
+
+    procedure tcgcpu.a_loadfpu_reg_intreg(list : TAsmList; fromsize,tosize : tcgsize; fpureg,intreg : tregister);
+      begin
+        if not(tcgsize2size[fromsize]=4) or
+           not(tcgsize2size[tosize]=4) then
+          internalerror(2020091202);
+        list.concat(taicpu.op_reg_reg(A_RFR,intreg,fpureg));
+      end;
+
+
     procedure tcgcpu.maybeadjustresult(list : TAsmList; op : TOpCg; size : tcgsize; dst : tregister);
     procedure tcgcpu.maybeadjustresult(list : TAsmList; op : TOpCg; size : tcgsize; dst : tregister);
       const
       const
         overflowops = [OP_MUL,OP_SHL,OP_ADD,OP_SUB,OP_NEG];
         overflowops = [OP_MUL,OP_SHL,OP_ADD,OP_SUB,OP_NEG];

+ 27 - 0
compiler/xtensa/ncpuinl.pas

@@ -30,12 +30,16 @@ unit ncpuinl;
 
 
     type
     type
       tcpuinlineNode = class(tcginlinenode)
       tcpuinlineNode = class(tcginlinenode)
+        function first_abs_real: tnode; override;
         procedure second_abs_long; override;
         procedure second_abs_long; override;
+        procedure second_abs_real; override;
       end;
       end;
 
 
   implementation
   implementation
 
 
     uses
     uses
+      cpuinfo,
+      verbose,globals,
       compinnr,
       compinnr,
       aasmdata,
       aasmdata,
       aasmcpu,
       aasmcpu,
@@ -58,6 +62,29 @@ unit ncpuinl;
       end;
       end;
 
 
 
 
+    function tcpuinlinenode.first_abs_real : tnode;
+      begin
+        result:=nil;
+        if is_single(left.resultdef) and (FPUXTENSA_SINGLE in fpu_capabilities[current_settings.fputype]) then
+          expectloc:=LOC_FPUREGISTER
+        else
+          result:=inherited first_abs_real;
+      end;
+
+
+    procedure tcpuinlinenode.second_abs_real;
+      begin
+        if not(is_single(resultdef)) then
+          InternalError(2020091101);
+        secondpass(left);
+        hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
+        location_reset(location,LOC_FPUREGISTER,OS_F32);
+        location.register:=cg.getfpuregister(current_asmdata.CurrAsmList,location.size);
+        current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_ABS,location.register,left.location.register),PF_S));
+      end;
+
+
+
 begin
 begin
   cinlinenode:=tcpuinlinenode;
   cinlinenode:=tcpuinlinenode;
 end.
 end.

+ 59 - 24
packages/fpmkunit/src/fpmkunit.pp

@@ -488,7 +488,7 @@ Type
     Function GetValue(AName : String) : String;
     Function GetValue(AName : String) : String;
     Function GetValue(const AName,Args : String) : String; virtual;
     Function GetValue(const AName,Args : String) : String; virtual;
     Function ReplaceStrings(Const ASource : String; Const MaxDepth: Integer = 10) : String; virtual;
     Function ReplaceStrings(Const ASource : String; Const MaxDepth: Integer = 10) : String; virtual;
-    Function Substitute(Const Source : String; Macros : Array of string) : String; virtual;
+    Function Substitute(Const Source : String; const Macros : Array of string) : String; virtual;
   end;
   end;
 
 
   { TPackageDictionary }
   { TPackageDictionary }
@@ -855,6 +855,9 @@ Type
     // Is set when all sourcefiles are found
     // Is set when all sourcefiles are found
     FAllFilesResolved: boolean;
     FAllFilesResolved: boolean;
     FPackageVariants: TFPList;
     FPackageVariants: TFPList;
+{$ifndef NO_THREADING}
+    FResolveDirsCS: TRTLCriticalSection;
+{$endif}
     Function GetDescription : string;
     Function GetDescription : string;
     function GetDictionary: TDictionary;
     function GetDictionary: TDictionary;
     Function GetFileName : string;
     Function GetFileName : string;
@@ -894,6 +897,8 @@ Type
     procedure SetDefaultPackageVariant;
     procedure SetDefaultPackageVariant;
     procedure LoadUnitConfigFromFile(Const AFileName: String);
     procedure LoadUnitConfigFromFile(Const AFileName: String);
     procedure SaveUnitConfigToFile(Const AFileName: String;ACPU:TCPU;AOS:TOS);
     procedure SaveUnitConfigToFile(Const AFileName: String;ACPU:TCPU;AOS:TOS);
+    procedure EnterResolveDirsCS;
+    procedure LeaveResolveDirsCS;
     Property Version : String Read GetVersion Write SetVersion;
     Property Version : String Read GetVersion Write SetVersion;
     Property FileName : String Read GetFileName Write FFileName;
     Property FileName : String Read GetFileName Write FFileName;
     Property ShortName : String Read GetShortName Write FShortName;
     Property ShortName : String Read GetShortName Write FShortName;
@@ -1304,9 +1309,9 @@ Type
     Procedure CheckPackages; virtual;
     Procedure CheckPackages; virtual;
     Procedure CreateBuildEngine; virtual;
     Procedure CreateBuildEngine; virtual;
     Procedure Error(const Msg : String);
     Procedure Error(const Msg : String);
-    Procedure Error(const Fmt : String; Args : Array of const);
+    Procedure Error(const Fmt : String; const Args : Array of const);
     Procedure AnalyzeOptions;
     Procedure AnalyzeOptions;
-    Procedure Usage(const FMT : String; Args : Array of const);
+    Procedure Usage(const FMT : String; const Args : Array of const);
     Procedure Compile(Force : Boolean); virtual;
     Procedure Compile(Force : Boolean); virtual;
     Procedure Clean(AllTargets: boolean); virtual;
     Procedure Clean(AllTargets: boolean); virtual;
     Procedure Install(ForceBuild : Boolean); virtual;
     Procedure Install(ForceBuild : Boolean); virtual;
@@ -3683,6 +3688,9 @@ begin
   // Implicit dependency on RTL
   // Implicit dependency on RTL
   FDependencies.Add('rtl');
   FDependencies.Add('rtl');
   FSupportBuildModes:=[bmBuildUnit, bmOneByOne];
   FSupportBuildModes:=[bmBuildUnit, bmOneByOne];
+{$ifndef NO_THREADING}
+  InitCriticalSection(FResolveDirsCS);
+{$endif}
 end;
 end;
 
 
 
 
@@ -3690,6 +3698,9 @@ destructor TPackage.destroy;
 var
 var
   i: integer;
   i: integer;
 begin
 begin
+{$ifndef NO_THREADING}
+  DoneCriticalSection(FResolveDirsCS);
+{$endif}
   FreeAndNil(FDictionary);
   FreeAndNil(FDictionary);
   FreeAndNil(FDependencies);
   FreeAndNil(FDependencies);
   FreeAndNil(FInstallFiles);
   FreeAndNil(FInstallFiles);
@@ -4316,6 +4327,20 @@ begin
   end;
   end;
 end;
 end;
 
 
+procedure TPackage.EnterResolveDirsCS;
+begin
+{$ifndef NO_THREADING}
+   EnterCriticalSection(FResolveDirsCS);
+{$endif}
+end;
+
+procedure TPackage.LeaveResolveDirsCS;
+begin
+{$ifndef NO_THREADING}
+   LeaveCriticalSection(FResolveDirsCS);
+{$endif}
+end;
+
 
 
 
 
 {****************************************************************************
 {****************************************************************************
@@ -5040,7 +5065,7 @@ begin
 end;
 end;
 
 
 
 
-procedure TCustomInstaller.Error(const Fmt: String; Args: array of const);
+procedure TCustomInstaller.Error(const Fmt: String; const Args: array of const);
 begin
 begin
   Raise EInstallerError.CreateFmt(Fmt,Args);
   Raise EInstallerError.CreateFmt(Fmt,Args);
 end;
 end;
@@ -5377,7 +5402,7 @@ begin
 end;
 end;
 
 
 
 
-procedure TCustomInstaller.Usage(const FMT: String; Args: array of const);
+procedure TCustomInstaller.Usage(const FMT: String; const Args: array of const);
 
 
   Procedure LogCmd(const LC,Msg : String);
   Procedure LogCmd(const LC,Msg : String);
   begin
   begin
@@ -6602,27 +6627,36 @@ var
   i: Integer;
   i: Integer;
   Continue: Boolean;
   Continue: Boolean;
 begin
 begin
-  if APackage.UnitDir='' then
-    begin
-      Log(vldebug, SDbgSearchExtDepPath, [APackage.Name]);
-      GetPluginManager.BeforeResolvePackagePath(Self, APackage, Continue);
-      if Continue then
-        begin
-        for I := 0 to Defaults.SearchPath.Count-1 do
+{$ifndef NO_THREADING}
+  APackage.EnterResolveDirsCS;
+  try
+{$endif}
+    if APackage.UnitDir='' then
+      begin
+        Log(vldebug, SDbgSearchExtDepPath, [APackage.Name]);
+        GetPluginManager.BeforeResolvePackagePath(Self, APackage, Continue);
+        if Continue then
           begin
           begin
-            if Defaults.SearchPath[i]<>'' then
-              GetPluginManager.ResolvePackagePath(Self, APackage, Defaults.SearchPath[i], Continue);
-            if not Continue then
-              Break
-          end;
+          for I := 0 to Defaults.SearchPath.Count-1 do
+            begin
+              if Defaults.SearchPath[i]<>'' then
+                GetPluginManager.ResolvePackagePath(Self, APackage, Defaults.SearchPath[i], Continue);
+              if not Continue then
+                Break
+            end;
 
 
-        if Continue then
-          GetPluginManager.AfterResolvePackagePath(Self, APackage, Continue);
-        end;
+          if Continue then
+            GetPluginManager.AfterResolvePackagePath(Self, APackage, Continue);
+          end;
 
 
-      if APackage.UnitDir = '' then
-        APackage.UnitDir := DirNotFound
-    end;
+        if APackage.UnitDir = '' then
+          APackage.UnitDir := DirNotFound
+      end;
+{$ifndef NO_THREADING}
+  finally
+    APackage.LeaveResolveDirsCS;
+  end;
+{$endif}
 end;
 end;
 
 
 
 
@@ -9488,7 +9522,7 @@ begin
 end;
 end;
 
 
 
 
-Function TDictionary.Substitute(Const Source : String; Macros : Array of string) : String;
+Function TDictionary.Substitute(Const Source : String; const Macros : Array of string) : String;
 Var
 Var
   I : Integer;
   I : Integer;
 begin
 begin
@@ -9499,6 +9533,7 @@ begin
       Inc(I,2);
       Inc(I,2);
     end;
     end;
   Result:=ReplaceStrings(Source);
   Result:=ReplaceStrings(Source);
+  I:=0;
   While I<High(Macros) do
   While I<High(Macros) do
     begin
     begin
       RemoveItem(Macros[i]);
       RemoveItem(Macros[i]);

+ 42 - 23
packages/pastojs/src/fppas2js.pp

@@ -1744,8 +1744,12 @@ type
 
 
   TInterfaceSectionContext = Class(TSectionContext)
   TInterfaceSectionContext = Class(TSectionContext)
   public
   public
+    ImplContext: TSectionContext;
     ImplHeaderStatements: TFPList;
     ImplHeaderStatements: TFPList;
+    ImplSrcElements: TJSSourceElements;
+    ImplHeaderIndex: integer; // index in TJSSourceElements(JSElement).Statements
     destructor Destroy; override;
     destructor Destroy; override;
+    procedure AddImplHeaderStatement(JS: TJSElement);
   end;
   end;
 
 
   { TDotContext - used for converting eopSubIdent }
   { TDotContext - used for converting eopSubIdent }
@@ -1994,7 +1998,7 @@ type
       Full: boolean = false; Ref: TResolvedReference = nil): TJSElement; virtual;
       Full: boolean = false; Ref: TResolvedReference = nil): TJSElement; virtual;
     Function CreateGlobalTypePath(El: TPasType; AContext : TConvertContext): string; virtual;
     Function CreateGlobalTypePath(El: TPasType; AContext : TConvertContext): string; virtual;
     // section
     // section
-    Function CreateImplementationSection(El: TPasModule; AContext: TInterfaceSectionContext): TJSFunctionDeclarationStatement; virtual;
+    Function CreateImplementationSection(El: TPasModule; IntfContext: TInterfaceSectionContext): TJSFunctionDeclarationStatement; virtual;
     Procedure CreateInitSection(El: TPasModule; Src: TJSSourceElements; AContext: TConvertContext); virtual;
     Procedure CreateInitSection(El: TPasModule; Src: TJSSourceElements; AContext: TConvertContext); virtual;
     Procedure AddHeaderStatement(JS: TJSElement; PosEl: TPasElement; aContext: TConvertContext); virtual;
     Procedure AddHeaderStatement(JS: TJSElement; PosEl: TPasElement; aContext: TConvertContext); virtual;
     Procedure AddImplHeaderStatement(JS: TJSElement; PosEl: TPasElement; aContext: TConvertContext); virtual;
     Procedure AddImplHeaderStatement(JS: TJSElement; PosEl: TPasElement; aContext: TConvertContext); virtual;
@@ -2393,6 +2397,29 @@ begin
   inherited Destroy;
   inherited Destroy;
 end;
 end;
 
 
+procedure TInterfaceSectionContext.AddImplHeaderStatement(JS: TJSElement);
+begin
+  if JS=nil then exit;
+  if ImplContext<>nil then
+    begin
+    // unit impl is currently created
+    ImplContext.AddHeaderStatement(JS);
+    end
+  else if ImplSrcElements<>nil then
+    begin
+    // unit impl finished -> e.g. during the initialization section
+    ImplSrcElements.Statements.InsertNode(ImplHeaderIndex).Node:=JS;
+    inc(ImplHeaderIndex);
+    end
+  else
+    begin
+    // unit impl not yet created
+    if ImplHeaderStatements=nil then
+      ImplHeaderStatements:=TFPList.Create;
+    ImplHeaderStatements.Add(JS);
+    end;
+end;
+
 { TPas2JSResolverHub }
 { TPas2JSResolverHub }
 
 
 function TPas2JSResolverHub.GetJSDelaySpecializes(Index: integer
 function TPas2JSResolverHub.GetJSDelaySpecializes(Index: integer
@@ -16771,7 +16798,7 @@ begin
 end;
 end;
 
 
 function TPasToJSConverter.CreateImplementationSection(El: TPasModule;
 function TPasToJSConverter.CreateImplementationSection(El: TPasModule;
-  AContext: TInterfaceSectionContext): TJSFunctionDeclarationStatement;
+  IntfContext: TInterfaceSectionContext): TJSFunctionDeclarationStatement;
 var
 var
   Src: TJSSourceElements;
   Src: TJSSourceElements;
   ImplContext: TSectionContext;
   ImplContext: TSectionContext;
@@ -16784,33 +16811,37 @@ begin
   // create function(){}
   // create function(){}
   FunDecl:=CreateFunctionSt(El.ImplementationSection,true,true);
   FunDecl:=CreateFunctionSt(El.ImplementationSection,true,true);
   Src:=TJSSourceElements(FunDecl.AFunction.Body.A);
   Src:=TJSSourceElements(FunDecl.AFunction.Body.A);
+  IntfContext.ImplSrcElements:=Src;
 
 
   // create section context (a function)
   // create section context (a function)
-  ImplContext:=TSectionContext.Create(El.ImplementationSection,Src,AContext);
+  ImplContext:=TSectionContext.Create(El.ImplementationSection,Src,IntfContext);
   try
   try
+    IntfContext.ImplContext:=ImplContext;
     // ToDo: IntfContext.ThisPas:=El;
     // ToDo: IntfContext.ThisPas:=El;
     // ToDo: IntfContext.ThisKind:=cctkGlobal;
     // ToDo: IntfContext.ThisKind:=cctkGlobal;
 
 
     // add pending impl header statements
     // add pending impl header statements
-    if AContext.ImplHeaderStatements<>nil then
+    if IntfContext.ImplHeaderStatements<>nil then
       begin
       begin
-      for i:=0 to AContext.ImplHeaderStatements.Count-1 do
+      for i:=0 to IntfContext.ImplHeaderStatements.Count-1 do
         begin
         begin
-        JS:=TJSElement(AContext.ImplHeaderStatements[i]);
+        JS:=TJSElement(IntfContext.ImplHeaderStatements[i]);
         ImplContext.AddHeaderStatement(JS);
         ImplContext.AddHeaderStatement(JS);
-        AContext.ImplHeaderStatements[i]:=nil;
+        IntfContext.ImplHeaderStatements[i]:=nil;
         end;
         end;
-      FreeAndNil(AContext.ImplHeaderStatements);
+      FreeAndNil(IntfContext.ImplHeaderStatements);
       end;
       end;
 
 
     // create implementation declarations
     // create implementation declarations
     ImplDecl:=ConvertDeclarations(El.ImplementationSection,ImplContext);
     ImplDecl:=ConvertDeclarations(El.ImplementationSection,ImplContext);
     if ImplDecl<>nil then
     if ImplDecl<>nil then
       RaiseInconsistency(20170910175032,El); // elements should have been added directly
       RaiseInconsistency(20170910175032,El); // elements should have been added directly
+    IntfContext.ImplHeaderIndex:=ImplContext.HeaderIndex;
     if Src.Statements.Count=0 then
     if Src.Statements.Count=0 then
       exit; // no implementation
       exit; // no implementation
     Result:=FunDecl;
     Result:=FunDecl;
   finally
   finally
+    IntfContext.ImplContext:=nil;
     ImplContext.Free;
     ImplContext.Free;
     if Result=nil then
     if Result=nil then
       FunDecl.Free;
       FunDecl.Free;
@@ -16849,25 +16880,13 @@ end;
 procedure TPasToJSConverter.AddImplHeaderStatement(JS: TJSElement;
 procedure TPasToJSConverter.AddImplHeaderStatement(JS: TJSElement;
   PosEl: TPasElement; aContext: TConvertContext);
   PosEl: TPasElement; aContext: TConvertContext);
 var
 var
-  SectionCtx: TSectionContext;
   IntfSec: TInterfaceSectionContext;
   IntfSec: TInterfaceSectionContext;
 begin
 begin
   if JS=nil then exit;
   if JS=nil then exit;
-  SectionCtx:=TSectionContext(aContext.GetContextOfType(TSectionContext));
-  if SectionCtx=nil then
+  IntfSec:=TInterfaceSectionContext(aContext.GetContextOfType(TInterfaceSectionContext));
+  if IntfSec=nil then
     RaiseNotSupported(PosEl,aContext,20200606142555);
     RaiseNotSupported(PosEl,aContext,20200606142555);
-  if SectionCtx.PasElement is TImplementationSection then
-    SectionCtx.AddHeaderStatement(JS)
-  else if SectionCtx is TInterfaceSectionContext then
-    begin
-    // add pending impl header statement
-    IntfSec:=TInterfaceSectionContext(SectionCtx);
-    if IntfSec.ImplHeaderStatements=nil then
-      IntfSec.ImplHeaderStatements:=TFPList.Create;
-    IntfSec.ImplHeaderStatements.Add(JS);
-    end
-  else
-    RaiseNotSupported(PosEl,aContext,20200911165632);
+  IntfSec.AddImplHeaderStatement(JS);
 end;
 end;
 
 
 procedure TPasToJSConverter.AddDelayedInits(El: TPasProgram;
 procedure TPasToJSConverter.AddDelayedInits(El: TPasProgram;

+ 6 - 0
packages/pastojs/tests/tcoptimizations.pas

@@ -303,6 +303,8 @@ begin
     '  end;',
     '  end;',
     '  TBear = class',
     '  TBear = class',
     '  end;',
     '  end;',
+    '  TFrog = class',
+    '  end;',
     'var Ant: TAnt;',
     'var Ant: TAnt;',
     '']),
     '']),
   LinesToStr([
   LinesToStr([
@@ -347,6 +349,7 @@ begin
   '  Ant:=TAnt.Create;', // init to impl-uses
   '  Ant:=TAnt.Create;', // init to impl-uses
   '  Bird:=TBird.Create;', // init to intf-uses
   '  Bird:=TBird.Create;', // init to intf-uses
   '  Eagle:=TEagle.Create;', // init to intf-JS
   '  Eagle:=TEagle.Create;', // init to intf-JS
+  '  TFrog.Create;', // only in init to impl-uses
   '  Eagle.Fly;',
   '  Eagle.Fly;',
   '  RedAnt.Run;',
   '  RedAnt.Run;',
   '']);
   '']);
@@ -359,6 +362,7 @@ begin
     'var $lm1 = null;',
     'var $lm1 = null;',
     'var $lt1 = null;',
     'var $lt1 = null;',
     'var $lt2 = null;',
     'var $lt2 = null;',
+    'var $lt3 = null;',
     'rtl.createClass($mod, "TEagle", $lt, function () {',
     'rtl.createClass($mod, "TEagle", $lt, function () {',
     '  this.Fly = function () {',
     '  this.Fly = function () {',
     '    $impl.TRedAnt.$create("Create");',
     '    $impl.TRedAnt.$create("Create");',
@@ -373,6 +377,7 @@ begin
     '$impl.Ant = $lt1.$create("Create");',
     '$impl.Ant = $lt1.$create("Create");',
     '$impl.Bird = $lt.$create("Create");',
     '$impl.Bird = $lt.$create("Create");',
     '$impl.Eagle = $mod.TEagle.$create("Create");',
     '$impl.Eagle = $mod.TEagle.$create("Create");',
+    '$lt3.$create("Create");',
     '$impl.Eagle.Fly();',
     '$impl.Eagle.Fly();',
     '$impl.RedAnt.Run();',
     '$impl.RedAnt.Run();',
     '']),
     '']),
@@ -380,6 +385,7 @@ begin
     '$lm1 = pas.UnitB;',
     '$lm1 = pas.UnitB;',
     '$lt1 = $lm1.TAnt;',
     '$lt1 = $lm1.TAnt;',
     '$lt2 = $lm1.TBear;',
     '$lt2 = $lm1.TBear;',
+    '$lt3 = $lm1.TFrog;',
     'rtl.createClass($impl, "TRedAnt", $lt1, function () {',
     'rtl.createClass($impl, "TRedAnt", $lt1, function () {',
     '  this.Run = function () {',
     '  this.Run = function () {',
     '    $impl.TRedAnt.$create("Create");',
     '    $impl.TRedAnt.$create("Create");',

+ 73 - 9
rtl/inc/text.inc

@@ -96,6 +96,12 @@ end;
 Procedure Assign(out t:Text;const s : UnicodeString);
 Procedure Assign(out t:Text;const s : UnicodeString);
 begin
 begin
   InitText(t);
   InitText(t);
+  if Length (S) >= Length (TextRec.Name) then
+{ The last character of TextRec.Name needs to be #0 }
+   begin
+     InOutRes:=3;
+     Exit;
+   end;
 {$ifdef FPC_ANSI_TEXTFILEREC}
 {$ifdef FPC_ANSI_TEXTFILEREC}
   TextRec(t).Name:=ToSingleByteFileSystemEncodedFileName(S);
   TextRec(t).Name:=ToSingleByteFileSystemEncodedFileName(S);
 {$else FPC_ANSI_TEXTFILEREC}
 {$else FPC_ANSI_TEXTFILEREC}
@@ -109,12 +115,29 @@ end;
 
 
 {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}
 {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}
 Procedure Assign(out t:Text;const s: RawByteString);
 Procedure Assign(out t:Text;const s: RawByteString);
+{$ifdef FPC_ANSI_TEXTFILEREC}
+var
+  R: RawByteString;
+{$endif FPC_ANSI_TEXTFILEREC}
 Begin
 Begin
   InitText(t);
   InitText(t);
 {$ifdef FPC_ANSI_TEXTFILEREC}
 {$ifdef FPC_ANSI_TEXTFILEREC}
   { ensure the characters in the record's filename are encoded correctly }
   { ensure the characters in the record's filename are encoded correctly }
-  TextRec(t).Name:=ToSingleByteFileSystemEncodedFileName(S);
+  R:=ToSingleByteFileSystemEncodedFileName(S);
+  if Length (R) >= Length (TextRec.Name) then
+{ The last character of TextRec.Name needs to be #0 }
+   begin
+     InOutRes:=3;
+     Exit;
+   end;
+  TextRec(t).Name:=R;
 {$else FPC_ANSI_TEXTFILEREC}
 {$else FPC_ANSI_TEXTFILEREC}
+  if Length (S) >= Length (TextRec.Name) then
+{ The last character of TextRec.Name needs to be #0 }
+   begin
+     InOutRes:=3;
+     Exit;
+   end;
   TextRec(t).Name:=S;
   TextRec(t).Name:=S;
 {$endif FPC_ANSI_TEXTFILEREC}
 {$endif FPC_ANSI_TEXTFILEREC}
   { null terminate, since the name array is regularly used as p(wide)char }
   { null terminate, since the name array is regularly used as p(wide)char }
@@ -138,27 +161,61 @@ End;
 
 
 
 
 Procedure Assign(out t:Text;const p: PAnsiChar);
 Procedure Assign(out t:Text;const p: PAnsiChar);
+var
+{$IFDEF FPC_HAS_FEATURE_ANSISTRINGS}
+  S: ansistring;
+{$ELSE FPC_HAS_FEATURE_ANSISTRINGS}
+  Counter: SizeInt;
+{$ENDIF FPC_HAS_FEATURE_ANSISTRINGS}
 Begin
 Begin
 {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}
 {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}
-  Assign(t,AnsiString(p));
+  S := AnsiString (P);
+  if Length (S) >= Length (TextRec.Name) then
+{ The last character of TextRec.Name needs to be #0 }
+   begin
+     InOutRes:=3;
+     Exit;
+   end;
+  Assign(t,S);
 {$else FPC_HAS_FEATURE_ANSISTRINGS}
 {$else FPC_HAS_FEATURE_ANSISTRINGS}
   { no use in making this the one that does the work, since the name field is
   { no use in making this the one that does the work, since the name field is
     limited to 255 characters anyway }
     limited to 255 characters anyway }
-  Assign(t,strpas(p));
+{  Assign(t,strpas(p));}
+  { TH: The length of name field may be extended sooner or later, let's play
+    safely }
+  Counter := IndexByte(P^,-1,0);
+  if Counter >= Length (TextRec.Name) then
+{ The last character of TextRec.Name needs to be #0 }
+   begin
+     InOutRes:=3;
+     Exit;
+   end;
+  Move(P^,TextRec(t).Name,counter+1);
 {$endif FPC_HAS_FEATURE_ANSISTRINGS}
 {$endif FPC_HAS_FEATURE_ANSISTRINGS}
 End;
 End;
 
 
 
 
 Procedure Assign(out t:Text;const c: AnsiChar);
 Procedure Assign(out t:Text;const c: AnsiChar);
+{$IFNDEF FPC_HAS_FEATURE_ANSISTRINGS}
+var
+  Counter: SizeInt;
+{$ENDIF FPC_HAS_FEATURE_ANSISTRINGS}
 Begin
 Begin
 {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}
 {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}
   Assign(t,AnsiString(c));
   Assign(t,AnsiString(c));
 {$else FPC_HAS_FEATURE_ANSISTRINGS}
 {$else FPC_HAS_FEATURE_ANSISTRINGS}
-  Assign(t,ShortString(c));
+  Counter := IndexByte(c,-1,0);
+  if Counter >= Length (TextRec.Name) then
+{ The last character of TextRec.Name needs to be #0 }
+   begin
+     InOutRes:=3;
+     Exit;
+   end;
+  Move(c,TextRec(F).Name,counter+1);
+{  Assign(t,ShortString(c));}
 {$endif FPC_HAS_FEATURE_ANSISTRINGS}
 {$endif FPC_HAS_FEATURE_ANSISTRINGS}
 End;
 End;
 
 
-
 Procedure Close(var t : Text);[IOCheck];
 Procedure Close(var t : Text);[IOCheck];
 Begin
 Begin
   if InOutRes<>0 then
   if InOutRes<>0 then
@@ -472,6 +529,8 @@ Begin
           (reads = 1) then
           (reads = 1) then
          begin
          begin
            oldfilepos := Do_FilePos(TextRec(t).handle) - TextRec(t).BufEnd;
            oldfilepos := Do_FilePos(TextRec(t).handle) - TextRec(t).BufEnd;
+           if InOutRes <> 0 then
+             isdevice := true;
            InOutRes:=0;
            InOutRes:=0;
          end;
          end;
        FileFunc(TextRec(t).InOutFunc)(TextRec(t));
        FileFunc(TextRec(t).InOutFunc)(TextRec(t));
@@ -506,7 +565,7 @@ Begin
   if not isdevice then
   if not isdevice then
     { if we didn't modify the buffer, simply restore the BufPos and BufEnd  }
     { if we didn't modify the buffer, simply restore the BufPos and BufEnd  }
     { (the latter because it's now probably set to zero because nothing was }
     { (the latter because it's now probably set to zero because nothing was }
-    {  was read anymore)                                                    }
+    { read anymore)                                                         }
     if (reads = 0) then
     if (reads = 0) then
       begin
       begin
         TextRec(t).BufPos:=oldbufpos;
         TextRec(t).BufPos:=oldbufpos;
@@ -515,10 +574,15 @@ Begin
     { otherwise return to the old filepos and reset the buffer }
     { otherwise return to the old filepos and reset the buffer }
     else
     else
       begin
       begin
+        InOutRes := 0;
         do_seek(TextRec(t).handle,oldfilepos);
         do_seek(TextRec(t).handle,oldfilepos);
-        InOutRes:=0;
-        FileFunc(TextRec(t).InOutFunc)(TextRec(t));
-        TextRec(t).BufPos:=oldbufpos;
+        if InOutRes = 0 then
+          begin
+            FileFunc(TextRec(t).InOutFunc)(TextRec(t));
+            TextRec(t).BufPos:=oldbufpos;
+          end
+        else
+          InOutRes:=0;
       end;
       end;
 End;
 End;
 
 

+ 30 - 14
rtl/win/sysutils.pp

@@ -415,7 +415,15 @@ begin
 end;
 end;
 
 
 
 
-function FileGetSymLinkTargetInt(const FileName: UnicodeString; out SymLinkRec: TUnicodeSymLinkRec; RaiseErrorOnMissing: Boolean): Boolean;
+type
+  TSymLinkResult = (
+    slrOk,
+    slrNoSymLink,
+    slrError
+  );
+
+
+function FileGetSymLinkTargetInt(const FileName: UnicodeString; out SymLinkRec: TUnicodeSymLinkRec; RaiseErrorOnMissing: Boolean): TSymLinkResult;
 { reparse point specific declarations from Windows headers }
 { reparse point specific declarations from Windows headers }
 const
 const
   IO_REPARSE_TAG_MOUNT_POINT = $A0000003;
   IO_REPARSE_TAG_MOUNT_POINT = $A0000003;
@@ -451,6 +459,7 @@ var
   PBuffer: ^TReparseDataBuffer;
   PBuffer: ^TReparseDataBuffer;
   BytesReturned: DWORD;
   BytesReturned: DWORD;
 begin
 begin
+  Result := slrError;
   SymLinkRec := Default(TUnicodeSymLinkRec);
   SymLinkRec := Default(TUnicodeSymLinkRec);
 
 
   HFile := CreateFileW(PUnicodeChar(FileName), FILE_READ_EA, CShareAny, Nil, OPEN_EXISTING, COpenReparse, 0);
   HFile := CreateFileW(PUnicodeChar(FileName), FILE_READ_EA, CShareAny, Nil, OPEN_EXISTING, COpenReparse, 0);
@@ -487,8 +496,10 @@ begin
               raise EDirectoryNotFoundException.Create(SysErrorMessage(GetLastOSError))
               raise EDirectoryNotFoundException.Create(SysErrorMessage(GetLastOSError))
             else
             else
               SymLinkRec.TargetName := '';
               SymLinkRec.TargetName := '';
-          end else
+          end else begin
             SetLastError(ERROR_REPARSE_TAG_INVALID);
             SetLastError(ERROR_REPARSE_TAG_INVALID);
+            Result := slrNoSymLink;
+          end;
         end else
         end else
           SetLastError(ERROR_REPARSE_TAG_INVALID);
           SetLastError(ERROR_REPARSE_TAG_INVALID);
       finally
       finally
@@ -497,13 +508,15 @@ begin
     finally
     finally
       CloseHandle(HFile);
       CloseHandle(HFile);
     end;
     end;
-  Result := SymLinkRec.TargetName <> '';
+
+  if SymLinkRec.TargetName <> '' then
+    Result := slrOk
 end;
 end;
 
 
 
 
 function FileGetSymLinkTarget(const FileName: UnicodeString; out SymLinkRec: TUnicodeSymLinkRec): Boolean;
 function FileGetSymLinkTarget(const FileName: UnicodeString; out SymLinkRec: TUnicodeSymLinkRec): Boolean;
 begin
 begin
-  Result := FileGetSymLinkTargetInt(FileName, SymLinkRec, True);
+  Result := FileGetSymLinkTargetInt(FileName, SymLinkRec, True) = slrOk;
 end;
 end;
 
 
 
 
@@ -526,14 +539,6 @@ const
     end;
     end;
   end;
   end;
 
 
-  function LinkFileExists: Boolean;
-  var
-    slr: TUnicodeSymLinkRec;
-  begin
-    Result := FileGetSymLinkTargetInt(FileOrDirName, slr, False) and
-                FileOrDirExists(slr.TargetName, CheckDir, False);
-  end;
-
 const
 const
   CNotExistsErrors = [
   CNotExistsErrors = [
     ERROR_FILE_NOT_FOUND,
     ERROR_FILE_NOT_FOUND,
@@ -548,14 +553,25 @@ const
   ];
   ];
 var
 var
   Attr : DWord;
   Attr : DWord;
+  slr : TUnicodeSymLinkRec;
+  res : TSymLinkResult;
 begin
 begin
   Attr := GetFileAttributesW(PUnicodeChar(FileOrDirName));
   Attr := GetFileAttributesW(PUnicodeChar(FileOrDirName));
   if Attr = INVALID_FILE_ATTRIBUTES then
   if Attr = INVALID_FILE_ATTRIBUTES then
     Result := not (GetLastError in CNotExistsErrors) and FoundByEnum
     Result := not (GetLastError in CNotExistsErrors) and FoundByEnum
   else begin
   else begin
     Result := (Attr and FILE_ATTRIBUTE_DIRECTORY) = CDirAttributes[CheckDir];
     Result := (Attr and FILE_ATTRIBUTE_DIRECTORY) = CDirAttributes[CheckDir];
-    if Result and FollowLink and ((Attr and FILE_ATTRIBUTE_REPARSE_POINT) <> 0) then
-      Result := LinkFileExists;
+    if Result and FollowLink and ((Attr and FILE_ATTRIBUTE_REPARSE_POINT) <> 0) then begin
+      res := FileGetSymLinkTargetInt(FileOrDirName, slr, False);
+      case res of
+        slrOk:
+          Result := FileOrDirExists(slr.TargetName, CheckDir, False);
+        slrNoSymLink:
+          Result := True;
+        else
+          Result := False;
+      end;
+    end;
   end;
   end;
 end;
 end;
 
 

+ 46 - 0
tests/test/units/system/tabs.pp

@@ -232,6 +232,51 @@ procedure fail;
       WriteLn('Success!');
       WriteLn('Success!');
   end;
   end;
 
 
+
+ procedure test_abs_single;
+  var
+   _result : boolean;
+   value : single;
+   value1: single;
+  begin
+    _result := true;
+    Write('Abs() test with single type...');
+
+    value := VALUE_ONE_REAL;
+    if (trunc(abs(value)) <> trunc(RESULT_CONST_ONE_REAL))  then
+       _result := false;
+
+    value := VALUE_THREE_REAL;
+    if trunc(abs(value)) <> trunc(RESULT_CONST_THREE_REAL) then
+       _result := false;
+
+    value := VALUE_FOUR_REAL;
+    if trunc(abs(value)) <> trunc(RESULT_CONST_FOUR_REAL) then
+       _result := false;
+
+    value := VALUE_ONE_REAL;
+    value1 := abs(value);
+    if trunc(value1) <> trunc(RESULT_ONE_REAL) then
+       _result := false;
+
+    value := VALUE_THREE_REAL;
+    value1 := abs(value);
+    if trunc(value1) <> trunc(RESULT_THREE_REAL) then
+       _result := false;
+
+    value := VALUE_FOUR_REAL;
+    value1 := abs(value);
+    if trunc(value1) <> trunc(RESULT_FOUR_REAL) then
+       _result := false;
+
+    if not _result then
+      fail
+    else
+      WriteLn('Success!');
+  end;
+
+
+
  procedure test_abs_real;
  procedure test_abs_real;
   var
   var
    _result : boolean;
    _result : boolean;
@@ -294,6 +339,7 @@ Begin
   test_abs_currency;
   test_abs_currency;
 {$endif SKIP_CURRENCY_TEST}
 {$endif SKIP_CURRENCY_TEST}
   test_abs_real;
   test_abs_real;
+  test_abs_single;
   test_abs_longint;
   test_abs_longint;
   test_abs_int64;
   test_abs_int64;
 end.
 end.