(* M2BasicBlock.mod converts a scope block into a list of basic blocks. 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 M2BasicBlock ; FROM Storage IMPORT ALLOCATE, DEALLOCATE ; FROM StrIO IMPORT WriteString, WriteLn ; FROM NumberIO IMPORT WriteCard ; FROM M2Debug IMPORT Assert ; FROM M2Options IMPORT OptimizeBasicBlock ; FROM M2Quads IMPORT IsReferenced, IsConditional, IsUnConditional, IsCall, IsReturn, IsNewLocalVar, IsKillLocalVar, IsCatchBegin, IsCatchEnd, IsInitStart, IsInitEnd, IsFinallyStart, IsFinallyEnd, IsInitialisingConst, IsConditionalBooleanQuad, IsPseudoQuad, IsDefOrModFile, GetNextQuad, GetQuad, QuadOperator, SubQuad, DisplayQuadRange ; FROM M2Scope IMPORT ScopeBlock, ForeachScopeBlockDo3 ; CONST Debugging = FALSE ; TYPE BasicBlock = POINTER TO RECORD Scope : CARDINAL ; (* Scope associated with the block. *) StartQuad : CARDINAL ; (* First Quad in Basic Block. *) EndQuad : CARDINAL ; (* End Quad in Basic Block. *) First : BOOLEAN ; (* The first block? *) Right : BasicBlock ; Left : BasicBlock ; END ; VAR FreeList : BasicBlock ; (* Free list of Basic Blocks *) HeadOfBasicBlock: BasicBlock ; PROCEDURE stop ; END stop ; (* InitBasicBlocks - converts a list of quadruples as defined by scope blocks into a set of basic blocks. All quadruples within this list which are not reachable are removed. *) PROCEDURE InitBasicBlocks (sb: ScopeBlock) : BasicBlock ; BEGIN HeadOfBasicBlock := NIL ; ForeachScopeBlockDo3 (sb, ConvertQuads2BasicBlock) ; RETURN HeadOfBasicBlock END InitBasicBlocks ; (* InitBasicBlocksFromRange - converts a list of quadruples as defined by start..end. All quadruples within this list which are not reachable are removed. *) PROCEDURE InitBasicBlocksFromRange (ScopeSym: CARDINAL; start, end: CARDINAL) : BasicBlock ; BEGIN HeadOfBasicBlock := NIL ; ConvertQuads2BasicBlock (ScopeSym, start, end) ; IF Debugging THEN DisplayBasicBlocks (HeadOfBasicBlock) END ; RETURN( HeadOfBasicBlock ) END InitBasicBlocksFromRange ; (* KillBasicBlocks - destroys the list of Basic Blocks. *) PROCEDURE KillBasicBlocks (VAR bb: BasicBlock) ; BEGIN FreeBasicBlocks (bb) ; bb := NIL END KillBasicBlocks ; (* FreeBasicBlocks - destroys the list of Basic Blocks. *) PROCEDURE FreeBasicBlocks (bb: BasicBlock) ; VAR b, c: BasicBlock ; BEGIN IF bb#NIL THEN b := bb ; REPEAT c := bb^.Right ; bb^.Right := FreeList ; FreeList := bb ; bb := c UNTIL bb=b END END FreeBasicBlocks ; (* New - returns a basic block. *) PROCEDURE New (Scope: CARDINAL; First: BOOLEAN) : BasicBlock ; VAR b: BasicBlock ; BEGIN IF FreeList=NIL THEN NEW (b) ELSE b := FreeList ; FreeList := FreeList^.Right END ; Assert (b#NIL) ; b^.Scope := Scope ; b^.First := First ; RETURN b END New ; (* ConvertQuads2BasicBlock - converts a list of quadruples to a list of Basic Blocks. A Basic Block is defined as a list of quadruples which has only has one entry and exit point. *) PROCEDURE ConvertQuads2BasicBlock (ScopeSym: CARDINAL; Start, End: CARDINAL) ; VAR First, LastQuadDefMod, LastQuadConditional, LastQuadCall, LastQuadReturn : BOOLEAN ; Quad : CARDINAL ; CurrentBB : BasicBlock ; LastBB : BasicBlock ; BEGIN IF Debugging THEN WriteString ("Enter ConvertQuads2BasicBlock") ; WriteLn ; DisplayQuadRange (ScopeSym, Start, End) END ; (* Algorithm to perform Basic Block: For every quadruple establish a set of leaders. A leader is defined as a quadruple which is either: (i) The first quadruple. (ii) Any quadruple which is the target of a jump or unconditional jump. (iii) Any statement which follows a conditional jump For each leader construct a basic block. A Basic Block starts with a leader quadruple and ends with either: (i) Another leader (ii) An unconditional Jump. Any quadruples that do not fall into a Basic Block can be thrown away since they will never be executed. *) LastBB := NIL ; CurrentBB := NIL ; Quad := Start ; LastQuadConditional := TRUE ; (* Force Rule (i). *) LastQuadCall := FALSE ; LastQuadReturn := FALSE ; LastQuadDefMod := FALSE ; First := TRUE ; (* Scan all quadruples. *) WHILE (Quad<=End) AND (Quad#0) DO IF Quad = 200 THEN stop END ; IF LastQuadConditional OR LastQuadCall OR LastQuadReturn OR LastQuadDefMod OR IsReferenced(Quad) THEN (* Rule (ii) *) CurrentBB := New (ScopeSym, First) ; (* Get a new Basic Block. *) (* At least one quad in this Basic Block. *) StartBB(CurrentBB, Quad) ; EndBB(CurrentBB, Quad) ; First := FALSE ELSIF CurrentBB#NIL THEN (* We have a Basic Block - therefore add quad to this Block *) EndBB(CurrentBB, Quad) ELSIF IsPseudoQuad(Quad) THEN (* Add Quad to the Last BB since Pseudo Quads - compiler directives *) (* must not be thrown away. *) EndBB(LastBB, Quad) ELSIF IsReturn(Quad) OR IsKillLocalVar(Quad) OR IsCatchEnd(Quad) OR IsCatchBegin(Quad) OR IsInitStart(Quad) OR IsInitEnd(Quad) OR IsFinallyStart(Quad) OR IsFinallyEnd(Quad) THEN (* We must leave these quads alone. *) EndBB(LastBB, Quad) ELSIF IsConditionalBooleanQuad (Quad) THEN (* We can remove unreachable const quads. *) SubQuad (Quad) (* ELSIF IsInitialisingConst(Quad) THEN (* But we leave remaining constant quads alone. *) EndBB(LastBB, Quad) *) ELSE (* Remove this Quad since it will never be reached. *) SubQuad(Quad) END ; LastQuadConditional := IsConditional(Quad) ; LastQuadCall := IsCall(Quad) ; LastQuadReturn := IsReturn(Quad) ; LastQuadDefMod := IsDefOrModFile(Quad) ; IF IsUnConditional(Quad) THEN LastBB := CurrentBB ; CurrentBB := NIL END ; Quad := GetNextQuad(Quad) END ; IF Debugging THEN WriteString ("Exit ConvertQuads2BasicBlock") ; WriteLn ; DisplayQuadRange (ScopeSym, Start, End) END END ConvertQuads2BasicBlock ; (* ForeachBasicBlockDo - for each basic block call procedure p. *) PROCEDURE ForeachBasicBlockDo (bb: BasicBlock; p: BasicBlockProc) ; VAR b: BasicBlock ; BEGIN IF bb#NIL THEN b := bb ; REPEAT WITH b^ DO p (b) END ; b := b^.Right UNTIL b=bb END END ForeachBasicBlockDo ; (* StartBB - Initially fills a Basic Block, b, with a start quad Quad. The Basic Block is then added to the end of Basic Block list. *) PROCEDURE StartBB (b: BasicBlock; Quad: CARDINAL) ; BEGIN WITH b^ DO StartQuad := Quad ; EndQuad := Quad END ; Add(HeadOfBasicBlock, b) (* Add b to the end of the Basic Block list *) END StartBB ; (* EndBB - Fills a Basic Block, b, with an end quad Quad. *) PROCEDURE EndBB (b: BasicBlock; Quad: CARDINAL) ; BEGIN b^.EndQuad := Quad END EndBB ; (* Add adds a specified element to the end of a queue. *) PROCEDURE Add (VAR Head: BasicBlock; b : BasicBlock) ; BEGIN IF Head=NIL THEN Head := b ; b^.Left := b ; b^.Right := b ELSE b^.Right := Head ; b^.Left := Head^.Left ; Head^.Left^.Right := b ; Head^.Left := b END END Add ; (* DisplayBasicBlocks - displays the basic block data structure. *) PROCEDURE DisplayBasicBlocks (bb: BasicBlock) ; VAR b: BasicBlock ; BEGIN b := bb ; WriteString('quadruples') ; WriteLn ; IF b#NIL THEN REPEAT DisplayBlock(b) ; b := b^.Right UNTIL b=bb END END DisplayBasicBlocks ; PROCEDURE DisplayBlock (b: BasicBlock) ; BEGIN WITH b^ DO WriteString(' start ') ; WriteCard(StartQuad, 6) ; WriteString(' end ') ; WriteCard(EndQuad, 6) ; END END DisplayBlock ; (* GetBasicBlockScope - return the scope associated with the basic block. *) PROCEDURE GetBasicBlockScope (bb: BasicBlock) : CARDINAL ; BEGIN RETURN bb^.Scope END GetBasicBlockScope ; (* GetBasicBlockStart - return the quad associated with the start of the basic block. *) PROCEDURE GetBasicBlockStart (bb: BasicBlock) : CARDINAL ; BEGIN RETURN bb^.StartQuad END GetBasicBlockStart ; (* GetBasicBlockEnd - return the quad associated with the end of the basic block. *) PROCEDURE GetBasicBlockEnd (bb: BasicBlock) : CARDINAL ; BEGIN RETURN bb^.EndQuad END GetBasicBlockEnd ; (* IsBasicBlockFirst - return TRUE if this basic block is the first in the sequence. *) PROCEDURE IsBasicBlockFirst (bb: BasicBlock) : BOOLEAN ; BEGIN RETURN bb^.First END IsBasicBlockFirst ; BEGIN FreeList := NIL END M2BasicBlock.