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) 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}