From a7232669fff29a5a4054bb64ea000f402d31bc45 Mon Sep 17 00:00:00 2001
From: pierre <pierre@freepascal.org>
Date: Mon, 7 Dec 2020 07:28:04 +0000
Subject: [PATCH]    * Adapted from patch node-dump-pass-1.patch submitted by
 J. Gareth Moreton from bug report 38156.      This patch extends the
 DEBUG_NODE_XML debug feature by also outputting,      to the *-node-dump.xml
 files, the node tree as it appears after the first pass,      since it often
 contains many more internal nodes like temporary allocations that may need   
   to be evaluated for debugging and development purposes, or node-level
 optimisation opportunities.

git-svn-id: trunk@47709 -
---
 compiler/psub.pas | 251 ++++++++++++++++++++++++++++------------------
 1 file changed, 152 insertions(+), 99 deletions(-)

diff --git a/compiler/psub.pas b/compiler/psub.pas
index b070099fc4..49836771a5 100644
--- a/compiler/psub.pas
+++ b/compiler/psub.pas
@@ -86,7 +86,7 @@ interface
         function has_assembler_child : boolean;
         procedure set_eh_info; override;
 {$ifdef DEBUG_NODE_XML}
-        procedure XMLPrintProc;
+        procedure XMLPrintProc(FirstHalf: Boolean);
 {$endif DEBUG_NODE_XML}
       end;
 
@@ -1437,15 +1437,19 @@ implementation
 
 
 {$ifdef DEBUG_NODE_XML}
-    procedure tcgprocinfo.XMLPrintProc;
+    procedure tcgprocinfo.XMLPrintProc(FirstHalf: Boolean);
       var
         T: Text;
         W: Word;
         syssym: tsyssym;
+        separate : boolean;
 
       procedure PrintType(Flag: string);
         begin
-          Write(T, ' type="', Flag, '"');
+          if df_generic in procdef.defoptions then
+            Write(T, ' type="generic ', Flag, '"')
+          else
+            Write(T, ' type="', Flag, '"');
         end;
 
       procedure PrintOption(Flag: string);
@@ -1467,109 +1471,132 @@ implementation
             Exit;
           end;
         {$pop}
-        Write(T, PrintNodeIndention, '<subroutine');
 
-        { Check to see if the procedure is a class or object method }
-        if Assigned(procdef.struct) then
+        separate := (df_generic in procdef.defoptions);
+
+        { First half prints the header and the nodes as a "code" tag }
+        if FirstHalf or separate then
           begin
-            if Assigned(procdef.struct.objrealname) then
-              Write(T, ' struct="', SanitiseXMLString(procdef.struct.objrealname^), '"')
-            else
-              Write(T, ' struct="&lt;NULL&gt;"');
+            Write(T, PrintNodeIndention, '<subroutine');
+            { Check to see if the procedure is a class or object method }
+            if Assigned(procdef.struct) then
+              begin
+                if Assigned(procdef.struct.objrealname) then
+                  Write(T, ' struct="', SanitiseXMLString(procdef.struct.objrealname^), '"')
+                else
+                  Write(T, ' struct="&lt;NULL&gt;"');
+              end;
+            case procdef.proctypeoption of
+              potype_none:
+                { Do nothing - should this be an internal error though? };
+              potype_procedure,
+              potype_function:
+                if po_classmethod in procdef.procoptions then
+                  begin
+                    if po_staticmethod in procdef.procoptions then
+                      PrintType('static class method')
+                    else
+                      PrintType('class method');
+                  end
+                else if df_generic in procdef.defoptions then
+                  Write(T, ' type="generic"');
+              potype_proginit,
+              potype_unitinit:
+                PrintType('initialization');
+              potype_unitfinalize:
+                PrintType('finalization');
+              potype_constructor:
+                PrintType('constructor');
+              potype_destructor:
+                PrintType('destructor');
+              potype_operator:
+                PrintType('operator');
+              potype_class_constructor:
+                PrintType('class constructor');
+              potype_class_destructor:
+                PrintType('class destructor');
+              potype_propgetter:
+                PrintType('dispinterface getter');
+              potype_propsetter:
+                PrintType('dispinterface setter');
+              potype_exceptfilter:
+                PrintType('except filter');
+              potype_mainstub:
+                PrintType('main stub');
+              potype_libmainstub:
+                PrintType('library main stub');
+              potype_pkgstub:
+                PrintType('package stub');
+            end;
+
+            Write(T, ' name="', SanitiseXMLString(procdef.customprocname([pno_showhidden, pno_noclassmarker])), '"');
+            if po_hascallingconvention in procdef.procoptions then
+              Write(T, ' convention="', proccalloptionStr[procdef.proccalloption], '"');
+            WriteLn(T, '>');
+
+            PrintNodeIndent;
+
+            if Assigned(procdef.returndef) and not is_void(procdef.returndef) then
+              WriteLn(T, PrintNodeIndention, '<returndef>', SanitiseXMLString(procdef.returndef.typesymbolprettyname), '</returndef>');
+
+            if po_reintroduce in procdef.procoptions then
+              PrintOption('reintroduce');
+            if po_virtualmethod in procdef.procoptions then
+              PrintOption('virtual');
+            if po_finalmethod in procdef.procoptions then
+              PrintOption('final');
+            if po_overridingmethod in procdef.procoptions then
+              PrintOption('override');
+            if po_overload in procdef.procoptions then
+              PrintOption('overload');
+            if po_compilerproc in procdef.procoptions then
+              PrintOption('compilerproc');
+            if po_assembler in procdef.procoptions then
+              PrintOption('assembler');
+            if po_nostackframe in procdef.procoptions then
+              PrintOption('nostackframe');
+            if po_inline in procdef.procoptions then
+              PrintOption('inline');
+            if po_noreturn in procdef.procoptions then
+              PrintOption('noreturn');
+            if po_noinline in procdef.procoptions then
+              PrintOption('noinline');
           end;
 
-        case procdef.proctypeoption of
-          potype_none: { Do nothing };
+          if Assigned(Code) then
+            begin
+              if FirstHalf then
+                WriteLn(T, PrintNodeIndention, '<code>')
+              else
+                begin
+                  WriteLn(T); { Line for spacing }
+                  WriteLn(T, PrintNodeIndention, '<firstpass>');
+                end;
 
-          potype_procedure,
-          potype_function:
-            if po_classmethod in procdef.procoptions then
-              begin
-                if po_staticmethod in procdef.procoptions then
-                  PrintType('static class method')
-                else
-                  PrintType('class method');
-              end;
-            { Do nothing otherwise }
+              PrintNodeIndent;
+              XMLPrintNode(T, Code);
+              PrintNodeUnindent;
 
-          potype_proginit,
-          potype_unitinit:
-            PrintType('initialization');
-          potype_unitfinalize:
-            PrintType('finalization');
-          potype_constructor:
-            PrintType('constructor');
-          potype_destructor:
-            PrintType('destructor');
-          potype_operator:
-            PrintType('operator');
-          potype_class_constructor:
-            PrintType('class constructor');
-          potype_class_destructor:
-            PrintType('class destructor');
-          potype_propgetter:
-            PrintType('dispinterface getter');
-          potype_propsetter:
-            PrintType('dispinterface setter');
-          potype_exceptfilter:
-            PrintType('except filter');
-          potype_mainstub:
-            PrintType('main stub');
-          potype_libmainstub:
-            PrintType('library main stub');
-          potype_pkgstub:
-            PrintType('package stub');
-        end;
+              if FirstHalf then
+                WriteLn(T, PrintNodeIndention, '</code>')
+              else
+                WriteLn(T, PrintNodeIndention, '</firstpass>');
+            end
+          else { Code=Nil }
+            begin
+              { Don't print anything for second half - if there's no code, there's no firstpass }
+              if FirstHalf then
+                WriteLn(T, PrintNodeIndention, '<code />');
+            end;
 
-        Write(T, ' name="', SanitiseXMLString(procdef.customprocname([pno_showhidden, pno_noclassmarker])), '"');
-
-        if po_hascallingconvention in procdef.procoptions then
-          Write(T, ' convention="', proccalloptionStr[procdef.proccalloption], '"');
-
-        WriteLn(T, '>');
-
-        PrintNodeIndent;
-
-        if Assigned(procdef.returndef) and not is_void(procdef.returndef) then
-          WriteLn(T, PrintNodeIndention, '<returndef>', SanitiseXMLString(procdef.returndef.typesymbolprettyname), '</returndef>');
-
-        if po_reintroduce in procdef.procoptions then
-          PrintOption('reintroduce');
-        if po_virtualmethod in procdef.procoptions then
-          PrintOption('virtual');
-        if po_finalmethod in procdef.procoptions then
-          PrintOption('final');
-        if po_overridingmethod in procdef.procoptions then
-          PrintOption('override');
-        if po_overload in procdef.procoptions then
-          PrintOption('overload');
-        if po_compilerproc in procdef.procoptions then
-          PrintOption('compilerproc');
-        if po_assembler in procdef.procoptions then
-          PrintOption('assembler');
-        if po_nostackframe in procdef.procoptions then
-          PrintOption('nostackframe');
-        if po_inline in procdef.procoptions then
-          PrintOption('inline');
-        if po_noreturn in procdef.procoptions then
-          PrintOption('noreturn');
-        if po_noinline in procdef.procoptions then
-          PrintOption('noinline');
-
-        if Assigned(Code) then
+        { Print footer only for second half }
+        if (not FirstHalf) or separate then
           begin
-            WriteLn(T, PrintNodeIndention, '<code>');
-            PrintNodeIndent;
-            XMLPrintNode(T, Code);
             PrintNodeUnindent;
-            WriteLn(T, PrintNodeIndention, '</code>');
-          end
-        else
-          WriteLn(T, PrintNodeIndention, '<code />');
+            WriteLn(T, PrintNodeIndention, '</subroutine>');
+            WriteLn(T); { Line for spacing }
+          end;
 
-        PrintNodeUnindent;
-        WriteLn(T, PrintNodeIndention, '</subroutine>');
-        WriteLn(T); { Line for spacing }
         Close(T);
       end;
 {$endif DEBUG_NODE_XML}
@@ -1789,7 +1816,14 @@ implementation
           don't need to generate anything. When it was an empty
           procedure there would be at least a blocknode }
         if not assigned(code) then
-          exit;
+          begin
+{$ifdef DEBUG_NODE_XML}
+            { Print out nodes as they appear after the first pass }
+            XMLPrintProc(True);
+            XMLPrintProc(False);
+{$endif DEBUG_NODE_XML}
+            exit;
+          end;
 
         { We need valid code }
         if Errorcount<>0 then
@@ -1883,6 +1917,10 @@ implementation
            (procdef.proccalloption=pocall_safecall) then
           include(flags, pi_needs_implicit_finally);
 {$endif}
+{$ifdef DEBUG_NODE_XML}
+        { Print out nodes as they appear after the first pass }
+        XMLPrintProc(True);
+{$endif DEBUG_NODE_XML}
         { firstpass everything }
         flowcontrol:=[];
         do_firstpass(code);
@@ -1912,7 +1950,14 @@ implementation
           do_optloadmodifystore(code);
 
         { only do secondpass if there are no errors }
-        if (ErrorCount=0) then
+        if (ErrorCount<>0) then
+          begin
+{$ifdef DEBUG_NODE_XML}
+            { Print out nodes as they appear after the first pass }
+            XMLPrintProc(False);
+{$endif DEBUG_NODE_XML}
+          end
+        else
           begin
             create_hlcodegen;
 
@@ -1962,6 +2007,11 @@ implementation
             if paraprintnodetree <> 0 then
               printproc( 'right before code generation');
 
+{$ifdef DEBUG_NODE_XML}
+            { Print out nodes as they appear after the first pass }
+            XMLPrintProc(False);
+{$endif DEBUG_NODE_XML}
+
             { generate code for the node tree }
             do_secondpass(code);
             aktproccode.concatlist(current_asmdata.CurrAsmList);
@@ -2470,7 +2520,10 @@ implementation
            printproc( 'after parsing');
 
 {$ifdef DEBUG_NODE_XML}
-         XMLPrintProc;
+         { Methods of generic classes don't get any code generated, so output
+           the node tree here }
+         if (df_generic in procdef.defoptions) then
+           XMLPrintProc(True);
 {$endif DEBUG_NODE_XML}
 
          { ... remove symbol tables }