Skip to content

Commit

Permalink
Merge pull request #1047 from zickgraf/master
Browse files Browse the repository at this point in the history
Simplify `List( list, func )[index]` to `func( list[index] )` in post-processing
  • Loading branch information
zickgraf authored Sep 21, 2022
2 parents 75f0b17 + f8a149b commit 50e938f
Show file tree
Hide file tree
Showing 6 changed files with 239 additions and 152 deletions.
2 changes: 1 addition & 1 deletion CompilerForCAP/PackageInfo.g
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ SetPackageInfo( rec(

PackageName := "CompilerForCAP",
Subtitle := "Speed up computations in CAP categories",
Version := "2022.09-07",
Version := "2022.09-08",
Date := Concatenation( "01/", ~.Version{[ 6, 7 ]}, "/", ~.Version{[ 1 .. 4 ]} ),
License := "GPL-2.0-or-later",

Expand Down
22 changes: 17 additions & 5 deletions CompilerForCAP/examples/CapJitDisableDataTypeInference.g
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,15 @@
LoadPackage( "CompilerForCAP", false );
#! true

func := list -> Sum( list[1] );;
func := { list1, list2 } -> List( list1, x -> Sum( list2[x] ) );;
type_signature := [
[
rec(
filter := IsList,
element_type := rec(
filter := IsInt,
),
),
rec(
filter := IsList,
element_type := rec(
Expand All @@ -26,15 +32,21 @@ type_signature := [
CapJitDisableDataTypeInference( );

Display( CapJitCompiledFunction( func, type_signature ) );
#! function ( list_1 )
#! return Sum( list_1[1] );
#! function ( list1_1, list2_1 )
#! return List( list1_1, function ( x_2 )
#! return Sum( list2_1[x_2] );
#! end );
#! end

CapJitEnableDataTypeInference( );

Display( CapJitCompiledFunction( func, type_signature ) );
#! function ( list_1 )
#! return List( list_1, Sum )[1];
#! function ( list1_1, list2_1 )
#! local hoisted_3_1;
#! hoisted_3_1 := List( list2_1, Sum );
#! return List( list1_1, function ( x_2 )
#! return hoisted_3_1[x_2];
#! end );
#! end

#! @EndExample
69 changes: 68 additions & 1 deletion CompilerForCAP/gap/CompilerForCAP.gi
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ InstallGlobalFunction( CapJitCompiledFunctionAsEnhancedSyntaxTree, function ( fu
end );

InstallGlobalFunction( CAP_JIT_INTERNAL_POST_PROCESSED_SYNTAX_TREE, function ( tree, category, debug )
local compiled_func;
local compiled_func, changed, pre_func;

if debug then
# COVERAGE_IGNORE_BLOCK_START
Expand Down Expand Up @@ -447,6 +447,73 @@ InstallGlobalFunction( CAP_JIT_INTERNAL_POST_PROCESSED_SYNTAX_TREE, function ( t

tree := CapJitDeduplicatedExpressions( tree );

# Simplify `List( list, func )[index]` to `func( list[index] )`.
# We do not want to do this during compilation because of the following situation:
# expr1 := List( [ 1 .. var1 ], x -> very_expensive_operation( x ) ); expr2 := List( [ 1 .. var2 ], y -> List( [ 1 .. var1 ], x -> expr1[x][y] ) );
# If we inline and transform this to
# expr2 := List( [ 1 .. var2 ], y -> List( [ 1 .. var1 ], x -> very_expensive_operation( x )[y] ) );
# we cannot simply hoist `very_expensive_operation( x )`. One solution would be "generalized hoisting": We can detect that the subexpression
# `very_expensive_operation( x )` and its domain `[ 1 .. var1 ]` are independent of `y` and thus extract `expr1` from `expr2` again.
# However, this only improves the runtime if looping over `[ 1 .. var1 ]` is less expensive than the additional computations of `very_expensive_operation( x )`
# in the inlined expression. CompilerForCAP cannot decide this.
# Another solution would be to only transform `List( list, func )[index]` if `List( list, func )` depends on the same function levels as `index` and can thus not
# be hoisted anyway. However, the function levels on which `List( list, func )` depends can change during the compilation due to cancellation.
# Thus, we use the brute-force algorithm here: If we encounter `List( list, func )[index]` during post-processing and after inlining and hoisting,
# simplifying it to `func( list[index] )` always makes sense. This simplification might lead to new instances of `List( list, func )[index]`,
# so we repeat the process until no occurrences of `List( list, func )[index]` remain. In principle, we should rerun the whole rule phase, but this would require
# type signatures and can thus not be triggered from the post-processing currently. As a consequence, one cannot apply logic to the result of this simplifcation.
while true do

changed := false;

pre_func := function ( tree, additional_arguments )

if CapJitIsCallToGlobalFunction( tree, "[]" ) and CapJitIsCallToGlobalFunction( tree.args.1, "List" ) and tree.args.1.args.length = 2 then

changed := true;

# func( list[index] )
return rec(
type := "EXPR_FUNCCALL",
funcref := tree.args.1.args.2, # func
args := AsSyntaxTreeList( [
rec(
type := "EXPR_FUNCCALL",
funcref := rec(
type := "EXPR_REF_GVAR",
gvar := "[]",
),
args := AsSyntaxTreeList( [
tree.args.1.args.1, # list
tree.args.2, # index
] ),
),
] ),
);

fi;

return tree;

end;

tree := CapJitIterateOverTree( tree, pre_func, CapJitResultFuncCombineChildren, ReturnTrue, true );

if not changed then

break;

fi;

tree := CapJitInlinedArguments( tree );
tree := CapJitInlinedSimpleFunctionCalls( tree );
tree := CapJitInlinedFunctionCalls( tree );
tree := CapJitInlinedBindingsFully( tree );
tree := CapJitHoistedExpressions( tree );
tree := CapJitDeduplicatedExpressions( tree );

od;

fi;

return tree;
Expand Down
2 changes: 1 addition & 1 deletion LinearAlgebraForCAP/PackageInfo.g
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ SetPackageInfo( rec(

PackageName := "LinearAlgebraForCAP",
Subtitle := "Category of Matrices over a Field for CAP",
Version := "2022.09-07",
Version := "2022.09-08",
Date := Concatenation( "01/", ~.Version{[ 6, 7 ]}, "/", ~.Version{[ 1 .. 4 ]} ),
License := "GPL-2.0-or-later",

Expand Down
Loading

0 comments on commit 50e938f

Please sign in to comment.