[PATCH] D64646: [OPENMP]Add support for analysis of if clauses.

Alexey Bataev via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Mon Jul 15 07:13:42 PDT 2019

ABataev marked an inline comment as done.
ABataev added a comment.

Thanks for the review!

Comment at: test/Analysis/cfg-openmp.cpp:58-67
 #pragma omp distribute simd
   for (int i = 0; i < 10; ++i)
     argc = x;
-// CHECK-NEXT:  27: x
-// CHECK-NEXT:  28: [B1.27] (ImplicitCastExpr, LValueToRValue, int)
-// CHECK-NEXT:  29: argc
-// CHECK-NEXT:  30: [B1.29] = [B1.28]
-// CHECK-NEXT:  31: #pragma omp for
+// CHECK-NEXT:  [[#FOR:]]: x
+// CHECK-NEXT:  [[#FOR+1]]: [B1.[[#FOR]]] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:  [[#FOR+2]]: argc
+// CHECK-NEXT:  [[#FOR+3]]: [B1.[[#FOR+2]]] = [B1.[[#FOR+1]]]
NoQ wrote:
> I'm slowly updating my mental model of these CFGs. Just to confirm my understanding - tried the following example:
> ```lang=c++
> int main(int argc, char **argv) {
>   int x = 0;
> #pragma omp for
>   for (int i = 0; i < 10; ++i)
>     x += argv[i];
> }
> ```
> The CFG was as follows:
> ```
>    1: 0
>    2: int x = 0;
>    3: x
>    4: argv
>    5: [B1.4] (ImplicitCastExpr, LValueToRValue, char **)
>    6: i
>    7: [B1.6] (ImplicitCastExpr, LValueToRValue, int)
>    8: [B1.5][[B1.7]]
>    9: [B1.8] (ImplicitCastExpr, LValueToRValue, char *)
>   10: [B1.3] += [B1.9]
>   11: #pragma omp for
>     for (int i = 0; i < 10; ++i)
>         [B1.10];
> ```
> Do i understand correctly that `[B1.10]` aka `argv[0]` is going to act like an "argument" to the "outlined function" and then it's going to be re-used (as if it was a "local" "variable") on subsequent iterations of the loop (i.e., assigned values `argv[1]`, ..., `argv[9]`)? I.e., the "function" is going to be responsible for computing `argv[1]` and storing it in the "parameter variable" (`OMPCapturedExprDecl` which is a sub-class of `VarDecl`) that previously contained `argv[0]`, but it's not responsible for computing `argv[0]` itself, right?
`argv` here is the shared variable, so it is passed by reference to the "outlined function". We do not create local copy of this variable here, we use the original `argv` in the "outlined function".
you can consider this code as something like this:
char **argv;
int x = 0;
outlined(x, argv);

void outlined(char **&argv, int &x) {
  for(int i =0; i < 10; ++i)
  x += argv[i];

This is very schematic but good enough to understand how it works.

`OMPCapturedExprDecl` is used only in some rare cases, when we need to pass the expression to the outlined region. For example:
#pragma omp target parallel if(a+b)
After codegen it must look like this:
<OMPCapturedExprDecl> int .captured_expr. = a+b;
if (.captured_expr.) {
  offload target_outlined(.captured_expr.)
} else {
  call on host target_outlined(.captured_expr.)
void target_outlined(int .captured_expr.) {
  if (.captured_expr.)
    parallel outlined();
    serialized outlined();
void outined() {
In this case `if` clause is applied to both, `target` and `parallel` constructs. We could capture variables `a` and `b` and calculate `a+b` inside of the target region but this is not effective. Instead, it is better to capture the result of `a+b` condition into the special variable and capture only this single variable by value (the value of clauses in most cases must be pre-evaluated before the real execution of the OpenMP construct). Does it make it a little bit clearer?
`OMPCapturedExprDecl` is used only in some rare cases, only for the complex combined constructs (which consists of several simple constructs) and only for the clauses, which require expression evaluation before entering the construct.

  rC Clang



More information about the cfe-commits mailing list