blob: 72cdae45cf675c0b13b3d98481408562efd1f0d4 [file] [log] [blame]
(* M2BasicBlock.mod converts a scope block into a list of basic blocks.
Copyright (C) 2001-2025 Free Software Foundation, Inc.
Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
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 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.