diff --git a/Source/Mosa.Compiler.Framework/Loop.cs b/Source/Mosa.Compiler.Framework/Loop.cs index 1fff89812e..ee940e4afd 100644 --- a/Source/Mosa.Compiler.Framework/Loop.cs +++ b/Source/Mosa.Compiler.Framework/Loop.cs @@ -7,8 +7,9 @@ namespace Mosa.Compiler.Framework; public sealed class Loop { public BasicBlock Header { get; set; } - public readonly List Backedges = new List(); - public readonly List LoopBlocks = new List(); + public readonly List Backedges = new(); + public readonly List LoopBlocks = new(); + //private readonly HashSet LoopBlocksSet = new(); public Loop(BasicBlock header, BasicBlock backedge) { @@ -25,5 +26,11 @@ public void AddNode(BasicBlock block) { Debug.Assert(!LoopBlocks.Contains(block)); LoopBlocks.Add(block); + //LoopBlocksSet.Add(block); } + + //public bool Contains(BasicBlock block) + //{ + // return LoopBlocksSet.Contains(block); + //} } diff --git a/Source/Mosa.Compiler.Framework/Stages/LoopRangeTrackerStage.cs b/Source/Mosa.Compiler.Framework/Stages/LoopRangeTrackerStage.cs index b013229734..9ec7d87a76 100644 --- a/Source/Mosa.Compiler.Framework/Stages/LoopRangeTrackerStage.cs +++ b/Source/Mosa.Compiler.Framework/Stages/LoopRangeTrackerStage.cs @@ -75,22 +75,16 @@ private void ProcessLoop(Loop loop) continue; if (node.Instruction == IR.Phi32) - ProcessNode32(node, loop); - - //if (node.Instruction == IR.Phi64)) - //ProcessNode64(node, loop); + ProcessNode(node, loop, true); + else if (node.Instruction == IR.Phi64) + ProcessNode(node, loop, false); } } - private void ProcessNode32(Node node, Loop loop) + private void ProcessNode(Node node, Loop loop, bool is32Bit) { var headerblock = node.Block.PreviousBlocks[0]; - // match a = phi(x, y) { B1, B2} - // in header loop - // where x is constant - // B1 is loop.header.previous - var result = node.Result; var x = node.Operand1; var y = node.Operand2; @@ -110,19 +104,14 @@ private void ProcessNode32(Node node, Loop loop) if (b1 != headerblock) return; - //y.defined by - //instruction = Add - //op1 = x - //op2 = positive constant c (increment) - //in block within loop // may not be necessary in SSA form - // => at this point, we know the lower of a is constant x - if (!y.IsDefinedOnce) return; var d = y.Definitions[0]; - if (d.Instruction != IR.Add32) + // Future: determine direction base on IR.Add or IR.Sub and constant + + if (!(d.Instruction == IR.Add32 || d.Instruction == IR.Add64)) return; if (d.Result != y) @@ -134,18 +123,18 @@ private void ProcessNode32(Node node, Loop loop) if (!d.Operand2.IsResolvedConstant) return; - if (d.Operand2.ConstantUnsigned32 <= 0) + if (d.Operand2.ConstantUnsigned64 <= 0) return; if (!loop.LoopBlocks.Contains(d.Block)) return; - result.BitValue.NarrowMin(x.ConstantUnsigned32); + result.BitValue.NarrowMin(x.ConstantUnsigned64); - trace?.Log($"{result} MinValue = {x.ConstantUnsigned32}"); + trace?.Log($"{result} MinValue = {x.ConstantUnsigned64}"); MinDetermined.Increment(); - if (DetermineMaxOut32(d.Operand1, d.Operand2, loop, out var max)) + if (DetermineMaxOut(d.Operand1, d.Operand2, loop, out var max)) { result.BitValue.NarrowMax((ulong)max); @@ -154,22 +143,14 @@ private void ProcessNode32(Node node, Loop loop) } } - private bool DetermineMaxOut32(Operand incrementVariable, Operand incrementValue, Loop loop, out int max) + private static bool DetermineMaxOut(Operand incrementVariable, Operand incrementValue, Loop loop, out long max) { bool determined = false; - max = int.MaxValue; - - //a.used by - //instruction = branch - //compare: < - //op1 = result - //op2 = constant d - //branch is to phi node - //in block within loop + max = long.MaxValue; foreach (var b in incrementVariable.Uses) { - if (b.Instruction != IR.Branch32) + if (!(b.Instruction == IR.Branch32 || b.Instruction == IR.Branch64)) continue; // only that are the header or backedge (if only one) @@ -184,22 +165,35 @@ private bool DetermineMaxOut32(Operand incrementVariable, Operand incrementValue ? b.Block.NextBlocks[0] : b.Block.NextBlocks[1]; - if (!(condition == ConditionCode.Less - || condition == ConditionCode.LessOrEqual - || condition == ConditionCode.UnsignedLess - || condition == ConditionCode.UnsignedLessOrEqual - || condition == ConditionCode.Equal)) + // form: x (variable) where branch exits the loop + + // change form - on condition + if (condition is not (ConditionCode.Less + or ConditionCode.LessOrEqual + or ConditionCode.UnsignedLess + or ConditionCode.UnsignedLessOrEqual + or ConditionCode.Equal)) { - // swap - (x, y, condition, target, othertarget) = (y, x, condition.GetOpposite(), othertarget, target); + (x, y, condition) = (y, x, condition.GetOpposite()); // swap } - // form: x (variable) which branch exits the loop - if (!(condition == ConditionCode.Less - || condition == ConditionCode.LessOrEqual - || condition == ConditionCode.UnsignedLess - || condition == ConditionCode.UnsignedLessOrEqual - || condition == ConditionCode.Equal)) + // change form - on branch + if (!loop.LoopBlocks.Contains(target)) + { + (condition, target, othertarget) = (condition.GetOpposite(), othertarget, target); // swap + } + + // change form - on constant to right + if (!y.IsResolvedConstant && condition == ConditionCode.Equal) + { + (x, y) = (y, x); + } + + if (condition is not (ConditionCode.Less + or ConditionCode.LessOrEqual + or ConditionCode.UnsignedLess + or ConditionCode.UnsignedLessOrEqual + or ConditionCode.Equal)) continue; if (x != incrementVariable) @@ -208,12 +202,12 @@ private bool DetermineMaxOut32(Operand incrementVariable, Operand incrementValue if (!y.IsResolvedConstant) continue; - if (!loop.LoopBlocks.Contains(target)) // exits loop - continue; + if (!loop.LoopBlocks.Contains(target)) + continue; // exits loop var adj = condition == ConditionCode.LessOrEqual || condition == ConditionCode.Equal ? 1 : 0; - var branchmax = y.ConstantSigned32 + incrementValue.ConstantSigned32 - 1 + adj; + var branchmax = y.ConstantSigned64 + incrementValue.ConstantSigned64 - 1 + adj; max = Math.Min(max, branchmax); diff --git a/Source/Mosa.Tool.Explorer/MainForm.cs b/Source/Mosa.Tool.Explorer/MainForm.cs index 8d3457898e..ec1530c0d1 100644 --- a/Source/Mosa.Tool.Explorer/MainForm.cs +++ b/Source/Mosa.Tool.Explorer/MainForm.cs @@ -974,6 +974,7 @@ private void ToggleOptimization(bool state) cbEnableLongExpansion.Checked = state; cbEnableTwoPassOptimizations.Checked = state; cbEnableBitTracker.Checked = state; + cbEnableLoopRangeTracker.Checked = state; cbLoopInvariantCodeMotion.Checked = state; cbPlatformOptimizations.Checked = state; cbEnableDevirtualization.Checked = state; diff --git a/Source/Mosa.UnitTests/Optimization/LoopStrengthReduction.cs b/Source/Mosa.UnitTests/Optimization/LoopStrengthReduction.cs index 6d29634328..d75e2a55ba 100644 --- a/Source/Mosa.UnitTests/Optimization/LoopStrengthReduction.cs +++ b/Source/Mosa.UnitTests/Optimization/LoopStrengthReduction.cs @@ -82,7 +82,7 @@ public static int Reduction6() for (var i = 0; i < n; i++) { - a *= i; + a += i; if (i > 20) return 0; @@ -91,6 +91,108 @@ public static int Reduction6() return a; } + [MosaUnitTest] + public static int Reduction6a() + { + var a = 8; + var n = 10; + + for (var i = 0; i < n; i++) + { + a += i; + + if (i > 9) + return 0; + } + + return a; + } + + [MosaUnitTest] + public static int Reduction6b() + { + var a = 8; + var n = 10; + + for (var i = 0; i < n; i++) + { + a += i; + + if (i > 10) + return 0; + } + + return a; + } + + [MosaUnitTest] + public static int Reduction6c() + { + var a = 8; + var n = 10; + + for (var i = 0; i < n; i++) + { + a += i; + + if (i > 11) + return 0; + } + + return a; + } + + [MosaUnitTest] + public static int Reduction6d() + { + var a = 8; + var n = 10; + + for (var i = 0; i != n; i++) + { + a += i; + + if (i > 9) + return 0; + } + + return a; + } + + [MosaUnitTest] + public static int Reduction6e() + { + var a = 8; + var n = 10; + + for (var i = 0; i != n; i++) + { + a += i; + + if (i > 10) + return 0; + } + + return a; + } + + [MosaUnitTest] + public static int Reduction6f() + { + var a = 8; + var n = 10; + + for (var i = 0; i != n; i++) + { + a += i; + + if (i > 11) + return 0; + } + + return a; + } + [MosaUnitTest] public static int Reduction7() {