This is an archive of the discontinued LLVM Phabricator instance.

[WIP][OPENMP5.0] allow lvalue for motion clause
AbandonedPublic

Authored by cchen on Jan 15 2020, 2:49 PM.

Details

Reviewers
ABataev
jdoerfert
Summary

In OpenMP 5.0 we allow any lvalue for motion clause and map clause, below are some examples for lvalue:

int *p;

int **pp;

struct S {
  int struct *sp;
  double *d;
  struct S **sp_arr;
};
struct S *s;

#pragma omp target update to(*p)
#pragma omp target update to(*(p+3))
#pragma omp target update to((p+3)[k])

#pragma omp target update to(**pp)
#pragma omp target update to(*pp[0])
#pragma omp target update to(*(pp+l)[2])
#pragma omp target update to((pp+l)[2][3])

#pragma omp target update to(*(s->d))
#pragma omp target update to(*(s->sp->d))
#pragma omp target update to(*(s->sp->d+k))
#pragma omp target update to((s->sp->d+k)[2])
#pragma omp target update to(*(s->sp->sp_arr+k))

Now only add test for motion clause, after the implementation is fine,
will add test for map since the core logic is in the same helper
function.

Event Timeline

cchen created this revision.Jan 15 2020, 2:49 PM
Herald added a project: Restricted Project. · View Herald Transcript
cchen edited the summary of this revision. (Show Details)Jan 15 2020, 3:01 PM
ABataev added inline comments.Jan 15 2020, 3:15 PM
clang/lib/CodeGen/CGOpenMPRuntime.cpp
7707–7709

This assertion must check that the expression is just an lvalue, no?

clang/lib/Sema/SemaOpenMP.cpp
15525–15526

Why just the LHS is analyzed? Also, what about support for other expressions, like casting, call, choose etc., which may result in lvalue?

cchen marked 2 inline comments as done.Jan 16 2020, 8:54 AM
cchen added inline comments.
clang/lib/CodeGen/CGOpenMPRuntime.cpp
7707–7709

Yes.

clang/lib/Sema/SemaOpenMP.cpp
15525–15526
  1. LHS: I'll fix that
  2. I'll add support for casting, call, etc
  3. For "choose" are you referring to something like (a < b ? b : a)?

Not sure that we need to dig that deep. Maybe just keep thw original analysis for the known expressions and map all other lvalues without some extra analysis, just like DeclRefExpr nodes?

Hmm, we still need to find some basic decl to remap it successfully at the codegen. Not sure that we'll be able to support it in full. It would be good to investigate how we can handle them at the codegen.

cchen marked an inline comment as done.Jan 21 2020, 11:44 AM
cchen added inline comments.
clang/lib/Sema/SemaOpenMP.cpp
15525–15526

For the handling of BinaryOperator, I'm not sure why should we handle RHS since the possible source code I can imagine is *(ptr+l) or something like (ptr+l)[3].

ABataev added inline comments.Jan 21 2020, 11:51 AM
clang/lib/Sema/SemaOpenMP.cpp
15525–15526

*(2+ptr) is correct too. And, btw, 3[ptr+1] too, especially in C. Moreover, something like *(b+c) is also allowed. That's why I said that better to avoid deep analysis of lvalues, there are too many combinations and better to switch to something basic.

cchen marked an inline comment as done.Jan 21 2020, 12:50 PM
cchen added inline comments.
clang/lib/Sema/SemaOpenMP.cpp
15525–15526

But at least we need the base declaration for motion/map clause, right? And to achieve this, we need to peel the expression to get the DeclRefExpr.

ABataev added inline comments.Jan 21 2020, 12:52 PM
clang/lib/Sema/SemaOpenMP.cpp
15525–15526

What's the base declaration in *(a+b)?

cchen marked an inline comment as done.Jan 21 2020, 1:08 PM
cchen added inline comments.
clang/lib/Sema/SemaOpenMP.cpp
15525–15526

I understand your point, I'm just not sure how to handle (do not analyze) this given that we need to fill VarDecl for OMPToClause/OMPFromClause.

cchen marked an inline comment as done.Jan 21 2020, 1:17 PM
cchen added inline comments.
clang/lib/Sema/SemaOpenMP.cpp
15525–15526

But is *(a+b) even valid? Clang and GCC both emit error message: https://godbolt.org/z/jqDBx_

ABataev added inline comments.Jan 21 2020, 1:31 PM
clang/lib/Sema/SemaOpenMP.cpp
15525–15526

Yes, in this form it is not. But here is another form *(a+*b) or *(a+(unsigned long long)b). You an try to filter rvalues out of all these forms, though and still try to find a base decl. But still, there are going to be some cases where you won't be possible to handle them correctly, like foo().
If you still want to dig that deep, I would recommend to use RecursiseStmtVisitor. If an expression is rvalue - throw it out of analysis. If base decl is not single, not variable and not member decl - emit an error.

cchen updated this revision to Diff 240029.Jan 23 2020, 3:29 PM

Add a checker for locator (test is not complete yet).

The logic of finding basic decl in LocatorChecker:

  • int *B; omp target map(*B)
    • B
      • pointer count (* in type): 1
      • deref count: 1
      • B is basic decl since pointer count equal to deref count
  • int *B, l; omp target map(*(B+l))
    • B
      • pointer count (* in type): 1
      • deref count: 1
      • B is basic decl since pointer count equal to deref count
    • l
      • pointer count (* in type): 0
      • deref count: 1
      • pointer count = 0, deref count 1 => not equal
  • int **B, **l; omp target map((B+**l)[1][2]
    • B
      • pointer count (* in type): 2
      • deref count: 2 (2 array subscript)
      • B is basic decl since pointer count equal to deref count
    • l
      • pointer count (* in type): 2
      • deref count: 4 (2 array subscript, 2 unary op)
      • pointer count = 2, deref count 4 => not equal

Thanks for working on this! While you are at it, *this is probably one of the most important ones to test and support.

ABataev added inline comments.Jan 24 2020, 6:45 AM
clang/lib/CodeGen/CGOpenMPRuntime.cpp
7708–7709

This must be updated, I assume. Instead need to check that it is an lvalue.

7837

Here we should not have any functiondecls. Must be an assert.

clang/lib/Sema/SemaOpenMP.cpp
15212

I don't think anything except for VarDecls must be allowed here.

15235

Need a check that this is a dereference op. Also, maybe allow using an addr_of operation?

15244–15245

Why you have all these comments here?

15267–15271

Some extra checks for the allowed operators are required.

15268

FunctionDecls should not be allowed here

15276

I would add a check that the child is and expression and not a glvalue, then do not analyze it.

15281

getFoundBase or something like this?

15283

Why do you need components list here?

15327

Same here, no function decls

15521

Why are using IgnoreParenImpCasts() here? It drops implicit casts to RValue.

16058–16059

Message should be updated too.

16059

Why MLV_LValueCast must be allowed here?

16124

Again, functiondecls must not be allowed here. I would suggest emitting a warning for them (that user mapped a function) a drop them from the mapping list.

clang/test/OpenMP/target_teams_map_messages.cpp
441–442

Not sure that this must be supported. What is the base decl here, x or y?

cchen marked 2 inline comments as done.Jan 24 2020, 8:24 AM
cchen added inline comments.
clang/lib/CodeGen/CGOpenMPRuntime.cpp
7837

Don't we need to support something like #pragma omp target map(r.S.foo()[:12])?

clang/lib/Sema/SemaOpenMP.cpp
15283

Since I need to insert the information in VisitDeclRefExpr.

ABataev added inline comments.Jan 24 2020, 8:34 AM
clang/lib/CodeGen/CGOpenMPRuntime.cpp
7837

It does not lead to the actual mapping. Better to inform the user about this rather than consuming it silently.

clang/lib/Sema/SemaOpenMP.cpp
15283

You can do this outside of this class if you need to do it. Still. you have this GetDRE() member function.

cchen marked an inline comment as done.Jan 24 2020, 12:58 PM

Thanks for working on this! While you are at it, *this is probably one of the most important ones to test and support.

Can anyone tell me how to get ValueDecl from CXXThisExpr? I cannot find any method return decl in https://clang.llvm.org/doxygen/classclang_1_1CXXThisExpr.html#details.
Thanks!

clang/lib/Sema/SemaOpenMP.cpp
15235

is addr_of operation allowed in lvalue?

In this code:

int arr[50];

#pragma omp target map(&arr)
  {}

We now reject &arr since RE->IgnoreParenImpCasts()->isLValue() return false. (RE is the expr of &arr)

cchen marked an inline comment as done.Jan 24 2020, 12:59 PM
cchen added inline comments.
clang/lib/Sema/SemaOpenMP.cpp
15235

BTW, RE->isLValue() also return false in this case.

Thanks for working on this! While you are at it, *this is probably one of the most important ones to test and support.

Can anyone tell me how to get ValueDecl from CXXThisExpr? I cannot find any method return decl in https://clang.llvm.org/doxygen/classclang_1_1CXXThisExpr.html#details.
Thanks!

CXXThisExpr is an expression without associated declaration.

clang/lib/Sema/SemaOpenMP.cpp
15235

I'm not saying that &var must be allowed, but something like *(&var). Of course, just &var is an rvalue.

cchen marked an inline comment as done.Jan 24 2020, 1:10 PM
cchen added inline comments.
clang/lib/Sema/SemaOpenMP.cpp
15235

Got it, thanks for the clarification!

cchen marked an inline comment as done.Jan 27 2020, 1:50 PM

Thanks for working on this! While you are at it, *this is probably one of the most important ones to test and support.

Can anyone tell me how to get ValueDecl from CXXThisExpr? I cannot find any method return decl in https://clang.llvm.org/doxygen/classclang_1_1CXXThisExpr.html#details.
Thanks!

CXXThisExpr is an expression without associated declaration.

Then which kind of thing should I sent to CurComponents if we do not have associated declaration for CXXThisExpr? We can't just send nullptr, right?

clang/lib/Sema/SemaOpenMP.cpp
16059

I'm doing this since isLValue return false for either C style casting CXX style casting and MLV_LValueCast can categorize these two as MLV_LValueCast.

Thanks for working on this! While you are at it, *this is probably one of the most important ones to test and support.

Can anyone tell me how to get ValueDecl from CXXThisExpr? I cannot find any method return decl in https://clang.llvm.org/doxygen/classclang_1_1CXXThisExpr.html#details.
Thanks!

CXXThisExpr is an expression without associated declaration.

Then which kind of thing should I sent to CurComponents if we do not have associated declaration for CXXThisExpr? We can't just send nullptr, right?

Check how compiler handles mapping of this[0:1], which is the same as *this.

clang/lib/Sema/SemaOpenMP.cpp
16059

Are they the lvalues according to the standard? If not, no need for this analysis.

cchen updated this revision to Diff 241291.Jan 29 2020, 2:14 PM

Fix based on feedback

cchen marked 21 inline comments as done.Jan 29 2020, 2:17 PM
cchen updated this revision to Diff 241293.Jan 29 2020, 2:23 PM

Update due to negligence

ABataev added inline comments.Jan 30 2020, 9:08 AM
clang/lib/Sema/SemaOpenMP.cpp
15201

Seems to me, you're skipping many expressions, which could be supported. Did you try to test it with casting expressions and others?

15203–15205

Use default initializers for fields.

15213

Better to use early exit where possible to reduce structural complexity of the functions.

15215–15216

This really looks ugly. Need to find a better solution.

15233

Why do you need to count the number of dereferences? And have this comparison here?

15267–15268

Restore original code

15267–15268

If you have the visitor class, you can replace all this code with an analysis in the visitor.

15523

General question about several cases. How we're going to support them?

  1. (a ? b : c).
  2. __builtin_choose_expr(a, b, c).
  3. a = b.
  4. a?:b
  5. __builtin_convertvector(x, ty)
  6. (int&)a
  7. v.xy, where v is an extended vector
  8. a.b, where b is a bitfield
  9. __builtin_bit_cast(v, ty)
  10. const_cast<ty &>(a)
  11. dynamic_cast<ty &>(a)
  12. reinterpret_cast
  13. static_cast
  14. typeid() (also is an lvalue).
  15. __uuidof(*comPtr)
  16. lambda calls
  17. User defined literals
15524

Better to pass CurComponents as an argument at the construction of the checker to avoid extra filling/copying.

cchen marked an inline comment as done.Jan 31 2020, 1:55 PM
cchen added inline comments.
clang/lib/Sema/SemaOpenMP.cpp
15523

I think we could first evaluate the lvalue, and then pass the result of &lvalue to device?

ABataev added inline comments.Jan 31 2020, 2:03 PM
clang/lib/Sema/SemaOpenMP.cpp
15523

What do you mean when you say evaluate lvalue? In veneral, it can be evaluated at the runtime. Do you propose to implement dyic translation? It will definetely slow down the execution on the device.

cchen marked an inline comment as done.Jan 31 2020, 2:13 PM
cchen added inline comments.
clang/lib/Sema/SemaOpenMP.cpp
15523

I mean evaluate lvalue before sending &lvalue to device. For example:

int a, b;
b = 5;
#pragma omp target map(a = b) // assign b to a before sending `&(a=b)` to device
{
   a++;
}

Therefore, the above example have the same semantics as this:

int a, b;
b = 5;
int &c = (a=b)
#pragma omp target map(c)
{
   a++;
}
ABataev added inline comments.Jan 31 2020, 2:24 PM
clang/lib/Sema/SemaOpenMP.cpp
15523

Sure, we do this already, generally speaking. The main problem here is how to map the address and associate it with address on the device. We do it at the compile time, support of general lvalues requires runtime translation + special instrumentation of the device code for address translation.

cchen updated this revision to Diff 243950.Feb 11 2020, 12:15 PM
  1. Refactor based on feedback and use the visitor class to integrate the analysis

in checkMapClauseExpressionBase.

  1. Handle more lvalue cases

I would suggest starting with the reworking of the existing implementation with StmtVisitor class and after that step-by-step extend the functionality of the visitor with handling other kinds а expressions.

clang/lib/Sema/SemaOpenMP.cpp
15274–15276

Again, this definitely should be reworked.

15293

The check is really bad. If you want to handle something like *(B+x) better to treat, say, B as the base and x as the index and, thus, treat the whole expression as something like B[x]

15303

Why do you need this?

15338

Do not call IgnoreParenImpCasts() here, just Visit(E). Also, I assume, it may lead to infinite recursion.

15356

Same here

cchen marked an inline comment as done.Feb 11 2020, 12:29 PM

Quoted Text

clang/lib/Sema/SemaOpenMP.cpp
15523
  • (a ? b : c).
    • Error out for now, not sure what to for this one
  • __builtin_choose_expr(a, b, c).
    • Allow this one since we know what to send to device at compile time
  • a = b.
    • Sema accept this one, but need more work for codegen I think (Clang not emit the a=b ir if "a=b" inside map/motion clause)
  • a?:b
    • What's the name of this kind of expression? I don't know what to do for this one
  • __builtin_convertvector(x, ty)
    • not sure
  • v.xy, where v is an extended vector
    • not sure
  • a.b, where b is a bitfield
    • Error out for this one since bitfield is not addressable
  • __builtin_bit_cast(v, ty)
    • Error out for this one since bitfield is not addressable
  • casts
    • Error out if the expression inside the cast is not lvalue
  • typeid() (also is an lvalue).
    • I guess we can support this just like normal variable?
  • __uuidof(*comPtr)
    • not sure
  • lambda calls
    • OpenMP 5.0 spec has rules for lambda. Now not error out for sema but need more work for codegen
  • User defined literals
    • error out since not addressable
cchen marked an inline comment as done.Feb 11 2020, 12:34 PM
cchen added inline comments.
clang/lib/Sema/SemaOpenMP.cpp
15293

I don't understand how to do this, is there any sample code that I can learn from? Thanks

ABataev added inline comments.Feb 11 2020, 12:50 PM
clang/lib/Sema/SemaOpenMP.cpp
15293

Not sure we have something like this, need to invent something new if we want to support lvalues in full. Or discard it as unsupported if we're unable to support it properly.

cchen abandoned this revision.Feb 19 2020, 2:33 PM