Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize ROT #346

Merged
merged 4 commits into from
Sep 7, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions src/Neo.Compiler.MSIL/Optimizer/OptimizerExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,19 @@ public static bool IsValidValue(this BigInteger value)
return true;
}

public static bool IsPushOrNull(this NefInstruction ins, out BigInteger? value)
{
if (ins.OpCode == OpCode.PUSHNULL)
{
value = null;
return true;
}

var ret = IsPush(ins, out var retval);
value = retval;
return ret;
}

public static bool IsPush(this NefInstruction ins, out BigInteger value)
{
switch (ins.OpCode)
Expand Down Expand Up @@ -82,5 +95,22 @@ public static bool IsPush(this NefInstruction ins, out BigInteger value)
value = 0;
return false;
}

public static bool IsPushData(this NefInstruction ins, out byte[] value)
{
switch (ins.OpCode)
{
case OpCode.PUSHDATA1:
case OpCode.PUSHDATA2:
case OpCode.PUSHDATA4:
{
value = ins.Data;
return true;
}
}

value = null;
return false;
}
}
}
26 changes: 25 additions & 1 deletion src/Neo.Compiler.MSIL/Optimizer/Parser_DeleteConstExecution.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public void Parse(List<INefItem> items)
{
if (items[x - 1] is NefInstruction p1)
{
if (p1.IsPush(out _) || (p1.OpCode == OpCode.PUSHNULL))
if (p1.IsPushOrNull(out _))
{
items.RemoveRange(x - 1, 2);
OptimizedCount++;
Expand Down Expand Up @@ -233,6 +233,30 @@ public void Parse(List<INefItem> items)
}
break;
}

// Three stack items

case OpCode.ROT:
{
if (x >= 3 &&
items[x - 1] is NefInstruction p1 &&
items[x - 2] is NefInstruction p2 &&
items[x - 3] is NefInstruction p3 &&
(p1.IsPushOrNull(out _) || p1.IsPushData(out _)) &&
(p2.IsPushOrNull(out _) || p2.IsPushData(out _)) &&
(p3.IsPushOrNull(out _) || p3.IsPushData(out _))
)
{
items[x - 3] = p2;
items[x - 2] = p1;
items[x - 1] = p3;

items.RemoveRange(x, 1);
OptimizedCount++;
x -= 3;
}
break;
}
}
}
}
Expand Down
54 changes: 54 additions & 0 deletions tests/Neo.Compiler.MSIL.UnitTests/UnitTest_NefOptimizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,60 @@ public void Test_Optimize_StaticMath_MUL()
}
}

[TestMethod]
public void Test_Optimize_ConstExecution_ROT()
{
using (var scriptBefore = new ScriptBuilder())
{
scriptBefore.Emit(VM.OpCode.PUSH1);
scriptBefore.Emit(VM.OpCode.PUSH2);
scriptBefore.Emit(VM.OpCode.PUSH3);
scriptBefore.Emit(VM.OpCode.ROT);

using (var scriptAfter = new ScriptBuilder())
{
scriptAfter.Emit(VM.OpCode.PUSH2);
scriptAfter.Emit(VM.OpCode.PUSH3);
scriptAfter.Emit(VM.OpCode.PUSH1);

var optimized = NefOptimizeTool.Optimize(scriptBefore.ToArray(), Array.Empty<int>(), OptimizeParserType.DELETE_CONST_EXECUTION);
CollectionAssert.AreEqual(scriptAfter.ToArray(), optimized);
}
}

using (var scriptBefore = new ScriptBuilder())
{
scriptBefore.Emit(VM.OpCode.PUSH1);
scriptBefore.Emit(VM.OpCode.PUSH2);
scriptBefore.Emit(VM.OpCode.PUSHNULL);
scriptBefore.Emit(VM.OpCode.ROT);

using (var scriptAfter = new ScriptBuilder())
{
scriptAfter.Emit(VM.OpCode.PUSH2);
scriptAfter.Emit(VM.OpCode.PUSHNULL);
scriptAfter.Emit(VM.OpCode.PUSH1);

var optimized = NefOptimizeTool.Optimize(scriptBefore.ToArray(), Array.Empty<int>(), OptimizeParserType.DELETE_CONST_EXECUTION);
CollectionAssert.AreEqual(scriptAfter.ToArray(), optimized);
}
}

using (var scriptBefore = new ScriptBuilder())
{
scriptBefore.Emit(VM.OpCode.PUSH5);
scriptBefore.Emit(VM.OpCode.PUSH4);
scriptBefore.EmitJump(VM.OpCode.JMP, 3);
scriptBefore.Emit(VM.OpCode.PUSH1);
scriptBefore.Emit(VM.OpCode.PUSH2);
scriptBefore.Emit(VM.OpCode.PUSH3);
scriptBefore.Emit(VM.OpCode.ROT);

var optimized = NefOptimizeTool.Optimize(scriptBefore.ToArray(), Array.Empty<int>(), OptimizeParserType.DELETE_CONST_EXECUTION);
CollectionAssert.AreEqual(scriptBefore.ToArray(), optimized);
}
}

[TestMethod]
public void Test_Optimize_Recalculate_BoolEqualTrue()
{
Expand Down