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

Add Constant Var support #1682

Merged
merged 3 commits into from
Oct 2, 2017
Merged

Conversation

ChrisJefferson
Copy link
Contributor

This adds to gap the concept of a constant variable. They are created with MakeConstantVar, and behave similarly to MakeReadOnlyVar, except:

  • they can never be changed
  • they can only be small integers, true or false
  • The interpreter will inline them to optimise byte code.

The inlining is always done, and further to interpreter will inline away if statements of the form if constvar then... for a constant variable constvar.

@@ -541,7 +541,30 @@ local variables or function arguments).
<P/>
First, such variables may be marked <E>read-only</E>. In which case
attempts to change them will fail. Most of the global variables
defined in the &GAP; library are so marked.
defined in the &GAP; library are so marked. <E>read-only</E> variables
can be made read-write again. GAP also features <E>constant</E> variables,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps: "can be made read-write again [using the command XYZ]"

## named by the string <name> is constant and false otherwise (the default)
##

IS_CONSTANT_GLOBAL := IsConstantGVar;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Meta-note: It's really crazy that we define kernel function using CamelCase, then define alternate names in SNAKE_CASE, and finally high level names again in CamelCase. (Of course this PR is just imitating what the surrounding code does, so the PR is fine; I just think we may want to resolve this in another PR in the future)

src/code.c Outdated
// Some optimisation cases
if (nr == 1) {
if (TNUM_EXPR(cond1) == T_TRUE_EXPR) {
// Leave Statement
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Statement -> statement

src/intrprtr.c Outdated
** 'IntrSmallGAPIntExpr' is the action to 'interpret' a existing GAP small
** integer. This is used for implementing constants.
*/
void IntrSmallGAPIntExpr(Obj val)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really prefer to refer to "immediate integers", as "small integer" is quite ambiguous (a reader may not realize it has a technical meaning). So perhaps IntrImmediateIntExpr and CodeImmediateIntExpr?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or ...IntObj?

src/read.c Outdated
else if (IS_INTOBJ(val))
IntrSmallGAPIntExpr(val);
else
SyntaxError("Invalid Constant Variable");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Invalid Constant Variable" -> "Invalid constant variable"

if boolfalsevar then
return 6;
fi;
return;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, perhaps also test if/elif/fi and if/elif/else/fi ?

@codecov
Copy link

codecov bot commented Sep 7, 2017

Codecov Report

Merging #1682 into master will increase coverage by <.01%.
The diff coverage is 83.16%.

@@            Coverage Diff             @@
##           master    #1682      +/-   ##
==========================================
+ Coverage   64.06%   64.07%   +<.01%     
==========================================
  Files         999      999              
  Lines      322458   322550      +92     
  Branches    13025    13064      +39     
==========================================
+ Hits       206593   206675      +82     
- Misses     113146   113151       +5     
- Partials     2719     2724       +5
Impacted Files Coverage Δ
lib/global.g 88.88% <ø> (ø) ⬆️
src/code.h 100% <ø> (ø) ⬆️
src/gap.c 56.26% <100%> (+0.14%) ⬆️
src/intrprtr.c 70.5% <66.66%> (-0.03%) ⬇️
src/gvars.c 77.79% <71.42%> (-0.01%) ⬇️
src/stats.c 71.95% <75%> (+0.2%) ⬆️
lib/global.gi 40.57% <83.33%> (+4.86%) ⬆️
src/read.c 81.59% <90%> (+0.06%) ⬆️
src/code.c 86.96% <93.93%> (+0.14%) ⬆️
src/hpc/traverse.c 77.9% <0%> (-0.31%) ⬇️
... and 8 more

@ChrisJefferson
Copy link
Contributor Author

I believe I have fixed issues, and written more tests. This PR includes a commit which fixes printing elif true, which was always printed as else.

I agree the camel case / allcaps dance is weird (and I would like to remove the methods MakeConstantGVar and friends, as to a user I think it's unclear if they should be using MakeConstantGVar and MakeConstantGlobal).

@ChrisJefferson
Copy link
Contributor Author

Note the optimisations this supports are currently very limited. It only simplifies code of the form if true then or if false then. We could easily support more advanced simplifications, but I would prefer to add only a small set (a future system based on turning bytecode into GAP objects could do clever, more extensive, rewrites).

@olexandr-konovalov olexandr-konovalov added the gapdays2017-fall Issues and PRs that arose at https://www.gapdays.de/gapdays2017-fall label Sep 9, 2017
@fingolfin
Copy link
Member

BTW, why do you capitalise "Constant" in e.g. the commit message "Add Constant support" ? Shouldn't it be rather "Add support for constant variables" or so?

lib/global.g Outdated
@@ -92,6 +102,16 @@ MAKE_READ_WRITE_GLOBAL := MakeReadWriteGVar;

#############################################################################
##
#F MAKE_CONSTANT_GLOBAL ( <name> ) . . .make a global variable constant
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add at least a space before "make". But actually there should be enough . . . to right-align the text afterwards... Alternatively, just remove the whole . . .make a global variable constant bit, as it is kind of redundant given the following text.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still would like to see that space (or, as in my other comment: Remove that line).

lib/global.gd Outdated
@@ -155,6 +170,26 @@ DeclareGlobalFunction("MakeReadWriteGlobal");

#############################################################################
##
#F MakeConstantGlobal( <name> ) . . . . make a global variable constant
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again the . . . business... should change the triple spaces to a single one and insert more . -- the same in other places, too, of course

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I copied the triple spaces from the function directly above, and below, this one. This file has either triple spaces, or double spaces, never a single one.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are 25 places in the whole library using a triple space in that location, i.e. less than 1% -- I think they come from somebody not being careful and/or not caring.

Now, I am first to agree that it sucks to manually update these kinds of comments. But I still think there are only two sane choices:

  1. Abolish them, possibly incrementally (by just not adding them to new code)
  2. Keep using them "as intended" -- and then triple spaces to me look quite clearly like a bug, which simply proliferates by copy&paste.

tl;dr: please either delete this line, or format it to match the rest of the library (and not just the rest of this comparatively short file).

lib/global.gd Outdated
## MakeConstantGlobal ( <A>name</A> ) marks the global variable named
## by the string <A>name</A> as constant. A constant variable can never
## be changed or made read-write. Constant variables can only take an
## integer value, <C>true</C> or <C>false</C>.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should that be "immediate integer value"? Hmm, though not everybody will know what that means..

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the concept is defined in the documentation -- not anywhere obvious, anyway. Maybe just say that there is a limit on the size of the integers.

lib/global.gi Outdated
## MakeConstantGlobal ( <name> ) marks the global variable named
## by the string <name> as constant
##
## A warning is given if <name> is already constant
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add extra space before A warning

lib/global.gi Outdated
##
#F MakeConstantGlobal ( <name> ) . . . . make a global variable constant
##
## MakeConstantGlobal ( <name> ) marks the global variable named
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the weird wrapping here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

once again, same as the wrapping on the function just before

can be made read-write again by calling <Ref Func="MakeReadWriteGlobal"/>.
GAP also features <E>constant</E> variables,
which can never be changed. In some cases, GAP can optimise code which
uses <E>constant</E> variables, as their value never changes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, the user at this point knows very little about constants, and has no idea how to learn more. E.g. they won't know that only immediate integers and some booleans can be made constant. I'd add a ref to MakeConstantGVar here, and then make sure they can learn enough about that in its documentation (which currently does not seem to exist...?).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting back to this, it seems this this should be MakeConstantGlobal instead (also in the example below)

src/code.c Outdated
Stat body2 = PopStat();
cond2 = PopExpr();
PushExpr(cond2);
PushStat(body2);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't really need to pop/push body2 (and the original code also did not need to push/pop body...

// Remove entire if statement
PopStat();
PopExpr();
PushStat(NewStat(T_EMPTY, 0));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... is that PushStat really necessary?

src/gvars.c Outdated
@@ -799,10 +856,9 @@ Obj FuncMakeReadWriteGVar (
Int IsReadOnlyGVar (
UInt gvar )
{
return !INT_INTOBJ(ELM_GVAR_LIST(WriteGVars, gvar));
return INT_INTOBJ(ELM_GVAR_LIST(WriteGVars, gvar)) == 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rewrite this as return ELM_GVAR_LIST(WriteGVars, gvar) == INTOBJ_INT(0)

src/gvars.c Outdated
Obj self,
Obj name )
{
/* check the argument */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I try to avoid those "right aligned with lots of spaces" comments, and just use C++ style // comments. While this makes the new code slightly different than the old code, I think we should eventually replace all those weird aligned comments with these

(That's just a vague suggestion, not an actual request to change the PR).

function (name)
local isro;
CheckGlobalName( name );
isro := IS_CONSTANT_GLOBAL(name);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why "isro" ? Probably copy & paste from IsReadOnlyGlobal, but this name doesn't make sense here.

@@ -1616,6 +1654,11 @@ void CodePow ( void )
}


void CodeGAPSmallInt(Obj val)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd really prefer if this was called CodeImmediateInt -- saying "small int" is quite ambiguous. This code instead deals with "immediate integer handles" (to use the language from gmpints.c)

[ Sorry, I thought I had mentioned this in my previous PR? But perhaps I failed to actually submit that comment? I can't find it now, in any case :-/ ]

#ifdef HPCGAP
UInt var = GVarName( "HPCGAP" );
AssGVar( var, True );
MakeReadOnlyGVar( var );
MakeConstantGVar( var );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps IsBound(CONST_VAR) should be optimized true if CONST_VAR is bound during coding? (I am not asking for this to be done in this PR, just wondering)

*/
Int IsConstantGVar(UInt gvar)
{
return INT_INTOBJ(ELM_GVAR_LIST(WriteGVars, gvar)) == -1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better (and slightly safer...) code can be generated if you instead write return ELM_GVAR_LIST(WriteGVars, gvar) == INTOBJ_INT(-1); -- this would then also match IsReadOnlyGVar above.

lib/global.gd Outdated
@@ -155,6 +170,26 @@ DeclareGlobalFunction("MakeReadWriteGlobal");

#############################################################################
##
#F MakeConstantGlobal( <name> ) . . . . make a global variable constant
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are 25 places in the whole library using a triple space in that location, i.e. less than 1% -- I think they come from somebody not being careful and/or not caring.

Now, I am first to agree that it sucks to manually update these kinds of comments. But I still think there are only two sane choices:

  1. Abolish them, possibly incrementally (by just not adding them to new code)
  2. Keep using them "as intended" -- and then triple spaces to me look quite clearly like a bug, which simply proliferates by copy&paste.

tl;dr: please either delete this line, or format it to match the rest of the library (and not just the rest of this comparatively short file).

@@ -825,6 +881,34 @@ static Obj FuncIsReadOnlyGVar (
return IsReadOnlyGVar(GVarName(CSTR_STRING(name))) ? True : False;
}

/****************************************************************************
**
*F IsConstantGVar( <gvar> ) . . . . . . return if a variable is a constant
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hrmf, somehow GitHub decided that the comments I was collecting for a review were all to be suddenly published as comments instead, taking away from me the possibility to edit them beforehand... I was about to add the following (or possibly, replace those comments completely with it) regarding the comment formatting: "OK, I see now that these files you are touching are particularly bad when it comes to the comment formatting (and grammar...). So it probably makes more sense to go over them separately later on, and to "clean up" those comments, and/or to remove parts of them."

Copy link
Member

@fingolfin fingolfin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, this looks good to me now. There are some minor formatting issues in my view (such as places with double empty lines or trailing spaces, new code which has comments of the form /* some text + a zillion spaces for right-aligning */ instead of // some text, etc., and perhaps 1-2 other minor chances for improvements, but nothing really that warrants holding this back much longer.

I'd still feel better if @stevelinton or @markuspf also had a look at this before merging.

@fingolfin fingolfin added kind: enhancement Label for issues suggesting enhancements; and for pull requests implementing enhancements kind: new feature labels Sep 19, 2017
@fingolfin fingolfin added this to the GAP 4.9.0 milestone Sep 19, 2017
@stevelinton
Copy link
Contributor

My only concern with this is that if we want to take it further and have a "proper" optimisation framework then quite a bit of it will be superceded. On reflection though, it would be the implementation, and maybe the printing of functions that had optimised versions that would change, and not the UI. This may be developed further in future -- for instance a Constant Var holding a function would allow inlining. I imagine in future we might also stop printing the optimised versions of functions, but rather hold the original and the optimised bodys and print one while running the other, so again maybe the documentation should make clear that this may change, but we promise it will never hurt to make constant things constant.

@ChrisJefferson
Copy link
Contributor Author

I agree about saying that we don't promise to show optimised functions.

I would prefer a general framework based on @markuspf's transforming of GAP functions to GAP objects -- in particular I would love GAP to have inlining.

Also, I don't think we should expand this much further -- it would be easy to continue through the parser and handle things like true or X is true, but then we would end up with effectively "3" execution paths -- immediate execution, turning into bytecode and execution while generating bytecode.

@fingolfin
Copy link
Member

Supporting simplification of true or X, IsBound(constVar), false and X, etc. actually seems pretty much straightforward, and I wouldn't consider it a "third execution path" -- OK, in some sens it is, but this is really basic stuff, running in guaranteed constant time. On the plus side, it would make it possible to simply expressions involving multiple constant vars.

Of course it's tricky were to draw the line... Simplifying expressions like 1+1, or, more realistically, 2^20, would be a natural next step, and again pretty easy to implement, but of course now things get way more complex, as the result may not fit into an immediate integer, or may even raise an error (think 1/0).

And I really think this would already provide some nice (minor) speed up for some code, without needing the full power (and considerable complexity) of a full code transformation framework...

Anyway, that's just some thoughts, but of course they in no way speak against this PR :-).

GAP also features <E>constant</E> variables, which are created by calling
<Ref Func="MakeConstantGlobal"/>. Constant variables can never be changed.
In some cases, GAP can optimise code which uses <E>constant</E> variables,
as their value never changes. This can be observed by printing the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would delete the sentence beginning "This can be observed", or add a warning that that might change.
Otherwise approved.

lib/global.gd Outdated
## MakeConstantGlobal ( <A>name</A> ) marks the global variable named
## by the string <A>name</A> as constant. A constant variable can never
## be changed or made read-write. Constant variables can only take an
## integer value, <C>true</C> or <C>false</C>.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the concept is defined in the documentation -- not anywhere obvious, anyway. Maybe just say that there is a limit on the size of the integers.

@olexandr-konovalov
Copy link
Member

@ChrisJefferson just adding ManSection to the documentation does not automatically add it to the manual - it needs to be hooked somewhere via the Include mechanism. This is why cross-reference to MakeConstantGlobal is not resolved, as you can see at https://travis-ci.org/gap-system/gap/jobs/279972109. Unfortunately, that test does not fail automatically when cross-references are not resolved (it only fails if the build completely fails to produce manuals), so one should check it manually for any PR that updates manuals.

Perhaps we can detect unresolved cross-references too - but should carefully do that to ignore reports on them during the first run of the build.

@ChrisJefferson ChrisJefferson deleted the constant branch November 6, 2017 12:44
@fingolfin fingolfin added the release notes: added PRs introducing changes that have since been mentioned in the release notes label Dec 13, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
gapdays2017-fall Issues and PRs that arose at https://www.gapdays.de/gapdays2017-fall kind: enhancement Label for issues suggesting enhancements; and for pull requests implementing enhancements kind: new feature release notes: added PRs introducing changes that have since been mentioned in the release notes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants