diff --git a/Source/Mosa.Compiler.Framework/BaseTransform.cs b/Source/Mosa.Compiler.Framework/BaseTransform.cs
index 1f6388d7dd..029a6047d3 100644
--- a/Source/Mosa.Compiler.Framework/BaseTransform.cs
+++ b/Source/Mosa.Compiler.Framework/BaseTransform.cs
@@ -1183,19 +1183,19 @@ protected static bool IsBitValueZeroOrOne(Operand operand)
{
return (int)value1.BitsSet > (int)value2.BitsSet;
}
- else if (value1.Is32Bit && value2.Is32Bit && value1.IsSignBitClear32 && value2.IsSignBitClear32 && value1.MinValue > value2.MaxValue)
+ else if (value1.Is32Bit && value2.Is32Bit && value1.IsSignBitKnown32 && value2.IsSignBitKnown32 && value1.IsSignBitClear32 && value2.IsSignBitClear32 && value1.MinValue > value2.MaxValue)
{
return true;
}
- else if (value1.Is32Bit && value2.Is32Bit && value1.IsSignBitClear32 && value2.IsSignBitClear32 && value1.MaxValue < value2.MinValue)
+ else if (value1.Is32Bit && value2.Is32Bit && value1.IsSignBitKnown32 && value2.IsSignBitKnown32 && value1.IsSignBitClear32 && value2.IsSignBitClear32 && value1.MaxValue < value2.MinValue)
{
return false;
}
- else if (value1.Is64Bit && value2.Is64Bit && value1.IsSignBitClear64 && value2.IsSignBitClear64 && value1.MinValue > value2.MaxValue)
+ else if (value1.Is64Bit && value2.Is64Bit && value1.IsSignBitKnown64 && value2.IsSignBitKnown64 && value1.IsSignBitClear64 && value2.IsSignBitClear64 && value1.MinValue > value2.MaxValue)
{
return true;
}
- else if (value1.Is64Bit && value2.Is64Bit && value1.IsSignBitClear64 && value2.IsSignBitClear64 && value1.MaxValue < value2.MinValue)
+ else if (value1.Is64Bit && value2.Is64Bit && value1.IsSignBitKnown64 && value2.IsSignBitKnown64 && value1.IsSignBitClear64 && value2.IsSignBitClear64 && value1.MaxValue < value2.MinValue)
{
return false;
}
@@ -1211,19 +1211,19 @@ protected static bool IsBitValueZeroOrOne(Operand operand)
{
return (int)value1.BitsSet < (int)value2.BitsSet;
}
- else if (value1.Is32Bit && value2.Is32Bit && value1.IsSignBitClear32 && value2.IsSignBitClear32 && value1.MaxValue < value2.MinValue)
+ else if (value1.Is32Bit && value2.Is32Bit && value1.IsSignBitKnown32 && value2.IsSignBitKnown32 && value1.IsSignBitClear32 && value2.IsSignBitClear32 && value1.MaxValue < value2.MinValue)
{
return true;
}
- else if (value1.Is32Bit && value2.Is32Bit && value1.IsSignBitClear32 && value2.IsSignBitClear32 && value1.MinValue > value2.MaxValue)
+ else if (value1.Is32Bit && value2.Is32Bit && value1.IsSignBitKnown32 && value2.IsSignBitKnown32 && value1.IsSignBitClear32 && value2.IsSignBitClear32 && value1.MinValue > value2.MaxValue)
{
return false;
}
- else if (value1.Is64Bit && value2.Is64Bit && value1.IsSignBitClear64 && value2.IsSignBitClear64 && value1.MaxValue < value2.MinValue)
+ else if (value1.Is64Bit && value2.Is64Bit && value1.IsSignBitKnown64 && value2.IsSignBitKnown64 && value1.IsSignBitClear64 && value2.IsSignBitClear64 && value1.MaxValue < value2.MinValue)
{
return true;
}
- else if (value1.Is64Bit && value2.Is64Bit && value1.IsSignBitClear64 && value2.IsSignBitClear64 && value1.MinValue > value2.MaxValue)
+ else if (value1.Is64Bit && value2.Is64Bit && value1.IsSignBitKnown64 && value2.IsSignBitKnown64 && value1.IsSignBitClear64 && value2.IsSignBitClear64 && value1.MinValue > value2.MaxValue)
{
return false;
}
@@ -1239,19 +1239,19 @@ protected static bool IsBitValueZeroOrOne(Operand operand)
{
return (int)value1.BitsSet >= (int)value2.BitsSet;
}
- else if (value1.Is32Bit && value2.Is32Bit && value1.IsSignBitClear32 && value2.IsSignBitClear32 && value1.MinValue >= value2.MaxValue)
+ else if (value1.Is32Bit && value2.Is32Bit && value1.IsSignBitKnown32 && value2.IsSignBitKnown32 && value1.IsSignBitClear32 && value2.IsSignBitClear32 && value1.MinValue >= value2.MaxValue)
{
return true;
}
- else if (value1.Is32Bit && value2.Is32Bit && value1.IsSignBitClear32 && value2.IsSignBitClear32 && value1.MaxValue <= value2.MinValue)
+ else if (value1.Is32Bit && value2.Is32Bit && value1.IsSignBitKnown32 && value2.IsSignBitKnown32 && value1.IsSignBitClear32 && value2.IsSignBitClear32 && value1.MaxValue <= value2.MinValue)
{
return false;
}
- else if (value1.Is64Bit && value2.Is64Bit && value1.IsSignBitClear64 && value2.IsSignBitClear64 && value1.MinValue >= value2.MaxValue)
+ else if (value1.Is64Bit && value2.Is64Bit && value1.IsSignBitKnown64 && value2.IsSignBitKnown64 && value1.IsSignBitClear64 && value2.IsSignBitClear64 && value1.MinValue >= value2.MaxValue)
{
return true;
}
- else if (value1.Is64Bit && value2.Is64Bit && value1.IsSignBitClear64 && value2.IsSignBitClear64 && value1.MaxValue <= value2.MinValue)
+ else if (value1.Is64Bit && value2.Is64Bit && value1.IsSignBitKnown64 && value2.IsSignBitKnown64 && value1.IsSignBitClear64 && value2.IsSignBitClear64 && value1.MaxValue <= value2.MinValue)
{
return false;
}
@@ -1267,19 +1267,19 @@ protected static bool IsBitValueZeroOrOne(Operand operand)
{
return (int)value1.BitsSet <= (int)value2.BitsSet;
}
- else if (value1.Is32Bit && value2.Is32Bit && value1.IsSignBitClear32 && value2.IsSignBitClear32 && value1.MaxValue <= value2.MinValue)
+ else if (value1.Is32Bit && value2.Is32Bit && value1.IsSignBitKnown32 && value2.IsSignBitKnown32 && value1.IsSignBitClear32 && value2.IsSignBitClear32 && value1.MaxValue <= value2.MinValue)
{
return true;
}
- else if (value1.Is32Bit && value2.Is32Bit && value1.IsSignBitClear32 && value2.IsSignBitClear32 && value1.MinValue >= value2.MaxValue)
+ else if (value1.Is32Bit && value2.Is32Bit && value1.IsSignBitKnown32 && value2.IsSignBitKnown32 && value1.IsSignBitClear32 && value2.IsSignBitClear32 && value1.MinValue >= value2.MaxValue)
{
return false;
}
- else if (value1.Is64Bit && value2.Is64Bit && value1.IsSignBitClear64 && value2.IsSignBitClear64 && value1.MaxValue <= value2.MinValue)
+ else if (value1.Is64Bit && value2.Is64Bit && value1.IsSignBitKnown64 && value2.IsSignBitKnown64 && value1.IsSignBitClear64 && value2.IsSignBitClear64 && value1.MaxValue <= value2.MinValue)
{
return true;
}
- else if (value1.Is64Bit && value2.Is64Bit && value1.IsSignBitClear64 && value2.IsSignBitClear64 && value1.MinValue >= value2.MaxValue)
+ else if (value1.Is64Bit && value2.Is64Bit && value1.IsSignBitKnown64 && value2.IsSignBitKnown64 && value1.IsSignBitClear64 && value2.IsSignBitClear64 && value1.MinValue >= value2.MaxValue)
{
return false;
}
diff --git a/Source/Mosa.Compiler.Framework/BitValue.cs b/Source/Mosa.Compiler.Framework/BitValue.cs
index f127b1999b..629eff33e4 100644
--- a/Source/Mosa.Compiler.Framework/BitValue.cs
+++ b/Source/Mosa.Compiler.Framework/BitValue.cs
@@ -188,6 +188,30 @@ public BitValue NarrowMin(ulong minValue)
return Narrow();
}
+ public BitValue NarrowSignRange(long minValue, long maxValue)
+ {
+ if (IsFixed)
+ return this;
+
+ if (minValue > maxValue)
+ {
+ (minValue, maxValue) = (maxValue, minValue); // swap
+ }
+
+ if (minValue >= 0 && maxValue >= 0)
+ {
+ return NarrowMax((ulong)maxValue).NarrowMin((ulong)minValue);
+ }
+ else if (minValue < 0 && maxValue < 0)
+ {
+ return NarrowMin((ulong)maxValue).NarrowMax((ulong)minValue);
+ }
+
+ // unable to narrow
+
+ return this;
+ }
+
public BitValue NarrowSetBits(ulong bitsSet)
{
if (IsFixed)
@@ -322,11 +346,11 @@ public override string ToString()
{
var sb = new StringBuilder();
- sb.Append($"MaxValue: {MaxValue}");
- sb.Append($"MinValue: {MinValue}");
- sb.Append($"BitsSet: {Convert.ToString((long)BitsSet, 2).PadLeft(64, '0')}");
- sb.Append($"BitsClear: {Convert.ToString((long)BitsClear, 2).PadLeft(64, '0')}");
- sb.Append($"BitsKnown: {Convert.ToString((long)BitsKnown, 2).PadLeft(64, '0')}");
+ sb.AppendLine($" Min: {MinValue}");
+ sb.AppendLine($" Max: {MaxValue}");
+ sb.AppendLine($" BitsSet: {Convert.ToString((long)BitsSet, 2).PadLeft(64, '0')}");
+ sb.AppendLine($" BitsClear: {Convert.ToString((long)BitsClear, 2).PadLeft(64, '0')}");
+ sb.AppendLine($" BitsKnown: {Convert.ToString((long)BitsKnown, 2).PadLeft(64, '0')}");
return sb.ToString();
}
diff --git a/Source/Mosa.Compiler.Framework/Compiler.cs b/Source/Mosa.Compiler.Framework/Compiler.cs
index 0fd107fbff..797dc82b11 100644
--- a/Source/Mosa.Compiler.Framework/Compiler.cs
+++ b/Source/Mosa.Compiler.Framework/Compiler.cs
@@ -161,14 +161,14 @@ public sealed class Compiler
mosaSettings.SparseConditionalConstantPropagation && mosaSettings.SSA ? new SparseConditionalConstantPropagationStage() : null,
mosaSettings.BasicOptimizations && mosaSettings.SSA && (mosaSettings.ValueNumbering || mosaSettings.LoopInvariantCodeMotion || mosaSettings.SparseConditionalConstantPropagation) ? new OptimizationStage(false) : null,
mosaSettings.BitTracker ? new BitTrackerStage() : null,
- //mosaSettings.LoopRangeTracker && mosaSettings.SSA ? new LoopRangeTrackerStage() : null,
+ mosaSettings.LoopRangeTracker && mosaSettings.SSA ? new LoopRangeTrackerStage() : null,
mosaSettings.BasicOptimizations ? new OptimizationStage(mosaSettings.LongExpansion) : null,
mosaSettings.TwoPassOptimization && mosaSettings.ValueNumbering && mosaSettings.SSA ? new ValueNumberingStage() : null,
mosaSettings.TwoPassOptimization && mosaSettings.LoopInvariantCodeMotion && mosaSettings.SSA ? new LoopInvariantCodeMotionStage() : null,
mosaSettings.TwoPassOptimization && mosaSettings.SparseConditionalConstantPropagation && mosaSettings.SSA ? new SparseConditionalConstantPropagationStage() : null,
mosaSettings.TwoPassOptimization && mosaSettings.BitTracker ? new BitTrackerStage() : null,
- //mosaSettings.TwoPassOptimization && mosaSettings.LoopRangeTracker && mosaSettings.SSA ? new LoopRangeTrackerStage() : null,
+ mosaSettings.TwoPassOptimization && mosaSettings.LoopRangeTracker && mosaSettings.SSA ? new LoopRangeTrackerStage() : null,
mosaSettings.TwoPassOptimization && mosaSettings.BasicOptimizations && mosaSettings.SSA ? new OptimizationStage(mosaSettings.LongExpansion) : null,
new NopRemovalStage(),
diff --git a/Source/Mosa.Compiler.Framework/Operand.cs b/Source/Mosa.Compiler.Framework/Operand.cs
index 1a1944821b..0dc6d2429e 100644
--- a/Source/Mosa.Compiler.Framework/Operand.cs
+++ b/Source/Mosa.Compiler.Framework/Operand.cs
@@ -113,6 +113,27 @@ public bool IsConstantZero
}
}
+ public bool IsNegative
+ {
+ get
+ {
+ if (!IsResolvedConstant)
+ return false;
+ else if (IsLocalStack || IsOnStack || IsParameter)
+ return ConstantUnsigned64 < 0;
+ else if (IsNull)
+ return false;
+ else if (IsR8)
+ return ConstantDouble < 0;
+ else if (IsR4)
+ return ConstantFloat < 0;
+ else if (IsInt32)
+ return ConstantSigned32 < 0;
+ else
+ return ConstantSigned64 < 0;
+ }
+ }
+
public bool IsPhysicalRegister => Location == LocationType.PhysicalRegister;
public bool IsFloatingPoint => IsR4 | IsR8;
diff --git a/Source/Mosa.Compiler.Framework/Stages/BaseTransformStage.cs b/Source/Mosa.Compiler.Framework/Stages/BaseTransformStage.cs
index d770740a83..4489f3626a 100644
--- a/Source/Mosa.Compiler.Framework/Stages/BaseTransformStage.cs
+++ b/Source/Mosa.Compiler.Framework/Stages/BaseTransformStage.cs
@@ -275,9 +275,15 @@ private bool ApplyBlockTransforms()
var updated = count != 0;
changed |= updated;
- if (updated && MethodCompiler.Statistics)
+ if (updated)
{
- UpdateCounter(transform.Name, count);
+ MethodCompiler.CreateTranformInstructionTrace(this, Steps++);
+
+ if (MosaSettings.FullCheckMode)
+ FullCheck(false);
+
+ if (MethodCompiler.Statistics)
+ UpdateCounter(transform.Name, count);
}
}
diff --git a/Source/Mosa.Compiler.Framework/Stages/LoopRangeTrackerStage.cs b/Source/Mosa.Compiler.Framework/Stages/LoopRangeTrackerStage.cs
index 9ec7d87a76..5b3a9f4c7d 100644
--- a/Source/Mosa.Compiler.Framework/Stages/LoopRangeTrackerStage.cs
+++ b/Source/Mosa.Compiler.Framework/Stages/LoopRangeTrackerStage.cs
@@ -1,5 +1,6 @@
// Copyright (c) MOSA Project. Licensed under the New BSD License.
+using System.Diagnostics;
using Mosa.Compiler.Framework.Analysis;
namespace Mosa.Compiler.Framework.Stages;
@@ -9,15 +10,13 @@ namespace Mosa.Compiler.Framework.Stages;
///
public sealed class LoopRangeTrackerStage : BaseMethodCompilerStage
{
- private readonly Counter MinDetermined = new("LoopRangeTrackerStage.MinDetermined");
- private readonly Counter MaxDetermined = new("LoopRangeTrackerStage.MaxDetermined");
+ private readonly Counter RangeDetermined = new("LoopRangeTrackerStage.RangeDetermined");
private TraceLog trace;
protected override void Initialize()
{
- Register(MinDetermined);
- Register(MaxDetermined);
+ Register(RangeDetermined);
}
protected override void Finish()
@@ -109,91 +108,298 @@ private void ProcessNode(Node node, Loop loop, bool is32Bit)
var d = y.Definitions[0];
- // Future: determine direction base on IR.Add or IR.Sub and constant
-
- if (!(d.Instruction == IR.Add32 || d.Instruction == IR.Add64))
+ if (!(d.Instruction == IR.Add32
+ || d.Instruction == IR.Add64
+ || d.Instruction == IR.Sub32
+ || d.Instruction == IR.Sub64))
return;
+ var direction = d.Instruction == IR.Add32 || d.Instruction == IR.Add64;
+
+ var incrementValueOperand = d.Operand2;
+ var incrementVariableOperand = d.Operand1;
+
if (d.Result != y)
return;
- if (d.Operand1 != result)
+ if (incrementVariableOperand != result)
return;
- if (!d.Operand2.IsResolvedConstant)
+ if (!incrementValueOperand.IsResolvedConstant)
return;
- if (d.Operand2.ConstantUnsigned64 <= 0)
+ if (!loop.LoopBlocks.Contains(d.Block))
return;
- if (!loop.LoopBlocks.Contains(d.Block))
+ if (incrementValueOperand.ConstantSigned64 == 0)
+ return;
+
+ var signedAnalysis = DetermineSignUsage(incrementVariableOperand);
+
+ if (signedAnalysis == SignAnalysis.Unknown || signedAnalysis == SignAnalysis.Both)
return;
- result.BitValue.NarrowMin(x.ConstantUnsigned64);
+ var signed = signedAnalysis == SignAnalysis.Signed;
+
+ if ((signed && incrementValueOperand.IsNegative)
+ || (!signed && incrementValueOperand.IsNegative))
+ {
+ direction = !direction;
+ }
+
+ var startOperand = x;
+
+ if (direction)
+ {
+ if (DetermineMaxOut(incrementVariableOperand, incrementValueOperand, loop, out var end))
+ {
+ if (!signed)
+ {
+ var start = startOperand.ConstantUnsigned64;
+
+ trace?.Log($"{result}");
+ result.BitValue.NarrowMin(start).NarrowMax((ulong)end);
+
+ trace?.Log($"{result} Start = {start}");
+ trace?.Log($"{result} End = {end}");
+ trace?.Log($"{result.BitValue}");
+
+ RangeDetermined.Increment();
+ }
+ else
+ {
+ var start = startOperand.ConstantSigned64;
- trace?.Log($"{result} MinValue = {x.ConstantUnsigned64}");
- MinDetermined.Increment();
+ trace?.Log($"{result}");
+ result.BitValue.NarrowSignRange(start, end);
- if (DetermineMaxOut(d.Operand1, d.Operand2, loop, out var max))
+ trace?.Log($"{result} Start = {start}");
+ trace?.Log($"{result} End = {end}");
+ trace?.Log($"{result.BitValue}");
+
+ RangeDetermined.Increment();
+ }
+ }
+ }
+ else
{
- result.BitValue.NarrowMax((ulong)max);
+ if (DetermineMinOut(incrementVariableOperand, incrementValueOperand, loop, out var end))
+ {
+ if (!signed)
+ {
+ var start = startOperand.ConstantUnsigned64;
+
+ trace?.Log($"{result}");
+ result.BitValue.NarrowMax(start).NarrowMin((ulong)end);
+
+ trace?.Log($"** Start = {start}");
+ trace?.Log($"** End = {end}");
+ trace?.Log($"{result.BitValue}");
+
+ RangeDetermined.Increment();
+ }
+ else
+ {
+ var start = startOperand.ConstantSigned64;
- trace?.Log($"{result} MaxValue = {max}");
- MaxDetermined.Increment();
+ trace?.Log($"{result}");
+ result.BitValue.NarrowSignRange(start, end);
+
+ trace?.Log($"** Start = {start}");
+ trace?.Log($"** End = {end}");
+ trace?.Log($"{result.BitValue}");
+
+ RangeDetermined.Increment();
+ }
+ }
}
}
+ private enum SignAnalysis
+ { Unknown, Signed, NotSigned, Both };
+
+ private static SignAnalysis DetermineSignUsage(Operand value)
+ {
+ var signAnalysis = SignAnalysis.Unknown;
+
+ foreach (var use in value.Uses)
+ {
+ if (!(use.Instruction == IR.Branch32 || use.Instruction == IR.Branch64))
+ continue;
+
+ var condition = use.ConditionCode;
+ var signed = condition.IsSigned();
+
+ if (signAnalysis == SignAnalysis.Unknown)
+ {
+ signAnalysis = signed ? SignAnalysis.Signed : SignAnalysis.NotSigned;
+ }
+ else
+ {
+ if (signed && signAnalysis == SignAnalysis.Signed)
+ continue;
+
+ if (!signed && signAnalysis == SignAnalysis.NotSigned)
+ continue;
+
+ return SignAnalysis.Both;
+ }
+ }
+
+ return signAnalysis;
+ }
+
private static bool DetermineMaxOut(Operand incrementVariable, Operand incrementValue, Loop loop, out long max)
{
- bool determined = false;
+ var determined = false;
max = long.MaxValue;
- foreach (var b in incrementVariable.Uses)
+ // limit to increament values that can not cause overflow
+ if (incrementValue.IsInt32 && (incrementValue.ConstantSigned32 >= short.MaxValue - 1 || incrementValue.ConstantSigned32 <= short.MinValue + 1))
+ return false;
+
+ if (!incrementValue.IsInt32 && (incrementValue.ConstantSigned64 >= short.MaxValue - 1 || incrementValue.ConstantSigned64 <= short.MinValue + 1))
+ return false;
+
+ foreach (var use in incrementVariable.Uses)
{
- if (!(b.Instruction == IR.Branch32 || b.Instruction == IR.Branch64))
+ if (!(use.Instruction == IR.Branch32 || use.Instruction == IR.Branch64))
continue;
- // only that are the header or backedge (if only one)
- if (!(b.Block == loop.Header || (loop.Backedges.Count == 1 && loop.Backedges.Contains(b.Block))))
+ // only analysis the header or backedge (if only one)
+ if (!(use.Block == loop.Header || (loop.Backedges.Count == 1 && loop.Backedges.Contains(use.Block))))
continue;
- var x = b.Operand1;
- var y = b.Operand2;
- var condition = b.ConditionCode;
- var target = b.BranchTarget1;
- var othertarget = target != b.Block.NextBlocks[0]
- ? b.Block.NextBlocks[0]
- : b.Block.NextBlocks[1];
+ var x = use.Operand1;
+ var y = use.Operand2;
+ var condition = use.ConditionCode;
+ var target = use.BranchTarget1;
+ var othertarget = target != use.Block.NextBlocks[0]
+ ? use.Block.NextBlocks[0]
+ : use.Block.NextBlocks[1];
+
+ // form: x (variable) {>,>=,==} y (constant) -> where branch exits loop
- // form: x (variable) <=/== y (constant) -> where branch exits the loop
+ // change form - on branch
+ if (loop.LoopBlocks.Contains(target))
+ {
+ (condition, target, othertarget) = (condition.GetOpposite(), othertarget, target);
+ }
+
+ // change form - on constant to right
+ if (!y.IsResolvedConstant && (condition == ConditionCode.Equal || condition == ConditionCode.NotEqual))
+ {
+ (x, y) = (y, x);
+ }
// change form - on condition
- if (condition is not (ConditionCode.Less
- or ConditionCode.LessOrEqual
- or ConditionCode.UnsignedLess
- or ConditionCode.UnsignedLessOrEqual
- or ConditionCode.Equal))
+ if (!y.IsResolvedConstant)
{
(x, y, condition) = (y, x, condition.GetOpposite()); // swap
}
+ if (condition is not (
+ ConditionCode.Greater
+ or ConditionCode.GreaterOrEqual
+ or ConditionCode.UnsignedGreater
+ or ConditionCode.UnsignedGreaterOrEqual))
+ continue;
+
+ if (condition == ConditionCode.NotEqual && !incrementValue.IsConstantOne)
+ continue;
+
+ if (condition == ConditionCode.Equal)
+ continue;
+
+ if (x != incrementVariable)
+ continue;
+
+ if (!y.IsResolvedConstant)
+ continue;
+
+ Debug.Assert(y.IsInt32 == incrementValue.IsInt32);
+
+ if (y.IsInt32 && (y.ConstantSigned32 >= short.MaxValue - 1 || y.ConstantSigned32 <= short.MinValue + 1))
+ continue;
+
+ if (!y.IsInt32 && (y.ConstantSigned64 >= short.MaxValue - 1 || y.ConstantSigned64 <= short.MinValue + 1))
+ continue;
+
+ var adj = condition == ConditionCode.GreaterOrEqual
+ || condition == ConditionCode.UnsignedGreaterOrEqual ? 0 : 1;
+
+ var value = y.IsInt32
+ ? y.ConstantSigned32 + incrementValue.ConstantSigned32 + adj
+ : y.ConstantSigned64 + incrementValue.ConstantSigned64 + adj;
+
+ max = Math.Min(max, value);
+
+ determined = true;
+ }
+
+ return determined;
+ }
+
+ private static bool DetermineMinOut(Operand incrementVariable, Operand incrementValue, Loop loop, out long min)
+ {
+ var determined = false;
+ min = long.MinValue;
+
+ // limit to increament values that can not cause overflow
+ if (incrementValue.IsInt32 && (incrementValue.ConstantSigned32 >= short.MaxValue - 1 || incrementValue.ConstantSigned32 <= short.MinValue + 1))
+ return false;
+
+ if (!incrementValue.IsInt32 && (incrementValue.ConstantSigned64 >= short.MaxValue - 1 || incrementValue.ConstantSigned64 <= short.MinValue + 1))
+ return false;
+
+ foreach (var use in incrementVariable.Uses)
+ {
+ if (!(use.Instruction == IR.Branch32 || use.Instruction == IR.Branch64))
+ continue;
+
+ // only analysis the header or backedge (if only one)
+ if (!(use.Block == loop.Header || (loop.Backedges.Count == 1 && loop.Backedges.Contains(use.Block))))
+ continue;
+
+ var x = use.Operand1;
+ var y = use.Operand2;
+ var condition = use.ConditionCode;
+ var target = use.BranchTarget1;
+ var othertarget = target != use.Block.NextBlocks[0]
+ ? use.Block.NextBlocks[0]
+ : use.Block.NextBlocks[1];
+
+ // form: x (variable) {<,<=,==} y (constant) -> where branch exits the loop
+
// change form - on branch
- if (!loop.LoopBlocks.Contains(target))
+ 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)
+ if (!y.IsResolvedConstant && (condition == ConditionCode.Equal || condition == ConditionCode.NotEqual))
{
(x, y) = (y, x);
}
- if (condition is not (ConditionCode.Less
+ // change form - on condition
+ if (!y.IsResolvedConstant)
+ {
+ (x, y, condition) = (y, x, condition.GetOpposite()); // swap
+ }
+
+ if (condition is not (
+ ConditionCode.Less
or ConditionCode.LessOrEqual
or ConditionCode.UnsignedLess
- or ConditionCode.UnsignedLessOrEqual
- or ConditionCode.Equal))
+ or ConditionCode.UnsignedLessOrEqual))
+ continue;
+
+ if (condition == ConditionCode.NotEqual && !incrementValue.IsConstantOne)
+ continue;
+
+ if (condition == ConditionCode.Equal)
continue;
if (x != incrementVariable)
@@ -202,14 +408,22 @@ or ConditionCode.UnsignedLessOrEqual
if (!y.IsResolvedConstant)
continue;
- if (!loop.LoopBlocks.Contains(target))
- continue; // exits loop
+ Debug.Assert(y.IsInt32 == incrementValue.IsInt32);
+
+ if (y.IsInt32 && (y.ConstantSigned32 >= short.MaxValue - 1 || y.ConstantSigned32 <= short.MinValue + 1))
+ continue;
+
+ if (!y.IsInt32 && (y.ConstantSigned64 >= short.MaxValue - 1 || y.ConstantSigned64 <= short.MinValue + 1))
+ continue;
- var adj = condition == ConditionCode.LessOrEqual || condition == ConditionCode.Equal ? 1 : 0;
+ var adj = condition == ConditionCode.LessOrEqual
+ || condition == ConditionCode.UnsignedLessOrEqual ? 1 : 0;
- var branchmax = y.ConstantSigned64 + incrementValue.ConstantSigned64 - 1 + adj;
+ var value = y.IsInt32
+ ? y.ConstantSigned32 + incrementValue.ConstantSigned32 + adj
+ : y.ConstantSigned64 + incrementValue.ConstantSigned64 + adj;
- max = Math.Min(max, branchmax);
+ min = Math.Max(min, value);
determined = true;
}
diff --git a/Source/Mosa.Compiler.Framework/Transform.cs b/Source/Mosa.Compiler.Framework/Transform.cs
index 24faf16c71..e1f71185d4 100644
--- a/Source/Mosa.Compiler.Framework/Transform.cs
+++ b/Source/Mosa.Compiler.Framework/Transform.cs
@@ -259,6 +259,24 @@ public void TraceAfter(Context context)
TraceLog?.Log();
}
+ public void TraceBefore(BaseBlockTransform transformation, BasicBlock block)
+ {
+ TraceLog?.Log($"{TotalTransformCount,-7}\t| {transformation.Name}");
+
+ if (transformation.Log)
+ SpecialTraceLog?.Log($"{transformation.Name}\t{Method.FullName}");
+
+ TraceLog?.Log($"{block}\t| {transformation.Name}");
+
+ TotalTransformCount++;
+ }
+
+ public void TraceAfter(BaseBlockTransform transformation)
+ {
+ TraceLog?.Log($" \t| {transformation.Name}");
+ TraceLog?.Log();
+ }
+
#endregion Trace
#region Basic Block Helpers
diff --git a/Source/Mosa.Compiler.Framework/Transforms/BasicBlocks/MergeBlocks.cs b/Source/Mosa.Compiler.Framework/Transforms/BasicBlocks/MergeBlocks.cs
index 8f7649fe96..46a09bf3d1 100644
--- a/Source/Mosa.Compiler.Framework/Transforms/BasicBlocks/MergeBlocks.cs
+++ b/Source/Mosa.Compiler.Framework/Transforms/BasicBlocks/MergeBlocks.cs
@@ -49,6 +49,8 @@ public override int Process(Transform transform)
trace?.Log($"Merge Blocking: {block} with: {next}");
+ transform.TraceBefore(this, block);
+
if (isInSSAForm)
{
PhiHelper.UpdatePhiTargets(next.NextBlocks, next, block);
@@ -68,6 +70,8 @@ public override int Process(Transform transform)
insertPoint.MoveFrom(next.AfterFirst.ForwardToNonEmpty, next.Last.Previous.BackwardsToNonEmpty);
emptied++;
changed = true;
+
+ transform.TraceAfter(this);
}
}
diff --git a/Source/Mosa.UnitTests/Optimization/LoopRange.cs b/Source/Mosa.UnitTests/Optimization/LoopRange.cs
new file mode 100644
index 0000000000..98901f6dad
--- /dev/null
+++ b/Source/Mosa.UnitTests/Optimization/LoopRange.cs
@@ -0,0 +1,690 @@
+// Copyright (c) MOSA Project. Licensed under the New BSD License.
+
+namespace Mosa.UnitTests.Basic;
+
+public static class LoopRange
+{
+ [MosaUnitTest]
+ public static int LoopIncreasing1()
+ {
+ var start = 0;
+ var end = 10;
+ var exit = 8;
+ var a = 0;
+
+ for (var i = start; i < end; i++)
+ {
+ a += i;
+
+ if (i > exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static int LoopIncreasing2()
+ {
+ var start = 0;
+ var end = 10;
+ var exit = 9;
+ var a = 0;
+
+ for (var i = start; i < end; i++)
+ {
+ a += i;
+
+ if (i > exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static int LoopIncreasing3()
+ {
+ var start = 0;
+ var end = 10;
+ var exit = 10;
+ var a = 0;
+
+ for (var i = start; i < end; i++)
+ {
+ a += i;
+
+ if (i > exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static int LoopIncreasing4()
+ {
+ var start = 0;
+ var end = 10;
+ var exit = 11;
+ var a = 0;
+
+ for (var i = start; i < end; i++)
+ {
+ a += i;
+
+ if (i > exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static int LoopIncreasing1b()
+ {
+ var start = 0;
+ var end = 10;
+ var exit = 8;
+ var a = 0;
+
+ for (var i = start; i <= end; i++)
+ {
+ a += i;
+
+ if (i > exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static int LoopIncreasing2b()
+ {
+ var start = 0;
+ var end = 10;
+ var exit = 9;
+ var a = 0;
+
+ for (var i = start; i <= end; i++)
+ {
+ a += i;
+
+ if (i > exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static int LoopIncreasing3b()
+ {
+ var start = 0;
+ var end = 10;
+ var exit = 10;
+ var a = 0;
+
+ for (var i = start; i <= end; i++)
+ {
+ a += i;
+
+ if (i > exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static int LoopIncreasing4b()
+ {
+ var start = 0;
+ var end = 10;
+ var exit = 11;
+ var a = 0;
+
+ for (var i = start; i <= end; i++)
+ {
+ a += i;
+
+ if (i > exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static uint LoopIncreasing1u()
+ {
+ var start = 0u;
+ var end = 10u;
+ var exit = 8u;
+ var a = 0u;
+
+ for (var i = start; i < end; i++)
+ {
+ a += i;
+
+ if (i > exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static uint LoopIncreasing2u()
+ {
+ var start = 0u;
+ var end = 10u;
+ var exit = 9u;
+ var a = 0u;
+
+ for (var i = start; i < end; i++)
+ {
+ a += i;
+
+ if (i > exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static uint LoopIncreasing3u()
+ {
+ var start = 0u;
+ var end = 10u;
+ var exit = 10u;
+ var a = 0u;
+
+ for (var i = start; i < end; i++)
+ {
+ a += i;
+
+ if (i > exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static uint LoopIncreasing4u()
+ {
+ var start = 0u;
+ var end = 10u;
+ var exit = 11u;
+ var a = 0u;
+
+ for (var i = start; i < end; i++)
+ {
+ a += i;
+
+ if (i > exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static uint LoopIncreasing1bu()
+ {
+ var start = 0u;
+ var end = 10u;
+ var exit = 8u;
+ var a = 0u;
+
+ for (var i = start; i <= end; i++)
+ {
+ a += i;
+
+ if (i > exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static uint LoopIncreasing2bu()
+ {
+ var start = 0u;
+ var end = 10u;
+ var exit = 9u;
+ var a = 0u;
+
+ for (var i = start; i <= end; i++)
+ {
+ a += i;
+
+ if (i > exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static uint LoopIncreasing3bu()
+ {
+ var start = 0u;
+ var end = 10u;
+ var exit = 10u;
+ var a = 0u;
+
+ for (var i = start; i <= end; i++)
+ {
+ a += i;
+
+ if (i > exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static uint LoopIncreasing4bu()
+ {
+ var start = 0u;
+ var end = 10u;
+ var exit = 11u;
+ var a = 0u;
+
+ for (var i = start; i <= end; i++)
+ {
+ a += i;
+
+ if (i > exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static int LoopDecreasing1()
+ {
+ var start = 10;
+ var end = 0;
+ var exit = 10;
+ var a = 0;
+
+ for (var i = start; i > end; i--)
+ {
+ a += i;
+
+ if (i < exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static int LoopDecreasing2()
+ {
+ var start = 10;
+ var end = 0;
+ var exit = 9;
+ var a = 0;
+
+ for (var i = start; i > end; i--)
+ {
+ a += i;
+
+ if (i < exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static int LoopDecreasing3()
+ {
+ var start = 10;
+ var end = 0;
+ var exit = 0;
+ var a = 0;
+
+ for (var i = start; i > end; i--)
+ {
+ a += i;
+
+ if (i < exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static int LoopDecreasing4()
+ {
+ var start = 10;
+ var end = 0;
+ var exit = -1;
+ var a = 0;
+
+ for (var i = start; i > end; i--)
+ {
+ a += i;
+
+ if (i < exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static int LoopDecreasing1b()
+ {
+ var start = 10;
+ var end = 0;
+ var exit = 10;
+ var a = 0;
+
+ for (var i = start; i >= end; i--)
+ {
+ a += i;
+
+ if (i < exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static int LoopDecreasing2b()
+ {
+ var start = 10;
+ var end = 0;
+ var exit = 9;
+ var a = 0;
+
+ for (var i = start; i >= end; i--)
+ {
+ a += i;
+
+ if (i < exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static int LoopDecreasing3b()
+ {
+ var start = 10;
+ var end = 0;
+ var exit = 0;
+ var a = 0;
+
+ for (var i = start; i >= end; i--)
+ {
+ a += i;
+
+ if (i < exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static int LoopDecreasing4b()
+ {
+ var start = 10;
+ var end = 0;
+ var exit = -1;
+ var a = 0;
+
+ for (var i = start; i >= end; i--)
+ {
+ a += i;
+
+ if (i < exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static uint LoopDecreasing1u()
+ {
+ var start = 10u;
+ var end = 0u;
+ var exit = 8u;
+ var a = 0u;
+
+ for (var i = start; i > end; i--)
+ {
+ a += i;
+
+ if (i < exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static uint LoopDecreasing2u()
+ {
+ var start = 10u;
+ var end = 0u;
+ var exit = 9u;
+ var a = 0u;
+
+ for (var i = start; i > end; i--)
+ {
+ a += i;
+
+ if (i < exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static uint LoopDecreasing3u()
+ {
+ var start = 10u;
+ var end = 0u;
+ var exit = 0u;
+ var a = 0u;
+
+ for (var i = start; i > end; i--)
+ {
+ a += i;
+
+ if (i < exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static uint LoopDecreasing4u()
+ {
+ var start = 10u;
+ var end = 0u;
+ var exit = 11u;
+ var a = 11u;
+
+ for (var i = start; i > end; i--)
+ {
+ a += i;
+
+ if (i < exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static uint LoopDecreasing1bu()
+ {
+ var start = 10u;
+ var end = 0u;
+ var exit = 10u;
+ var a = 0u;
+
+ for (var i = start; i >= end; i--)
+ {
+ a += i;
+
+ if (i < exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static uint LoopDecreasing2bu()
+ {
+ var start = 10u;
+ var end = 0u;
+ var exit = 9u;
+ var a = 0u;
+
+ for (var i = start; i >= end; i--)
+ {
+ a += i;
+
+ if (i < exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static uint LoopDecreasing3bu()
+ {
+ var start = 10u;
+ var end = 0u;
+ var exit = 1u;
+ var a = 0u;
+
+ for (var i = start; i >= end; i--)
+ {
+ a += i;
+
+ if (i < exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static uint LoopDecreasing4bu()
+ {
+ var start = 10u;
+ var end = 1u;
+ var exit = 11u;
+ var a = 0u;
+
+ for (var i = start; i >= end; i--)
+ {
+ a += i;
+
+ if (i < exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static int LoopDecreasing3bxx()
+ {
+ var start = 10;
+ var end = 0;
+ var exit = 10;
+ var a = 0;
+
+ for (var i = start; i >= end; i--)
+ {
+ a += i;
+
+ if (i > exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static int LoopDecreasing4bxx()
+ {
+ var start = 10;
+ var end = 0;
+ var exit = 11;
+ var a = 0;
+
+ for (var i = start; i >= end; i--)
+ {
+ a += i;
+
+ if (i > exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static uint LoopDecreasing3buxx()
+ {
+ var start = 10u;
+ var end = 0u;
+ var exit = 10u;
+ var a = 0u;
+
+ for (var i = start; i >= end; i--)
+ {
+ a += i;
+
+ if (i > exit)
+ return 0;
+ }
+
+ return a;
+ }
+
+ [MosaUnitTest]
+ public static uint LoopDecreasing4buxx()
+ {
+ var start = 10u;
+ var end = 0u;
+ var exit = 11u;
+ var a = 0u;
+
+ for (var i = start; i >= end; i--)
+ {
+ a += i;
+
+ if (i > exit)
+ return 0;
+ }
+
+ return a;
+ }
+}
diff --git a/Source/Mosa.Utility.UnitTests/Mosa.Utility.UnitTests.csproj b/Source/Mosa.Utility.UnitTests/Mosa.Utility.UnitTests.csproj
index 60c72fb0f6..14b34108bd 100644
--- a/Source/Mosa.Utility.UnitTests/Mosa.Utility.UnitTests.csproj
+++ b/Source/Mosa.Utility.UnitTests/Mosa.Utility.UnitTests.csproj
@@ -51,7 +51,8 @@
-
+
+
diff --git a/Source/Mosa.sln b/Source/Mosa.sln
index c0f1757be4..96f56a44c5 100644
--- a/Source/Mosa.sln
+++ b/Source/Mosa.sln
@@ -176,12 +176,15 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Documentation", "Documentat
Docs\compiler-transformations.rst = Docs\compiler-transformations.rst
Docs\conf.py = Docs\conf.py
Docs\contents.txt = Docs\contents.txt
+ Docs\create-operating-system.rst = Docs\create-operating-system.rst
Docs\demos.rst = Docs\demos.rst
Docs\faq.rst = Docs\faq.rst
Docs\get-involved.rst = Docs\get-involved.rst
+ Docs\getting-started.rst = Docs\getting-started.rst
Docs\index.rst = Docs\index.rst
Docs\introduction.rst = Docs\introduction.rst
Docs\license.rst = Docs\license.rst
+ Docs\mosa-project-structure.rst = Docs\mosa-project-structure.rst
Docs\mosa-runtime-tables.dot = Docs\mosa-runtime-tables.dot
Docs\runtime-tables.rst = Docs\runtime-tables.rst
Docs\settings-options.rst = Docs\settings-options.rst
@@ -192,9 +195,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Documentation", "Documentat
Docs\tool-launcher.rst = Docs\tool-launcher.rst
Docs\unit-tests.rst = Docs\unit-tests.rst
Docs\usb-flash-drive-installation.rst = Docs\usb-flash-drive-installation.rst
- Docs\create-operating-system.rst = Docs\create-operating-system.rst
- Docs\mosa-project-structure.rst = Docs\mosa-project-structure.rst
- Docs\getting-started.rst = Docs\getting-started.rst
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mosa.Utility.Disassembler", "Mosa.Utility.Disassembler\Mosa.Utility.Disassembler.csproj", "{E45FBA9E-6F57-4511-8977-D8045DE09622}"
@@ -247,6 +247,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mosa.Kernel.BareMetal.Intel
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mosa.BareMetal.TestWorld.ARM32", "Mosa.BareMetal.TestWorld.ARM32\Mosa.BareMetal.TestWorld.ARM32.csproj", "{26667157-E909-4F7A-9130-F8B5C15A1E4E}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Template", "Template", "{A1660856-2153-477F-BAAC-39E8BEB75971}"
+ ProjectSection(SolutionItems) = preProject
+ TemplateLibrary.txt = TemplateLibrary.txt
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -1506,6 +1511,7 @@ Global
{282FA278-D577-48BC-93BD-214519F3AB28} = {3A538FDC-0226-4971-A3C0-31570CDA340D}
{E94607AB-584E-4D15-B0FA-68E086FE9E70} = {75BB6B40-C122-422F-8B40-F50A70A08E0D}
{26667157-E909-4F7A-9130-F8B5C15A1E4E} = {3A538FDC-0226-4971-A3C0-31570CDA340D}
+ {A1660856-2153-477F-BAAC-39E8BEB75971} = {F0EFF742-92D5-4219-939A-8F6F8DAB24E5}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C22A5C94-6B05-4B1B-845A-A2EA7615E093}