mirror of
https://github.com/byteworksinc/ORCA-C.git
synced 2025-01-02 19:29:21 +00:00
Fix problems with loop invariant removal optimization.
These mainly related to situations where the optimization of multiple natural loops (including those created by continue statements) could interact to generate invalid results. Invalid optimizations could also be performed in certain other cases where there were multiple goto statements targeting a single label and at least one of them formed a loop. These issues are addressed by appropriately adjusting the control flow and updating various data structures after each loop is processed during loop invariant removal. This fixes #18 (compca18.c).
This commit is contained in:
parent
89f4257742
commit
4e7a7e67e7
235
DAG.pas
235
DAG.pas
@ -3224,18 +3224,7 @@ var
|
||||
end; {DepthFirstOrder}
|
||||
|
||||
|
||||
procedure Dominators;
|
||||
|
||||
{ Find a list of dominators for each node }
|
||||
|
||||
var
|
||||
bb: blockPtr; {used to trace the block list}
|
||||
change: boolean; {for loop termination test}
|
||||
i, j: integer; {loop variables}
|
||||
maxdfn, mindfn: integer; {max and min dfn values used}
|
||||
|
||||
|
||||
procedure Add (var dom: blockListPtr; dfn: integer);
|
||||
procedure AddDominator (var dom: blockListPtr; dfn: integer);
|
||||
|
||||
{ Add dfn to the list of dominators }
|
||||
{ }
|
||||
@ -3246,14 +3235,25 @@ var
|
||||
var
|
||||
dp: blockListPtr; {new node}
|
||||
|
||||
begin {Add}
|
||||
begin {AddDominator}
|
||||
new(dp);
|
||||
dp^.last := nil;
|
||||
dp^.next := dom;
|
||||
dom^.last := dp;
|
||||
dom := dp;
|
||||
dp^.dfn := dfn;
|
||||
end; {Add}
|
||||
end; {AddDominator}
|
||||
|
||||
|
||||
procedure Dominators;
|
||||
|
||||
{ Find a list of dominators for each node }
|
||||
|
||||
var
|
||||
bb: blockPtr; {used to trace the block list}
|
||||
change: boolean; {for loop termination test}
|
||||
i, j: integer; {loop variables}
|
||||
maxdfn, mindfn: integer; {max and min dfn values used}
|
||||
|
||||
|
||||
procedure CheckPredecessors (bb: blockPtr; bl: dftptr);
|
||||
@ -3305,13 +3305,13 @@ var
|
||||
maxdfn := bb^.dfn;
|
||||
bb := bb^.next;
|
||||
end; {while}
|
||||
Add(DAGBlocks^.dom, DAGBlocks^.dfn); {the first node is it's own dominator}
|
||||
AddDominator(DAGBlocks^.dom, DAGBlocks^.dfn); {the first node is it's own dominator}
|
||||
mindfn := DAGBlocks^.dfn; {assume all other nodes are dominated by every other node}
|
||||
for i := mindfn+1 to maxdfn do begin
|
||||
bb := DFN(i);
|
||||
if bb <> nil then
|
||||
for j := mindfn to maxdfn do
|
||||
Add(bb^.dom, j);
|
||||
AddDominator(bb^.dom, j);
|
||||
end; {for}
|
||||
repeat {iterate to the true set of dominators}
|
||||
change := false;
|
||||
@ -3595,8 +3595,31 @@ var
|
||||
loops: loopListPtr; {list of loops}
|
||||
lp: loopPtr; {used to trace loop lists}
|
||||
llp: loopListPtr; {used to trace the list of loops}
|
||||
fakeDFN: integer; {to uniquely number newly-created blocks}
|
||||
|
||||
|
||||
function InLoop (blk: blockPtr; lp: loopPtr): boolean;
|
||||
|
||||
{ See if the block is in the loop }
|
||||
{ }
|
||||
{ parameters: }
|
||||
{ blk - block to check for }
|
||||
{ lp - loop list }
|
||||
{ }
|
||||
{ Returns: True if blk is in the list, else false }
|
||||
|
||||
begin {InLoop}
|
||||
InLoop := false;
|
||||
while lp <> nil do begin
|
||||
if lp^.block = blk then begin
|
||||
lp := nil;
|
||||
InLoop := true;
|
||||
end {if}
|
||||
else
|
||||
lp := lp^.next;
|
||||
end; {while}
|
||||
end; {InLoop}
|
||||
|
||||
|
||||
procedure FindLoops;
|
||||
|
||||
@ -3630,29 +3653,6 @@ var
|
||||
end; {Add}
|
||||
|
||||
|
||||
function InLoop (blk: blockPtr; lp: loopPtr): boolean;
|
||||
|
||||
{ See if the block is in the loop }
|
||||
{ }
|
||||
{ parameters: }
|
||||
{ blk - block to check for }
|
||||
{ lp - loop list }
|
||||
{ }
|
||||
{ Returns: True if blk is in the list, else false }
|
||||
|
||||
begin {InLoop}
|
||||
InLoop := false;
|
||||
while lp <> nil do begin
|
||||
if lp^.block = blk then begin
|
||||
lp := nil;
|
||||
InLoop := true;
|
||||
end {if}
|
||||
else
|
||||
lp := lp^.next;
|
||||
end; {while}
|
||||
end; {InLoop}
|
||||
|
||||
|
||||
procedure Insert (block: blockPtr);
|
||||
|
||||
{ Insert a block into the loop list }
|
||||
@ -3679,28 +3679,6 @@ var
|
||||
end; {AddPredecessors}
|
||||
|
||||
|
||||
function InLoop (block: blockPtr; lp: loopPtr): boolean;
|
||||
|
||||
{ See if a block is in the loop }
|
||||
{ }
|
||||
{ parameters: }
|
||||
{ block - block to check }
|
||||
{ lp - list of blocks in the loop }
|
||||
{ }
|
||||
{ Returns: True if the block is in the loop, else false }
|
||||
|
||||
begin {InLoop}
|
||||
InLoop := false;
|
||||
while lp <> nil do
|
||||
if lp^.block = block then begin
|
||||
InLoop := true;
|
||||
lp := nil;
|
||||
end {if}
|
||||
else
|
||||
lp := lp^.next;
|
||||
end; {InLoop}
|
||||
|
||||
|
||||
begin {Insert}
|
||||
if not InLoop(block, llp^.loop) then begin
|
||||
Add(block);
|
||||
@ -4243,7 +4221,8 @@ var
|
||||
|
||||
var
|
||||
icount, oldIcount: integer; {invariant order counters}
|
||||
nhp: blockPtr; {new loop hedaer pointer}
|
||||
nhp: blockPtr; {new loop header pointer}
|
||||
ohp: blockPtr; {old loop header pointer}
|
||||
op1, op2, op3: icptr; {used to reverse the code list}
|
||||
|
||||
|
||||
@ -4252,11 +4231,10 @@ var
|
||||
{ Create the new loop header }
|
||||
{ }
|
||||
{ Notes: As a side effect, CreateHeader sets nhp to point to }
|
||||
{ the new loop header. }
|
||||
{ the new loop header, and ohp to point to the old header. }
|
||||
|
||||
var
|
||||
lp: loopPtr; {new loop list entry}
|
||||
ohp: blockPtr; {old loop hedaer pointer}
|
||||
|
||||
begin {CreateHeader}
|
||||
nhp := pointer(Calloc(sizeof(block))); {create the new block}
|
||||
@ -4266,6 +4244,8 @@ var
|
||||
nhp^.last^.next := nhp;
|
||||
nhp^.next := ohp;
|
||||
ohp^.last := nhp;
|
||||
nhp^.dfn := fakeDFN; {just a unique number, not a real DFN}
|
||||
fakeDFN := fakeDFN - 1;
|
||||
new(lp); {add it to the loop list}
|
||||
lp^.next := llp^.loop;
|
||||
llp^.loop := lp;
|
||||
@ -4465,6 +4445,125 @@ var
|
||||
end; {RemoveInvariant}
|
||||
|
||||
|
||||
procedure AdjustControlFlow;
|
||||
|
||||
{ Adjust control flow to account for loop invariant removal. }
|
||||
{ The current loop's back edges should go to the old header }
|
||||
{ block, bypassing removed invariant computations. Any other }
|
||||
{ jumps to the start of the loop should go to the new header }
|
||||
{ block so that those computations are performed. }
|
||||
|
||||
var
|
||||
lp: loopPtr; {used to trace loop list}
|
||||
op, op1: icptr; {used to trace code list}
|
||||
|
||||
begin {AdjustControlFlow}
|
||||
{move old header label to new header}
|
||||
{(for any jumps to it from outside loop)}
|
||||
if (ohp^.code = nil) or (ohp^.code^.opcode <> dc_lab) then
|
||||
TermError(3); {shouldn't happen, but let's be sure}
|
||||
op1 := pointer(Calloc(sizeof(intermediate_code)));
|
||||
op1^.opcode := dc_lab;
|
||||
op1^.q := ohp^.code^.q;
|
||||
op1^.next := nhp^.code;
|
||||
nhp^.code := op1;
|
||||
|
||||
ohp^.code^.q := GenLabel; {make new label for old header &}
|
||||
lp := llp^.loop; {adjust loop back edges to go to it}
|
||||
while (lp <> nil) do begin
|
||||
op := lp^.block^.code;
|
||||
while op <> nil do begin
|
||||
if op^.opcode in [pc_ujp,pc_fjp,pc_tjp,pc_add] then
|
||||
if op^.q = op1^.q then begin
|
||||
op^.q := ohp^.code^.q;
|
||||
end;
|
||||
op := op^.next;
|
||||
end; {while}
|
||||
lp := lp^.next;
|
||||
end; {while}
|
||||
end; {AdjustControlFlow}
|
||||
|
||||
|
||||
procedure UpdateLoopLists;
|
||||
|
||||
{ Update not-yet-processed loops to include the new header }
|
||||
{ block if appropriate. Also update any additional loops with }
|
||||
{ the same original header to now include all the nodes of the }
|
||||
{ loop just processed, since their back edges will now go to }
|
||||
{ the new header, which dominates the original header. }
|
||||
|
||||
var
|
||||
lp, lp2, lp3: loopPtr; {used to trace loop list}
|
||||
|
||||
begin {UpdateLoopLists}
|
||||
loops := llp^.next;
|
||||
while loops <> nil do begin
|
||||
if loops^.loop^.block = ohp then begin
|
||||
{Another loop with the same header.}
|
||||
{Nodes of llp^.loop must be added to it.}
|
||||
{They go after the original header.}
|
||||
lp3 := loops^.loop;
|
||||
lp := llp^.loop;
|
||||
while lp <> nil do begin
|
||||
if lp^.block <> nhp then
|
||||
if not InLoop(lp^.block, loops^.loop) then begin
|
||||
new(lp2);
|
||||
lp2^.next := lp3^.next;
|
||||
lp2^.block := lp^.block;
|
||||
lp2^.exit := lp^.exit;
|
||||
lp3^.next := lp2;
|
||||
lp3 := lp2;
|
||||
end; {if}
|
||||
lp := lp^.next;
|
||||
end; {while}
|
||||
end; {if}
|
||||
lp := loops^.loop; {Add nhp to other loops containing ohp}
|
||||
while lp <> nil do begin
|
||||
if lp^.block = ohp then begin
|
||||
new(lp2);
|
||||
lp2^.next := lp^.next;
|
||||
lp2^.block := lp^.block;
|
||||
lp2^.exit := lp^.exit;
|
||||
lp^.next := lp2;
|
||||
lp^.block := nhp;
|
||||
lp^.exit := false;
|
||||
lp := nil;
|
||||
end {if}
|
||||
else
|
||||
lp := lp^.next;
|
||||
end; {while}
|
||||
loops := loops^.next;
|
||||
end; {while}
|
||||
end; {UpdateLoopLists}
|
||||
|
||||
|
||||
procedure UpdateDominators;
|
||||
|
||||
{ Set dominators of the new header block, and update }
|
||||
{ dominators of other blocks to include it where appropriate. }
|
||||
|
||||
var
|
||||
bb: blockPtr; {used to trace list of basic blocks}
|
||||
dom: blockListPtr; {used to trace dominator list}
|
||||
|
||||
begin {UpdateDominators}
|
||||
dom := ohp^.dom; {Set dominators of new header block}
|
||||
while dom <> nil do begin
|
||||
if dom^.dfn <> ohp^.dfn then
|
||||
AddDominator(nhp^.dom, dom^.dfn);
|
||||
dom := dom^.next;
|
||||
end; {while}
|
||||
AddDominator(nhp^.dom, nhp^.dfn);
|
||||
|
||||
bb := DAGBlocks; {Add nhp to other loops' dominators}
|
||||
while bb <> nil do begin
|
||||
if MemberDFNList(ohp^.dfn, bb^.dom) then
|
||||
AddDominator(bb^.dom, nhp^.dfn);
|
||||
bb := bb^.next;
|
||||
end; {while}
|
||||
end; {UpdateDominators}
|
||||
|
||||
|
||||
begin {RemoveInvariants}
|
||||
CreateHeader; {create a loop header block}
|
||||
icount := 0; {find & remove all invariants}
|
||||
@ -4483,6 +4582,13 @@ var
|
||||
op2 := op3;
|
||||
end; {while}
|
||||
nhp^.code := op2;
|
||||
{adjust things to account for changes}
|
||||
if nhp^.code <> nil then begin
|
||||
Spin;
|
||||
AdjustControlFlow;
|
||||
UpdateLoopLists;
|
||||
UpdateDominators;
|
||||
end; {if}
|
||||
end; {RemoveInvariants}
|
||||
|
||||
|
||||
@ -4529,6 +4635,7 @@ var
|
||||
begin {LoopInvariantRemoval}
|
||||
Spin;
|
||||
FindLoops; {find a list of natural loops}
|
||||
fakeDFN := -1;
|
||||
|
||||
llp := loops; {scan the loops...}
|
||||
icount := 1;
|
||||
|
Loading…
Reference in New Issue
Block a user