Skip to content

Commit 453dc11

Browse files
committed
Add new pass to restructure the conditional checks for loops. This saves an unconditional jump from the loop's end by repeating the conditional check at that point and conditionally jumping to the start of the loop body instead of unconditionally to the loop header. For safety, this pass occurs before the SSA conversion.
1 parent a19e339 commit 453dc11

4 files changed

Lines changed: 141 additions & 2 deletions

File tree

src/kOS.Safe.Test/Execution/OptimizationTest.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -939,5 +939,44 @@ public void TestIfElseIfElseDetection()
939939
Where(b => Safe.Compilation.Optimization.Passes.BlockOrdering.IdentifyBranch(b, null, out _)).Count());
940940
}
941941
#endregion
942+
943+
#region Loop Condition Reordering
944+
[Test]
945+
public void TestUntilLoopCondition()
946+
{
947+
optimizationLevel = OptimizationLevel.Balanced;
948+
List<CodePart> _code = CompileCodePart("integration/branching/until.ks");
949+
optimizationLevel = OptimizationLevel.Minimal;
950+
List<Safe.Compilation.Opcode> opcodes = _code[0].MainCode;
951+
Assert.AreEqual(opcodes[4].ToString(), opcodes[10].ToString());
952+
Assert.IsInstanceOf(typeof(OpcodeBranchIfTrue), opcodes[5]);
953+
Assert.IsInstanceOf(typeof(OpcodeBranchIfFalse), opcodes[11]);
954+
}
955+
[Test]
956+
public void TestForLoopCondition()
957+
{
958+
optimizationLevel = OptimizationLevel.Balanced;
959+
List<CodePart> _code = CompileCodePart("integration/branching/for.ks");
960+
optimizationLevel = OptimizationLevel.Minimal;
961+
List<Safe.Compilation.Opcode> opcodes = _code[0].MainCode;
962+
Assert.AreEqual(opcodes[8].ToString(), opcodes[15].ToString());
963+
Assert.AreEqual(opcodes[9].ToString(), opcodes[16].ToString());
964+
Assert.IsInstanceOf(typeof(OpcodeBranchIfFalse), opcodes[10]);
965+
Assert.IsInstanceOf(typeof(OpcodeBranchIfTrue), opcodes[17]);
966+
}
967+
[Test]
968+
public void TestFromLoopCondition()
969+
{
970+
optimizationLevel = OptimizationLevel.Balanced;
971+
List<CodePart> _code = CompileCodePart("integration/branching/from.ks");
972+
optimizationLevel = OptimizationLevel.Minimal;
973+
List<Safe.Compilation.Opcode> opcodes = _code[0].MainCode;
974+
Assert.AreEqual(opcodes[7].ToString(), opcodes[19].ToString());
975+
Assert.AreEqual(opcodes[8].ToString(), opcodes[20].ToString());
976+
Assert.AreEqual(opcodes[9].ToString(), opcodes[21].ToString());
977+
Assert.IsInstanceOf(typeof(OpcodeBranchIfTrue), opcodes[10]);
978+
Assert.IsInstanceOf(typeof(OpcodeBranchIfFalse), opcodes[22]);
979+
}
980+
#endregion
942981
}
943982
}

src/kOS.Safe/Compilation/Optimization/OptimizationLevel.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ namespace kOS.Safe.Compilation
2626
* 32767. Block ordering to minimize unconditional jumps.
2727
*
2828
* O2:
29+
* -10000. Loop condition reorganization
2930
* 1000. Common expression elimination
3031
* Particularly: Any expression of 3 opcodes used more than twice,
3132
* or any expression of >3 opcodes used more than once

src/kOS.Safe/Compilation/Optimization/Passes/BlockOrdering.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,9 @@ private static MetaBlockSequence ConstructMetaSequence(BasicBlock root, Stack<Ba
106106
newOffshoots.Enqueue(child);
107107
block = loopData.exit;
108108
}
109-
else if (IdentifyBranch(block, regionExits.Peek(), out BranchData branchData))
109+
else if (IdentifyBranch(block, regionExits.Peek(), out BranchData branchData) &&
110+
!((branchData.ifBlock?.Dominator != null && branchData.ifBlock.Dominator != block) ||
111+
(branchData.elseBlock?.Dominator != null && branchData.elseBlock.Dominator != block)))
110112
{
111113
sequence.Add(ConstructMetaSequence(branchData.ifBlock, regionExits, out Queue<BasicBlock> childOffshoots));
112114
foreach (BasicBlock child in childOffshoots)
@@ -197,6 +199,7 @@ private static BasicBlock GetSequenceEnd(BasicBlock block)
197199
}
198200
private static bool BackEdgeDetection(BasicBlock successor, BasicBlock target)
199201
{
202+
BasicBlock firstSuccessor = successor;
200203
if (successor.Dominator != target)
201204
return false;
202205

@@ -207,7 +210,7 @@ private static bool BackEdgeDetection(BasicBlock successor, BasicBlock target)
207210
return true;
208211
}
209212

210-
return successor.Successors.Contains(target);
213+
return successor.Successors.Contains(target) || successor.Successors.Contains(firstSuccessor);
211214
}
212215
private static BasicBlock FindLocalMerge(BasicBlock ifBlock, BasicBlock regionExit)
213216
{
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using kOS.Safe.Compilation.IR;
5+
6+
namespace kOS.Safe.Compilation.Optimization.Passes
7+
{
8+
public class LoopConditionalRelocation : IHolisticOptimizationPass
9+
{
10+
public OptimizationLevel OptimizationLevel => OptimizationLevel.Balanced;
11+
12+
public short SortIndex => -10000;
13+
14+
public void ApplyPass(IRCodePart codePart)
15+
{
16+
foreach (IRCodePart.IRFunction function in codePart.Functions)
17+
foreach (IRCodePart.IRFunction.IRFunctionFragment fragment in function.Fragments)
18+
ApplyPass(fragment.FunctionCode[0]);
19+
foreach (IRCodePart.IRTrigger trigger in codePart.Triggers)
20+
ApplyPass(trigger.Code[0]);
21+
ApplyPass(codePart.MainCode[0]);
22+
}
23+
24+
private static void ApplyPass(BasicBlock root)
25+
{
26+
IEnumerable<BasicBlock> GetEdges(BasicBlock block)
27+
=> block.Successors.Where(BlockOrdering.InitialPredicate);
28+
29+
List<BasicBlock> reversePostOrder = BasicBlock.GetReversePostOrder(root, GetEdges);
30+
Stack<BasicBlock> regionExits = new Stack<BasicBlock>();
31+
regionExits.Push(reversePostOrder[reversePostOrder.Count - 1]);
32+
33+
List<BlockOrdering.LoopData> loopData = new List<BlockOrdering.LoopData>();
34+
35+
FindLoops(root, regionExits, loopData);
36+
37+
foreach (BlockOrdering.LoopData loop in loopData)
38+
{
39+
RelocateConditional(loop);
40+
}
41+
}
42+
43+
private static void RelocateConditional(BlockOrdering.LoopData loopData)
44+
{
45+
BasicBlock header = loopData.header;
46+
BasicBlock block = loopData.body;
47+
while (block.PostDominator?.Dominator == block)
48+
block = block.PostDominator;
49+
50+
IRBranch newBranch = (IRBranch)header.Instructions[header.Instructions.Count - 1];
51+
newBranch = newBranch.Clone(block);
52+
newBranch.PreferFalse = !newBranch.PreferFalse;
53+
54+
block.Instructions[block.Instructions.Count - 1] = newBranch;
55+
block.AddSuccessor(newBranch.True);
56+
block.AddSuccessor(newBranch.False);
57+
block.RemoveSuccessor(header);
58+
}
59+
60+
private static void FindLoops(BasicBlock root, Stack<BasicBlock> regionExits, List<BlockOrdering.LoopData> loops)
61+
{
62+
BasicBlock block = root;
63+
while (block != null && block != regionExits.Peek())
64+
{
65+
if (BlockOrdering.IdentifyLoop(block, regionExits.Peek(), out BlockOrdering.LoopData loopData))
66+
{
67+
loops.Add(loopData);
68+
regionExits.Push(loopData.exit);
69+
FindLoops(loopData.body, regionExits, loops);
70+
regionExits.Pop();
71+
block = loopData.exit;
72+
}
73+
else if (BlockOrdering.IdentifyBranch(block, regionExits.Peek(), out BlockOrdering.BranchData branchData))
74+
{
75+
FindLoops(branchData.ifBlock, regionExits, loops);
76+
if (branchData.exit == null && branchData.elseBlock != null)
77+
{
78+
block = branchData.elseBlock;
79+
}
80+
else
81+
{
82+
if (branchData.elseBlock != null)
83+
FindLoops(branchData.elseBlock, regionExits, loops);
84+
block = branchData.exit;
85+
}
86+
}
87+
else if (block.PostDominator?.Dominator == block)
88+
{
89+
block = block.PostDominator;
90+
}
91+
else
92+
return;
93+
}
94+
}
95+
}
96+
}

0 commit comments

Comments
 (0)