[clang] [flang] [llvm] [openmp] [Clang][OpenMP][LoopTransformations] Add support for "#pragma omp fuse" loop transformation direcrive and "looprange" clause (PR #139293)
Alexey Bataev via llvm-commits
llvm-commits at lists.llvm.org
Fri May 9 11:12:06 PDT 2025
================
@@ -14175,27 +14222,350 @@ bool SemaOpenMP::checkTransformableLoopNest(
return false;
},
[&OriginalInits](OMPLoopBasedDirective *Transform) {
- Stmt *DependentPreInits;
- if (auto *Dir = dyn_cast<OMPTileDirective>(Transform))
- DependentPreInits = Dir->getPreInits();
- else if (auto *Dir = dyn_cast<OMPStripeDirective>(Transform))
- DependentPreInits = Dir->getPreInits();
- else if (auto *Dir = dyn_cast<OMPUnrollDirective>(Transform))
- DependentPreInits = Dir->getPreInits();
- else if (auto *Dir = dyn_cast<OMPReverseDirective>(Transform))
- DependentPreInits = Dir->getPreInits();
- else if (auto *Dir = dyn_cast<OMPInterchangeDirective>(Transform))
- DependentPreInits = Dir->getPreInits();
- else
- llvm_unreachable("Unhandled loop transformation");
-
- appendFlattenedStmtList(OriginalInits.back(), DependentPreInits);
+ updatePreInits(Transform, OriginalInits);
});
assert(OriginalInits.back().empty() && "No preinit after innermost loop");
OriginalInits.pop_back();
return Result;
}
+// Counts the total number of nested loops, including the outermost loop (the
+// original loop). PRECONDITION of this visitor is that it must be invoked from
+// the original loop to be analyzed. The traversal is stop for Decl's and
+// Expr's given that they may contain inner loops that must not be counted.
+//
+// Example AST structure for the code:
+//
+// int main() {
+// #pragma omp fuse
+// {
+// for (int i = 0; i < 100; i++) { <-- Outer loop
+// []() {
+// for(int j = 0; j < 100; j++) {} <-- NOT A LOOP
+// };
+// for(int j = 0; j < 5; ++j) {} <-- Inner loop
+// }
+// for (int r = 0; i < 100; i++) { <-- Outer loop
+// struct LocalClass {
+// void bar() {
+// for(int j = 0; j < 100; j++) {} <-- NOT A LOOP
+// }
+// };
+// for(int k = 0; k < 10; ++k) {} <-- Inner loop
+// {x = 5; for(k = 0; k < 10; ++k) x += k; x}; <-- NOT A LOOP
+// }
+// }
+// }
+// Result: Loop 'i' contains 2 loops, Loop 'r' also contains 2 loops
+class NestedLoopCounterVisitor : public DynamicRecursiveASTVisitor {
+private:
+ unsigned NestedLoopCount = 0;
+
+public:
+ explicit NestedLoopCounterVisitor() {}
+
+ unsigned getNestedLoopCount() const { return NestedLoopCount; }
+
+ bool VisitForStmt(ForStmt *FS) override {
+ ++NestedLoopCount;
+ return true;
+ }
+
+ bool VisitCXXForRangeStmt(CXXForRangeStmt *FRS) override {
+ ++NestedLoopCount;
+ return true;
+ }
+
+ bool TraverseStmt(Stmt *S) override {
+ if (!S)
+ return true;
+
+ // Skip traversal of all expressions, including special cases like
+ // LambdaExpr, StmtExpr, BlockExpr, and RequiresExpr. These expressions
+ // may contain inner statements (and even loops), but they are not part
+ // of the syntactic body of the surrounding loop structure.
+ // Therefore must not be counted
+ if (isa<Expr>(S))
+ return true;
+
+ // Only recurse into CompoundStmt (block {}) and loop bodies
+ if (isa<CompoundStmt>(S) || isa<ForStmt>(S) || isa<CXXForRangeStmt>(S)) {
+ return DynamicRecursiveASTVisitor::TraverseStmt(S);
+ }
----------------
alexey-bataev wrote:
```suggestion
if (isa<CompoundStmt, ForStmt, CXXForRangeStmt>(S))
return DynamicRecursiveASTVisitor::TraverseStmt(S);
```
https://github.com/llvm/llvm-project/pull/139293
More information about the llvm-commits
mailing list