// ...
// orig_varn = private_orig_varn;
// }
- auto *ThenBB = createBasicBlock(".omp.lastprivate.then");
- auto *DoneBB = createBasicBlock(".omp.lastprivate.done");
- Builder.CreateCondBr(IsLastIterCond, ThenBB, DoneBB);
- EmitBlock(ThenBB);
+ llvm::BasicBlock *ThenBB = nullptr;
+ llvm::BasicBlock *DoneBB = nullptr;
+ if (IsLastIterCond) {
+ ThenBB = createBasicBlock(".omp.lastprivate.then");
+ DoneBB = createBasicBlock(".omp.lastprivate.done");
+ Builder.CreateCondBr(IsLastIterCond, ThenBB, DoneBB);
+ EmitBlock(ThenBB);
+ }
llvm::DenseMap<const Decl *, const Expr *> LoopCountersAndUpdates;
const Expr *LastIterVal = nullptr;
const Expr *IVExpr = nullptr;
const Expr *IncExpr = nullptr;
if (auto *LoopDirective = dyn_cast<OMPLoopDirective>(&D)) {
- LastIterVal =
- cast<VarDecl>(cast<DeclRefExpr>(LoopDirective->getUpperBoundVariable())
- ->getDecl())
- ->getAnyInitializer();
- IVExpr = LoopDirective->getIterationVariable();
- IncExpr = LoopDirective->getInc();
- auto IUpdate = LoopDirective->updates().begin();
- for (auto *E : LoopDirective->counters()) {
- auto *D = cast<DeclRefExpr>(E)->getDecl()->getCanonicalDecl();
- LoopCountersAndUpdates[D] = *IUpdate;
- ++IUpdate;
+ if (isOpenMPWorksharingDirective(D.getDirectiveKind())) {
+ LastIterVal = cast<VarDecl>(cast<DeclRefExpr>(
+ LoopDirective->getUpperBoundVariable())
+ ->getDecl())
+ ->getAnyInitializer();
+ IVExpr = LoopDirective->getIterationVariable();
+ IncExpr = LoopDirective->getInc();
+ auto IUpdate = LoopDirective->updates().begin();
+ for (auto *E : LoopDirective->counters()) {
+ auto *D = cast<DeclRefExpr>(E)->getDecl()->getCanonicalDecl();
+ LoopCountersAndUpdates[D] = *IUpdate;
+ ++IUpdate;
+ }
}
}
{
// directive, update its value before copyin back to original
// variable.
if (auto *UpExpr = LoopCountersAndUpdates.lookup(CanonicalVD)) {
- if (FirstLCV) {
+ if (FirstLCV && LastIterVal) {
EmitAnyExprToMem(LastIterVal, EmitLValue(IVExpr).getAddress(),
IVExpr->getType().getQualifiers(),
/*IsInitializer=*/false);
}
}
}
- EmitBlock(DoneBB, /*IsFinished=*/true);
+ if (IsLastIterCond) {
+ EmitBlock(DoneBB, /*IsFinished=*/true);
+ }
}
void CodeGenFunction::EmitOMPReductionClauseInit(
}
}
+ bool HasLastprivateClause;
{
OMPPrivateScope LoopScope(CGF);
EmitPrivateLoopCounters(CGF, LoopScope, S.counters());
EmitPrivateLinearVars(CGF, S, LoopScope);
CGF.EmitOMPPrivateClause(S, LoopScope);
+ HasLastprivateClause = CGF.EmitOMPLastprivateClauseInit(S, LoopScope);
(void)LoopScope.Privatize();
CGF.EmitOMPInnerLoop(S, LoopScope.requiresCleanups(),
S.getCond(), S.getInc(),
CGF.EmitStopPoint(&S);
},
[](CodeGenFunction &) {});
+ // Emit final copy of the lastprivate variables at the end of loops.
+ if (HasLastprivateClause) {
+ CGF.EmitOMPLastprivateClauseFinal(S);
+ }
}
CGF.EmitOMPSimdFinal(S);
// Emit: if (PreCond) - end.
/// \param D Directive that has at least one 'lastprivate' directives.
/// \param IsLastIterCond Boolean condition that must be set to 'i1 true' if
/// it is the last iteration of the loop code in associated directive, or to
- /// 'i1 false' otherwise.
+ /// 'i1 false' otherwise. If this item is nullptr, no final check is required.
void EmitOMPLastprivateClauseFinal(const OMPExecutableDirective &D,
- llvm::Value *IsLastIterCond);
+ llvm::Value *IsLastIterCond = nullptr);
/// \brief Emit initial code for reduction variables. Creates reduction copies
/// and initializes them with the values according to OpenMP standard.
///
}
int A;
+ // CHECK: store i32 -1, i32* [[A:%.+]],
+ A = -1;
#pragma omp simd lastprivate(A)
// Clause 'lastprivate' implementation is not completed yet.
// Test checks that one iteration is separated in presence of lastprivate.
// CHECK: [[IV7_0:%.+]] = load i64, i64* [[OMP_IV7]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP7_ID]]
// CHECK-NEXT: [[LC_IT_1:%.+]] = mul nsw i64 [[IV7_0]], 3
// CHECK-NEXT: [[LC_IT_2:%.+]] = add nsw i64 -10, [[LC_IT_1]]
-// CHECK-NEXT: store i64 [[LC_IT_2]], i64* {{.+}}, !llvm.mem.parallel_loop_access ![[SIMPLE_LOOP7_ID]]
+// CHECK-NEXT: store i64 [[LC_IT_2]], i64* [[LC:%[^,]+]],{{.+}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP7_ID]]
+// CHECK-NEXT: [[LC_VAL:%.+]] = load i64, i64* [[LC]]{{.+}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP7_ID]]
+// CHECK-NEXT: [[CONV:%.+]] = trunc i64 [[LC_VAL]] to i32
+// CHECK-NEXT: store i32 [[CONV]], i32* [[A_PRIV:%[^,]+]],{{.+}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP7_ID]]
A = i;
// CHECK: [[IV7_2:%.+]] = load i64, i64* [[OMP_IV7]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP7_ID]]
// CHECK-NEXT: [[ADD7_2:%.+]] = add nsw i64 [[IV7_2]], 1
// CHECK-NEXT: store i64 [[ADD7_2]], i64* [[OMP_IV7]]{{.*}}!llvm.mem.parallel_loop_access ![[SIMPLE_LOOP7_ID]]
}
// CHECK: [[SIMPLE_LOOP7_END]]
+// CHECK-NEXT: [[A_PRIV_VAL:%.+]] = load i32, i32* [[A_PRIV]],
+// CHECK-NEXT: store i32 [[A_PRIV_VAL]], i32* [[A]],
// CHECK-NEXT: ret void
}