[Compiler] how set flag or restrict properties when generate AST nodes

Hi,
I’m working on a uni project. I want to add a small feature on the compiler.
Currently, I have added a new syntax which has “GPU” as a keyword for the “on” locale statement. For example:

on GPU here do {
    forall a in A do
      a += 1.0;

    var C = + reduce A;
}

This will call another function buildOnGPUStmt in chapel/compiler/AST/build.cpp instead of buildOnStmt.
I try to build special forall and reduce expression base on whether it is in “on GPU” block or in normal “on” block. I want all statements and expression insdie this “on GPU” block to be built with certain properties.

Currently, in buildOnGPUStmt function, I have add an extra DefExpr to the return block statement. This DefExpr contains VarSymbol has a special symbol flag indicates whether it is in normal or special “on” block.
However, in buildReduceExpr, I cannot find access to the block statement built by buildOnGPUStmt so there is no information about whether this reduce expression is inside the “on GPU” block or not.
Is there any other way I can achieve this?
Is that possible to store a value in a flag where it can be accessed by all AST nodes?

Thanks.

1 Like

Hello Allie,

Here are some quick thoughts about your question.

First, be sure you are compiling with CHPL_COMM set to something other than “none” or that you pass --no-local to the compiler. Otherwise you might hit issues because the compiler does not expect on statements after the parser during a purely-local compilation.

The parser does not know where the forall and reduce things are going into. One solution is to have buildOnGPUStmt traverse its body and adjust the foralls and reduces that have been already built.

A better solution is to delay such adjustment until createTaskFunctions(), which converts on-blocks to “task functions”. You may want to label on GPU task functions with a separate flag. Then traverse their bodies, adjusting foralls and reduces.

Alternatively, when a forall or reduce is lowered, you can check whether its parentSymbol is such a task function. It will be more complicated if a forall is inside another parallel construct that, in turn, is inside an on GPU task function. Feel free to discuss that situation here when you need to handle it.

Vass

Hi Vass,
Thanks for your reply.
Could you provide more information on createTaskFunctions(), I couldn’t find an example usage for it.
Are there any examples of task functions?
Which phrase of the compiler is the converting to task functions in, any related file or document for me to learn more about this?

Allie,

createTaskFunctions is a pass in the compiler that is run just before resolve. The main code is in compiler/passes/createTaskFunctions.cpp .

Here we are talking about compiler internals, for which the best documentation is comments in the code and also the documents in $CHPL_HOME/doc/rst/developer/bestPractices/ .

In your situation I suggest examining the AST “before” and “after” this pass. For example you will see that an on-statement in the AST “before” will be replaced with a call to a task function in the AST “after”. Then, in the debugger set the compiler’s variable breakOnID to the ID of the task function node. See CompilerIRTricks.rst in the bestPractices directory. This will bring you to the code that creates that task function and that you may consider adding to.

Vass

edit:
For the traverse its body in buildOnGPUStmt approach:
I found that the reduce expression almost always nested in other expressions, such as c = + reduce A, the reduce CallExpr is actually the right hand side expression in a assignment CallExpr.
When I try to recursively search all the expressions in a block statement, I have to manually handle all the possible nested expression where a reduce could be placed. Am I on the right track of finding the reduce CallExpr?

Another place you can learn about the compiler’s passes and the way it represents programs is the compiler overview document. It is out of date in some ways but still has pretty good introductory material. https://github.com/chapel-lang/chapel/blob/master/doc/rst/developer/compilerOverview/compilerOverview.pdf

1 Like

Within buildOnGPUStmt, you should be able to use collectCallExprs on the block statement. Then traverse the vector that it populates looking for PRIM_REDUCE, ex.

for_vector(CallExpr, call, callsVector) {
  if (call->isPrimitive(PRIM_REDUCE)) {
    do the transformation;
  }
}
1 Like

Is there any advantage of modify in createTaskFunctions pass?
In my option, it is a pass after the buildOnStmt, it is better to replace the expression in the earliest stage, before all passes.
This pass seems only affects blocks with begin keyword.
Thanks.

Feel free to modify the expression early. You may be right in seeing no benefit in delaying until createTaskFunctions.