This is an archive of the discontinued LLVM Phabricator instance.

[OPENMP51]Initial support for the dispatch directive
ClosedPublic

Authored by mikerice on Mar 29 2021, 1:29 PM.

Details

Summary

Added basic parsing/sema/serialization support for dispatch directive.

Starting support for 'omp dispatch'. We are working on additional patches for the 'novariants' and 'nocontext' and 'adjust_args' and 'append_args' for 'omp declare variant'.

Diff Detail

Event Timeline

mikerice created this revision.Mar 29 2021, 1:29 PM
mikerice requested review of this revision.Mar 29 2021, 1:29 PM
Herald added a project: Restricted Project. · View Herald TranscriptMar 29 2021, 1:29 PM
ABataev added inline comments.Mar 29 2021, 1:50 PM
clang/include/clang/AST/StmtOpenMP.h
5150

final

5201

const

clang/lib/Basic/OpenMPKinds.cpp
649–651

Why do you need to push OMPD_dispatch here? Maybe OMPD_unknown should be enough?

clang/lib/Sema/SemaOpenMP.cpp
9766–9768

Why Expr->IgnoreParenImpCasts() does not work here?

mikerice marked 3 inline comments as done.Mar 29 2021, 5:47 PM

Thanks for the review.

clang/lib/Sema/SemaOpenMP.cpp
9766–9768

No reason not to use IgnoreParenImpCasts() instead of IgnoreParens() as far as I know. That should eliminate the need for visiting MaterializeTemporaryExpr. It unfortunately doesn't skip over CXXBindTemporaryExpr. Or were you suggesting something else?

ABataev added inline comments.Mar 30 2021, 5:13 AM
clang/lib/Sema/SemaOpenMP.cpp
9766–9768

Then just extend IgnoreParenImpCasts to support MaterializeTemporaryExpr and control it by the parameter.

mikerice added inline comments.Mar 30 2021, 8:30 AM
clang/lib/Sema/SemaOpenMP.cpp
9766–9768

CXXBindTemporaryExpr isn't the only reason to use the visitor. It ends up handling the top level statements and ExprWithCleanups easily and is fairly understandable to me. I went ahead and hand wrote the code to see what it would look like. Turns out to be long chains of one line if statement like this:

static Expr *getDirectCallExpr(Expr *E) {
  E = E->IgnoreParenImpCasts();
  if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(E))
    E = BTE->getSubExpr();
  if (auto *CE = dyn_cast<CallExpr>(E))
    if (CE->getDirectCallee())
      return E;
  return nullptr;
}

  SourceLocation TargetCallLoc;

  if (!CurContext->isDependentContext()) {
    Expr *TargetCall = nullptr;

    auto *E = dyn_cast<Expr>(S);
    if (!E) {
      Diag(S->getBeginLoc(), diag::err_omp_dispatch_statement_call);
      return StmtError();
    }

    if (auto *EWC = dyn_cast<ExprWithCleanups>(S))
      E = EWC->getSubExpr();

    E = E->IgnoreParenImpCasts();

    if (auto *CastE = dyn_cast<CastExpr>(E))
      if (CastE->getCastKind() == CK_ToVoid)
        E = CastE->getSubExpr()->IgnoreParenImpCasts();

    if (auto *COCE = dyn_cast<CXXOperatorCallExpr>(E)) {
      if (COCE->getOperator() == OO_Equal) {
        if (Expr *TE = getDirectCallExpr(COCE->getArg(1)))
          TargetCall = TE;
        else if (COCE->getDirectCallee())
          TargetCall = COCE;
      }
    } else if (auto *BO = dyn_cast<BinaryOperator>(E)) {
      if (BO->getOpcode() == BO_Assign)
        if (Expr *TE = getDirectCallExpr(BO->getRHS()))
          TargetCall = TE;
    } else if (auto *CE = dyn_cast<CallExpr>(E)) {
      if (CE->getDirectCallee())
        TargetCall = E;
    }
    if (!TargetCall) {
      Diag(E->getBeginLoc(), diag::err_omp_dispatch_statement_call);
      return StmtError();
    }
    TargetCallLoc = TargetCall->getExprLoc();
  }

I didn't originally write the visitor code so I am not attached to it or anything. Do you think this is better? Is there some rule-of-thumb when to use visitors and when to write it out by hand?

ABataev added inline comments.Mar 30 2021, 9:43 AM
clang/lib/Sema/SemaOpenMP.cpp
9766–9768

I think something like this will work

static Expr *getDirectCallExpr(Expr *E) {
  E = E->IgnoreParenCasts();
  if (auto *CE = dyn_cast<CallExpr>(E))
    if (CE->getDirectCallee())
      return E;
  return nullptr;
}

  SourceLocation TargetCallLoc;

  if (!CurContext->isDependentContext()) {
    Expr *TargetCall = nullptr;

    auto *E = dyn_cast<Expr>(S);
    if (!E) {
      Diag(S->getBeginLoc(), diag::err_omp_dispatch_statement_call);
      return StmtError();
    }

    E = E->IgnoreParenCasts();

    if (auto *BO = dyn_cast<BinaryOperator>(E)) {
      if (BO->getOpcode() == BO_Assign)
        TargetCall = getDirectCallExpr(BO->getRHS());
    } else {
      if (auto *COCE = dyn_cast<CXXOperatorCallExpr>(E))
        if (COCE->getOperator() == OO_Equal)
          TargetCall = getDirectCallExpr(COCE->getArg(1));
      if (!TargetCall)
        TargetCall = getDirectCallExpr(E);
    }
    if (!TargetCall) {
      Diag(E->getBeginLoc(), diag::err_omp_dispatch_statement_call);
      return StmtError();
    }
    TargetCallLoc = TargetCall->getExprLoc();
  }
mikerice added inline comments.Mar 30 2021, 11:56 AM
clang/lib/Sema/SemaOpenMP.cpp
9766–9768

Thanks. That's pretty good but it does not handle the CXXBindTemporaryExpr so the test:

Obj o;
o = foo_obj();

CXXOperatorCallExpr 0x5b50b0 'struct Obj' lvalue '='
|-ImplicitCastExpr 0x5b5098 'struct Obj &(*)(const struct Obj &) noexcept' <FunctionToPointerDecay>
| `-DeclRefExpr 0x5b4f98 'struct Obj &(const struct Obj &) noexcept' lvalue CXXMethod 0x5b4de8 'operator=' 'struct Obj &(const struct Obj &) noexcept'
|-DeclRefExpr 0x5b4d00 'struct Obj' lvalue Var 0x5b4830 'o' 'struct Obj'
`-MaterializeTemporaryExpr 0x5b4f80 'const struct Obj' lvalue
  `-ImplicitCastExpr 0x5b4f68 'const struct Obj' <NoOp>
    `-CXXBindTemporaryExpr 0x5b4dc8 'struct Obj' (CXXTemporary 0x5b4dc8)
      `-CallExpr 0x5b4da0 'struct Obj'
        `-ImplicitCastExpr 0x5b4d88 'struct Obj (*)(void)' <FunctionToPointerDecay>
          `-DeclRefExpr 0x5b4d68 'struct Obj (void)' lvalue Function 0x5af938 'foo_obj' 'struct Obj (void)'

Would choose the operator= call as the target instead of foo_obj(). I am assuming the user would want foo_obj here.

I am not sure there is a single 'Ignore' call that works here. And this case has two levels. An additional call to IgnoreImplicit() in getDirectCallExpr it should take care of it though. I'll upload a new patch.

ABataev added inline comments.Mar 30 2021, 12:04 PM
clang/lib/Sema/SemaOpenMP.cpp
9766–9768

Yes, just add IgnoreImplicit() call

mikerice updated this revision to Diff 334244.Mar 30 2021, 12:07 PM

Addressed review comments.

ABataev added inline comments.Mar 30 2021, 12:38 PM
clang/lib/Sema/SemaOpenMP.cpp
9799

E->IgnoreParenCasts()->IgnoreImplicit();?

mikerice updated this revision to Diff 334247.Mar 30 2021, 12:56 PM
mikerice marked an inline comment as done.

Addressed review comment.

This revision is now accepted and ready to land.Mar 30 2021, 12:56 PM
This revision was automatically updated to reflect the committed changes.
Herald added a project: Restricted Project. · View Herald TranscriptMar 30 2021, 2:22 PM
Herald added a subscriber: cfe-commits. · View Herald Transcript
jdoerfert added a subscriber: jyu2.Apr 2 2021, 8:46 AM

Cool, are you expecting to hook this up to the variant selection logic as well? @jyu2 similarly do you intend to hook up novariant?

We should also update https://clang.llvm.org/docs/OpenMPSupport.html to claim parts you are working on (upstreaming).

@jyu2 is currently working on the novariants and nocontext clauses. We are still working on the overall construct so I'm not sure yet what more we will have to contribute.

I'll look into updating the support doc.