Skip to content

Commit

Permalink
Merge pull request #708 from zickgraf/compiler_improvements
Browse files Browse the repository at this point in the history
Some improvements to the compiler
  • Loading branch information
zickgraf authored Sep 10, 2021
2 parents 3a97766 + 7463598 commit edaebd2
Show file tree
Hide file tree
Showing 22 changed files with 271 additions and 206 deletions.
1 change: 1 addition & 0 deletions CAP/gap/CAP.gi
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,7 @@ InstallMethod( CreateCapCategory,
category!.enable_compilation := enable_compilation;

category!.compiled_functions := rec( );
category!.compiled_functions_trees := rec( );

CREATE_CAP_CATEGORY_FILTERS( category );

Expand Down
2 changes: 1 addition & 1 deletion CAP/gap/CategoriesCategory.gi
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ InstallGlobalFunction( CAP_INTERNAL_CREATE_Cat,

function( )

InstallValue( CapCat, rec( caching_info := rec( ), overhead := true, is_computable := true, enable_compilation := false, compiled_functions := rec( ) ) );
InstallValue( CapCat, rec( caching_info := rec( ), overhead := true, is_computable := true, enable_compilation := false, compiled_functions := rec( ), compiled_functions_trees := rec( ) ) );

CREATE_CAP_CATEGORY_OBJECT( CapCat, [ [ "Name", "Cat" ] ] );

Expand Down
1 change: 1 addition & 0 deletions CAP/gap/InstallAdds.gi
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,7 @@ InstallGlobalFunction( CapInternalInstallAdd,
if not IsBound( category!.compiled_functions.( function_name ) ) then

category!.compiled_functions.( function_name ) := [ ];
category!.compiled_functions_trees.( function_name ) := [ ];

fi;

Expand Down
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 := "2021.09-02",
Version := "2021.09-03",
Date := Concatenation( "01/", ~.Version{[ 6, 7 ]}, "/", ~.Version{[ 1 .. 4 ]} ),
License := "GPL-2.0-or-later",

Expand Down
8 changes: 2 additions & 6 deletions CompilerForCAP/doc/Extension.autodoc
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ a completely new one, see <Ref Sect="Section_CompilationSteps" />.

For debugging you can:
* use <Ref Func="CapJitPrettyPrintSyntaxTree" />,
* set `debug` to `true` in <Ref Func="CapJitCompiledFunction" /> (Note: this causes informational break loops which are not actual errors),
* set `debug` to `true` in the code of <Ref Func="CapJitCompiledFunctionAsEnhancedSyntaxTree" />
(Note: this causes informational break loops which are not actual errors),
* use the `debug` and `debug_path` record entries of logic templates (see <Ref Func="CapJitAddLogicTemplate" />).

@Section Logic
Expand All @@ -26,11 +27,6 @@ To simplify the handling of syntax trees, the CAP compiler enhances syntax trees
* Branches of STAT_IF etc. are given the type BRANCH_IF.
* If the body of a BRANCH_IF is not a STAT_SEQ_STAT, the body is wrapped in a STAT_SEQ_STAT.
* The key-value pairs of EXPR_RECs are given the type REC_KEY_VALUE_PAIR.
* Statements of the form `if condition then return expr_if_true; else return expr_if_false; fi` and
`if condition then var := expr_if_true; else var := expr_if_false; fi` are coded using
a new expression type `EXPR_CONDITIONAL` with components `condition`, `expr_if_true`, and `expr_if_false`.
This makes such statements easier to handle. Hopefully, GAP will support conditional expressions
(i.e. `condition ? expr_if_true : expr_if_false`) natively in the future.
* A globally unique ID is assigned to each function.
* The handling of local variables and higher variables is unified by the concept of function variables:
function variables (FVARs) reference local variables in functions via the function id (`func_id`) and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,6 @@ func2 := function( x )
#% CAP_JIT_RESOLVE_FUNCTION
if x = 1 then return fail; else return 1; fi; end;;

# we have to work hard to not write semicolons so AutoDoc
# does not begin a new statement
func3 := EvalString( ReplacedString( """function( x )
local y@
#% CAP_JIT_RESOLVE_FUNCTION
if x = 1 then
y := fail@
else
y := 1@
fi@
return y@
end""", "@", ";" ) );;

call_func1 := function( x )
#% CAP_JIT_NEXT_FUNCCALL_DOES_NOT_RETURN_FAIL
return func1( x ); end;;
Expand All @@ -62,10 +49,6 @@ call_func2 := function( x )
#% CAP_JIT_NEXT_FUNCCALL_DOES_NOT_RETURN_FAIL
return func2( x ); end;;

call_func3 := function( x )
#% CAP_JIT_NEXT_FUNCCALL_DOES_NOT_RETURN_FAIL
return func3( x ); end;;

Display( CapJitCompiledFunction( call_func1, [ 2 ] ) );
#! function ( x_1 )
#! return 1;
Expand All @@ -74,9 +57,5 @@ Display( CapJitCompiledFunction( call_func2, [ 2 ] ) );
#! function ( x_1 )
#! return 1;
#! end
Display( CapJitCompiledFunction( call_func3, [ 2 ] ) );
#! function ( x_1 )
#! return 1;
#! end

#! @EndExample
65 changes: 40 additions & 25 deletions CompilerForCAP/examples/EXPR_CONDITIONAL.g
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,28 @@

#! @Section Tests

#! @Example

LoadPackage( "CompilerForCAP" );
#! true

#! @Example
MY_ID_FUNC := x -> x;;

func1 := function( x )
if x = 1 then return 1; else return 2; fi; end;;

tree1 := ENHANCED_SYNTAX_TREE( func1 );;
tree1 := CapJitDetectedTernaryConditionalExpressions( tree1 );;
tree1.stats.statements[1].obj.type = "EXPR_CONDITIONAL";
#! true

coded_func1 := ENHANCED_SYNTAX_TREE_CODE( tree1 );;
String( func1 ) = ReplacedString( String( coded_func1 ), "_1", "" );
#! true

func2 := function( x )
local y; if x = 1 then y := 1; else y := 2; fi; return y; end;;

tree2 := ENHANCED_SYNTAX_TREE( func2 );;
tree2.stats.statements[1].rhs.type = "EXPR_CONDITIONAL";
#! true

coded_func2 := ENHANCED_SYNTAX_TREE_CODE( tree2 );;
String( func2 ) = ReplacedString( String( coded_func2 ), "_1", "" );
#! true

tree3 := rec(
tree2 := rec(
type := "EXPR_FUNC",
id := 1,
nams := [ ],
Expand All @@ -44,7 +39,7 @@ tree3 := rec(
type := "EXPR_FUNCCALL",
funcref := rec(
type := "EXPR_REF_GVAR",
gvar := "IdFunc",
gvar := "MY_ID_FUNC",
),
args := [
rec(
Expand All @@ -68,10 +63,10 @@ tree3 := rec(
),
);;

coded_func3 := ENHANCED_SYNTAX_TREE_CODE( tree3 );;
Display( coded_func3 );
coded_func2 := ENHANCED_SYNTAX_TREE_CODE( tree2 );;
Display( coded_func2 );
#! function ( )
#! return IdFunc( function ( )
#! return MY_ID_FUNC( function ( )
#! if false then
#! return 1;
#! else
Expand All @@ -81,28 +76,48 @@ Display( coded_func3 );
#! end( ) );
#! end

coded_func3();
coded_func2();
#! 2

func4 := function( x )
local y; if x then y := 1; else y := 2; fi; return IdFunc( y ); end;;

compiled_func4 := CapJitCompiledFunction( func4, [ true ] );;
Display( compiled_func4 );

# we have to work hard to not write semicolons so AutoDoc
# does not begin a new statement
func3 := EvalString( ReplacedString( """function( x )
local inner_func@
inner_func := function( )
local y@
if x then
return 1@
else
y := 2@
return y@
fi@
end@
return MY_ID_FUNC( inner_func( ) )@
end""", "@", ";" ) );;

compiled_func3 := CapJitCompiledFunction( func3, [ true ] );;
Display( compiled_func3 );
#! function ( x_1 )
#! if x_1 then
#! return ID_FUNC( 1 );
#! return MY_ID_FUNC( 1 );
#! else
#! return ID_FUNC( 2 );
#! return MY_ID_FUNC( 2 );
#! fi;
#! return;
#! end

func5 := function( x )


func4 := function( x )
local y; if x then return 1; else return 1; fi; end;;

compiled_func5 := CapJitCompiledFunction( func5, [ true ] );;
Display( compiled_func5 );
compiled_func4 := CapJitCompiledFunction( func4, [ true ] );;
Display( compiled_func4 );
#! function ( x_1 )
#! return 1;
#! end
Expand Down
4 changes: 2 additions & 2 deletions CompilerForCAP/examples/LinearAlgebraForCAP.g
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ Display( SYNTAX_TREE_CODE( tree2 ) );
#! function ( logic_new_func_x_2, logic_new_func_y_2 )
#! return UnionOfColumns( UnderlyingRing( cat_1 ),
#! Dimension( logic_new_func_x_2 ),
#! List( logic_new_func_y_2, function ( s_2_3 )
#! return UnderlyingMatrix( s_2_3 );
#! List( logic_new_func_y_2, function ( s_3 )
#! return UnderlyingMatrix( s_3 );
#! end ) );
#! end ) ) );
#! end
Expand Down
9 changes: 8 additions & 1 deletion CompilerForCAP/gap/CompilerForCAP.gd
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ DeclareInfoClass( "InfoCapJit" );
#! @Section Compiling a function manually

#! @Description
#! Returns a compiled version of the function <A>func</A>.
#! Returns a compiled version of the function <A>func</A> (if <A>func</A> is an operation or a kernel function, it is returned unchanged).
#! The list of arguments <A>jit_args</A> is used to infer the types of variables.
#! If <A>jit_args</A> is shorter than the number of arguments accepted by <A>func</A>,
#! all steps which require knowledge about the types of variables are skipped.
Expand All @@ -35,3 +35,10 @@ DeclareInfoClass( "InfoCapJit" );
#! @Returns a function
#! @Arguments func, jit_args
DeclareGlobalFunction( "CapJitCompiledFunction" );

#! @Description
#! Like <Ref Func="CapJitCompiledFunction" />, but returns an enhanced syntax tree of the compiled function.
#! <A>func</A> must not be an operation or a kernel function because those cannot properly be represented as a syntax tree.
#! @Returns a record
#! @Arguments func, jit_args
DeclareGlobalFunction( "CapJitCompiledFunctionAsEnhancedSyntaxTree" );
28 changes: 23 additions & 5 deletions CompilerForCAP/gap/CompilerForCAP.gi
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,27 @@ InstallGlobalFunction( ContinueCompilationAtCategory, function ( category )
end );

InstallGlobalFunction( CapJitCompiledFunction, function ( func, jit_args )

if IsOperation( func ) or IsKernelFunction( func ) then

Info( InfoCapJit, 1, "<func> is a operation or kernel function, this is not supported yet." );
return func;

fi;

return ENHANCED_SYNTAX_TREE_CODE( CapJitCompiledFunctionAsEnhancedSyntaxTree( func, jit_args ) );

end );

InstallGlobalFunction( CapJitCompiledFunctionAsEnhancedSyntaxTree, function ( func, jit_args )
local debug, tree, orig_tree, compiled_func;

Info( InfoCapJit, 1, "####" );
Info( InfoCapJit, 1, "Start compilation." );

if IsOperation( func ) or IsKernelFunction( func ) then

Info( InfoCapJit, 1, "<func> is a operation or kernel function, this is not supported yet." );
return func;
Error( "<func> is a operation or kernel function, this is not supported yet." );

fi;

Expand Down Expand Up @@ -197,6 +209,14 @@ InstallGlobalFunction( CapJitCompiledFunction, function ( func, jit_args )

tree := CapJitInlinedVariableAssignments( tree );

if debug then
compiled_func := ENHANCED_SYNTAX_TREE_CODE( tree );
Display( compiled_func );
Error( "apply CapJitDetectedTernaryConditionalExpressions" );
fi;

tree := CapJitDetectedTernaryConditionalExpressions( tree );

od;

# post-processing
Expand Down Expand Up @@ -233,11 +253,9 @@ InstallGlobalFunction( CapJitCompiledFunction, function ( func, jit_args )

fi;

compiled_func := ENHANCED_SYNTAX_TREE_CODE( tree );

Info( InfoCapJit, 1, "####" );
Info( InfoCapJit, 1, "Compilation finished." );

return compiled_func;
return tree;

end );
16 changes: 16 additions & 0 deletions CompilerForCAP/gap/DetectTernaryConditionalExpressions.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# CompilerForCAP: Speed up computations in CAP categories
#
# Declarations
#
#! @Chapter Improving and extending the compiler

#! @Section Compilation steps

#! @Description
#! Detects statements of the form `if condition then return expr_if_true; else return expr_if_false; fi` and
#! changes their representation by using a new expression type `EXPR_CONDITIONAL` with components `condition`,
#! `expr_if_true`, and `expr_if_false`. This makes such statements easier to handle.
#! @Returns a record
#! @Arguments tree
DeclareGlobalFunction( "CapJitDetectedTernaryConditionalExpressions" );
55 changes: 55 additions & 0 deletions CompilerForCAP/gap/DetectTernaryConditionalExpressions.gi
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# CompilerForCAP: Speed up computations in CAP categories
#
# Implementations
#
InstallGlobalFunction( CapJitDetectedTernaryConditionalExpressions, function ( tree )
local pre_func;

pre_func := function ( tree, additional_arguments )
local body_if_true, body_if_false, statement_if_true, statement_if_false;

if IsRecord( tree ) then

Assert( 0, IsBound( tree.type ) );

if tree.type = "STAT_IF_ELSE" then

Assert( 0, Length( tree.branches ) = 2 );
Assert( 0, tree.branches[2].condition.type = "EXPR_TRUE" );

body_if_true := tree.branches[1].body;
body_if_false := tree.branches[2].body;

if Length( body_if_true.statements ) = 1 and Length( body_if_false.statements ) = 1 then

statement_if_true := body_if_true.statements[1];
statement_if_false := body_if_false.statements[1];

if statement_if_true.type = "STAT_RETURN_OBJ" and statement_if_false.type = "STAT_RETURN_OBJ" then

tree := rec(
type := "STAT_RETURN_OBJ",
obj := rec(
type := "EXPR_CONDITIONAL",
condition := tree.branches[1].condition,
expr_if_true := statement_if_true.obj,
expr_if_false := statement_if_false.obj,
),
);

fi;

fi;

fi;

fi;

return tree;

end;

return CapJitIterateOverTree( tree, pre_func, CapJitResultFuncCombineChildren, ReturnTrue, true );

end );
Loading

0 comments on commit edaebd2

Please sign in to comment.