diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -4404,6 +4404,32 @@ } } +namespace { +class LinearStepVarChecker : public StmtVisitor { + llvm::SmallVector ImplicitFirstprivate; +public: + bool VisitDeclRefExpr(DeclRefExpr *E) { + if (auto *VD = dyn_cast(E->getDecl())) { + ImplicitFirstprivate.push_back(cast(E)); + return true; + } + return false; + } + bool VisitStmt(Stmt *S) { + for (Stmt *Child : S->children()) { + if (Child && Visit(Child)) + return true; + } + return false; + } + ArrayRef getImplicitFirstprivate() const { + return ImplicitFirstprivate; + } + + explicit LinearStepVarChecker() {} +}; +} // namespace + StmtResult Sema::ActOnOpenMPExecutableDirective( OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName, OpenMPDirectiveKind CancelRegion, ArrayRef Clauses, @@ -4460,6 +4486,17 @@ for (Expr *E : IRC->taskgroup_descriptors()) if (E) ImplicitFirstprivates.emplace_back(E); + } else if (auto *LC = dyn_cast(C)) { + Expr *E = LC->getStep(); + if (E) { + LinearStepVarChecker LSVChecker; + LSVChecker.Visit(E); + ArrayRef LinearVars = LSVChecker.getImplicitFirstprivate(); + ImplicitFirstprivates.insert( + ImplicitFirstprivates.end(), + std::make_move_iterator(LinearVars.begin()), + std::make_move_iterator(LinearVars.end())); + } } } if (!ImplicitFirstprivates.empty()) { diff --git a/clang/test/OpenMP/parallel_for_linear_codegen.cpp b/clang/test/OpenMP/parallel_for_linear_codegen.cpp --- a/clang/test/OpenMP/parallel_for_linear_codegen.cpp +++ b/clang/test/OpenMP/parallel_for_linear_codegen.cpp @@ -28,6 +28,19 @@ float f; char cnt; +int a[100]; + +int foo (int i, int k) +{ +#pragma omp parallel for linear (i: k + 1) + for (int j = 16; j < 64; j++) + { + a[i] = j; + i += 4; + } + return i; +} + // CHECK: [[S_FLOAT_TY:%.+]] = type { float } // CHECK: [[S_INT_TY:%.+]] = type { i32 } // CHECK-DAG: [[F:@.+]] = global float 0.0