diff mbox series

PR modula2/113836 gm2 does not dump gimple or quadruples to a file

Message ID 87mss5ga2x.fsf@localhost
State New
Headers show
Series PR modula2/113836 gm2 does not dump gimple or quadruples to a file | expand

Commit Message

Gaius Mulley Feb. 12, 2024, 12:07 p.m. UTC
Bootstrapped and regtested on aarch64 and ppc64le with languages=all (no
additional test failures seen).  Bootstrapped language=m2 on Debian,
SUSE, Redhat and also built with clang.  Does the patch seem reasonable
- in particular lang.opt?

-- >8 --

PR modula2/113836 gm2 does not dump gimple or quadruples to a file

During the triage of PR113588 it would have been helpful if gm2 had
the ability to dump its IR to a file and also filter the
IR on procedure name.  This patch implements: -fdump-lang-all,
-fdump-lang-quad, -fdump-lang-quad=, -fdump-lang-gimple,
-fdump-lang-gimple= and -fm2-dump-filter=.

The filter must be a comma separated list which can take three forms:
the full decl textual name of a procedure, [libname.]module.ident or
[filename.]module.ident.  Currently it only filters on procedure names,
no regexp is allowed and no dependencies are followed.

gcc/ChangeLog:

	PR modula2/113836
	* doc/gm2.texi (Compiler options): Document -fdump-lang-all,
	-fdump-lang-quad, -fdump-lang-quad=, -fdump-lang-gimple,
	-fdump-lang-gimple= and -fm2-dump-lang-filter=.

gcc/m2/ChangeLog:

	PR modula2/113836
	* Make-lang.in (GM2_C_OBJS): Change m2/m2pp.o to
	m2/gm2-gcc/m2pp.o.
	(m2/m2pp.o): Change to m2/gm2-gcc/m2pp.o.
	(GM2-COMP-BOOT-DEFS): Add M2LangDump.def.
	(GM2-COMP-BOOT-MODS): Add M2LangDump.mod.
	(GM2-COMP-DEFS): Add M2LangDump.def.
	(GM2-COMP-MODS): Add M2LangDump.mod.
	* gm2-compiler/M2CaseList.mod: Remove import of printf1.
	Add import of WriteCard.
	(WriteCase): Replace printf1 with WriteCard.
	* gm2-compiler/M2Code.mod (M2Quads): Remove DisplayQuadruples and
	DisplayQuadList.  Add DumpLangGimple and DumpQuadruples.
	(TraceQuadruples): New constant.
	(OptimizationAnalysis): Call DumpQuadruples.
	(DoCodeBlock): Add filename, len and create gimple dump if
	DumpLangGimple is true.
	(Code): Call DumpQuadruples, before any optimization,
	after dead procedure elimination and after identifying simple
	subexpression temporaries.
	(DisplayQuadsInScope): Remove.
	(DisplayQuadsNumbers): Remove.
	(CodeBlock): Change DisplayQuadruples to TraceQuadruples.
	* gm2-compiler/M2GCCDeclare.mod (TraceQuadruples): New constant.
	(DeclareTypesConstantsProceduresInRange): Change DisplayQuadruples
	to TraceQuadruples.
	* gm2-compiler/M2GenGCC.mod (M2Quads): Remove import of
	DisplayQuadruples.
	(ResolveConstantExpressions): Remove dead code.
	* gm2-compiler/M2Options.def (DisplayQuadruples): Remove.
	(DumpLangQuad): New boolean variable.
	(DumpLangGimple): New boolean variable.
	(GetDumpLangQuadFilename): New procedure function.
	(SetDumpLangQuadFilename): New procedure.
	(GetDumpLangGimpleFilename): New procedure function.
	(SetDumpLangGimpleFilename): New procedure.
	(SetM2DumpFilter): New procedure.
	(GetM2DumpFilter): New procedure function.
	(GetDumpLangGimple): New procedure function.
	* gm2-compiler/M2Options.mod (GetDumpLangQuadFilename): New
	procedure function.
	(SetDumpLangQuadFilename): New procedure.
	(GetDumpLangGimpleFilename): New procedure function.
	(SetDumpLangGimpleFilename): New procedure.
	(SetM2DumpFilter): New procedure.
	(GetM2DumpFilter): New procedure function.
	(GetDumpLangGimple): New procedure function.
	(SetQuadDebugging): Reimplement.
	(M2Options): Remove DisplayQuadruples.
	Add DumpLangQuad and initialize to FALSE.
	Add DumpLangQuadFilename and initialize to NIL.
	Add DumpLangGimpleFilename and initialize to NIL.
	Add DumpLangGimple and initialize to FALSE.
	Add M2DumpFilter and initialize to NIL.
	* gm2-compiler/M2Quads.def (DumpQuadruples): New procedure.
	(DisplayQuadList): Remove.
	* gm2-compiler/M2Quads.mod (StrLib): Import StrLen.
	(M2Printf): Import fprintf0, fprintf1, fprintf3 and fprintf4.
	(M2Options): Import GetDumpDir, GetM2DumpFilter and DumpLangQuad.
	(M2LangDump): Import MakeQuadTemplate.
	(FIO): Import.
	(SFIO): Import.
	(StdIO): Import.
	(DumpWrite): New procedure.
	(CloseOutput): New procedure.
	(ConfigureOutput): New procedure.
	(GetCtorInit): New procedure function.
	(GetCtorFini): New procedure function.
	(DumpQuadrupleFilter): New procedure.
	(DisplayQuadList): Renamed to DumpQuadrupleAll.
	(DumpQuadruples): New procedure.
	(DisplayQuad): Replace printf with fprintf and outputFile.
	(DisplayProcedureAttributes): Ditto.
	(WriteQuad): Ditto.
	(WriteOperator): Ditto.
	(WriteOperand): Ditto.
	(WriteMode): Ditto.
	* gm2-compiler/M2Scope.mod (M2Options): Remove DisplayQuadruples.
	(TraceQuadruples): New constant.
	(ForeachScopeBlockDo2): Change DisplayQuadruples to
	TraceQuadruples.
	(ForeachScopeBlockDo3): Change DisplayQuadruples to
	TraceQuadruples.
	* gm2-compiler/SymbolConversion.def (Gcc2Mod): New procedure function.
	* gm2-compiler/SymbolConversion.mod (Gcc2Mod): New procedure
	function implemented.
	(Indexing): Import HighIndice.
	* gm2-gcc/m2misc.cc (m2misc_DebugTree): Tidy up comment.
	(m2misc_DebugTreeChain): Correct comment.
	* gm2-gcc/m2options.h (M2Options_GetDumpLangQuadFilename): New function.
	(M2Options_SetDumpLangQuadFilename): New function.
	(M2Options_GetDumpLangGimpleFilename): New function.
	(M2Options_SetDumpLangGimpleFilename): New function.
	(M2Options_GetDumpLangGimple): New function.
	(M2Options_SetM2DumpFilter): New function.
	(M2Options_GetM2DumpFilter): New function.
	* m2pp.cc: Moved to...
	* gm2-gcc/m2pp.cc: ...here.
	(pretty): Add output field.
	(initPretty): Add kind parameter.
	(m2pp_output_file): New array.
	(do_pf): Add parameter M2PP_DUMP_STDOUT.
	(pe): Ditto.
	(pet): Ditto.
	(pt): Ditto.
	(pv): Ditto.
	(getoutput): New function.
	(m2pp_loc): Change printf to fprintf using file from getoutput.
	(m2pp_type_lowlevel): Ditto.
	(hextree): Ditto.
	(m2pp_module_block): Ditto.
	(m2pp_var_list): Ditto.
	(m2pp_recordfield_alignment): Ditto.
	(m2pp_print_char): Ditto and replace putchar with fputc.
	(m2pp_CreateDumpGimple): New function.
	(m2pp_CloseDumpGimple): New function.
	(m2pp_dump_gimple): New function.
	* m2pp.h: Moved to...
	* gm2-gcc/m2pp.h: ...here.
	(m2pp_dump_kind): New typedef.
	(m2pp_CreateDumpGimple): New function.
	(m2pp_CloseDumpGimple): New function.
	(m2pp_dump_gimple): New function.
	* gm2-gcc/m2statement.cc (m2statement_BuildEndFunctionCode): Call
	m2pp_dump_gimple.
	* gm2-lang.cc (gm2_langhook_handle_option): Add case
	OPT_fdump_lang_all, OPT_fdump_lang_gimple, OPT_fdump_lang_gimple_,
	OPT_fdump_lang_quad, OPT_fdump_lang_quad_ and OPT_fm2_dump_filter_.
	* gm2-libs/DynamicStrings.def (ReverseIndex): New procedure
	function.
	(RIndex): Improve comment.
	* gm2-libs/DynamicStrings.mod (ReverseIndex): New procedure
	function.
	(RIndex): Improve comment.
	* lang.opt: New entries for fdump-lang-all, fdump-lang-gimple,
	fdump-lang-gimple=, fdump-lang-quad, fdump-lang-quad= and
	fm2-dump-filter=.
	* gm2-compiler/M2LangDump.def: New file.
	* gm2-compiler/M2LangDump.mod: New file.
	* gm2-gcc/m2langdump.h: New file.
	* gm2-gcc/m2pp.def: New file.
diff mbox series

Patch

diff --git a/gcc/doc/gm2.texi b/gcc/doc/gm2.texi
index 028a0715f64..ee829cd45a7 100644
--- a/gcc/doc/gm2.texi
+++ b/gcc/doc/gm2.texi
@@ -416,6 +416,25 @@  The default implementation and module filename suffix is @file{.def}.
 If this option is used GNU Modula-2 will still fall back to this
 default if a requested definition module is not found.
 
+@item -fdump-lang-all
+turn on all modula-2 language dump file.  Currently this enables
+@samp{-fdump-lang-quad} and @samp{-fdump-lang-gimple}.
+This is an internal command line option.
+
+@item -fdump-lang-quad
+generate internal debugging dump files containing the quadruple
+intemediate representation of the source.
+
+@item -fdump-lang-quad=@file{filestem}
+dump quadruple representation to the @file{filestem} specified.
+
+@item -fdump-lang-gimple
+generate internal debugging dump files containing a modula-2 gimple
+representation of the source.
+
+@item -fdump-lang-gimple=@file{filestem}
+dump modula-2 gimple representation to the @file{filestem} specified.
+
 @item -fdump-system-exports
 display all inbuilt system items.
 This is an internal command line option.
@@ -474,6 +493,15 @@  this option forces the use of the static version.
 @c Modula-2 Joined
 @c set all location values to a specific value (internal switch)
 
+@item -fm2-dump-filter=@samp{rules}
+filter the language dumps @samp{-fdump-lang-quad} and
+@samp{-fdump-lang-quad} on @samp{rules}.  @samp{rules} must be a comma
+separated list which can take three forms: the full decl textual name
+of a procedure, @samp{[libname.]module.ident} or
+@samp{[filename.]module.ident}.  This is an internal command line
+option.  Currently it only filters on procedure names and regexp
+matching is not implemented.
+
 @item -fm2-g
 improve the debugging experience for new programmers at the expense
 of generating @code{nop} instructions if necessary to ensure single
diff --git a/gcc/m2/Make-lang.in b/gcc/m2/Make-lang.in
index 45bfa933dca..73f0f3e85d1 100644
--- a/gcc/m2/Make-lang.in
+++ b/gcc/m2/Make-lang.in
@@ -519,7 +519,7 @@  SO=-O0 -g -fPIC
 # Language-specific object files for the gm2 compiler.
 
 GM2_C_OBJS        = m2/gm2-lang.o \
-                    m2/m2pp.o \
+                    m2/gm2-gcc/m2pp.o \
                     m2/gm2-gcc/m2assert.o \
                     m2/gm2-gcc/m2block.o \
                     m2/gm2-gcc/m2builtins.o \
@@ -608,11 +608,6 @@  m2/gm2-lang.o: $(srcdir)/m2/gm2-lang.cc gt-m2-gm2-lang.h $(GCC_HEADER_DEPENDENCI
             $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
 	$(POSTCOMPILE)
 
-m2/m2pp.o : $(srcdir)/m2/m2pp.cc $(GCC_HEADER_DEPENDENCIES_FOR_M2)
-	$(COMPILER) $(CM2DEP) -c -g -DGM2 $(ALL_COMPILERFLAGS) \
-            $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
-	$(POSTCOMPILE)
-
 m2/gm2-gcc/rtegraph.o: $(srcdir)/m2/gm2-gcc/rtegraph.cc $(GCC_HEADER_DEPENDENCIES_FOR_M2) \
                        gt-m2-rtegraph.h
 	-test -d $(@D)/$(DEPDIR) || $(mkinstalldirs) $(@D)/$(DEPDIR)
@@ -761,6 +756,7 @@  GM2-COMP-BOOT-DEFS = \
    M2GCCDeclare.def \
    M2GenGCC.def \
    M2Graph.def \
+   M2LangDump.def \
    M2LexBuf.def \
    M2MetaError.def \
    M2Optimize.def \
@@ -834,6 +830,7 @@  GM2-COMP-BOOT-MODS = \
    M2GCCDeclare.mod \
    M2GenGCC.mod \
    M2Graph.mod \
+   M2LangDump.mod \
    M2LexBuf.mod \
    M2MetaError.mod \
    M2Optimize.mod \
@@ -886,6 +883,7 @@  GM2-GCC-DEFS = \
    m2expr.def \
    m2linemap.def \
    m2misc.def \
+   m2pp.def \
    m2statement.def \
    m2top.def \
    m2tree.def \
@@ -1040,6 +1038,7 @@  GM2-COMP-DEFS = \
    M2GCCDeclare.def \
    M2GenGCC.def \
    M2Graph.def \
+   M2LangDump.def \
    M2LexBuf.def \
    M2MetaError.def \
    M2Optimize.def \
@@ -1110,6 +1109,7 @@  GM2-COMP-MODS = \
    M2GCCDeclare.mod \
    M2GenGCC.mod \
    M2Graph.mod \
+   M2LangDump.mod \
    M2LexBuf.mod \
    M2MetaError.mod \
    M2Optimize.mod \
diff --git a/gcc/m2/gm2-compiler/M2CaseList.mod b/gcc/m2/gm2-compiler/M2CaseList.mod
index 08a6052e796..b98f55375bd 100644
--- a/gcc/m2/gm2-compiler/M2CaseList.mod
+++ b/gcc/m2/gm2-compiler/M2CaseList.mod
@@ -39,8 +39,8 @@  FROM m2type IMPORT GetMinFrom ;
 FROM m2expr IMPORT GetIntegerOne, CSTIntToString, CSTIntToChar ;
 FROM Storage IMPORT ALLOCATE ;
 FROM M2Base IMPORT IsExpressionCompatible, Char ;
-FROM M2Printf IMPORT printf1 ;
 FROM M2LexBuf IMPORT TokenToLocation ;
+FROM NumberIO IMPORT WriteCard ;
 
 FROM SymbolTable IMPORT NulSym, IsConst, IsFieldVarient, IsRecord, IsRecordField, GetVarientTag, GetType,
                         ForeachLocalSymDo, GetSymName, IsEnumeration, SkipType, NoOfElements, GetNth,
@@ -1191,7 +1191,7 @@  end InRangeList ;
 PROCEDURE WriteCase (c: CARDINAL) ;
 BEGIN
    (* this debugging PROCEDURE should be finished.  *)
-   printf1 ("%d", c)
+   WriteCard (c, 0)
 END WriteCase ;
 
 
diff --git a/gcc/m2/gm2-compiler/M2Code.mod b/gcc/m2/gm2-compiler/M2Code.mod
index 010e1d02fca..ea06f362845 100644
--- a/gcc/m2/gm2-compiler/M2Code.mod
+++ b/gcc/m2/gm2-compiler/M2Code.mod
@@ -23,10 +23,12 @@  IMPLEMENTATION MODULE M2Code ;
 
 
 FROM SYSTEM IMPORT WORD ;
-FROM M2Options IMPORT Statistics, DisplayQuadruples, OptimizeUncalledProcedures,
-                      (* OptimizeDynamic, *) OptimizeCommonSubExpressions,
-                      StyleChecking, Optimizing, WholeProgram ;
+FROM M2Options IMPORT Statistics, OptimizeUncalledProcedures,
+                      OptimizeCommonSubExpressions,
+                      StyleChecking, Optimizing, WholeProgram,
+                      DumpLangGimple ;
 
+FROM M2LangDump IMPORT MakeGimpleTemplate ;
 FROM M2Error IMPORT InternalError ;
 FROM M2Students IMPORT StudentVariableCheck ;
 
@@ -41,7 +43,8 @@  FROM M2Printf IMPORT printf2, printf1, printf0 ;
 FROM NameKey IMPORT Name ;
 FROM M2Batch IMPORT ForeachSourceModuleDo ;
 
-FROM M2Quads IMPORT CountQuads, GetFirstQuad, DisplayQuadList, DisplayQuadRange,
+FROM M2Quads IMPORT CountQuads, GetFirstQuad,
+                    DumpQuadruples, DisplayQuadRange,
                     BackPatchSubrangesAndOptParam,
                     LoopAnalysis, ForLoopAnalysis, GetQuad, QuadOperator ;
 
@@ -71,12 +74,14 @@  FROM m2flex IMPORT GetTotalLines ;
 FROM FIO IMPORT FlushBuffer, StdOut ;
 FROM M2Quiet IMPORT qprintf0 ;
 FROM M2SSA IMPORT DiscoverSSA ;
+FROM m2pp IMPORT CreateDumpGimple, CloseDumpGimple ;
+FROM DynamicStrings IMPORT String, KillString ;
 
 
 CONST
-   MaxOptimTimes = 10 ;   (* upper limit of no of times we run through all optimization *)
-   Debugging     = TRUE ;
-
+   MaxOptimTimes   = 10 ;   (* upper limit of no of times we run through all optimization *)
+   Debugging       = TRUE ;
+   TraceQuadruples = FALSE ;
 
 VAR
    Total,
@@ -139,11 +144,7 @@  BEGIN
       printf1 ('Total source lines compiled    : %6d\n', Count) ;
       FlushBuffer (StdOut)
    END ;
-   IF DisplayQuadruples
-   THEN
-      printf0 ('after all front end optimization\n') ;
-      DisplayQuadList
-   END
+   DumpQuadruples ('after all front end optimization\n')
 END OptimizationAnalysis ;
 
 
@@ -198,11 +199,17 @@  END PrintModule ;
 *)
 
 PROCEDURE DoCodeBlock ;
+VAR
+   filename: String ;
+   len     : CARDINAL ;
 BEGIN
-   IF WholeProgram
+   IF DumpLangGimple
    THEN
-      (* ForeachSourceModuleDo(PrintModule) ; *)
-      CodeBlock (GetMainModule ())
+      filename := MakeGimpleTemplate (len) ;
+      CreateDumpGimple (filename, len) ;
+      filename := KillString (filename) ;
+      CodeBlock (GetMainModule ()) ;
+      CloseDumpGimple
    ELSE
       CodeBlock (GetMainModule ())
    END
@@ -238,11 +245,7 @@  BEGIN
 
    ForLoopAnalysis ;   (* must be done before any optimization as the index variable increment quad might change *)
 
-   IF DisplayQuadruples
-   THEN
-      printf0 ('before any optimization\n') ;
-      DisplayQuadList
-   END ;
+   DumpQuadruples ('before any optimization\n') ;
 
    (* now is a suitable time to check for student errors as *)
    (* we know all the front end symbols must be resolved.   *)
@@ -258,20 +261,9 @@  BEGIN
    InitDeclarations ;     (* default and fixed sized types are all declared from now on.  *)
 
    RemoveUnreachableCode ;
-
-   IF DisplayQuadruples
-   THEN
-      printf0 ('after dead procedure elimination\n') ;
-      DisplayQuadList
-   END ;
-
+   DumpQuadruples ('after dead procedure elimination\n') ;
    DetermineSubExpTemporaries ;
-
-   IF DisplayQuadruples
-   THEN
-      printf0 ('after identifying simple subexpression temporaries\n') ;
-      DisplayQuadList
-   END ;
+   DumpQuadruples ('after identifying simple subexpression temporaries\n') ;
 
    qprintf0 ('        symbols to gcc trees\n') ;
    DoModuleDeclare ;
@@ -377,20 +369,6 @@  BEGIN
 END Init ;
 
 
-(*
-   DisplayQuadsInScope -
-*)
-
-(*
-PROCEDURE DisplayQuadsInScope (sb: ScopeBlock) ;
-BEGIN
-   printf0 ('Quads in scope\n') ;
-   ForeachScopeBlockDo (sb, DisplayQuadRange) ;
-   printf0 ('===============\n')
-END DisplayQuadsInScope ;
-*)
-
-
 (*
    OptimizeScopeBlock -
 *)
@@ -416,21 +394,6 @@  BEGIN
 END OptimizeScopeBlock ;
 
 
-(*
-   DisplayQuadNumbers - the range, start..end.
-*)
-
-(*
-PROCEDURE DisplayQuadNumbers (start, end: CARDINAL) ;
-BEGIN
-   IF DisplayQuadruples
-   THEN
-      printf2 ('Coding [%d..%d]\n', start, end)
-   END
-END DisplayQuadNumbers ;
-*)
-
-
 (*
    CodeProceduresWithinBlock - codes the procedures within the module scope.
 *)
@@ -465,7 +428,7 @@  VAR
    sb: ScopeBlock ;
    n : Name ;
 BEGIN
-   IF DisplayQuadruples
+   IF TraceQuadruples
    THEN
       n := GetSymName (scope) ;
       printf1 ('before coding block %a\n', n)
@@ -474,7 +437,7 @@  BEGIN
    OptimizeScopeBlock (sb) ;
    IF IsProcedure (scope)
    THEN
-      IF DisplayQuadruples
+      IF TraceQuadruples
       THEN
          n := GetSymName(scope) ;
          printf1('before coding procedure %a\n', n) ;
@@ -484,7 +447,7 @@  BEGIN
       ForeachScopeBlockDo2 (sb, ConvertQuadsToTree)
    ELSIF IsModuleWithinProcedure(scope)
    THEN
-      IF DisplayQuadruples
+      IF TraceQuadruples
       THEN
          n := GetSymName(scope) ;
          printf1('before coding module %a within procedure\n', n) ;
@@ -494,7 +457,7 @@  BEGIN
       ForeachScopeBlockDo2 (sb, ConvertQuadsToTree) ;
       ForeachProcedureDo(scope, CodeBlock)
    ELSE
-      IF DisplayQuadruples
+      IF TraceQuadruples
       THEN
          n := GetSymName(scope) ;
          printf1('before coding module %a\n', n) ;
diff --git a/gcc/m2/gm2-compiler/M2GCCDeclare.mod b/gcc/m2/gm2-compiler/M2GCCDeclare.mod
index dae5a6b34bd..80a4a536c62 100644
--- a/gcc/m2/gm2-compiler/M2GCCDeclare.mod
+++ b/gcc/m2/gm2-compiler/M2GCCDeclare.mod
@@ -38,8 +38,7 @@  FROM M2Quads IMPORT DisplayQuadRange ;
 
 IMPORT FIO ;
 
-FROM M2Options IMPORT DisplayQuadruples,
-                      GenerateDebugging, GenerateLineDebug, Iso, Optimizing, WholeProgram,
+FROM M2Options IMPORT GenerateDebugging, GenerateLineDebug, Iso, Optimizing, WholeProgram,
                       ScaffoldStatic, GetRuntimeModuleOverride ;
 
 FROM M2AsmUtil IMPORT GetFullSymName, GetFullScopeAsmName ;
@@ -209,10 +208,11 @@  TYPE
 
 
 CONST
-   Debugging   = FALSE ;
-   Progress    = FALSE ;
-   EnableSSA   = FALSE ;
-   EnableWatch = FALSE ;
+   Debugging       = FALSE ;
+   Progress        = FALSE ;
+   EnableSSA       = FALSE ;
+   EnableWatch     = FALSE ;
+   TraceQuadruples = FALSE ;
 
 
 TYPE
@@ -2767,7 +2767,7 @@  VAR
    copy: Group ;
    loop: CARDINAL ;
 BEGIN
-   IF DisplayQuadruples
+   IF TraceQuadruples
    THEN
       DisplayQuadRange (scope, start, end)
    END ;
@@ -2783,7 +2783,7 @@  BEGIN
       END ;
       IF loop = DebugLoop
       THEN
-         IF DisplayQuadruples
+         IF TraceQuadruples
          THEN
             DisplayQuadRange (scope, start, end)
          END ;
diff --git a/gcc/m2/gm2-compiler/M2GenGCC.mod b/gcc/m2/gm2-compiler/M2GenGCC.mod
index 25bfbf894aa..99f36413516 100644
--- a/gcc/m2/gm2-compiler/M2GenGCC.mod
+++ b/gcc/m2/gm2-compiler/M2GenGCC.mod
@@ -92,7 +92,7 @@  FROM M2Error IMPORT InternalError, WriteFormat0, WriteFormat1, WriteFormat2, War
 FROM M2MetaError IMPORT MetaErrorT0, MetaErrorT1, MetaErrorT2, MetaErrorT3,
                         MetaError1, MetaError2, MetaErrorStringT1 ;
 
-FROM M2Options IMPORT DisplayQuadruples, UnboundedByReference, PedanticCast,
+FROM M2Options IMPORT UnboundedByReference, PedanticCast,
                       VerboseUnbounded, Iso, Pim, DebugBuiltins, WholeProgram,
                       StrictTypeChecking, AutoInit, cflag, ScaffoldMain,
                       ScaffoldDynamic, ScaffoldStatic,
@@ -256,8 +256,7 @@  FROM m2except IMPORT BuildThrow, BuildTryBegin, BuildTryEnd,
 FROM M2Quads IMPORT QuadOperator, GetQuad, IsReferenced, GetNextQuad,
                     SubQuad, PutQuad, MustCheckOverflow, GetQuadOtok,
                     QuadToTokenNo, DisplayQuad, GetQuadtok,
-                    GetM2OperatorDesc, GetQuadOp,
-                    DisplayQuadList ;
+                    GetM2OperatorDesc, GetQuadOp ;
 
 FROM M2Check IMPORT ParameterTypeCompatible, AssignmentTypeCompatible,  ExpressionTypeCompatible ;
 FROM M2SSA IMPORT EnableSSA ;
@@ -640,11 +639,6 @@  BEGIN
          Changed := TRUE
       END
    UNTIL NoChange ;
-   IF Debugging AND DisplayQuadruples AND FALSE
-   THEN
-      printf0('after resolving expressions with gcc\n') ;
-      DisplayQuadList
-   END ;
    RETURN Changed
 END ResolveConstantExpressions ;
 
diff --git a/gcc/m2/gm2-compiler/M2LangDump.def b/gcc/m2/gm2-compiler/M2LangDump.def
new file mode 100644
index 00000000000..8298da2a54d
--- /dev/null
+++ b/gcc/m2/gm2-compiler/M2LangDump.def
@@ -0,0 +1,65 @@ 
+(* M2LangDump.def provides support routines for the -flang-dump.
+
+Copyright (C) 2024 Free Software Foundation, Inc.
+Contributed by Gaius Mulley <gaiusmod2@gmail.com>.
+
+This file is part of GNU Modula-2.
+
+GNU Modula-2 is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GNU Modula-2 is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Modula-2; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  *)
+
+DEFINITION MODULE M2LangDump ;
+
+FROM m2tree IMPORT Tree ;
+FROM DynamicStrings IMPORT String ;
+
+
+(*
+   IsDumpRequiredTree - return TRUE if the gcc tree should be dumped.
+*)
+
+PROCEDURE IsDumpRequiredTree (tree: Tree) : BOOLEAN ;
+
+
+(*
+   IsDumpRequired - return TRUE if symbol sym should be dumped
+                    according to the rules of the filter.
+                    No filter specified will always return TRUE.
+                    The filter is a comma separated list of either:
+
+                    DECL names for example: m2pim_NumberIO_HexToStr
+                    filename:m2symbolname for example: NumberIO.mod:HexToStr
+                    fully qualified m2name for example: NumberIO.HexToStr
+*)
+
+PROCEDURE IsDumpRequired (sym: CARDINAL) : BOOLEAN ;
+
+
+(*
+   MakeQuadTemplate - return a template for the quad dump file.
+*)
+
+PROCEDURE MakeQuadTemplate () : String ;
+
+
+(*
+   MakeGimpleTemplate - return a template for the gimple dump file and assign
+                        len to the max number of characters required to complete
+                        a template.
+*)
+
+PROCEDURE MakeGimpleTemplate (VAR len: CARDINAL) : String ;
+
+
+END M2LangDump.
diff --git a/gcc/m2/gm2-compiler/M2LangDump.mod b/gcc/m2/gm2-compiler/M2LangDump.mod
new file mode 100644
index 00000000000..ad822a75fc4
--- /dev/null
+++ b/gcc/m2/gm2-compiler/M2LangDump.mod
@@ -0,0 +1,457 @@ 
+(* M2LangDump.mod provides support routines for the -flang-dump.
+
+Copyright (C) 2024 Free Software Foundation, Inc.
+Contributed by Gaius Mulley <gaiusmod2@gmail.com>.
+
+This file is part of GNU Modula-2.
+
+GNU Modula-2 is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GNU Modula-2 is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Modula-2; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  *)
+
+IMPLEMENTATION MODULE M2LangDump ;
+
+FROM SYSTEM IMPORT ADDRESS ;
+
+FROM DynamicStrings IMPORT String, Length, InitString, Mark, Slice, EqualArray,
+                           InitStringCharStar, ConCatChar, ConCat, KillString,
+                           Dup, string, char, Index, ReverseIndex, RIndex, Equal,
+                           PushAllocation, PopAllocationExemption ;
+
+FROM SymbolTable IMPORT NulSym,
+                        GetSymName, GetLibName,
+                        GetScope, GetModuleScope, GetMainModule, GetDeclaredMod,
+                        IsInnerModule,
+                        IsVar,
+                        IsProcedure,
+                        IsModule,
+                        IsDefImp,
+                        IsExportQualified, IsExportUnQualified,
+                        IsExported, IsPublic, IsExtern, IsMonoName,
+                        IsDefinitionForC ;
+
+FROM M2Options IMPORT GetM2DumpFilter, GetDumpDir, GetDumpLangQuadFilename,
+                      GetDumpLangGimpleFilename ;
+
+FROM NameKey IMPORT Name, GetKey, MakeKey, makekey, KeyToCharStar, NulName ;
+FROM SymbolConversion IMPORT Gcc2Mod, Mod2Gcc ;
+FROM M2AsmUtil IMPORT GetFullScopeAsmName ;
+FROM M2LexBuf IMPORT FindFileNameFromToken ;
+FROM M2Printf IMPORT printf0, printf1, printf2 ;
+FROM M2Error IMPORT InternalError ;
+FROM libc IMPORT printf ;
+
+
+CONST
+   Debugging = FALSE ;
+
+
+(*
+   IsDumpRequiredTree - return TRUE if the gcc tree should be dumped.
+*)
+
+PROCEDURE IsDumpRequiredTree (tree: Tree) : BOOLEAN ;
+VAR
+   sym: CARDINAL ;
+BEGIN
+   sym := Gcc2Mod (tree) ;
+   IF sym = NulSym
+   THEN
+      RETURN FALSE
+   ELSE
+      RETURN IsDumpRequired (sym)
+   END
+END IsDumpRequiredTree ;
+
+
+(*
+   IsDumpRequired - return TRUE if symbol sym should be dumped
+                    according to the rules of the filter.
+                    No filter specified will always return TRUE.
+                    The filter is a comma separated list.  Each element
+                    of the list can specify a symbol three ways.
+                    Firstly by DECL name for example: m2pim_NumberIO_HexToStr
+                    Secondly by qualified scope: [pathname.]NumberIO.HexToStr
+                    Thirdly by filename and scope: NumberIO.mod:HexToStr
+*)
+
+PROCEDURE IsDumpRequired (sym: CARDINAL) : BOOLEAN ;
+VAR
+   filter: String ;
+BEGIN
+   filter := GetM2DumpFilter () ;
+   IF filter = NIL
+   THEN
+      RETURN TRUE
+   ELSE
+      RETURN Match (filter, sym)
+   END
+END IsDumpRequired ;
+
+
+(*
+   Match - return TRUE if sym matches any of the filter rules.
+*)
+
+PROCEDURE Match (filter: ADDRESS; sym: CARDINAL) : BOOLEAN ;
+VAR
+   result: BOOLEAN ;
+   rule,
+   full  : String ;
+   start,
+   i     : INTEGER ;
+BEGIN
+   full := InitStringCharStar (filter) ;
+   start := 0 ;
+   REPEAT
+      i := Index (full, ',', start) ;
+      IF i = -1
+      THEN
+         rule := Slice (full, start, 0)
+      ELSE
+         rule := Slice (full, start, i)
+      END ;
+      result := MatchRule (rule, sym) ;
+      rule := KillString (rule) ;
+      IF result
+      THEN
+         full := KillString (full) ;
+         RETURN TRUE
+      END ;
+      start := i+1 ;
+   UNTIL i = -1 ;
+   full := KillString (full) ;
+   RETURN FALSE
+END Match ;
+
+
+(*
+   MatchRule - return TRUE if rule matches sym.
+*)
+
+PROCEDURE MatchRule (rule: String; sym: CARDINAL) : BOOLEAN ;
+BEGIN
+   IF Index (rule, ':', 0) # -1
+   THEN
+      (* Filename and scope qualification tests.  *)
+      RETURN MatchRuleFilenameScope (rule, sym)
+   ELSIF Index (rule, '.', 0) # -1
+   THEN
+      (* Modula-2 scoping tests.  *)
+      RETURN MatchRuleScope (rule, sym)
+   ELSE
+      (* Text decl tests.  *)
+      RETURN MatchRuleText (rule, sym)
+   END
+END MatchRule ;
+
+
+(*
+   MatchRuleFilenameScope - returns TRUE if rule contains filename.ext:qualident
+                            and it matches sym.
+*)
+
+PROCEDURE MatchRuleFilenameScope (rule: String; sym: CARDINAL) : BOOLEAN ;
+VAR
+   rulefile,
+   symfile,
+   subrule : String ;
+BEGIN
+   rulefile := Slice (rule, 0, Index (rule, ':', 0)) ;
+   (* Do not deallocate symfile.  *)
+   symfile := FindFileNameFromToken (GetDeclaredMod (sym), 0) ;
+   IF TextMatch (rulefile, symfile)
+   THEN
+      subrule := Slice (rule, Index (rule, ':', 0) + 1, 0) ;
+      IF MatchRuleScope (subrule, sym)
+      THEN
+         subrule := KillString (subrule) ;
+         RETURN TRUE
+      END
+   END ;
+   rulefile := KillString (rulefile) ;
+   RETURN FALSE
+END MatchRuleFilenameScope ;
+
+
+(*
+   MatchRuleScope - returns TRUE if rule contains a [libname.]qualified.ident
+                    and it matches sym.
+*)
+
+PROCEDURE MatchRuleScope (rule: String; sym: CARDINAL) : BOOLEAN ;
+VAR
+   i   : INTEGER ;
+   name: Name ;
+BEGIN
+   IF Debugging
+   THEN
+      name := GetSymName (sym) ;
+      printf2 ("MatchRuleScope (%s, %a)\n", rule, name)
+   END ;
+   (* Compare qualident right to left.  *)
+   i := RIndex (rule, '.', 0) ;
+   IF i = -1
+   THEN
+      (* No qualification, just the ident.  *)
+      RETURN MatchRuleIdent (rule, sym)
+   ELSE
+      RETURN MatchRuleQualident (rule, Slice (rule, i+1, 0), i, sym)
+   END
+END MatchRuleScope ;
+
+
+(*
+   MatchRuleQualident - returns TRUE if rule matches qualified sym.
+                        PostCondition:  subrule will be deallocated upon exit.
+                                        TRUE is returned if rule matches qualified sym.
+*)
+
+PROCEDURE MatchRuleQualident (rule, subrule: String; i: INTEGER; sym: CARDINAL) : BOOLEAN ;
+VAR
+   scope: CARDINAL ;
+BEGIN
+   IF TextCompareName (subrule, GetSymName (sym))
+   THEN
+      IF NOT QualifiedScope (rule, sym, i, scope)
+      THEN
+         RETURN FALSE
+      END ;
+      IF OptionalLibname (rule, sym, i, scope)
+      THEN
+         RETURN TRUE
+      END
+   END ;
+   subrule := KillString (subrule) ;
+   IF Debugging
+   THEN
+      printf0 ("MatchRuleQualident FALSE\n")
+   END ;
+   RETURN FALSE
+END MatchRuleQualident ;
+
+
+(*
+   QualifiedScope - PostCondition: true is returned is rule matches a qualified sym.
+                                   i is -1 if no more qualifications or libname is found.
+                                   scope will be the set to the last outer scope seen.
+*)
+
+PROCEDURE QualifiedScope (rule: String; sym: CARDINAL; VAR i: INTEGER; VAR scope: CARDINAL) : BOOLEAN ;
+VAR
+   subrule: String ;
+   j      : INTEGER ;
+   name   : Name ;
+BEGIN
+   IF Debugging
+   THEN
+      name := GetSymName (sym) ;
+      printf2 ("seen ident name, QualifiedScope (rule = %s, %a)\n", rule, name)
+   END ;
+   scope := sym ;
+   subrule := NIL ;
+   REPEAT
+      j := i ;
+      scope := GetScope (scope) ;
+      i := ReverseIndex (rule, '.', j - 1) ;
+      IF Debugging
+      THEN
+         printf2 (" reverseindex (rule = %s, '.', j = %d)\n", rule, j);
+         printf1 ("    returns i = %d\n", i)
+      END ;
+      IF scope # NulSym
+      THEN
+         subrule := KillString (subrule) ;
+         subrule := Slice (rule, i + 1, j) ;
+         IF Debugging
+         THEN
+            name := GetSymName (scope) ;
+            printf2 ("QualifiedScope (subrule = %s, %a)\n", subrule, name)
+         END ;
+         IF NOT TextCompareName (subrule, GetSymName (scope))
+         THEN
+            subrule := KillString (subrule) ;
+            IF Debugging
+            THEN
+               printf0 ("QualifiedScope FALSE\n")
+            END ;
+            RETURN FALSE
+         END
+      END
+   UNTIL (i <= 0) OR IsDefImp (scope) OR IsModule (scope) ;
+   subrule := KillString (subrule) ;
+   RETURN TRUE
+END QualifiedScope ;
+
+
+(*
+   OptionalLibname - returns TRUE if rule[0..dot] matches syms libname or
+                     if there is no libname the scope is a module or defimp
+                     symbol.
+*)
+
+PROCEDURE OptionalLibname (rule: String; sym: CARDINAL; dot: INTEGER; scope: CARDINAL) : BOOLEAN ;
+VAR
+   subrule: String ;
+BEGIN
+   IF dot > 0
+   THEN
+      (* Check for optional libname.  *)
+      subrule := Slice (rule, 0, dot) ;
+      IF Debugging
+      THEN
+         printf2 ("checking for optional libname (subrule = %s, '.', dot = %d)\n",
+                  rule, dot)
+      END ;
+      IF TextCompareName (subrule, GetLibName (GetModuleScope (sym)))
+      THEN
+         subrule := KillString (subrule) ;
+         IF Debugging
+         THEN
+            printf0 ("OptionalLibname TRUE\n")
+         END ;
+         RETURN TRUE
+      END ;
+      subrule := KillString (subrule)
+   ELSIF (scope # NulSym) AND (IsModule (scope) OR IsDefImp (scope))
+   THEN
+      IF Debugging
+      THEN
+         printf0 ("OptionalLibname TRUE\n")
+      END ;
+      RETURN TRUE
+   END ;
+   RETURN FALSE
+END OptionalLibname ;
+
+
+(*
+   MatchRuleIdent - return TRUE if ident sym matches rule.
+                    The ident must be in a module or defimp scope.
+*)
+
+PROCEDURE MatchRuleIdent (rule: String; sym: CARDINAL) : BOOLEAN ;
+VAR
+   scope: CARDINAL ;
+BEGIN
+   IF TextCompareName (rule, GetSymName (sym))
+   THEN
+      scope := GetScope (sym) ;
+      RETURN IsModule (scope) OR IsDefImp (scope)
+   END ;
+   RETURN FALSE
+END MatchRuleIdent ;
+
+
+(*
+   MatchRuleText - returns TRUE if rule matches sym.
+*)
+
+PROCEDURE MatchRuleText (rule: String; sym: CARDINAL) : BOOLEAN ;
+BEGIN
+   RETURN TextCompareName (rule, GetFullScopeAsmName (sym))
+END MatchRuleText ;
+
+
+(*
+   TextCompareName - return TRUE if rule matches name.
+*)
+
+PROCEDURE TextCompareName (rule: String; name: Name) : BOOLEAN ;
+VAR
+   result: BOOLEAN ;
+   text  : String ;
+BEGIN
+   text := InitStringCharStar (KeyToCharStar (name)) ;
+   result := TextMatch (rule, text) ;
+   text := KillString (text) ;
+   RETURN result
+END TextCompareName ;
+
+
+(*
+   TextMatch - returns TRUE if rule matches text.  Currently this
+               is a simple string compare, but could be extended
+               to implement regexp (seen in the rule).
+*)
+
+PROCEDURE TextMatch (rule, text: String) : BOOLEAN ;
+BEGIN
+   IF Debugging
+   THEN
+      printf2 ("TextMatch (%s, %s)\n", rule, text)
+   END ;
+   RETURN Equal (rule, text)
+END TextMatch ;
+
+
+(*
+   CreateTemplate - create and return a template filename with extension.
+                    If the user has specified "-" then "-" is returned otherwise
+                    a template is formed from "dumpdir + filename + .%03dl.extension".
+*)
+
+PROCEDURE CreateTemplate (filename, extension: String) : String ;
+BEGIN
+   IF filename = NIL
+   THEN
+      (* User has not specified a file.  *)
+      IF GetDumpDir () = NIL
+      THEN
+         filename := InitStringCharStar (KeyToCharStar (GetSymName (GetMainModule ())))
+      ELSE
+         filename := Dup (GetDumpDir ()) ;
+         filename := ConCat (filename, Mark (InitStringCharStar (KeyToCharStar (GetSymName (GetMainModule ())))))
+      END ;
+      filename := ConCat (filename, Mark (InitString ('.mod')))
+   ELSE
+      (* We need to duplicate the filename to create a new string before ConCat
+         is used later on.  *)
+      filename := Dup (filename)
+   END ;
+   IF NOT EqualArray (filename, '-')
+   THEN
+      filename := ConCat (ConCat (filename, InitString ('.%03dl.')), extension)
+   END ;
+   RETURN filename
+END CreateTemplate ;
+
+
+(*
+   MakeQuadTemplate - return a template for the quad dump file.
+*)
+
+PROCEDURE MakeQuadTemplate () : String ;
+BEGIN
+   RETURN CreateTemplate (GetDumpLangQuadFilename (), InitString ('quad'))
+END MakeQuadTemplate ;
+
+
+(*
+   MakeGimpleTemplate - return a template for the gimple dump file and assign
+                        len to the max number of characters required to complete
+                        a template (including a nul terminator).
+*)
+
+PROCEDURE MakeGimpleTemplate (VAR len: CARDINAL) : String ;
+VAR
+   filename: String ;
+BEGIN
+   filename := CreateTemplate (GetDumpLangGimpleFilename (), InitString ('gimple')) ;
+   len := Length (filename) ;  (* This is a short cut based on '%03d' format
+                                  specifier used above.  *)
+   RETURN filename
+END MakeGimpleTemplate ;
+
+
+END M2LangDump.
diff --git a/gcc/m2/gm2-compiler/M2Options.def b/gcc/m2/gm2-compiler/M2Options.def
index 4e5f4993f82..0303850e0b0 100644
--- a/gcc/m2/gm2-compiler/M2Options.def
+++ b/gcc/m2/gm2-compiler/M2Options.def
@@ -55,7 +55,8 @@  VAR
    PedanticCast,                 (* -Wpedantic-cast warns if sizes differ.   *)
    Statistics,                   (* -fstatistics information about code      *)
    StyleChecking,                (* -Wstudents checks for common student errs*)
-   DisplayQuadruples,            (* -Wq option will display quadruples.      *)
+   DumpLangQuad,                 (* -fq, -fdump-lang-quad dump quadruples.   *)
+   DumpLangGimple,               (* -fdump-lang-gimple.                      *)
    UnboundedByReference,         (* -funbounded-by-reference                 *)
    VerboseUnbounded,             (* -Wverbose-unbounded                      *)
    OptimizeUncalledProcedures,   (* -Ouncalled removes uncalled procedures   *)
@@ -1002,6 +1003,56 @@  PROCEDURE SetIEEELongDouble (value: BOOLEAN) ;
 PROCEDURE GetIEEELongDouble () : BOOLEAN ;
 
 
+(*
+   GetDumpLangQuadFilename - returns the DumpLangQuadFilename.
+*)
+
+PROCEDURE GetDumpLangQuadFilename () : String ;
+
+
+(*
+   SetDumpLangQuadFilename - set DumpLangQuadFilename to filename.
+*)
+
+PROCEDURE SetDumpLangQuadFilename (value: BOOLEAN; filename: ADDRESS) ;
+
+
+(*
+   GetDumpLangGimpleFilename - returns the DumpLangGimpleFilename.
+*)
+
+PROCEDURE GetDumpLangGimpleFilename () : String ;
+
+
+(*
+   SetDumpLangGimpleFilename - set DumpLangGimpleFilename to filename.
+*)
+
+PROCEDURE SetDumpLangGimpleFilename (value: BOOLEAN; filename: ADDRESS) ;
+
+
+(*
+   SetM2DumpFilter - sets the filter to a comma separated list of procedures
+                     and modules.
+*)
+
+PROCEDURE SetM2DumpFilter (value: BOOLEAN; filter: ADDRESS) ;
+
+
+(*
+   GetM2DumpFilter - returns the dump filter.
+*)
+
+PROCEDURE GetM2DumpFilter () : ADDRESS ;
+
+
+(*
+   GetDumpLangGimple - return TRUE if -fdump-lang-gimple is set.
+*)
+
+PROCEDURE GetDumpLangGimple () : BOOLEAN ;
+
+
 (*
    FinaliseOptions - once all options have been parsed we set any inferred
                      values.
diff --git a/gcc/m2/gm2-compiler/M2Options.mod b/gcc/m2/gm2-compiler/M2Options.mod
index ae4980860b0..3b96b7463f2 100644
--- a/gcc/m2/gm2-compiler/M2Options.mod
+++ b/gcc/m2/gm2-compiler/M2Options.mod
@@ -34,7 +34,6 @@  FROM m2linemap IMPORT location_t ;
 FROM m2configure IMPORT FullPathCPP, TargetIEEEQuadDefault ;
 FROM M2Error IMPORT InternalError ;
 
-
 FROM DynamicStrings IMPORT String, Length, InitString, Mark, Slice, EqualArray,
                            InitStringCharStar, ConCatChar, ConCat, KillString,
                            Dup, string, char,
@@ -56,6 +55,9 @@  CONST
    DefaultRuntimeModuleOverride = "m2iso:RTentity,m2iso:Storage,m2iso:SYSTEM,m2iso:M2RTS,m2iso:RTExceptions,m2iso:IOLink" ;
 
 VAR
+   DumpLangQuadFilename,
+   DumpLangGimpleFilename,
+   M2DumpFilter,
    M2Prefix,
    M2PathName,
    Barg,
@@ -1049,7 +1051,9 @@  END SetSwig ;
 
 PROCEDURE SetQuadDebugging (value: BOOLEAN) ;
 BEGIN
-   DisplayQuadruples := value
+   DumpLangQuad := value ;
+   DumpLangQuadFilename := KillString (DumpLangQuadFilename) ;
+   DumpLangQuadFilename := InitString ('-')
 END SetQuadDebugging ;
 
 
@@ -1670,6 +1674,96 @@  BEGIN
 END InitializeLongDoubleFlags ;
 
 
+(*
+   GetDumpLangQuadFilename - returns the DumpLangQuadFilename.
+*)
+
+PROCEDURE GetDumpLangQuadFilename () : String ;
+BEGIN
+   RETURN DumpLangQuadFilename
+END GetDumpLangQuadFilename ;
+
+
+(*
+   SetDumpLangQuadFilename -
+*)
+
+PROCEDURE SetDumpLangQuadFilename (value: BOOLEAN; filename: ADDRESS) ;
+BEGIN
+   DumpLangQuad := value ;
+   DumpLangQuadFilename := KillString (DumpLangQuadFilename) ;
+   IF filename # NIL
+   THEN
+      DumpLangQuadFilename := InitStringCharStar (filename)
+   END
+END SetDumpLangQuadFilename ;
+
+
+(*
+   GetDumpLangGimpleFilename - returns the DumpLangGimpleFilename.
+*)
+
+PROCEDURE GetDumpLangGimpleFilename () : String ;
+BEGIN
+   RETURN DumpLangGimpleFilename
+END GetDumpLangGimpleFilename ;
+
+
+(*
+   SetDumpLangGimpleFilename - set DumpLangGimpleFilename to filename.
+*)
+
+PROCEDURE SetDumpLangGimpleFilename (value: BOOLEAN; filename: ADDRESS) ;
+BEGIN
+   DumpLangGimple := value ;
+   DumpLangGimpleFilename := KillString (DumpLangGimpleFilename) ;
+   IF value AND (filename # NIL)
+   THEN
+      DumpLangGimpleFilename := InitStringCharStar (filename)
+   END
+END SetDumpLangGimpleFilename ;
+
+
+(*
+   SetM2DumpFilter - sets the filter to a comma separated list of procedures
+                     and modules.
+*)
+
+PROCEDURE SetM2DumpFilter (value: BOOLEAN; filter: ADDRESS) ;
+BEGIN
+   M2DumpFilter := KillString (M2DumpFilter) ;
+   IF value AND (filter # NIL)
+   THEN
+      M2DumpFilter := InitStringCharStar (filter)
+   END
+END SetM2DumpFilter ;
+
+
+(*
+   GetM2DumpFilter - returns the dump filter.
+*)
+
+PROCEDURE GetM2DumpFilter () : ADDRESS ;
+BEGIN
+   IF M2DumpFilter = NIL
+   THEN
+      RETURN NIL
+   ELSE
+      RETURN string (M2DumpFilter)
+   END
+END GetM2DumpFilter ;
+
+
+(*
+   GetDumpLangGimple - return TRUE if -fdump-lang-gimple is set.
+*)
+
+PROCEDURE GetDumpLangGimple () : BOOLEAN ;
+BEGIN
+   RETURN DumpLangGimple
+END GetDumpLangGimple ;
+
+
 BEGIN
    cflag                             := FALSE ;  (* -c.  *)
    RuntimeModuleOverride             := InitString (DefaultRuntimeModuleOverride) ;
@@ -1691,7 +1785,7 @@  BEGIN
    Quiet                             :=  TRUE ;
    CC1Quiet                          :=  TRUE ;
    Profiling                         := FALSE ;
-   DisplayQuadruples                 := FALSE ;
+   DumpLangQuad                      := FALSE ;
    OptimizeBasicBlock                := FALSE ;
    OptimizeUncalledProcedures        := FALSE ;
    OptimizeCommonSubExpressions      := FALSE ;
@@ -1751,5 +1845,9 @@  BEGIN
    MQFlag                            := NIL ;
    InitializeLongDoubleFlags ;
    M2Prefix                          := InitString ('') ;
-   M2PathName                        := InitString ('')
+   M2PathName                        := InitString ('') ;
+   DumpLangQuadFilename              := NIL ;
+   DumpLangGimpleFilename            := NIL ;
+   DumpLangGimple                    := FALSE ;
+   M2DumpFilter                      := NIL
 END M2Options.
diff --git a/gcc/m2/gm2-compiler/M2Quads.def b/gcc/m2/gm2-compiler/M2Quads.def
index acc49c84b43..db1ec2c2055 100644
--- a/gcc/m2/gm2-compiler/M2Quads.def
+++ b/gcc/m2/gm2-compiler/M2Quads.def
@@ -125,7 +125,7 @@  EXPORT QUALIFIED StartBuildDefFile, StartBuildModFile, EndBuildFile,
                  IsDefOrModFile,
                  IsInitialisingConst,
 
-                 DisplayQuadList, DisplayQuadRange, DisplayQuad,
+                 DumpQuadruples, DisplayQuadRange, DisplayQuad,
                  WriteOperator, BackPatchSubrangesAndOptParam,
 
                  GetQuad, GetFirstQuad, GetNextQuad, PutQuad,
@@ -436,10 +436,12 @@  PROCEDURE IsDefOrModFile (QuadNo: CARDINAL) : BOOLEAN ;
 
 
 (*
-   DisplayQuadList - displays all quads.
+   DumpQuadruples - dump all quadruples providing the -fq, -fdump-lang-quad,
+                    -fdump-lang-quad= or -fdump-lang-all were issued to the
+                    command line.
 *)
 
-PROCEDURE DisplayQuadList ;
+PROCEDURE DumpQuadruples (title: ARRAY OF CHAR) ;
 
 
 (*
diff --git a/gcc/m2/gm2-compiler/M2Quads.mod b/gcc/m2/gm2-compiler/M2Quads.mod
index a23fa32906e..70a0fbd974b 100644
--- a/gcc/m2/gm2-compiler/M2Quads.mod
+++ b/gcc/m2/gm2-compiler/M2Quads.mod
@@ -27,6 +27,7 @@  FROM M2Debug IMPORT Assert, WriteDebug ;
 FROM NameKey IMPORT Name, NulName, MakeKey, GetKey, makekey, KeyToCharStar, WriteKey ;
 FROM FormatStrings IMPORT Sprintf0, Sprintf1, Sprintf2, Sprintf3 ;
 FROM M2DebugStack IMPORT DebugStack ;
+FROM StrLib IMPORT StrLen ;
 FROM M2Scaffold IMPORT DeclareScaffold, mainFunction, initFunction,
                        finiFunction, linkFunction, PopulateCtorArray,
                        ForeachModuleCallInit, ForeachModuleCallFinish ;
@@ -159,7 +160,8 @@  FROM M2Error IMPORT Error,
                     ErrorStringAt, ErrorStringAt2, ErrorStringsAt2,
                     WarnStringAt, WarnStringAt2, WarnStringsAt2 ;
 
-FROM M2Printf IMPORT printf0, printf1, printf2, printf3, printf4 ;
+FROM M2Printf IMPORT fprintf0, fprintf1, fprintf2, fprintf3, fprintf4,
+                     printf0, printf1, printf2, printf3, printf4 ;
 
 FROM M2Reserved IMPORT PlusTok, MinusTok, TimesTok, DivTok, ModTok,
                        DivideTok, RemTok,
@@ -217,8 +219,11 @@  FROM M2Options IMPORT NilChecking,
                       UninitVariableChecking,
                       ScaffoldDynamic, ScaffoldStatic, cflag,
                       ScaffoldMain, SharedFlag, WholeProgram,
-                      GetRuntimeModuleOverride ;
+                      GetDumpDir, GetM2DumpFilter,
+                      GetRuntimeModuleOverride,
+                      DumpLangQuad ;
 
+FROM M2LangDump IMPORT MakeQuadTemplate ;
 FROM M2Pass IMPORT IsPassCodeGeneration, IsNoPass ;
 
 FROM M2StackAddress IMPORT StackOfAddress, InitStackAddress, KillStackAddress,
@@ -260,8 +265,9 @@  FROM M2Range IMPORT InitAssignmentRangeCheck,
 FROM M2CaseList IMPORT PushCase, PopCase, AddRange, BeginCaseList, EndCaseList, ElseCase ;
 FROM PCSymBuild IMPORT SkipConst ;
 FROM m2builtins IMPORT GetBuiltinTypeInfoType ;
+FROM M2LangDump IMPORT IsDumpRequired ;
 
-IMPORT M2Error ;
+IMPORT M2Error, FIO, SFIO, DynamicStrings, StdIO ;
 
 
 CONST
@@ -5473,9 +5479,9 @@  BEGIN
       THEN
          IF i<=ParamTotal
          THEN
-            printf0('; ')
+            printf0 ('; ')
          ELSE
-            printf0(' ) ; \n')
+            printf0 (' ) ; \n')
          END
       END
    END
@@ -13182,23 +13188,206 @@  BEGIN
 END GenQuadOtok ;
 
 
+VAR
+   outputFile: FIO.File ;
+   mustClose : BOOLEAN ;
+   NoOfDumps : CARDINAL ;
+
+
+(*
+   DumpWrite - writes a single ch to the dump output.
+*)
+
+PROCEDURE DumpWrite (ch: CHAR) ;
+BEGIN
+   FIO.WriteChar (outputFile, ch)
+END DumpWrite ;
+
+
 (*
-   DisplayQuadList - displays all quads.
+   CloseOutput - close the dump output file.
 *)
 
-PROCEDURE DisplayQuadList ;
+PROCEDURE CloseOutput ;
+BEGIN
+   IF mustClose
+   THEN
+      FIO.Close (outputFile) ;
+      mustClose := FALSE
+   ELSE
+      FIO.FlushBuffer (outputFile)
+   END ;
+   StdIO.PopOutput ;
+   outputFile := FIO.StdOut
+END CloseOutput ;
+
+
+(*
+   ConfigureOutput - configure the dump file for a quad dump.
+*)
+
+PROCEDURE ConfigureOutput ;
+VAR
+   filename: String ;
+BEGIN
+   INC (NoOfDumps) ;
+   filename := MakeQuadTemplate () ;
+   IF DynamicStrings.EqualArray (filename, '-')
+   THEN
+      mustClose := FALSE ;
+      outputFile := FIO.StdOut
+   ELSE
+      filename := Sprintf1 (filename, NoOfDumps) ;
+      outputFile := SFIO.OpenToWrite (filename) ;
+      mustClose := FIO.IsNoError (outputFile)
+   END ;
+   filename := KillString (filename) ;
+   StdIO.PushOutput (DumpWrite)
+END ConfigureOutput ;
+
+
+(*
+   DumpUntil - dump all quadruples until we seen the ending quadruple
+               with procsym in the third operand.
+               Return the quad number containing the match.
+*)
+
+PROCEDURE DumpUntil (ending: QuadOperator;
+                     procsym: CARDINAL; quad: CARDINAL) : CARDINAL ;
+VAR
+   op           : QuadOperator ;
+   op1, op2, op3: CARDINAL ;
+   f            : QuadFrame ;
+BEGIN
+   fprintf0 (outputFile, '\n...\n\n');
+   REPEAT
+      GetQuad (quad, op, op1, op2, op3) ;
+      DisplayQuad (quad) ;
+      f := GetQF (quad) ;
+      quad := f^.Next
+   UNTIL (op = ending) AND (op3 = procsym) ;
+   RETURN quad
+END DumpUntil ;
+
+
+(*
+   GetCtorInit - return the init procedure for the module.
+*)
+
+PROCEDURE GetCtorInit (sym: CARDINAL) : CARDINAL ;
+VAR
+   ctor, init, fini, dep: CARDINAL ;
+BEGIN
+   GetModuleCtors (sym, ctor, init, fini, dep) ;
+   RETURN init
+END GetCtorInit ;
+
+
+(*
+   GetCtorFini - return the fini procedure for the module.
+*)
+
+PROCEDURE GetCtorFini (sym: CARDINAL) : CARDINAL ;
+VAR
+   ctor, init, fini, dep: CARDINAL ;
+BEGIN
+   GetModuleCtors (sym, ctor, init, fini, dep) ;
+   RETURN fini
+END GetCtorFini ;
+
+
+(*
+   DumpQuadrupleFilter -
+*)
+
+PROCEDURE DumpQuadrupleFilter ;
+VAR
+   f            : QuadFrame ;
+   i            : CARDINAL ;
+   op           : QuadOperator ;
+   proc,
+   op1, op2, op3: CARDINAL ;
+BEGIN
+   i := Head ;
+   WHILE i # 0 DO
+      GetQuad (i, op, op1, op2, op3) ;
+      IF (op = ProcedureScopeOp) AND IsDumpRequired (op3)
+      THEN
+         i := DumpUntil (KillLocalVarOp, op3, i)
+      ELSIF (op = InitStartOp) AND IsDumpRequired (GetCtorInit (op3))
+      THEN
+         i := DumpUntil (InitEndOp, op3, i)
+      ELSIF (op = FinallyStartOp) AND IsDumpRequired (GetCtorFini (op3))
+      THEN
+         i := DumpUntil (FinallyEndOp, op3, i)
+      ELSE
+         f := GetQF (i) ;
+         i := f^.Next
+      END
+   END
+END DumpQuadrupleFilter ;
+
+
+(*
+   DumpQuadrupleAll - dump all quadruples.
+*)
+
+PROCEDURE DumpQuadrupleAll ;
 VAR
-   i: CARDINAL ;
    f: QuadFrame ;
+   i: CARDINAL ;
 BEGIN
-   printf0('Quadruples:\n') ;
    i := Head ;
-   WHILE i#0 DO
-      DisplayQuad(i) ;
-      f := GetQF(i) ;
+   WHILE i # 0 DO
+      DisplayQuad (i) ;
+      f := GetQF (i) ;
       i := f^.Next
    END
-END DisplayQuadList ;
+END DumpQuadrupleAll ;
+
+
+(*
+   DumpQuadruples - dump all quadruples providing the -fq, -fdump-lang-quad,
+                    -fdump-lang-quad= or -fdump-lang-all were issued to the
+                    command line.
+*)
+
+PROCEDURE DumpQuadruples (title: ARRAY OF CHAR) ;
+VAR
+   len,
+   text,
+   i   : CARDINAL ;
+   s   : String ;
+BEGIN
+   IF DumpLangQuad
+   THEN
+      ConfigureOutput ;
+      s := Sprintf0 (Mark (InitString (title))) ;
+      s := KillString (SFIO.WriteS (outputFile, s)) ;
+      len := StrLen (title) ;
+      i := 0 ;
+      text := 0 ;
+      WHILE i < len DO
+         IF title[i] = '\'
+         THEN
+            INC (i, 2)
+         ELSE
+            INC (i) ;
+            INC (text)
+         END
+      END ;
+      s := DynamicStrings.Mult (Mark (InitString ('=')), text) ;
+      s := KillString (SFIO.WriteS (outputFile, s)) ;
+      fprintf0 (outputFile, '\n');
+      IF GetM2DumpFilter () = NIL
+      THEN
+         DumpQuadrupleAll
+      ELSE
+         DumpQuadrupleFilter
+      END ;
+      CloseOutput
+   END
+END DumpQuadruples ;
 
 
 (*
@@ -13209,7 +13398,7 @@  PROCEDURE DisplayQuadRange (scope: CARDINAL; start, end: CARDINAL) ;
 VAR
    f: QuadFrame ;
 BEGIN
-   printf1 ('Quadruples for scope: %d\n', scope) ;
+   fprintf1 (outputFile, 'Quadruples for scope: %d\n', scope) ;
    WHILE (start <= end) AND (start # 0) DO
       DisplayQuad (start) ;
       f := GetQF (start) ;
@@ -13341,7 +13530,7 @@  END ds ;
 PROCEDURE DisplayQuad (QuadNo: CARDINAL) ;
 BEGIN
    DSdbEnter ;
-   printf1('%4d  ', QuadNo) ; WriteQuad(QuadNo) ; printf0('\n') ;
+   fprintf1 (outputFile, '%4d  ', QuadNo) ; WriteQuad(QuadNo) ; fprintf0 (outputFile, '\n') ;
    DSdbExit
 END DisplayQuad ;
 
@@ -13354,19 +13543,19 @@  PROCEDURE DisplayProcedureAttributes (proc: CARDINAL) ;
 BEGIN
    IF IsCtor (proc)
    THEN
-      printf0 (" (ctor)")
+      fprintf0 (outputFile, " (ctor)")
    END ;
    IF IsPublic (proc)
    THEN
-      printf0 (" (public)")
+      fprintf0 (outputFile, " (public)")
    END ;
    IF IsExtern (proc)
    THEN
-      printf0 (" (extern)")
+      fprintf0 (outputFile, " (extern)")
    END ;
    IF IsMonoName (proc)
    THEN
-      printf0 (" (mononame)")
+      fprintf0 (outputFile, " (mononame)")
    END
 END DisplayProcedureAttributes ;
 
@@ -13385,11 +13574,11 @@  BEGIN
    f := GetQF(BufferQuad) ;
    WITH f^ DO
       WriteOperator(Operator) ;
-      printf1('  [%d]    ', NoOfTimesReferenced) ;
+      fprintf1 (outputFile, '  [%d]    ', NoOfTimesReferenced) ;
       CASE Operator OF
 
       HighOp           : WriteOperand(Operand1) ;
-                         printf1('  %4d  ', Operand2) ;
+                         fprintf1 (outputFile, '  %4d  ', Operand2) ;
                          WriteOperand(Operand3) |
       InitAddressOp,
       SavePriorityOp,
@@ -13404,7 +13593,7 @@  BEGIN
       FunctValueOp,
       NegateOp,
       AddrOp            : WriteOperand(Operand1) ;
-                          printf0('  ') ;
+                          fprintf0 (outputFile, '  ') ;
                           WriteOperand(Operand3) |
       ElementSizeOp,
       IfInOp,
@@ -13415,22 +13604,22 @@  BEGIN
       IfGreOp,
       IfLessEquOp,
       IfGreEquOp        : WriteOperand(Operand1) ;
-                          printf0('  ') ;
+                          fprintf0 (outputFile, '  ') ;
                           WriteOperand(Operand2) ;
-                          printf1('  %4d', Operand3) |
+                          fprintf1 (outputFile, '  %4d', Operand3) |
 
       InlineOp,
       RetryOp,
       TryOp,
-      GotoOp            : printf1('%4d', Operand3) |
+      GotoOp            : fprintf1 (outputFile, '%4d', Operand3) |
 
       StatementNoteOp   : l := TokenToLineNo(Operand3, 0) ;
                           n := GetTokenName (Operand3) ;
-                          printf4('%a:%d:%a (tokenno %d)', Operand1, l, n, Operand3) |
-      LineNumberOp      : printf2('%a:%d', Operand1, Operand3) |
+                          fprintf4 (outputFile, '%a:%d:%a (tokenno %d)', Operand1, l, n, Operand3) |
+      LineNumberOp      : fprintf2 (outputFile, '%a:%d', Operand1, Operand3) |
 
       EndFileOp         : n1 := GetSymName(Operand3) ;
-                          printf1('%a', n1) |
+                          fprintf1 (outputFile, '%a', n1) |
 
       ThrowOp,
       ReturnOp,
@@ -13439,7 +13628,7 @@  BEGIN
 
       ProcedureScopeOp  : n1 := GetSymName(Operand2) ;
                           n2 := GetSymName(Operand3) ;
-                          printf3('  %4d  %a  %a', Operand1, n1, n2) ;
+                          fprintf3 (outputFile, '  %4d  %a  %a', Operand1, n1, n2) ;
                           DisplayProcedureAttributes (Operand3) |
       NewLocalVarOp,
       FinallyStartOp,
@@ -13447,19 +13636,19 @@  BEGIN
       InitEndOp,
       InitStartOp       : n1 := GetSymName(Operand2) ;
                           n2 := GetSymName(Operand3) ;
-                          printf3('  %4d  %a  %a', Operand1, n1, n2) |
+                          fprintf3 (outputFile, '  %4d  %a  %a', Operand1, n1, n2) |
 
       ModuleScopeOp,
       StartModFileOp    : n1 := GetSymName(Operand3) ;
-                          printf4('%a:%d  %a(%d)', Operand2, Operand1, n1, Operand3) |
+                          fprintf4 (outputFile, '%a:%d  %a(%d)', Operand2, Operand1, n1, Operand3) |
 
       StartDefFileOp    : n1 := GetSymName(Operand3) ;
-                          printf2('  %4d  %a', Operand1, n1) |
+                          fprintf2 (outputFile, '  %4d  %a', Operand1, n1) |
 
       OptParamOp,
-      ParamOp           : printf1('%4d  ', Operand1) ;
+      ParamOp           : fprintf1 (outputFile, '%4d  ', Operand1) ;
                           WriteOperand(Operand2) ;
-                          printf0('  ') ;
+                          fprintf0 (outputFile, '  ') ;
                           WriteOperand(Operand3) |
       SizeOp,
       RecordFieldOp,
@@ -13487,9 +13676,9 @@  BEGIN
       DivFloorOp,
       ModTruncOp,
       DivTruncOp        : WriteOperand(Operand1) ;
-                          printf0('  ') ;
+                          fprintf0 (outputFile, '  ') ;
                           WriteOperand(Operand2) ;
-                          printf0('  ') ;
+                          fprintf0 (outputFile, '  ') ;
                           WriteOperand(Operand3) |
       DummyOp,
       CodeOnOp,
@@ -13499,23 +13688,23 @@  BEGIN
       OptimizeOnOp,
       OptimizeOffOp     : |
       BuiltinConstOp    : WriteOperand(Operand1) ;
-                          printf1('   %a', Operand3) |
+                          fprintf1 (outputFile, '   %a', Operand3) |
       BuiltinTypeInfoOp : WriteOperand(Operand1) ;
-                          printf1('   %a', Operand2) ;
-                          printf1('   %a', Operand3) |
+                          fprintf1 (outputFile, '   %a', Operand2) ;
+                          fprintf1 (outputFile, '   %a', Operand3) |
       StandardFunctionOp: WriteOperand(Operand1) ;
-                          printf0('  ') ;
+                          fprintf0 (outputFile, '  ') ;
                           WriteOperand(Operand2) ;
-                          printf0('  ') ;
+                          fprintf0 (outputFile, '  ') ;
                           WriteOperand(Operand3) |
       CatchBeginOp,
       CatchEndOp        : |
 
       RangeCheckOp,
-      ErrorOp           : WriteRangeCheck(Operand3) |
+      ErrorOp           : WriteRangeCheck (Operand3) |
       SaveExceptionOp,
       RestoreExceptionOp: WriteOperand(Operand1) ;
-                          printf0('  ') ;
+                          fprintf0 (outputFile, '  ') ;
                           WriteOperand(Operand3)
 
       ELSE
@@ -13533,91 +13722,91 @@  PROCEDURE WriteOperator (Operator: QuadOperator) ;
 BEGIN
    CASE Operator OF
 
-   ArithAddOp               : printf0('Arith +           ') |
-   InitAddressOp            : printf0('InitAddress       ') |
-   LogicalOrOp              : printf0('Or                ') |
-   LogicalAndOp             : printf0('And               ') |
-   LogicalXorOp             : printf0('Xor               ') |
-   LogicalDiffOp            : printf0('Ldiff             ') |
-   LogicalShiftOp           : printf0('Shift             ') |
-   LogicalRotateOp          : printf0('Rotate            ') |
-   BecomesOp                : printf0('Becomes           ') |
-   IndrXOp                  : printf0('IndrX             ') |
-   XIndrOp                  : printf0('XIndr             ') |
-   ArrayOp                  : printf0('Array             ') |
-   ElementSizeOp            : printf0('ElementSize       ') |
-   RecordFieldOp            : printf0('RecordField       ') |
-   AddrOp                   : printf0('Addr              ') |
-   SizeOp                   : printf0('Size              ') |
-   IfInOp                   : printf0('If IN             ') |
-   IfNotInOp                : printf0('If NOT IN         ') |
-   IfNotEquOp               : printf0('If <>             ') |
-   IfEquOp                  : printf0('If =              ') |
-   IfLessEquOp              : printf0('If <=             ') |
-   IfGreEquOp               : printf0('If >=             ') |
-   IfGreOp                  : printf0('If >              ') |
-   IfLessOp                 : printf0('If <              ') |
-   GotoOp                   : printf0('Goto              ') |
-   DummyOp                  : printf0('Dummy             ') |
-   ModuleScopeOp            : printf0('ModuleScopeOp     ') |
-   StartDefFileOp           : printf0('StartDefFile      ') |
-   StartModFileOp           : printf0('StartModFile      ') |
-   EndFileOp                : printf0('EndFileOp         ') |
-   InitStartOp              : printf0('InitStart         ') |
-   InitEndOp                : printf0('InitEnd           ') |
-   FinallyStartOp           : printf0('FinallyStart      ') |
-   FinallyEndOp             : printf0('FinallyEnd        ') |
-   RetryOp                  : printf0('Retry             ') |
-   TryOp                    : printf0('Try               ') |
-   ThrowOp                  : printf0('Throw             ') |
-   CatchBeginOp             : printf0('CatchBegin        ') |
-   CatchEndOp               : printf0('CatchEnd          ') |
-   AddOp                    : printf0('+                 ') |
-   SubOp                    : printf0('-                 ') |
-   DivM2Op                  : printf0('DIV M2            ') |
-   ModM2Op                  : printf0('MOD M2            ') |
-   DivCeilOp                : printf0('DIV ceil          ') |
-   ModCeilOp                : printf0('MOD ceil          ') |
-   DivFloorOp               : printf0('DIV floor         ') |
-   ModFloorOp               : printf0('MOD floor         ') |
-   DivTruncOp               : printf0('DIV trunc         ') |
-   ModTruncOp               : printf0('MOD trunc         ') |
-   MultOp                   : printf0('*                 ') |
-   NegateOp                 : printf0('Negate            ') |
-   InclOp                   : printf0('Incl              ') |
-   ExclOp                   : printf0('Excl              ') |
-   ReturnOp                 : printf0('Return            ') |
-   ReturnValueOp            : printf0('ReturnValue       ') |
-   FunctValueOp             : printf0('FunctValue        ') |
-   CallOp                   : printf0('Call              ') |
-   ParamOp                  : printf0('Param             ') |
-   OptParamOp               : printf0('OptParam          ') |
-   NewLocalVarOp            : printf0('NewLocalVar       ') |
-   KillLocalVarOp           : printf0('KillLocalVar      ') |
-   ProcedureScopeOp         : printf0('ProcedureScope    ') |
-   UnboundedOp              : printf0('Unbounded         ') |
-   CoerceOp                 : printf0('Coerce            ') |
-   ConvertOp                : printf0('Convert           ') |
-   CastOp                   : printf0('Cast              ') |
-   HighOp                   : printf0('High              ') |
-   CodeOnOp                 : printf0('CodeOn            ') |
-   CodeOffOp                : printf0('CodeOff           ') |
-   ProfileOnOp              : printf0('ProfileOn         ') |
-   ProfileOffOp             : printf0('ProfileOff        ') |
-   OptimizeOnOp             : printf0('OptimizeOn        ') |
-   OptimizeOffOp            : printf0('OptimizeOff       ') |
-   InlineOp                 : printf0('Inline            ') |
-   StatementNoteOp          : printf0('StatementNote     ') |
-   LineNumberOp             : printf0('LineNumber        ') |
-   BuiltinConstOp           : printf0('BuiltinConst      ') |
-   BuiltinTypeInfoOp        : printf0('BuiltinTypeInfo   ') |
-   StandardFunctionOp       : printf0('StandardFunction  ') |
-   SavePriorityOp           : printf0('SavePriority      ') |
-   RestorePriorityOp        : printf0('RestorePriority   ') |
-   RangeCheckOp             : printf0('RangeCheck        ') |
-   ErrorOp                  : printf0('Error             ') |
-   SaveExceptionOp          : printf0('SaveException     ') |
-   RestoreExceptionOp       : printf0('RestoreException  ')
+   ArithAddOp               : fprintf0 (outputFile, 'Arith +           ') |
+   InitAddressOp            : fprintf0 (outputFile, 'InitAddress       ') |
+   LogicalOrOp              : fprintf0 (outputFile, 'Or                ') |
+   LogicalAndOp             : fprintf0 (outputFile, 'And               ') |
+   LogicalXorOp             : fprintf0 (outputFile, 'Xor               ') |
+   LogicalDiffOp            : fprintf0 (outputFile, 'Ldiff             ') |
+   LogicalShiftOp           : fprintf0 (outputFile, 'Shift             ') |
+   LogicalRotateOp          : fprintf0 (outputFile, 'Rotate            ') |
+   BecomesOp                : fprintf0 (outputFile, 'Becomes           ') |
+   IndrXOp                  : fprintf0 (outputFile, 'IndrX             ') |
+   XIndrOp                  : fprintf0 (outputFile, 'XIndr             ') |
+   ArrayOp                  : fprintf0 (outputFile, 'Array             ') |
+   ElementSizeOp            : fprintf0 (outputFile, 'ElementSize       ') |
+   RecordFieldOp            : fprintf0 (outputFile, 'RecordField       ') |
+   AddrOp                   : fprintf0 (outputFile, 'Addr              ') |
+   SizeOp                   : fprintf0 (outputFile, 'Size              ') |
+   IfInOp                   : fprintf0 (outputFile, 'If IN             ') |
+   IfNotInOp                : fprintf0 (outputFile, 'If NOT IN         ') |
+   IfNotEquOp               : fprintf0 (outputFile, 'If <>             ') |
+   IfEquOp                  : fprintf0 (outputFile, 'If =              ') |
+   IfLessEquOp              : fprintf0 (outputFile, 'If <=             ') |
+   IfGreEquOp               : fprintf0 (outputFile, 'If >=             ') |
+   IfGreOp                  : fprintf0 (outputFile, 'If >              ') |
+   IfLessOp                 : fprintf0 (outputFile, 'If <              ') |
+   GotoOp                   : fprintf0 (outputFile, 'Goto              ') |
+   DummyOp                  : fprintf0 (outputFile, 'Dummy             ') |
+   ModuleScopeOp            : fprintf0 (outputFile, 'ModuleScopeOp     ') |
+   StartDefFileOp           : fprintf0 (outputFile, 'StartDefFile      ') |
+   StartModFileOp           : fprintf0 (outputFile, 'StartModFile      ') |
+   EndFileOp                : fprintf0 (outputFile, 'EndFileOp         ') |
+   InitStartOp              : fprintf0 (outputFile, 'InitStart         ') |
+   InitEndOp                : fprintf0 (outputFile, 'InitEnd           ') |
+   FinallyStartOp           : fprintf0 (outputFile, 'FinallyStart      ') |
+   FinallyEndOp             : fprintf0 (outputFile, 'FinallyEnd        ') |
+   RetryOp                  : fprintf0 (outputFile, 'Retry             ') |
+   TryOp                    : fprintf0 (outputFile, 'Try               ') |
+   ThrowOp                  : fprintf0 (outputFile, 'Throw             ') |
+   CatchBeginOp             : fprintf0 (outputFile, 'CatchBegin        ') |
+   CatchEndOp               : fprintf0 (outputFile, 'CatchEnd          ') |
+   AddOp                    : fprintf0 (outputFile, '+                 ') |
+   SubOp                    : fprintf0 (outputFile, '-                 ') |
+   DivM2Op                  : fprintf0 (outputFile, 'DIV M2            ') |
+   ModM2Op                  : fprintf0 (outputFile, 'MOD M2            ') |
+   DivCeilOp                : fprintf0 (outputFile, 'DIV ceil          ') |
+   ModCeilOp                : fprintf0 (outputFile, 'MOD ceil          ') |
+   DivFloorOp               : fprintf0 (outputFile, 'DIV floor         ') |
+   ModFloorOp               : fprintf0 (outputFile, 'MOD floor         ') |
+   DivTruncOp               : fprintf0 (outputFile, 'DIV trunc         ') |
+   ModTruncOp               : fprintf0 (outputFile, 'MOD trunc         ') |
+   MultOp                   : fprintf0 (outputFile, '*                 ') |
+   NegateOp                 : fprintf0 (outputFile, 'Negate            ') |
+   InclOp                   : fprintf0 (outputFile, 'Incl              ') |
+   ExclOp                   : fprintf0 (outputFile, 'Excl              ') |
+   ReturnOp                 : fprintf0 (outputFile, 'Return            ') |
+   ReturnValueOp            : fprintf0 (outputFile, 'ReturnValue       ') |
+   FunctValueOp             : fprintf0 (outputFile, 'FunctValue        ') |
+   CallOp                   : fprintf0 (outputFile, 'Call              ') |
+   ParamOp                  : fprintf0 (outputFile, 'Param             ') |
+   OptParamOp               : fprintf0 (outputFile, 'OptParam          ') |
+   NewLocalVarOp            : fprintf0 (outputFile, 'NewLocalVar       ') |
+   KillLocalVarOp           : fprintf0 (outputFile, 'KillLocalVar      ') |
+   ProcedureScopeOp         : fprintf0 (outputFile, 'ProcedureScope    ') |
+   UnboundedOp              : fprintf0 (outputFile, 'Unbounded         ') |
+   CoerceOp                 : fprintf0 (outputFile, 'Coerce            ') |
+   ConvertOp                : fprintf0 (outputFile, 'Convert           ') |
+   CastOp                   : fprintf0 (outputFile, 'Cast              ') |
+   HighOp                   : fprintf0 (outputFile, 'High              ') |
+   CodeOnOp                 : fprintf0 (outputFile, 'CodeOn            ') |
+   CodeOffOp                : fprintf0 (outputFile, 'CodeOff           ') |
+   ProfileOnOp              : fprintf0 (outputFile, 'ProfileOn         ') |
+   ProfileOffOp             : fprintf0 (outputFile, 'ProfileOff        ') |
+   OptimizeOnOp             : fprintf0 (outputFile, 'OptimizeOn        ') |
+   OptimizeOffOp            : fprintf0 (outputFile, 'OptimizeOff       ') |
+   InlineOp                 : fprintf0 (outputFile, 'Inline            ') |
+   StatementNoteOp          : fprintf0 (outputFile, 'StatementNote     ') |
+   LineNumberOp             : fprintf0 (outputFile, 'LineNumber        ') |
+   BuiltinConstOp           : fprintf0 (outputFile, 'BuiltinConst      ') |
+   BuiltinTypeInfoOp        : fprintf0 (outputFile, 'BuiltinTypeInfo   ') |
+   StandardFunctionOp       : fprintf0 (outputFile, 'StandardFunction  ') |
+   SavePriorityOp           : fprintf0 (outputFile, 'SavePriority      ') |
+   RestorePriorityOp        : fprintf0 (outputFile, 'RestorePriority   ') |
+   RangeCheckOp             : fprintf0 (outputFile, 'RangeCheck        ') |
+   ErrorOp                  : fprintf0 (outputFile, 'Error             ') |
+   SaveExceptionOp          : fprintf0 (outputFile, 'SaveException     ') |
+   RestoreExceptionOp       : fprintf0 (outputFile, 'RestoreException  ')
 
    ELSE
       InternalError ('operator not expected')
@@ -13635,15 +13824,15 @@  VAR
 BEGIN
    IF Sym = NulSym
    THEN
-      printf0 ('<nulsym>')
+      fprintf0 (outputFile, '<nulsym>')
    ELSE
       n := GetSymName (Sym) ;
-      printf1 ('%a', n) ;
+      fprintf1 (outputFile, '%a', n) ;
       IF IsVar (Sym) OR IsConst (Sym)
       THEN
-         printf0 ('[') ; WriteMode (GetMode (Sym)) ; printf0(']')
+         fprintf0 (outputFile, '[') ; WriteMode (GetMode (Sym)) ; fprintf0 (outputFile, ']')
       END ;
-      printf1 ('(%d)', Sym)
+      fprintf1 (outputFile, '(%d)', Sym)
    END
 END WriteOperand ;
 
@@ -13652,10 +13841,10 @@  PROCEDURE WriteMode (Mode: ModeOfAddr) ;
 BEGIN
    CASE Mode OF
 
-   ImmediateValue: printf0('i') |
-   NoValue       : printf0('n') |
-   RightValue    : printf0('r') |
-   LeftValue     : printf0('l')
+   ImmediateValue: fprintf0 (outputFile, 'i') |
+   NoValue       : fprintf0 (outputFile, 'n') |
+   RightValue    : fprintf0 (outputFile, 'r') |
+   LeftValue     : fprintf0 (outputFile, 'l')
 
    ELSE
       InternalError ('unrecognised mode')
@@ -15357,7 +15546,9 @@  BEGIN
    FreeLineList := NIL ;
    InitList(VarientFields) ;
    VarientFieldNo := 0 ;
-   NoOfQuads := 0
+   NoOfQuads := 0 ;
+   NoOfDumps := 0 ;
+   outputFile := FIO.StdOut
 END Init ;
 
 
diff --git a/gcc/m2/gm2-compiler/M2Scope.mod b/gcc/m2/gm2-compiler/M2Scope.mod
index f157ad42ba6..2c2ff459d81 100644
--- a/gcc/m2/gm2-compiler/M2Scope.mod
+++ b/gcc/m2/gm2-compiler/M2Scope.mod
@@ -29,7 +29,6 @@  FROM SymbolTable IMPORT IsProcedure, IsDefImp, GetProcedureQuads, GetScope,
                         GetProcedureScope, IsModule, IsModuleWithinProcedure,
                         GetSymName, GetErrorScope, NulSym ;
 
-FROM M2Options IMPORT DisplayQuadruples ;
 FROM M2Printf IMPORT printf0, printf1 ;
 FROM M2Quads IMPORT QuadOperator, GetFirstQuad, GetNextQuad, GetQuad, DisplayQuadRange ;
 FROM M2StackWord IMPORT StackOfWord, InitStackWord, KillStackWord,
@@ -38,7 +37,8 @@  IMPORT M2Error ;
 
 
 CONST
-   Debugging = FALSE ;
+   Debugging       = FALSE ;
+   TraceQuadruples = FALSE ;
 
 TYPE
    scopeKind = (unsetscope, ignorescope, procedurescope, modulescope, definitionscope, implementationscope, programscope) ;
@@ -381,7 +381,7 @@  BEGIN
          ELSE
             sb := GetGlobalQuads (sb, scope) ;
          END ;
-         IF DisplayQuadruples
+         IF TraceQuadruples
          THEN
             DisplayScope (sb)
          END
@@ -416,13 +416,13 @@  END KillScopeBlock ;
 
 PROCEDURE ForeachScopeBlockDo2 (sb: ScopeBlock; p: ScopeProcedure2) ;
 BEGIN
-   IF DisplayQuadruples
+   IF TraceQuadruples
    THEN
       printf0 ("ForeachScopeBlockDo\n")
    END ;
    WHILE sb#NIL DO
       WITH sb^ DO
-         IF DisplayQuadruples
+         IF TraceQuadruples
          THEN
             DisplayScope (sb)
          END ;
@@ -435,7 +435,7 @@  BEGIN
       END ;
       sb := sb^.next
    END ;
-   IF DisplayQuadruples
+   IF TraceQuadruples
    THEN
       printf0 ("end ForeachScopeBlockDo\n\n")
    END ;
@@ -449,13 +449,13 @@  END ForeachScopeBlockDo2 ;
 
 PROCEDURE ForeachScopeBlockDo3 (sb: ScopeBlock; p: ScopeProcedure3) ;
 BEGIN
-   IF DisplayQuadruples
+   IF TraceQuadruples
    THEN
       printf0 ("ForeachScopeBlockDo\n")
    END ;
    WHILE sb#NIL DO
       WITH sb^ DO
-         IF DisplayQuadruples
+         IF TraceQuadruples
          THEN
             DisplayScope (sb)
          END ;
@@ -468,7 +468,7 @@  BEGIN
       END ;
       sb := sb^.next
    END ;
-   IF DisplayQuadruples
+   IF TraceQuadruples
    THEN
       printf0 ("end ForeachScopeBlockDo\n\n")
    END ;
diff --git a/gcc/m2/gm2-compiler/SymbolConversion.def b/gcc/m2/gm2-compiler/SymbolConversion.def
index 8f8d4650ce2..81a52e4aa1e 100644
--- a/gcc/m2/gm2-compiler/SymbolConversion.def
+++ b/gcc/m2/gm2-compiler/SymbolConversion.def
@@ -31,8 +31,6 @@  DEFINITION MODULE SymbolConversion ;
 
 FROM m2tree IMPORT Tree ;
 FROM SYSTEM IMPORT WORD ;
-EXPORT QUALIFIED Mod2Gcc, AddModGcc, GccKnowsAbout, AddTemporaryKnown,
-                 RemoveTemporaryKnown, Poison, RemoveMod2Gcc ;
 
 
 (*
@@ -42,6 +40,13 @@  EXPORT QUALIFIED Mod2Gcc, AddModGcc, GccKnowsAbout, AddTemporaryKnown,
 PROCEDURE Mod2Gcc (sym: CARDINAL) : Tree ;
 
 
+(*
+   Gcc2Mod - given a gcc tree return the modula-2 symbol.
+*)
+
+PROCEDURE Gcc2Mod (tree: Tree) : CARDINAL ;
+
+
 (*
    AddModGcc - adds the tuple [ sym, gcc ] into the database.
 *)
diff --git a/gcc/m2/gm2-compiler/SymbolConversion.mod b/gcc/m2/gm2-compiler/SymbolConversion.mod
index c3c484db00a..39d23e1fd7f 100644
--- a/gcc/m2/gm2-compiler/SymbolConversion.mod
+++ b/gcc/m2/gm2-compiler/SymbolConversion.mod
@@ -24,10 +24,10 @@  IMPLEMENTATION MODULE SymbolConversion ;
 FROM NameKey IMPORT Name ;
 
 FROM Indexing IMPORT Index, InitIndex, PutIndice, GetIndice, InBounds,
-                     DebugIndex ;
+                     DebugIndex, HighIndice ;
 
 FROM SymbolTable IMPORT IsConst, PopValue, IsValueSolved, GetSymName,
-                        GetType, SkipType ;
+                        GetType, SkipType, NulSym ;
 
 FROM M2Error IMPORT InternalError ;
 FROM M2ALU IMPORT PushTypeOfTree ;
@@ -87,6 +87,27 @@  BEGIN
 END Mod2Gcc ;
 
 
+(*
+   Gcc2Mod - given a gcc tree return the modula-2 symbol.
+*)
+
+PROCEDURE Gcc2Mod (tree: Tree) : CARDINAL ;
+VAR
+   high, i: CARDINAL ;
+BEGIN
+   i := 1 ;
+   high := HighIndice (mod2gcc) ;
+   WHILE i <= high DO
+      IF GetIndice (mod2gcc, i) = tree
+      THEN
+         RETURN i
+      END ;
+      INC (i)
+   END ;
+   RETURN NulSym
+END Gcc2Mod ;
+
+
 (*
    AddModGcc - adds the tuple [ sym, gcc ] into the database.
 *)
diff --git a/gcc/m2/gm2-gcc/m2langdump.h b/gcc/m2/gm2-gcc/m2langdump.h
new file mode 100644
index 00000000000..ba0e54e2c41
--- /dev/null
+++ b/gcc/m2/gm2-gcc/m2langdump.h
@@ -0,0 +1,41 @@ 
+/* m2langdump.h header file for m2langdump.cc.
+
+Copyright (C) 2024 Free Software Foundation, Inc.
+Contributed by Gaius Mulley <gaiusmod2@gmail.com>.
+
+This file is part of GNU Modula-2.
+
+GNU Modula-2 is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GNU Modula-2 is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Modula-2; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#if !defined(m2langdump_h)
+#define m2langdump_h
+#if defined(m2langdump_c)
+#if defined(__GNUG__)
+#define EXTERN extern "C"
+#else /* !__GNUG__.  */
+#define EXTERN
+#endif /* !__GNUG__.  */
+#else /* !m2langdump_c.  */
+#if defined(__GNUG__)
+#define EXTERN extern "C"
+#else /* !__GNUG__.  */
+#define EXTERN extern
+#endif /* !__GNUG__.  */
+#endif /* !m2langdump_c.  */
+
+EXTERN bool M2LangDump_IsDumpRequiredTree (tree t);
+
+#undef EXTERN
+#endif  /* m2langdump_h.  */
diff --git a/gcc/m2/gm2-gcc/m2misc.cc b/gcc/m2/gm2-gcc/m2misc.cc
index d69f33c003d..451abfe14f9 100644
--- a/gcc/m2/gm2-gcc/m2misc.cc
+++ b/gcc/m2/gm2-gcc/m2misc.cc
@@ -29,7 +29,7 @@  along with GNU Modula-2; see the file COPYING3.  If not see
 #include "m2misc.h"
 #include "m2tree.h"
 
-/* DebugTree - display the tree, t.  */
+/* DebugTree - display the tree t.  */
 
 void
 m2misc_DebugTree (tree t)
@@ -37,7 +37,7 @@  m2misc_DebugTree (tree t)
   debug_tree (t);
 }
 
-/* DebugTree - display the tree, t.  */
+/* DebugTree - display the trees chained in t.  */
 
 void
 m2misc_DebugTreeChain (tree t)
@@ -46,7 +46,7 @@  m2misc_DebugTreeChain (tree t)
     debug_tree (t);
 }
 
-/* DebugTree - display the tree, t.  */
+/* DebugTree - display the current statement list.  */
 
 void
 m2misc_printStmt (void)
diff --git a/gcc/m2/gm2-gcc/m2options.h b/gcc/m2/gm2-gcc/m2options.h
index 01256a9fc80..7bcd6962f6d 100644
--- a/gcc/m2/gm2-gcc/m2options.h
+++ b/gcc/m2/gm2-gcc/m2options.h
@@ -152,6 +152,13 @@  EXTERN void M2Options_SetIBMLongDouble (bool value);
 EXTERN bool M2Options_GetIBMLongDouble (void);
 EXTERN void M2Options_SetIEEELongDouble (bool value);
 EXTERN bool M2Options_GetIEEELongDouble (void);
+EXTERN bool M2Options_GetDumpLangQuadFilename (void);
+EXTERN void M2Options_SetDumpLangQuadFilename (bool value, const char *arg);
+EXTERN bool M2Options_GetDumpLangGimpleFilename (void);
+EXTERN void M2Options_SetDumpLangGimpleFilename (bool value, const char *arg);
+EXTERN bool M2Options_GetDumpLangGimple (void);
+EXTERN void M2Options_SetM2DumpFilter (bool value, const char *args);
+EXTERN char *M2Options_GetM2DumpFilter (void);
 
 #undef EXTERN
 #endif /* m2options_h.  */
diff --git a/gcc/m2/m2pp.cc b/gcc/m2/gm2-gcc/m2pp.cc
similarity index 93%
rename from gcc/m2/m2pp.cc
rename to gcc/m2/gm2-gcc/m2pp.cc
index 2f4c45ced14..ff2e3ee224f 100644
--- a/gcc/m2/m2pp.cc
+++ b/gcc/m2/gm2-gcc/m2pp.cc
@@ -19,28 +19,27 @@  You should have received a copy of the GNU General Public License
 along with GNU Modula-2; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
-#if defined(GM2)
-#include "gm2-gcc/gcc-consolidation.h"
+#include "gcc-consolidation.h"
 
-#include "m2-tree.h"
-#include "gm2-lang.h"
+#include "../m2-tree.h"
+#include "../gm2-lang.h"
 
-#include "gm2-gcc/m2tree.h"
-#include "gm2-gcc/m2expr.h"
-#include "gm2-gcc/m2type.h"
-#include "gm2-gcc/m2decl.h"
-#else
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "cp/cp-tree.h"
-#include "stringpool.h"
-#include "gm2-gcc/gcc-consolidation.h"
-#include "../cp/cp-tree.h"
-#endif
+#include "m2tree.h"
+#include "m2expr.h"
+#include "m2type.h"
+#include "m2decl.h"
+#include "m2options.h"
+#include "m2langdump.h"
 
 #define M2PP_C
-#include "m2/m2pp.h"
+#include "m2pp.h"
+
+const char *m2pp_dump_description[M2PP_DUMP_END] =
+{
+  "interactive user invoked output",
+  "modula-2 gimple trees pre genercize",
+  "modula-2 gimple trees post genercize",
+};
 
 namespace modula2 {
 
@@ -48,6 +47,7 @@  namespace modula2 {
 
 typedef struct pretty_t
 {
+  m2pp_dump_kind output;
   int needs_space;
   int needs_indent;
   int curpos;
@@ -67,7 +67,7 @@  typedef struct m2stack_t
 
 /* Prototypes.  */
 
-static pretty *initPretty (int bits);
+static pretty *initPretty (m2pp_dump_kind kind, int bits);
 static pretty *dupPretty (pretty *s);
 static int getindent (pretty *s);
 static void setindent (pretty *s, int n);
@@ -156,6 +156,8 @@  static void pop (void);
 static int begin_printed (tree t);
 static void m2pp_decl_list (pretty *s, tree t);
 static void m2pp_loc (pretty *s, tree t);
+static FILE *getoutput (pretty *s);
+
 
 void pet (tree t);
 void m2pp_integer (pretty *s, tree t);
@@ -163,13 +165,14 @@  void m2pp_integer (pretty *s, tree t);
 extern void stop (void);
 
 static stack *stackPtr = NULL;
+static FILE *m2pp_output_file[M2PP_DUMP_END];
 
 /* do_pf helper function for pf.  */
 
 void
 do_pf (tree t, int bits)
 {
-  pretty *state = initPretty (bits);
+  pretty *state = initPretty (M2PP_DUMP_STDOUT, bits);
 
   if (TREE_CODE (t) == TRANSLATION_UNIT_DECL)
     m2pp_translation (state, t);
@@ -197,7 +200,7 @@  pf (tree t)
 void
 pe (tree t)
 {
-  pretty *state = initPretty (FALSE);
+  pretty *state = initPretty (M2PP_DUMP_STDOUT, FALSE);
 
   m2pp_expression (state, t);
   m2pp_needspace (state);
@@ -212,7 +215,7 @@  pe (tree t)
 void
 pet (tree t)
 {
-  pretty *state = initPretty (FALSE);
+  pretty *state = initPretty (M2PP_DUMP_STDOUT, FALSE);
 
   m2pp_expression (state, t);
   m2pp_needspace (state);
@@ -228,7 +231,7 @@  pet (tree t)
 void
 pt (tree t)
 {
-  pretty *state = initPretty (FALSE);
+  pretty *state = initPretty (M2PP_DUMP_STDOUT, FALSE);
   m2pp_type (state, t);
   m2pp_needspace (state);
   m2pp_print (state, ";\n");
@@ -241,7 +244,7 @@  pt (tree t)
 void
 ptl (tree t)
 {
-  pretty *state = initPretty (FALSE);
+  pretty *state = initPretty (M2PP_DUMP_STDOUT, FALSE);
   m2pp_type_lowlevel (state, t);
   m2pp_needspace (state);
   m2pp_print (state, ";\n");
@@ -253,7 +256,7 @@  ptl (tree t)
 void
 ptcl (tree t)
 {
-  pretty *state = initPretty (FALSE);
+  pretty *state = initPretty (M2PP_DUMP_STDOUT, FALSE);
 
   m2pp_decl_list (state, t);
   m2pp_print (state, "\n");
@@ -278,7 +281,7 @@  m2pp_loc (pretty *s, tree t)
               m2pp_print (s, "(* ");
               m2pp_print (s, l.file);
               m2pp_print (s, ":");
-              printf ("%d", l.line);
+              fprintf (getoutput (s), "%d", l.line);
               m2pp_print (s, " *)");
               m2pp_print (s, "\n");
             }
@@ -332,7 +335,7 @@  pv (tree t)
 
       if (code == PARM_DECL)
         {
-          pretty *state = initPretty (FALSE);
+          pretty *state = initPretty (M2PP_DUMP_STDOUT, FALSE);
           m2pp_identifier (state, t);
           m2pp_needspace (state);
           m2pp_print (state, "<parm_decl context = ");
@@ -350,7 +353,7 @@  pv (tree t)
         }
       if (code == VAR_DECL)
         {
-          pretty *state = initPretty (FALSE);
+          pretty *state = initPretty (M2PP_DUMP_STDOUT, FALSE);
           m2pp_identifier (state, t);
           m2pp_needspace (state);
           m2pp_print (state, "(* <var_decl context = ");
@@ -429,7 +432,7 @@  begin_printed (tree t)
 static pretty *
 dupPretty (pretty *s)
 {
-  pretty *p = initPretty (s->bits);
+  pretty *p = initPretty (s->output, s->bits);
   *p = *s;
   return p;
 }
@@ -437,9 +440,10 @@  dupPretty (pretty *s)
 /* initPretty initialise the state of the pretty printer.  */
 
 static pretty *
-initPretty (int bits)
+initPretty (m2pp_dump_kind kind, int bits)
 {
   pretty *state = (pretty *)xmalloc (sizeof (pretty));
+  state->output = kind;
   state->needs_space = FALSE;
   state->needs_indent = FALSE;
   state->curpos = 0;
@@ -457,8 +461,8 @@  initPretty (int bits)
 static void
 killPretty (pretty *s)
 {
+  fflush (getoutput (s));
   free (s);
-  fflush (stdout);
 }
 
 /* getindent returns the current indent value.  */
@@ -488,6 +492,12 @@  getcurpos (pretty *s)
     return s->curpos;
 }
 
+static FILE *
+getoutput (pretty *s)
+{
+  return m2pp_output_file[s->output];
+}
+
 /* m2pp_type_lowlevel prints out the low level details of a
    fundamental type.  */
 
@@ -509,9 +519,10 @@  m2pp_type_lowlevel (pretty *s, tree t)
       m2pp_needspace (s);
       m2pp_integer_cst (s, TYPE_SIZE (t));
 
-      printf (", precision %d, mode %d, align %d, user align %d",
-              TYPE_PRECISION (t), TYPE_MODE (t), TYPE_ALIGN (t),
-              TYPE_USER_ALIGN (t));
+      fprintf (getoutput (s),
+	       ", precision %d, mode %d, align %d, user align %d",
+	       TYPE_PRECISION (t), TYPE_MODE (t), TYPE_ALIGN (t),
+	       TYPE_USER_ALIGN (t));
 
       m2pp_needspace (s);
       if (TYPE_UNSIGNED (t))
@@ -581,7 +592,7 @@  hextree (tree t)
     }
   if (VAR_P (t))
     {
-      pretty *state = initPretty (FALSE);
+      pretty *state = initPretty (M2PP_DUMP_STDOUT, FALSE);
 
       printf ("(* VAR_DECL %p <", (void *)t);
       if (DECL_SEEN_IN_BIND_EXPR_P (t))
@@ -598,7 +609,7 @@  hextree (tree t)
     }
   if (TREE_CODE (t) == PARM_DECL)
     {
-      pretty *state = initPretty (FALSE);
+      pretty *state = initPretty (M2PP_DUMP_STDOUT, FALSE);
 
       printf ("(* PARM_DECL %p <", (void *)t);
       printf ("> context = %p*)\n", (void *)decl_function_context (t));
@@ -647,12 +658,12 @@  m2pp_module_block (pretty *s, tree t)
             if (!DECL_EXTERNAL (t))
               {
                 pretty *p = dupPretty (s);
-                printf ("\n");
+                fprintf (getoutput (s), "\n");
                 p->in_vars = FALSE;
                 p->in_types = FALSE;
                 m2pp_function (p, t);
                 killPretty (p);
-                printf ("\n");
+                fprintf (getoutput (s), "\n");
                 s->in_vars = FALSE;
                 s->in_types = FALSE;
               }
@@ -691,7 +702,7 @@  m2pp_module_block (pretty *s, tree t)
             break;
 
           case DECL_EXPR:
-            printf ("is this node legal here? \n");
+            fprintf (getoutput (s), "is this node legal here? \n");
             m2pp_decl_expr (s, t);
             break;
 
@@ -817,18 +828,18 @@  m2pp_var_list (pretty *s, tree t)
         if (TREE_CODE (t) == FUNCTION_DECL)
           {
             pretty *p = dupPretty (s);
-            printf ("\n");
+            fprintf (getoutput (s), "\n");
             p->in_vars = FALSE;
             p->in_types = FALSE;
             m2pp_function (p, t);
             killPretty (p);
-            printf ("\n");
+            fprintf (getoutput (s), "\n");
           }
         else if (TREE_CODE (t) == TYPE_DECL)
           m2pp_identifier (s, t);
         else if (TREE_CODE (t) == DECL_EXPR)
           {
-            printf ("is this node legal here? \n");
+            fprintf (getoutput (s), "is this node legal here? \n");
             // is it legal to have a DECL_EXPR here ?
             m2pp_var_type_decl (s, DECL_EXPR_DECL (t));
           }
@@ -1158,7 +1169,7 @@  m2pp_print (pretty *s, const char *p)
 
       if (s->needs_space)
         {
-          printf (" ");
+          fprintf (getoutput (s), " ");
           s->needs_space = FALSE;
           s->curpos++;
         }
@@ -1169,19 +1180,19 @@  m2pp_print (pretty *s, const char *p)
             {
               s->needs_indent = TRUE;
               s->curpos = 0;
-              printf ("\n");
+              fprintf (getoutput (s), "\n");
             }
           else
             {
               if (s->needs_indent)
                 {
                   if (s->indent > 0)
-                    printf ("%*c", s->indent, ' ');
+                    fprintf (getoutput (s), "%*c", s->indent, ' ');
                   s->needs_indent = FALSE;
                   s->curpos += s->indent;
                 }
               s->curpos++;
-              putchar (p[i]);
+              fputc (p[i], getoutput (s));
             }
           i++;
         }
@@ -1196,25 +1207,25 @@  m2pp_print_char (pretty *s, char ch)
 {
   if (s->needs_space)
     {
-      printf (" ");
+      fprintf (getoutput (s), " ");
       s->needs_space = FALSE;
       s->curpos++;
     }
   if (s->needs_indent)
     {
       if (s->indent > 0)
-        printf ("%*c", s->indent, ' ');
+        fprintf (getoutput (s), "%*c", s->indent, ' ');
       s->needs_indent = FALSE;
       s->curpos += s->indent;
     }
   if (ch == '\n')
     {
       s->curpos++;
-      putchar ('\\');
-      putchar ('n');
+      fputc ('\\', getoutput (s));
+      fputc ('n', getoutput (s));
     }
   else
-    putchar (ch);
+    fputc (ch, getoutput (s));
   s->curpos++;
 }
 
@@ -1531,7 +1542,7 @@  m2pp_recordfield_alignment (pretty *s, tree t)
       m2pp_print (s, "<* bytealignment (");
       setindent (s, p + 18);
 
-      printf ("%d", aligned / BITS_PER_UNIT);
+      fprintf (getoutput (s), "%d", aligned / BITS_PER_UNIT);
 
       m2pp_print (s, ")");
       m2pp_needspace (s);
@@ -2738,3 +2749,63 @@  m2pp_component_ref (pretty *s, tree t)
 }
 
 }
+
+/* Code interface to this module.  */
+
+/* CreateDumpGimple creates the dump files using the template name.  */
+
+void m2pp_CreateDumpGimple (char *template_name, int template_len)
+{
+  int kind = M2PP_DUMP_STDOUT;
+  modula2::m2pp_output_file[kind] = stdout;
+  kind++;
+  for (; kind < M2PP_DUMP_END; kind++)
+    {
+      char *name = (char *)alloca (template_len);
+
+      snprintf (name, template_len, template_name, kind);
+      modula2::m2pp_output_file[kind] = fopen (name, "w");
+      if (modula2::m2pp_output_file[kind] == NULL)
+	{
+	  fprintf (stderr, "unable to create dump file %s: %s\n",
+		   name, xstrerror (errno));
+	  exit (1);
+	}
+      fprintf (modula2::m2pp_output_file[kind], "%s\n\n",
+	       m2pp_dump_description[kind]);
+    }
+}
+
+/* Close all dump files and fflush stdout.  */
+
+void m2pp_CloseDumpGimple (void)
+{
+  int kind = M2PP_DUMP_STDOUT;
+  fflush (modula2::m2pp_output_file[kind]);
+  kind++;
+  for (; kind < M2PP_DUMP_END; kind++)
+    fclose (modula2::m2pp_output_file[kind]);
+}
+
+
+/* Generate modula-2 style gimple for fndecl.  */
+
+void m2pp_dump_gimple (m2pp_dump_kind kind, tree fndecl)
+{
+  if (M2Options_GetDumpLangGimple ()
+      && M2LangDump_IsDumpRequiredTree (fndecl))
+    {
+      modula2::pretty *state = modula2::initPretty (kind, FALSE);
+
+      modula2::m2pp_print (state, "\n");
+      if (TREE_CODE (fndecl) == TRANSLATION_UNIT_DECL)
+	modula2::m2pp_translation (state, fndecl);
+      else if (TREE_CODE (fndecl) == BLOCK)
+	modula2::m2pp_module_block (state, fndecl);
+      else if (TREE_CODE (fndecl) == FUNCTION_DECL)
+	modula2::m2pp_function (state, fndecl);
+      else
+	modula2::m2pp_statement_sequence (state, fndecl);
+      modula2::killPretty (state);
+    }
+}
diff --git a/gcc/m2/gm2-gcc/m2pp.def b/gcc/m2/gm2-gcc/m2pp.def
new file mode 100644
index 00000000000..030c1aa07bd
--- /dev/null
+++ b/gcc/m2/gm2-gcc/m2pp.def
@@ -0,0 +1,41 @@ 
+(* m2pp.def definition module for m2pp.cc.
+
+Copyright (C) 2024 Free Software Foundation, Inc.
+Contributed by Gaius Mulley <gaiusmod2@gmail.com>.
+
+This file is part of GNU Modula-2.
+
+GNU Modula-2 is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GNU Modula-2 is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Modula-2; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  *)
+
+DEFINITION MODULE FOR "C" m2pp ;
+
+FROM SYSTEM IMPORT ADDRESS ;
+
+
+(*
+   CreateDumpGimple - create the gimple dump files.
+*)
+
+PROCEDURE CreateDumpGimple (templatename: ADDRESS; templatelen: CARDINAL) ;
+
+
+(*
+   CloseDumpGimple - close the gimple dump files.
+*)
+
+PROCEDURE CloseDumpGimple ;
+
+
+END m2pp.
diff --git a/gcc/m2/m2pp.h b/gcc/m2/gm2-gcc/m2pp.h
similarity index 57%
rename from gcc/m2/m2pp.h
rename to gcc/m2/gm2-gcc/m2pp.h
index e901102fab7..d1c526c2b98 100644
--- a/gcc/m2/m2pp.h
+++ b/gcc/m2/gm2-gcc/m2pp.h
@@ -19,17 +19,37 @@  You should have received a copy of the GNU General Public License
 along with GNU Modula-2; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
-#if !defined(M2PP_H)
-#   define M2PP_H
-
-#   if defined(M2PP_C)
-#      define EXTERN
-#   else
-#      define EXTERN extern
-#   endif
+#if !defined(m2pp_h)
+#define m2pp_h
+#if defined(m2pp_c)
+#if defined(__GNUG__)
+#define EXTERN extern "C"
+#else /* !__GNUG__.  */
+#define EXTERN
+#endif /* !__GNUG__.  */
+#else /* !m2pp_c.  */
+#if defined(__GNUG__)
+#define EXTERN extern "C"
+#else /* !__GNUG__.  */
+#define EXTERN extern
+#endif /* !__GNUG__.  */
+#endif /* !m2pp_c.  */
+
+typedef enum
+{
+  M2PP_DUMP_STDOUT,  /* This must remain the first field.  */
+  M2PP_DUMP_PRE_GENERICIZE,
+  M2PP_DUMP_POST_GENERICIZE,
+  M2PP_DUMP_END,
+} m2pp_dump_kind;
+
+EXTERN void m2pp_CreateDumpGimple (char *template_name, int template_len);
+EXTERN void m2pp_dump_gimple (m2pp_dump_kind kind, tree fndecl);
+EXTERN void m2pp_CloseDumpGimple (void);
 
 namespace modula2 {
-/* These functions allow a maintainer to dump the trees in Modula-2.  */
+/* GDB Interactive interface to m2pp.  Allow a maintainer to dump
+   the trees in Modula-2.  */
 
 EXTERN void pf (tree t);
 EXTERN void pe (tree t);
diff --git a/gcc/m2/gm2-gcc/m2statement.cc b/gcc/m2/gm2-gcc/m2statement.cc
index 3c048d40a99..dd7f2529f5d 100644
--- a/gcc/m2/gm2-gcc/m2statement.cc
+++ b/gcc/m2/gm2-gcc/m2statement.cc
@@ -36,6 +36,7 @@  along with GNU Modula-2; see the file COPYING3.  If not see
 #include "m2treelib.h"
 #include "m2type.h"
 #include "m2convert.h"
+#include "m2pp.h"
 
 static GTY (()) tree param_list = NULL_TREE; /* Ready for the next time we
                                                 call/define a function.  */
@@ -102,11 +103,15 @@  m2statement_BuildEndFunctionCode (location_t location, tree fndecl, bool nested)
   m2block_finishFunctionCode (fndecl);
   m2statement_SetEndLocation (location);
 
+  m2pp_dump_gimple (M2PP_DUMP_PRE_GENERICIZE, fndecl);
   gm2_genericize (fndecl);
   if (nested)
     (void)cgraph_node::get_create (fndecl);
   else
-    cgraph_node::finalize_function (fndecl, false);
+    {
+      m2pp_dump_gimple (M2PP_DUMP_POST_GENERICIZE, fndecl);
+      cgraph_node::finalize_function (fndecl, false);
+    }
 
   m2block_popFunctionScope ();
 
diff --git a/gcc/m2/gm2-lang.cc b/gcc/m2/gm2-lang.cc
index 86124df603a..603f3ab2ffd 100644
--- a/gcc/m2/gm2-lang.cc
+++ b/gcc/m2/gm2-lang.cc
@@ -214,8 +214,7 @@  gm2_langhook_init_options (unsigned int decoded_options_count,
 	  M2Options_Setc (value);
 	  break;
 	case OPT_dumpdir:
-	  if (building_cpp_command)
-	    M2Options_SetDumpDir (arg);
+	  M2Options_SetDumpDir (arg);
 	  break;
 	case OPT_save_temps:
 	  if (building_cpp_command)
@@ -407,6 +406,9 @@  gm2_langhook_handle_option (
 
   switch (code)
     {
+    case OPT_dumpdir:
+      M2Options_SetDumpDir (arg);
+      return 1;
     case OPT_I:
       push_back_Ipath (arg);
       return 1;
@@ -479,6 +481,22 @@  gm2_langhook_handle_option (
     case OPT_fdebug_function_line_numbers:
       M2Options_SetDebugFunctionLineNumbers (value);
       return 1;
+    case OPT_fdump_lang_all:
+      M2Options_SetDumpLangQuadFilename (value, NULL);
+      M2Options_SetDumpLangGimpleFilename (value, NULL);
+      return 1;
+    case OPT_fdump_lang_gimple:
+      M2Options_SetDumpLangGimpleFilename (value, NULL);
+      return 1;
+    case OPT_fdump_lang_gimple_:
+      M2Options_SetDumpLangGimpleFilename (value, arg);
+      return 1;
+    case OPT_fdump_lang_quad:
+      M2Options_SetDumpLangQuadFilename (value, NULL);
+      return 1;
+    case OPT_fdump_lang_quad_:
+      M2Options_SetDumpLangQuadFilename (value, arg);
+      return 1;
     case OPT_fauto_init:
       M2Options_SetAutoInit (value);
       return 1;
@@ -519,6 +537,9 @@  gm2_langhook_handle_option (
     case OPT_fm2_strict_type:
       M2Options_SetStrictTypeChecking (value);
       return 1;
+    case OPT_fm2_dump_filter_:
+      M2Options_SetM2DumpFilter (value, arg);
+      return 1;
     case OPT_Wall:
       M2Options_SetWall (value);
       return 1;
diff --git a/gcc/m2/gm2-libs/DynamicStrings.def b/gcc/m2/gm2-libs/DynamicStrings.def
index 29f4989b794..25c27e8a939 100644
--- a/gcc/m2/gm2-libs/DynamicStrings.def
+++ b/gcc/m2/gm2-libs/DynamicStrings.def
@@ -29,7 +29,7 @@  DEFINITION MODULE DynamicStrings ;
 FROM SYSTEM IMPORT ADDRESS ;
 EXPORT QUALIFIED String,
                  InitString, KillString, Fin, InitStringCharStar,
-                 InitStringChar, Index, RIndex,
+                 InitStringChar, Index, RIndex, ReverseIndex,
                  Mark, Length, ConCat, ConCatChar, Assign, Dup, Add,
                  Equal, EqualCharStar, EqualArray, ToUpper, ToLower,
                  CopyOut, Mult, Slice, ReplaceChar,
@@ -201,13 +201,27 @@  PROCEDURE Index (s: String; ch: CHAR; o: CARDINAL) : INTEGER ;
 
 (*
    RIndex - returns the indice of the last occurance of, ch,
-            in String, s. The search starts at position, o.
-            -1 is returned if, ch, is not found.
+            in String, s.  The search starts at position, o.
+            -1 is returned if ch is not found.  The search
+            is performed left to right.
 *)
 
 PROCEDURE RIndex (s: String; ch: CHAR; o: CARDINAL) : INTEGER ;
 
 
+(*
+   ReverseIndex - returns the indice of the last occurance of ch
+                  in String s.  The search starts at position o
+                  and searches from right to left.  The start position
+                  may be indexed negatively from the right (-1 is the
+                  last index).
+                  The return value if ch is found will always be positive.
+                  -1 is returned if ch is not found.
+*)
+
+PROCEDURE ReverseIndex (s: String; ch: CHAR; o: INTEGER) : INTEGER ;
+
+
 (*
    RemoveComment - assuming that, comment, is a comment delimiter
                    which indicates anything to its right is a comment
diff --git a/gcc/m2/gm2-libs/DynamicStrings.mod b/gcc/m2/gm2-libs/DynamicStrings.mod
index c79e21c12be..b53f0f285b5 100644
--- a/gcc/m2/gm2-libs/DynamicStrings.mod
+++ b/gcc/m2/gm2-libs/DynamicStrings.mod
@@ -1466,8 +1466,9 @@  END Index ;
 
 (*
    RIndex - returns the indice of the last occurance of, ch,
-            in String, s. The search starts at position, o.
-            -1 is returned if, ch, is not found.
+            in String, s.  The search starts at position, o.
+            -1 is returned if, ch, is not found.  The search
+            is performed left to right.
 *)
 
 PROCEDURE RIndex (s: String; ch: CHAR; o: CARDINAL) : INTEGER ;
@@ -1509,6 +1510,47 @@  BEGIN
 END RIndex ;
 
 
+(*
+   ReverseIndex - returns the indice of the last occurance of ch
+                  in String s.  The search starts at position o
+                  and searches from right to left.  The start position
+                  may be indexed negatively from the right (-1 is the
+                  last index).
+                  The return value if ch is found will always be positive.
+                  -1 is returned if ch is not found.
+*)
+
+PROCEDURE ReverseIndex (s: String; ch: CHAR; o: INTEGER) : INTEGER ;
+VAR
+   c: CARDINAL ;
+BEGIN
+   IF PoisonOn
+   THEN
+      s := CheckPoisoned (s)
+   END ;
+   IF o < 0
+   THEN
+      o := VAL (INTEGER, Length (s)) + o ;
+      IF o < 0
+      THEN
+         RETURN -1
+      END
+   END ;
+   IF VAL (CARDINAL, o) < Length (s)
+   THEN
+      WHILE o >= 0 DO
+         IF char (s, o) = ch
+         THEN
+            RETURN o
+         ELSE
+            DEC (o)
+         END
+      END
+   END ;
+   RETURN -1
+END ReverseIndex ;
+
+
 (*
    RemoveComment - assuming that, comment, is a comment delimiter
                    which indicates anything to its right is a comment
diff --git a/gcc/m2/lang.opt b/gcc/m2/lang.opt
index 505f4b56e8a..7ae413e70bc 100644
--- a/gcc/m2/lang.opt
+++ b/gcc/m2/lang.opt
@@ -106,6 +106,26 @@  fdef=
 Modula-2 Joined
 recognise the specified suffix as a definition module filename
 
+fdump-lang-all
+Modula-2
+dump all Modula-2 internal intemediate representation
+
+fdump-lang-gimple
+Modula-2
+dump gimple in Modula-2
+
+fdump-lang-gimple=
+Modula-2 Joined
+dump gimple in Modula-2 to the filename stem specified
+
+fdump-lang-quad
+Modula-2
+dump quadruple representation
+
+fdump-lang-quad=
+Modula-2 Joined
+dump quadruple representation to the filename stem specified
+
 fdump-system-exports
 Modula-2
 display all inbuilt system items
@@ -138,6 +158,10 @@  flocation=
 Modula-2 Joined
 set all location values to a specific value (internal switch)
 
+fm2-dump-filter=
+Modula-2 Joined
+filter the language dump using a comma separated list of procedures and modules
+
 fm2-g
 Modula-2
 generate extra nops to improve debugging, producing an instruction for every code related keyword