Author: erichkeane
Date: 2025-04-30T12:02:52-07:00
New Revision: ea0e6e33835fe9fada89f77cc3a6cd74eb690067

URL: 
https://github.com/llvm/llvm-project/commit/ea0e6e33835fe9fada89f77cc3a6cd74eb690067
DIFF: 
https://github.com/llvm/llvm-project/commit/ea0e6e33835fe9fada89f77cc3a6cd74eb690067.diff

LOG: [OpenACC] Improve 'loop' content restrictions

The 'loop' construct has some limitations that are not particularly
clear on what can be in the for-loop. This patch adds some restriction
so that the increment can only be a addition or subtraction operation,
   BUT starts allowing Itr = Itr +/- N forms.

Added: 
    

Modified: 
    clang/lib/Sema/SemaOpenACC.cpp
    clang/test/SemaOpenACC/loop-construct.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp
index fc191bd95a35e..4ad47c7e58bea 100644
--- a/clang/lib/Sema/SemaOpenACC.cpp
+++ b/clang/lib/Sema/SemaOpenACC.cpp
@@ -1275,11 +1275,8 @@ bool 
SemaOpenACC::ForStmtBeginChecker::checkForCond(const Stmt *CondStmt,
          CondVar->getCanonicalDecl() != InitVar->getCanonicalDecl() &&
          CE->getNumArgs() > 1))
       CondVar = getDeclFromExpr(CE->getArg(1));
-  } else if (const auto *ME = dyn_cast<CXXMemberCallExpr>(CondStmt)) {
-    // Here there isn't much we can do besides hope it is the right variable.
-    // Codegen might have to just give up on figuring out trip count in this
-    // case?
-    CondVar = getDeclFromExpr(ME->getImplicitObjectArgument());
+  } else {
+    return DiagCondVar();
   }
 
   if (!CondVar)
@@ -1293,6 +1290,59 @@ bool 
SemaOpenACC::ForStmtBeginChecker::checkForCond(const Stmt *CondStmt,
   return false;
 }
 
+namespace {
+// Helper to check the RHS of an assignment during for's step. We can allow
+// InitVar = InitVar + N, InitVar = N + InitVar, and Initvar = Initvar - N,
+// where N is an integer.
+bool isValidForIncRHSAssign(const ValueDecl *InitVar, const Expr *RHS) {
+
+  auto isValid = [](const ValueDecl *InitVar, const Expr *InnerLHS,
+                    const Expr *InnerRHS, bool IsAddition) {
+    // ONE of the sides has to be an integer type.
+    if (!InnerLHS->getType()->isIntegerType() &&
+        !InnerRHS->getType()->isIntegerType())
+      return false;
+
+    // If the init var is already an error, don't bother trying to check for
+    // it.
+    if (!InitVar)
+      return true;
+
+    const ValueDecl *LHSDecl = getDeclFromExpr(InnerLHS);
+    const ValueDecl *RHSDecl = getDeclFromExpr(InnerRHS);
+    // If we can't get a declaration, this is probably an error, so give up.
+    if (!LHSDecl || !RHSDecl)
+      return true;
+
+    // If the LHS is the InitVar, the other must be int, so this is valid.
+    if (LHSDecl->getCanonicalDecl() ==
+        InitVar->getCanonicalDecl())
+      return true;
+
+    // Subtraction doesn't allow the RHS to be init var, so this is invalid.
+    if (!IsAddition)
+      return false;
+
+    return RHSDecl->getCanonicalDecl() ==
+           InitVar->getCanonicalDecl();
+  };
+
+  if (const auto *BO = dyn_cast<BinaryOperator>(RHS)) {
+    BinaryOperatorKind OpC = BO->getOpcode();
+    if (OpC != BO_Add && OpC != BO_Sub)
+      return false;
+    return isValid(InitVar, BO->getLHS(), BO->getRHS(), OpC == BO_Add);
+  } else if (const auto *CE = dyn_cast<CXXOperatorCallExpr>(RHS)) {
+    OverloadedOperatorKind Op = CE->getOperator();
+    if (Op != OO_Plus && Op != OO_Minus)
+      return false;
+    return isValid(InitVar, CE->getArg(0), CE->getArg(1), Op == OO_Plus);
+  }
+
+  return false;
+}
+} // namespace
+
 bool SemaOpenACC::ForStmtBeginChecker::checkForInc(const Stmt *IncStmt,
                                                    const ValueDecl *InitVar,
                                                    bool Diag) {
@@ -1335,14 +1385,12 @@ bool 
SemaOpenACC::ForStmtBeginChecker::checkForInc(const Stmt *IncStmt,
       return DiagIncVar();
     case BO_AddAssign:
     case BO_SubAssign:
-    case BO_MulAssign:
-    case BO_DivAssign:
+      break;
     case BO_Assign:
-      // += -= *= /= should all be fine here, this should be all of the
-      // 'monotonical' compound-assign ops.
-      // Assignment we just give up on, we could do better, and ensure that it
-      // is a binary/operator expr doing more work, but that seems like a lot
-      // of work for an error prone check.
+      // For assignment we also allow InitVar = InitVar + N, InitVar = N +
+      // InitVar, and InitVar = InitVar - N;  BUT only if 'N' is integral.
+      if (!isValidForIncRHSAssign(InitVar, BO->getRHS()))
+        return DiagIncVar();
       break;
     }
     IncVar = getDeclFromExpr(BO->getLHS());
@@ -1354,23 +1402,18 @@ bool 
SemaOpenACC::ForStmtBeginChecker::checkForInc(const Stmt *IncStmt,
     case OO_MinusMinus:
     case OO_PlusEqual:
     case OO_MinusEqual:
-    case OO_StarEqual:
-    case OO_SlashEqual:
+      break;
     case OO_Equal:
-      // += -= *= /= should all be fine here, this should be all of the
-      // 'monotonical' compound-assign ops.
-      // Assignment we just give up on, we could do better, and ensure that it
-      // is a binary/operator expr doing more work, but that seems like a
-      // lot of work for an error prone check.
+      // For assignment we also allow InitVar = InitVar + N, InitVar = N +
+      // InitVar, and InitVar = InitVar - N;  BUT only if 'N' is integral.
+      if (!isValidForIncRHSAssign(InitVar, CE->getArg(1)))
+        return DiagIncVar();
       break;
     }
 
     IncVar = getDeclFromExpr(CE->getArg(0));
-
-  } else if (const auto *ME = dyn_cast<CXXMemberCallExpr>(IncStmt)) {
-    IncVar = getDeclFromExpr(ME->getImplicitObjectArgument());
-    // We can't really do much for member expressions, other than hope they are
-    // doing the right thing, so give up here.
+  } else {
+    return DiagIncVar();
   }
 
   if (!IncVar)

diff  --git a/clang/test/SemaOpenACC/loop-construct.cpp 
b/clang/test/SemaOpenACC/loop-construct.cpp
index 7509811635598..0282258023baf 100644
--- a/clang/test/SemaOpenACC/loop-construct.cpp
+++ b/clang/test/SemaOpenACC/loop-construct.cpp
@@ -30,6 +30,11 @@ struct SomeRAIterator {
   bool operator!=(SomeRAIterator&);
 };
 
+SomeRAIterator &operator+(const SomeRAIterator&, int);
+SomeRAIterator &operator+(int,const SomeRAIterator&);
+SomeRAIterator &operator-(const SomeRAIterator&, int);
+SomeRAIterator &operator-(int,const SomeRAIterator&);
+
 struct HasIteratorCollection {
   SomeIterator &begin();
   SomeIterator &end();
@@ -400,3 +405,37 @@ void inst() {
   LoopRules<int, int*, float, SomeStruct, SomeIterator, SomeRAIterator>();
 }
 
+void allowTrivialAssignStep(int N) {
+#pragma acc loop
+  for(int i = 0; i !=5; i = i + N);
+#pragma acc loop
+  for(int i = 0; i !=5; i = i - N);
+#pragma acc loop
+  for(int i = 0; i !=5; i = N + i);
+
+  // expected-error@+3{{OpenACC 'loop' variable must monotonically increase or 
decrease}}
+  // expected-note@+1{{'loop' construct is here}}
+#pragma acc loop
+  for(int i = 0; i !=5; i = N - i);
+  // expected-error@+3{{OpenACC 'loop' variable must monotonically increase or 
decrease}}
+  // expected-note@+1{{'loop' construct is here}}
+#pragma acc loop
+  for(int i = 0; i !=5; i = N + N);
+
+  HasRAIteratorCollection Col;
+
+#pragma acc loop
+  for (auto Itr = Col.begin(); Itr != Col.end(); Itr = Itr + N);
+
+#pragma acc loop
+  for (auto Itr = Col.begin(); Itr != Col.end(); Itr = Itr - N);
+
+#pragma acc loop
+  for (auto Itr = Col.begin(); Itr != Col.end(); Itr = N + Itr);
+
+  // expected-error@+3{{OpenACC 'loop' variable must monotonically increase or 
decrease}}
+  // expected-note@+1{{'loop' construct is here}}
+#pragma acc loop
+  for (auto Itr = Col.begin(); Itr != Col.end(); Itr = N - Itr);
+}
+


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to