Browse Source

* synchronized with trunk

git-svn-id: branches/wasm@47772 -
nickysn 4 years ago
parent
commit
adb631f2cf
4 changed files with 407 additions and 30 deletions
  1. 16 11
      compiler/nflw.pas
  2. 4 0
      compiler/x86_64/aoptcpu.pas
  3. 83 5
      packages/pastojs/src/pas2jscompiler.pp
  4. 304 14
      tests/test/tminmax.pp

+ 16 - 11
compiler/nflw.pas

@@ -1592,13 +1592,11 @@ implementation
 {$if defined(i386) or defined(x86_64) or defined(xtensa)}
 {$if defined(i386) or defined(x86_64) or defined(xtensa)}
         { use min/max intrinsic? }
         { use min/max intrinsic? }
         if (cs_opt_level2 in current_settings.optimizerswitches) and
         if (cs_opt_level2 in current_settings.optimizerswitches) and
-           (left.nodetype in [gtn,gten,ltn,lten]) and IsSingleStatement(right,thenstmnt) and IsSingleStatement(t1,elsestmnt) and
-          (thenstmnt.nodetype=assignn) and (elsestmnt.nodetype=assignn) and
+           (left.nodetype in [gtn,gten,ltn,lten]) and IsSingleStatement(right,thenstmnt) and ((t1=nil) or IsSingleStatement(t1,elsestmnt)) and
+          (thenstmnt.nodetype=assignn) and ((t1=nil) or (elsestmnt.nodetype=assignn)) and
           not(might_have_sideeffects(left)) and
           not(might_have_sideeffects(left)) and
-          tassignmentnode(thenstmnt).left.isequal(tassignmentnode(elsestmnt).left) and
+          ((t1=nil) or tassignmentnode(thenstmnt).left.isequal(tassignmentnode(elsestmnt).left)) and
 {$if defined(i386) or defined(x86_64)}
 {$if defined(i386) or defined(x86_64)}
-          { for now, limit it to fastmath mode as NaN handling is not implemented properly yet }
-          (cs_opt_fastmath in current_settings.optimizerswitches) and
 {$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))
@@ -1610,8 +1608,9 @@ implementation
 {$if defined(xtensa)}
 {$if defined(xtensa)}
           (CPUXTENSA_HAS_MINMAX in cpu_capabilities[current_settings.cputype]) and is_32bitint(tassignmentnode(thenstmnt).right.resultdef) and
           (CPUXTENSA_HAS_MINMAX in cpu_capabilities[current_settings.cputype]) and is_32bitint(tassignmentnode(thenstmnt).right.resultdef) and
 {$endif defined(xtensa)}
 {$endif defined(xtensa)}
-          ((tassignmentnode(thenstmnt).right.isequal(taddnode(left).left) and (tassignmentnode(elsestmnt).right.isequal(taddnode(left).right))) or
-           (tassignmentnode(thenstmnt).right.isequal(taddnode(left).right) and (tassignmentnode(elsestmnt).right.isequal(taddnode(left).left)))) then
+          ((tassignmentnode(thenstmnt).right.isequal(taddnode(left).left) and ((t1=nil) or (tassignmentnode(elsestmnt).right.isequal(taddnode(left).right)))) or
+           (tassignmentnode(thenstmnt).right.isequal(taddnode(left).right) and ((t1=nil) or (tassignmentnode(elsestmnt).right.isequal(taddnode(left).left))))
+          ) then
           begin
           begin
             paratype:=tassignmentnode(thenstmnt).left.resultdef;
             paratype:=tassignmentnode(thenstmnt).left.resultdef;
             if ((left.nodetype in [gtn,gten]) and
             if ((left.nodetype in [gtn,gten]) and
@@ -1644,10 +1643,16 @@ implementation
               Due to the defined behaviour for the min/max intrinsics that in case of a NaN
               Due to the defined behaviour for the min/max intrinsics that in case of a NaN
               the second parameter is taken, we have to put the else part into the second parameter
               the second parameter is taken, we have to put the else part into the second parameter
               thus pass it to the first callparanode call }
               thus pass it to the first callparanode call }
-            Result:=cassignmentnode.create_internal(tassignmentnode(thenstmnt).left.getcopy,
-              cinlinenode.create(in_nr,false,ccallparanode.create(tassignmentnode(elsestmnt).right.getcopy,
-                    ccallparanode.create(tassignmentnode(thenstmnt).right.getcopy,nil)))
-              );
+            if t1=nil then
+              Result:=cassignmentnode.create_internal(tassignmentnode(thenstmnt).left.getcopy,
+                cinlinenode.create(in_nr,false,ccallparanode.create(tassignmentnode(thenstmnt).left.getcopy,
+                      ccallparanode.create(tassignmentnode(thenstmnt).right.getcopy,nil)))
+                )
+            else
+              Result:=cassignmentnode.create_internal(tassignmentnode(thenstmnt).left.getcopy,
+                cinlinenode.create(in_nr,false,ccallparanode.create(tassignmentnode(elsestmnt).right.getcopy,
+                      ccallparanode.create(tassignmentnode(thenstmnt).right.getcopy,nil)))
+                );
           end;
           end;
 {$endif defined(i386) or defined(x86_64) or defined(xtensa)}
 {$endif defined(i386) or defined(x86_64) or defined(xtensa)}
 {$endif llvm}
 {$endif llvm}

+ 4 - 0
compiler/x86_64/aoptcpu.pas

@@ -90,6 +90,10 @@ uses
                 A_VMOVUPS,
                 A_VMOVUPS,
                 A_VMOVUPD:
                 A_VMOVUPD:
                   result:=OptPass1_V_MOVAP(p);
                   result:=OptPass1_V_MOVAP(p);
+                A_VMINSS,
+                A_VMINSD,
+                A_VMAXSS,
+                A_VMAXSD,
                 A_VSQRTSD,
                 A_VSQRTSD,
                 A_VSQRTSS,
                 A_VSQRTSS,
                 A_VDIVSD,
                 A_VDIVSD,

+ 83 - 5
packages/pastojs/src/pas2jscompiler.pp

@@ -489,6 +489,7 @@ type
     FHasShownEncoding: boolean;
     FHasShownEncoding: boolean;
     FHasShownLogo: boolean;
     FHasShownLogo: boolean;
     FInsertFilenames: TStringList;
     FInsertFilenames: TStringList;
+    FAppendFilenames: TStringList;
     FInterfaceType: TPasClassInterfaceType;
     FInterfaceType: TPasClassInterfaceType;
     FLog: TPas2jsLogger;
     FLog: TPas2jsLogger;
     FMainFile: TPas2jsCompilerFile;
     FMainFile: TPas2jsCompilerFile;
@@ -516,6 +517,7 @@ type
     FResourceStrings : TResourceStringsFile;
     FResourceStrings : TResourceStringsFile;
     FResourceStringFile :  TP2JSResourceStringFile;
     FResourceStringFile :  TP2JSResourceStringFile;
     procedure AddInsertJSFilename(const aFilename: string);
     procedure AddInsertJSFilename(const aFilename: string);
+    procedure AddAppendJSFilename(const aFilename: string);
     Procedure AddNamespaces(const Paths: string; FromCmdLine: boolean);
     Procedure AddNamespaces(const Paths: string; FromCmdLine: boolean);
     procedure AddUnitResourceStrings(aFile: TPas2jsCompilerFile);
     procedure AddUnitResourceStrings(aFile: TPas2jsCompilerFile);
     function CreateFileWriter(aFile: TPas2jsCompilerFile; const aFilename: string): TPas2JSMapper;
     function CreateFileWriter(aFile: TPas2jsCompilerFile; const aFilename: string): TPas2JSMapper;
@@ -538,10 +540,13 @@ type
     function GetWriteDebugLog: boolean;
     function GetWriteDebugLog: boolean;
     function GetWriteMsgToStdErr: boolean;
     function GetWriteMsgToStdErr: boolean;
     function IndexOfInsertJSFilename(const aFilename: string): integer;
     function IndexOfInsertJSFilename(const aFilename: string): integer;
+    function IndexOfAppendJSFilename(const aFilename: string): integer;
     procedure InsertCustomJSFiles(aWriter: TPas2JSMapper);
     procedure InsertCustomJSFiles(aWriter: TPas2JSMapper);
+    procedure AppendCustomJSFiles(aWriter: TPas2JSMapper);
     function LoadUsedUnit(Info: TLoadUnitInfo; Context: TPas2jsCompilerFile): TPas2jsCompilerFile;
     function LoadUsedUnit(Info: TLoadUnitInfo; Context: TPas2jsCompilerFile): TPas2jsCompilerFile;
     function OnMacroCfgDir(Sender: TObject; var Params: string; Lvl: integer): boolean;
     function OnMacroCfgDir(Sender: TObject; var Params: string; Lvl: integer): boolean;
     procedure RemoveInsertJSFilename(const aFilename: string);
     procedure RemoveInsertJSFilename(const aFilename: string);
+    procedure RemoveAppendJSFilename(const aFilename: string);
     function ResolvedMainJSFile: string;
     function ResolvedMainJSFile: string;
     procedure SetAllJSIntoMainJS(AValue: Boolean);
     procedure SetAllJSIntoMainJS(AValue: Boolean);
     procedure SetConverterGlobals(const AValue: TPasToJSConverterGlobals);
     procedure SetConverterGlobals(const AValue: TPasToJSConverterGlobals);
@@ -716,7 +721,8 @@ type
     property WriteMsgToStdErr: boolean read GetWriteMsgToStdErr write SetWriteMsgToStdErr;
     property WriteMsgToStdErr: boolean read GetWriteMsgToStdErr write SetWriteMsgToStdErr;
     property AllJSIntoMainJS: Boolean Read FAllJSIntoMainJS Write SetAllJSIntoMainJS;
     property AllJSIntoMainJS: Boolean Read FAllJSIntoMainJS Write SetAllJSIntoMainJS;
     property ExitCode: longint read GetExitCode write SetExitCode;
     property ExitCode: longint read GetExitCode write SetExitCode;
-    property InsertFilenames: TStringList read FInsertFilenames;
+    property InsertFilenames : TStringList read FInsertFilenames;
+    Property AppendFileNames : TStringList read FAppendFileNames;
     property MainJSFile: String Read FMainJSFile Write FMainJSFile;
     property MainJSFile: String Read FMainJSFile Write FMainJSFile;
     property MainSrcFile: String Read FMainSrcFile Write FMainSrcFile;
     property MainSrcFile: String Read FMainSrcFile Write FMainSrcFile;
     property SrcMapBaseDir: string read FSrcMapBaseDir write SetSrcMapBaseDir; // includes trailing pathdelim
     property SrcMapBaseDir: string read FSrcMapBaseDir write SetSrcMapBaseDir; // includes trailing pathdelim
@@ -2790,6 +2796,8 @@ begin
 
 
     if isSingleFile or aFile.isMainFile then
     if isSingleFile or aFile.isMainFile then
       begin
       begin
+      if aFile.IsMainFile  then
+        AppendCustomJSFiles(aFileWriter);
       if Assigned(PostProcessorSupport) then
       if Assigned(PostProcessorSupport) then
         PostProcessorSupport.CallPostProcessors(aFile.JSFilename,aFileWriter);
         PostProcessorSupport.CallPostProcessors(aFile.JSFilename,aFileWriter);
 
 
@@ -3399,9 +3407,13 @@ begin
       else ParamFatal('invalid encoding (-Je) "'+aValue+'"');
       else ParamFatal('invalid encoding (-Je) "'+aValue+'"');
       end;
       end;
     end;
     end;
+  'a', // -Ja<js-file>
   'i': // -Ji<js-file>
   'i': // -Ji<js-file>
     if aValue='' then
     if aValue='' then
-      ParamFatal('missing insertion file "'+aValue+'"')
+      if c='a' then
+        ParamFatal('missing append file "'+aValue+'"')
+      else
+        ParamFatal('missing insertion file "'+aValue+'"')
     else if not Quick then
     else if not Quick then
     begin
     begin
       if aValue='' then
       if aValue='' then
@@ -3411,10 +3423,16 @@ begin
         Delete(aValue,length(aValue),1);
         Delete(aValue,length(aValue),1);
         if aValue='' then
         if aValue='' then
           Result:=False
           Result:=False
+        else if c='i' then
+          RemoveInsertJSFilename(aValue)
         else
         else
-          RemoveInsertJSFilename(aValue);
-      end else
-        AddInsertJSFilename(aValue);
+          RemoveAppendJSFileName(aValue);
+      end
+      else
+        if C='i' then
+          AddInsertJSFilename(aValue)
+        else
+          addAppendJSFileName(aValue)
     end;
     end;
   'l': // -Jl
   'l': // -Jl
     SetOption(coLowercase,aValue<>'-');
     SetOption(coLowercase,aValue<>'-');
@@ -4205,6 +4223,7 @@ begin
   FNamespaces:=TStringList.Create;
   FNamespaces:=TStringList.Create;
   FDefines:=TStringList.Create;
   FDefines:=TStringList.Create;
   FInsertFilenames:=TStringList.Create;
   FInsertFilenames:=TStringList.Create;
+  FAppendFileNames:=TStringList.Create;
   FLog:=CreateLog;
   FLog:=CreateLog;
   FLog.OnFormatPath:=@FormatPath;
   FLog.OnFormatPath:=@FormatPath;
   FParamMacros:=CreateMacroEngine;
   FParamMacros:=CreateMacroEngine;
@@ -4233,6 +4252,7 @@ destructor TPas2jsCompiler.Destroy;
     FreeAndNil(FNamespaces);
     FreeAndNil(FNamespaces);
     FreeAndNil(FWPOAnalyzer);
     FreeAndNil(FWPOAnalyzer);
     FreeAndNil(FInsertFilenames);
     FreeAndNil(FInsertFilenames);
+    FreeAndNil(FAppendFilenames);
 
 
     FMainFile:=nil;
     FMainFile:=nil;
     FreeAndNil(FUnits);
     FreeAndNil(FUnits);
@@ -4430,6 +4450,7 @@ begin
   FReadingModules.Clear;
   FReadingModules.Clear;
   FFiles.FreeItems;
   FFiles.FreeItems;
   FInsertFilenames.Clear;
   FInsertFilenames.Clear;
+  FAppendFIleNames.Clear;
   if Assigned(FPostProcessorSupport) then
   if Assigned(FPostProcessorSupport) then
     FPostProcessorSupport.Clear;
     FPostProcessorSupport.Clear;
   FCompilerExe:='';
   FCompilerExe:='';
@@ -4699,6 +4720,7 @@ begin
   w('   -FU<x>: Set unit output path to <x>');
   w('   -FU<x>: Set unit output path to <x>');
   w('  -I<x>  : Add <x> to include paths, same as -Fi');
   w('  -I<x>  : Add <x> to include paths, same as -Fi');
   w('  -J...  Extra options of pas2js');
   w('  -J...  Extra options of pas2js');
+  w('   -Ja<x>: Append JS file <x> to main JS file. E.g. -Jamap.js. Can be given multiple times. To remove a file name append a minus, e.g. -Jamap.js-.');
   w('   -Jc   : Write all JavaScript concatenated into the output file');
   w('   -Jc   : Write all JavaScript concatenated into the output file');
   w('   -Je<x>: Encode messages as <x>.');
   w('   -Je<x>: Encode messages as <x>.');
   w('     -Jeconsole: Console codepage. This is the default.');
   w('     -Jeconsole: Console codepage. This is the default.');
@@ -5173,6 +5195,32 @@ begin
   end;
   end;
 end;
 end;
 
 
+procedure TPas2jsCompiler.AppendCustomJSFiles(aWriter: TPas2JSMapper);
+var
+  i: Integer;
+  Filename: String;
+  FileResolver: TPas2jsFSResolver;
+  aFile: TPas2jsFile;
+begin
+  if AppendFilenames.Count=0 then exit;
+  FileResolver:=FS.CreateResolver;
+  try
+    for i:=0 to AppendFilenames.Count-1 do begin
+      Filename:=FS.FindCustomJSFileName(AppendFilenames[i]);
+      if Filename='' then
+      begin
+        Log.LogMsg(nCustomJSFileNotFound,[AppendFilenames[i]]);
+        raise EFileNotFoundError.Create('');
+      end;
+      aFile:=LoadFile(Filename);
+      if aFile.Source='' then continue;
+      aWriter.WriteFile(aFile.Source,Filename);
+    end
+  finally
+    FileResolver.Free;
+  end;
+end;
+
 function TPas2jsCompiler.IndexOfInsertJSFilename(const aFilename: string
 function TPas2jsCompiler.IndexOfInsertJSFilename(const aFilename: string
   ): integer;
   ): integer;
 var
 var
@@ -5186,6 +5234,7 @@ end;
 
 
 procedure TPas2jsCompiler.AddInsertJSFilename(const aFilename: string);
 procedure TPas2jsCompiler.AddInsertJSFilename(const aFilename: string);
 begin
 begin
+
   if IndexOfInsertJSFilename(aFilename)<0 then
   if IndexOfInsertJSFilename(aFilename)<0 then
     InsertFilenames.Add(aFilename);
     InsertFilenames.Add(aFilename);
 end;
 end;
@@ -5199,6 +5248,35 @@ begin
     InsertFilenames.Delete(i);
     InsertFilenames.Delete(i);
 end;
 end;
 
 
+function TPas2jsCompiler.IndexOfAppendJSFilename(const aFilename: string
+  ): integer;
+var
+  i: Integer;
+begin
+  for i:=0 to AppendFilenames.Count-1 do
+    if FS.SameFileName(aFilename,AppendFilenames[i]) then
+      exit(i);
+  Result:=-1;
+end;
+
+
+procedure TPas2jsCompiler.RemoveAppendJSFilename(const aFilename: string);
+var
+  i: Integer;
+begin
+  i:=IndexOfAppendJSFilename(aFilename);
+  if i>=0 then
+    AppendFilenames.Delete(i);
+end;
+
+
+procedure TPas2jsCompiler.AddAppendJSFilename(const aFilename: string);
+begin
+  if IndexOfAppendJSFilename(aFilename)<0 then
+    AppendFilenames.Add(aFilename);
+end;
+
+
 function TPas2jsCompiler.GetResolvedMainJSFile: string;
 function TPas2jsCompiler.GetResolvedMainJSFile: string;
 
 
 begin
 begin

+ 304 - 14
tests/test/tminmax.pp

@@ -1,4 +1,4 @@
-{ %opt=-O- -Oonofastmath }  { with fast math, the operands of min/max might be swapped and this breaks the tests using NaN }
+{ %opt=-Oonofastmath }  { with fast math, the operands of min/max might be swapped and this breaks the tests using NaN }
 
 
 {$mode objfpc}
 {$mode objfpc}
 uses
 uses
@@ -23,6 +23,7 @@ procedure TestSingle;
         Result := b;
         Result := b;
     end;
     end;
 
 
+
   function Min2(a, b: Single): Single; inline;
   function Min2(a, b: Single): Single; inline;
     begin
     begin
       if a <= b then
       if a <= b then
@@ -40,6 +41,38 @@ procedure TestSingle;
         Result := b;
         Result := b;
     end;
     end;
 
 
+
+  function Min3(a, b: Single): Single; inline;
+    begin
+      Result := b;
+      if a < b then
+        Result := a;
+    end;
+
+
+  function Max3(a, b: Single): Single; inline;
+    begin
+      Result := b;
+      if a > b then
+        Result := a;
+    end;
+
+
+  function Min4(a, b: Single): Single; inline;
+    begin
+      Result := b;
+      if a <= b then
+        Result := a;
+    end;
+
+
+  function Max4(a, b: Single): Single; inline;
+    begin
+      Result := b;
+      if a >= b then
+        Result := a;
+    end;
+
   var
   var
     v1,v3,vNaN : Single;
     v1,v3,vNaN : Single;
 
 
@@ -54,6 +87,14 @@ procedure TestSingle;
       halt(3);
       halt(3);
     if Max2(1,3)<>3 then
     if Max2(1,3)<>3 then
       halt(4);
       halt(4);
+    if Min3(1,3)<>1 then
+      halt(5);
+    if Max3(1,3)<>3 then
+      halt(6);
+    if Min3(1,3)<>1 then
+      halt(7);
+    if Max3(1,3)<>3 then
+      halt(8);
     if Min1(1,v3)<>1 then
     if Min1(1,v3)<>1 then
       halt(11);
       halt(11);
     if Max1(1,v3)<>3 then
     if Max1(1,v3)<>3 then
@@ -62,6 +103,14 @@ procedure TestSingle;
       halt(13);
       halt(13);
     if Max2(1,v3)<>3 then
     if Max2(1,v3)<>3 then
       halt(14);
       halt(14);
+    if Min3(1,v3)<>1 then
+      halt(15);
+    if Max3(1,v3)<>3 then
+      halt(16);
+    if Min4(1,v3)<>1 then
+      halt(17);
+    if Max4(1,v3)<>3 then
+      halt(18);
     if Min1(1,v3)<>1 then
     if Min1(1,v3)<>1 then
       halt(21);
       halt(21);
     if Max1(1,v3)<>v3 then
     if Max1(1,v3)<>v3 then
@@ -70,6 +119,14 @@ procedure TestSingle;
       halt(23);
       halt(23);
     if Max2(1,v3)<>v3 then
     if Max2(1,v3)<>v3 then
       halt(24);
       halt(24);
+    if Min3(1,v3)<>1 then
+      halt(25);
+    if Max3(1,v3)<>v3 then
+      halt(26);
+    if Min4(1,v3)<>1 then
+      halt(27);
+    if Max4(1,v3)<>v3 then
+      halt(28);
     if Min1(v1,v3)<>v1 then
     if Min1(v1,v3)<>v1 then
       halt(31);
       halt(31);
     if Max1(v1,v3)<>v3 then
     if Max1(v1,v3)<>v3 then
@@ -78,6 +135,14 @@ procedure TestSingle;
       halt(33);
       halt(33);
     if Max2(v1,v3)<>v3 then
     if Max2(v1,v3)<>v3 then
       halt(34);
       halt(34);
+    if Min3(v1,v3)<>v1 then
+      halt(35);
+    if Max3(v1,v3)<>v3 then
+      halt(36);
+    if Min4(v1,v3)<>v1 then
+      halt(37);
+    if Max4(v1,v3)<>v3 then
+      halt(38);
     SetExceptionMask([exInvalidOp]);
     SetExceptionMask([exInvalidOp]);
     vNaN:=NaN;
     vNaN:=NaN;
     if not(IsNaN(Min1(v1,vNaN))) then
     if not(IsNaN(Min1(v1,vNaN))) then
@@ -96,6 +161,22 @@ procedure TestSingle;
       halt(47);
       halt(47);
     if Max2(vNaN,v3)<>v3 then
     if Max2(vNaN,v3)<>v3 then
       halt(48);
       halt(48);
+    if not(IsNaN(Min3(v1,vNaN))) then
+      halt(49);
+    if Min3(NaN,v1)<>v1 then
+      halt(50);
+    if not(IsNaN(Max3(v1,vNaN))) then
+      halt(51);
+    if Max3(vNaN,v3)<>v3 then
+      halt(52);
+    if not(IsNaN(Min4(v1,vNaN))) then
+      halt(53);
+    if Min4(vNaN,v3)<>v3 then
+      halt(54);
+    if not(IsNaN(Max4(v1,vNaN))) then
+      halt(55);
+    if Max4(vNaN,v3)<>v3 then
+      halt(56);
     SetExceptionMask([]);
     SetExceptionMask([]);
   end;
   end;
 
 
@@ -118,6 +199,7 @@ procedure TestDouble;
         Result := b;
         Result := b;
     end;
     end;
 
 
+
   function Min2(a, b: Double): Double; inline;
   function Min2(a, b: Double): Double; inline;
     begin
     begin
       if a <= b then
       if a <= b then
@@ -135,6 +217,38 @@ procedure TestDouble;
         Result := b;
         Result := b;
     end;
     end;
 
 
+
+  function Min3(a, b: Double): Double; inline;
+    begin
+      Result := b;
+      if a < b then
+        Result := a;
+    end;
+
+
+  function Max3(a, b: Double): Double; inline;
+    begin
+      Result := b;
+      if a > b then
+        Result := a;
+    end;
+
+
+  function Min4(a, b: Double): Double; inline;
+    begin
+      Result := b;
+      if a <= b then
+        Result := a;
+    end;
+
+
+  function Max4(a, b: Double): Double; inline;
+    begin
+      Result := b;
+      if a >= b then
+        Result := a;
+    end;
+
   var
   var
     v1,v3,vNaN : Double;
     v1,v3,vNaN : Double;
 
 
@@ -142,13 +256,21 @@ procedure TestDouble;
     v1:=1;
     v1:=1;
     v3:=3;
     v3:=3;
     if Min1(1,3)<>1 then
     if Min1(1,3)<>1 then
-      halt(1);
+      halt(101);
     if Max1(1,3)<>3 then
     if Max1(1,3)<>3 then
-      halt(2);
+      halt(102);
     if Min2(1,3)<>1 then
     if Min2(1,3)<>1 then
-      halt(3);
+      halt(103);
     if Max2(1,3)<>3 then
     if Max2(1,3)<>3 then
-      halt(4);
+      halt(104);
+    if Min3(1,3)<>1 then
+      halt(105);
+    if Max3(1,3)<>3 then
+      halt(106);
+    if Min3(1,3)<>1 then
+      halt(107);
+    if Max3(1,3)<>3 then
+      halt(108);
     if Min1(1,v3)<>1 then
     if Min1(1,v3)<>1 then
       halt(111);
       halt(111);
     if Max1(1,v3)<>3 then
     if Max1(1,v3)<>3 then
@@ -157,6 +279,14 @@ procedure TestDouble;
       halt(113);
       halt(113);
     if Max2(1,v3)<>3 then
     if Max2(1,v3)<>3 then
       halt(114);
       halt(114);
+    if Min3(1,v3)<>1 then
+      halt(115);
+    if Max3(1,v3)<>3 then
+      halt(116);
+    if Min4(1,v3)<>1 then
+      halt(117);
+    if Max4(1,v3)<>3 then
+      halt(118);
     if Min1(1,v3)<>1 then
     if Min1(1,v3)<>1 then
       halt(121);
       halt(121);
     if Max1(1,v3)<>v3 then
     if Max1(1,v3)<>v3 then
@@ -165,6 +295,14 @@ procedure TestDouble;
       halt(123);
       halt(123);
     if Max2(1,v3)<>v3 then
     if Max2(1,v3)<>v3 then
       halt(124);
       halt(124);
+    if Min3(1,v3)<>1 then
+      halt(125);
+    if Max3(1,v3)<>v3 then
+      halt(126);
+    if Min4(1,v3)<>1 then
+      halt(127);
+    if Max4(1,v3)<>v3 then
+      halt(128);
     if Min1(v1,v3)<>v1 then
     if Min1(v1,v3)<>v1 then
       halt(131);
       halt(131);
     if Max1(v1,v3)<>v3 then
     if Max1(v1,v3)<>v3 then
@@ -173,6 +311,14 @@ procedure TestDouble;
       halt(133);
       halt(133);
     if Max2(v1,v3)<>v3 then
     if Max2(v1,v3)<>v3 then
       halt(134);
       halt(134);
+    if Min3(v1,v3)<>v1 then
+      halt(135);
+    if Max3(v1,v3)<>v3 then
+      halt(136);
+    if Min4(v1,v3)<>v1 then
+      halt(137);
+    if Max4(v1,v3)<>v3 then
+      halt(138);
     SetExceptionMask([exInvalidOp]);
     SetExceptionMask([exInvalidOp]);
     vNaN:=NaN;
     vNaN:=NaN;
     if not(IsNaN(Min1(v1,vNaN))) then
     if not(IsNaN(Min1(v1,vNaN))) then
@@ -191,6 +337,22 @@ procedure TestDouble;
       halt(147);
       halt(147);
     if Max2(vNaN,v3)<>v3 then
     if Max2(vNaN,v3)<>v3 then
       halt(148);
       halt(148);
+    if not(IsNaN(Min3(v1,vNaN))) then
+      halt(149);
+    if Min3(NaN,v1)<>v1 then
+      halt(150);
+    if not(IsNaN(Max3(v1,vNaN))) then
+      halt(151);
+    if Max3(vNaN,v3)<>v3 then
+      halt(152);
+    if not(IsNaN(Min4(v1,vNaN))) then
+      halt(153);
+    if Min4(vNaN,v3)<>v3 then
+      halt(154);
+    if not(IsNaN(Max4(v1,vNaN))) then
+      halt(155);
+    if Max4(vNaN,v3)<>v3 then
+      halt(156);
     SetExceptionMask([]);
     SetExceptionMask([]);
   end;
   end;
 
 
@@ -214,6 +376,7 @@ procedure TestDWord;
         Result := b;
         Result := b;
     end;
     end;
 
 
+
   function Min2(a, b: DWord): DWord; inline;
   function Min2(a, b: DWord): DWord; inline;
     begin
     begin
       if a <= b then
       if a <= b then
@@ -231,6 +394,38 @@ procedure TestDWord;
         Result := b;
         Result := b;
     end;
     end;
 
 
+
+  function Min3(a, b: DWord): DWord; inline;
+    begin
+      Result := b;
+      if a < b then
+        Result := a;
+    end;
+
+
+  function Max3(a, b: DWord): DWord; inline;
+    begin
+      Result := b;
+      if a > b then
+        Result := a;
+    end;
+
+
+  function Min4(a, b: DWord): DWord; inline;
+    begin
+      Result := b;
+      if a <= b then
+        Result := a;
+    end;
+
+
+  function Max4(a, b: Double): Double; inline;
+    begin
+      Result := b;
+      if a >= b then
+        Result := a;
+    end;
+
   var
   var
     v1,v3 : DWord;
     v1,v3 : DWord;
 
 
@@ -238,13 +433,21 @@ procedure TestDWord;
     v1:=1;
     v1:=1;
     v3:=3;
     v3:=3;
     if Min1(1,3)<>1 then
     if Min1(1,3)<>1 then
-      halt(1);
+      halt(201);
     if Max1(1,3)<>3 then
     if Max1(1,3)<>3 then
-      halt(2);
+      halt(202);
     if Min2(1,3)<>1 then
     if Min2(1,3)<>1 then
-      halt(3);
+      halt(203);
     if Max2(1,3)<>3 then
     if Max2(1,3)<>3 then
-      halt(4);
+      halt(204);
+    if Min3(1,3)<>1 then
+      halt(205);
+    if Max3(1,3)<>3 then
+      halt(206);
+    if Min3(1,3)<>1 then
+      halt(207);
+    if Max3(1,3)<>3 then
+      halt(208);
     if Min1(1,v3)<>1 then
     if Min1(1,v3)<>1 then
       halt(211);
       halt(211);
     if Max1(1,v3)<>3 then
     if Max1(1,v3)<>3 then
@@ -253,6 +456,14 @@ procedure TestDWord;
       halt(213);
       halt(213);
     if Max2(1,v3)<>3 then
     if Max2(1,v3)<>3 then
       halt(214);
       halt(214);
+    if Min3(1,v3)<>1 then
+      halt(215);
+    if Max3(1,v3)<>3 then
+      halt(216);
+    if Min4(1,v3)<>1 then
+      halt(217);
+    if Max4(1,v3)<>3 then
+      halt(218);
     if Min1(1,v3)<>1 then
     if Min1(1,v3)<>1 then
       halt(221);
       halt(221);
     if Max1(1,v3)<>v3 then
     if Max1(1,v3)<>v3 then
@@ -261,6 +472,14 @@ procedure TestDWord;
       halt(223);
       halt(223);
     if Max2(1,v3)<>v3 then
     if Max2(1,v3)<>v3 then
       halt(224);
       halt(224);
+    if Min3(1,v3)<>1 then
+      halt(225);
+    if Max3(1,v3)<>v3 then
+      halt(226);
+    if Min4(1,v3)<>1 then
+      halt(227);
+    if Max4(1,v3)<>v3 then
+      halt(228);
     if Min1(v1,v3)<>v1 then
     if Min1(v1,v3)<>v1 then
       halt(231);
       halt(231);
     if Max1(v1,v3)<>v3 then
     if Max1(v1,v3)<>v3 then
@@ -269,6 +488,14 @@ procedure TestDWord;
       halt(233);
       halt(233);
     if Max2(v1,v3)<>v3 then
     if Max2(v1,v3)<>v3 then
       halt(234);
       halt(234);
+    if Min3(v1,v3)<>v1 then
+      halt(235);
+    if Max3(v1,v3)<>v3 then
+      halt(236);
+    if Min4(v1,v3)<>v1 then
+      halt(237);
+    if Max4(v1,v3)<>v3 then
+      halt(238);
   end;
   end;
 
 
 procedure TestLongint;
 procedure TestLongint;
@@ -307,6 +534,38 @@ procedure TestLongint;
         Result := b;
         Result := b;
     end;
     end;
 
 
+
+  function Min3(a, b: Longint): Longint; inline;
+    begin
+      Result := b;
+      if a < b then
+        Result := a;
+    end;
+
+
+  function Max3(a, b: Longint): Longint; inline;
+    begin
+      Result := b;
+      if a > b then
+        Result := a;
+    end;
+
+
+  function Min4(a, b: Longint): Longint; inline;
+    begin
+      Result := b;
+      if a <= b then
+        Result := a;
+    end;
+
+
+  function Max4(a, b: Longint): Longint; inline;
+    begin
+      Result := b;
+      if a >= b then
+        Result := a;
+    end;
+
   var
   var
     v1,v3 : Longint;
     v1,v3 : Longint;
 
 
@@ -314,13 +573,21 @@ procedure TestLongint;
     v1:=1;
     v1:=1;
     v3:=3;
     v3:=3;
     if Min1(1,3)<>1 then
     if Min1(1,3)<>1 then
-      halt(1);
+      halt(301);
     if Max1(1,3)<>3 then
     if Max1(1,3)<>3 then
-      halt(2);
+      halt(302);
     if Min2(1,3)<>1 then
     if Min2(1,3)<>1 then
-      halt(3);
+      halt(303);
     if Max2(1,3)<>3 then
     if Max2(1,3)<>3 then
-      halt(4);
+      halt(304);
+    if Min3(1,3)<>1 then
+      halt(305);
+    if Max3(1,3)<>3 then
+      halt(306);
+    if Min3(1,3)<>1 then
+      halt(307);
+    if Max3(1,3)<>3 then
+      halt(308);
     if Min1(1,v3)<>1 then
     if Min1(1,v3)<>1 then
       halt(311);
       halt(311);
     if Max1(1,v3)<>3 then
     if Max1(1,v3)<>3 then
@@ -329,6 +596,14 @@ procedure TestLongint;
       halt(313);
       halt(313);
     if Max2(1,v3)<>3 then
     if Max2(1,v3)<>3 then
       halt(314);
       halt(314);
+    if Min3(1,v3)<>1 then
+      halt(315);
+    if Max3(1,v3)<>3 then
+      halt(316);
+    if Min4(1,v3)<>1 then
+      halt(317);
+    if Max4(1,v3)<>3 then
+      halt(318);
     if Min1(1,v3)<>1 then
     if Min1(1,v3)<>1 then
       halt(321);
       halt(321);
     if Max1(1,v3)<>v3 then
     if Max1(1,v3)<>v3 then
@@ -337,7 +612,14 @@ procedure TestLongint;
       halt(323);
       halt(323);
     if Max2(1,v3)<>v3 then
     if Max2(1,v3)<>v3 then
       halt(324);
       halt(324);
-    v1:=1;
+    if Min3(1,v3)<>1 then
+      halt(325);
+    if Max3(1,v3)<>v3 then
+      halt(326);
+    if Min4(1,v3)<>1 then
+      halt(327);
+    if Max4(1,v3)<>v3 then
+      halt(328);
     if Min1(v1,v3)<>v1 then
     if Min1(v1,v3)<>v1 then
       halt(331);
       halt(331);
     if Max1(v1,v3)<>v3 then
     if Max1(v1,v3)<>v3 then
@@ -346,6 +628,14 @@ procedure TestLongint;
       halt(333);
       halt(333);
     if Max2(v1,v3)<>v3 then
     if Max2(v1,v3)<>v3 then
       halt(334);
       halt(334);
+    if Min3(v1,v3)<>v1 then
+      halt(335);
+    if Max3(v1,v3)<>v3 then
+      halt(336);
+    if Min4(v1,v3)<>v1 then
+      halt(337);
+    if Max4(v1,v3)<>v3 then
+      halt(338);
   end;
   end;
 
 
 begin
 begin