From ca803c975d9f3235664b631a6bab8d8ce601e156 Mon Sep 17 00:00:00 2001 From: ike709 Date: Mon, 28 Oct 2024 14:22:01 -0500 Subject: [PATCH 01/10] Refactor the PeepholeOptimizer into arbitrary passes --- DMCompiler/Optimizer/BytecodeOptimizer.cs | 7 +- .../Optimizer/CompactorOptimizations.cs | 366 ++++++++++++++++++ DMCompiler/Optimizer/PeepholeOptimizations.cs | 355 ----------------- DMCompiler/Optimizer/PeepholeOptimizer.cs | 38 +- 4 files changed, 399 insertions(+), 367 deletions(-) create mode 100644 DMCompiler/Optimizer/CompactorOptimizations.cs diff --git a/DMCompiler/Optimizer/BytecodeOptimizer.cs b/DMCompiler/Optimizer/BytecodeOptimizer.cs index 8b1eca71d0..6d5f58baf6 100644 --- a/DMCompiler/Optimizer/BytecodeOptimizer.cs +++ b/DMCompiler/Optimizer/BytecodeOptimizer.cs @@ -11,7 +11,12 @@ public List Optimize(List input) { RemoveUnreferencedLabels(input); JoinAndForwardLabels(input); RemoveUnreferencedLabels(input); - PeepholeOptimizer.RunPeephole(input); + + // The order of these passes matter, as later passes depend on opcodes created by prior passes + PeepholeOptimizer.RunOptimizations(input); + PeepholeOptimizer.RunOptimizations(input); + PeepholeOptimizer.RunOptimizations(input); + return input; } diff --git a/DMCompiler/Optimizer/CompactorOptimizations.cs b/DMCompiler/Optimizer/CompactorOptimizations.cs new file mode 100644 index 0000000000..aca95ee23d --- /dev/null +++ b/DMCompiler/Optimizer/CompactorOptimizations.cs @@ -0,0 +1,366 @@ +using DMCompiler.Bytecode; + +namespace DMCompiler.Optimizer; + +#region BytecodeCompactors + +// PushString [string] +// ... +// PushString [string] +// -> PushNStrings [count] [string] ... [string] +internal sealed class PushNStrings : IBytecodeCompactor { + public ReadOnlySpan GetOpcodes() { + return [ + DreamProcOpcode.PushString, + DreamProcOpcode.PushString + ]; + } + + public void Apply(List input, int index) { + int count = 0; + int stackDelta = 0; + + while (index + count < input.Count && + input[index + count] is AnnotatedBytecodeInstruction { Opcode: DreamProcOpcode.PushString }) { + count++; + } + + List args = new List(count + 1); + args.Add(new AnnotatedBytecodeInteger(count, new Location())); + + for (int i = 0; i < count; i++) { + AnnotatedBytecodeInstruction instruction = (AnnotatedBytecodeInstruction)(input[index + i]); + args.Add(instruction.GetArg(0)); + stackDelta++; + } + + input.RemoveRange(index, count); + input.Insert(index, new AnnotatedBytecodeInstruction(DreamProcOpcode.PushNStrings, stackDelta, args)); + } +} + +// PushFloat [float] +// ... +// PushFloat [float] +// -> PushNFloats [count] [float] ... [float] +internal sealed class PushNFloats : IBytecodeCompactor { + public ReadOnlySpan GetOpcodes() { + return [ + DreamProcOpcode.PushFloat, + DreamProcOpcode.PushFloat + ]; + } + + public void Apply(List input, int index) { + int count = 0; + int stackDelta = 0; + + while (index + count < input.Count && + input[index + count] is AnnotatedBytecodeInstruction { Opcode: DreamProcOpcode.PushFloat }) { + count++; + } + + List args = new List(count + 1); + args.Add(new AnnotatedBytecodeInteger(count, new Location())); + + for (int i = 0; i < count; i++) { + AnnotatedBytecodeInstruction instruction = (AnnotatedBytecodeInstruction)(input[index + i]); + args.Add(instruction.GetArg(0)); + stackDelta++; + } + + input.RemoveRange(index, count); + input.Insert(index, new AnnotatedBytecodeInstruction(DreamProcOpcode.PushNFloats, stackDelta, args)); + } +} + +// PushReferenceValue [ref] +// ... +// PushReferenceValue [ref] +// -> PushNRef [count] [ref] ... [ref] +internal sealed class PushNRef : IBytecodeCompactor { + public ReadOnlySpan GetOpcodes() { + return [ + DreamProcOpcode.PushReferenceValue, + DreamProcOpcode.PushReferenceValue + ]; + } + + public void Apply(List input, int index) { + int count = 0; + int stackDelta = 0; + + while (index + count < input.Count && + input[index + count] is AnnotatedBytecodeInstruction { Opcode: DreamProcOpcode.PushReferenceValue }) { + count++; + } + + List args = new List(count + 1); + args.Add(new AnnotatedBytecodeInteger(count, new Location())); + + for (int i = 0; i < count; i++) { + AnnotatedBytecodeInstruction instruction = (AnnotatedBytecodeInstruction)(input[index + i]); + args.Add(instruction.GetArg(0)); + stackDelta++; + } + + input.RemoveRange(index, count); + input.Insert(index, new AnnotatedBytecodeInstruction(DreamProcOpcode.PushNRefs, stackDelta, args)); + } +} + +// PushString [string] +// PushFloat [float] +// -> PushStringFloat [string] [float] +// or if there's multiple +// -> PushNOfStringFloat [count] [string] [float] ... [string] [float] +internal sealed class PushStringFloat : IBytecodeCompactor { + public ReadOnlySpan GetOpcodes() { + return [ + DreamProcOpcode.PushString, + DreamProcOpcode.PushFloat + ]; + } + + public void Apply(List input, int index) { + if (index + 1 >= input.Count) { + throw new ArgumentOutOfRangeException(nameof(index), "Index plus one is outside the bounds of the input list."); + } + + int count = 0; + while (index + count*2 + 1 < input.Count && + input[index + count * 2] is AnnotatedBytecodeInstruction { Opcode: DreamProcOpcode.PushString } && input[index + count * 2 + 1] is AnnotatedBytecodeInstruction { Opcode: DreamProcOpcode.PushFloat }) { + count++; + } + + // If the pattern only occurs once, replace with PushStringFloat and return + if (count == 1) { + AnnotatedBytecodeInstruction firstInstruction = (AnnotatedBytecodeInstruction)(input[index]); + AnnotatedBytecodeInstruction secondInstruction = (AnnotatedBytecodeInstruction)(input[index + 1]); + AnnotatedBytecodeString pushVal1 = firstInstruction.GetArg(0); + AnnotatedBytecodeFloat pushVal2 = secondInstruction.GetArg(0); + + input.RemoveRange(index, 2); + input.Insert(index, new AnnotatedBytecodeInstruction(DreamProcOpcode.PushStringFloat, [pushVal1, pushVal2])); + return; + } + + // Otherwise, replace with PushNOfStringFloat + + int stackDelta = 0; + List args = new List(2 * count + 1) { new AnnotatedBytecodeInteger(count, input[index].GetLocation()) }; + + for (int i = 0; i < count; i++) { + AnnotatedBytecodeInstruction stringInstruction = (AnnotatedBytecodeInstruction)(input[index + i*2]); + AnnotatedBytecodeInstruction floatInstruction = (AnnotatedBytecodeInstruction)(input[index + i*2 + 1]); + args.Add(stringInstruction.GetArg(0)); + args.Add(floatInstruction.GetArg(0)); + stackDelta += 2; + } + + input.RemoveRange(index, count * 2); + input.Insert(index, new AnnotatedBytecodeInstruction(DreamProcOpcode.PushNOfStringFloats, stackDelta, args)); + } +} + +// PushResource [resource] +// ... +// PushResource [resource] +// -> PushNResources [count] [resource] ... [resource] +internal sealed class PushNResources : IBytecodeCompactor { + public ReadOnlySpan GetOpcodes() { + return [ + DreamProcOpcode.PushResource, + DreamProcOpcode.PushResource + ]; + } + + public void Apply(List input, int index) { + int count = 0; + int stackDelta = 0; + while (index + count < input.Count && + input[index + count] is AnnotatedBytecodeInstruction { Opcode: DreamProcOpcode.PushResource }) { + count++; + } + + List args = new List(count + 1); + args.Add(new AnnotatedBytecodeInteger(count, new Location())); + + for (int i = 0; i < count; i++) { + AnnotatedBytecodeInstruction instruction = (AnnotatedBytecodeInstruction)(input[index + i]); + args.Add(instruction.GetArg(0)); + stackDelta++; + } + + input.RemoveRange(index, count); + input.Insert(index, new AnnotatedBytecodeInstruction(DreamProcOpcode.PushNResources, stackDelta, args)); + } +} + +#endregion + +#region ListCompactors + +// PushNFloats [count] [float] ... [float] +// CreateList [count] +// -> CreateListNFloats [count] [float] ... [float] +internal sealed class CreateListNFloats : IListCompactor { + public ReadOnlySpan GetOpcodes() { + return [ + DreamProcOpcode.PushNFloats, + DreamProcOpcode.CreateList + ]; + } + + public bool CheckPreconditions(List input, int index) { + if (index + 1 >= input.Count) { + throw new ArgumentOutOfRangeException(nameof(index), "Index plus one is outside the bounds of the input list."); + } + + AnnotatedBytecodeInstruction firstInstruction = (AnnotatedBytecodeInstruction)(input[index]); + AnnotatedBytecodeInstruction secondInstruction = (AnnotatedBytecodeInstruction)(input[index + 1]); + int pushVal1 = firstInstruction.GetArg(0).Value; + int pushVal2 = secondInstruction.GetArg(0).Size; + + return pushVal1 == pushVal2; + } + + public void Apply(List input, int index) { + if (index + 1 >= input.Count) { + throw new ArgumentOutOfRangeException(nameof(index), "Index plus one is outside the bounds of the input list."); + } + + AnnotatedBytecodeInstruction firstInstruction = (AnnotatedBytecodeInstruction)(input[index]); + int pushVal1 = firstInstruction.GetArg(0).Value; + + List args = new List(pushVal1 + 1); + args.Add(new AnnotatedBytecodeInteger(pushVal1, new Location())); + args.AddRange(firstInstruction.GetArgs()[1..(pushVal1+1)]); + + input.RemoveRange(index, 2); + input.Insert(index, new AnnotatedBytecodeInstruction(DreamProcOpcode.CreateListNFloats, 1, args)); + } +} + +// PushNStrings [count] [string] ... [string] +// CreateList [count] +// -> CreateListNStrings [count] [string] ... [string] +internal sealed class CreateListNStrings : IListCompactor { + public ReadOnlySpan GetOpcodes() { + return [ + DreamProcOpcode.PushNStrings, + DreamProcOpcode.CreateList + ]; + } + + public bool CheckPreconditions(List input, int index) { + if (index + 1 >= input.Count) { + throw new ArgumentOutOfRangeException(nameof(index), "Index plus one is outside the bounds of the input list."); + } + + AnnotatedBytecodeInstruction firstInstruction = (AnnotatedBytecodeInstruction)(input[index]); + AnnotatedBytecodeInstruction secondInstruction = (AnnotatedBytecodeInstruction)(input[index + 1]); + int pushVal1 = firstInstruction.GetArg(0).Value; + int pushVal2 = secondInstruction.GetArg(0).Size; + + return pushVal1 == pushVal2; + } + + public void Apply(List input, int index) { + if (index + 1 >= input.Count) { + throw new ArgumentOutOfRangeException(nameof(index), "Index plus one is outside the bounds of the input list."); + } + + AnnotatedBytecodeInstruction firstInstruction = (AnnotatedBytecodeInstruction)(input[index]); + int pushVal1 = firstInstruction.GetArg(0).Value; + + List args = new List(pushVal1 + 1); + args.Add(new AnnotatedBytecodeInteger(pushVal1, new Location())); + args.AddRange(firstInstruction.GetArgs()[1..(pushVal1+1)]); + + input.RemoveRange(index, 2); + input.Insert(index, new AnnotatedBytecodeInstruction(DreamProcOpcode.CreateListNStrings, 1, args)); + } +} + +// PushNResources [count] [resource] ... [resource] +// CreateList [count] +// -> CreateListNResources [count] [resource] ... [resource] +internal sealed class CreateListNResources : IListCompactor { + public ReadOnlySpan GetOpcodes() { + return [ + DreamProcOpcode.PushNResources, + DreamProcOpcode.CreateList + ]; + } + + public bool CheckPreconditions(List input, int index) { + if (index + 1 >= input.Count) { + throw new ArgumentOutOfRangeException(nameof(index), "Index plus one is outside the bounds of the input list."); + } + + AnnotatedBytecodeInstruction firstInstruction = (AnnotatedBytecodeInstruction)(input[index]); + AnnotatedBytecodeInstruction secondInstruction = (AnnotatedBytecodeInstruction)(input[index + 1]); + int pushVal1 = firstInstruction.GetArg(0).Value; + int pushVal2 = secondInstruction.GetArg(0).Size; + + return pushVal1 == pushVal2; + } + + public void Apply(List input, int index) { + if (index + 1 >= input.Count) { + throw new ArgumentOutOfRangeException(nameof(index), "Index plus one is outside the bounds of the input list."); + } + + AnnotatedBytecodeInstruction firstInstruction = (AnnotatedBytecodeInstruction)(input[index]); + int pushVal1 = firstInstruction.GetArg(0).Value; + + List args = new List(pushVal1 + 1); + args.Add(new AnnotatedBytecodeInteger(pushVal1, new Location())); + args.AddRange(firstInstruction.GetArgs()[1..(pushVal1+1)]); + + input.RemoveRange(index, 2); + input.Insert(index, new AnnotatedBytecodeInstruction(DreamProcOpcode.CreateListNResources, 1, args)); + } +} + +// PushNRefs [count] [ref] ... [ref] +// CreateList [count] +// -> CreateListNRefs [count] [ref] ... [ref] +internal sealed class CreateListNRefs : IListCompactor { + public ReadOnlySpan GetOpcodes() { + return [ + DreamProcOpcode.PushNRefs, + DreamProcOpcode.CreateList + ]; + } + + public bool CheckPreconditions(List input, int index) { + if (index + 1 >= input.Count) { + throw new ArgumentOutOfRangeException(nameof(index),"Bytecode index is outside the bounds of the input list."); + } + + int pushVal1 = ((AnnotatedBytecodeInstruction)input[index]).GetArg(0).Value; + int pushVal2 = ((AnnotatedBytecodeInstruction)input[index + 1]).GetArg(0).Size; + + return pushVal1 == pushVal2; + } + + public void Apply(List input, int index) { + if (index + 1 >= input.Count) { + throw new ArgumentOutOfRangeException(nameof(index), "Bytecode index is outside the bounds of the input list."); + } + + var firstInstruction = (AnnotatedBytecodeInstruction)(input[index]); + int pushVal1 = firstInstruction.GetArg(0).Value; + + List args = new List(1 + pushVal1); + args.Add(new AnnotatedBytecodeInteger(pushVal1, new Location())); + args.AddRange(firstInstruction.GetArgs()[1..(pushVal1+1)]); + + input.RemoveRange(index, 2); + input.Insert(index, new AnnotatedBytecodeInstruction(DreamProcOpcode.CreateListNRefs, 1, args)); + } +} + +#endregion diff --git a/DMCompiler/Optimizer/PeepholeOptimizations.cs b/DMCompiler/Optimizer/PeepholeOptimizations.cs index 72446f68b8..6571c390f3 100644 --- a/DMCompiler/Optimizer/PeepholeOptimizations.cs +++ b/DMCompiler/Optimizer/PeepholeOptimizations.cs @@ -170,165 +170,6 @@ public void Apply(List input, int index) { } } -// PushString [string] -// ... -// PushString [string] -// -> PushNStrings [count] [string] ... [string] -internal sealed class PushNStrings : IPeepholeOptimization { - public ReadOnlySpan GetOpcodes() { - return [ - DreamProcOpcode.PushString, - DreamProcOpcode.PushString - ]; - } - - public void Apply(List input, int index) { - int count = 0; - int stackDelta = 0; - - while (index + count < input.Count && - input[index + count] is AnnotatedBytecodeInstruction { Opcode: DreamProcOpcode.PushString }) { - count++; - } - - List args = new List(count + 1); - args.Add(new AnnotatedBytecodeInteger(count, new Location())); - - for (int i = 0; i < count; i++) { - AnnotatedBytecodeInstruction instruction = (AnnotatedBytecodeInstruction)(input[index + i]); - args.Add(instruction.GetArg(0)); - stackDelta++; - } - - input.RemoveRange(index, count); - input.Insert(index, new AnnotatedBytecodeInstruction(DreamProcOpcode.PushNStrings, stackDelta, args)); - } -} - -// PushFloat [float] -// ... -// PushFloat [float] -// -> PushNFloats [count] [float] ... [float] -internal sealed class PushNFloats : IPeepholeOptimization { - public ReadOnlySpan GetOpcodes() { - return [ - DreamProcOpcode.PushFloat, - DreamProcOpcode.PushFloat - ]; - } - - public void Apply(List input, int index) { - int count = 0; - int stackDelta = 0; - - while (index + count < input.Count && - input[index + count] is AnnotatedBytecodeInstruction { Opcode: DreamProcOpcode.PushFloat }) { - count++; - } - - List args = new List(count + 1); - args.Add(new AnnotatedBytecodeInteger(count, new Location())); - - for (int i = 0; i < count; i++) { - AnnotatedBytecodeInstruction instruction = (AnnotatedBytecodeInstruction)(input[index + i]); - args.Add(instruction.GetArg(0)); - stackDelta++; - } - - input.RemoveRange(index, count); - input.Insert(index, new AnnotatedBytecodeInstruction(DreamProcOpcode.PushNFloats, stackDelta, args)); - } -} - -// PushReferenceValue [ref] -// ... -// PushReferenceValue [ref] -// -> PushNRef [count] [ref] ... [ref] -internal sealed class PushNRef : IPeepholeOptimization { - public ReadOnlySpan GetOpcodes() { - return [ - DreamProcOpcode.PushReferenceValue, - DreamProcOpcode.PushReferenceValue - ]; - } - - public void Apply(List input, int index) { - int count = 0; - int stackDelta = 0; - - while (index + count < input.Count && - input[index + count] is AnnotatedBytecodeInstruction { Opcode: DreamProcOpcode.PushReferenceValue }) { - count++; - } - - List args = new List(count + 1); - args.Add(new AnnotatedBytecodeInteger(count, new Location())); - - for (int i = 0; i < count; i++) { - AnnotatedBytecodeInstruction instruction = (AnnotatedBytecodeInstruction)(input[index + i]); - args.Add(instruction.GetArg(0)); - stackDelta++; - } - - input.RemoveRange(index, count); - input.Insert(index, new AnnotatedBytecodeInstruction(DreamProcOpcode.PushNRefs, stackDelta, args)); - } -} - -// PushString [string] -// PushFloat [float] -// -> PushStringFloat [string] [float] -// or if there's multiple -// -> PushNOfStringFloat [count] [string] [float] ... [string] [float] -internal sealed class PushStringFloat : IPeepholeOptimization { - public ReadOnlySpan GetOpcodes() { - return [ - DreamProcOpcode.PushString, - DreamProcOpcode.PushFloat - ]; - } - - public void Apply(List input, int index) { - if (index + 1 >= input.Count) { - throw new ArgumentOutOfRangeException(nameof(index), "Index plus one is outside the bounds of the input list."); - } - - int count = 0; - while (index + count*2 + 1 < input.Count && - input[index + count * 2] is AnnotatedBytecodeInstruction { Opcode: DreamProcOpcode.PushString } && input[index + count * 2 + 1] is AnnotatedBytecodeInstruction { Opcode: DreamProcOpcode.PushFloat }) { - count++; - } - - // If the pattern only occurs once, replace with PushStringFloat and return - if (count == 1) { - AnnotatedBytecodeInstruction firstInstruction = (AnnotatedBytecodeInstruction)(input[index]); - AnnotatedBytecodeInstruction secondInstruction = (AnnotatedBytecodeInstruction)(input[index + 1]); - AnnotatedBytecodeString pushVal1 = firstInstruction.GetArg(0); - AnnotatedBytecodeFloat pushVal2 = secondInstruction.GetArg(0); - - input.RemoveRange(index, 2); - input.Insert(index, new AnnotatedBytecodeInstruction(DreamProcOpcode.PushStringFloat, [pushVal1, pushVal2])); - return; - } - - // Otherwise, replace with PushNOfStringFloat - - int stackDelta = 0; - List args = new List(2 * count + 1) { new AnnotatedBytecodeInteger(count, input[index].GetLocation()) }; - - for (int i = 0; i < count; i++) { - AnnotatedBytecodeInstruction stringInstruction = (AnnotatedBytecodeInstruction)(input[index + i*2]); - AnnotatedBytecodeInstruction floatInstruction = (AnnotatedBytecodeInstruction)(input[index + i*2 + 1]); - args.Add(stringInstruction.GetArg(0)); - args.Add(floatInstruction.GetArg(0)); - stackDelta += 2; - } - - input.RemoveRange(index, count * 2); - input.Insert(index, new AnnotatedBytecodeInstruction(DreamProcOpcode.PushNOfStringFloats, stackDelta, args)); - } -} - // PushFloat [float] // SwitchCase [label] // -> SwitchOnFloat [float] [label] @@ -381,202 +222,6 @@ public void Apply(List input, int index) { } } -// PushResource [resource] -// ... -// PushResource [resource] -// -> PushNResources [count] [resource] ... [resource] -internal sealed class PushNResources : IPeepholeOptimization { - public ReadOnlySpan GetOpcodes() { - return [ - DreamProcOpcode.PushResource, - DreamProcOpcode.PushResource - ]; - } - - public void Apply(List input, int index) { - int count = 0; - int stackDelta = 0; - while (index + count < input.Count && - input[index + count] is AnnotatedBytecodeInstruction { Opcode: DreamProcOpcode.PushResource }) { - count++; - } - - List args = new List(count + 1); - args.Add(new AnnotatedBytecodeInteger(count, new Location())); - - for (int i = 0; i < count; i++) { - AnnotatedBytecodeInstruction instruction = (AnnotatedBytecodeInstruction)(input[index + i]); - args.Add(instruction.GetArg(0)); - stackDelta++; - } - - input.RemoveRange(index, count); - input.Insert(index, new AnnotatedBytecodeInstruction(DreamProcOpcode.PushNResources, stackDelta, args)); - } -} - -// PushNFloats [count] [float] ... [float] -// CreateList [count] -// -> CreateListNFloats [count] [float] ... [float] -internal sealed class CreateListNFloats : IPeepholeOptimization { - public ReadOnlySpan GetOpcodes() { - return [ - DreamProcOpcode.PushNFloats, - DreamProcOpcode.CreateList - ]; - } - - public bool CheckPreconditions(List input, int index) { - if (index + 1 >= input.Count) { - throw new ArgumentOutOfRangeException(nameof(index), "Index plus one is outside the bounds of the input list."); - } - - AnnotatedBytecodeInstruction firstInstruction = (AnnotatedBytecodeInstruction)(input[index]); - AnnotatedBytecodeInstruction secondInstruction = (AnnotatedBytecodeInstruction)(input[index + 1]); - int pushVal1 = firstInstruction.GetArg(0).Value; - int pushVal2 = secondInstruction.GetArg(0).Size; - - return pushVal1 == pushVal2; - } - - public void Apply(List input, int index) { - if (index + 1 >= input.Count) { - throw new ArgumentOutOfRangeException(nameof(index), "Index plus one is outside the bounds of the input list."); - } - - AnnotatedBytecodeInstruction firstInstruction = (AnnotatedBytecodeInstruction)(input[index]); - int pushVal1 = firstInstruction.GetArg(0).Value; - - List args = new List(pushVal1 + 1); - args.Add(new AnnotatedBytecodeInteger(pushVal1, new Location())); - args.AddRange(firstInstruction.GetArgs()[1..(pushVal1+1)]); - - input.RemoveRange(index, 2); - input.Insert(index, new AnnotatedBytecodeInstruction(DreamProcOpcode.CreateListNFloats, 1, args)); - } -} - -// PushNStrings [count] [string] ... [string] -// CreateList [count] -// -> CreateListNStrings [count] [string] ... [string] -internal sealed class CreateListNStrings : IPeepholeOptimization { - public ReadOnlySpan GetOpcodes() { - return [ - DreamProcOpcode.PushNStrings, - DreamProcOpcode.CreateList - ]; - } - - public bool CheckPreconditions(List input, int index) { - if (index + 1 >= input.Count) { - throw new ArgumentOutOfRangeException(nameof(index), "Index plus one is outside the bounds of the input list."); - } - - AnnotatedBytecodeInstruction firstInstruction = (AnnotatedBytecodeInstruction)(input[index]); - AnnotatedBytecodeInstruction secondInstruction = (AnnotatedBytecodeInstruction)(input[index + 1]); - int pushVal1 = firstInstruction.GetArg(0).Value; - int pushVal2 = secondInstruction.GetArg(0).Size; - - return pushVal1 == pushVal2; - } - - public void Apply(List input, int index) { - if (index + 1 >= input.Count) { - throw new ArgumentOutOfRangeException(nameof(index), "Index plus one is outside the bounds of the input list."); - } - - AnnotatedBytecodeInstruction firstInstruction = (AnnotatedBytecodeInstruction)(input[index]); - int pushVal1 = firstInstruction.GetArg(0).Value; - - List args = new List(pushVal1 + 1); - args.Add(new AnnotatedBytecodeInteger(pushVal1, new Location())); - args.AddRange(firstInstruction.GetArgs()[1..(pushVal1+1)]); - - input.RemoveRange(index, 2); - input.Insert(index, new AnnotatedBytecodeInstruction(DreamProcOpcode.CreateListNStrings, 1, args)); - } -} - -// PushNResources [count] [resource] ... [resource] -// CreateList [count] -// -> CreateListNResources [count] [resource] ... [resource] -internal sealed class CreateListNResources : IPeepholeOptimization { - public ReadOnlySpan GetOpcodes() { - return [ - DreamProcOpcode.PushNResources, - DreamProcOpcode.CreateList - ]; - } - - public bool CheckPreconditions(List input, int index) { - if (index + 1 >= input.Count) { - throw new ArgumentOutOfRangeException(nameof(index), "Index plus one is outside the bounds of the input list."); - } - - AnnotatedBytecodeInstruction firstInstruction = (AnnotatedBytecodeInstruction)(input[index]); - AnnotatedBytecodeInstruction secondInstruction = (AnnotatedBytecodeInstruction)(input[index + 1]); - int pushVal1 = firstInstruction.GetArg(0).Value; - int pushVal2 = secondInstruction.GetArg(0).Size; - - return pushVal1 == pushVal2; - } - - public void Apply(List input, int index) { - if (index + 1 >= input.Count) { - throw new ArgumentOutOfRangeException(nameof(index), "Index plus one is outside the bounds of the input list."); - } - - AnnotatedBytecodeInstruction firstInstruction = (AnnotatedBytecodeInstruction)(input[index]); - int pushVal1 = firstInstruction.GetArg(0).Value; - - List args = new List(pushVal1 + 1); - args.Add(new AnnotatedBytecodeInteger(pushVal1, new Location())); - args.AddRange(firstInstruction.GetArgs()[1..(pushVal1+1)]); - - input.RemoveRange(index, 2); - input.Insert(index, new AnnotatedBytecodeInstruction(DreamProcOpcode.CreateListNResources, 1, args)); - } -} - -// PushNRefs [count] [ref] ... [ref] -// CreateList [count] -// -> CreateListNRefs [count] [ref] ... [ref] -internal sealed class CreateListNRefs : IPeepholeOptimization { - public ReadOnlySpan GetOpcodes() { - return [ - DreamProcOpcode.PushNRefs, - DreamProcOpcode.CreateList - ]; - } - - public bool CheckPreconditions(List input, int index) { - if (index + 1 >= input.Count) { - throw new ArgumentOutOfRangeException(nameof(index),"Bytecode index is outside the bounds of the input list."); - } - - int pushVal1 = ((AnnotatedBytecodeInstruction)input[index]).GetArg(0).Value; - int pushVal2 = ((AnnotatedBytecodeInstruction)input[index + 1]).GetArg(0).Size; - - return pushVal1 == pushVal2; - } - - public void Apply(List input, int index) { - if (index + 1 >= input.Count) { - throw new ArgumentOutOfRangeException(nameof(index), "Bytecode index is outside the bounds of the input list."); - } - - var firstInstruction = (AnnotatedBytecodeInstruction)(input[index]); - int pushVal1 = firstInstruction.GetArg(0).Value; - - List args = new List(1 + pushVal1); - args.Add(new AnnotatedBytecodeInteger(pushVal1, new Location())); - args.AddRange(firstInstruction.GetArgs()[1..(pushVal1+1)]); - - input.RemoveRange(index, 2); - input.Insert(index, new AnnotatedBytecodeInstruction(DreamProcOpcode.CreateListNRefs, 1, args)); - } -} - // Jump [label1] // Jump [label2] <- Dead code // -> Jump [label1] diff --git a/DMCompiler/Optimizer/PeepholeOptimizer.cs b/DMCompiler/Optimizer/PeepholeOptimizer.cs index a7f8588389..7e8f55372e 100644 --- a/DMCompiler/Optimizer/PeepholeOptimizer.cs +++ b/DMCompiler/Optimizer/PeepholeOptimizer.cs @@ -3,7 +3,10 @@ namespace DMCompiler.Optimizer; -internal interface IPeepholeOptimization { +/// +/// Every interface that inherits IOptimization can be executed as a separate peephole optimizer pass +/// +internal interface IOptimization { public ReadOnlySpan GetOpcodes(); public void Apply(List input, int index); @@ -25,9 +28,24 @@ public static void ReplaceInstructions(List input, int index } } -internal sealed class PeepholeOptimizer { +/// +/// First-pass peephole optimizations (e.g. const folding) +/// +internal interface IPeepholeOptimization : IOptimization; + +/// +/// Next-pass bytecode compacting (e.g. PushNFloats and other PushN opcodes) +/// +internal interface IBytecodeCompactor : IOptimization; + +/// +/// Final-pass list compacting (e.g. PushNFloats & CreateList -> CreateListNFloats) +/// +internal interface IListCompactor : IOptimization; + +internal sealed class PeepholeOptimizer where T : class, IOptimization { private class OptimizationTreeEntry { - public IPeepholeOptimization? Optimization; + public T? Optimization; public Dictionary? Children; } @@ -38,19 +56,17 @@ private class OptimizationTreeEntry { /// Setup static PeepholeOptimizer() { - var possibleTypes = typeof(PeepholeOptimizer).Assembly.GetTypes(); - var optimizationTypes = new List(possibleTypes.Length); + var possibleTypes = typeof(T).Assembly.GetTypes(); + var optimizationTypes = new List(); + foreach (var type in possibleTypes) { - if (typeof(IPeepholeOptimization).IsAssignableFrom(type)) { + if (typeof(T).IsAssignableFrom(type) && type.IsClass && !type.IsAbstract) { optimizationTypes.Add(type); } } foreach (var optType in optimizationTypes) { - if (optType.IsInterface || optType.IsAbstract) - continue; - - var opt = (IPeepholeOptimization)(Activator.CreateInstance(optType))!; + var opt = (T)(Activator.CreateInstance(optType)!); var opcodes = opt.GetOpcodes(); if (opcodes.Length < 2) { DMCompiler.ForcedError(Location.Internal, $"Peephole optimization {optType} must have at least 2 opcodes"); @@ -81,7 +97,7 @@ static PeepholeOptimizer() { } } - public static void RunPeephole(List input) { + public static void RunOptimizations(List input) { OptimizationTreeEntry? currentOpt = null; int optSize = 0; From 03e6d51cb38ee46bb40080671d05be53c999339c Mon Sep 17 00:00:00 2001 From: ike709 Date: Mon, 28 Oct 2024 16:04:33 -0500 Subject: [PATCH 02/10] address resharper --- .../Optimizer/CompactorOptimizations.cs | 24 +++++++------------ DMCompiler/Optimizer/PeepholeOptimizations.cs | 2 ++ DMCompiler/Optimizer/PeepholeOptimizer.cs | 3 ++- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/DMCompiler/Optimizer/CompactorOptimizations.cs b/DMCompiler/Optimizer/CompactorOptimizations.cs index aca95ee23d..dc5ee3f4ba 100644 --- a/DMCompiler/Optimizer/CompactorOptimizations.cs +++ b/DMCompiler/Optimizer/CompactorOptimizations.cs @@ -25,8 +25,7 @@ public void Apply(List input, int index) { count++; } - List args = new List(count + 1); - args.Add(new AnnotatedBytecodeInteger(count, new Location())); + List args = new List(count + 1) { new AnnotatedBytecodeInteger(count, new Location()) }; for (int i = 0; i < count; i++) { AnnotatedBytecodeInstruction instruction = (AnnotatedBytecodeInstruction)(input[index + i]); @@ -60,8 +59,7 @@ public void Apply(List input, int index) { count++; } - List args = new List(count + 1); - args.Add(new AnnotatedBytecodeInteger(count, new Location())); + List args = new List(count + 1) { new AnnotatedBytecodeInteger(count, new Location()) }; for (int i = 0; i < count; i++) { AnnotatedBytecodeInstruction instruction = (AnnotatedBytecodeInstruction)(input[index + i]); @@ -95,8 +93,7 @@ public void Apply(List input, int index) { count++; } - List args = new List(count + 1); - args.Add(new AnnotatedBytecodeInteger(count, new Location())); + List args = new List(count + 1) { new AnnotatedBytecodeInteger(count, new Location()) }; for (int i = 0; i < count; i++) { AnnotatedBytecodeInstruction instruction = (AnnotatedBytecodeInstruction)(input[index + i]); @@ -183,8 +180,7 @@ public void Apply(List input, int index) { count++; } - List args = new List(count + 1); - args.Add(new AnnotatedBytecodeInteger(count, new Location())); + List args = new List(count + 1) { new AnnotatedBytecodeInteger(count, new Location()) }; for (int i = 0; i < count; i++) { AnnotatedBytecodeInstruction instruction = (AnnotatedBytecodeInstruction)(input[index + i]); @@ -233,8 +229,7 @@ public void Apply(List input, int index) { AnnotatedBytecodeInstruction firstInstruction = (AnnotatedBytecodeInstruction)(input[index]); int pushVal1 = firstInstruction.GetArg(0).Value; - List args = new List(pushVal1 + 1); - args.Add(new AnnotatedBytecodeInteger(pushVal1, new Location())); + List args = new List(pushVal1 + 1) { new AnnotatedBytecodeInteger(pushVal1, new Location()) }; args.AddRange(firstInstruction.GetArgs()[1..(pushVal1+1)]); input.RemoveRange(index, 2); @@ -274,8 +269,7 @@ public void Apply(List input, int index) { AnnotatedBytecodeInstruction firstInstruction = (AnnotatedBytecodeInstruction)(input[index]); int pushVal1 = firstInstruction.GetArg(0).Value; - List args = new List(pushVal1 + 1); - args.Add(new AnnotatedBytecodeInteger(pushVal1, new Location())); + List args = new List(pushVal1 + 1) { new AnnotatedBytecodeInteger(pushVal1, new Location()) }; args.AddRange(firstInstruction.GetArgs()[1..(pushVal1+1)]); input.RemoveRange(index, 2); @@ -315,8 +309,7 @@ public void Apply(List input, int index) { AnnotatedBytecodeInstruction firstInstruction = (AnnotatedBytecodeInstruction)(input[index]); int pushVal1 = firstInstruction.GetArg(0).Value; - List args = new List(pushVal1 + 1); - args.Add(new AnnotatedBytecodeInteger(pushVal1, new Location())); + List args = new List(pushVal1 + 1) { new AnnotatedBytecodeInteger(pushVal1, new Location()) }; args.AddRange(firstInstruction.GetArgs()[1..(pushVal1+1)]); input.RemoveRange(index, 2); @@ -354,8 +347,7 @@ public void Apply(List input, int index) { var firstInstruction = (AnnotatedBytecodeInstruction)(input[index]); int pushVal1 = firstInstruction.GetArg(0).Value; - List args = new List(1 + pushVal1); - args.Add(new AnnotatedBytecodeInteger(pushVal1, new Location())); + List args = new List(1 + pushVal1) { new AnnotatedBytecodeInteger(pushVal1, new Location()) }; args.AddRange(firstInstruction.GetArgs()[1..(pushVal1+1)]); input.RemoveRange(index, 2); diff --git a/DMCompiler/Optimizer/PeepholeOptimizations.cs b/DMCompiler/Optimizer/PeepholeOptimizations.cs index 6571c390f3..3cf78600ec 100644 --- a/DMCompiler/Optimizer/PeepholeOptimizations.cs +++ b/DMCompiler/Optimizer/PeepholeOptimizations.cs @@ -263,6 +263,7 @@ public void Apply(List input, int index) { } #region Constant Folding + // PushFloat [constant] // PushFloat [constant] // Multiply @@ -420,4 +421,5 @@ public void Apply(List input, int index) { new AnnotatedBytecodeInstruction(DreamProcOpcode.PushFloat, 1, args)); } } + #endregion diff --git a/DMCompiler/Optimizer/PeepholeOptimizer.cs b/DMCompiler/Optimizer/PeepholeOptimizer.cs index 7e8f55372e..4dcb4ef8ee 100644 --- a/DMCompiler/Optimizer/PeepholeOptimizer.cs +++ b/DMCompiler/Optimizer/PeepholeOptimizer.cs @@ -43,6 +43,7 @@ internal interface IBytecodeCompactor : IOptimization; /// internal interface IListCompactor : IOptimization; +// ReSharper disable once ClassNeverInstantiated.Global internal sealed class PeepholeOptimizer where T : class, IOptimization { private class OptimizationTreeEntry { public T? Optimization; @@ -60,7 +61,7 @@ static PeepholeOptimizer() { var optimizationTypes = new List(); foreach (var type in possibleTypes) { - if (typeof(T).IsAssignableFrom(type) && type.IsClass && !type.IsAbstract) { + if (typeof(T).IsAssignableFrom(type) && type is { IsClass: true, IsAbstract: false }) { optimizationTypes.Add(type); } } From 92b809a0199f9edfcff43b183a554067c8bba97c Mon Sep 17 00:00:00 2001 From: ike709 Date: Thu, 7 Nov 2024 05:23:59 -0600 Subject: [PATCH 03/10] address reviews --- DMCompiler/Optimizer/BytecodeOptimizer.cs | 5 +- .../Optimizer/CompactorOptimizations.cs | 38 +++-- DMCompiler/Optimizer/PeepholeOptimizations.cs | 130 ++++++++++++------ DMCompiler/Optimizer/PeepholeOptimizer.cs | 57 ++++---- 4 files changed, 148 insertions(+), 82 deletions(-) diff --git a/DMCompiler/Optimizer/BytecodeOptimizer.cs b/DMCompiler/Optimizer/BytecodeOptimizer.cs index 6d5f58baf6..d1bae822fe 100644 --- a/DMCompiler/Optimizer/BytecodeOptimizer.cs +++ b/DMCompiler/Optimizer/BytecodeOptimizer.cs @@ -12,10 +12,7 @@ public List Optimize(List input) { JoinAndForwardLabels(input); RemoveUnreferencedLabels(input); - // The order of these passes matter, as later passes depend on opcodes created by prior passes - PeepholeOptimizer.RunOptimizations(input); - PeepholeOptimizer.RunOptimizations(input); - PeepholeOptimizer.RunOptimizations(input); + PeepholeOptimizer.RunOptimizations(input); return input; } diff --git a/DMCompiler/Optimizer/CompactorOptimizations.cs b/DMCompiler/Optimizer/CompactorOptimizations.cs index dc5ee3f4ba..bde1fe89b6 100644 --- a/DMCompiler/Optimizer/CompactorOptimizations.cs +++ b/DMCompiler/Optimizer/CompactorOptimizations.cs @@ -1,5 +1,7 @@ using DMCompiler.Bytecode; +// ReSharper disable UnusedType.Global + namespace DMCompiler.Optimizer; #region BytecodeCompactors @@ -8,7 +10,9 @@ namespace DMCompiler.Optimizer; // ... // PushString [string] // -> PushNStrings [count] [string] ... [string] -internal sealed class PushNStrings : IBytecodeCompactor { +internal sealed class PushNStrings : IOptimization { + public OptPass OptimizationPass => OptPass.BytecodeCompactor; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.PushString, @@ -42,7 +46,9 @@ public void Apply(List input, int index) { // ... // PushFloat [float] // -> PushNFloats [count] [float] ... [float] -internal sealed class PushNFloats : IBytecodeCompactor { +internal sealed class PushNFloats : IOptimization { + public OptPass OptimizationPass => OptPass.BytecodeCompactor; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.PushFloat, @@ -76,7 +82,9 @@ public void Apply(List input, int index) { // ... // PushReferenceValue [ref] // -> PushNRef [count] [ref] ... [ref] -internal sealed class PushNRef : IBytecodeCompactor { +internal sealed class PushNRef : IOptimization { + public OptPass OptimizationPass => OptPass.BytecodeCompactor; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.PushReferenceValue, @@ -111,7 +119,9 @@ public void Apply(List input, int index) { // -> PushStringFloat [string] [float] // or if there's multiple // -> PushNOfStringFloat [count] [string] [float] ... [string] [float] -internal sealed class PushStringFloat : IBytecodeCompactor { +internal sealed class PushStringFloat : IOptimization { + public OptPass OptimizationPass => OptPass.BytecodeCompactor; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.PushString, @@ -164,7 +174,9 @@ public void Apply(List input, int index) { // ... // PushResource [resource] // -> PushNResources [count] [resource] ... [resource] -internal sealed class PushNResources : IBytecodeCompactor { +internal sealed class PushNResources : IOptimization { + public OptPass OptimizationPass => OptPass.BytecodeCompactor; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.PushResource, @@ -200,7 +212,9 @@ public void Apply(List input, int index) { // PushNFloats [count] [float] ... [float] // CreateList [count] // -> CreateListNFloats [count] [float] ... [float] -internal sealed class CreateListNFloats : IListCompactor { +internal sealed class CreateListNFloats : IOptimization { + public OptPass OptimizationPass => OptPass.ListCompactor; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.PushNFloats, @@ -240,7 +254,9 @@ public void Apply(List input, int index) { // PushNStrings [count] [string] ... [string] // CreateList [count] // -> CreateListNStrings [count] [string] ... [string] -internal sealed class CreateListNStrings : IListCompactor { +internal sealed class CreateListNStrings : IOptimization { + public OptPass OptimizationPass => OptPass.ListCompactor; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.PushNStrings, @@ -280,7 +296,9 @@ public void Apply(List input, int index) { // PushNResources [count] [resource] ... [resource] // CreateList [count] // -> CreateListNResources [count] [resource] ... [resource] -internal sealed class CreateListNResources : IListCompactor { +internal sealed class CreateListNResources : IOptimization { + public OptPass OptimizationPass => OptPass.ListCompactor; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.PushNResources, @@ -320,7 +338,9 @@ public void Apply(List input, int index) { // PushNRefs [count] [ref] ... [ref] // CreateList [count] // -> CreateListNRefs [count] [ref] ... [ref] -internal sealed class CreateListNRefs : IListCompactor { +internal sealed class CreateListNRefs : IOptimization { + public OptPass OptimizationPass => OptPass.ListCompactor; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.PushNRefs, diff --git a/DMCompiler/Optimizer/PeepholeOptimizations.cs b/DMCompiler/Optimizer/PeepholeOptimizations.cs index 0a8eb12d5d..7b47d92041 100644 --- a/DMCompiler/Optimizer/PeepholeOptimizations.cs +++ b/DMCompiler/Optimizer/PeepholeOptimizations.cs @@ -1,11 +1,15 @@ using DMCompiler.Bytecode; +// ReSharper disable UnusedType.Global + namespace DMCompiler.Optimizer; // Append [ref] // Pop // -> AppendNoPush [ref] -internal sealed class AppendNoPush : IPeepholeOptimization { +internal sealed class AppendNoPush : IOptimization { + public OptPass OptimizationPass => OptPass.PeepholeOptimization; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.Append, @@ -29,7 +33,9 @@ public void Apply(List input, int index) { // Assign [ref] // Pop // -> AssignNoPush [ref] -internal sealed class AssignNoPush : IPeepholeOptimization { +internal sealed class AssignNoPush : IOptimization { + public OptPass OptimizationPass => OptPass.PeepholeOptimization; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.Assign, @@ -53,7 +59,9 @@ public void Apply(List input, int index) { // PushNull // AssignNoPush [ref] // -> AssignNull [ref] -internal sealed class AssignNull : IPeepholeOptimization { +internal sealed class AssignNull : IOptimization { + public OptPass OptimizationPass => OptPass.PeepholeOptimization; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.PushNull, @@ -82,7 +90,9 @@ public void Apply(List input, int index) { // PushReferenceValue [ref] // DereferenceField [field] // -> PushRefAndDereferenceField [ref, field] -internal sealed class PushField : IPeepholeOptimization { +internal sealed class PushField : IOptimization { + public OptPass OptimizationPass => OptPass.PeepholeOptimization; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.PushReferenceValue, @@ -109,7 +119,9 @@ public void Apply(List input, int index) { // PushReferenceValue [ref] // Return // -> ReturnReferenceValue [ref] -internal class ReturnReferenceValue : IPeepholeOptimization { +internal class ReturnReferenceValue : IOptimization { + public OptPass OptimizationPass => OptPass.PeepholeOptimization; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.PushReferenceValue, @@ -128,7 +140,9 @@ public void Apply(List input, int index) { // PushFloat [float] // Return // -> ReturnFloat [float] -internal class ReturnFloat : IPeepholeOptimization { +internal class ReturnFloat : IOptimization { + public OptPass OptimizationPass => OptPass.PeepholeOptimization; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.PushFloat, @@ -137,8 +151,8 @@ public ReadOnlySpan GetOpcodes() { } public void Apply(List input, int index) { - var firstInstruction = IPeepholeOptimization.GetInstructionAndValue(input[index], out var pushVal); - IPeepholeOptimization.ReplaceInstructions(input, index, 2, + var firstInstruction = IOptimization.GetInstructionAndValue(input[index], out var pushVal); + IOptimization.ReplaceInstructions(input, index, 2, new AnnotatedBytecodeInstruction(DreamProcOpcode.ReturnFloat, [new AnnotatedBytecodeFloat(pushVal, firstInstruction.Location)])); } } @@ -146,7 +160,9 @@ public void Apply(List input, int index) { // PushReferenceValue [ref] // JumpIfFalse [label] // -> JumpIfReferenceFalse [ref] [label] -internal sealed class JumpIfReferenceFalse : IPeepholeOptimization { +internal sealed class JumpIfReferenceFalse : IOptimization { + public OptPass OptimizationPass => OptPass.PeepholeOptimization; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.PushReferenceValue, @@ -173,7 +189,9 @@ public void Apply(List input, int index) { // PushFloat [float] // SwitchCase [label] // -> SwitchOnFloat [float] [label] -internal sealed class SwitchOnFloat : IPeepholeOptimization { +internal sealed class SwitchOnFloat : IOptimization { + public OptPass OptimizationPass => OptPass.PeepholeOptimization; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.PushFloat, @@ -199,7 +217,9 @@ public void Apply(List input, int index) { // PushString [string] // SwitchCase [label] // -> SwitchOnString [string] [label] -internal sealed class SwitchOnString : IPeepholeOptimization { +internal sealed class SwitchOnString : IOptimization { + public OptPass OptimizationPass => OptPass.PeepholeOptimization; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.PushString, @@ -225,7 +245,9 @@ public void Apply(List input, int index) { // Jump [label1] // Jump [label2] <- Dead code // -> Jump [label1] -internal sealed class RemoveJumpFollowedByJump : IPeepholeOptimization { +internal sealed class RemoveJumpFollowedByJump : IOptimization { + public OptPass OptimizationPass => OptPass.PeepholeOptimization; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.Jump, @@ -241,7 +263,9 @@ public void Apply(List input, int index) { // PushType [type] // IsType // -> IsTypeDirect [type] -internal sealed class IsTypeDirect : IPeepholeOptimization { +internal sealed class IsTypeDirect : IOptimization { + public OptPass OptimizationPass => OptPass.PeepholeOptimization; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.PushType, @@ -268,7 +292,9 @@ public void Apply(List input, int index) { // PushFloat [constant] // Multiply // -> PushFloat [result] -internal sealed class ConstFoldMultiply : IPeepholeOptimization { +internal sealed class ConstFoldMultiply : IOptimization { + public OptPass OptimizationPass => OptPass.PeepholeOptimization; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.PushFloat, @@ -278,13 +304,13 @@ public ReadOnlySpan GetOpcodes() { } public void Apply(List input, int index) { - var firstInstruction = IPeepholeOptimization.GetInstructionAndValue(input[index], out var pushVal1); + var firstInstruction = IOptimization.GetInstructionAndValue(input[index], out var pushVal1); - IPeepholeOptimization.GetInstructionAndValue(input[index + 1], out var pushVal2); + IOptimization.GetInstructionAndValue(input[index + 1], out var pushVal2); var args = new List(1) {new AnnotatedBytecodeFloat(pushVal1 * pushVal2, firstInstruction.Location)}; - IPeepholeOptimization.ReplaceInstructions(input, index, 3, + IOptimization.ReplaceInstructions(input, index, 3, new AnnotatedBytecodeInstruction(DreamProcOpcode.PushFloat, 1, args)); } } @@ -293,7 +319,9 @@ public void Apply(List input, int index) { // PushFloat [constant] // Divide // -> PushFloat [result] -internal sealed class ConstFoldDivide : IPeepholeOptimization { +internal sealed class ConstFoldDivide : IOptimization { + public OptPass OptimizationPass => OptPass.PeepholeOptimization; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.PushFloat, @@ -303,15 +331,15 @@ public ReadOnlySpan GetOpcodes() { } public void Apply(List input, int index) { - var firstInstruction = IPeepholeOptimization.GetInstructionAndValue(input[index], out var pushVal1); + var firstInstruction = IOptimization.GetInstructionAndValue(input[index], out var pushVal1); - IPeepholeOptimization.GetInstructionAndValue(input[index + 1], out var pushVal2); + IOptimization.GetInstructionAndValue(input[index + 1], out var pushVal2); // At runtime, given "A / B" we pop B then A // In the peephole optimizer, index is "A", index+1 is "B" var args = new List(1) {new AnnotatedBytecodeFloat(pushVal1 / pushVal2, firstInstruction.Location)}; - IPeepholeOptimization.ReplaceInstructions(input, index, 3, + IOptimization.ReplaceInstructions(input, index, 3, new AnnotatedBytecodeInstruction(DreamProcOpcode.PushFloat, 1, args)); } } @@ -320,7 +348,9 @@ public void Apply(List input, int index) { // PushFloat [constant] // Add // -> PushFloat [result] -internal sealed class ConstFoldAdd : IPeepholeOptimization { +internal sealed class ConstFoldAdd : IOptimization { + public OptPass OptimizationPass => OptPass.PeepholeOptimization; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.PushFloat, @@ -330,13 +360,13 @@ public ReadOnlySpan GetOpcodes() { } public void Apply(List input, int index) { - var firstInstruction = IPeepholeOptimization.GetInstructionAndValue(input[index], out var pushVal1); + var firstInstruction = IOptimization.GetInstructionAndValue(input[index], out var pushVal1); - IPeepholeOptimization.GetInstructionAndValue(input[index + 1], out var pushVal2); + IOptimization.GetInstructionAndValue(input[index + 1], out var pushVal2); var args = new List(1) {new AnnotatedBytecodeFloat(pushVal1 + pushVal2, firstInstruction.Location)}; - IPeepholeOptimization.ReplaceInstructions(input, index, 3, + IOptimization.ReplaceInstructions(input, index, 3, new AnnotatedBytecodeInstruction(DreamProcOpcode.PushFloat, 1, args)); } } @@ -345,7 +375,9 @@ public void Apply(List input, int index) { // PushFloat [constant] // Subtract // -> PushFloat [result] -internal sealed class ConstFoldSubtract : IPeepholeOptimization { +internal sealed class ConstFoldSubtract : IOptimization { + public OptPass OptimizationPass => OptPass.PeepholeOptimization; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.PushFloat, @@ -355,15 +387,15 @@ public ReadOnlySpan GetOpcodes() { } public void Apply(List input, int index) { - var firstInstruction = IPeepholeOptimization.GetInstructionAndValue(input[index], out var pushVal1); + var firstInstruction = IOptimization.GetInstructionAndValue(input[index], out var pushVal1); - IPeepholeOptimization.GetInstructionAndValue(input[index + 1], out var pushVal2); + IOptimization.GetInstructionAndValue(input[index + 1], out var pushVal2); // At runtime, given "A - B" we pop B then A // In the peephole optimizer, index is "A", index+1 is "B" var args = new List(1) {new AnnotatedBytecodeFloat(pushVal1 - pushVal2, firstInstruction.Location)}; - IPeepholeOptimization.ReplaceInstructions(input, index, 3, + IOptimization.ReplaceInstructions(input, index, 3, new AnnotatedBytecodeInstruction(DreamProcOpcode.PushFloat, 1, args)); } } @@ -372,7 +404,9 @@ public void Apply(List input, int index) { // PushFloat [constant] // Modulus // -> PushFloat [result] -internal sealed class ConstFoldModulus : IPeepholeOptimization { +internal sealed class ConstFoldModulus : IOptimization { + public OptPass OptimizationPass => OptPass.PeepholeOptimization; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.PushFloat, @@ -382,15 +416,15 @@ public ReadOnlySpan GetOpcodes() { } public void Apply(List input, int index) { - var firstInstruction = IPeepholeOptimization.GetInstructionAndValue(input[index], out var pushVal1); + var firstInstruction = IOptimization.GetInstructionAndValue(input[index], out var pushVal1); - IPeepholeOptimization.GetInstructionAndValue(input[index + 1], out var pushVal2); + IOptimization.GetInstructionAndValue(input[index + 1], out var pushVal2); // At runtime, given "A % B" we pop B then A // In the peephole optimizer, index is "A", index+1 is "B" var args = new List(1) {new AnnotatedBytecodeFloat((int)pushVal1 % (int)pushVal2, firstInstruction.Location)}; - IPeepholeOptimization.ReplaceInstructions(input, index, 3, + IOptimization.ReplaceInstructions(input, index, 3, new AnnotatedBytecodeInstruction(DreamProcOpcode.PushFloat, 1, args)); } } @@ -399,7 +433,9 @@ public void Apply(List input, int index) { // PushFloat [constant] // Power // -> PushFloat [result] -internal sealed class ConstFoldPower : IPeepholeOptimization { +internal sealed class ConstFoldPower : IOptimization { + public OptPass OptimizationPass => OptPass.PeepholeOptimization; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.PushFloat, @@ -409,15 +445,15 @@ public ReadOnlySpan GetOpcodes() { } public void Apply(List input, int index) { - var firstInstruction = IPeepholeOptimization.GetInstructionAndValue(input[index], out var pushVal1); + var firstInstruction = IOptimization.GetInstructionAndValue(input[index], out var pushVal1); - IPeepholeOptimization.GetInstructionAndValue(input[index + 1], out var pushVal2); + IOptimization.GetInstructionAndValue(input[index + 1], out var pushVal2); // At runtime, given "A ** B" we pop B then A // In the peephole optimizer, index is "A", index+1 is "B" var args = new List(1) {new AnnotatedBytecodeFloat(MathF.Pow(pushVal1, pushVal2), firstInstruction.Location)}; - IPeepholeOptimization.ReplaceInstructions(input, index, 3, + IOptimization.ReplaceInstructions(input, index, 3, new AnnotatedBytecodeInstruction(DreamProcOpcode.PushFloat, 1, args)); } } @@ -426,7 +462,9 @@ public void Apply(List input, int index) { // PushFloat [constant] // BitshiftLeft // -> PushFloat [result] -internal sealed class ConstFoldBitshiftLeft : IPeepholeOptimization { +internal sealed class ConstFoldBitshiftLeft : IOptimization { + public OptPass OptimizationPass => OptPass.PeepholeOptimization; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.PushFloat, @@ -436,14 +474,14 @@ public ReadOnlySpan GetOpcodes() { } public void Apply(List input, int index) { - var firstInstruction = IPeepholeOptimization.GetInstructionAndValue(input[index], out var pushVal1); - IPeepholeOptimization.GetInstructionAndValue(input[index + 1], out var pushVal2); + var firstInstruction = IOptimization.GetInstructionAndValue(input[index], out var pushVal1); + IOptimization.GetInstructionAndValue(input[index + 1], out var pushVal2); // At runtime, given "A << B" we pop B then A // In the peephole optimizer, index is "A", index+1 is "B" var args = new List(1) {new AnnotatedBytecodeFloat(((int)pushVal1 << (int)pushVal2), firstInstruction.Location)}; - IPeepholeOptimization.ReplaceInstructions(input, index, 3, + IOptimization.ReplaceInstructions(input, index, 3, new AnnotatedBytecodeInstruction(DreamProcOpcode.PushFloat, 1, args)); } } @@ -452,7 +490,9 @@ public void Apply(List input, int index) { // PushFloat [constant] // BitshiftRight // -> PushFloat [result] -internal sealed class ConstFoldBitshiftRight : IPeepholeOptimization { +internal sealed class ConstFoldBitshiftRight : IOptimization { + public OptPass OptimizationPass => OptPass.PeepholeOptimization; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.PushFloat, @@ -462,14 +502,14 @@ public ReadOnlySpan GetOpcodes() { } public void Apply(List input, int index) { - var firstInstruction = IPeepholeOptimization.GetInstructionAndValue(input[index], out var pushVal1); - IPeepholeOptimization.GetInstructionAndValue(input[index + 1], out var pushVal2); + var firstInstruction = IOptimization.GetInstructionAndValue(input[index], out var pushVal1); + IOptimization.GetInstructionAndValue(input[index + 1], out var pushVal2); // At runtime, given "A >> B" we pop B then A // In the peephole optimizer, index is "A", index+1 is "B" var args = new List(1) {new AnnotatedBytecodeFloat(((int)pushVal1 >> (int)pushVal2), firstInstruction.Location)}; - IPeepholeOptimization.ReplaceInstructions(input, index, 3, + IOptimization.ReplaceInstructions(input, index, 3, new AnnotatedBytecodeInstruction(DreamProcOpcode.PushFloat, 1, args)); } } diff --git a/DMCompiler/Optimizer/PeepholeOptimizer.cs b/DMCompiler/Optimizer/PeepholeOptimizer.cs index 4dcb4ef8ee..02863769b9 100644 --- a/DMCompiler/Optimizer/PeepholeOptimizer.cs +++ b/DMCompiler/Optimizer/PeepholeOptimizer.cs @@ -4,9 +4,10 @@ namespace DMCompiler.Optimizer; /// -/// Every interface that inherits IOptimization can be executed as a separate peephole optimizer pass +/// A single peephole optimization (e.g. const fold an operator) /// internal interface IOptimization { + public OptPass OptimizationPass { get; } public ReadOnlySpan GetOpcodes(); public void Apply(List input, int index); @@ -29,57 +30,57 @@ public static void ReplaceInstructions(List input, int index } /// -/// First-pass peephole optimizations (e.g. const folding) +/// The list of peephole optimizer passes in the order that they should run /// -internal interface IPeepholeOptimization : IOptimization; - -/// -/// Next-pass bytecode compacting (e.g. PushNFloats and other PushN opcodes) -/// -internal interface IBytecodeCompactor : IOptimization; - -/// -/// Final-pass list compacting (e.g. PushNFloats & CreateList -> CreateListNFloats) -/// -internal interface IListCompactor : IOptimization; +internal enum OptPass : byte { + PeepholeOptimization = 1, // First-pass peephole optimizations (e.g. const folding) + BytecodeCompactor = 2, // Next-pass bytecode compacting (e.g. PushNFloats and other PushN opcodes) + ListCompactor = 3 // Final-pass list compacting (e.g. PushNFloats & CreateList -> CreateListNFloats) +} // ReSharper disable once ClassNeverInstantiated.Global -internal sealed class PeepholeOptimizer where T : class, IOptimization { +internal sealed class PeepholeOptimizer { private class OptimizationTreeEntry { - public T? Optimization; + public IOptimization? Optimization; public Dictionary? Children; } /// /// Trees matching chains of opcodes to peephole optimizations /// - private static readonly Dictionary OptimizationTrees = new(); + /// This is instantiated when the optimizer runs + private static Dictionary _optimizationTrees = null!; - /// Setup - static PeepholeOptimizer() { - var possibleTypes = typeof(T).Assembly.GetTypes(); + /// Setup for the current + private static void GetOptimizations(OptPass optPass) { + _optimizationTrees = new(); + + var possibleTypes = typeof(IOptimization).Assembly.GetTypes(); var optimizationTypes = new List(); foreach (var type in possibleTypes) { - if (typeof(T).IsAssignableFrom(type) && type is { IsClass: true, IsAbstract: false }) { + if (typeof(IOptimization).IsAssignableFrom(type) && type is { IsClass: true, IsAbstract: false }) { optimizationTypes.Add(type); } } foreach (var optType in optimizationTypes) { - var opt = (T)(Activator.CreateInstance(optType)!); + var opt = (IOptimization)(Activator.CreateInstance(optType)!); + if(opt.OptimizationPass != optPass) + continue; + var opcodes = opt.GetOpcodes(); if (opcodes.Length < 2) { DMCompiler.ForcedError(Location.Internal, $"Peephole optimization {optType} must have at least 2 opcodes"); continue; } - if (!OptimizationTrees.TryGetValue(opcodes[0], out var treeEntry)) { + if (!_optimizationTrees.TryGetValue(opcodes[0], out var treeEntry)) { treeEntry = new() { Children = new() }; - OptimizationTrees.Add(opcodes[0], treeEntry); + _optimizationTrees.Add(opcodes[0], treeEntry); } for (int i = 1; i < opcodes.Length; i++) { @@ -99,6 +100,14 @@ static PeepholeOptimizer() { } public static void RunOptimizations(List input) { + var passes = (OptPass[])Enum.GetValues(typeof(OptPass)); + foreach (var optPass in passes) { + GetOptimizations(optPass); + RunPass(input); + } + } + + private static void RunPass(List input) { OptimizationTreeEntry? currentOpt = null; int optSize = 0; @@ -133,7 +142,7 @@ int AttemptCurrentOpt(int i) { if (currentOpt == null) { optSize = 1; - OptimizationTrees.TryGetValue(opcode, out currentOpt); + _optimizationTrees.TryGetValue(opcode, out currentOpt); continue; } From 3b9bdbb1344ace2bd1e357e2a7a9b9d7ed1c3e18 Mon Sep 17 00:00:00 2001 From: ike709 Date: Fri, 15 Nov 2024 19:28:35 -0600 Subject: [PATCH 04/10] fix merge --- .../Optimizer/CompactorOptimizations.cs | 24 +++++++------- DMCompiler/Optimizer/PeepholeOptimizations.cs | 31 ++++++++++--------- DMCompiler/Optimizer/PeepholeOptimizer.cs | 8 +++-- 3 files changed, 34 insertions(+), 29 deletions(-) diff --git a/DMCompiler/Optimizer/CompactorOptimizations.cs b/DMCompiler/Optimizer/CompactorOptimizations.cs index bde1fe89b6..4e1632b980 100644 --- a/DMCompiler/Optimizer/CompactorOptimizations.cs +++ b/DMCompiler/Optimizer/CompactorOptimizations.cs @@ -20,7 +20,7 @@ public ReadOnlySpan GetOpcodes() { ]; } - public void Apply(List input, int index) { + public void Apply(DMCompiler compiler, List input, int index) { int count = 0; int stackDelta = 0; @@ -56,7 +56,7 @@ public ReadOnlySpan GetOpcodes() { ]; } - public void Apply(List input, int index) { + public void Apply(DMCompiler compiler, List input, int index) { int count = 0; int stackDelta = 0; @@ -92,7 +92,7 @@ public ReadOnlySpan GetOpcodes() { ]; } - public void Apply(List input, int index) { + public void Apply(DMCompiler compiler, List input, int index) { int count = 0; int stackDelta = 0; @@ -129,7 +129,7 @@ public ReadOnlySpan GetOpcodes() { ]; } - public void Apply(List input, int index) { + public void Apply(DMCompiler compiler, List input, int index) { if (index + 1 >= input.Count) { throw new ArgumentOutOfRangeException(nameof(index), "Index plus one is outside the bounds of the input list."); } @@ -184,7 +184,7 @@ public ReadOnlySpan GetOpcodes() { ]; } - public void Apply(List input, int index) { + public void Apply(DMCompiler compiler, List input, int index) { int count = 0; int stackDelta = 0; while (index + count < input.Count && @@ -235,7 +235,7 @@ public bool CheckPreconditions(List input, int index) { return pushVal1 == pushVal2; } - public void Apply(List input, int index) { + public void Apply(DMCompiler compiler, List input, int index) { if (index + 1 >= input.Count) { throw new ArgumentOutOfRangeException(nameof(index), "Index plus one is outside the bounds of the input list."); } @@ -264,7 +264,7 @@ public ReadOnlySpan GetOpcodes() { ]; } - public bool CheckPreconditions(List input, int index) { + public bool CheckPreconditions(DMCompiler compiler, List input, int index) { if (index + 1 >= input.Count) { throw new ArgumentOutOfRangeException(nameof(index), "Index plus one is outside the bounds of the input list."); } @@ -277,7 +277,7 @@ public bool CheckPreconditions(List input, int index) { return pushVal1 == pushVal2; } - public void Apply(List input, int index) { + public void Apply(DMCompiler compiler, List input, int index) { if (index + 1 >= input.Count) { throw new ArgumentOutOfRangeException(nameof(index), "Index plus one is outside the bounds of the input list."); } @@ -306,7 +306,7 @@ public ReadOnlySpan GetOpcodes() { ]; } - public bool CheckPreconditions(List input, int index) { + public bool CheckPreconditions(DMCompiler compiler, List input, int index) { if (index + 1 >= input.Count) { throw new ArgumentOutOfRangeException(nameof(index), "Index plus one is outside the bounds of the input list."); } @@ -319,7 +319,7 @@ public bool CheckPreconditions(List input, int index) { return pushVal1 == pushVal2; } - public void Apply(List input, int index) { + public void Apply(DMCompiler compiler, List input, int index) { if (index + 1 >= input.Count) { throw new ArgumentOutOfRangeException(nameof(index), "Index plus one is outside the bounds of the input list."); } @@ -348,7 +348,7 @@ public ReadOnlySpan GetOpcodes() { ]; } - public bool CheckPreconditions(List input, int index) { + public bool CheckPreconditions(DMCompiler compiler, List input, int index) { if (index + 1 >= input.Count) { throw new ArgumentOutOfRangeException(nameof(index),"Bytecode index is outside the bounds of the input list."); } @@ -359,7 +359,7 @@ public bool CheckPreconditions(List input, int index) { return pushVal1 == pushVal2; } - public void Apply(List input, int index) { + public void Apply(DMCompiler compiler, List input, int index) { if (index + 1 >= input.Count) { throw new ArgumentOutOfRangeException(nameof(index), "Bytecode index is outside the bounds of the input list."); } diff --git a/DMCompiler/Optimizer/PeepholeOptimizations.cs b/DMCompiler/Optimizer/PeepholeOptimizations.cs index 40cf8508bd..720266a531 100644 --- a/DMCompiler/Optimizer/PeepholeOptimizations.cs +++ b/DMCompiler/Optimizer/PeepholeOptimizations.cs @@ -186,7 +186,6 @@ public void Apply(DMCompiler compiler, List input, int index } } - // PushFloat [float] // SwitchCase [label] // -> SwitchOnFloat [float] [label] @@ -292,7 +291,7 @@ public void Apply(DMCompiler compiler, List input, int index // PushFloat [constant] // BitNot // -> PushFloat [result] -internal sealed class ConstFoldBitNot : IPeepholeOptimization { +internal sealed class ConstFoldBitNot : IOptimization { public OptPass OptimizationPass => OptPass.PeepholeOptimization; public ReadOnlySpan GetOpcodes() { @@ -303,11 +302,11 @@ public ReadOnlySpan GetOpcodes() { } public void Apply(DMCompiler compiler, List input, int index) { - var firstInstruction = IPeepholeOptimization.GetInstructionAndValue(input[index], out var pushVal1); + var firstInstruction = IOptimization.GetInstructionAndValue(input[index], out var pushVal1); var args = new List(1) {new AnnotatedBytecodeFloat(((~(int)pushVal1) & 0xFFFFFF), firstInstruction.Location)}; - IPeepholeOptimization.ReplaceInstructions(input, index, 2, + IOptimization.ReplaceInstructions(input, index, 2, new AnnotatedBytecodeInstruction(DreamProcOpcode.PushFloat, 1, args)); } } @@ -316,7 +315,7 @@ public void Apply(DMCompiler compiler, List input, int index // PushFloat [constant] // BitOr // -> PushFloat [result] -internal sealed class ConstFoldBitOr : IPeepholeOptimization { +internal sealed class ConstFoldBitOr : IOptimization { public OptPass OptimizationPass => OptPass.PeepholeOptimization; public ReadOnlySpan GetOpcodes() { @@ -328,13 +327,13 @@ public ReadOnlySpan GetOpcodes() { } public void Apply(DMCompiler compiler, List input, int index) { - var firstInstruction = IPeepholeOptimization.GetInstructionAndValue(input[index], out var pushVal1); + var firstInstruction = IOptimization.GetInstructionAndValue(input[index], out var pushVal1); - IPeepholeOptimization.GetInstructionAndValue(input[index + 1], out var pushVal2); + IOptimization.GetInstructionAndValue(input[index + 1], out var pushVal2); var args = new List(1) {new AnnotatedBytecodeFloat(((int)pushVal1 | (int)pushVal2), firstInstruction.Location)}; - IPeepholeOptimization.ReplaceInstructions(input, index, 3, + IOptimization.ReplaceInstructions(input, index, 3, new AnnotatedBytecodeInstruction(DreamProcOpcode.PushFloat, 1, args)); } } @@ -343,7 +342,7 @@ public void Apply(DMCompiler compiler, List input, int index // PushFloat [constant] // BitAnd // -> PushFloat [result] -internal sealed class ConstFoldBitAnd : IPeepholeOptimization { +internal sealed class ConstFoldBitAnd : IOptimization { public OptPass OptimizationPass => OptPass.PeepholeOptimization; public ReadOnlySpan GetOpcodes() { @@ -355,13 +354,13 @@ public ReadOnlySpan GetOpcodes() { } public void Apply(DMCompiler compiler, List input, int index) { - var firstInstruction = IPeepholeOptimization.GetInstructionAndValue(input[index], out var pushVal1); + var firstInstruction = IOptimization.GetInstructionAndValue(input[index], out var pushVal1); - IPeepholeOptimization.GetInstructionAndValue(input[index + 1], out var pushVal2); + IOptimization.GetInstructionAndValue(input[index + 1], out var pushVal2); var args = new List(1) {new AnnotatedBytecodeFloat(((int)pushVal1 & (int)pushVal2), firstInstruction.Location)}; - IPeepholeOptimization.ReplaceInstructions(input, index, 3, + IOptimization.ReplaceInstructions(input, index, 3, new AnnotatedBytecodeInstruction(DreamProcOpcode.PushFloat, 1, args)); } } @@ -540,7 +539,9 @@ public void Apply(DMCompiler compiler, List input, int index // PushReferenceValue [ref] // -> Assign [ref] // These opcodes can be reduced to a single Assign as long as the [ref]s are the same -internal sealed class AssignAndPushReferenceValue : IPeepholeOptimization { +internal sealed class AssignAndPushReferenceValue : IOptimization { + public OptPass OptimizationPass => OptPass.PeepholeOptimization; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.AssignNoPush, @@ -580,7 +581,9 @@ public void Apply(DMCompiler compiler, List input, int index // PushReferenceValue [ref] // -> Append [ref] // These opcodes can be reduced to a single Append as long as the [ref]s are the same -internal sealed class AppendAndPushReferenceValue : IPeepholeOptimization { +internal sealed class AppendAndPushReferenceValue : IOptimization { + public OptPass OptimizationPass => OptPass.PeepholeOptimization; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.AppendNoPush, diff --git a/DMCompiler/Optimizer/PeepholeOptimizer.cs b/DMCompiler/Optimizer/PeepholeOptimizer.cs index aabee811ee..5ee001d538 100644 --- a/DMCompiler/Optimizer/PeepholeOptimizer.cs +++ b/DMCompiler/Optimizer/PeepholeOptimizer.cs @@ -52,7 +52,7 @@ private class OptimizationTreeEntry { private static Dictionary _optimizationTrees = null!; /// Setup for the current - private static void GetOptimizations(OptPass optPass) { + private static void GetOptimizations(DMCompiler compiler, OptPass optPass) { _optimizationTrees = new(); var possibleTypes = typeof(IOptimization).Assembly.GetTypes(); @@ -102,10 +102,12 @@ private static void GetOptimizations(OptPass optPass) { public static void RunPeephole(DMCompiler compiler, List input) { var passes = (OptPass[])Enum.GetValues(typeof(OptPass)); foreach (var optPass in passes) { - GetOptimizations(optPass); - RunPass(input); + GetOptimizations(compiler, optPass); + RunPass(compiler, input); } } + + private static void RunPass(DMCompiler compiler, List input) { OptimizationTreeEntry? currentOpt = null; int optSize = 0; From 5633fb1ccefd212f6c288ea770f8c4bc5fed839c Mon Sep 17 00:00:00 2001 From: ike709 Date: Sat, 16 Nov 2024 09:33:15 -0600 Subject: [PATCH 05/10] fix some broken CheckPreconditions() --- DMCompiler/Optimizer/CompactorOptimizations.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DMCompiler/Optimizer/CompactorOptimizations.cs b/DMCompiler/Optimizer/CompactorOptimizations.cs index 4e1632b980..9a6525e2fa 100644 --- a/DMCompiler/Optimizer/CompactorOptimizations.cs +++ b/DMCompiler/Optimizer/CompactorOptimizations.cs @@ -264,7 +264,7 @@ public ReadOnlySpan GetOpcodes() { ]; } - public bool CheckPreconditions(DMCompiler compiler, List input, int index) { + public bool CheckPreconditions(List input, int index) { if (index + 1 >= input.Count) { throw new ArgumentOutOfRangeException(nameof(index), "Index plus one is outside the bounds of the input list."); } @@ -306,7 +306,7 @@ public ReadOnlySpan GetOpcodes() { ]; } - public bool CheckPreconditions(DMCompiler compiler, List input, int index) { + public bool CheckPreconditions(List input, int index) { if (index + 1 >= input.Count) { throw new ArgumentOutOfRangeException(nameof(index), "Index plus one is outside the bounds of the input list."); } @@ -348,7 +348,7 @@ public ReadOnlySpan GetOpcodes() { ]; } - public bool CheckPreconditions(DMCompiler compiler, List input, int index) { + public bool CheckPreconditions(List input, int index) { if (index + 1 >= input.Count) { throw new ArgumentOutOfRangeException(nameof(index),"Bytecode index is outside the bounds of the input list."); } From 6289b7b545d65d83933b148d29f8a8887b4d551e Mon Sep 17 00:00:00 2001 From: ike709 Date: Sun, 17 Nov 2024 11:31:06 -0600 Subject: [PATCH 06/10] fix merge --- DMCompiler/Optimizer/PeepholeOptimizations.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/DMCompiler/Optimizer/PeepholeOptimizations.cs b/DMCompiler/Optimizer/PeepholeOptimizations.cs index 9690fdca94..56f6f4577f 100644 --- a/DMCompiler/Optimizer/PeepholeOptimizations.cs +++ b/DMCompiler/Optimizer/PeepholeOptimizations.cs @@ -452,7 +452,9 @@ public void Apply(DMCompiler compiler, List input, int index // PushString [constant] // Add // -> PushString [result] -internal sealed class ConstFoldAddStrings : IPeepholeOptimization { +internal sealed class ConstFoldAddStrings : IOptimization { + public OptPass OptimizationPass => OptPass.PeepholeOptimization; + public ReadOnlySpan GetOpcodes() { return [ DreamProcOpcode.PushString, @@ -470,7 +472,7 @@ public void Apply(DMCompiler compiler, List input, int index var args = new List(1) {new AnnotatedBytecodeString(combinedId, firstInstruction.Location)}; - IPeepholeOptimization.ReplaceInstructions(input, index, 3, + IOptimization.ReplaceInstructions(input, index, 3, new AnnotatedBytecodeInstruction(DreamProcOpcode.PushString, 1, args)); } } From 50de2d9f3c3ff2b56da4767e67867e3e3aabed41 Mon Sep 17 00:00:00 2001 From: ike709 Date: Sun, 17 Nov 2024 12:19:34 -0600 Subject: [PATCH 07/10] do the review --- DMCompiler/Optimizer/PeepholeOptimizer.cs | 45 +++++++++++++---------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/DMCompiler/Optimizer/PeepholeOptimizer.cs b/DMCompiler/Optimizer/PeepholeOptimizer.cs index 5ee001d538..9c88ec7104 100644 --- a/DMCompiler/Optimizer/PeepholeOptimizer.cs +++ b/DMCompiler/Optimizer/PeepholeOptimizer.cs @@ -33,9 +33,9 @@ public static void ReplaceInstructions(List input, int index /// The list of peephole optimizer passes in the order that they should run /// internal enum OptPass : byte { - PeepholeOptimization = 1, // First-pass peephole optimizations (e.g. const folding) - BytecodeCompactor = 2, // Next-pass bytecode compacting (e.g. PushNFloats and other PushN opcodes) - ListCompactor = 3 // Final-pass list compacting (e.g. PushNFloats & CreateList -> CreateListNFloats) + PeepholeOptimization = 0, // First-pass peephole optimizations (e.g. const folding) + BytecodeCompactor = 1, // Next-pass bytecode compacting (e.g. PushNFloats and other PushN opcodes) + ListCompactor = 2 // Final-pass list compacting (e.g. PushNFloats & CreateList -> CreateListNFloats) } // ReSharper disable once ClassNeverInstantiated.Global @@ -45,18 +45,28 @@ private class OptimizationTreeEntry { public Dictionary? Children; } + /// + /// The optimization passes in the order that they run + /// + private static OptPass[] _passes; + /// /// Trees matching chains of opcodes to peephole optimizations /// - /// This is instantiated when the optimizer runs - private static Dictionary _optimizationTrees = null!; + private static Dictionary[] _optimizationTrees; - /// Setup for the current - private static void GetOptimizations(DMCompiler compiler, OptPass optPass) { - _optimizationTrees = new(); + static PeepholeOptimizer() { + _passes = (OptPass[])Enum.GetValues(typeof(OptPass)); + _optimizationTrees = new Dictionary[_passes.Length]; + for (int i = 0; i < _optimizationTrees.Length; i++) { + _optimizationTrees[i] = new Dictionary(); + } + } + /// Setup for each + private static void GetOptimizations(DMCompiler compiler) { var possibleTypes = typeof(IOptimization).Assembly.GetTypes(); - var optimizationTypes = new List(); + var optimizationTypes = new List(possibleTypes.Length); foreach (var type in possibleTypes) { if (typeof(IOptimization).IsAssignableFrom(type) && type is { IsClass: true, IsAbstract: false }) { @@ -66,8 +76,6 @@ private static void GetOptimizations(DMCompiler compiler, OptPass optPass) { foreach (var optType in optimizationTypes) { var opt = (IOptimization)(Activator.CreateInstance(optType)!); - if(opt.OptimizationPass != optPass) - continue; var opcodes = opt.GetOpcodes(); if (opcodes.Length < 2) { @@ -75,12 +83,12 @@ private static void GetOptimizations(DMCompiler compiler, OptPass optPass) { continue; } - if (!_optimizationTrees.TryGetValue(opcodes[0], out var treeEntry)) { + if (!_optimizationTrees[(byte)opt.OptimizationPass].TryGetValue(opcodes[0], out var treeEntry)) { treeEntry = new() { Children = new() }; - _optimizationTrees.Add(opcodes[0], treeEntry); + _optimizationTrees[(byte)opt.OptimizationPass].Add(opcodes[0], treeEntry); } for (int i = 1; i < opcodes.Length; i++) { @@ -100,14 +108,13 @@ private static void GetOptimizations(DMCompiler compiler, OptPass optPass) { } public static void RunPeephole(DMCompiler compiler, List input) { - var passes = (OptPass[])Enum.GetValues(typeof(OptPass)); - foreach (var optPass in passes) { - GetOptimizations(compiler, optPass); - RunPass(compiler, input); + GetOptimizations(compiler); + foreach (var optPass in _passes) { + RunPass(compiler, (byte)optPass, input); } } - private static void RunPass(DMCompiler compiler, List input) { + private static void RunPass(DMCompiler compiler, byte pass, List input) { OptimizationTreeEntry? currentOpt = null; int optSize = 0; @@ -142,7 +149,7 @@ int AttemptCurrentOpt(int i) { if (currentOpt == null) { optSize = 1; - _optimizationTrees.TryGetValue(opcode, out currentOpt); + _optimizationTrees[pass].TryGetValue(opcode, out currentOpt); continue; } From 35d2f67ce952bbdf3a82518f83e367bd58917a72 Mon Sep 17 00:00:00 2001 From: ike709 Date: Sun, 17 Nov 2024 12:53:43 -0600 Subject: [PATCH 08/10] Update DMCompiler/Optimizer/PeepholeOptimizer.cs --- DMCompiler/Optimizer/PeepholeOptimizer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DMCompiler/Optimizer/PeepholeOptimizer.cs b/DMCompiler/Optimizer/PeepholeOptimizer.cs index 9c88ec7104..58467a1137 100644 --- a/DMCompiler/Optimizer/PeepholeOptimizer.cs +++ b/DMCompiler/Optimizer/PeepholeOptimizer.cs @@ -48,7 +48,7 @@ private class OptimizationTreeEntry { /// /// The optimization passes in the order that they run /// - private static OptPass[] _passes; + private static readonly OptPass[] _passes; /// /// Trees matching chains of opcodes to peephole optimizations From ef00751100b27168e591dc3a22c010a1e2bb5104 Mon Sep 17 00:00:00 2001 From: ike709 Date: Sun, 17 Nov 2024 12:53:55 -0600 Subject: [PATCH 09/10] Update DMCompiler/Optimizer/PeepholeOptimizer.cs --- DMCompiler/Optimizer/PeepholeOptimizer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DMCompiler/Optimizer/PeepholeOptimizer.cs b/DMCompiler/Optimizer/PeepholeOptimizer.cs index 58467a1137..c0239e565e 100644 --- a/DMCompiler/Optimizer/PeepholeOptimizer.cs +++ b/DMCompiler/Optimizer/PeepholeOptimizer.cs @@ -53,7 +53,7 @@ private class OptimizationTreeEntry { /// /// Trees matching chains of opcodes to peephole optimizations /// - private static Dictionary[] _optimizationTrees; + private static readonly Dictionary[] _optimizationTrees; static PeepholeOptimizer() { _passes = (OptPass[])Enum.GetValues(typeof(OptPass)); From 740cb8f929e51c2cfad517c281b7e8c2744727f6 Mon Sep 17 00:00:00 2001 From: ike709 Date: Sun, 17 Nov 2024 17:02:20 -0600 Subject: [PATCH 10/10] im tired boss --- DMCompiler/Optimizer/PeepholeOptimizer.cs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/DMCompiler/Optimizer/PeepholeOptimizer.cs b/DMCompiler/Optimizer/PeepholeOptimizer.cs index c0239e565e..aad7cd7287 100644 --- a/DMCompiler/Optimizer/PeepholeOptimizer.cs +++ b/DMCompiler/Optimizer/PeepholeOptimizer.cs @@ -48,22 +48,22 @@ private class OptimizationTreeEntry { /// /// The optimization passes in the order that they run /// - private static readonly OptPass[] _passes; + private static readonly OptPass[] Passes; /// /// Trees matching chains of opcodes to peephole optimizations /// - private static readonly Dictionary[] _optimizationTrees; + private static readonly Dictionary[] OptimizationTrees; static PeepholeOptimizer() { - _passes = (OptPass[])Enum.GetValues(typeof(OptPass)); - _optimizationTrees = new Dictionary[_passes.Length]; - for (int i = 0; i < _optimizationTrees.Length; i++) { - _optimizationTrees[i] = new Dictionary(); + Passes = (OptPass[])Enum.GetValues(typeof(OptPass)); + OptimizationTrees = new Dictionary[Passes.Length]; + for (int i = 0; i < OptimizationTrees.Length; i++) { + OptimizationTrees[i] = new Dictionary(); } } - /// Setup for each + /// Setup for each private static void GetOptimizations(DMCompiler compiler) { var possibleTypes = typeof(IOptimization).Assembly.GetTypes(); var optimizationTypes = new List(possibleTypes.Length); @@ -83,12 +83,12 @@ private static void GetOptimizations(DMCompiler compiler) { continue; } - if (!_optimizationTrees[(byte)opt.OptimizationPass].TryGetValue(opcodes[0], out var treeEntry)) { + if (!OptimizationTrees[(byte)opt.OptimizationPass].TryGetValue(opcodes[0], out var treeEntry)) { treeEntry = new() { Children = new() }; - _optimizationTrees[(byte)opt.OptimizationPass].Add(opcodes[0], treeEntry); + OptimizationTrees[(byte)opt.OptimizationPass].Add(opcodes[0], treeEntry); } for (int i = 1; i < opcodes.Length; i++) { @@ -109,7 +109,7 @@ private static void GetOptimizations(DMCompiler compiler) { public static void RunPeephole(DMCompiler compiler, List input) { GetOptimizations(compiler); - foreach (var optPass in _passes) { + foreach (var optPass in Passes) { RunPass(compiler, (byte)optPass, input); } } @@ -149,7 +149,7 @@ int AttemptCurrentOpt(int i) { if (currentOpt == null) { optSize = 1; - _optimizationTrees[pass].TryGetValue(opcode, out currentOpt); + OptimizationTrees[pass].TryGetValue(opcode, out currentOpt); continue; }