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)}
         { use min/max intrinsic? }
         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
-          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)}
-          { 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}
           (((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))
@@ -1610,8 +1608,9 @@ implementation
 {$if defined(xtensa)}
           (CPUXTENSA_HAS_MINMAX in cpu_capabilities[current_settings.cputype]) and is_32bitint(tassignmentnode(thenstmnt).right.resultdef) and
 {$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
             paratype:=tassignmentnode(thenstmnt).left.resultdef;
             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
               the second parameter is taken, we have to put the else part into the second parameter
               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;
 {$endif defined(i386) or defined(x86_64) or defined(xtensa)}
 {$endif llvm}

+ 4 - 0
compiler/x86_64/aoptcpu.pas

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

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

@@ -489,6 +489,7 @@ type
     FHasShownEncoding: boolean;
     FHasShownLogo: boolean;
     FInsertFilenames: TStringList;
+    FAppendFilenames: TStringList;
     FInterfaceType: TPasClassInterfaceType;
     FLog: TPas2jsLogger;
     FMainFile: TPas2jsCompilerFile;
@@ -516,6 +517,7 @@ type
     FResourceStrings : TResourceStringsFile;
     FResourceStringFile :  TP2JSResourceStringFile;
     procedure AddInsertJSFilename(const aFilename: string);
+    procedure AddAppendJSFilename(const aFilename: string);
     Procedure AddNamespaces(const Paths: string; FromCmdLine: boolean);
     procedure AddUnitResourceStrings(aFile: TPas2jsCompilerFile);
     function CreateFileWriter(aFile: TPas2jsCompilerFile; const aFilename: string): TPas2JSMapper;
@@ -538,10 +540,13 @@ type
     function GetWriteDebugLog: boolean;
     function GetWriteMsgToStdErr: boolean;
     function IndexOfInsertJSFilename(const aFilename: string): integer;
+    function IndexOfAppendJSFilename(const aFilename: string): integer;
     procedure InsertCustomJSFiles(aWriter: TPas2JSMapper);
+    procedure AppendCustomJSFiles(aWriter: TPas2JSMapper);
     function LoadUsedUnit(Info: TLoadUnitInfo; Context: TPas2jsCompilerFile): TPas2jsCompilerFile;
     function OnMacroCfgDir(Sender: TObject; var Params: string; Lvl: integer): boolean;
     procedure RemoveInsertJSFilename(const aFilename: string);
+    procedure RemoveAppendJSFilename(const aFilename: string);
     function ResolvedMainJSFile: string;
     procedure SetAllJSIntoMainJS(AValue: Boolean);
     procedure SetConverterGlobals(const AValue: TPasToJSConverterGlobals);
@@ -716,7 +721,8 @@ type
     property WriteMsgToStdErr: boolean read GetWriteMsgToStdErr write SetWriteMsgToStdErr;
     property AllJSIntoMainJS: Boolean Read FAllJSIntoMainJS Write SetAllJSIntoMainJS;
     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 MainSrcFile: String Read FMainSrcFile Write FMainSrcFile;
     property SrcMapBaseDir: string read FSrcMapBaseDir write SetSrcMapBaseDir; // includes trailing pathdelim
@@ -2790,6 +2796,8 @@ begin
 
     if isSingleFile or aFile.isMainFile then
       begin
+      if aFile.IsMainFile  then
+        AppendCustomJSFiles(aFileWriter);
       if Assigned(PostProcessorSupport) then
         PostProcessorSupport.CallPostProcessors(aFile.JSFilename,aFileWriter);
 
@@ -3399,9 +3407,13 @@ begin
       else ParamFatal('invalid encoding (-Je) "'+aValue+'"');
       end;
     end;
+  'a', // -Ja<js-file>
   'i': // -Ji<js-file>
     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
     begin
       if aValue='' then
@@ -3411,10 +3423,16 @@ begin
         Delete(aValue,length(aValue),1);
         if aValue='' then
           Result:=False
+        else if c='i' then
+          RemoveInsertJSFilename(aValue)
         else
-          RemoveInsertJSFilename(aValue);
-      end else
-        AddInsertJSFilename(aValue);
+          RemoveAppendJSFileName(aValue);
+      end
+      else
+        if C='i' then
+          AddInsertJSFilename(aValue)
+        else
+          addAppendJSFileName(aValue)
     end;
   'l': // -Jl
     SetOption(coLowercase,aValue<>'-');
@@ -4205,6 +4223,7 @@ begin
   FNamespaces:=TStringList.Create;
   FDefines:=TStringList.Create;
   FInsertFilenames:=TStringList.Create;
+  FAppendFileNames:=TStringList.Create;
   FLog:=CreateLog;
   FLog.OnFormatPath:=@FormatPath;
   FParamMacros:=CreateMacroEngine;
@@ -4233,6 +4252,7 @@ destructor TPas2jsCompiler.Destroy;
     FreeAndNil(FNamespaces);
     FreeAndNil(FWPOAnalyzer);
     FreeAndNil(FInsertFilenames);
+    FreeAndNil(FAppendFilenames);
 
     FMainFile:=nil;
     FreeAndNil(FUnits);
@@ -4430,6 +4450,7 @@ begin
   FReadingModules.Clear;
   FFiles.FreeItems;
   FInsertFilenames.Clear;
+  FAppendFIleNames.Clear;
   if Assigned(FPostProcessorSupport) then
     FPostProcessorSupport.Clear;
   FCompilerExe:='';
@@ -4699,6 +4720,7 @@ begin
   w('   -FU<x>: Set unit output path to <x>');
   w('  -I<x>  : Add <x> to include paths, same as -Fi');
   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('   -Je<x>: Encode messages as <x>.');
   w('     -Jeconsole: Console codepage. This is the default.');
@@ -5173,6 +5195,32 @@ begin
   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
   ): integer;
 var
@@ -5186,6 +5234,7 @@ end;
 
 procedure TPas2jsCompiler.AddInsertJSFilename(const aFilename: string);
 begin
+
   if IndexOfInsertJSFilename(aFilename)<0 then
     InsertFilenames.Add(aFilename);
 end;
@@ -5199,6 +5248,35 @@ begin
     InsertFilenames.Delete(i);
 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;
 
 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}
 uses
@@ -23,6 +23,7 @@ procedure TestSingle;
         Result := b;
     end;
 
+
   function Min2(a, b: Single): Single; inline;
     begin
       if a <= b then
@@ -40,6 +41,38 @@ procedure TestSingle;
         Result := b;
     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
     v1,v3,vNaN : Single;
 
@@ -54,6 +87,14 @@ procedure TestSingle;
       halt(3);
     if Max2(1,3)<>3 then
       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
       halt(11);
     if Max1(1,v3)<>3 then
@@ -62,6 +103,14 @@ procedure TestSingle;
       halt(13);
     if Max2(1,v3)<>3 then
       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
       halt(21);
     if Max1(1,v3)<>v3 then
@@ -70,6 +119,14 @@ procedure TestSingle;
       halt(23);
     if Max2(1,v3)<>v3 then
       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
       halt(31);
     if Max1(v1,v3)<>v3 then
@@ -78,6 +135,14 @@ procedure TestSingle;
       halt(33);
     if Max2(v1,v3)<>v3 then
       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]);
     vNaN:=NaN;
     if not(IsNaN(Min1(v1,vNaN))) then
@@ -96,6 +161,22 @@ procedure TestSingle;
       halt(47);
     if Max2(vNaN,v3)<>v3 then
       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([]);
   end;
 
@@ -118,6 +199,7 @@ procedure TestDouble;
         Result := b;
     end;
 
+
   function Min2(a, b: Double): Double; inline;
     begin
       if a <= b then
@@ -135,6 +217,38 @@ procedure TestDouble;
         Result := b;
     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
     v1,v3,vNaN : Double;
 
@@ -142,13 +256,21 @@ procedure TestDouble;
     v1:=1;
     v3:=3;
     if Min1(1,3)<>1 then
-      halt(1);
+      halt(101);
     if Max1(1,3)<>3 then
-      halt(2);
+      halt(102);
     if Min2(1,3)<>1 then
-      halt(3);
+      halt(103);
     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
       halt(111);
     if Max1(1,v3)<>3 then
@@ -157,6 +279,14 @@ procedure TestDouble;
       halt(113);
     if Max2(1,v3)<>3 then
       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
       halt(121);
     if Max1(1,v3)<>v3 then
@@ -165,6 +295,14 @@ procedure TestDouble;
       halt(123);
     if Max2(1,v3)<>v3 then
       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
       halt(131);
     if Max1(v1,v3)<>v3 then
@@ -173,6 +311,14 @@ procedure TestDouble;
       halt(133);
     if Max2(v1,v3)<>v3 then
       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]);
     vNaN:=NaN;
     if not(IsNaN(Min1(v1,vNaN))) then
@@ -191,6 +337,22 @@ procedure TestDouble;
       halt(147);
     if Max2(vNaN,v3)<>v3 then
       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([]);
   end;
 
@@ -214,6 +376,7 @@ procedure TestDWord;
         Result := b;
     end;
 
+
   function Min2(a, b: DWord): DWord; inline;
     begin
       if a <= b then
@@ -231,6 +394,38 @@ procedure TestDWord;
         Result := b;
     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
     v1,v3 : DWord;
 
@@ -238,13 +433,21 @@ procedure TestDWord;
     v1:=1;
     v3:=3;
     if Min1(1,3)<>1 then
-      halt(1);
+      halt(201);
     if Max1(1,3)<>3 then
-      halt(2);
+      halt(202);
     if Min2(1,3)<>1 then
-      halt(3);
+      halt(203);
     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
       halt(211);
     if Max1(1,v3)<>3 then
@@ -253,6 +456,14 @@ procedure TestDWord;
       halt(213);
     if Max2(1,v3)<>3 then
       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
       halt(221);
     if Max1(1,v3)<>v3 then
@@ -261,6 +472,14 @@ procedure TestDWord;
       halt(223);
     if Max2(1,v3)<>v3 then
       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
       halt(231);
     if Max1(v1,v3)<>v3 then
@@ -269,6 +488,14 @@ procedure TestDWord;
       halt(233);
     if Max2(v1,v3)<>v3 then
       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;
 
 procedure TestLongint;
@@ -307,6 +534,38 @@ procedure TestLongint;
         Result := b;
     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
     v1,v3 : Longint;
 
@@ -314,13 +573,21 @@ procedure TestLongint;
     v1:=1;
     v3:=3;
     if Min1(1,3)<>1 then
-      halt(1);
+      halt(301);
     if Max1(1,3)<>3 then
-      halt(2);
+      halt(302);
     if Min2(1,3)<>1 then
-      halt(3);
+      halt(303);
     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
       halt(311);
     if Max1(1,v3)<>3 then
@@ -329,6 +596,14 @@ procedure TestLongint;
       halt(313);
     if Max2(1,v3)<>3 then
       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
       halt(321);
     if Max1(1,v3)<>v3 then
@@ -337,7 +612,14 @@ procedure TestLongint;
       halt(323);
     if Max2(1,v3)<>v3 then
       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
       halt(331);
     if Max1(v1,v3)<>v3 then
@@ -346,6 +628,14 @@ procedure TestLongint;
       halt(333);
     if Max2(v1,v3)<>v3 then
       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;
 
 begin