[PATCH] D99537: [OPENMP51]Initial support for the dispatch directive
Mike Rice via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Tue Mar 30 11:56:55 PDT 2021
mikerice added inline comments.
================
Comment at: clang/lib/Sema/SemaOpenMP.cpp:9766-9768
+namespace {
+class DispatchStmtExprChecker
+ : public StmtVisitor<DispatchStmtExprChecker, bool> {
----------------
ABataev wrote:
> mikerice wrote:
> > ABataev wrote:
> > > mikerice wrote:
> > > > ABataev wrote:
> > > > > Why `Expr->IgnoreParenImpCasts()` does not work here?
> > > > 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?
> > > Then just extend `IgnoreParenImpCasts` to support `MaterializeTemporaryExpr` and control it by the parameter.
> > 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?
> 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();
> }
> ```
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.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D99537/new/
https://reviews.llvm.org/D99537
More information about the llvm-commits
mailing list