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

Optimize true/false conditions when coding if-statements #2199

Merged
merged 1 commit into from
Feb 27, 2018

Conversation

fingolfin
Copy link
Member

Short version: This PR turns if true then ... else ... fi; and if false then ... fi; into something that's even closer to #if 1 ... #else ... #endif and #if 0 ... #endif, by making it ignore access to global variables inside the else resp. the if false branches. This is useful when using if IsHPCGAP to add HPC-GAP specific functionality into code. As one minor example for that, look at the lib/system.g change in this PR. Another example is that right now in master, if you modify lib/type1.g or lib/oper1.g (forcing GAP to use them, not their C counter parts), you'll see a bunch of warnings about undefined globals. With this PR, these are gone.

Personally, I find this highly useful, esp. when writing code involving if IsHPCGAP (so also in packages at some point). But of course one can also be critical of this change: It might cause one to miss bugs in code that one "temporarily" disabled using if false then .... However, I'd argue that this is not a major problem; one will after all immediately get a warning once on changes this to if true then... .

Here is the full commit message:

We already had some code which "optimized" some if-statements
with one or two conditions, where one or both were constant equal
to true or false. We skipped branches whose condition was
always false. However, we did not use the IntrIgnoring mechanism
for that. Thus, such code would still trigger warnings if it contained
undefined globals, e.g.

gap> f:=function()  if false then undefined_global(); fi; end;;
Syntax warning: Unbound global variable
f:=function()  if false then undefined_global(); fi; end;;
                                             ^

This can be viewed as a feature, or as a bug, depending on view point.
A reason to consider it a "bug" (or at least an undesirable feature)
is when using global constants to only conditionally execute code, such
as this:

if IsHPCGAP then
    UNLOCK(lock);
fi;

This code is optimized away in regular GAP, but still triggers a warning
during parsing.

With this commit, we change how we deal with true/false conditions in
if-statements, by making use of the IntrIgnoring mechanism. This avoids
the warnings about globals in the examples above. It also has the side
effect of being "better" at optimizing away branches of an if-statement
which can never be executed.


// if the condition is 'true', ignore other branches of the if-statement
if (TNUM_EXPR(cond) == T_TRUE_EXPR) {
STATE(IntrIgnoring) = 1;
Copy link
Member Author

Choose a reason for hiding this comment

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

One thing I don't like about this PR is that I have to access IntrIgnoring twice in src/code.c; previously, there was no other access to IntrIgnoring, IntrReturning or IntrCoding in src/code.c. And only a handful of access to any of them outside of src/intrprt.c (namely in src/gap.c and src/read.c).

But this is only a minor blemish, IMHO

@fingolfin
Copy link
Member Author

Here is another reason why we may not want this, or at least not quite the way it is done in this PR: In the future, I would expect that we keep two copies of the body (which really is an abstract syntax tree of the function): one which represents a pristine copy of the original function (possibly even with comments retained?), and the other an optimized version, were code transformations have been applied, such as the if-statement optimizations in this PR, but also more (e.g. constant folding for things like 2^30). We might even implement a true bytecode system for GAP (which I think might give some interesting speedups), and from there going to a very simple JIT is easy.

But I think it'll be trivial to revert the changes in this PR in the future, or adapt them to, say, only suppress the warnings about the undefined globals but not actually ignore the code bodies. So, I am not overly concerned, but wanted to mention these thoughts for completeness.

We already had some code which "optimized" some if-statements
with one or two conditions, where one or both were constant equal
to `true` or `false`. We skipped branches whose condition was
always `false`. However, we did not use the `IntrIgnoring` mechanism
for that. Thus, such code would still trigger warnings if it contained
undefined globals, e.g.

    gap> f:=function()  if false then undefined_global(); fi; end;;
    Syntax warning: Unbound global variable
    f:=function()  if false then undefined_global(); fi; end;;
                                                 ^

This can be viewed as a feature, or as a bug, depending on view point.
A reason to consider it a "bug" (or at least an undesirable feature)
is when using global constants to only conditionally execute code, such
as this:

    if IsHPCGAP then
        UNLOCK(lock);
    fi;

This code is optimized away in regular GAP, but still triggers a warning
during parsing.

With this commit, we change how we deal with true/false conditions in
if-statements, by making use of the `IntrIgnoring` mechanism. This avoids
the warnings about globals in the examples above. It also has the side
effect of being "better" at optimizing away branches of an if-statement
which can never be executed.
@ChrisJefferson
Copy link
Contributor

I think we should merge this, although we should only add things (like this, and the earlier if HPCGAP work) which help us write GAP code, rather than just for performance improvements.

Also, we are already simplifying code anyway, and any future optimisation could perfectly well start from here, instead of from the original code.

@ChrisJefferson ChrisJefferson merged commit 144b52a into gap-system:master Feb 27, 2018
@fingolfin fingolfin deleted the mh/if-coding branch February 27, 2018 23:00
@fingolfin fingolfin added the release notes: to be added PRs introducing changes that should be (but have not yet been) mentioned in the release notes label Jul 31, 2018
@fingolfin fingolfin added release notes: added PRs introducing changes that have since been mentioned in the release notes and removed release notes: to be added PRs introducing changes that should be (but have not yet been) mentioned in the release notes labels Sep 21, 2018
@fingolfin fingolfin added kind: discussion discussions, questions, requests for comments, and so on and removed kind: request for comments labels Mar 21, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind: discussion discussions, questions, requests for comments, and so on kind: new feature release notes: added PRs introducing changes that have since been mentioned in the release notes topic: kernel
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants