From dced648667b386f5411f4c112af9260d0c8a40e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20R=C3=A4tzel?= Date: Sat, 4 Jan 2025 10:34:04 +0000 Subject: [PATCH] fuse common expressions of integer subtraction in IR --- implement/pine/PineVM/PineIRCompiler.cs | 68 +++++++++++-- implement/test-elm-time/PineVMTests.cs | 123 ++++++++++++++++++++++++ 2 files changed, 183 insertions(+), 8 deletions(-) diff --git a/implement/pine/PineVM/PineIRCompiler.cs b/implement/pine/PineVM/PineIRCompiler.cs index 3aec1aee..c3674ed0 100644 --- a/implement/pine/PineVM/PineIRCompiler.cs +++ b/implement/pine/PineVM/PineIRCompiler.cs @@ -481,7 +481,9 @@ public static IReadOnlyList CompileKernelApplication_Int_Add( { return [ - new StackInstruction(StackInstructionKind.Push_Literal, Literal: PineValueAsInteger.ValueFromSignedInteger(0)) + new StackInstruction( + StackInstructionKind.Push_Literal, + Literal: PineValueAsInteger.ValueFromSignedInteger(0)) ]; } @@ -491,16 +493,33 @@ public static IReadOnlyList CompileKernelApplication_Int_Add( { var item = listExpr.items[i]; - var itemOps = - CompileExpressionTransitive( - item, - localIndexFromExpr); + if (0 < i && TryParseExprAsIntNegation(item) is { } negatedItem) + { + var itemOps = + CompileExpressionTransitive( + negatedItem, + localIndexFromExpr); - addOps.AddRange(itemOps); + addOps.AddRange(itemOps); - if (0 < i) + if (0 < i) + { + addOps.Add(new StackInstruction(StackInstructionKind.Int_Sub_Binary)); + } + } + else { - addOps.Add(new StackInstruction(StackInstructionKind.Int_Add_Binary)); + var itemOps = + CompileExpressionTransitive( + item, + localIndexFromExpr); + + addOps.AddRange(itemOps); + + if (0 < i) + { + addOps.Add(new StackInstruction(StackInstructionKind.Int_Add_Binary)); + } } } @@ -810,4 +829,37 @@ .. CompileExpressionTransitive(input, localIndexFromExpr), new StackInstruction(StackInstructionKind.Bit_Shift_Right_List) ]; } + + public static Expression? TryParseExprAsIntNegation(Expression expression) + { + if (expression is not Expression.KernelApplication kernelApp) + { + return null; + } + + if (kernelApp.Function is "negate") + { + return kernelApp.Input; + } + + if (kernelApp.Function is "int_mul" && + kernelApp.Input is Expression.List mulList && mulList.items.Count is 2) + { + if (mulList.items[0] is Expression.Literal literalExpr && + KernelFunction.SignedIntegerFromValueRelaxed(literalExpr.Value) is { } literalValue && + literalValue == -1) + { + return mulList.items[1]; + } + + if (mulList.items[1] is Expression.Literal literalExpr2 && + KernelFunction.SignedIntegerFromValueRelaxed(literalExpr2.Value) is { } literalValue2 && + literalValue2 == -1) + { + return mulList.items[0]; + } + } + + return null; + } } diff --git a/implement/test-elm-time/PineVMTests.cs b/implement/test-elm-time/PineVMTests.cs index ba732aeb..7161c955 100644 --- a/implement/test-elm-time/PineVMTests.cs +++ b/implement/test-elm-time/PineVMTests.cs @@ -1110,6 +1110,129 @@ public void Compile_stack_frame_instructions() StackInstruction.Return ]) }, + + new + { + expression = + (Expression) + new Expression.KernelApplication( + function: "int_add", + input: + Expression.ListInstance( + [ + new Expression.KernelApplication( + function: "head", + input: + new Expression.KernelApplication( + function: "skip", + input: + Expression.ListInstance( + [ + Expression.LiteralInstance(PineValueAsInteger.ValueFromSignedInteger(1)), + Expression.EnvironmentInstance, + ]))), + + new Expression.KernelApplication( + function: "negate", + input: + new Expression.KernelApplication( + function: "head", + input: + new Expression.KernelApplication( + function: "skip", + input: + Expression.ListInstance( + [ + Expression.LiteralInstance(PineValueAsInteger.ValueFromSignedInteger(2)), + Expression.EnvironmentInstance, + ])))), + ])), + + expected = + new PineVM.StackFrameInstructions( + [ + StackInstruction.PushEnvironment, + + new StackInstruction( + StackInstructionKind.Skip_Head_Const, + SkipCount: 1), + + StackInstruction.PushEnvironment, + + new StackInstruction( + StackInstructionKind.Skip_Head_Const, + SkipCount: 2), + + new StackInstruction( + StackInstructionKind.Int_Sub_Binary), + + StackInstruction.Return, + ]) + }, + + new + { + expression = + (Expression) + new Expression.KernelApplication( + function: "int_add", + input: + Expression.ListInstance( + [ + new Expression.KernelApplication( + function: "head", + input: + new Expression.KernelApplication( + function: "skip", + input: + Expression.ListInstance( + [ + Expression.LiteralInstance(PineValueAsInteger.ValueFromSignedInteger(1)), + Expression.EnvironmentInstance, + ]))), + + new Expression.KernelApplication( + function: "int_mul", + input: + Expression.ListInstance( + [ + Expression.LiteralInstance(PineValueAsInteger.ValueFromSignedInteger(-1)), + + new Expression.KernelApplication( + function: "head", + input: + new Expression.KernelApplication( + function: "skip", + input: + Expression.ListInstance( + [ + Expression.LiteralInstance(PineValueAsInteger.ValueFromSignedInteger(2)), + Expression.EnvironmentInstance, + ]))) + ])), + ])), + + expected = + new PineVM.StackFrameInstructions( + [ + StackInstruction.PushEnvironment, + + new StackInstruction( + StackInstructionKind.Skip_Head_Const, + SkipCount: 1), + + StackInstruction.PushEnvironment, + + new StackInstruction( + StackInstructionKind.Skip_Head_Const, + SkipCount: 2), + + new StackInstruction( + StackInstructionKind.Int_Sub_Binary), + + StackInstruction.Return, + ]) + }, }; var parseCache = new PineVMParseCache();