Skip to content

Commit 653d23b

Browse files
authored
Merge pull request #658 from zickgraf/compiler_improvements
Compiler improvements
2 parents e845426 + 438390a commit 653d23b

26 files changed

+860
-119
lines changed

CAP/gap/DerivedMethods.gi

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1317,6 +1317,7 @@ AddDerivationToCAP( LiftAlongMonomorphism,
13171317
function( cat, alpha, beta )
13181318

13191319
## Caution with the order of the arguments!
1320+
#% CAP_JIT_NEXT_FUNCCALL_DOES_NOT_RETURN_FAIL
13201321
return Lift( beta, alpha );
13211322

13221323
end : Description := "LiftAlongMonomorphism using Lift" );
@@ -1327,6 +1328,7 @@ AddDerivationToCAP( ProjectiveLift,
13271328

13281329
function( cat, alpha, beta )
13291330

1331+
#% CAP_JIT_NEXT_FUNCCALL_DOES_NOT_RETURN_FAIL
13301332
return Lift( alpha, beta );
13311333

13321334
end : Description := "ProjectiveLift using Lift" );
@@ -1338,6 +1340,7 @@ AddDerivationToCAP( ColiftAlongEpimorphism,
13381340

13391341
function( cat, alpha, beta )
13401342

1343+
#% CAP_JIT_NEXT_FUNCCALL_DOES_NOT_RETURN_FAIL
13411344
return Colift( alpha, beta );
13421345

13431346
end : Description := "ColiftAlongEpimorphism using Colift" );
@@ -1348,6 +1351,7 @@ AddDerivationToCAP( InjectiveColift,
13481351

13491352
function( cat, alpha, beta )
13501353

1354+
#% CAP_JIT_NEXT_FUNCCALL_DOES_NOT_RETURN_FAIL
13511355
return Colift( alpha, beta );
13521356

13531357
end : Description := "InjectiveColift using Colift" );

CompilerForCAP/TODO

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ Features:
99

1010
* list expressions for logic templates
1111
* do not inline variables but only a reference to them for the logic to use
12-
* support for KeyDependentOperation
1312
* support compilation of operations
1413
* support assigning a variable multiple times, at least in different if branches
1514
* handle WithGiven derivations explicitely (Note: The WithGiven derivations use CallFuncList with the second argument

CompilerForCAP/doc/Extension.autodoc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ To simplify the handling of syntax trees, the CAP compiler enhances syntax trees
2626
* Branches of STAT_IF etc. are given the type BRANCH_IF.
2727
* If the body of a BRANCH_IF is not a STAT_SEQ_STAT, the body is wrapped in a STAT_SEQ_STAT.
2828
* The key-value pairs of EXPR_RECs are given the type REC_KEY_VALUE_PAIR.
29+
* Statements of the form `if condition then return expr_if_true; else return expr_if_false; fi` and
30+
`if condition then var := expr_if_true; else var := expr_if_false; fi` are coded using
31+
a new expression type `EXPR_CONDITIONAL` with components `condition`, `expr_if_true`, and `expr_if_false`.
32+
This makes such statements easier to handle. Hopefully, GAP will support conditional expressions
33+
(i.e. `condition ? expr_if_true : expr_if_false`) natively in the future.
2934
* A globally unique ID is assigned to each function.
3035
* The handling of local variables and higher variables is unified by the concept of function variables:
3136
function variables (FVARs) reference local variables in functions via the function id (`func_id`) and

CompilerForCAP/doc/Usage.autodoc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ During the resolving phase, operations and global variables are resolved:
3939
are considered, and those do not have to be annotated with `CAP_JIT_RESOLVE_FUNCTION`. In particular, caching, pre functions, etc.
4040
are bypassed.
4141
* References to global functions are resolved if the function is annotated with the pragma `CAP_JIT_RESOLVE_FUNCTION`.
42+
* If a call of a global function or operation (occuring as the right hand side of a variable assignment or as the return value of a function)
43+
is annotated with the pragma `CAP_JIT_NEXT_FUNCCALL_DOES_NOT_RETURN_FAIL`, the compiler assumes that the resolved function never returns `fail`
44+
and thus simply removes any code of the form `if condition then return fail; fi;` (or similar) from the resolved function.
45+
The pragma has to be placed right before the variable assignment or the return statement.
46+
* If a KeyDependentOperation is detected, the corresponding `Op` method is resolved.
4247
For details see <Ref Func="CapJitResolvedOperations" /> and <Ref Func="CapJitResolvedGlobalVariables" />.
4348
If no operation or global variable can be resolved anymore, we continue with the rule phase.
4449

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#! @Chapter Examples and tests
2+
3+
#! @Section Tests
4+
5+
LoadPackage( "LinearAlgebraForCAP" );
6+
7+
#! @Example
8+
9+
Q := HomalgFieldOfRationals();;
10+
rows := MatrixCategory( Q );;
11+
12+
MyKernelLift := function( cat, mor, test_morphism )
13+
#% CAP_JIT_NEXT_FUNCCALL_DOES_NOT_RETURN_FAIL
14+
return Lift( cat, test_morphism, KernelEmbedding( cat, mor ) ); end;;
15+
16+
V := VectorSpaceObject( 2, Q );;
17+
compiled_func := CapJitCompiledFunction(
18+
MyKernelLift,
19+
[ rows, ZeroMorphism( V, V ), IdentityMorphism( V ) ]
20+
);;
21+
tree := SYNTAX_TREE( compiled_func );;
22+
# check that the fail has been compiled away,
23+
# that is, we simply return a CAP morphism
24+
Length( tree.stats.statements ) = 1;
25+
#! true
26+
tree.stats.statements[1].type = "STAT_RETURN_OBJ";
27+
#! true
28+
StartsWith( tree.stats.statements[1].obj.type, "EXPR_FUNCCALL" );
29+
#! true
30+
tree.stats.statements[1].obj.funcref.type = "EXPR_REF_GVAR";
31+
#! true
32+
tree.stats.statements[1].obj.funcref.gvar = "ObjectifyWithAttributes";
33+
#! true
34+
35+
func1 := function( x )
36+
#% CAP_JIT_RESOLVE_FUNCTION
37+
if x = 1 then return fail; fi; return 1; end;;
38+
39+
func2 := function( x )
40+
#% CAP_JIT_RESOLVE_FUNCTION
41+
if x = 1 then return fail; else return 1; fi; end;;
42+
43+
# we have to work hard to not write semicolons so AutoDoc
44+
# does not begin a new statement
45+
func3 := EvalString( ReplacedString( """function( x )
46+
local y@
47+
#% CAP_JIT_RESOLVE_FUNCTION
48+
if x = 1 then
49+
y := fail@
50+
else
51+
y := 1@
52+
fi@
53+
return y@
54+
end""", "@", ";" ) );;
55+
56+
call_func1 := function( x )
57+
#% CAP_JIT_NEXT_FUNCCALL_DOES_NOT_RETURN_FAIL
58+
return func1( x ); end;;
59+
60+
call_func2 := function( x )
61+
#% CAP_JIT_NEXT_FUNCCALL_DOES_NOT_RETURN_FAIL
62+
return func2( x ); end;;
63+
64+
call_func3 := function( x )
65+
#% CAP_JIT_NEXT_FUNCCALL_DOES_NOT_RETURN_FAIL
66+
return func3( x ); end;;
67+
68+
Display( CapJitCompiledFunction( call_func1, [ 2 ] ) );
69+
#! function ( x )
70+
#! return 1;
71+
#! end
72+
Display( CapJitCompiledFunction( call_func2, [ 2 ] ) );
73+
#! function ( x )
74+
#! return 1;
75+
#! end
76+
Display( CapJitCompiledFunction( call_func3, [ 2 ] ) );
77+
#! function ( x )
78+
#! return 1;
79+
#! end
80+
81+
#! @EndExample
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
#! @Chapter Examples and tests
2+
3+
#! @Section Tests
4+
5+
LoadPackage( "CompilerForCAP" );
6+
7+
#! @Example
8+
9+
func1 := function( x )
10+
if x = 1 then return 1; else return 2; fi; end;;
11+
12+
tree1 := ENHANCED_SYNTAX_TREE( func1 );;
13+
tree1.stats.statements[1].obj.type = "EXPR_CONDITIONAL";
14+
#! true
15+
16+
coded_func1 := ENHANCED_SYNTAX_TREE_CODE( tree1 );;
17+
String( func1 ) = String( coded_func1 );
18+
#! true
19+
20+
func2 := function( x )
21+
local y; if x = 1 then y := 1; else y := 2; fi; return y; end;;
22+
23+
tree2 := ENHANCED_SYNTAX_TREE( func2 );;
24+
tree2.stats.statements[1].rhs.type = "EXPR_CONDITIONAL";
25+
#! true
26+
27+
coded_func2 := ENHANCED_SYNTAX_TREE_CODE( tree2 );;
28+
String( func2 ) = String( coded_func2 );
29+
#! true
30+
31+
tree3 := rec(
32+
type := "EXPR_FUNC",
33+
id := 1,
34+
nams := [ ],
35+
narg := 0,
36+
nloc := 0,
37+
variadic := false,
38+
stats := rec(
39+
type := "STAT_SEQ_STAT",
40+
statements := [
41+
rec(
42+
type := "STAT_RETURN_OBJ",
43+
obj := rec(
44+
type := "EXPR_FUNCCALL",
45+
funcref := rec(
46+
type := "EXPR_REF_GVAR",
47+
gvar := "IdFunc",
48+
),
49+
args := [
50+
rec(
51+
type := "EXPR_CONDITIONAL",
52+
condition := rec(
53+
type := "EXPR_FALSE",
54+
),
55+
expr_if_true := rec(
56+
type := "EXPR_INT",
57+
value := 1,
58+
),
59+
expr_if_false := rec(
60+
type := "EXPR_INT",
61+
value := 2,
62+
),
63+
),
64+
],
65+
),
66+
),
67+
],
68+
),
69+
);;
70+
71+
coded_func3 := ENHANCED_SYNTAX_TREE_CODE( tree3 );;
72+
Display( coded_func3 );
73+
#! function ( )
74+
#! return IdFunc( function ( )
75+
#! if false then
76+
#! return 1;
77+
#! else
78+
#! return 2;
79+
#! fi;
80+
#! return;
81+
#! end( ) );
82+
#! end
83+
84+
coded_func3();
85+
#! 2
86+
87+
func4 := function( x )
88+
local y; if x then y := 1; else y := 2; fi; return IdFunc( y ); end;;
89+
90+
compiled_func4 := CapJitCompiledFunction( func4, [ true ] );;
91+
Display( compiled_func4 );
92+
#! function ( x )
93+
#! if x then
94+
#! return ID_FUNC( 1 );
95+
#! else
96+
#! return ID_FUNC( 2 );
97+
#! fi;
98+
#! return;
99+
#! end
100+
101+
func5 := function( x )
102+
local y; if x then return 1; else return 1; fi; end;;
103+
104+
compiled_func5 := CapJitCompiledFunction( func5, [ true ] );;
105+
Display( compiled_func5 );
106+
#! function ( x )
107+
#! return 1;
108+
#! end
109+
110+
#! @EndExample
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#! @Chapter Examples and tests
2+
3+
#! @Section Tests
4+
5+
LoadPackage( "CompilerForCAP" );
6+
7+
#! @Example
8+
9+
KeyDependentOperation( "MyKeyDependentOperation",
10+
IsGroup, IsInt, ReturnTrue );;
11+
12+
InstallMethod( MyKeyDependentOperationOp,
13+
[ IsGroup, IsInt ],
14+
function( G, int )
15+
#% CAP_JIT_RESOLVE_FUNCTION
16+
return int; end );;
17+
18+
G := SymmetricGroup(3);;
19+
20+
MyKeyDependentOperation( G, 2 ) = 2;
21+
#! true
22+
23+
MyFunction := G -> MyKeyDependentOperation( G, 2 );;
24+
25+
compiled_func := CapJitCompiledFunction( MyFunction, [ G ] );;
26+
27+
Display( compiled_func );
28+
#! function ( G )
29+
#! return 2;
30+
#! end
31+
32+
#! @EndExample

CompilerForCAP/examples/LinearAlgebraForCAP.g

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
#! @Section Examples
44

5+
LoadPackage( "LinearAlgebra" );
6+
57
#! @Example
68

79
Q := HomalgFieldOfRationals();;
@@ -22,7 +24,7 @@ tree1 := SYNTAX_TREE(
2224
vec!.compiled_functions.MorphismBetweenDirectSums[3]
2325
);;
2426
# fixup nams
25-
tree1.stats.statements[1].branches[2].body.statements[1].
27+
tree1.stats.statements[1].branches[2].body.
2628
obj.args[12].args[1].args[2].nams := [ "row" ];;
2729
Display( SYNTAX_TREE_CODE( tree1 ) );
2830
#! function ( cat, S, morphism_matrix, T )
@@ -47,7 +49,7 @@ tree2 := SYNTAX_TREE( CapJitCompiledFunction(
4749
[ vec, W, morphism_matrix, W ]
4850
) );;
4951
# fixup nams
50-
tree2.stats.statements[1].branches[2].body.statements[1].
52+
tree2.stats.statements[1].branches[2].body.
5153
obj.args[12].args[1].args[2].nams := [ "row" ];;
5254
Display( SYNTAX_TREE_CODE( tree2 ) );
5355
#! function ( cat, S, morphism_matrix, T )
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#! @Chapter Examples and tests
2+
3+
#! @Section Tests
4+
5+
LoadPackage( "CompilerForCAP" );
6+
7+
#! @Example
8+
9+
func1 := function( x, y )
10+
#% CAP_JIT_RESOLVE_FUNCTION
11+
return x; end;;
12+
13+
func2 := function( )
14+
local var; var := 1; var := func1( 2, var ); return var; end;;
15+
16+
compiled_func := CapJitCompiledFunction( func2, [] );;
17+
compiled_func();
18+
#! 2
19+
20+
#! @EndExample

CompilerForCAP/gap/CompilerForCAP.gi

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,14 @@ InstallGlobalFunction( CapJitCompiledFunction, function ( func, jit_args )
7373

7474
tree := CapJitAppliedLogicTemplates( tree, jit_args, true );
7575

76+
if debug then
77+
compiled_func := ENHANCED_SYNTAX_TREE_CODE( tree );
78+
Display( compiled_func );
79+
Error( "apply CapJitInlinedVariableAssignments (for rapid reassignments only)" );
80+
fi;
81+
82+
tree := CapJitInlinedVariableAssignments( tree : inline_rapid_reassignments_only := true );
83+
7684
# new functions might be resolved -> test for side effects
7785
CapJitThrowErrorOnSideEffects( tree );
7886

@@ -95,10 +103,10 @@ InstallGlobalFunction( CapJitCompiledFunction, function ( func, jit_args )
95103
if debug then
96104
compiled_func := ENHANCED_SYNTAX_TREE_CODE( tree );
97105
Display( compiled_func );
98-
Error( "apply CapJitInlinedVariableAssignments" );
106+
Error( "apply CapJitInlinedVariableAssignments (for global variables only)" );
99107
fi;
100108

101-
tree := CapJitInlinedVariableAssignments( tree, true );
109+
tree := CapJitInlinedVariableAssignments( tree : inline_gvars_only := true );
102110

103111
if debug then
104112
compiled_func := ENHANCED_SYNTAX_TREE_CODE( tree );

CompilerForCAP/gap/DropHandledEdgeCases.gi

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ InstallGlobalFunction( CapJitDroppedHandledEdgeCases, function ( tree )
6565

6666
branch := branches[j];
6767

68-
if Last( branch.body.statements ).type = "STAT_RETURN_OBJ" then
68+
if Length( branch.body.statements ) > 0 and Last( branch.body.statements ).type = "STAT_RETURN_OBJ" then
6969

7070
# we are in the main sequence of statements of a function => we are not inside of a loop
7171
# and this branch ends with a return statement

0 commit comments

Comments
 (0)