(* M2Code.mod coordinate the activity of the front end. Copyright (C) 2001-2025 Free Software Foundation, Inc. Contributed by Gaius Mulley . 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 . *) IMPLEMENTATION MODULE M2Code ; FROM SYSTEM IMPORT WORD ; FROM M2Options IMPORT Statistics, OptimizeUncalledProcedures, OptimizeCommonSubExpressions, StyleChecking, Optimizing, WholeProgram, GetDumpDecl, GetDumpGimple ; FROM M2LangDump IMPORT CreateDumpDecl, CloseDumpDecl, MakeGimpleTemplate ; FROM M2Error IMPORT InternalError ; FROM M2Students IMPORT StudentVariableCheck ; FROM SymbolTable IMPORT GetMainModule, IsProcedure, IsModuleWithinProcedure, CheckHiddenTypeAreAddress, IsModule, IsDefImp, DebugLineNumbers, ForeachProcedureDo, ForeachInnerModuleDo, GetSymName ; FROM M2Printf IMPORT printf2, printf1, printf0 ; FROM NameKey IMPORT Name ; FROM M2Batch IMPORT ForeachSourceModuleDo ; FROM M2Quads IMPORT CountQuads, GetFirstQuad, DumpQuadruples, DisplayQuadRange, BackPatchSubrangesAndOptParam, LoopAnalysis, ForLoopAnalysis, GetQuad, QuadOperator ; FROM M2SymInit IMPORT ScopeBlockVariableAnalysis ; FROM M2Pass IMPORT SetPassToNoPass, SetPassToCodeGeneration ; FROM M2BasicBlock IMPORT BasicBlock, InitBasicBlocks, InitBasicBlocksFromRange, KillBasicBlocks, FreeBasicBlocks, ForeachBasicBlockDo ; FROM M2Optimize IMPORT FoldBranches, RemoveProcedures ; FROM M2GenGCC IMPORT ConvertQuadsToTree ; FROM M2GCCDeclare IMPORT FoldConstants, StartDeclareScope, DeclareProcedure, InitDeclarations, DeclareModuleVariables, MarkExported, DumpFilteredResolver, DumpFilteredDefinitive ; FROM M2Scope IMPORT ScopeBlock, InitScopeBlock, KillScopeBlock, ForeachScopeBlockDo2, ForeachScopeBlockDo3 ; FROM m2top IMPORT StartGlobalContext, EndGlobalContext, SetFlagUnitAtATime ; FROM M2Error IMPORT FlushErrors, FlushWarnings ; FROM M2Swig IMPORT GenerateSwigFile ; 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 ; TraceQuadruples = FALSE ; VAR Total, Count, OptimTimes, DeltaProc, Proc, DeltaConst, Const, DeltaJump, Jump, DeltaBasicB, BasicB : CARDINAL ; (* Percent - calculates the percentage from numerator and divisor *) PROCEDURE Percent (numerator, divisor: CARDINAL) ; VAR value: CARDINAL ; BEGIN printf0 (' (') ; IF divisor=0 THEN printf0 ('overflow error') ELSE value := numerator*100 DIV divisor ; printf1 ('%3d', value) END ; printf0 ('\%)') END Percent ; (* OptimizationAnalysis - displays some simple front end optimization statistics. *) PROCEDURE OptimizationAnalysis ; VAR value: CARDINAL ; BEGIN IF Statistics THEN Count := CountQuads() ; printf1 ('M2 initial number of quadruples: %6d', Total) ; Percent (Total, Total) ; printf0 ('\n'); printf1 ('M2 constant folding achieved : %6d', Const) ; Percent (Const, Total) ; printf0 ('\n'); printf1 ('M2 branch folding achieved : %6d', Jump) ; Percent (Jump, Total) ; printf0 ('\n'); value := Const+Jump+Proc ; printf1 ('Front end optimization removed : %6d', value) ; Percent (value, Total) ; printf0 ('\n') ; printf1 ('Front end final : %6d', Count) ; Percent (Count, Total) ; printf0 ('\n') ; Count := GetTotalLines () ; printf1 ('Total source lines compiled : %6d\n', Count) ; FlushBuffer (StdOut) END ; DumpQuadruples ('after all front end optimization\n') END OptimizationAnalysis ; (* RemoveUnreachableCode - *) PROCEDURE RemoveUnreachableCode ; BEGIN IF WholeProgram THEN ForeachSourceModuleDo(RemoveProcedures) ELSE RemoveProcedures(GetMainModule()) END END RemoveUnreachableCode ; (* DoModuleDeclare - declare all constants, types, variables, procedures for the main module or all modules. *) PROCEDURE DoModuleDeclare ; BEGIN IF GetDumpDecl () THEN CreateDumpDecl ("symbol resolver of filtered symbols\n") ; DumpFilteredResolver END ; IF WholeProgram THEN ForeachSourceModuleDo (StartDeclareScope) ELSE StartDeclareScope (GetMainModule ()) END ; IF GetDumpDecl () THEN CloseDumpDecl ; CreateDumpDecl ("definitive declaration of filtered symbols\n") ; DumpFilteredDefinitive ; CloseDumpDecl END END DoModuleDeclare ; (* PrintModule - *) (* PROCEDURE PrintModule (sym: CARDINAL) ; VAR n: Name ; BEGIN n := GetSymName (sym) ; printf1 ('module %a\n', n) END PrintModule ; *) (* DoCodeBlock - generate code for the main module or all modules. *) PROCEDURE DoCodeBlock ; VAR filename: String ; len : CARDINAL ; BEGIN IF GetDumpGimple () THEN filename := MakeGimpleTemplate (len) ; CreateDumpGimple (filename, len) ; filename := KillString (filename) ; CodeBlock (GetMainModule ()) ; CloseDumpGimple ELSE CodeBlock (GetMainModule ()) END END DoCodeBlock ; (* DetermineSubExpTemporaries - *) PROCEDURE DetermineSubExpTemporaries ; BEGIN IF WholeProgram THEN ForeachSourceModuleDo (DiscoverSSA) ELSE DiscoverSSA (GetMainModule ()) END END DetermineSubExpTemporaries ; (* Code - calls procedures to generates trees from the quadruples. All front end quadruple optimization is performed via this call. *) PROCEDURE Code ; BEGIN DumpQuadruples ('before any optimization\n') ; CheckHiddenTypeAreAddress ; SetPassToNoPass ; BackPatchSubrangesAndOptParam ; Total := CountQuads () ; ForLoopAnalysis ; (* must be done before any optimization as the index variable increment quad might change *) DumpQuadruples ('before declaring symbols to gcc\n') ; (* now is a suitable time to check for student errors as *) (* we know all the front end symbols must be resolved. *) IF StyleChecking THEN StudentVariableCheck END ; SetPassToCodeGeneration ; SetFlagUnitAtATime (Optimizing) ; StartGlobalContext ; InitDeclarations ; (* default and fixed sized types are all declared from now on. *) RemoveUnreachableCode ; DumpQuadruples ('after dead procedure elimination\n') ; DetermineSubExpTemporaries ; DumpQuadruples ('after identifying simple subexpression temporaries\n') ; qprintf0 (' symbols to gcc trees\n') ; DoModuleDeclare ; FlushWarnings ; FlushErrors ; qprintf0 (' statements to gcc trees\n') ; DoCodeBlock ; MarkExported (GetMainModule ()) ; GenerateSwigFile (GetMainModule ()) ; DebugLineNumbers (GetMainModule ()) ; qprintf0 (' gcc trees given to the gcc backend\n') ; EndGlobalContext ; OptimizationAnalysis END Code ; (* InitialDeclareAndCodeBlock - declares all objects within scope, *) PROCEDURE InitialDeclareAndOptimize (scope: CARDINAL; start, end: CARDINAL) ; BEGIN Count := CountQuads () ; FreeBasicBlocks (InitBasicBlocksFromRange (scope, start, end)) ; BasicB := Count - CountQuads () ; Count := CountQuads () ; FoldBranches (start, end) ; Jump := Count - CountQuads () ; Count := CountQuads () END InitialDeclareAndOptimize ; (* DeclareAndCodeBlock - declares all objects within scope, *) PROCEDURE SecondDeclareAndOptimize (scope: CARDINAL; start, end: CARDINAL) ; VAR bb: BasicBlock ; BEGIN REPEAT bb := InitBasicBlocksFromRange (scope, start, end) ; ForeachBasicBlockDo (bb, FoldConstants) ; FreeBasicBlocks (bb) ; DeltaConst := Count - CountQuads () ; Count := CountQuads () ; FreeBasicBlocks(InitBasicBlocksFromRange (scope, start, end)) ; DeltaBasicB := Count - CountQuads () ; Count := CountQuads () ; FreeBasicBlocks (InitBasicBlocksFromRange (scope, start, end)) ; FoldBranches(start, end) ; DeltaJump := Count - CountQuads () ; Count := CountQuads () ; FreeBasicBlocks(InitBasicBlocksFromRange (scope, start, end)) ; INC (DeltaBasicB, Count - CountQuads ()) ; Count := CountQuads () ; (* now total the optimization components *) INC (Proc, DeltaProc) ; INC (Const, DeltaConst) ; INC (Jump, DeltaJump) ; INC (BasicB, DeltaBasicB) UNTIL (OptimTimes>=MaxOptimTimes) OR ((DeltaProc=0) AND (DeltaConst=0) AND (DeltaJump=0) AND (DeltaBasicB=0)) ; IF (DeltaProc#0) OR (DeltaConst#0) OR (DeltaJump#0) OR (DeltaBasicB#0) THEN printf0 ('optimization finished although more reduction may be possible (increase MaxOptimTimes)\n') END END SecondDeclareAndOptimize ; (* InitOptimizeVariables - *) PROCEDURE InitOptimizeVariables ; BEGIN Count := CountQuads () ; OptimTimes := 0 ; DeltaProc := 0 ; DeltaConst := 0 ; DeltaJump := 0 ; DeltaBasicB := 0 END InitOptimizeVariables ; (* Init - *) PROCEDURE Init ; BEGIN Proc := 0 ; Const := 0 ; Jump := 0 ; BasicB := 0 END Init ; (* OptimizeScopeBlock - *) PROCEDURE OptimizeScopeBlock (sb: ScopeBlock) ; VAR OptimTimes, Previous, Current : CARDINAL ; BEGIN InitOptimizeVariables ; OptimTimes := 1 ; Current := CountQuads () ; ForeachScopeBlockDo3 (sb, InitialDeclareAndOptimize) ; ForeachScopeBlockDo3 (sb, ScopeBlockVariableAnalysis) ; REPEAT ForeachScopeBlockDo3 (sb, SecondDeclareAndOptimize) ; Previous := Current ; Current := CountQuads () ; INC (OptimTimes) UNTIL (OptimTimes=MaxOptimTimes) OR (Current=Previous) ; ForeachScopeBlockDo3 (sb, LoopAnalysis) END OptimizeScopeBlock ; (* CodeProceduresWithinBlock - codes the procedures within the module scope. *) PROCEDURE CodeProceduresWithinBlock (scope: CARDINAL) ; BEGIN ForeachProcedureDo (scope, CodeBlock) END CodeProceduresWithinBlock ; (* CodeProcedures - *) PROCEDURE CodeProcedures (scope: CARDINAL) ; BEGIN IF IsDefImp (scope) OR IsModule (scope) THEN ForeachProcedureDo (scope, CodeBlock) END END CodeProcedures ; (* CodeBlock - generates all code for this block and also declares all types and procedures for this block. It will also optimize quadruples within this scope. *) PROCEDURE CodeBlock (scope: WORD) ; VAR sb: ScopeBlock ; n : Name ; BEGIN IF TraceQuadruples THEN n := GetSymName (scope) ; printf1 ('before coding block %a\n', n) END ; sb := InitScopeBlock (scope) ; OptimizeScopeBlock (sb) ; IF IsProcedure (scope) THEN IF TraceQuadruples THEN n := GetSymName(scope) ; printf1('before coding procedure %a\n', n) ; ForeachScopeBlockDo3 (sb, DisplayQuadRange) ; printf0('===============\n') END ; ForeachScopeBlockDo2 (sb, ConvertQuadsToTree) ELSIF IsModuleWithinProcedure(scope) THEN IF TraceQuadruples THEN n := GetSymName(scope) ; printf1('before coding module %a within procedure\n', n) ; ForeachScopeBlockDo3 (sb, DisplayQuadRange) ; printf0('===============\n') END ; ForeachScopeBlockDo2 (sb, ConvertQuadsToTree) ; ForeachProcedureDo(scope, CodeBlock) ELSE IF TraceQuadruples THEN n := GetSymName(scope) ; printf1('before coding module %a\n', n) ; ForeachScopeBlockDo3 (sb, DisplayQuadRange) ; printf0('===============\n') END ; ForeachScopeBlockDo2 (sb, ConvertQuadsToTree) ; IF WholeProgram THEN ForeachSourceModuleDo(CodeProcedures) ELSE ForeachProcedureDo(scope, CodeBlock) END ; ForeachInnerModuleDo(scope, CodeProceduresWithinBlock) END ; KillScopeBlock(sb) END CodeBlock ; BEGIN Init END M2Code.