-
Notifications
You must be signed in to change notification settings - Fork 49
Explanation of how to implement a semantic check #939
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
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @psteinfeld for writing this document based on your experience of implementing the do index variable redefinition check. Should be helpful for new people writing semantic checks.
I like the title of this PR (Explanation of how to implement a semantic check) but the filename probably has to be modified to look something like the title of the PR.
What information would you have missed if you had the visitor at the ActualArgSpec level? Is it just the source location?
Have noted some minor nits inline.
documentation/FrontEndTutorial.md
Outdated
shall neither be redefined nor become undefined while the DO construct is active. | ||
``` | ||
One of the ways that DO variables might be redefined is if they are passed to | ||
functions with dummy arguments whose ```INTENT``` is ```INTENT(IN)``` or |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
INTENT(OUT)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use single backquotes (grave accents) for inline code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
documentation/FrontEndTutorial.md
Outdated
```INTENT``` of the dummy argument associated with the actual argument from the | ||
a function called ```dummyIntent()``` in the class |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo "the a function called"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
documentation/FrontEndTutorial.md
Outdated
nodes. I would look at each of these nodes to determine the ```INTENT``` of | ||
the associated dummy argument. | ||
|
||
This combination of the traveral framework and ```dummyIntent()``` would give |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo traversal
Thanks for reviewing this, @kiranchandramohan. I wasn't sure what to call the document. How about "ImplementingASemanticCheck.md"? I probably should have discussed this in the document, but at one point I had a visitor that triggered on the type |
Since you have written in a conversational style it will be good to have this info that you went the parser::ActualArg path and found that the information that you need is not available. A word about why source information is there in some nodes and not there in others would also be useful. Also, some information about how an expression models a function call might be useful. In the case of subroutines, you have a call statement so it is obvious there.
Are you hinting here that the Subroutine's arguments have the Actual Argument info but a Function's arguments do not have? |
A bit of time spent on where a semantic check should be added would also be good. That is probably the first thing that hits a first-time contributor. Some high-level guidance like if it is an Execution Construct it should be here or if it is a Declaration Construct it should be there. When should a person write his own checker and when not. Should a check be added during name or label resolution? Also in some cases, it is obvious like If it is something related to a do loop, OpenMP or co-array. Feel free to ignore if this is outside the scope of this document. |
Thanks, Kiran. The very fact that you're wondering about this means that I should have included it in the document. I'll do that now. I plan to explain the difference between this case (for function calls), and the case for subroutine calls along with their relevant differences that affected the implementation. Please review again after I add this information.
Will do.
I plan to explain this further in the addition I describe above, but here's a preview. In both cases, the most difficult piece of information I need is the INTENT of the dummy argument. This is accessible through the
The For a function call, though, there is no way to map from a parse tree node to an For a |
I can certainly add a little more information about how I decided where to implement this check. I think it is out of the scope of this document to cover the topic generally. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
|
||
I also used this program to produce a parse tree for the program using the command: | ||
```bash | ||
./bin/f18 -fdebug-dump-parse-tree -fparse-only testfun.f90 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe just f18
instead of ./bin/f18
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I think your choice is better.
checking is implemented in the files .../lib/semantics/semantics.[cc,h]. | ||
Here's a fragment of the declaration of the framework's parse tree visitor from | ||
.../lib/semantics/semantics.cc: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you could simply put lib/semantics/semantics.[cpp,h]
& lib/semantics/semantics.cpp
. (They are in code format)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. Given the rearrangement of the header files, I think it's best not to mention them at all. I'll remove them and change all of the references to ".cc" to ".cpp".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, it looks like there are several header files I need to mention. I'll fix up their path names.
node. | ||
|
||
Since my semantic check was focused on DO CONCURRENT statements, I added it to | ||
the file .../lib/semantics/check-do.cc where most of the semantic checking for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here: lib/semantics/check-do.cpp
.
|
||
## Taking advantage of prior work | ||
When implementing a similar check for SUBROUTINE calls, I created a utility | ||
functions in .../lib/semantics/semantics.[cc.h] to emit messages if |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here & the rest of this doc. (note that .cc
was changed to .cpp
too)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep.
`evaluate::ActualArgument` nodes. The code that I planned to model it on | ||
was the existing infrastructure that collected all of the `semantics::Symbol` nodes from an | ||
`evaluate::Expr`. I found this implementation in | ||
.../lib/evaluate/tools.cc: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I strongly recommend getting rid of all the .../
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do.
@@ -0,0 +1,813 @@ | |||
<!--===- documentation/FrontEndTutorial.md |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
haven't decided the final name yet?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch!
And thanks for reading through this and providing feedback.
2263a94
to
12fe847
Compare
They hold all of the information I needed. | ||
|
||
So my plan was to start with the `parser::Expr` node and extract its | ||
associated `evaluate::Expr` field. I would then traverse the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think a little bit explanation between parser::Expr
and evaluate::Expr
would be better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. I was certainly confused when I first learned that there were two different types named Expr
in the compiler. I'll add a short explanation.
This is the story of implementing semantic checks for passing DO variables to functions with dummy arguments with INTENT(OUT) or INTENT(INOUT).
12fe847
to
889f909
Compare
The second `Expr` type is in the `evaluate` namespace. The `evaluate` | ||
namespace contains many types associated with semantic checking of expressions. | ||
`evaluate::Expr` is defined in the file `include/flang/evaluate/expression.h`. | ||
It represents an expression after it has undergone semantic checking and | ||
contains information that is only available after semantic analysis. This | ||
information includes the Fortran type of the expression, whether it's a | ||
reference to a function, whether it's an actual argument, etc. After an | ||
expression has undergone semantic analysis, the field `typedExpr` in the | ||
`parser::Expr` node is filled in with a pointer to the analyzed expression in | ||
`evaluate::Expr`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice, thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The evaluate::Expr<T>
template classes, which are parameterized over the various types of Fortran, constitute a suite of strongly-typed representations of valid Fortran expressions of type T
that have been fully elaborated with conversion operations and subjected to constant folding.
This is the story of implementing semantic checks for passing DO variables to functions with dummy arguments with INTENT(OUT) or INTENT(INOUT). Original-commit: flang-compiler/f18@889f909 Reviewed-on: flang-compiler/f18#939
…/ps-dev-story Explanation of how to implement a semantic check Original-commit: flang-compiler/f18@bedca14 Reviewed-on: flang-compiler/f18#939
This is the story of implementing semantic checks for passing DO variables to functions with dummy arguments with INTENT(OUT) or INTENT(INOUT). Original-commit: flang-compiler/f18@889f909 Reviewed-on: flang-compiler/f18#939
This is the story of implementing semantic checks for passing DO
variables to functions with dummy arguments with INTENT(OUT) or
INTENT(INOUT). I wrote it as an example of how to make changes
to the compiler for a newcomer.