1e5dd7070Spatrick //===--- CGStmtOpenMP.cpp - Emit LLVM Code from Statements ----------------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // This contains code to emit OpenMP nodes as LLVM code.
10e5dd7070Spatrick //
11e5dd7070Spatrick //===----------------------------------------------------------------------===//
12e5dd7070Spatrick
13e5dd7070Spatrick #include "CGCleanup.h"
14e5dd7070Spatrick #include "CGOpenMPRuntime.h"
15e5dd7070Spatrick #include "CodeGenFunction.h"
16e5dd7070Spatrick #include "CodeGenModule.h"
17e5dd7070Spatrick #include "TargetInfo.h"
18e5dd7070Spatrick #include "clang/AST/ASTContext.h"
19e5dd7070Spatrick #include "clang/AST/Attr.h"
20e5dd7070Spatrick #include "clang/AST/DeclOpenMP.h"
21ec727ea7Spatrick #include "clang/AST/OpenMPClause.h"
22e5dd7070Spatrick #include "clang/AST/Stmt.h"
23e5dd7070Spatrick #include "clang/AST/StmtOpenMP.h"
24a9ac8606Spatrick #include "clang/AST/StmtVisitor.h"
25ec727ea7Spatrick #include "clang/Basic/OpenMPKinds.h"
26e5dd7070Spatrick #include "clang/Basic/PrettyStackTrace.h"
27*12c85518Srobert #include "llvm/ADT/SmallSet.h"
28*12c85518Srobert #include "llvm/BinaryFormat/Dwarf.h"
29ec727ea7Spatrick #include "llvm/Frontend/OpenMP/OMPConstants.h"
30e5dd7070Spatrick #include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
31ec727ea7Spatrick #include "llvm/IR/Constants.h"
32*12c85518Srobert #include "llvm/IR/DebugInfoMetadata.h"
33ec727ea7Spatrick #include "llvm/IR/Instructions.h"
34*12c85518Srobert #include "llvm/IR/IntrinsicInst.h"
35*12c85518Srobert #include "llvm/IR/Metadata.h"
36ec727ea7Spatrick #include "llvm/Support/AtomicOrdering.h"
37*12c85518Srobert #include <optional>
38e5dd7070Spatrick using namespace clang;
39e5dd7070Spatrick using namespace CodeGen;
40e5dd7070Spatrick using namespace llvm::omp;
41e5dd7070Spatrick
42ec727ea7Spatrick static const VarDecl *getBaseDecl(const Expr *Ref);
43ec727ea7Spatrick
44e5dd7070Spatrick namespace {
45e5dd7070Spatrick /// Lexical scope for OpenMP executable constructs, that handles correct codegen
46e5dd7070Spatrick /// for captured expressions.
47e5dd7070Spatrick class OMPLexicalScope : public CodeGenFunction::LexicalScope {
emitPreInitStmt(CodeGenFunction & CGF,const OMPExecutableDirective & S)48e5dd7070Spatrick void emitPreInitStmt(CodeGenFunction &CGF, const OMPExecutableDirective &S) {
49e5dd7070Spatrick for (const auto *C : S.clauses()) {
50e5dd7070Spatrick if (const auto *CPI = OMPClauseWithPreInit::get(C)) {
51e5dd7070Spatrick if (const auto *PreInit =
52e5dd7070Spatrick cast_or_null<DeclStmt>(CPI->getPreInitStmt())) {
53e5dd7070Spatrick for (const auto *I : PreInit->decls()) {
54e5dd7070Spatrick if (!I->hasAttr<OMPCaptureNoInitAttr>()) {
55e5dd7070Spatrick CGF.EmitVarDecl(cast<VarDecl>(*I));
56e5dd7070Spatrick } else {
57e5dd7070Spatrick CodeGenFunction::AutoVarEmission Emission =
58e5dd7070Spatrick CGF.EmitAutoVarAlloca(cast<VarDecl>(*I));
59e5dd7070Spatrick CGF.EmitAutoVarCleanups(Emission);
60e5dd7070Spatrick }
61e5dd7070Spatrick }
62e5dd7070Spatrick }
63e5dd7070Spatrick }
64e5dd7070Spatrick }
65e5dd7070Spatrick }
66e5dd7070Spatrick CodeGenFunction::OMPPrivateScope InlinedShareds;
67e5dd7070Spatrick
isCapturedVar(CodeGenFunction & CGF,const VarDecl * VD)68e5dd7070Spatrick static bool isCapturedVar(CodeGenFunction &CGF, const VarDecl *VD) {
69e5dd7070Spatrick return CGF.LambdaCaptureFields.lookup(VD) ||
70e5dd7070Spatrick (CGF.CapturedStmtInfo && CGF.CapturedStmtInfo->lookup(VD)) ||
71ec727ea7Spatrick (CGF.CurCodeDecl && isa<BlockDecl>(CGF.CurCodeDecl) &&
72ec727ea7Spatrick cast<BlockDecl>(CGF.CurCodeDecl)->capturesVariable(VD));
73e5dd7070Spatrick }
74e5dd7070Spatrick
75e5dd7070Spatrick public:
OMPLexicalScope(CodeGenFunction & CGF,const OMPExecutableDirective & S,const std::optional<OpenMPDirectiveKind> CapturedRegion=std::nullopt,const bool EmitPreInitStmt=true)76e5dd7070Spatrick OMPLexicalScope(
77e5dd7070Spatrick CodeGenFunction &CGF, const OMPExecutableDirective &S,
78*12c85518Srobert const std::optional<OpenMPDirectiveKind> CapturedRegion = std::nullopt,
79e5dd7070Spatrick const bool EmitPreInitStmt = true)
80e5dd7070Spatrick : CodeGenFunction::LexicalScope(CGF, S.getSourceRange()),
81e5dd7070Spatrick InlinedShareds(CGF) {
82e5dd7070Spatrick if (EmitPreInitStmt)
83e5dd7070Spatrick emitPreInitStmt(CGF, S);
84*12c85518Srobert if (!CapturedRegion)
85e5dd7070Spatrick return;
86e5dd7070Spatrick assert(S.hasAssociatedStmt() &&
87e5dd7070Spatrick "Expected associated statement for inlined directive.");
88e5dd7070Spatrick const CapturedStmt *CS = S.getCapturedStmt(*CapturedRegion);
89e5dd7070Spatrick for (const auto &C : CS->captures()) {
90e5dd7070Spatrick if (C.capturesVariable() || C.capturesVariableByCopy()) {
91e5dd7070Spatrick auto *VD = C.getCapturedVar();
92e5dd7070Spatrick assert(VD == VD->getCanonicalDecl() &&
93e5dd7070Spatrick "Canonical decl must be captured.");
94e5dd7070Spatrick DeclRefExpr DRE(
95e5dd7070Spatrick CGF.getContext(), const_cast<VarDecl *>(VD),
96e5dd7070Spatrick isCapturedVar(CGF, VD) || (CGF.CapturedStmtInfo &&
97e5dd7070Spatrick InlinedShareds.isGlobalVarCaptured(VD)),
98e5dd7070Spatrick VD->getType().getNonReferenceType(), VK_LValue, C.getLocation());
99*12c85518Srobert InlinedShareds.addPrivate(VD, CGF.EmitLValue(&DRE).getAddress(CGF));
100e5dd7070Spatrick }
101e5dd7070Spatrick }
102e5dd7070Spatrick (void)InlinedShareds.Privatize();
103e5dd7070Spatrick }
104e5dd7070Spatrick };
105e5dd7070Spatrick
106e5dd7070Spatrick /// Lexical scope for OpenMP parallel construct, that handles correct codegen
107e5dd7070Spatrick /// for captured expressions.
108e5dd7070Spatrick class OMPParallelScope final : public OMPLexicalScope {
EmitPreInitStmt(const OMPExecutableDirective & S)109e5dd7070Spatrick bool EmitPreInitStmt(const OMPExecutableDirective &S) {
110e5dd7070Spatrick OpenMPDirectiveKind Kind = S.getDirectiveKind();
111e5dd7070Spatrick return !(isOpenMPTargetExecutionDirective(Kind) ||
112e5dd7070Spatrick isOpenMPLoopBoundSharingDirective(Kind)) &&
113e5dd7070Spatrick isOpenMPParallelDirective(Kind);
114e5dd7070Spatrick }
115e5dd7070Spatrick
116e5dd7070Spatrick public:
OMPParallelScope(CodeGenFunction & CGF,const OMPExecutableDirective & S)117e5dd7070Spatrick OMPParallelScope(CodeGenFunction &CGF, const OMPExecutableDirective &S)
118*12c85518Srobert : OMPLexicalScope(CGF, S, /*CapturedRegion=*/std::nullopt,
119e5dd7070Spatrick EmitPreInitStmt(S)) {}
120e5dd7070Spatrick };
121e5dd7070Spatrick
122e5dd7070Spatrick /// Lexical scope for OpenMP teams construct, that handles correct codegen
123e5dd7070Spatrick /// for captured expressions.
124e5dd7070Spatrick class OMPTeamsScope final : public OMPLexicalScope {
EmitPreInitStmt(const OMPExecutableDirective & S)125e5dd7070Spatrick bool EmitPreInitStmt(const OMPExecutableDirective &S) {
126e5dd7070Spatrick OpenMPDirectiveKind Kind = S.getDirectiveKind();
127e5dd7070Spatrick return !isOpenMPTargetExecutionDirective(Kind) &&
128e5dd7070Spatrick isOpenMPTeamsDirective(Kind);
129e5dd7070Spatrick }
130e5dd7070Spatrick
131e5dd7070Spatrick public:
OMPTeamsScope(CodeGenFunction & CGF,const OMPExecutableDirective & S)132e5dd7070Spatrick OMPTeamsScope(CodeGenFunction &CGF, const OMPExecutableDirective &S)
133*12c85518Srobert : OMPLexicalScope(CGF, S, /*CapturedRegion=*/std::nullopt,
134e5dd7070Spatrick EmitPreInitStmt(S)) {}
135e5dd7070Spatrick };
136e5dd7070Spatrick
137e5dd7070Spatrick /// Private scope for OpenMP loop-based directives, that supports capturing
138e5dd7070Spatrick /// of used expression from loop statement.
139e5dd7070Spatrick class OMPLoopScope : public CodeGenFunction::RunCleanupsScope {
emitPreInitStmt(CodeGenFunction & CGF,const OMPLoopBasedDirective & S)140a9ac8606Spatrick void emitPreInitStmt(CodeGenFunction &CGF, const OMPLoopBasedDirective &S) {
141a9ac8606Spatrick const DeclStmt *PreInits;
142e5dd7070Spatrick CodeGenFunction::OMPMapVars PreCondVars;
143a9ac8606Spatrick if (auto *LD = dyn_cast<OMPLoopDirective>(&S)) {
144e5dd7070Spatrick llvm::DenseSet<const VarDecl *> EmittedAsPrivate;
145a9ac8606Spatrick for (const auto *E : LD->counters()) {
146e5dd7070Spatrick const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
147e5dd7070Spatrick EmittedAsPrivate.insert(VD->getCanonicalDecl());
148e5dd7070Spatrick (void)PreCondVars.setVarAddr(
149e5dd7070Spatrick CGF, VD, CGF.CreateMemTemp(VD->getType().getNonReferenceType()));
150e5dd7070Spatrick }
151e5dd7070Spatrick // Mark private vars as undefs.
152a9ac8606Spatrick for (const auto *C : LD->getClausesOfKind<OMPPrivateClause>()) {
153e5dd7070Spatrick for (const Expr *IRef : C->varlists()) {
154a9ac8606Spatrick const auto *OrigVD =
155a9ac8606Spatrick cast<VarDecl>(cast<DeclRefExpr>(IRef)->getDecl());
156e5dd7070Spatrick if (EmittedAsPrivate.insert(OrigVD->getCanonicalDecl()).second) {
157*12c85518Srobert QualType OrigVDTy = OrigVD->getType().getNonReferenceType();
158e5dd7070Spatrick (void)PreCondVars.setVarAddr(
159e5dd7070Spatrick CGF, OrigVD,
160a9ac8606Spatrick Address(llvm::UndefValue::get(CGF.ConvertTypeForMem(
161*12c85518Srobert CGF.getContext().getPointerType(OrigVDTy))),
162*12c85518Srobert CGF.ConvertTypeForMem(OrigVDTy),
163e5dd7070Spatrick CGF.getContext().getDeclAlign(OrigVD)));
164e5dd7070Spatrick }
165e5dd7070Spatrick }
166e5dd7070Spatrick }
167e5dd7070Spatrick (void)PreCondVars.apply(CGF);
168e5dd7070Spatrick // Emit init, __range and __end variables for C++ range loops.
169a9ac8606Spatrick (void)OMPLoopBasedDirective::doForAllLoops(
170a9ac8606Spatrick LD->getInnermostCapturedStmt()->getCapturedStmt(),
171a9ac8606Spatrick /*TryImperfectlyNestedLoops=*/true, LD->getLoopsNumber(),
172a9ac8606Spatrick [&CGF](unsigned Cnt, const Stmt *CurStmt) {
173a9ac8606Spatrick if (const auto *CXXFor = dyn_cast<CXXForRangeStmt>(CurStmt)) {
174e5dd7070Spatrick if (const Stmt *Init = CXXFor->getInit())
175e5dd7070Spatrick CGF.EmitStmt(Init);
176e5dd7070Spatrick CGF.EmitStmt(CXXFor->getRangeStmt());
177e5dd7070Spatrick CGF.EmitStmt(CXXFor->getEndStmt());
178e5dd7070Spatrick }
179a9ac8606Spatrick return false;
180a9ac8606Spatrick });
181a9ac8606Spatrick PreInits = cast_or_null<DeclStmt>(LD->getPreInits());
182a9ac8606Spatrick } else if (const auto *Tile = dyn_cast<OMPTileDirective>(&S)) {
183a9ac8606Spatrick PreInits = cast_or_null<DeclStmt>(Tile->getPreInits());
184a9ac8606Spatrick } else if (const auto *Unroll = dyn_cast<OMPUnrollDirective>(&S)) {
185a9ac8606Spatrick PreInits = cast_or_null<DeclStmt>(Unroll->getPreInits());
186a9ac8606Spatrick } else {
187a9ac8606Spatrick llvm_unreachable("Unknown loop-based directive kind.");
188e5dd7070Spatrick }
189a9ac8606Spatrick if (PreInits) {
190e5dd7070Spatrick for (const auto *I : PreInits->decls())
191e5dd7070Spatrick CGF.EmitVarDecl(cast<VarDecl>(*I));
192e5dd7070Spatrick }
193e5dd7070Spatrick PreCondVars.restore(CGF);
194e5dd7070Spatrick }
195e5dd7070Spatrick
196e5dd7070Spatrick public:
OMPLoopScope(CodeGenFunction & CGF,const OMPLoopBasedDirective & S)197a9ac8606Spatrick OMPLoopScope(CodeGenFunction &CGF, const OMPLoopBasedDirective &S)
198e5dd7070Spatrick : CodeGenFunction::RunCleanupsScope(CGF) {
199e5dd7070Spatrick emitPreInitStmt(CGF, S);
200e5dd7070Spatrick }
201e5dd7070Spatrick };
202e5dd7070Spatrick
203e5dd7070Spatrick class OMPSimdLexicalScope : public CodeGenFunction::LexicalScope {
204e5dd7070Spatrick CodeGenFunction::OMPPrivateScope InlinedShareds;
205e5dd7070Spatrick
isCapturedVar(CodeGenFunction & CGF,const VarDecl * VD)206e5dd7070Spatrick static bool isCapturedVar(CodeGenFunction &CGF, const VarDecl *VD) {
207e5dd7070Spatrick return CGF.LambdaCaptureFields.lookup(VD) ||
208e5dd7070Spatrick (CGF.CapturedStmtInfo && CGF.CapturedStmtInfo->lookup(VD)) ||
209e5dd7070Spatrick (CGF.CurCodeDecl && isa<BlockDecl>(CGF.CurCodeDecl) &&
210e5dd7070Spatrick cast<BlockDecl>(CGF.CurCodeDecl)->capturesVariable(VD));
211e5dd7070Spatrick }
212e5dd7070Spatrick
213e5dd7070Spatrick public:
OMPSimdLexicalScope(CodeGenFunction & CGF,const OMPExecutableDirective & S)214e5dd7070Spatrick OMPSimdLexicalScope(CodeGenFunction &CGF, const OMPExecutableDirective &S)
215e5dd7070Spatrick : CodeGenFunction::LexicalScope(CGF, S.getSourceRange()),
216e5dd7070Spatrick InlinedShareds(CGF) {
217e5dd7070Spatrick for (const auto *C : S.clauses()) {
218e5dd7070Spatrick if (const auto *CPI = OMPClauseWithPreInit::get(C)) {
219e5dd7070Spatrick if (const auto *PreInit =
220e5dd7070Spatrick cast_or_null<DeclStmt>(CPI->getPreInitStmt())) {
221e5dd7070Spatrick for (const auto *I : PreInit->decls()) {
222e5dd7070Spatrick if (!I->hasAttr<OMPCaptureNoInitAttr>()) {
223e5dd7070Spatrick CGF.EmitVarDecl(cast<VarDecl>(*I));
224e5dd7070Spatrick } else {
225e5dd7070Spatrick CodeGenFunction::AutoVarEmission Emission =
226e5dd7070Spatrick CGF.EmitAutoVarAlloca(cast<VarDecl>(*I));
227e5dd7070Spatrick CGF.EmitAutoVarCleanups(Emission);
228e5dd7070Spatrick }
229e5dd7070Spatrick }
230e5dd7070Spatrick }
231e5dd7070Spatrick } else if (const auto *UDP = dyn_cast<OMPUseDevicePtrClause>(C)) {
232e5dd7070Spatrick for (const Expr *E : UDP->varlists()) {
233e5dd7070Spatrick const Decl *D = cast<DeclRefExpr>(E)->getDecl();
234e5dd7070Spatrick if (const auto *OED = dyn_cast<OMPCapturedExprDecl>(D))
235e5dd7070Spatrick CGF.EmitVarDecl(*OED);
236e5dd7070Spatrick }
237ec727ea7Spatrick } else if (const auto *UDP = dyn_cast<OMPUseDeviceAddrClause>(C)) {
238ec727ea7Spatrick for (const Expr *E : UDP->varlists()) {
239ec727ea7Spatrick const Decl *D = getBaseDecl(E);
240ec727ea7Spatrick if (const auto *OED = dyn_cast<OMPCapturedExprDecl>(D))
241ec727ea7Spatrick CGF.EmitVarDecl(*OED);
242ec727ea7Spatrick }
243e5dd7070Spatrick }
244e5dd7070Spatrick }
245e5dd7070Spatrick if (!isOpenMPSimdDirective(S.getDirectiveKind()))
246e5dd7070Spatrick CGF.EmitOMPPrivateClause(S, InlinedShareds);
247e5dd7070Spatrick if (const auto *TG = dyn_cast<OMPTaskgroupDirective>(&S)) {
248e5dd7070Spatrick if (const Expr *E = TG->getReductionRef())
249e5dd7070Spatrick CGF.EmitVarDecl(*cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl()));
250e5dd7070Spatrick }
251a9ac8606Spatrick // Temp copy arrays for inscan reductions should not be emitted as they are
252a9ac8606Spatrick // not used in simd only mode.
253a9ac8606Spatrick llvm::DenseSet<CanonicalDeclPtr<const Decl>> CopyArrayTemps;
254a9ac8606Spatrick for (const auto *C : S.getClausesOfKind<OMPReductionClause>()) {
255a9ac8606Spatrick if (C->getModifier() != OMPC_REDUCTION_inscan)
256a9ac8606Spatrick continue;
257a9ac8606Spatrick for (const Expr *E : C->copy_array_temps())
258a9ac8606Spatrick CopyArrayTemps.insert(cast<DeclRefExpr>(E)->getDecl());
259a9ac8606Spatrick }
260e5dd7070Spatrick const auto *CS = cast_or_null<CapturedStmt>(S.getAssociatedStmt());
261e5dd7070Spatrick while (CS) {
262e5dd7070Spatrick for (auto &C : CS->captures()) {
263e5dd7070Spatrick if (C.capturesVariable() || C.capturesVariableByCopy()) {
264e5dd7070Spatrick auto *VD = C.getCapturedVar();
265a9ac8606Spatrick if (CopyArrayTemps.contains(VD))
266a9ac8606Spatrick continue;
267e5dd7070Spatrick assert(VD == VD->getCanonicalDecl() &&
268e5dd7070Spatrick "Canonical decl must be captured.");
269e5dd7070Spatrick DeclRefExpr DRE(CGF.getContext(), const_cast<VarDecl *>(VD),
270e5dd7070Spatrick isCapturedVar(CGF, VD) ||
271e5dd7070Spatrick (CGF.CapturedStmtInfo &&
272e5dd7070Spatrick InlinedShareds.isGlobalVarCaptured(VD)),
273e5dd7070Spatrick VD->getType().getNonReferenceType(), VK_LValue,
274e5dd7070Spatrick C.getLocation());
275*12c85518Srobert InlinedShareds.addPrivate(VD, CGF.EmitLValue(&DRE).getAddress(CGF));
276e5dd7070Spatrick }
277e5dd7070Spatrick }
278e5dd7070Spatrick CS = dyn_cast<CapturedStmt>(CS->getCapturedStmt());
279e5dd7070Spatrick }
280e5dd7070Spatrick (void)InlinedShareds.Privatize();
281e5dd7070Spatrick }
282e5dd7070Spatrick };
283e5dd7070Spatrick
284e5dd7070Spatrick } // namespace
285e5dd7070Spatrick
286e5dd7070Spatrick static void emitCommonOMPTargetDirective(CodeGenFunction &CGF,
287e5dd7070Spatrick const OMPExecutableDirective &S,
288e5dd7070Spatrick const RegionCodeGenTy &CodeGen);
289e5dd7070Spatrick
EmitOMPSharedLValue(const Expr * E)290e5dd7070Spatrick LValue CodeGenFunction::EmitOMPSharedLValue(const Expr *E) {
291e5dd7070Spatrick if (const auto *OrigDRE = dyn_cast<DeclRefExpr>(E)) {
292e5dd7070Spatrick if (const auto *OrigVD = dyn_cast<VarDecl>(OrigDRE->getDecl())) {
293e5dd7070Spatrick OrigVD = OrigVD->getCanonicalDecl();
294e5dd7070Spatrick bool IsCaptured =
295e5dd7070Spatrick LambdaCaptureFields.lookup(OrigVD) ||
296e5dd7070Spatrick (CapturedStmtInfo && CapturedStmtInfo->lookup(OrigVD)) ||
297e5dd7070Spatrick (CurCodeDecl && isa<BlockDecl>(CurCodeDecl));
298e5dd7070Spatrick DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(OrigVD), IsCaptured,
299e5dd7070Spatrick OrigDRE->getType(), VK_LValue, OrigDRE->getExprLoc());
300e5dd7070Spatrick return EmitLValue(&DRE);
301e5dd7070Spatrick }
302e5dd7070Spatrick }
303e5dd7070Spatrick return EmitLValue(E);
304e5dd7070Spatrick }
305e5dd7070Spatrick
getTypeSize(QualType Ty)306e5dd7070Spatrick llvm::Value *CodeGenFunction::getTypeSize(QualType Ty) {
307e5dd7070Spatrick ASTContext &C = getContext();
308e5dd7070Spatrick llvm::Value *Size = nullptr;
309e5dd7070Spatrick auto SizeInChars = C.getTypeSizeInChars(Ty);
310e5dd7070Spatrick if (SizeInChars.isZero()) {
311e5dd7070Spatrick // getTypeSizeInChars() returns 0 for a VLA.
312e5dd7070Spatrick while (const VariableArrayType *VAT = C.getAsVariableArrayType(Ty)) {
313e5dd7070Spatrick VlaSizePair VlaSize = getVLASize(VAT);
314e5dd7070Spatrick Ty = VlaSize.Type;
315*12c85518Srobert Size =
316*12c85518Srobert Size ? Builder.CreateNUWMul(Size, VlaSize.NumElts) : VlaSize.NumElts;
317e5dd7070Spatrick }
318e5dd7070Spatrick SizeInChars = C.getTypeSizeInChars(Ty);
319e5dd7070Spatrick if (SizeInChars.isZero())
320e5dd7070Spatrick return llvm::ConstantInt::get(SizeTy, /*V=*/0);
321e5dd7070Spatrick return Builder.CreateNUWMul(Size, CGM.getSize(SizeInChars));
322e5dd7070Spatrick }
323e5dd7070Spatrick return CGM.getSize(SizeInChars);
324e5dd7070Spatrick }
325e5dd7070Spatrick
GenerateOpenMPCapturedVars(const CapturedStmt & S,SmallVectorImpl<llvm::Value * > & CapturedVars)326e5dd7070Spatrick void CodeGenFunction::GenerateOpenMPCapturedVars(
327e5dd7070Spatrick const CapturedStmt &S, SmallVectorImpl<llvm::Value *> &CapturedVars) {
328e5dd7070Spatrick const RecordDecl *RD = S.getCapturedRecordDecl();
329e5dd7070Spatrick auto CurField = RD->field_begin();
330e5dd7070Spatrick auto CurCap = S.captures().begin();
331e5dd7070Spatrick for (CapturedStmt::const_capture_init_iterator I = S.capture_init_begin(),
332e5dd7070Spatrick E = S.capture_init_end();
333e5dd7070Spatrick I != E; ++I, ++CurField, ++CurCap) {
334e5dd7070Spatrick if (CurField->hasCapturedVLAType()) {
335e5dd7070Spatrick const VariableArrayType *VAT = CurField->getCapturedVLAType();
336e5dd7070Spatrick llvm::Value *Val = VLASizeMap[VAT->getSizeExpr()];
337e5dd7070Spatrick CapturedVars.push_back(Val);
338e5dd7070Spatrick } else if (CurCap->capturesThis()) {
339e5dd7070Spatrick CapturedVars.push_back(CXXThisValue);
340e5dd7070Spatrick } else if (CurCap->capturesVariableByCopy()) {
341e5dd7070Spatrick llvm::Value *CV = EmitLoadOfScalar(EmitLValue(*I), CurCap->getLocation());
342e5dd7070Spatrick
343e5dd7070Spatrick // If the field is not a pointer, we need to save the actual value
344e5dd7070Spatrick // and load it as a void pointer.
345e5dd7070Spatrick if (!CurField->getType()->isAnyPointerType()) {
346e5dd7070Spatrick ASTContext &Ctx = getContext();
347e5dd7070Spatrick Address DstAddr = CreateMemTemp(
348e5dd7070Spatrick Ctx.getUIntPtrType(),
349e5dd7070Spatrick Twine(CurCap->getCapturedVar()->getName(), ".casted"));
350e5dd7070Spatrick LValue DstLV = MakeAddrLValue(DstAddr, Ctx.getUIntPtrType());
351e5dd7070Spatrick
352e5dd7070Spatrick llvm::Value *SrcAddrVal = EmitScalarConversion(
353e5dd7070Spatrick DstAddr.getPointer(), Ctx.getPointerType(Ctx.getUIntPtrType()),
354e5dd7070Spatrick Ctx.getPointerType(CurField->getType()), CurCap->getLocation());
355e5dd7070Spatrick LValue SrcLV =
356e5dd7070Spatrick MakeNaturalAlignAddrLValue(SrcAddrVal, CurField->getType());
357e5dd7070Spatrick
358e5dd7070Spatrick // Store the value using the source type pointer.
359e5dd7070Spatrick EmitStoreThroughLValue(RValue::get(CV), SrcLV);
360e5dd7070Spatrick
361e5dd7070Spatrick // Load the value using the destination type pointer.
362e5dd7070Spatrick CV = EmitLoadOfScalar(DstLV, CurCap->getLocation());
363e5dd7070Spatrick }
364e5dd7070Spatrick CapturedVars.push_back(CV);
365e5dd7070Spatrick } else {
366e5dd7070Spatrick assert(CurCap->capturesVariable() && "Expected capture by reference.");
367e5dd7070Spatrick CapturedVars.push_back(EmitLValue(*I).getAddress(*this).getPointer());
368e5dd7070Spatrick }
369e5dd7070Spatrick }
370e5dd7070Spatrick }
371e5dd7070Spatrick
castValueFromUintptr(CodeGenFunction & CGF,SourceLocation Loc,QualType DstType,StringRef Name,LValue AddrLV)372e5dd7070Spatrick static Address castValueFromUintptr(CodeGenFunction &CGF, SourceLocation Loc,
373e5dd7070Spatrick QualType DstType, StringRef Name,
374e5dd7070Spatrick LValue AddrLV) {
375e5dd7070Spatrick ASTContext &Ctx = CGF.getContext();
376e5dd7070Spatrick
377e5dd7070Spatrick llvm::Value *CastedPtr = CGF.EmitScalarConversion(
378e5dd7070Spatrick AddrLV.getAddress(CGF).getPointer(), Ctx.getUIntPtrType(),
379e5dd7070Spatrick Ctx.getPointerType(DstType), Loc);
380e5dd7070Spatrick Address TmpAddr =
381*12c85518Srobert CGF.MakeNaturalAlignAddrLValue(CastedPtr, DstType).getAddress(CGF);
382e5dd7070Spatrick return TmpAddr;
383e5dd7070Spatrick }
384e5dd7070Spatrick
getCanonicalParamType(ASTContext & C,QualType T)385e5dd7070Spatrick static QualType getCanonicalParamType(ASTContext &C, QualType T) {
386e5dd7070Spatrick if (T->isLValueReferenceType())
387e5dd7070Spatrick return C.getLValueReferenceType(
388e5dd7070Spatrick getCanonicalParamType(C, T.getNonReferenceType()),
389e5dd7070Spatrick /*SpelledAsLValue=*/false);
390e5dd7070Spatrick if (T->isPointerType())
391e5dd7070Spatrick return C.getPointerType(getCanonicalParamType(C, T->getPointeeType()));
392e5dd7070Spatrick if (const ArrayType *A = T->getAsArrayTypeUnsafe()) {
393e5dd7070Spatrick if (const auto *VLA = dyn_cast<VariableArrayType>(A))
394e5dd7070Spatrick return getCanonicalParamType(C, VLA->getElementType());
395e5dd7070Spatrick if (!A->isVariablyModifiedType())
396e5dd7070Spatrick return C.getCanonicalType(T);
397e5dd7070Spatrick }
398e5dd7070Spatrick return C.getCanonicalParamType(T);
399e5dd7070Spatrick }
400e5dd7070Spatrick
401e5dd7070Spatrick namespace {
402e5dd7070Spatrick /// Contains required data for proper outlined function codegen.
403e5dd7070Spatrick struct FunctionOptions {
404e5dd7070Spatrick /// Captured statement for which the function is generated.
405e5dd7070Spatrick const CapturedStmt *S = nullptr;
406e5dd7070Spatrick /// true if cast to/from UIntPtr is required for variables captured by
407e5dd7070Spatrick /// value.
408e5dd7070Spatrick const bool UIntPtrCastRequired = true;
409e5dd7070Spatrick /// true if only casted arguments must be registered as local args or VLA
410e5dd7070Spatrick /// sizes.
411e5dd7070Spatrick const bool RegisterCastedArgsOnly = false;
412e5dd7070Spatrick /// Name of the generated function.
413e5dd7070Spatrick const StringRef FunctionName;
414ec727ea7Spatrick /// Location of the non-debug version of the outlined function.
415ec727ea7Spatrick SourceLocation Loc;
FunctionOptions__anon20b8c0360311::FunctionOptions416e5dd7070Spatrick explicit FunctionOptions(const CapturedStmt *S, bool UIntPtrCastRequired,
417ec727ea7Spatrick bool RegisterCastedArgsOnly, StringRef FunctionName,
418ec727ea7Spatrick SourceLocation Loc)
419e5dd7070Spatrick : S(S), UIntPtrCastRequired(UIntPtrCastRequired),
420e5dd7070Spatrick RegisterCastedArgsOnly(UIntPtrCastRequired && RegisterCastedArgsOnly),
421ec727ea7Spatrick FunctionName(FunctionName), Loc(Loc) {}
422e5dd7070Spatrick };
423ec727ea7Spatrick } // namespace
424e5dd7070Spatrick
emitOutlinedFunctionPrologue(CodeGenFunction & CGF,FunctionArgList & Args,llvm::MapVector<const Decl *,std::pair<const VarDecl *,Address>> & LocalAddrs,llvm::DenseMap<const Decl *,std::pair<const Expr *,llvm::Value * >> & VLASizes,llvm::Value * & CXXThisValue,const FunctionOptions & FO)425e5dd7070Spatrick static llvm::Function *emitOutlinedFunctionPrologue(
426e5dd7070Spatrick CodeGenFunction &CGF, FunctionArgList &Args,
427e5dd7070Spatrick llvm::MapVector<const Decl *, std::pair<const VarDecl *, Address>>
428e5dd7070Spatrick &LocalAddrs,
429e5dd7070Spatrick llvm::DenseMap<const Decl *, std::pair<const Expr *, llvm::Value *>>
430e5dd7070Spatrick &VLASizes,
431e5dd7070Spatrick llvm::Value *&CXXThisValue, const FunctionOptions &FO) {
432e5dd7070Spatrick const CapturedDecl *CD = FO.S->getCapturedDecl();
433e5dd7070Spatrick const RecordDecl *RD = FO.S->getCapturedRecordDecl();
434e5dd7070Spatrick assert(CD->hasBody() && "missing CapturedDecl body");
435e5dd7070Spatrick
436e5dd7070Spatrick CXXThisValue = nullptr;
437e5dd7070Spatrick // Build the argument list.
438e5dd7070Spatrick CodeGenModule &CGM = CGF.CGM;
439e5dd7070Spatrick ASTContext &Ctx = CGM.getContext();
440e5dd7070Spatrick FunctionArgList TargetArgs;
441e5dd7070Spatrick Args.append(CD->param_begin(),
442e5dd7070Spatrick std::next(CD->param_begin(), CD->getContextParamPosition()));
443e5dd7070Spatrick TargetArgs.append(
444e5dd7070Spatrick CD->param_begin(),
445e5dd7070Spatrick std::next(CD->param_begin(), CD->getContextParamPosition()));
446e5dd7070Spatrick auto I = FO.S->captures().begin();
447e5dd7070Spatrick FunctionDecl *DebugFunctionDecl = nullptr;
448e5dd7070Spatrick if (!FO.UIntPtrCastRequired) {
449e5dd7070Spatrick FunctionProtoType::ExtProtoInfo EPI;
450*12c85518Srobert QualType FunctionTy = Ctx.getFunctionType(Ctx.VoidTy, std::nullopt, EPI);
451e5dd7070Spatrick DebugFunctionDecl = FunctionDecl::Create(
452e5dd7070Spatrick Ctx, Ctx.getTranslationUnitDecl(), FO.S->getBeginLoc(),
453e5dd7070Spatrick SourceLocation(), DeclarationName(), FunctionTy,
454e5dd7070Spatrick Ctx.getTrivialTypeSourceInfo(FunctionTy), SC_Static,
455*12c85518Srobert /*UsesFPIntrin=*/false, /*isInlineSpecified=*/false,
456*12c85518Srobert /*hasWrittenPrototype=*/false);
457e5dd7070Spatrick }
458e5dd7070Spatrick for (const FieldDecl *FD : RD->fields()) {
459e5dd7070Spatrick QualType ArgType = FD->getType();
460e5dd7070Spatrick IdentifierInfo *II = nullptr;
461e5dd7070Spatrick VarDecl *CapVar = nullptr;
462e5dd7070Spatrick
463e5dd7070Spatrick // If this is a capture by copy and the type is not a pointer, the outlined
464e5dd7070Spatrick // function argument type should be uintptr and the value properly casted to
465e5dd7070Spatrick // uintptr. This is necessary given that the runtime library is only able to
466e5dd7070Spatrick // deal with pointers. We can pass in the same way the VLA type sizes to the
467e5dd7070Spatrick // outlined function.
468e5dd7070Spatrick if (FO.UIntPtrCastRequired &&
469e5dd7070Spatrick ((I->capturesVariableByCopy() && !ArgType->isAnyPointerType()) ||
470e5dd7070Spatrick I->capturesVariableArrayType()))
471e5dd7070Spatrick ArgType = Ctx.getUIntPtrType();
472e5dd7070Spatrick
473e5dd7070Spatrick if (I->capturesVariable() || I->capturesVariableByCopy()) {
474e5dd7070Spatrick CapVar = I->getCapturedVar();
475e5dd7070Spatrick II = CapVar->getIdentifier();
476e5dd7070Spatrick } else if (I->capturesThis()) {
477e5dd7070Spatrick II = &Ctx.Idents.get("this");
478e5dd7070Spatrick } else {
479e5dd7070Spatrick assert(I->capturesVariableArrayType());
480e5dd7070Spatrick II = &Ctx.Idents.get("vla");
481e5dd7070Spatrick }
482e5dd7070Spatrick if (ArgType->isVariablyModifiedType())
483e5dd7070Spatrick ArgType = getCanonicalParamType(Ctx, ArgType);
484e5dd7070Spatrick VarDecl *Arg;
485*12c85518Srobert if (CapVar && (CapVar->getTLSKind() != clang::VarDecl::TLS_None)) {
486*12c85518Srobert Arg = ImplicitParamDecl::Create(Ctx, /*DC=*/nullptr, FD->getLocation(),
487*12c85518Srobert II, ArgType,
488*12c85518Srobert ImplicitParamDecl::ThreadPrivateVar);
489*12c85518Srobert } else if (DebugFunctionDecl && (CapVar || I->capturesThis())) {
490e5dd7070Spatrick Arg = ParmVarDecl::Create(
491e5dd7070Spatrick Ctx, DebugFunctionDecl,
492e5dd7070Spatrick CapVar ? CapVar->getBeginLoc() : FD->getBeginLoc(),
493e5dd7070Spatrick CapVar ? CapVar->getLocation() : FD->getLocation(), II, ArgType,
494e5dd7070Spatrick /*TInfo=*/nullptr, SC_None, /*DefArg=*/nullptr);
495e5dd7070Spatrick } else {
496e5dd7070Spatrick Arg = ImplicitParamDecl::Create(Ctx, /*DC=*/nullptr, FD->getLocation(),
497e5dd7070Spatrick II, ArgType, ImplicitParamDecl::Other);
498e5dd7070Spatrick }
499e5dd7070Spatrick Args.emplace_back(Arg);
500e5dd7070Spatrick // Do not cast arguments if we emit function with non-original types.
501e5dd7070Spatrick TargetArgs.emplace_back(
502e5dd7070Spatrick FO.UIntPtrCastRequired
503e5dd7070Spatrick ? Arg
504e5dd7070Spatrick : CGM.getOpenMPRuntime().translateParameter(FD, Arg));
505e5dd7070Spatrick ++I;
506e5dd7070Spatrick }
507*12c85518Srobert Args.append(std::next(CD->param_begin(), CD->getContextParamPosition() + 1),
508e5dd7070Spatrick CD->param_end());
509e5dd7070Spatrick TargetArgs.append(
510e5dd7070Spatrick std::next(CD->param_begin(), CD->getContextParamPosition() + 1),
511e5dd7070Spatrick CD->param_end());
512e5dd7070Spatrick
513e5dd7070Spatrick // Create the function declaration.
514e5dd7070Spatrick const CGFunctionInfo &FuncInfo =
515e5dd7070Spatrick CGM.getTypes().arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, TargetArgs);
516e5dd7070Spatrick llvm::FunctionType *FuncLLVMTy = CGM.getTypes().GetFunctionType(FuncInfo);
517e5dd7070Spatrick
518e5dd7070Spatrick auto *F =
519e5dd7070Spatrick llvm::Function::Create(FuncLLVMTy, llvm::GlobalValue::InternalLinkage,
520e5dd7070Spatrick FO.FunctionName, &CGM.getModule());
521e5dd7070Spatrick CGM.SetInternalFunctionAttributes(CD, F, FuncInfo);
522e5dd7070Spatrick if (CD->isNothrow())
523e5dd7070Spatrick F->setDoesNotThrow();
524e5dd7070Spatrick F->setDoesNotRecurse();
525e5dd7070Spatrick
526a9ac8606Spatrick // Always inline the outlined function if optimizations are enabled.
527*12c85518Srobert if (CGM.getCodeGenOpts().OptimizationLevel != 0) {
528*12c85518Srobert F->removeFnAttr(llvm::Attribute::NoInline);
529a9ac8606Spatrick F->addFnAttr(llvm::Attribute::AlwaysInline);
530*12c85518Srobert }
531a9ac8606Spatrick
532e5dd7070Spatrick // Generate the function.
533e5dd7070Spatrick CGF.StartFunction(CD, Ctx.VoidTy, F, FuncInfo, TargetArgs,
534ec727ea7Spatrick FO.UIntPtrCastRequired ? FO.Loc : FO.S->getBeginLoc(),
535ec727ea7Spatrick FO.UIntPtrCastRequired ? FO.Loc
536ec727ea7Spatrick : CD->getBody()->getBeginLoc());
537e5dd7070Spatrick unsigned Cnt = CD->getContextParamPosition();
538e5dd7070Spatrick I = FO.S->captures().begin();
539e5dd7070Spatrick for (const FieldDecl *FD : RD->fields()) {
540e5dd7070Spatrick // Do not map arguments if we emit function with non-original types.
541e5dd7070Spatrick Address LocalAddr(Address::invalid());
542e5dd7070Spatrick if (!FO.UIntPtrCastRequired && Args[Cnt] != TargetArgs[Cnt]) {
543e5dd7070Spatrick LocalAddr = CGM.getOpenMPRuntime().getParameterAddress(CGF, Args[Cnt],
544e5dd7070Spatrick TargetArgs[Cnt]);
545e5dd7070Spatrick } else {
546e5dd7070Spatrick LocalAddr = CGF.GetAddrOfLocalVar(Args[Cnt]);
547e5dd7070Spatrick }
548e5dd7070Spatrick // If we are capturing a pointer by copy we don't need to do anything, just
549e5dd7070Spatrick // use the value that we get from the arguments.
550e5dd7070Spatrick if (I->capturesVariableByCopy() && FD->getType()->isAnyPointerType()) {
551e5dd7070Spatrick const VarDecl *CurVD = I->getCapturedVar();
552e5dd7070Spatrick if (!FO.RegisterCastedArgsOnly)
553e5dd7070Spatrick LocalAddrs.insert({Args[Cnt], {CurVD, LocalAddr}});
554e5dd7070Spatrick ++Cnt;
555e5dd7070Spatrick ++I;
556e5dd7070Spatrick continue;
557e5dd7070Spatrick }
558e5dd7070Spatrick
559e5dd7070Spatrick LValue ArgLVal = CGF.MakeAddrLValue(LocalAddr, Args[Cnt]->getType(),
560e5dd7070Spatrick AlignmentSource::Decl);
561e5dd7070Spatrick if (FD->hasCapturedVLAType()) {
562e5dd7070Spatrick if (FO.UIntPtrCastRequired) {
563e5dd7070Spatrick ArgLVal = CGF.MakeAddrLValue(
564e5dd7070Spatrick castValueFromUintptr(CGF, I->getLocation(), FD->getType(),
565e5dd7070Spatrick Args[Cnt]->getName(), ArgLVal),
566e5dd7070Spatrick FD->getType(), AlignmentSource::Decl);
567e5dd7070Spatrick }
568e5dd7070Spatrick llvm::Value *ExprArg = CGF.EmitLoadOfScalar(ArgLVal, I->getLocation());
569e5dd7070Spatrick const VariableArrayType *VAT = FD->getCapturedVLAType();
570e5dd7070Spatrick VLASizes.try_emplace(Args[Cnt], VAT->getSizeExpr(), ExprArg);
571e5dd7070Spatrick } else if (I->capturesVariable()) {
572e5dd7070Spatrick const VarDecl *Var = I->getCapturedVar();
573e5dd7070Spatrick QualType VarTy = Var->getType();
574e5dd7070Spatrick Address ArgAddr = ArgLVal.getAddress(CGF);
575e5dd7070Spatrick if (ArgLVal.getType()->isLValueReferenceType()) {
576e5dd7070Spatrick ArgAddr = CGF.EmitLoadOfReference(ArgLVal);
577e5dd7070Spatrick } else if (!VarTy->isVariablyModifiedType() || !VarTy->isPointerType()) {
578e5dd7070Spatrick assert(ArgLVal.getType()->isPointerType());
579e5dd7070Spatrick ArgAddr = CGF.EmitLoadOfPointer(
580e5dd7070Spatrick ArgAddr, ArgLVal.getType()->castAs<PointerType>());
581e5dd7070Spatrick }
582e5dd7070Spatrick if (!FO.RegisterCastedArgsOnly) {
583e5dd7070Spatrick LocalAddrs.insert(
584*12c85518Srobert {Args[Cnt], {Var, ArgAddr.withAlignment(Ctx.getDeclAlign(Var))}});
585e5dd7070Spatrick }
586e5dd7070Spatrick } else if (I->capturesVariableByCopy()) {
587e5dd7070Spatrick assert(!FD->getType()->isAnyPointerType() &&
588e5dd7070Spatrick "Not expecting a captured pointer.");
589e5dd7070Spatrick const VarDecl *Var = I->getCapturedVar();
590e5dd7070Spatrick LocalAddrs.insert({Args[Cnt],
591e5dd7070Spatrick {Var, FO.UIntPtrCastRequired
592e5dd7070Spatrick ? castValueFromUintptr(
593e5dd7070Spatrick CGF, I->getLocation(), FD->getType(),
594e5dd7070Spatrick Args[Cnt]->getName(), ArgLVal)
595e5dd7070Spatrick : ArgLVal.getAddress(CGF)}});
596e5dd7070Spatrick } else {
597e5dd7070Spatrick // If 'this' is captured, load it into CXXThisValue.
598e5dd7070Spatrick assert(I->capturesThis());
599e5dd7070Spatrick CXXThisValue = CGF.EmitLoadOfScalar(ArgLVal, I->getLocation());
600e5dd7070Spatrick LocalAddrs.insert({Args[Cnt], {nullptr, ArgLVal.getAddress(CGF)}});
601e5dd7070Spatrick }
602e5dd7070Spatrick ++Cnt;
603e5dd7070Spatrick ++I;
604e5dd7070Spatrick }
605e5dd7070Spatrick
606e5dd7070Spatrick return F;
607e5dd7070Spatrick }
608e5dd7070Spatrick
609e5dd7070Spatrick llvm::Function *
GenerateOpenMPCapturedStmtFunction(const CapturedStmt & S,SourceLocation Loc)610ec727ea7Spatrick CodeGenFunction::GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S,
611ec727ea7Spatrick SourceLocation Loc) {
612e5dd7070Spatrick assert(
613e5dd7070Spatrick CapturedStmtInfo &&
614e5dd7070Spatrick "CapturedStmtInfo should be set when generating the captured function");
615e5dd7070Spatrick const CapturedDecl *CD = S.getCapturedDecl();
616e5dd7070Spatrick // Build the argument list.
617e5dd7070Spatrick bool NeedWrapperFunction =
618e5dd7070Spatrick getDebugInfo() && CGM.getCodeGenOpts().hasReducedDebugInfo();
619e5dd7070Spatrick FunctionArgList Args;
620e5dd7070Spatrick llvm::MapVector<const Decl *, std::pair<const VarDecl *, Address>> LocalAddrs;
621e5dd7070Spatrick llvm::DenseMap<const Decl *, std::pair<const Expr *, llvm::Value *>> VLASizes;
622e5dd7070Spatrick SmallString<256> Buffer;
623e5dd7070Spatrick llvm::raw_svector_ostream Out(Buffer);
624e5dd7070Spatrick Out << CapturedStmtInfo->getHelperName();
625e5dd7070Spatrick if (NeedWrapperFunction)
626e5dd7070Spatrick Out << "_debug__";
627e5dd7070Spatrick FunctionOptions FO(&S, !NeedWrapperFunction, /*RegisterCastedArgsOnly=*/false,
628ec727ea7Spatrick Out.str(), Loc);
629e5dd7070Spatrick llvm::Function *F = emitOutlinedFunctionPrologue(*this, Args, LocalAddrs,
630e5dd7070Spatrick VLASizes, CXXThisValue, FO);
631e5dd7070Spatrick CodeGenFunction::OMPPrivateScope LocalScope(*this);
632e5dd7070Spatrick for (const auto &LocalAddrPair : LocalAddrs) {
633e5dd7070Spatrick if (LocalAddrPair.second.first) {
634*12c85518Srobert LocalScope.addPrivate(LocalAddrPair.second.first,
635*12c85518Srobert LocalAddrPair.second.second);
636e5dd7070Spatrick }
637e5dd7070Spatrick }
638e5dd7070Spatrick (void)LocalScope.Privatize();
639e5dd7070Spatrick for (const auto &VLASizePair : VLASizes)
640e5dd7070Spatrick VLASizeMap[VLASizePair.second.first] = VLASizePair.second.second;
641e5dd7070Spatrick PGO.assignRegionCounters(GlobalDecl(CD), F);
642e5dd7070Spatrick CapturedStmtInfo->EmitBody(*this, CD->getBody());
643e5dd7070Spatrick (void)LocalScope.ForceCleanup();
644e5dd7070Spatrick FinishFunction(CD->getBodyRBrace());
645e5dd7070Spatrick if (!NeedWrapperFunction)
646e5dd7070Spatrick return F;
647e5dd7070Spatrick
648e5dd7070Spatrick FunctionOptions WrapperFO(&S, /*UIntPtrCastRequired=*/true,
649e5dd7070Spatrick /*RegisterCastedArgsOnly=*/true,
650ec727ea7Spatrick CapturedStmtInfo->getHelperName(), Loc);
651e5dd7070Spatrick CodeGenFunction WrapperCGF(CGM, /*suppressNewContext=*/true);
652e5dd7070Spatrick WrapperCGF.CapturedStmtInfo = CapturedStmtInfo;
653e5dd7070Spatrick Args.clear();
654e5dd7070Spatrick LocalAddrs.clear();
655e5dd7070Spatrick VLASizes.clear();
656e5dd7070Spatrick llvm::Function *WrapperF =
657e5dd7070Spatrick emitOutlinedFunctionPrologue(WrapperCGF, Args, LocalAddrs, VLASizes,
658e5dd7070Spatrick WrapperCGF.CXXThisValue, WrapperFO);
659e5dd7070Spatrick llvm::SmallVector<llvm::Value *, 4> CallArgs;
660a9ac8606Spatrick auto *PI = F->arg_begin();
661e5dd7070Spatrick for (const auto *Arg : Args) {
662e5dd7070Spatrick llvm::Value *CallArg;
663e5dd7070Spatrick auto I = LocalAddrs.find(Arg);
664e5dd7070Spatrick if (I != LocalAddrs.end()) {
665e5dd7070Spatrick LValue LV = WrapperCGF.MakeAddrLValue(
666e5dd7070Spatrick I->second.second,
667e5dd7070Spatrick I->second.first ? I->second.first->getType() : Arg->getType(),
668e5dd7070Spatrick AlignmentSource::Decl);
669a9ac8606Spatrick if (LV.getType()->isAnyComplexType())
670a9ac8606Spatrick LV.setAddress(WrapperCGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
671a9ac8606Spatrick LV.getAddress(WrapperCGF),
672a9ac8606Spatrick PI->getType()->getPointerTo(
673*12c85518Srobert LV.getAddress(WrapperCGF).getAddressSpace()),
674*12c85518Srobert PI->getType()));
675e5dd7070Spatrick CallArg = WrapperCGF.EmitLoadOfScalar(LV, S.getBeginLoc());
676e5dd7070Spatrick } else {
677e5dd7070Spatrick auto EI = VLASizes.find(Arg);
678e5dd7070Spatrick if (EI != VLASizes.end()) {
679e5dd7070Spatrick CallArg = EI->second.second;
680e5dd7070Spatrick } else {
681*12c85518Srobert LValue LV =
682*12c85518Srobert WrapperCGF.MakeAddrLValue(WrapperCGF.GetAddrOfLocalVar(Arg),
683*12c85518Srobert Arg->getType(), AlignmentSource::Decl);
684e5dd7070Spatrick CallArg = WrapperCGF.EmitLoadOfScalar(LV, S.getBeginLoc());
685e5dd7070Spatrick }
686e5dd7070Spatrick }
687e5dd7070Spatrick CallArgs.emplace_back(WrapperCGF.EmitFromMemory(CallArg, Arg->getType()));
688a9ac8606Spatrick ++PI;
689e5dd7070Spatrick }
690ec727ea7Spatrick CGM.getOpenMPRuntime().emitOutlinedFunctionCall(WrapperCGF, Loc, F, CallArgs);
691e5dd7070Spatrick WrapperCGF.FinishFunction();
692e5dd7070Spatrick return WrapperF;
693e5dd7070Spatrick }
694e5dd7070Spatrick
695e5dd7070Spatrick //===----------------------------------------------------------------------===//
696e5dd7070Spatrick // OpenMP Directive Emission
697e5dd7070Spatrick //===----------------------------------------------------------------------===//
EmitOMPAggregateAssign(Address DestAddr,Address SrcAddr,QualType OriginalType,const llvm::function_ref<void (Address,Address)> CopyGen)698e5dd7070Spatrick void CodeGenFunction::EmitOMPAggregateAssign(
699e5dd7070Spatrick Address DestAddr, Address SrcAddr, QualType OriginalType,
700e5dd7070Spatrick const llvm::function_ref<void(Address, Address)> CopyGen) {
701e5dd7070Spatrick // Perform element-by-element initialization.
702e5dd7070Spatrick QualType ElementTy;
703e5dd7070Spatrick
704e5dd7070Spatrick // Drill down to the base element type on both arrays.
705e5dd7070Spatrick const ArrayType *ArrayTy = OriginalType->getAsArrayTypeUnsafe();
706e5dd7070Spatrick llvm::Value *NumElements = emitArrayLength(ArrayTy, ElementTy, DestAddr);
707e5dd7070Spatrick SrcAddr = Builder.CreateElementBitCast(SrcAddr, DestAddr.getElementType());
708e5dd7070Spatrick
709e5dd7070Spatrick llvm::Value *SrcBegin = SrcAddr.getPointer();
710e5dd7070Spatrick llvm::Value *DestBegin = DestAddr.getPointer();
711e5dd7070Spatrick // Cast from pointer to array type to pointer to single element.
712*12c85518Srobert llvm::Value *DestEnd = Builder.CreateInBoundsGEP(DestAddr.getElementType(),
713*12c85518Srobert DestBegin, NumElements);
714*12c85518Srobert
715e5dd7070Spatrick // The basic structure here is a while-do loop.
716e5dd7070Spatrick llvm::BasicBlock *BodyBB = createBasicBlock("omp.arraycpy.body");
717e5dd7070Spatrick llvm::BasicBlock *DoneBB = createBasicBlock("omp.arraycpy.done");
718e5dd7070Spatrick llvm::Value *IsEmpty =
719e5dd7070Spatrick Builder.CreateICmpEQ(DestBegin, DestEnd, "omp.arraycpy.isempty");
720e5dd7070Spatrick Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB);
721e5dd7070Spatrick
722e5dd7070Spatrick // Enter the loop body, making that address the current address.
723e5dd7070Spatrick llvm::BasicBlock *EntryBB = Builder.GetInsertBlock();
724e5dd7070Spatrick EmitBlock(BodyBB);
725e5dd7070Spatrick
726e5dd7070Spatrick CharUnits ElementSize = getContext().getTypeSizeInChars(ElementTy);
727e5dd7070Spatrick
728e5dd7070Spatrick llvm::PHINode *SrcElementPHI =
729e5dd7070Spatrick Builder.CreatePHI(SrcBegin->getType(), 2, "omp.arraycpy.srcElementPast");
730e5dd7070Spatrick SrcElementPHI->addIncoming(SrcBegin, EntryBB);
731e5dd7070Spatrick Address SrcElementCurrent =
732*12c85518Srobert Address(SrcElementPHI, SrcAddr.getElementType(),
733e5dd7070Spatrick SrcAddr.getAlignment().alignmentOfArrayElement(ElementSize));
734e5dd7070Spatrick
735*12c85518Srobert llvm::PHINode *DestElementPHI = Builder.CreatePHI(
736*12c85518Srobert DestBegin->getType(), 2, "omp.arraycpy.destElementPast");
737e5dd7070Spatrick DestElementPHI->addIncoming(DestBegin, EntryBB);
738e5dd7070Spatrick Address DestElementCurrent =
739*12c85518Srobert Address(DestElementPHI, DestAddr.getElementType(),
740e5dd7070Spatrick DestAddr.getAlignment().alignmentOfArrayElement(ElementSize));
741e5dd7070Spatrick
742e5dd7070Spatrick // Emit copy.
743e5dd7070Spatrick CopyGen(DestElementCurrent, SrcElementCurrent);
744e5dd7070Spatrick
745e5dd7070Spatrick // Shift the address forward by one element.
746*12c85518Srobert llvm::Value *DestElementNext =
747*12c85518Srobert Builder.CreateConstGEP1_32(DestAddr.getElementType(), DestElementPHI,
748*12c85518Srobert /*Idx0=*/1, "omp.arraycpy.dest.element");
749*12c85518Srobert llvm::Value *SrcElementNext =
750*12c85518Srobert Builder.CreateConstGEP1_32(SrcAddr.getElementType(), SrcElementPHI,
751*12c85518Srobert /*Idx0=*/1, "omp.arraycpy.src.element");
752e5dd7070Spatrick // Check whether we've reached the end.
753e5dd7070Spatrick llvm::Value *Done =
754e5dd7070Spatrick Builder.CreateICmpEQ(DestElementNext, DestEnd, "omp.arraycpy.done");
755e5dd7070Spatrick Builder.CreateCondBr(Done, DoneBB, BodyBB);
756e5dd7070Spatrick DestElementPHI->addIncoming(DestElementNext, Builder.GetInsertBlock());
757e5dd7070Spatrick SrcElementPHI->addIncoming(SrcElementNext, Builder.GetInsertBlock());
758e5dd7070Spatrick
759e5dd7070Spatrick // Done.
760e5dd7070Spatrick EmitBlock(DoneBB, /*IsFinished=*/true);
761e5dd7070Spatrick }
762e5dd7070Spatrick
EmitOMPCopy(QualType OriginalType,Address DestAddr,Address SrcAddr,const VarDecl * DestVD,const VarDecl * SrcVD,const Expr * Copy)763e5dd7070Spatrick void CodeGenFunction::EmitOMPCopy(QualType OriginalType, Address DestAddr,
764e5dd7070Spatrick Address SrcAddr, const VarDecl *DestVD,
765e5dd7070Spatrick const VarDecl *SrcVD, const Expr *Copy) {
766e5dd7070Spatrick if (OriginalType->isArrayType()) {
767e5dd7070Spatrick const auto *BO = dyn_cast<BinaryOperator>(Copy);
768e5dd7070Spatrick if (BO && BO->getOpcode() == BO_Assign) {
769e5dd7070Spatrick // Perform simple memcpy for simple copying.
770e5dd7070Spatrick LValue Dest = MakeAddrLValue(DestAddr, OriginalType);
771e5dd7070Spatrick LValue Src = MakeAddrLValue(SrcAddr, OriginalType);
772e5dd7070Spatrick EmitAggregateAssign(Dest, Src, OriginalType);
773e5dd7070Spatrick } else {
774e5dd7070Spatrick // For arrays with complex element types perform element by element
775e5dd7070Spatrick // copying.
776e5dd7070Spatrick EmitOMPAggregateAssign(
777e5dd7070Spatrick DestAddr, SrcAddr, OriginalType,
778e5dd7070Spatrick [this, Copy, SrcVD, DestVD](Address DestElement, Address SrcElement) {
779e5dd7070Spatrick // Working with the single array element, so have to remap
780e5dd7070Spatrick // destination and source variables to corresponding array
781e5dd7070Spatrick // elements.
782e5dd7070Spatrick CodeGenFunction::OMPPrivateScope Remap(*this);
783*12c85518Srobert Remap.addPrivate(DestVD, DestElement);
784*12c85518Srobert Remap.addPrivate(SrcVD, SrcElement);
785e5dd7070Spatrick (void)Remap.Privatize();
786e5dd7070Spatrick EmitIgnoredExpr(Copy);
787e5dd7070Spatrick });
788e5dd7070Spatrick }
789e5dd7070Spatrick } else {
790e5dd7070Spatrick // Remap pseudo source variable to private copy.
791e5dd7070Spatrick CodeGenFunction::OMPPrivateScope Remap(*this);
792*12c85518Srobert Remap.addPrivate(SrcVD, SrcAddr);
793*12c85518Srobert Remap.addPrivate(DestVD, DestAddr);
794e5dd7070Spatrick (void)Remap.Privatize();
795e5dd7070Spatrick // Emit copying of the whole variable.
796e5dd7070Spatrick EmitIgnoredExpr(Copy);
797e5dd7070Spatrick }
798e5dd7070Spatrick }
799e5dd7070Spatrick
EmitOMPFirstprivateClause(const OMPExecutableDirective & D,OMPPrivateScope & PrivateScope)800e5dd7070Spatrick bool CodeGenFunction::EmitOMPFirstprivateClause(const OMPExecutableDirective &D,
801e5dd7070Spatrick OMPPrivateScope &PrivateScope) {
802e5dd7070Spatrick if (!HaveInsertPoint())
803e5dd7070Spatrick return false;
804e5dd7070Spatrick bool DeviceConstTarget =
805e5dd7070Spatrick getLangOpts().OpenMPIsDevice &&
806e5dd7070Spatrick isOpenMPTargetExecutionDirective(D.getDirectiveKind());
807e5dd7070Spatrick bool FirstprivateIsLastprivate = false;
808ec727ea7Spatrick llvm::DenseMap<const VarDecl *, OpenMPLastprivateModifier> Lastprivates;
809e5dd7070Spatrick for (const auto *C : D.getClausesOfKind<OMPLastprivateClause>()) {
810e5dd7070Spatrick for (const auto *D : C->varlists())
811ec727ea7Spatrick Lastprivates.try_emplace(
812ec727ea7Spatrick cast<VarDecl>(cast<DeclRefExpr>(D)->getDecl())->getCanonicalDecl(),
813ec727ea7Spatrick C->getKind());
814e5dd7070Spatrick }
815e5dd7070Spatrick llvm::DenseSet<const VarDecl *> EmittedAsFirstprivate;
816e5dd7070Spatrick llvm::SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
817e5dd7070Spatrick getOpenMPCaptureRegions(CaptureRegions, D.getDirectiveKind());
818e5dd7070Spatrick // Force emission of the firstprivate copy if the directive does not emit
819e5dd7070Spatrick // outlined function, like omp for, omp simd, omp distribute etc.
820e5dd7070Spatrick bool MustEmitFirstprivateCopy =
821e5dd7070Spatrick CaptureRegions.size() == 1 && CaptureRegions.back() == OMPD_unknown;
822e5dd7070Spatrick for (const auto *C : D.getClausesOfKind<OMPFirstprivateClause>()) {
823ec727ea7Spatrick const auto *IRef = C->varlist_begin();
824ec727ea7Spatrick const auto *InitsRef = C->inits().begin();
825e5dd7070Spatrick for (const Expr *IInit : C->private_copies()) {
826e5dd7070Spatrick const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
827e5dd7070Spatrick bool ThisFirstprivateIsLastprivate =
828e5dd7070Spatrick Lastprivates.count(OrigVD->getCanonicalDecl()) > 0;
829e5dd7070Spatrick const FieldDecl *FD = CapturedStmtInfo->lookup(OrigVD);
830e5dd7070Spatrick const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(IInit)->getDecl());
831e5dd7070Spatrick if (!MustEmitFirstprivateCopy && !ThisFirstprivateIsLastprivate && FD &&
832e5dd7070Spatrick !FD->getType()->isReferenceType() &&
833e5dd7070Spatrick (!VD || !VD->hasAttr<OMPAllocateDeclAttr>())) {
834e5dd7070Spatrick EmittedAsFirstprivate.insert(OrigVD->getCanonicalDecl());
835e5dd7070Spatrick ++IRef;
836e5dd7070Spatrick ++InitsRef;
837e5dd7070Spatrick continue;
838e5dd7070Spatrick }
839e5dd7070Spatrick // Do not emit copy for firstprivate constant variables in target regions,
840e5dd7070Spatrick // captured by reference.
841e5dd7070Spatrick if (DeviceConstTarget && OrigVD->getType().isConstant(getContext()) &&
842e5dd7070Spatrick FD && FD->getType()->isReferenceType() &&
843e5dd7070Spatrick (!VD || !VD->hasAttr<OMPAllocateDeclAttr>())) {
844a9ac8606Spatrick EmittedAsFirstprivate.insert(OrigVD->getCanonicalDecl());
845e5dd7070Spatrick ++IRef;
846e5dd7070Spatrick ++InitsRef;
847e5dd7070Spatrick continue;
848e5dd7070Spatrick }
849e5dd7070Spatrick FirstprivateIsLastprivate =
850e5dd7070Spatrick FirstprivateIsLastprivate || ThisFirstprivateIsLastprivate;
851e5dd7070Spatrick if (EmittedAsFirstprivate.insert(OrigVD->getCanonicalDecl()).second) {
852e5dd7070Spatrick const auto *VDInit =
853e5dd7070Spatrick cast<VarDecl>(cast<DeclRefExpr>(*InitsRef)->getDecl());
854e5dd7070Spatrick bool IsRegistered;
855e5dd7070Spatrick DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(OrigVD),
856e5dd7070Spatrick /*RefersToEnclosingVariableOrCapture=*/FD != nullptr,
857e5dd7070Spatrick (*IRef)->getType(), VK_LValue, (*IRef)->getExprLoc());
858e5dd7070Spatrick LValue OriginalLVal;
859e5dd7070Spatrick if (!FD) {
860e5dd7070Spatrick // Check if the firstprivate variable is just a constant value.
861e5dd7070Spatrick ConstantEmission CE = tryEmitAsConstant(&DRE);
862e5dd7070Spatrick if (CE && !CE.isReference()) {
863e5dd7070Spatrick // Constant value, no need to create a copy.
864e5dd7070Spatrick ++IRef;
865e5dd7070Spatrick ++InitsRef;
866e5dd7070Spatrick continue;
867e5dd7070Spatrick }
868e5dd7070Spatrick if (CE && CE.isReference()) {
869e5dd7070Spatrick OriginalLVal = CE.getReferenceLValue(*this, &DRE);
870e5dd7070Spatrick } else {
871e5dd7070Spatrick assert(!CE && "Expected non-constant firstprivate.");
872e5dd7070Spatrick OriginalLVal = EmitLValue(&DRE);
873e5dd7070Spatrick }
874e5dd7070Spatrick } else {
875e5dd7070Spatrick OriginalLVal = EmitLValue(&DRE);
876e5dd7070Spatrick }
877e5dd7070Spatrick QualType Type = VD->getType();
878e5dd7070Spatrick if (Type->isArrayType()) {
879e5dd7070Spatrick // Emit VarDecl with copy init for arrays.
880e5dd7070Spatrick // Get the address of the original variable captured in current
881e5dd7070Spatrick // captured region.
882e5dd7070Spatrick AutoVarEmission Emission = EmitAutoVarAlloca(*VD);
883e5dd7070Spatrick const Expr *Init = VD->getInit();
884*12c85518Srobert if (!isa<CXXConstructExpr>(Init) || isTrivialInitializer(Init)) {
885e5dd7070Spatrick // Perform simple memcpy.
886*12c85518Srobert LValue Dest = MakeAddrLValue(Emission.getAllocatedAddress(), Type);
887e5dd7070Spatrick EmitAggregateAssign(Dest, OriginalLVal, Type);
888e5dd7070Spatrick } else {
889e5dd7070Spatrick EmitOMPAggregateAssign(
890*12c85518Srobert Emission.getAllocatedAddress(), OriginalLVal.getAddress(*this),
891*12c85518Srobert Type,
892*12c85518Srobert [this, VDInit, Init](Address DestElement, Address SrcElement) {
893e5dd7070Spatrick // Clean up any temporaries needed by the
894e5dd7070Spatrick // initialization.
895e5dd7070Spatrick RunCleanupsScope InitScope(*this);
896e5dd7070Spatrick // Emit initialization for single element.
897e5dd7070Spatrick setAddrOfLocalVar(VDInit, SrcElement);
898e5dd7070Spatrick EmitAnyExprToMem(Init, DestElement,
899e5dd7070Spatrick Init->getType().getQualifiers(),
900e5dd7070Spatrick /*IsInitializer*/ false);
901e5dd7070Spatrick LocalDeclMap.erase(VDInit);
902e5dd7070Spatrick });
903e5dd7070Spatrick }
904e5dd7070Spatrick EmitAutoVarCleanups(Emission);
905*12c85518Srobert IsRegistered =
906*12c85518Srobert PrivateScope.addPrivate(OrigVD, Emission.getAllocatedAddress());
907e5dd7070Spatrick } else {
908e5dd7070Spatrick Address OriginalAddr = OriginalLVal.getAddress(*this);
909e5dd7070Spatrick // Emit private VarDecl with copy init.
910e5dd7070Spatrick // Remap temp VDInit variable to the address of the original
911e5dd7070Spatrick // variable (for proper handling of captured global variables).
912e5dd7070Spatrick setAddrOfLocalVar(VDInit, OriginalAddr);
913e5dd7070Spatrick EmitDecl(*VD);
914e5dd7070Spatrick LocalDeclMap.erase(VDInit);
915*12c85518Srobert Address VDAddr = GetAddrOfLocalVar(VD);
916ec727ea7Spatrick if (ThisFirstprivateIsLastprivate &&
917ec727ea7Spatrick Lastprivates[OrigVD->getCanonicalDecl()] ==
918ec727ea7Spatrick OMPC_LASTPRIVATE_conditional) {
919ec727ea7Spatrick // Create/init special variable for lastprivate conditionals.
920*12c85518Srobert llvm::Value *V =
921*12c85518Srobert EmitLoadOfScalar(MakeAddrLValue(VDAddr, (*IRef)->getType(),
922ec727ea7Spatrick AlignmentSource::Decl),
923ec727ea7Spatrick (*IRef)->getExprLoc());
924*12c85518Srobert VDAddr = CGM.getOpenMPRuntime().emitLastprivateConditionalInit(
925*12c85518Srobert *this, OrigVD);
926*12c85518Srobert EmitStoreOfScalar(V, MakeAddrLValue(VDAddr, (*IRef)->getType(),
927ec727ea7Spatrick AlignmentSource::Decl));
928ec727ea7Spatrick LocalDeclMap.erase(VD);
929ec727ea7Spatrick setAddrOfLocalVar(VD, VDAddr);
930ec727ea7Spatrick }
931*12c85518Srobert IsRegistered = PrivateScope.addPrivate(OrigVD, VDAddr);
932e5dd7070Spatrick }
933e5dd7070Spatrick assert(IsRegistered &&
934e5dd7070Spatrick "firstprivate var already registered as private");
935e5dd7070Spatrick // Silence the warning about unused variable.
936e5dd7070Spatrick (void)IsRegistered;
937e5dd7070Spatrick }
938e5dd7070Spatrick ++IRef;
939e5dd7070Spatrick ++InitsRef;
940e5dd7070Spatrick }
941e5dd7070Spatrick }
942e5dd7070Spatrick return FirstprivateIsLastprivate && !EmittedAsFirstprivate.empty();
943e5dd7070Spatrick }
944e5dd7070Spatrick
EmitOMPPrivateClause(const OMPExecutableDirective & D,CodeGenFunction::OMPPrivateScope & PrivateScope)945e5dd7070Spatrick void CodeGenFunction::EmitOMPPrivateClause(
946e5dd7070Spatrick const OMPExecutableDirective &D,
947e5dd7070Spatrick CodeGenFunction::OMPPrivateScope &PrivateScope) {
948e5dd7070Spatrick if (!HaveInsertPoint())
949e5dd7070Spatrick return;
950e5dd7070Spatrick llvm::DenseSet<const VarDecl *> EmittedAsPrivate;
951e5dd7070Spatrick for (const auto *C : D.getClausesOfKind<OMPPrivateClause>()) {
952e5dd7070Spatrick auto IRef = C->varlist_begin();
953e5dd7070Spatrick for (const Expr *IInit : C->private_copies()) {
954e5dd7070Spatrick const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
955e5dd7070Spatrick if (EmittedAsPrivate.insert(OrigVD->getCanonicalDecl()).second) {
956e5dd7070Spatrick const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(IInit)->getDecl());
957e5dd7070Spatrick EmitDecl(*VD);
958*12c85518Srobert // Emit private VarDecl with copy init.
959*12c85518Srobert bool IsRegistered =
960*12c85518Srobert PrivateScope.addPrivate(OrigVD, GetAddrOfLocalVar(VD));
961e5dd7070Spatrick assert(IsRegistered && "private var already registered as private");
962e5dd7070Spatrick // Silence the warning about unused variable.
963e5dd7070Spatrick (void)IsRegistered;
964e5dd7070Spatrick }
965e5dd7070Spatrick ++IRef;
966e5dd7070Spatrick }
967e5dd7070Spatrick }
968e5dd7070Spatrick }
969e5dd7070Spatrick
EmitOMPCopyinClause(const OMPExecutableDirective & D)970e5dd7070Spatrick bool CodeGenFunction::EmitOMPCopyinClause(const OMPExecutableDirective &D) {
971e5dd7070Spatrick if (!HaveInsertPoint())
972e5dd7070Spatrick return false;
973e5dd7070Spatrick // threadprivate_var1 = master_threadprivate_var1;
974e5dd7070Spatrick // operator=(threadprivate_var2, master_threadprivate_var2);
975e5dd7070Spatrick // ...
976e5dd7070Spatrick // __kmpc_barrier(&loc, global_tid);
977e5dd7070Spatrick llvm::DenseSet<const VarDecl *> CopiedVars;
978e5dd7070Spatrick llvm::BasicBlock *CopyBegin = nullptr, *CopyEnd = nullptr;
979e5dd7070Spatrick for (const auto *C : D.getClausesOfKind<OMPCopyinClause>()) {
980e5dd7070Spatrick auto IRef = C->varlist_begin();
981e5dd7070Spatrick auto ISrcRef = C->source_exprs().begin();
982e5dd7070Spatrick auto IDestRef = C->destination_exprs().begin();
983e5dd7070Spatrick for (const Expr *AssignOp : C->assignment_ops()) {
984e5dd7070Spatrick const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
985e5dd7070Spatrick QualType Type = VD->getType();
986e5dd7070Spatrick if (CopiedVars.insert(VD->getCanonicalDecl()).second) {
987e5dd7070Spatrick // Get the address of the master variable. If we are emitting code with
988e5dd7070Spatrick // TLS support, the address is passed from the master as field in the
989e5dd7070Spatrick // captured declaration.
990e5dd7070Spatrick Address MasterAddr = Address::invalid();
991e5dd7070Spatrick if (getLangOpts().OpenMPUseTLS &&
992e5dd7070Spatrick getContext().getTargetInfo().isTLSSupported()) {
993e5dd7070Spatrick assert(CapturedStmtInfo->lookup(VD) &&
994e5dd7070Spatrick "Copyin threadprivates should have been captured!");
995e5dd7070Spatrick DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(VD), true,
996e5dd7070Spatrick (*IRef)->getType(), VK_LValue, (*IRef)->getExprLoc());
997e5dd7070Spatrick MasterAddr = EmitLValue(&DRE).getAddress(*this);
998e5dd7070Spatrick LocalDeclMap.erase(VD);
999e5dd7070Spatrick } else {
1000e5dd7070Spatrick MasterAddr =
1001e5dd7070Spatrick Address(VD->isStaticLocal() ? CGM.getStaticLocalDeclAddress(VD)
1002e5dd7070Spatrick : CGM.GetAddrOfGlobal(VD),
1003*12c85518Srobert CGM.getTypes().ConvertTypeForMem(VD->getType()),
1004e5dd7070Spatrick getContext().getDeclAlign(VD));
1005e5dd7070Spatrick }
1006e5dd7070Spatrick // Get the address of the threadprivate variable.
1007e5dd7070Spatrick Address PrivateAddr = EmitLValue(*IRef).getAddress(*this);
1008e5dd7070Spatrick if (CopiedVars.size() == 1) {
1009e5dd7070Spatrick // At first check if current thread is a master thread. If it is, no
1010e5dd7070Spatrick // need to copy data.
1011e5dd7070Spatrick CopyBegin = createBasicBlock("copyin.not.master");
1012e5dd7070Spatrick CopyEnd = createBasicBlock("copyin.not.master.end");
1013a9ac8606Spatrick // TODO: Avoid ptrtoint conversion.
1014a9ac8606Spatrick auto *MasterAddrInt =
1015a9ac8606Spatrick Builder.CreatePtrToInt(MasterAddr.getPointer(), CGM.IntPtrTy);
1016a9ac8606Spatrick auto *PrivateAddrInt =
1017a9ac8606Spatrick Builder.CreatePtrToInt(PrivateAddr.getPointer(), CGM.IntPtrTy);
1018e5dd7070Spatrick Builder.CreateCondBr(
1019a9ac8606Spatrick Builder.CreateICmpNE(MasterAddrInt, PrivateAddrInt), CopyBegin,
1020a9ac8606Spatrick CopyEnd);
1021e5dd7070Spatrick EmitBlock(CopyBegin);
1022e5dd7070Spatrick }
1023e5dd7070Spatrick const auto *SrcVD =
1024e5dd7070Spatrick cast<VarDecl>(cast<DeclRefExpr>(*ISrcRef)->getDecl());
1025e5dd7070Spatrick const auto *DestVD =
1026e5dd7070Spatrick cast<VarDecl>(cast<DeclRefExpr>(*IDestRef)->getDecl());
1027e5dd7070Spatrick EmitOMPCopy(Type, PrivateAddr, MasterAddr, DestVD, SrcVD, AssignOp);
1028e5dd7070Spatrick }
1029e5dd7070Spatrick ++IRef;
1030e5dd7070Spatrick ++ISrcRef;
1031e5dd7070Spatrick ++IDestRef;
1032e5dd7070Spatrick }
1033e5dd7070Spatrick }
1034e5dd7070Spatrick if (CopyEnd) {
1035e5dd7070Spatrick // Exit out of copying procedure for non-master thread.
1036e5dd7070Spatrick EmitBlock(CopyEnd, /*IsFinished=*/true);
1037e5dd7070Spatrick return true;
1038e5dd7070Spatrick }
1039e5dd7070Spatrick return false;
1040e5dd7070Spatrick }
1041e5dd7070Spatrick
EmitOMPLastprivateClauseInit(const OMPExecutableDirective & D,OMPPrivateScope & PrivateScope)1042e5dd7070Spatrick bool CodeGenFunction::EmitOMPLastprivateClauseInit(
1043e5dd7070Spatrick const OMPExecutableDirective &D, OMPPrivateScope &PrivateScope) {
1044e5dd7070Spatrick if (!HaveInsertPoint())
1045e5dd7070Spatrick return false;
1046e5dd7070Spatrick bool HasAtLeastOneLastprivate = false;
1047e5dd7070Spatrick llvm::DenseSet<const VarDecl *> SIMDLCVs;
1048e5dd7070Spatrick if (isOpenMPSimdDirective(D.getDirectiveKind())) {
1049e5dd7070Spatrick const auto *LoopDirective = cast<OMPLoopDirective>(&D);
1050e5dd7070Spatrick for (const Expr *C : LoopDirective->counters()) {
1051e5dd7070Spatrick SIMDLCVs.insert(
1052e5dd7070Spatrick cast<VarDecl>(cast<DeclRefExpr>(C)->getDecl())->getCanonicalDecl());
1053e5dd7070Spatrick }
1054e5dd7070Spatrick }
1055e5dd7070Spatrick llvm::DenseSet<const VarDecl *> AlreadyEmittedVars;
1056e5dd7070Spatrick for (const auto *C : D.getClausesOfKind<OMPLastprivateClause>()) {
1057e5dd7070Spatrick HasAtLeastOneLastprivate = true;
1058e5dd7070Spatrick if (isOpenMPTaskLoopDirective(D.getDirectiveKind()) &&
1059e5dd7070Spatrick !getLangOpts().OpenMPSimd)
1060e5dd7070Spatrick break;
1061ec727ea7Spatrick const auto *IRef = C->varlist_begin();
1062ec727ea7Spatrick const auto *IDestRef = C->destination_exprs().begin();
1063e5dd7070Spatrick for (const Expr *IInit : C->private_copies()) {
1064e5dd7070Spatrick // Keep the address of the original variable for future update at the end
1065e5dd7070Spatrick // of the loop.
1066e5dd7070Spatrick const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
1067e5dd7070Spatrick // Taskloops do not require additional initialization, it is done in
1068e5dd7070Spatrick // runtime support library.
1069e5dd7070Spatrick if (AlreadyEmittedVars.insert(OrigVD->getCanonicalDecl()).second) {
1070e5dd7070Spatrick const auto *DestVD =
1071e5dd7070Spatrick cast<VarDecl>(cast<DeclRefExpr>(*IDestRef)->getDecl());
1072e5dd7070Spatrick DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(OrigVD),
1073e5dd7070Spatrick /*RefersToEnclosingVariableOrCapture=*/
1074e5dd7070Spatrick CapturedStmtInfo->lookup(OrigVD) != nullptr,
1075e5dd7070Spatrick (*IRef)->getType(), VK_LValue, (*IRef)->getExprLoc());
1076*12c85518Srobert PrivateScope.addPrivate(DestVD, EmitLValue(&DRE).getAddress(*this));
1077e5dd7070Spatrick // Check if the variable is also a firstprivate: in this case IInit is
1078e5dd7070Spatrick // not generated. Initialization of this variable will happen in codegen
1079e5dd7070Spatrick // for 'firstprivate' clause.
1080e5dd7070Spatrick if (IInit && !SIMDLCVs.count(OrigVD->getCanonicalDecl())) {
1081e5dd7070Spatrick const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(IInit)->getDecl());
1082*12c85518Srobert Address VDAddr = Address::invalid();
1083ec727ea7Spatrick if (C->getKind() == OMPC_LASTPRIVATE_conditional) {
1084*12c85518Srobert VDAddr = CGM.getOpenMPRuntime().emitLastprivateConditionalInit(
1085*12c85518Srobert *this, OrigVD);
1086ec727ea7Spatrick setAddrOfLocalVar(VD, VDAddr);
1087*12c85518Srobert } else {
1088e5dd7070Spatrick // Emit private VarDecl with copy init.
1089e5dd7070Spatrick EmitDecl(*VD);
1090*12c85518Srobert VDAddr = GetAddrOfLocalVar(VD);
1091*12c85518Srobert }
1092*12c85518Srobert bool IsRegistered = PrivateScope.addPrivate(OrigVD, VDAddr);
1093e5dd7070Spatrick assert(IsRegistered &&
1094e5dd7070Spatrick "lastprivate var already registered as private");
1095e5dd7070Spatrick (void)IsRegistered;
1096e5dd7070Spatrick }
1097e5dd7070Spatrick }
1098e5dd7070Spatrick ++IRef;
1099e5dd7070Spatrick ++IDestRef;
1100e5dd7070Spatrick }
1101e5dd7070Spatrick }
1102e5dd7070Spatrick return HasAtLeastOneLastprivate;
1103e5dd7070Spatrick }
1104e5dd7070Spatrick
EmitOMPLastprivateClauseFinal(const OMPExecutableDirective & D,bool NoFinals,llvm::Value * IsLastIterCond)1105e5dd7070Spatrick void CodeGenFunction::EmitOMPLastprivateClauseFinal(
1106e5dd7070Spatrick const OMPExecutableDirective &D, bool NoFinals,
1107e5dd7070Spatrick llvm::Value *IsLastIterCond) {
1108e5dd7070Spatrick if (!HaveInsertPoint())
1109e5dd7070Spatrick return;
1110e5dd7070Spatrick // Emit following code:
1111e5dd7070Spatrick // if (<IsLastIterCond>) {
1112e5dd7070Spatrick // orig_var1 = private_orig_var1;
1113e5dd7070Spatrick // ...
1114e5dd7070Spatrick // orig_varn = private_orig_varn;
1115e5dd7070Spatrick // }
1116e5dd7070Spatrick llvm::BasicBlock *ThenBB = nullptr;
1117e5dd7070Spatrick llvm::BasicBlock *DoneBB = nullptr;
1118e5dd7070Spatrick if (IsLastIterCond) {
1119e5dd7070Spatrick // Emit implicit barrier if at least one lastprivate conditional is found
1120e5dd7070Spatrick // and this is not a simd mode.
1121e5dd7070Spatrick if (!getLangOpts().OpenMPSimd &&
1122e5dd7070Spatrick llvm::any_of(D.getClausesOfKind<OMPLastprivateClause>(),
1123e5dd7070Spatrick [](const OMPLastprivateClause *C) {
1124e5dd7070Spatrick return C->getKind() == OMPC_LASTPRIVATE_conditional;
1125e5dd7070Spatrick })) {
1126e5dd7070Spatrick CGM.getOpenMPRuntime().emitBarrierCall(*this, D.getBeginLoc(),
1127e5dd7070Spatrick OMPD_unknown,
1128e5dd7070Spatrick /*EmitChecks=*/false,
1129e5dd7070Spatrick /*ForceSimpleCall=*/true);
1130e5dd7070Spatrick }
1131e5dd7070Spatrick ThenBB = createBasicBlock(".omp.lastprivate.then");
1132e5dd7070Spatrick DoneBB = createBasicBlock(".omp.lastprivate.done");
1133e5dd7070Spatrick Builder.CreateCondBr(IsLastIterCond, ThenBB, DoneBB);
1134e5dd7070Spatrick EmitBlock(ThenBB);
1135e5dd7070Spatrick }
1136e5dd7070Spatrick llvm::DenseSet<const VarDecl *> AlreadyEmittedVars;
1137e5dd7070Spatrick llvm::DenseMap<const VarDecl *, const Expr *> LoopCountersAndUpdates;
1138e5dd7070Spatrick if (const auto *LoopDirective = dyn_cast<OMPLoopDirective>(&D)) {
1139e5dd7070Spatrick auto IC = LoopDirective->counters().begin();
1140e5dd7070Spatrick for (const Expr *F : LoopDirective->finals()) {
1141e5dd7070Spatrick const auto *D =
1142e5dd7070Spatrick cast<VarDecl>(cast<DeclRefExpr>(*IC)->getDecl())->getCanonicalDecl();
1143e5dd7070Spatrick if (NoFinals)
1144e5dd7070Spatrick AlreadyEmittedVars.insert(D);
1145e5dd7070Spatrick else
1146e5dd7070Spatrick LoopCountersAndUpdates[D] = F;
1147e5dd7070Spatrick ++IC;
1148e5dd7070Spatrick }
1149e5dd7070Spatrick }
1150e5dd7070Spatrick for (const auto *C : D.getClausesOfKind<OMPLastprivateClause>()) {
1151e5dd7070Spatrick auto IRef = C->varlist_begin();
1152e5dd7070Spatrick auto ISrcRef = C->source_exprs().begin();
1153e5dd7070Spatrick auto IDestRef = C->destination_exprs().begin();
1154e5dd7070Spatrick for (const Expr *AssignOp : C->assignment_ops()) {
1155e5dd7070Spatrick const auto *PrivateVD =
1156e5dd7070Spatrick cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
1157e5dd7070Spatrick QualType Type = PrivateVD->getType();
1158e5dd7070Spatrick const auto *CanonicalVD = PrivateVD->getCanonicalDecl();
1159e5dd7070Spatrick if (AlreadyEmittedVars.insert(CanonicalVD).second) {
1160e5dd7070Spatrick // If lastprivate variable is a loop control variable for loop-based
1161e5dd7070Spatrick // directive, update its value before copyin back to original
1162e5dd7070Spatrick // variable.
1163e5dd7070Spatrick if (const Expr *FinalExpr = LoopCountersAndUpdates.lookup(CanonicalVD))
1164e5dd7070Spatrick EmitIgnoredExpr(FinalExpr);
1165e5dd7070Spatrick const auto *SrcVD =
1166e5dd7070Spatrick cast<VarDecl>(cast<DeclRefExpr>(*ISrcRef)->getDecl());
1167e5dd7070Spatrick const auto *DestVD =
1168e5dd7070Spatrick cast<VarDecl>(cast<DeclRefExpr>(*IDestRef)->getDecl());
1169e5dd7070Spatrick // Get the address of the private variable.
1170e5dd7070Spatrick Address PrivateAddr = GetAddrOfLocalVar(PrivateVD);
1171e5dd7070Spatrick if (const auto *RefTy = PrivateVD->getType()->getAs<ReferenceType>())
1172*12c85518Srobert PrivateAddr = Address(
1173*12c85518Srobert Builder.CreateLoad(PrivateAddr),
1174*12c85518Srobert CGM.getTypes().ConvertTypeForMem(RefTy->getPointeeType()),
1175ec727ea7Spatrick CGM.getNaturalTypeAlignment(RefTy->getPointeeType()));
1176e5dd7070Spatrick // Store the last value to the private copy in the last iteration.
1177e5dd7070Spatrick if (C->getKind() == OMPC_LASTPRIVATE_conditional)
1178e5dd7070Spatrick CGM.getOpenMPRuntime().emitLastprivateConditionalFinalUpdate(
1179e5dd7070Spatrick *this, MakeAddrLValue(PrivateAddr, (*IRef)->getType()), PrivateVD,
1180e5dd7070Spatrick (*IRef)->getExprLoc());
1181e5dd7070Spatrick // Get the address of the original variable.
1182e5dd7070Spatrick Address OriginalAddr = GetAddrOfLocalVar(DestVD);
1183e5dd7070Spatrick EmitOMPCopy(Type, OriginalAddr, PrivateAddr, DestVD, SrcVD, AssignOp);
1184e5dd7070Spatrick }
1185e5dd7070Spatrick ++IRef;
1186e5dd7070Spatrick ++ISrcRef;
1187e5dd7070Spatrick ++IDestRef;
1188e5dd7070Spatrick }
1189e5dd7070Spatrick if (const Expr *PostUpdate = C->getPostUpdateExpr())
1190e5dd7070Spatrick EmitIgnoredExpr(PostUpdate);
1191e5dd7070Spatrick }
1192e5dd7070Spatrick if (IsLastIterCond)
1193e5dd7070Spatrick EmitBlock(DoneBB, /*IsFinished=*/true);
1194e5dd7070Spatrick }
1195e5dd7070Spatrick
EmitOMPReductionClauseInit(const OMPExecutableDirective & D,CodeGenFunction::OMPPrivateScope & PrivateScope,bool ForInscan)1196e5dd7070Spatrick void CodeGenFunction::EmitOMPReductionClauseInit(
1197e5dd7070Spatrick const OMPExecutableDirective &D,
1198ec727ea7Spatrick CodeGenFunction::OMPPrivateScope &PrivateScope, bool ForInscan) {
1199e5dd7070Spatrick if (!HaveInsertPoint())
1200e5dd7070Spatrick return;
1201e5dd7070Spatrick SmallVector<const Expr *, 4> Shareds;
1202e5dd7070Spatrick SmallVector<const Expr *, 4> Privates;
1203e5dd7070Spatrick SmallVector<const Expr *, 4> ReductionOps;
1204e5dd7070Spatrick SmallVector<const Expr *, 4> LHSs;
1205e5dd7070Spatrick SmallVector<const Expr *, 4> RHSs;
1206ec727ea7Spatrick OMPTaskDataTy Data;
1207ec727ea7Spatrick SmallVector<const Expr *, 4> TaskLHSs;
1208ec727ea7Spatrick SmallVector<const Expr *, 4> TaskRHSs;
1209e5dd7070Spatrick for (const auto *C : D.getClausesOfKind<OMPReductionClause>()) {
1210ec727ea7Spatrick if (ForInscan != (C->getModifier() == OMPC_REDUCTION_inscan))
1211ec727ea7Spatrick continue;
1212ec727ea7Spatrick Shareds.append(C->varlist_begin(), C->varlist_end());
1213ec727ea7Spatrick Privates.append(C->privates().begin(), C->privates().end());
1214ec727ea7Spatrick ReductionOps.append(C->reduction_ops().begin(), C->reduction_ops().end());
1215ec727ea7Spatrick LHSs.append(C->lhs_exprs().begin(), C->lhs_exprs().end());
1216ec727ea7Spatrick RHSs.append(C->rhs_exprs().begin(), C->rhs_exprs().end());
1217ec727ea7Spatrick if (C->getModifier() == OMPC_REDUCTION_task) {
1218ec727ea7Spatrick Data.ReductionVars.append(C->privates().begin(), C->privates().end());
1219ec727ea7Spatrick Data.ReductionOrigs.append(C->varlist_begin(), C->varlist_end());
1220ec727ea7Spatrick Data.ReductionCopies.append(C->privates().begin(), C->privates().end());
1221ec727ea7Spatrick Data.ReductionOps.append(C->reduction_ops().begin(),
1222ec727ea7Spatrick C->reduction_ops().end());
1223ec727ea7Spatrick TaskLHSs.append(C->lhs_exprs().begin(), C->lhs_exprs().end());
1224ec727ea7Spatrick TaskRHSs.append(C->rhs_exprs().begin(), C->rhs_exprs().end());
1225e5dd7070Spatrick }
1226e5dd7070Spatrick }
1227ec727ea7Spatrick ReductionCodeGen RedCG(Shareds, Shareds, Privates, ReductionOps);
1228e5dd7070Spatrick unsigned Count = 0;
1229ec727ea7Spatrick auto *ILHS = LHSs.begin();
1230ec727ea7Spatrick auto *IRHS = RHSs.begin();
1231ec727ea7Spatrick auto *IPriv = Privates.begin();
1232e5dd7070Spatrick for (const Expr *IRef : Shareds) {
1233e5dd7070Spatrick const auto *PrivateVD = cast<VarDecl>(cast<DeclRefExpr>(*IPriv)->getDecl());
1234e5dd7070Spatrick // Emit private VarDecl with reduction init.
1235ec727ea7Spatrick RedCG.emitSharedOrigLValue(*this, Count);
1236e5dd7070Spatrick RedCG.emitAggregateType(*this, Count);
1237e5dd7070Spatrick AutoVarEmission Emission = EmitAutoVarAlloca(*PrivateVD);
1238e5dd7070Spatrick RedCG.emitInitialization(*this, Count, Emission.getAllocatedAddress(),
1239*12c85518Srobert RedCG.getSharedLValue(Count).getAddress(*this),
1240e5dd7070Spatrick [&Emission](CodeGenFunction &CGF) {
1241e5dd7070Spatrick CGF.EmitAutoVarInit(Emission);
1242e5dd7070Spatrick return true;
1243e5dd7070Spatrick });
1244e5dd7070Spatrick EmitAutoVarCleanups(Emission);
1245e5dd7070Spatrick Address BaseAddr = RedCG.adjustPrivateAddress(
1246e5dd7070Spatrick *this, Count, Emission.getAllocatedAddress());
1247*12c85518Srobert bool IsRegistered =
1248*12c85518Srobert PrivateScope.addPrivate(RedCG.getBaseDecl(Count), BaseAddr);
1249e5dd7070Spatrick assert(IsRegistered && "private var already registered as private");
1250e5dd7070Spatrick // Silence the warning about unused variable.
1251e5dd7070Spatrick (void)IsRegistered;
1252e5dd7070Spatrick
1253e5dd7070Spatrick const auto *LHSVD = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
1254e5dd7070Spatrick const auto *RHSVD = cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
1255e5dd7070Spatrick QualType Type = PrivateVD->getType();
1256e5dd7070Spatrick bool isaOMPArraySectionExpr = isa<OMPArraySectionExpr>(IRef);
1257e5dd7070Spatrick if (isaOMPArraySectionExpr && Type->isVariablyModifiedType()) {
1258e5dd7070Spatrick // Store the address of the original variable associated with the LHS
1259e5dd7070Spatrick // implicit variable.
1260*12c85518Srobert PrivateScope.addPrivate(LHSVD,
1261*12c85518Srobert RedCG.getSharedLValue(Count).getAddress(*this));
1262*12c85518Srobert PrivateScope.addPrivate(RHSVD, GetAddrOfLocalVar(PrivateVD));
1263e5dd7070Spatrick } else if ((isaOMPArraySectionExpr && Type->isScalarType()) ||
1264e5dd7070Spatrick isa<ArraySubscriptExpr>(IRef)) {
1265e5dd7070Spatrick // Store the address of the original variable associated with the LHS
1266e5dd7070Spatrick // implicit variable.
1267*12c85518Srobert PrivateScope.addPrivate(LHSVD,
1268*12c85518Srobert RedCG.getSharedLValue(Count).getAddress(*this));
1269*12c85518Srobert PrivateScope.addPrivate(RHSVD, Builder.CreateElementBitCast(
1270*12c85518Srobert GetAddrOfLocalVar(PrivateVD),
1271e5dd7070Spatrick ConvertTypeForMem(RHSVD->getType()),
1272*12c85518Srobert "rhs.begin"));
1273e5dd7070Spatrick } else {
1274e5dd7070Spatrick QualType Type = PrivateVD->getType();
1275e5dd7070Spatrick bool IsArray = getContext().getAsArrayType(Type) != nullptr;
1276e5dd7070Spatrick Address OriginalAddr = RedCG.getSharedLValue(Count).getAddress(*this);
1277e5dd7070Spatrick // Store the address of the original variable associated with the LHS
1278e5dd7070Spatrick // implicit variable.
1279e5dd7070Spatrick if (IsArray) {
1280e5dd7070Spatrick OriginalAddr = Builder.CreateElementBitCast(
1281e5dd7070Spatrick OriginalAddr, ConvertTypeForMem(LHSVD->getType()), "lhs.begin");
1282e5dd7070Spatrick }
1283*12c85518Srobert PrivateScope.addPrivate(LHSVD, OriginalAddr);
1284e5dd7070Spatrick PrivateScope.addPrivate(
1285*12c85518Srobert RHSVD, IsArray ? Builder.CreateElementBitCast(
1286e5dd7070Spatrick GetAddrOfLocalVar(PrivateVD),
1287e5dd7070Spatrick ConvertTypeForMem(RHSVD->getType()), "rhs.begin")
1288*12c85518Srobert : GetAddrOfLocalVar(PrivateVD));
1289e5dd7070Spatrick }
1290e5dd7070Spatrick ++ILHS;
1291e5dd7070Spatrick ++IRHS;
1292e5dd7070Spatrick ++IPriv;
1293e5dd7070Spatrick ++Count;
1294e5dd7070Spatrick }
1295ec727ea7Spatrick if (!Data.ReductionVars.empty()) {
1296ec727ea7Spatrick Data.IsReductionWithTaskMod = true;
1297ec727ea7Spatrick Data.IsWorksharingReduction =
1298ec727ea7Spatrick isOpenMPWorksharingDirective(D.getDirectiveKind());
1299ec727ea7Spatrick llvm::Value *ReductionDesc = CGM.getOpenMPRuntime().emitTaskReductionInit(
1300ec727ea7Spatrick *this, D.getBeginLoc(), TaskLHSs, TaskRHSs, Data);
1301ec727ea7Spatrick const Expr *TaskRedRef = nullptr;
1302ec727ea7Spatrick switch (D.getDirectiveKind()) {
1303ec727ea7Spatrick case OMPD_parallel:
1304ec727ea7Spatrick TaskRedRef = cast<OMPParallelDirective>(D).getTaskReductionRefExpr();
1305ec727ea7Spatrick break;
1306ec727ea7Spatrick case OMPD_for:
1307ec727ea7Spatrick TaskRedRef = cast<OMPForDirective>(D).getTaskReductionRefExpr();
1308ec727ea7Spatrick break;
1309ec727ea7Spatrick case OMPD_sections:
1310ec727ea7Spatrick TaskRedRef = cast<OMPSectionsDirective>(D).getTaskReductionRefExpr();
1311ec727ea7Spatrick break;
1312ec727ea7Spatrick case OMPD_parallel_for:
1313ec727ea7Spatrick TaskRedRef = cast<OMPParallelForDirective>(D).getTaskReductionRefExpr();
1314ec727ea7Spatrick break;
1315ec727ea7Spatrick case OMPD_parallel_master:
1316ec727ea7Spatrick TaskRedRef =
1317ec727ea7Spatrick cast<OMPParallelMasterDirective>(D).getTaskReductionRefExpr();
1318ec727ea7Spatrick break;
1319ec727ea7Spatrick case OMPD_parallel_sections:
1320ec727ea7Spatrick TaskRedRef =
1321ec727ea7Spatrick cast<OMPParallelSectionsDirective>(D).getTaskReductionRefExpr();
1322ec727ea7Spatrick break;
1323ec727ea7Spatrick case OMPD_target_parallel:
1324ec727ea7Spatrick TaskRedRef =
1325ec727ea7Spatrick cast<OMPTargetParallelDirective>(D).getTaskReductionRefExpr();
1326ec727ea7Spatrick break;
1327ec727ea7Spatrick case OMPD_target_parallel_for:
1328ec727ea7Spatrick TaskRedRef =
1329ec727ea7Spatrick cast<OMPTargetParallelForDirective>(D).getTaskReductionRefExpr();
1330ec727ea7Spatrick break;
1331ec727ea7Spatrick case OMPD_distribute_parallel_for:
1332ec727ea7Spatrick TaskRedRef =
1333ec727ea7Spatrick cast<OMPDistributeParallelForDirective>(D).getTaskReductionRefExpr();
1334ec727ea7Spatrick break;
1335ec727ea7Spatrick case OMPD_teams_distribute_parallel_for:
1336ec727ea7Spatrick TaskRedRef = cast<OMPTeamsDistributeParallelForDirective>(D)
1337ec727ea7Spatrick .getTaskReductionRefExpr();
1338ec727ea7Spatrick break;
1339ec727ea7Spatrick case OMPD_target_teams_distribute_parallel_for:
1340ec727ea7Spatrick TaskRedRef = cast<OMPTargetTeamsDistributeParallelForDirective>(D)
1341ec727ea7Spatrick .getTaskReductionRefExpr();
1342ec727ea7Spatrick break;
1343ec727ea7Spatrick case OMPD_simd:
1344ec727ea7Spatrick case OMPD_for_simd:
1345ec727ea7Spatrick case OMPD_section:
1346ec727ea7Spatrick case OMPD_single:
1347ec727ea7Spatrick case OMPD_master:
1348ec727ea7Spatrick case OMPD_critical:
1349ec727ea7Spatrick case OMPD_parallel_for_simd:
1350ec727ea7Spatrick case OMPD_task:
1351ec727ea7Spatrick case OMPD_taskyield:
1352*12c85518Srobert case OMPD_error:
1353ec727ea7Spatrick case OMPD_barrier:
1354ec727ea7Spatrick case OMPD_taskwait:
1355ec727ea7Spatrick case OMPD_taskgroup:
1356ec727ea7Spatrick case OMPD_flush:
1357ec727ea7Spatrick case OMPD_depobj:
1358ec727ea7Spatrick case OMPD_scan:
1359ec727ea7Spatrick case OMPD_ordered:
1360ec727ea7Spatrick case OMPD_atomic:
1361ec727ea7Spatrick case OMPD_teams:
1362ec727ea7Spatrick case OMPD_target:
1363ec727ea7Spatrick case OMPD_cancellation_point:
1364ec727ea7Spatrick case OMPD_cancel:
1365ec727ea7Spatrick case OMPD_target_data:
1366ec727ea7Spatrick case OMPD_target_enter_data:
1367ec727ea7Spatrick case OMPD_target_exit_data:
1368ec727ea7Spatrick case OMPD_taskloop:
1369ec727ea7Spatrick case OMPD_taskloop_simd:
1370ec727ea7Spatrick case OMPD_master_taskloop:
1371ec727ea7Spatrick case OMPD_master_taskloop_simd:
1372ec727ea7Spatrick case OMPD_parallel_master_taskloop:
1373ec727ea7Spatrick case OMPD_parallel_master_taskloop_simd:
1374ec727ea7Spatrick case OMPD_distribute:
1375ec727ea7Spatrick case OMPD_target_update:
1376ec727ea7Spatrick case OMPD_distribute_parallel_for_simd:
1377ec727ea7Spatrick case OMPD_distribute_simd:
1378ec727ea7Spatrick case OMPD_target_parallel_for_simd:
1379ec727ea7Spatrick case OMPD_target_simd:
1380ec727ea7Spatrick case OMPD_teams_distribute:
1381ec727ea7Spatrick case OMPD_teams_distribute_simd:
1382ec727ea7Spatrick case OMPD_teams_distribute_parallel_for_simd:
1383ec727ea7Spatrick case OMPD_target_teams:
1384ec727ea7Spatrick case OMPD_target_teams_distribute:
1385ec727ea7Spatrick case OMPD_target_teams_distribute_parallel_for_simd:
1386ec727ea7Spatrick case OMPD_target_teams_distribute_simd:
1387ec727ea7Spatrick case OMPD_declare_target:
1388ec727ea7Spatrick case OMPD_end_declare_target:
1389ec727ea7Spatrick case OMPD_threadprivate:
1390ec727ea7Spatrick case OMPD_allocate:
1391ec727ea7Spatrick case OMPD_declare_reduction:
1392ec727ea7Spatrick case OMPD_declare_mapper:
1393ec727ea7Spatrick case OMPD_declare_simd:
1394ec727ea7Spatrick case OMPD_requires:
1395ec727ea7Spatrick case OMPD_declare_variant:
1396ec727ea7Spatrick case OMPD_begin_declare_variant:
1397ec727ea7Spatrick case OMPD_end_declare_variant:
1398ec727ea7Spatrick case OMPD_unknown:
1399ec727ea7Spatrick default:
1400ec727ea7Spatrick llvm_unreachable("Enexpected directive with task reductions.");
1401ec727ea7Spatrick }
1402ec727ea7Spatrick
1403ec727ea7Spatrick const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(TaskRedRef)->getDecl());
1404ec727ea7Spatrick EmitVarDecl(*VD);
1405ec727ea7Spatrick EmitStoreOfScalar(ReductionDesc, GetAddrOfLocalVar(VD),
1406ec727ea7Spatrick /*Volatile=*/false, TaskRedRef->getType());
1407ec727ea7Spatrick }
1408e5dd7070Spatrick }
1409e5dd7070Spatrick
EmitOMPReductionClauseFinal(const OMPExecutableDirective & D,const OpenMPDirectiveKind ReductionKind)1410e5dd7070Spatrick void CodeGenFunction::EmitOMPReductionClauseFinal(
1411e5dd7070Spatrick const OMPExecutableDirective &D, const OpenMPDirectiveKind ReductionKind) {
1412e5dd7070Spatrick if (!HaveInsertPoint())
1413e5dd7070Spatrick return;
1414e5dd7070Spatrick llvm::SmallVector<const Expr *, 8> Privates;
1415e5dd7070Spatrick llvm::SmallVector<const Expr *, 8> LHSExprs;
1416e5dd7070Spatrick llvm::SmallVector<const Expr *, 8> RHSExprs;
1417e5dd7070Spatrick llvm::SmallVector<const Expr *, 8> ReductionOps;
1418e5dd7070Spatrick bool HasAtLeastOneReduction = false;
1419ec727ea7Spatrick bool IsReductionWithTaskMod = false;
1420e5dd7070Spatrick for (const auto *C : D.getClausesOfKind<OMPReductionClause>()) {
1421ec727ea7Spatrick // Do not emit for inscan reductions.
1422ec727ea7Spatrick if (C->getModifier() == OMPC_REDUCTION_inscan)
1423ec727ea7Spatrick continue;
1424e5dd7070Spatrick HasAtLeastOneReduction = true;
1425e5dd7070Spatrick Privates.append(C->privates().begin(), C->privates().end());
1426e5dd7070Spatrick LHSExprs.append(C->lhs_exprs().begin(), C->lhs_exprs().end());
1427e5dd7070Spatrick RHSExprs.append(C->rhs_exprs().begin(), C->rhs_exprs().end());
1428e5dd7070Spatrick ReductionOps.append(C->reduction_ops().begin(), C->reduction_ops().end());
1429ec727ea7Spatrick IsReductionWithTaskMod =
1430ec727ea7Spatrick IsReductionWithTaskMod || C->getModifier() == OMPC_REDUCTION_task;
1431e5dd7070Spatrick }
1432e5dd7070Spatrick if (HasAtLeastOneReduction) {
1433ec727ea7Spatrick if (IsReductionWithTaskMod) {
1434ec727ea7Spatrick CGM.getOpenMPRuntime().emitTaskReductionFini(
1435ec727ea7Spatrick *this, D.getBeginLoc(),
1436ec727ea7Spatrick isOpenMPWorksharingDirective(D.getDirectiveKind()));
1437ec727ea7Spatrick }
1438e5dd7070Spatrick bool WithNowait = D.getSingleClause<OMPNowaitClause>() ||
1439e5dd7070Spatrick isOpenMPParallelDirective(D.getDirectiveKind()) ||
1440e5dd7070Spatrick ReductionKind == OMPD_simd;
1441e5dd7070Spatrick bool SimpleReduction = ReductionKind == OMPD_simd;
1442e5dd7070Spatrick // Emit nowait reduction if nowait clause is present or directive is a
1443e5dd7070Spatrick // parallel directive (it always has implicit barrier).
1444e5dd7070Spatrick CGM.getOpenMPRuntime().emitReduction(
1445e5dd7070Spatrick *this, D.getEndLoc(), Privates, LHSExprs, RHSExprs, ReductionOps,
1446e5dd7070Spatrick {WithNowait, SimpleReduction, ReductionKind});
1447e5dd7070Spatrick }
1448e5dd7070Spatrick }
1449e5dd7070Spatrick
emitPostUpdateForReductionClause(CodeGenFunction & CGF,const OMPExecutableDirective & D,const llvm::function_ref<llvm::Value * (CodeGenFunction &)> CondGen)1450e5dd7070Spatrick static void emitPostUpdateForReductionClause(
1451e5dd7070Spatrick CodeGenFunction &CGF, const OMPExecutableDirective &D,
1452e5dd7070Spatrick const llvm::function_ref<llvm::Value *(CodeGenFunction &)> CondGen) {
1453e5dd7070Spatrick if (!CGF.HaveInsertPoint())
1454e5dd7070Spatrick return;
1455e5dd7070Spatrick llvm::BasicBlock *DoneBB = nullptr;
1456e5dd7070Spatrick for (const auto *C : D.getClausesOfKind<OMPReductionClause>()) {
1457e5dd7070Spatrick if (const Expr *PostUpdate = C->getPostUpdateExpr()) {
1458e5dd7070Spatrick if (!DoneBB) {
1459e5dd7070Spatrick if (llvm::Value *Cond = CondGen(CGF)) {
1460e5dd7070Spatrick // If the first post-update expression is found, emit conditional
1461e5dd7070Spatrick // block if it was requested.
1462e5dd7070Spatrick llvm::BasicBlock *ThenBB = CGF.createBasicBlock(".omp.reduction.pu");
1463e5dd7070Spatrick DoneBB = CGF.createBasicBlock(".omp.reduction.pu.done");
1464e5dd7070Spatrick CGF.Builder.CreateCondBr(Cond, ThenBB, DoneBB);
1465e5dd7070Spatrick CGF.EmitBlock(ThenBB);
1466e5dd7070Spatrick }
1467e5dd7070Spatrick }
1468e5dd7070Spatrick CGF.EmitIgnoredExpr(PostUpdate);
1469e5dd7070Spatrick }
1470e5dd7070Spatrick }
1471e5dd7070Spatrick if (DoneBB)
1472e5dd7070Spatrick CGF.EmitBlock(DoneBB, /*IsFinished=*/true);
1473e5dd7070Spatrick }
1474e5dd7070Spatrick
1475e5dd7070Spatrick namespace {
1476e5dd7070Spatrick /// Codegen lambda for appending distribute lower and upper bounds to outlined
1477e5dd7070Spatrick /// parallel function. This is necessary for combined constructs such as
1478e5dd7070Spatrick /// 'distribute parallel for'
1479e5dd7070Spatrick typedef llvm::function_ref<void(CodeGenFunction &,
1480e5dd7070Spatrick const OMPExecutableDirective &,
1481e5dd7070Spatrick llvm::SmallVectorImpl<llvm::Value *> &)>
1482e5dd7070Spatrick CodeGenBoundParametersTy;
1483e5dd7070Spatrick } // anonymous namespace
1484e5dd7070Spatrick
1485ec727ea7Spatrick static void
checkForLastprivateConditionalUpdate(CodeGenFunction & CGF,const OMPExecutableDirective & S)1486ec727ea7Spatrick checkForLastprivateConditionalUpdate(CodeGenFunction &CGF,
1487ec727ea7Spatrick const OMPExecutableDirective &S) {
1488ec727ea7Spatrick if (CGF.getLangOpts().OpenMP < 50)
1489ec727ea7Spatrick return;
1490ec727ea7Spatrick llvm::DenseSet<CanonicalDeclPtr<const VarDecl>> PrivateDecls;
1491ec727ea7Spatrick for (const auto *C : S.getClausesOfKind<OMPReductionClause>()) {
1492ec727ea7Spatrick for (const Expr *Ref : C->varlists()) {
1493ec727ea7Spatrick if (!Ref->getType()->isScalarType())
1494ec727ea7Spatrick continue;
1495ec727ea7Spatrick const auto *DRE = dyn_cast<DeclRefExpr>(Ref->IgnoreParenImpCasts());
1496ec727ea7Spatrick if (!DRE)
1497ec727ea7Spatrick continue;
1498ec727ea7Spatrick PrivateDecls.insert(cast<VarDecl>(DRE->getDecl()));
1499ec727ea7Spatrick CGF.CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(CGF, Ref);
1500ec727ea7Spatrick }
1501ec727ea7Spatrick }
1502ec727ea7Spatrick for (const auto *C : S.getClausesOfKind<OMPLastprivateClause>()) {
1503ec727ea7Spatrick for (const Expr *Ref : C->varlists()) {
1504ec727ea7Spatrick if (!Ref->getType()->isScalarType())
1505ec727ea7Spatrick continue;
1506ec727ea7Spatrick const auto *DRE = dyn_cast<DeclRefExpr>(Ref->IgnoreParenImpCasts());
1507ec727ea7Spatrick if (!DRE)
1508ec727ea7Spatrick continue;
1509ec727ea7Spatrick PrivateDecls.insert(cast<VarDecl>(DRE->getDecl()));
1510ec727ea7Spatrick CGF.CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(CGF, Ref);
1511ec727ea7Spatrick }
1512ec727ea7Spatrick }
1513ec727ea7Spatrick for (const auto *C : S.getClausesOfKind<OMPLinearClause>()) {
1514ec727ea7Spatrick for (const Expr *Ref : C->varlists()) {
1515ec727ea7Spatrick if (!Ref->getType()->isScalarType())
1516ec727ea7Spatrick continue;
1517ec727ea7Spatrick const auto *DRE = dyn_cast<DeclRefExpr>(Ref->IgnoreParenImpCasts());
1518ec727ea7Spatrick if (!DRE)
1519ec727ea7Spatrick continue;
1520ec727ea7Spatrick PrivateDecls.insert(cast<VarDecl>(DRE->getDecl()));
1521ec727ea7Spatrick CGF.CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(CGF, Ref);
1522ec727ea7Spatrick }
1523ec727ea7Spatrick }
1524ec727ea7Spatrick // Privates should ne analyzed since they are not captured at all.
1525ec727ea7Spatrick // Task reductions may be skipped - tasks are ignored.
1526ec727ea7Spatrick // Firstprivates do not return value but may be passed by reference - no need
1527ec727ea7Spatrick // to check for updated lastprivate conditional.
1528ec727ea7Spatrick for (const auto *C : S.getClausesOfKind<OMPFirstprivateClause>()) {
1529ec727ea7Spatrick for (const Expr *Ref : C->varlists()) {
1530ec727ea7Spatrick if (!Ref->getType()->isScalarType())
1531ec727ea7Spatrick continue;
1532ec727ea7Spatrick const auto *DRE = dyn_cast<DeclRefExpr>(Ref->IgnoreParenImpCasts());
1533ec727ea7Spatrick if (!DRE)
1534ec727ea7Spatrick continue;
1535ec727ea7Spatrick PrivateDecls.insert(cast<VarDecl>(DRE->getDecl()));
1536ec727ea7Spatrick }
1537ec727ea7Spatrick }
1538ec727ea7Spatrick CGF.CGM.getOpenMPRuntime().checkAndEmitSharedLastprivateConditional(
1539ec727ea7Spatrick CGF, S, PrivateDecls);
1540ec727ea7Spatrick }
1541ec727ea7Spatrick
emitCommonOMPParallelDirective(CodeGenFunction & CGF,const OMPExecutableDirective & S,OpenMPDirectiveKind InnermostKind,const RegionCodeGenTy & CodeGen,const CodeGenBoundParametersTy & CodeGenBoundParameters)1542e5dd7070Spatrick static void emitCommonOMPParallelDirective(
1543e5dd7070Spatrick CodeGenFunction &CGF, const OMPExecutableDirective &S,
1544e5dd7070Spatrick OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen,
1545e5dd7070Spatrick const CodeGenBoundParametersTy &CodeGenBoundParameters) {
1546e5dd7070Spatrick const CapturedStmt *CS = S.getCapturedStmt(OMPD_parallel);
1547*12c85518Srobert llvm::Value *NumThreads = nullptr;
1548e5dd7070Spatrick llvm::Function *OutlinedFn =
1549e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitParallelOutlinedFunction(
1550e5dd7070Spatrick S, *CS->getCapturedDecl()->param_begin(), InnermostKind, CodeGen);
1551e5dd7070Spatrick if (const auto *NumThreadsClause = S.getSingleClause<OMPNumThreadsClause>()) {
1552e5dd7070Spatrick CodeGenFunction::RunCleanupsScope NumThreadsScope(CGF);
1553*12c85518Srobert NumThreads = CGF.EmitScalarExpr(NumThreadsClause->getNumThreads(),
1554e5dd7070Spatrick /*IgnoreResultAssign=*/true);
1555e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitNumThreadsClause(
1556e5dd7070Spatrick CGF, NumThreads, NumThreadsClause->getBeginLoc());
1557e5dd7070Spatrick }
1558e5dd7070Spatrick if (const auto *ProcBindClause = S.getSingleClause<OMPProcBindClause>()) {
1559e5dd7070Spatrick CodeGenFunction::RunCleanupsScope ProcBindScope(CGF);
1560e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitProcBindClause(
1561e5dd7070Spatrick CGF, ProcBindClause->getProcBindKind(), ProcBindClause->getBeginLoc());
1562e5dd7070Spatrick }
1563e5dd7070Spatrick const Expr *IfCond = nullptr;
1564e5dd7070Spatrick for (const auto *C : S.getClausesOfKind<OMPIfClause>()) {
1565e5dd7070Spatrick if (C->getNameModifier() == OMPD_unknown ||
1566e5dd7070Spatrick C->getNameModifier() == OMPD_parallel) {
1567e5dd7070Spatrick IfCond = C->getCondition();
1568e5dd7070Spatrick break;
1569e5dd7070Spatrick }
1570e5dd7070Spatrick }
1571e5dd7070Spatrick
1572e5dd7070Spatrick OMPParallelScope Scope(CGF, S);
1573e5dd7070Spatrick llvm::SmallVector<llvm::Value *, 16> CapturedVars;
1574e5dd7070Spatrick // Combining 'distribute' with 'for' requires sharing each 'distribute' chunk
1575e5dd7070Spatrick // lower and upper bounds with the pragma 'for' chunking mechanism.
1576e5dd7070Spatrick // The following lambda takes care of appending the lower and upper bound
1577e5dd7070Spatrick // parameters when necessary
1578e5dd7070Spatrick CodeGenBoundParameters(CGF, S, CapturedVars);
1579e5dd7070Spatrick CGF.GenerateOpenMPCapturedVars(*CS, CapturedVars);
1580e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitParallelCall(CGF, S.getBeginLoc(), OutlinedFn,
1581*12c85518Srobert CapturedVars, IfCond, NumThreads);
1582e5dd7070Spatrick }
1583e5dd7070Spatrick
isAllocatableDecl(const VarDecl * VD)1584a9ac8606Spatrick static bool isAllocatableDecl(const VarDecl *VD) {
1585a9ac8606Spatrick const VarDecl *CVD = VD->getCanonicalDecl();
1586a9ac8606Spatrick if (!CVD->hasAttr<OMPAllocateDeclAttr>())
1587a9ac8606Spatrick return false;
1588a9ac8606Spatrick const auto *AA = CVD->getAttr<OMPAllocateDeclAttr>();
1589a9ac8606Spatrick // Use the default allocation.
1590a9ac8606Spatrick return !((AA->getAllocatorType() == OMPAllocateDeclAttr::OMPDefaultMemAlloc ||
1591a9ac8606Spatrick AA->getAllocatorType() == OMPAllocateDeclAttr::OMPNullMemAlloc) &&
1592a9ac8606Spatrick !AA->getAllocator());
1593a9ac8606Spatrick }
1594a9ac8606Spatrick
emitEmptyBoundParameters(CodeGenFunction &,const OMPExecutableDirective &,llvm::SmallVectorImpl<llvm::Value * > &)1595e5dd7070Spatrick static void emitEmptyBoundParameters(CodeGenFunction &,
1596e5dd7070Spatrick const OMPExecutableDirective &,
1597e5dd7070Spatrick llvm::SmallVectorImpl<llvm::Value *> &) {}
1598e5dd7070Spatrick
emitOMPCopyinClause(CodeGenFunction & CGF,const OMPExecutableDirective & S)1599*12c85518Srobert static void emitOMPCopyinClause(CodeGenFunction &CGF,
1600*12c85518Srobert const OMPExecutableDirective &S) {
1601*12c85518Srobert bool Copyins = CGF.EmitOMPCopyinClause(S);
1602*12c85518Srobert if (Copyins) {
1603*12c85518Srobert // Emit implicit barrier to synchronize threads and avoid data races on
1604*12c85518Srobert // propagation master's thread values of threadprivate variables to local
1605*12c85518Srobert // instances of that variables of all other implicit threads.
1606*12c85518Srobert CGF.CGM.getOpenMPRuntime().emitBarrierCall(
1607*12c85518Srobert CGF, S.getBeginLoc(), OMPD_unknown, /*EmitChecks=*/false,
1608*12c85518Srobert /*ForceSimpleCall=*/true);
1609*12c85518Srobert }
1610*12c85518Srobert }
1611*12c85518Srobert
getAddressOfLocalVariable(CodeGenFunction & CGF,const VarDecl * VD)1612ec727ea7Spatrick Address CodeGenFunction::OMPBuilderCBHelpers::getAddressOfLocalVariable(
1613ec727ea7Spatrick CodeGenFunction &CGF, const VarDecl *VD) {
1614ec727ea7Spatrick CodeGenModule &CGM = CGF.CGM;
1615ec727ea7Spatrick auto &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
1616e5dd7070Spatrick
1617ec727ea7Spatrick if (!VD)
1618ec727ea7Spatrick return Address::invalid();
1619ec727ea7Spatrick const VarDecl *CVD = VD->getCanonicalDecl();
1620a9ac8606Spatrick if (!isAllocatableDecl(CVD))
1621ec727ea7Spatrick return Address::invalid();
1622ec727ea7Spatrick llvm::Value *Size;
1623ec727ea7Spatrick CharUnits Align = CGM.getContext().getDeclAlign(CVD);
1624ec727ea7Spatrick if (CVD->getType()->isVariablyModifiedType()) {
1625ec727ea7Spatrick Size = CGF.getTypeSize(CVD->getType());
1626ec727ea7Spatrick // Align the size: ((size + align - 1) / align) * align
1627ec727ea7Spatrick Size = CGF.Builder.CreateNUWAdd(
1628ec727ea7Spatrick Size, CGM.getSize(Align - CharUnits::fromQuantity(1)));
1629ec727ea7Spatrick Size = CGF.Builder.CreateUDiv(Size, CGM.getSize(Align));
1630ec727ea7Spatrick Size = CGF.Builder.CreateNUWMul(Size, CGM.getSize(Align));
1631ec727ea7Spatrick } else {
1632ec727ea7Spatrick CharUnits Sz = CGM.getContext().getTypeSizeInChars(CVD->getType());
1633ec727ea7Spatrick Size = CGM.getSize(Sz.alignTo(Align));
1634ec727ea7Spatrick }
1635ec727ea7Spatrick
1636a9ac8606Spatrick const auto *AA = CVD->getAttr<OMPAllocateDeclAttr>();
1637ec727ea7Spatrick assert(AA->getAllocator() &&
1638ec727ea7Spatrick "Expected allocator expression for non-default allocator.");
1639ec727ea7Spatrick llvm::Value *Allocator = CGF.EmitScalarExpr(AA->getAllocator());
1640ec727ea7Spatrick // According to the standard, the original allocator type is a enum (integer).
1641ec727ea7Spatrick // Convert to pointer type, if required.
1642ec727ea7Spatrick if (Allocator->getType()->isIntegerTy())
1643ec727ea7Spatrick Allocator = CGF.Builder.CreateIntToPtr(Allocator, CGM.VoidPtrTy);
1644ec727ea7Spatrick else if (Allocator->getType()->isPointerTy())
1645ec727ea7Spatrick Allocator = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(Allocator,
1646ec727ea7Spatrick CGM.VoidPtrTy);
1647ec727ea7Spatrick
1648a9ac8606Spatrick llvm::Value *Addr = OMPBuilder.createOMPAlloc(
1649ec727ea7Spatrick CGF.Builder, Size, Allocator,
1650ec727ea7Spatrick getNameWithSeparators({CVD->getName(), ".void.addr"}, ".", "."));
1651ec727ea7Spatrick llvm::CallInst *FreeCI =
1652a9ac8606Spatrick OMPBuilder.createOMPFree(CGF.Builder, Addr, Allocator);
1653ec727ea7Spatrick
1654ec727ea7Spatrick CGF.EHStack.pushCleanup<OMPAllocateCleanupTy>(NormalAndEHCleanup, FreeCI);
1655ec727ea7Spatrick Addr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
1656ec727ea7Spatrick Addr,
1657ec727ea7Spatrick CGF.ConvertTypeForMem(CGM.getContext().getPointerType(CVD->getType())),
1658ec727ea7Spatrick getNameWithSeparators({CVD->getName(), ".addr"}, ".", "."));
1659*12c85518Srobert return Address(Addr, CGF.ConvertTypeForMem(CVD->getType()), Align);
1660ec727ea7Spatrick }
1661ec727ea7Spatrick
getAddrOfThreadPrivate(CodeGenFunction & CGF,const VarDecl * VD,Address VDAddr,SourceLocation Loc)1662ec727ea7Spatrick Address CodeGenFunction::OMPBuilderCBHelpers::getAddrOfThreadPrivate(
1663ec727ea7Spatrick CodeGenFunction &CGF, const VarDecl *VD, Address VDAddr,
1664ec727ea7Spatrick SourceLocation Loc) {
1665ec727ea7Spatrick CodeGenModule &CGM = CGF.CGM;
1666ec727ea7Spatrick if (CGM.getLangOpts().OpenMPUseTLS &&
1667ec727ea7Spatrick CGM.getContext().getTargetInfo().isTLSSupported())
1668ec727ea7Spatrick return VDAddr;
1669ec727ea7Spatrick
1670ec727ea7Spatrick llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
1671ec727ea7Spatrick
1672ec727ea7Spatrick llvm::Type *VarTy = VDAddr.getElementType();
1673ec727ea7Spatrick llvm::Value *Data =
1674ec727ea7Spatrick CGF.Builder.CreatePointerCast(VDAddr.getPointer(), CGM.Int8PtrTy);
1675ec727ea7Spatrick llvm::ConstantInt *Size = CGM.getSize(CGM.GetTargetTypeStoreSize(VarTy));
1676ec727ea7Spatrick std::string Suffix = getNameWithSeparators({"cache", ""});
1677ec727ea7Spatrick llvm::Twine CacheName = Twine(CGM.getMangledName(VD)).concat(Suffix);
1678ec727ea7Spatrick
1679ec727ea7Spatrick llvm::CallInst *ThreadPrivateCacheCall =
1680a9ac8606Spatrick OMPBuilder.createCachedThreadPrivate(CGF.Builder, Data, Size, CacheName);
1681ec727ea7Spatrick
1682*12c85518Srobert return Address(ThreadPrivateCacheCall, CGM.Int8Ty, VDAddr.getAlignment());
1683ec727ea7Spatrick }
1684ec727ea7Spatrick
getNameWithSeparators(ArrayRef<StringRef> Parts,StringRef FirstSeparator,StringRef Separator)1685ec727ea7Spatrick std::string CodeGenFunction::OMPBuilderCBHelpers::getNameWithSeparators(
1686ec727ea7Spatrick ArrayRef<StringRef> Parts, StringRef FirstSeparator, StringRef Separator) {
1687ec727ea7Spatrick SmallString<128> Buffer;
1688ec727ea7Spatrick llvm::raw_svector_ostream OS(Buffer);
1689ec727ea7Spatrick StringRef Sep = FirstSeparator;
1690ec727ea7Spatrick for (StringRef Part : Parts) {
1691ec727ea7Spatrick OS << Sep << Part;
1692ec727ea7Spatrick Sep = Separator;
1693ec727ea7Spatrick }
1694ec727ea7Spatrick return OS.str().str();
1695ec727ea7Spatrick }
1696*12c85518Srobert
EmitOMPInlinedRegionBody(CodeGenFunction & CGF,const Stmt * RegionBodyStmt,InsertPointTy AllocaIP,InsertPointTy CodeGenIP,Twine RegionName)1697*12c85518Srobert void CodeGenFunction::OMPBuilderCBHelpers::EmitOMPInlinedRegionBody(
1698*12c85518Srobert CodeGenFunction &CGF, const Stmt *RegionBodyStmt, InsertPointTy AllocaIP,
1699*12c85518Srobert InsertPointTy CodeGenIP, Twine RegionName) {
1700*12c85518Srobert CGBuilderTy &Builder = CGF.Builder;
1701*12c85518Srobert Builder.restoreIP(CodeGenIP);
1702*12c85518Srobert llvm::BasicBlock *FiniBB = splitBBWithSuffix(Builder, /*CreateBranch=*/false,
1703*12c85518Srobert "." + RegionName + ".after");
1704*12c85518Srobert
1705*12c85518Srobert {
1706*12c85518Srobert OMPBuilderCBHelpers::InlinedRegionBodyRAII IRB(CGF, AllocaIP, *FiniBB);
1707*12c85518Srobert CGF.EmitStmt(RegionBodyStmt);
1708*12c85518Srobert }
1709*12c85518Srobert
1710*12c85518Srobert if (Builder.saveIP().isSet())
1711*12c85518Srobert Builder.CreateBr(FiniBB);
1712*12c85518Srobert }
1713*12c85518Srobert
EmitOMPOutlinedRegionBody(CodeGenFunction & CGF,const Stmt * RegionBodyStmt,InsertPointTy AllocaIP,InsertPointTy CodeGenIP,Twine RegionName)1714*12c85518Srobert void CodeGenFunction::OMPBuilderCBHelpers::EmitOMPOutlinedRegionBody(
1715*12c85518Srobert CodeGenFunction &CGF, const Stmt *RegionBodyStmt, InsertPointTy AllocaIP,
1716*12c85518Srobert InsertPointTy CodeGenIP, Twine RegionName) {
1717*12c85518Srobert CGBuilderTy &Builder = CGF.Builder;
1718*12c85518Srobert Builder.restoreIP(CodeGenIP);
1719*12c85518Srobert llvm::BasicBlock *FiniBB = splitBBWithSuffix(Builder, /*CreateBranch=*/false,
1720*12c85518Srobert "." + RegionName + ".after");
1721*12c85518Srobert
1722*12c85518Srobert {
1723*12c85518Srobert OMPBuilderCBHelpers::OutlinedRegionBodyRAII IRB(CGF, AllocaIP, *FiniBB);
1724*12c85518Srobert CGF.EmitStmt(RegionBodyStmt);
1725*12c85518Srobert }
1726*12c85518Srobert
1727*12c85518Srobert if (Builder.saveIP().isSet())
1728*12c85518Srobert Builder.CreateBr(FiniBB);
1729*12c85518Srobert }
1730*12c85518Srobert
EmitOMPParallelDirective(const OMPParallelDirective & S)1731ec727ea7Spatrick void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) {
1732ec727ea7Spatrick if (CGM.getLangOpts().OpenMPIRBuilder) {
1733ec727ea7Spatrick llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
1734e5dd7070Spatrick // Check if we have any if clause associated with the directive.
1735e5dd7070Spatrick llvm::Value *IfCond = nullptr;
1736e5dd7070Spatrick if (const auto *C = S.getSingleClause<OMPIfClause>())
1737e5dd7070Spatrick IfCond = EmitScalarExpr(C->getCondition(),
1738e5dd7070Spatrick /*IgnoreResultAssign=*/true);
1739e5dd7070Spatrick
1740e5dd7070Spatrick llvm::Value *NumThreads = nullptr;
1741e5dd7070Spatrick if (const auto *NumThreadsClause = S.getSingleClause<OMPNumThreadsClause>())
1742e5dd7070Spatrick NumThreads = EmitScalarExpr(NumThreadsClause->getNumThreads(),
1743e5dd7070Spatrick /*IgnoreResultAssign=*/true);
1744e5dd7070Spatrick
1745e5dd7070Spatrick ProcBindKind ProcBind = OMP_PROC_BIND_default;
1746e5dd7070Spatrick if (const auto *ProcBindClause = S.getSingleClause<OMPProcBindClause>())
1747e5dd7070Spatrick ProcBind = ProcBindClause->getProcBindKind();
1748e5dd7070Spatrick
1749e5dd7070Spatrick using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
1750e5dd7070Spatrick
1751e5dd7070Spatrick // The cleanup callback that finalizes all variabels at the given location,
1752e5dd7070Spatrick // thus calls destructors etc.
1753e5dd7070Spatrick auto FiniCB = [this](InsertPointTy IP) {
1754ec727ea7Spatrick OMPBuilderCBHelpers::FinalizeOMPRegion(*this, IP);
1755e5dd7070Spatrick };
1756e5dd7070Spatrick
1757e5dd7070Spatrick // Privatization callback that performs appropriate action for
1758e5dd7070Spatrick // shared/private/firstprivate/lastprivate/copyin/... variables.
1759e5dd7070Spatrick //
1760e5dd7070Spatrick // TODO: This defaults to shared right now.
1761e5dd7070Spatrick auto PrivCB = [](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
1762a9ac8606Spatrick llvm::Value &, llvm::Value &Val, llvm::Value *&ReplVal) {
1763e5dd7070Spatrick // The next line is appropriate only for variables (Val) with the
1764e5dd7070Spatrick // data-sharing attribute "shared".
1765e5dd7070Spatrick ReplVal = &Val;
1766e5dd7070Spatrick
1767e5dd7070Spatrick return CodeGenIP;
1768e5dd7070Spatrick };
1769e5dd7070Spatrick
1770e5dd7070Spatrick const CapturedStmt *CS = S.getCapturedStmt(OMPD_parallel);
1771e5dd7070Spatrick const Stmt *ParallelRegionBodyStmt = CS->getCapturedStmt();
1772e5dd7070Spatrick
1773*12c85518Srobert auto BodyGenCB = [&, this](InsertPointTy AllocaIP,
1774*12c85518Srobert InsertPointTy CodeGenIP) {
1775*12c85518Srobert OMPBuilderCBHelpers::EmitOMPOutlinedRegionBody(
1776*12c85518Srobert *this, ParallelRegionBodyStmt, AllocaIP, CodeGenIP, "parallel");
1777e5dd7070Spatrick };
1778e5dd7070Spatrick
1779e5dd7070Spatrick CGCapturedStmtInfo CGSI(*CS, CR_OpenMP);
1780e5dd7070Spatrick CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(*this, &CGSI);
1781a9ac8606Spatrick llvm::OpenMPIRBuilder::InsertPointTy AllocaIP(
1782a9ac8606Spatrick AllocaInsertPt->getParent(), AllocaInsertPt->getIterator());
1783a9ac8606Spatrick Builder.restoreIP(
1784a9ac8606Spatrick OMPBuilder.createParallel(Builder, AllocaIP, BodyGenCB, PrivCB, FiniCB,
1785a9ac8606Spatrick IfCond, NumThreads, ProcBind, S.hasCancel()));
1786e5dd7070Spatrick return;
1787e5dd7070Spatrick }
1788e5dd7070Spatrick
1789e5dd7070Spatrick // Emit parallel region as a standalone region.
1790e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
1791e5dd7070Spatrick Action.Enter(CGF);
1792e5dd7070Spatrick OMPPrivateScope PrivateScope(CGF);
1793*12c85518Srobert emitOMPCopyinClause(CGF, S);
1794e5dd7070Spatrick (void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
1795e5dd7070Spatrick CGF.EmitOMPPrivateClause(S, PrivateScope);
1796e5dd7070Spatrick CGF.EmitOMPReductionClauseInit(S, PrivateScope);
1797e5dd7070Spatrick (void)PrivateScope.Privatize();
1798e5dd7070Spatrick CGF.EmitStmt(S.getCapturedStmt(OMPD_parallel)->getCapturedStmt());
1799e5dd7070Spatrick CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_parallel);
1800e5dd7070Spatrick };
1801ec727ea7Spatrick {
1802ec727ea7Spatrick auto LPCRegion =
1803ec727ea7Spatrick CGOpenMPRuntime::LastprivateConditionalRAII::disable(*this, S);
1804e5dd7070Spatrick emitCommonOMPParallelDirective(*this, S, OMPD_parallel, CodeGen,
1805e5dd7070Spatrick emitEmptyBoundParameters);
1806e5dd7070Spatrick emitPostUpdateForReductionClause(*this, S,
1807e5dd7070Spatrick [](CodeGenFunction &) { return nullptr; });
1808e5dd7070Spatrick }
1809ec727ea7Spatrick // Check for outer lastprivate conditional update.
1810ec727ea7Spatrick checkForLastprivateConditionalUpdate(*this, S);
1811ec727ea7Spatrick }
1812e5dd7070Spatrick
EmitOMPMetaDirective(const OMPMetaDirective & S)1813*12c85518Srobert void CodeGenFunction::EmitOMPMetaDirective(const OMPMetaDirective &S) {
1814*12c85518Srobert EmitStmt(S.getIfStmt());
1815*12c85518Srobert }
1816*12c85518Srobert
1817a9ac8606Spatrick namespace {
1818a9ac8606Spatrick /// RAII to handle scopes for loop transformation directives.
1819a9ac8606Spatrick class OMPTransformDirectiveScopeRAII {
1820a9ac8606Spatrick OMPLoopScope *Scope = nullptr;
1821a9ac8606Spatrick CodeGenFunction::CGCapturedStmtInfo *CGSI = nullptr;
1822a9ac8606Spatrick CodeGenFunction::CGCapturedStmtRAII *CapInfoRAII = nullptr;
1823a9ac8606Spatrick
1824a9ac8606Spatrick public:
OMPTransformDirectiveScopeRAII(CodeGenFunction & CGF,const Stmt * S)1825a9ac8606Spatrick OMPTransformDirectiveScopeRAII(CodeGenFunction &CGF, const Stmt *S) {
1826a9ac8606Spatrick if (const auto *Dir = dyn_cast<OMPLoopBasedDirective>(S)) {
1827a9ac8606Spatrick Scope = new OMPLoopScope(CGF, *Dir);
1828a9ac8606Spatrick CGSI = new CodeGenFunction::CGCapturedStmtInfo(CR_OpenMP);
1829a9ac8606Spatrick CapInfoRAII = new CodeGenFunction::CGCapturedStmtRAII(CGF, CGSI);
1830a9ac8606Spatrick }
1831a9ac8606Spatrick }
~OMPTransformDirectiveScopeRAII()1832a9ac8606Spatrick ~OMPTransformDirectiveScopeRAII() {
1833a9ac8606Spatrick if (!Scope)
1834a9ac8606Spatrick return;
1835a9ac8606Spatrick delete CapInfoRAII;
1836a9ac8606Spatrick delete CGSI;
1837a9ac8606Spatrick delete Scope;
1838a9ac8606Spatrick }
1839a9ac8606Spatrick };
1840a9ac8606Spatrick } // namespace
1841a9ac8606Spatrick
emitBody(CodeGenFunction & CGF,const Stmt * S,const Stmt * NextLoop,int MaxLevel,int Level=0)1842e5dd7070Spatrick static void emitBody(CodeGenFunction &CGF, const Stmt *S, const Stmt *NextLoop,
1843e5dd7070Spatrick int MaxLevel, int Level = 0) {
1844e5dd7070Spatrick assert(Level < MaxLevel && "Too deep lookup during loop body codegen.");
1845e5dd7070Spatrick const Stmt *SimplifiedS = S->IgnoreContainers();
1846e5dd7070Spatrick if (const auto *CS = dyn_cast<CompoundStmt>(SimplifiedS)) {
1847e5dd7070Spatrick PrettyStackTraceLoc CrashInfo(
1848e5dd7070Spatrick CGF.getContext().getSourceManager(), CS->getLBracLoc(),
1849e5dd7070Spatrick "LLVM IR generation of compound statement ('{}')");
1850e5dd7070Spatrick
1851e5dd7070Spatrick // Keep track of the current cleanup stack depth, including debug scopes.
1852e5dd7070Spatrick CodeGenFunction::LexicalScope Scope(CGF, S->getSourceRange());
1853e5dd7070Spatrick for (const Stmt *CurStmt : CS->body())
1854e5dd7070Spatrick emitBody(CGF, CurStmt, NextLoop, MaxLevel, Level);
1855e5dd7070Spatrick return;
1856e5dd7070Spatrick }
1857e5dd7070Spatrick if (SimplifiedS == NextLoop) {
1858*12c85518Srobert if (auto *Dir = dyn_cast<OMPLoopTransformationDirective>(SimplifiedS))
1859a9ac8606Spatrick SimplifiedS = Dir->getTransformedStmt();
1860a9ac8606Spatrick if (const auto *CanonLoop = dyn_cast<OMPCanonicalLoop>(SimplifiedS))
1861a9ac8606Spatrick SimplifiedS = CanonLoop->getLoopStmt();
1862e5dd7070Spatrick if (const auto *For = dyn_cast<ForStmt>(SimplifiedS)) {
1863e5dd7070Spatrick S = For->getBody();
1864e5dd7070Spatrick } else {
1865e5dd7070Spatrick assert(isa<CXXForRangeStmt>(SimplifiedS) &&
1866e5dd7070Spatrick "Expected canonical for loop or range-based for loop.");
1867e5dd7070Spatrick const auto *CXXFor = cast<CXXForRangeStmt>(SimplifiedS);
1868e5dd7070Spatrick CGF.EmitStmt(CXXFor->getLoopVarStmt());
1869e5dd7070Spatrick S = CXXFor->getBody();
1870e5dd7070Spatrick }
1871e5dd7070Spatrick if (Level + 1 < MaxLevel) {
1872e5dd7070Spatrick NextLoop = OMPLoopDirective::tryToFindNextInnerLoop(
1873e5dd7070Spatrick S, /*TryImperfectlyNestedLoops=*/true);
1874e5dd7070Spatrick emitBody(CGF, S, NextLoop, MaxLevel, Level + 1);
1875e5dd7070Spatrick return;
1876e5dd7070Spatrick }
1877e5dd7070Spatrick }
1878e5dd7070Spatrick CGF.EmitStmt(S);
1879e5dd7070Spatrick }
1880e5dd7070Spatrick
EmitOMPLoopBody(const OMPLoopDirective & D,JumpDest LoopExit)1881e5dd7070Spatrick void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &D,
1882e5dd7070Spatrick JumpDest LoopExit) {
1883e5dd7070Spatrick RunCleanupsScope BodyScope(*this);
1884e5dd7070Spatrick // Update counters values on current iteration.
1885e5dd7070Spatrick for (const Expr *UE : D.updates())
1886e5dd7070Spatrick EmitIgnoredExpr(UE);
1887e5dd7070Spatrick // Update the linear variables.
1888e5dd7070Spatrick // In distribute directives only loop counters may be marked as linear, no
1889e5dd7070Spatrick // need to generate the code for them.
1890e5dd7070Spatrick if (!isOpenMPDistributeDirective(D.getDirectiveKind())) {
1891e5dd7070Spatrick for (const auto *C : D.getClausesOfKind<OMPLinearClause>()) {
1892e5dd7070Spatrick for (const Expr *UE : C->updates())
1893e5dd7070Spatrick EmitIgnoredExpr(UE);
1894e5dd7070Spatrick }
1895e5dd7070Spatrick }
1896e5dd7070Spatrick
1897e5dd7070Spatrick // On a continue in the body, jump to the end.
1898e5dd7070Spatrick JumpDest Continue = getJumpDestInCurrentScope("omp.body.continue");
1899e5dd7070Spatrick BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
1900e5dd7070Spatrick for (const Expr *E : D.finals_conditions()) {
1901e5dd7070Spatrick if (!E)
1902e5dd7070Spatrick continue;
1903e5dd7070Spatrick // Check that loop counter in non-rectangular nest fits into the iteration
1904e5dd7070Spatrick // space.
1905e5dd7070Spatrick llvm::BasicBlock *NextBB = createBasicBlock("omp.body.next");
1906e5dd7070Spatrick EmitBranchOnBoolExpr(E, NextBB, Continue.getBlock(),
1907e5dd7070Spatrick getProfileCount(D.getBody()));
1908e5dd7070Spatrick EmitBlock(NextBB);
1909e5dd7070Spatrick }
1910ec727ea7Spatrick
1911ec727ea7Spatrick OMPPrivateScope InscanScope(*this);
1912ec727ea7Spatrick EmitOMPReductionClauseInit(D, InscanScope, /*ForInscan=*/true);
1913ec727ea7Spatrick bool IsInscanRegion = InscanScope.Privatize();
1914ec727ea7Spatrick if (IsInscanRegion) {
1915ec727ea7Spatrick // Need to remember the block before and after scan directive
1916ec727ea7Spatrick // to dispatch them correctly depending on the clause used in
1917ec727ea7Spatrick // this directive, inclusive or exclusive. For inclusive scan the natural
1918ec727ea7Spatrick // order of the blocks is used, for exclusive clause the blocks must be
1919ec727ea7Spatrick // executed in reverse order.
1920ec727ea7Spatrick OMPBeforeScanBlock = createBasicBlock("omp.before.scan.bb");
1921ec727ea7Spatrick OMPAfterScanBlock = createBasicBlock("omp.after.scan.bb");
1922ec727ea7Spatrick // No need to allocate inscan exit block, in simd mode it is selected in the
1923ec727ea7Spatrick // codegen for the scan directive.
1924ec727ea7Spatrick if (D.getDirectiveKind() != OMPD_simd && !getLangOpts().OpenMPSimd)
1925ec727ea7Spatrick OMPScanExitBlock = createBasicBlock("omp.exit.inscan.bb");
1926ec727ea7Spatrick OMPScanDispatch = createBasicBlock("omp.inscan.dispatch");
1927ec727ea7Spatrick EmitBranch(OMPScanDispatch);
1928ec727ea7Spatrick EmitBlock(OMPBeforeScanBlock);
1929ec727ea7Spatrick }
1930ec727ea7Spatrick
1931e5dd7070Spatrick // Emit loop variables for C++ range loops.
1932e5dd7070Spatrick const Stmt *Body =
1933e5dd7070Spatrick D.getInnermostCapturedStmt()->getCapturedStmt()->IgnoreContainers();
1934e5dd7070Spatrick // Emit loop body.
1935e5dd7070Spatrick emitBody(*this, Body,
1936a9ac8606Spatrick OMPLoopBasedDirective::tryToFindNextInnerLoop(
1937e5dd7070Spatrick Body, /*TryImperfectlyNestedLoops=*/true),
1938a9ac8606Spatrick D.getLoopsNumber());
1939e5dd7070Spatrick
1940ec727ea7Spatrick // Jump to the dispatcher at the end of the loop body.
1941ec727ea7Spatrick if (IsInscanRegion)
1942ec727ea7Spatrick EmitBranch(OMPScanExitBlock);
1943ec727ea7Spatrick
1944e5dd7070Spatrick // The end (updates/cleanups).
1945e5dd7070Spatrick EmitBlock(Continue.getBlock());
1946e5dd7070Spatrick BreakContinueStack.pop_back();
1947e5dd7070Spatrick }
1948e5dd7070Spatrick
1949a9ac8606Spatrick using EmittedClosureTy = std::pair<llvm::Function *, llvm::Value *>;
1950a9ac8606Spatrick
1951a9ac8606Spatrick /// Emit a captured statement and return the function as well as its captured
1952a9ac8606Spatrick /// closure context.
emitCapturedStmtFunc(CodeGenFunction & ParentCGF,const CapturedStmt * S)1953a9ac8606Spatrick static EmittedClosureTy emitCapturedStmtFunc(CodeGenFunction &ParentCGF,
1954a9ac8606Spatrick const CapturedStmt *S) {
1955a9ac8606Spatrick LValue CapStruct = ParentCGF.InitCapturedStruct(*S);
1956a9ac8606Spatrick CodeGenFunction CGF(ParentCGF.CGM, /*suppressNewContext=*/true);
1957a9ac8606Spatrick std::unique_ptr<CodeGenFunction::CGCapturedStmtInfo> CSI =
1958a9ac8606Spatrick std::make_unique<CodeGenFunction::CGCapturedStmtInfo>(*S);
1959a9ac8606Spatrick CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, CSI.get());
1960a9ac8606Spatrick llvm::Function *F = CGF.GenerateCapturedStmtFunction(*S);
1961a9ac8606Spatrick
1962a9ac8606Spatrick return {F, CapStruct.getPointer(ParentCGF)};
1963a9ac8606Spatrick }
1964a9ac8606Spatrick
1965a9ac8606Spatrick /// Emit a call to a previously captured closure.
1966a9ac8606Spatrick static llvm::CallInst *
emitCapturedStmtCall(CodeGenFunction & ParentCGF,EmittedClosureTy Cap,llvm::ArrayRef<llvm::Value * > Args)1967a9ac8606Spatrick emitCapturedStmtCall(CodeGenFunction &ParentCGF, EmittedClosureTy Cap,
1968a9ac8606Spatrick llvm::ArrayRef<llvm::Value *> Args) {
1969a9ac8606Spatrick // Append the closure context to the argument.
1970a9ac8606Spatrick SmallVector<llvm::Value *> EffectiveArgs;
1971a9ac8606Spatrick EffectiveArgs.reserve(Args.size() + 1);
1972a9ac8606Spatrick llvm::append_range(EffectiveArgs, Args);
1973a9ac8606Spatrick EffectiveArgs.push_back(Cap.second);
1974a9ac8606Spatrick
1975a9ac8606Spatrick return ParentCGF.Builder.CreateCall(Cap.first, EffectiveArgs);
1976a9ac8606Spatrick }
1977a9ac8606Spatrick
1978a9ac8606Spatrick llvm::CanonicalLoopInfo *
EmitOMPCollapsedCanonicalLoopNest(const Stmt * S,int Depth)1979a9ac8606Spatrick CodeGenFunction::EmitOMPCollapsedCanonicalLoopNest(const Stmt *S, int Depth) {
1980a9ac8606Spatrick assert(Depth == 1 && "Nested loops with OpenMPIRBuilder not yet implemented");
1981a9ac8606Spatrick
1982*12c85518Srobert // The caller is processing the loop-associated directive processing the \p
1983*12c85518Srobert // Depth loops nested in \p S. Put the previous pending loop-associated
1984*12c85518Srobert // directive to the stack. If the current loop-associated directive is a loop
1985*12c85518Srobert // transformation directive, it will push its generated loops onto the stack
1986*12c85518Srobert // such that together with the loops left here they form the combined loop
1987*12c85518Srobert // nest for the parent loop-associated directive.
1988*12c85518Srobert int ParentExpectedOMPLoopDepth = ExpectedOMPLoopDepth;
1989*12c85518Srobert ExpectedOMPLoopDepth = Depth;
1990*12c85518Srobert
1991a9ac8606Spatrick EmitStmt(S);
1992a9ac8606Spatrick assert(OMPLoopNestStack.size() >= (size_t)Depth && "Found too few loops");
1993a9ac8606Spatrick
1994a9ac8606Spatrick // The last added loop is the outermost one.
1995*12c85518Srobert llvm::CanonicalLoopInfo *Result = OMPLoopNestStack.back();
1996*12c85518Srobert
1997*12c85518Srobert // Pop the \p Depth loops requested by the call from that stack and restore
1998*12c85518Srobert // the previous context.
1999*12c85518Srobert OMPLoopNestStack.pop_back_n(Depth);
2000*12c85518Srobert ExpectedOMPLoopDepth = ParentExpectedOMPLoopDepth;
2001*12c85518Srobert
2002*12c85518Srobert return Result;
2003a9ac8606Spatrick }
2004a9ac8606Spatrick
EmitOMPCanonicalLoop(const OMPCanonicalLoop * S)2005a9ac8606Spatrick void CodeGenFunction::EmitOMPCanonicalLoop(const OMPCanonicalLoop *S) {
2006a9ac8606Spatrick const Stmt *SyntacticalLoop = S->getLoopStmt();
2007a9ac8606Spatrick if (!getLangOpts().OpenMPIRBuilder) {
2008a9ac8606Spatrick // Ignore if OpenMPIRBuilder is not enabled.
2009a9ac8606Spatrick EmitStmt(SyntacticalLoop);
2010a9ac8606Spatrick return;
2011a9ac8606Spatrick }
2012a9ac8606Spatrick
2013a9ac8606Spatrick LexicalScope ForScope(*this, S->getSourceRange());
2014a9ac8606Spatrick
2015a9ac8606Spatrick // Emit init statements. The Distance/LoopVar funcs may reference variable
2016a9ac8606Spatrick // declarations they contain.
2017a9ac8606Spatrick const Stmt *BodyStmt;
2018a9ac8606Spatrick if (const auto *For = dyn_cast<ForStmt>(SyntacticalLoop)) {
2019a9ac8606Spatrick if (const Stmt *InitStmt = For->getInit())
2020a9ac8606Spatrick EmitStmt(InitStmt);
2021a9ac8606Spatrick BodyStmt = For->getBody();
2022a9ac8606Spatrick } else if (const auto *RangeFor =
2023a9ac8606Spatrick dyn_cast<CXXForRangeStmt>(SyntacticalLoop)) {
2024a9ac8606Spatrick if (const DeclStmt *RangeStmt = RangeFor->getRangeStmt())
2025a9ac8606Spatrick EmitStmt(RangeStmt);
2026a9ac8606Spatrick if (const DeclStmt *BeginStmt = RangeFor->getBeginStmt())
2027a9ac8606Spatrick EmitStmt(BeginStmt);
2028a9ac8606Spatrick if (const DeclStmt *EndStmt = RangeFor->getEndStmt())
2029a9ac8606Spatrick EmitStmt(EndStmt);
2030a9ac8606Spatrick if (const DeclStmt *LoopVarStmt = RangeFor->getLoopVarStmt())
2031a9ac8606Spatrick EmitStmt(LoopVarStmt);
2032a9ac8606Spatrick BodyStmt = RangeFor->getBody();
2033a9ac8606Spatrick } else
2034a9ac8606Spatrick llvm_unreachable("Expected for-stmt or range-based for-stmt");
2035a9ac8606Spatrick
2036a9ac8606Spatrick // Emit closure for later use. By-value captures will be captured here.
2037a9ac8606Spatrick const CapturedStmt *DistanceFunc = S->getDistanceFunc();
2038a9ac8606Spatrick EmittedClosureTy DistanceClosure = emitCapturedStmtFunc(*this, DistanceFunc);
2039a9ac8606Spatrick const CapturedStmt *LoopVarFunc = S->getLoopVarFunc();
2040a9ac8606Spatrick EmittedClosureTy LoopVarClosure = emitCapturedStmtFunc(*this, LoopVarFunc);
2041a9ac8606Spatrick
2042a9ac8606Spatrick // Call the distance function to get the number of iterations of the loop to
2043a9ac8606Spatrick // come.
2044a9ac8606Spatrick QualType LogicalTy = DistanceFunc->getCapturedDecl()
2045a9ac8606Spatrick ->getParam(0)
2046a9ac8606Spatrick ->getType()
2047a9ac8606Spatrick .getNonReferenceType();
2048a9ac8606Spatrick Address CountAddr = CreateMemTemp(LogicalTy, ".count.addr");
2049a9ac8606Spatrick emitCapturedStmtCall(*this, DistanceClosure, {CountAddr.getPointer()});
2050a9ac8606Spatrick llvm::Value *DistVal = Builder.CreateLoad(CountAddr, ".count");
2051a9ac8606Spatrick
2052a9ac8606Spatrick // Emit the loop structure.
2053a9ac8606Spatrick llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
2054a9ac8606Spatrick auto BodyGen = [&, this](llvm::OpenMPIRBuilder::InsertPointTy CodeGenIP,
2055a9ac8606Spatrick llvm::Value *IndVar) {
2056a9ac8606Spatrick Builder.restoreIP(CodeGenIP);
2057a9ac8606Spatrick
2058a9ac8606Spatrick // Emit the loop body: Convert the logical iteration number to the loop
2059a9ac8606Spatrick // variable and emit the body.
2060a9ac8606Spatrick const DeclRefExpr *LoopVarRef = S->getLoopVarRef();
2061a9ac8606Spatrick LValue LCVal = EmitLValue(LoopVarRef);
2062a9ac8606Spatrick Address LoopVarAddress = LCVal.getAddress(*this);
2063a9ac8606Spatrick emitCapturedStmtCall(*this, LoopVarClosure,
2064a9ac8606Spatrick {LoopVarAddress.getPointer(), IndVar});
2065a9ac8606Spatrick
2066a9ac8606Spatrick RunCleanupsScope BodyScope(*this);
2067a9ac8606Spatrick EmitStmt(BodyStmt);
2068a9ac8606Spatrick };
2069a9ac8606Spatrick llvm::CanonicalLoopInfo *CL =
2070a9ac8606Spatrick OMPBuilder.createCanonicalLoop(Builder, BodyGen, DistVal);
2071a9ac8606Spatrick
2072a9ac8606Spatrick // Finish up the loop.
2073a9ac8606Spatrick Builder.restoreIP(CL->getAfterIP());
2074a9ac8606Spatrick ForScope.ForceCleanup();
2075a9ac8606Spatrick
2076a9ac8606Spatrick // Remember the CanonicalLoopInfo for parent AST nodes consuming it.
2077a9ac8606Spatrick OMPLoopNestStack.push_back(CL);
2078a9ac8606Spatrick }
2079a9ac8606Spatrick
EmitOMPInnerLoop(const OMPExecutableDirective & S,bool RequiresCleanup,const Expr * LoopCond,const Expr * IncExpr,const llvm::function_ref<void (CodeGenFunction &)> BodyGen,const llvm::function_ref<void (CodeGenFunction &)> PostIncGen)2080e5dd7070Spatrick void CodeGenFunction::EmitOMPInnerLoop(
2081ec727ea7Spatrick const OMPExecutableDirective &S, bool RequiresCleanup, const Expr *LoopCond,
2082e5dd7070Spatrick const Expr *IncExpr,
2083e5dd7070Spatrick const llvm::function_ref<void(CodeGenFunction &)> BodyGen,
2084e5dd7070Spatrick const llvm::function_ref<void(CodeGenFunction &)> PostIncGen) {
2085e5dd7070Spatrick auto LoopExit = getJumpDestInCurrentScope("omp.inner.for.end");
2086e5dd7070Spatrick
2087e5dd7070Spatrick // Start the loop with a block that tests the condition.
2088e5dd7070Spatrick auto CondBlock = createBasicBlock("omp.inner.for.cond");
2089e5dd7070Spatrick EmitBlock(CondBlock);
2090e5dd7070Spatrick const SourceRange R = S.getSourceRange();
2091ec727ea7Spatrick
2092ec727ea7Spatrick // If attributes are attached, push to the basic block with them.
2093ec727ea7Spatrick const auto &OMPED = cast<OMPExecutableDirective>(S);
2094ec727ea7Spatrick const CapturedStmt *ICS = OMPED.getInnermostCapturedStmt();
2095ec727ea7Spatrick const Stmt *SS = ICS->getCapturedStmt();
2096ec727ea7Spatrick const AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(SS);
2097a9ac8606Spatrick OMPLoopNestStack.clear();
2098ec727ea7Spatrick if (AS)
2099ec727ea7Spatrick LoopStack.push(CondBlock, CGM.getContext(), CGM.getCodeGenOpts(),
2100ec727ea7Spatrick AS->getAttrs(), SourceLocToDebugLoc(R.getBegin()),
2101ec727ea7Spatrick SourceLocToDebugLoc(R.getEnd()));
2102ec727ea7Spatrick else
2103e5dd7070Spatrick LoopStack.push(CondBlock, SourceLocToDebugLoc(R.getBegin()),
2104e5dd7070Spatrick SourceLocToDebugLoc(R.getEnd()));
2105e5dd7070Spatrick
2106e5dd7070Spatrick // If there are any cleanups between here and the loop-exit scope,
2107e5dd7070Spatrick // create a block to stage a loop exit along.
2108e5dd7070Spatrick llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
2109e5dd7070Spatrick if (RequiresCleanup)
2110e5dd7070Spatrick ExitBlock = createBasicBlock("omp.inner.for.cond.cleanup");
2111e5dd7070Spatrick
2112e5dd7070Spatrick llvm::BasicBlock *LoopBody = createBasicBlock("omp.inner.for.body");
2113e5dd7070Spatrick
2114e5dd7070Spatrick // Emit condition.
2115e5dd7070Spatrick EmitBranchOnBoolExpr(LoopCond, LoopBody, ExitBlock, getProfileCount(&S));
2116e5dd7070Spatrick if (ExitBlock != LoopExit.getBlock()) {
2117e5dd7070Spatrick EmitBlock(ExitBlock);
2118e5dd7070Spatrick EmitBranchThroughCleanup(LoopExit);
2119e5dd7070Spatrick }
2120e5dd7070Spatrick
2121e5dd7070Spatrick EmitBlock(LoopBody);
2122e5dd7070Spatrick incrementProfileCounter(&S);
2123e5dd7070Spatrick
2124e5dd7070Spatrick // Create a block for the increment.
2125e5dd7070Spatrick JumpDest Continue = getJumpDestInCurrentScope("omp.inner.for.inc");
2126e5dd7070Spatrick BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
2127e5dd7070Spatrick
2128e5dd7070Spatrick BodyGen(*this);
2129e5dd7070Spatrick
2130e5dd7070Spatrick // Emit "IV = IV + 1" and a back-edge to the condition block.
2131e5dd7070Spatrick EmitBlock(Continue.getBlock());
2132e5dd7070Spatrick EmitIgnoredExpr(IncExpr);
2133e5dd7070Spatrick PostIncGen(*this);
2134e5dd7070Spatrick BreakContinueStack.pop_back();
2135e5dd7070Spatrick EmitBranch(CondBlock);
2136e5dd7070Spatrick LoopStack.pop();
2137e5dd7070Spatrick // Emit the fall-through block.
2138e5dd7070Spatrick EmitBlock(LoopExit.getBlock());
2139e5dd7070Spatrick }
2140e5dd7070Spatrick
EmitOMPLinearClauseInit(const OMPLoopDirective & D)2141e5dd7070Spatrick bool CodeGenFunction::EmitOMPLinearClauseInit(const OMPLoopDirective &D) {
2142e5dd7070Spatrick if (!HaveInsertPoint())
2143e5dd7070Spatrick return false;
2144e5dd7070Spatrick // Emit inits for the linear variables.
2145e5dd7070Spatrick bool HasLinears = false;
2146e5dd7070Spatrick for (const auto *C : D.getClausesOfKind<OMPLinearClause>()) {
2147e5dd7070Spatrick for (const Expr *Init : C->inits()) {
2148e5dd7070Spatrick HasLinears = true;
2149e5dd7070Spatrick const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(Init)->getDecl());
2150e5dd7070Spatrick if (const auto *Ref =
2151e5dd7070Spatrick dyn_cast<DeclRefExpr>(VD->getInit()->IgnoreImpCasts())) {
2152e5dd7070Spatrick AutoVarEmission Emission = EmitAutoVarAlloca(*VD);
2153e5dd7070Spatrick const auto *OrigVD = cast<VarDecl>(Ref->getDecl());
2154e5dd7070Spatrick DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(OrigVD),
2155e5dd7070Spatrick CapturedStmtInfo->lookup(OrigVD) != nullptr,
2156e5dd7070Spatrick VD->getInit()->getType(), VK_LValue,
2157e5dd7070Spatrick VD->getInit()->getExprLoc());
2158*12c85518Srobert EmitExprAsInit(
2159*12c85518Srobert &DRE, VD,
2160*12c85518Srobert MakeAddrLValue(Emission.getAllocatedAddress(), VD->getType()),
2161e5dd7070Spatrick /*capturedByInit=*/false);
2162e5dd7070Spatrick EmitAutoVarCleanups(Emission);
2163e5dd7070Spatrick } else {
2164e5dd7070Spatrick EmitVarDecl(*VD);
2165e5dd7070Spatrick }
2166e5dd7070Spatrick }
2167e5dd7070Spatrick // Emit the linear steps for the linear clauses.
2168e5dd7070Spatrick // If a step is not constant, it is pre-calculated before the loop.
2169e5dd7070Spatrick if (const auto *CS = cast_or_null<BinaryOperator>(C->getCalcStep()))
2170e5dd7070Spatrick if (const auto *SaveRef = cast<DeclRefExpr>(CS->getLHS())) {
2171e5dd7070Spatrick EmitVarDecl(*cast<VarDecl>(SaveRef->getDecl()));
2172e5dd7070Spatrick // Emit calculation of the linear step.
2173e5dd7070Spatrick EmitIgnoredExpr(CS);
2174e5dd7070Spatrick }
2175e5dd7070Spatrick }
2176e5dd7070Spatrick return HasLinears;
2177e5dd7070Spatrick }
2178e5dd7070Spatrick
EmitOMPLinearClauseFinal(const OMPLoopDirective & D,const llvm::function_ref<llvm::Value * (CodeGenFunction &)> CondGen)2179e5dd7070Spatrick void CodeGenFunction::EmitOMPLinearClauseFinal(
2180e5dd7070Spatrick const OMPLoopDirective &D,
2181e5dd7070Spatrick const llvm::function_ref<llvm::Value *(CodeGenFunction &)> CondGen) {
2182e5dd7070Spatrick if (!HaveInsertPoint())
2183e5dd7070Spatrick return;
2184e5dd7070Spatrick llvm::BasicBlock *DoneBB = nullptr;
2185e5dd7070Spatrick // Emit the final values of the linear variables.
2186e5dd7070Spatrick for (const auto *C : D.getClausesOfKind<OMPLinearClause>()) {
2187e5dd7070Spatrick auto IC = C->varlist_begin();
2188e5dd7070Spatrick for (const Expr *F : C->finals()) {
2189e5dd7070Spatrick if (!DoneBB) {
2190e5dd7070Spatrick if (llvm::Value *Cond = CondGen(*this)) {
2191e5dd7070Spatrick // If the first post-update expression is found, emit conditional
2192e5dd7070Spatrick // block if it was requested.
2193e5dd7070Spatrick llvm::BasicBlock *ThenBB = createBasicBlock(".omp.linear.pu");
2194e5dd7070Spatrick DoneBB = createBasicBlock(".omp.linear.pu.done");
2195e5dd7070Spatrick Builder.CreateCondBr(Cond, ThenBB, DoneBB);
2196e5dd7070Spatrick EmitBlock(ThenBB);
2197e5dd7070Spatrick }
2198e5dd7070Spatrick }
2199e5dd7070Spatrick const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IC)->getDecl());
2200e5dd7070Spatrick DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(OrigVD),
2201e5dd7070Spatrick CapturedStmtInfo->lookup(OrigVD) != nullptr,
2202e5dd7070Spatrick (*IC)->getType(), VK_LValue, (*IC)->getExprLoc());
2203e5dd7070Spatrick Address OrigAddr = EmitLValue(&DRE).getAddress(*this);
2204e5dd7070Spatrick CodeGenFunction::OMPPrivateScope VarScope(*this);
2205*12c85518Srobert VarScope.addPrivate(OrigVD, OrigAddr);
2206e5dd7070Spatrick (void)VarScope.Privatize();
2207e5dd7070Spatrick EmitIgnoredExpr(F);
2208e5dd7070Spatrick ++IC;
2209e5dd7070Spatrick }
2210e5dd7070Spatrick if (const Expr *PostUpdate = C->getPostUpdateExpr())
2211e5dd7070Spatrick EmitIgnoredExpr(PostUpdate);
2212e5dd7070Spatrick }
2213e5dd7070Spatrick if (DoneBB)
2214e5dd7070Spatrick EmitBlock(DoneBB, /*IsFinished=*/true);
2215e5dd7070Spatrick }
2216e5dd7070Spatrick
emitAlignedClause(CodeGenFunction & CGF,const OMPExecutableDirective & D)2217e5dd7070Spatrick static void emitAlignedClause(CodeGenFunction &CGF,
2218e5dd7070Spatrick const OMPExecutableDirective &D) {
2219e5dd7070Spatrick if (!CGF.HaveInsertPoint())
2220e5dd7070Spatrick return;
2221e5dd7070Spatrick for (const auto *Clause : D.getClausesOfKind<OMPAlignedClause>()) {
2222e5dd7070Spatrick llvm::APInt ClauseAlignment(64, 0);
2223e5dd7070Spatrick if (const Expr *AlignmentExpr = Clause->getAlignment()) {
2224e5dd7070Spatrick auto *AlignmentCI =
2225e5dd7070Spatrick cast<llvm::ConstantInt>(CGF.EmitScalarExpr(AlignmentExpr));
2226e5dd7070Spatrick ClauseAlignment = AlignmentCI->getValue();
2227e5dd7070Spatrick }
2228e5dd7070Spatrick for (const Expr *E : Clause->varlists()) {
2229e5dd7070Spatrick llvm::APInt Alignment(ClauseAlignment);
2230e5dd7070Spatrick if (Alignment == 0) {
2231e5dd7070Spatrick // OpenMP [2.8.1, Description]
2232e5dd7070Spatrick // If no optional parameter is specified, implementation-defined default
2233e5dd7070Spatrick // alignments for SIMD instructions on the target platforms are assumed.
2234e5dd7070Spatrick Alignment =
2235e5dd7070Spatrick CGF.getContext()
2236e5dd7070Spatrick .toCharUnitsFromBits(CGF.getContext().getOpenMPDefaultSimdAlign(
2237e5dd7070Spatrick E->getType()->getPointeeType()))
2238e5dd7070Spatrick .getQuantity();
2239e5dd7070Spatrick }
2240e5dd7070Spatrick assert((Alignment == 0 || Alignment.isPowerOf2()) &&
2241e5dd7070Spatrick "alignment is not power of 2");
2242e5dd7070Spatrick if (Alignment != 0) {
2243e5dd7070Spatrick llvm::Value *PtrValue = CGF.EmitScalarExpr(E);
2244ec727ea7Spatrick CGF.emitAlignmentAssumption(
2245e5dd7070Spatrick PtrValue, E, /*No second loc needed*/ SourceLocation(),
2246e5dd7070Spatrick llvm::ConstantInt::get(CGF.getLLVMContext(), Alignment));
2247e5dd7070Spatrick }
2248e5dd7070Spatrick }
2249e5dd7070Spatrick }
2250e5dd7070Spatrick }
2251e5dd7070Spatrick
EmitOMPPrivateLoopCounters(const OMPLoopDirective & S,CodeGenFunction::OMPPrivateScope & LoopScope)2252e5dd7070Spatrick void CodeGenFunction::EmitOMPPrivateLoopCounters(
2253e5dd7070Spatrick const OMPLoopDirective &S, CodeGenFunction::OMPPrivateScope &LoopScope) {
2254e5dd7070Spatrick if (!HaveInsertPoint())
2255e5dd7070Spatrick return;
2256e5dd7070Spatrick auto I = S.private_counters().begin();
2257e5dd7070Spatrick for (const Expr *E : S.counters()) {
2258e5dd7070Spatrick const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
2259e5dd7070Spatrick const auto *PrivateVD = cast<VarDecl>(cast<DeclRefExpr>(*I)->getDecl());
2260e5dd7070Spatrick // Emit var without initialization.
2261e5dd7070Spatrick AutoVarEmission VarEmission = EmitAutoVarAlloca(*PrivateVD);
2262e5dd7070Spatrick EmitAutoVarCleanups(VarEmission);
2263e5dd7070Spatrick LocalDeclMap.erase(PrivateVD);
2264*12c85518Srobert (void)LoopScope.addPrivate(VD, VarEmission.getAllocatedAddress());
2265e5dd7070Spatrick if (LocalDeclMap.count(VD) || CapturedStmtInfo->lookup(VD) ||
2266e5dd7070Spatrick VD->hasGlobalStorage()) {
2267e5dd7070Spatrick DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(VD),
2268e5dd7070Spatrick LocalDeclMap.count(VD) || CapturedStmtInfo->lookup(VD),
2269e5dd7070Spatrick E->getType(), VK_LValue, E->getExprLoc());
2270*12c85518Srobert (void)LoopScope.addPrivate(PrivateVD, EmitLValue(&DRE).getAddress(*this));
2271e5dd7070Spatrick } else {
2272*12c85518Srobert (void)LoopScope.addPrivate(PrivateVD, VarEmission.getAllocatedAddress());
2273e5dd7070Spatrick }
2274e5dd7070Spatrick ++I;
2275e5dd7070Spatrick }
2276e5dd7070Spatrick // Privatize extra loop counters used in loops for ordered(n) clauses.
2277e5dd7070Spatrick for (const auto *C : S.getClausesOfKind<OMPOrderedClause>()) {
2278e5dd7070Spatrick if (!C->getNumForLoops())
2279e5dd7070Spatrick continue;
2280a9ac8606Spatrick for (unsigned I = S.getLoopsNumber(), E = C->getLoopNumIterations().size();
2281e5dd7070Spatrick I < E; ++I) {
2282e5dd7070Spatrick const auto *DRE = cast<DeclRefExpr>(C->getLoopCounter(I));
2283e5dd7070Spatrick const auto *VD = cast<VarDecl>(DRE->getDecl());
2284e5dd7070Spatrick // Override only those variables that can be captured to avoid re-emission
2285e5dd7070Spatrick // of the variables declared within the loops.
2286e5dd7070Spatrick if (DRE->refersToEnclosingVariableOrCapture()) {
2287*12c85518Srobert (void)LoopScope.addPrivate(
2288*12c85518Srobert VD, CreateMemTemp(DRE->getType(), VD->getName()));
2289e5dd7070Spatrick }
2290e5dd7070Spatrick }
2291e5dd7070Spatrick }
2292e5dd7070Spatrick }
2293e5dd7070Spatrick
emitPreCond(CodeGenFunction & CGF,const OMPLoopDirective & S,const Expr * Cond,llvm::BasicBlock * TrueBlock,llvm::BasicBlock * FalseBlock,uint64_t TrueCount)2294e5dd7070Spatrick static void emitPreCond(CodeGenFunction &CGF, const OMPLoopDirective &S,
2295e5dd7070Spatrick const Expr *Cond, llvm::BasicBlock *TrueBlock,
2296e5dd7070Spatrick llvm::BasicBlock *FalseBlock, uint64_t TrueCount) {
2297e5dd7070Spatrick if (!CGF.HaveInsertPoint())
2298e5dd7070Spatrick return;
2299e5dd7070Spatrick {
2300e5dd7070Spatrick CodeGenFunction::OMPPrivateScope PreCondScope(CGF);
2301e5dd7070Spatrick CGF.EmitOMPPrivateLoopCounters(S, PreCondScope);
2302e5dd7070Spatrick (void)PreCondScope.Privatize();
2303e5dd7070Spatrick // Get initial values of real counters.
2304e5dd7070Spatrick for (const Expr *I : S.inits()) {
2305e5dd7070Spatrick CGF.EmitIgnoredExpr(I);
2306e5dd7070Spatrick }
2307e5dd7070Spatrick }
2308e5dd7070Spatrick // Create temp loop control variables with their init values to support
2309e5dd7070Spatrick // non-rectangular loops.
2310e5dd7070Spatrick CodeGenFunction::OMPMapVars PreCondVars;
2311e5dd7070Spatrick for (const Expr *E : S.dependent_counters()) {
2312e5dd7070Spatrick if (!E)
2313e5dd7070Spatrick continue;
2314e5dd7070Spatrick assert(!E->getType().getNonReferenceType()->isRecordType() &&
2315e5dd7070Spatrick "dependent counter must not be an iterator.");
2316e5dd7070Spatrick const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
2317e5dd7070Spatrick Address CounterAddr =
2318e5dd7070Spatrick CGF.CreateMemTemp(VD->getType().getNonReferenceType());
2319e5dd7070Spatrick (void)PreCondVars.setVarAddr(CGF, VD, CounterAddr);
2320e5dd7070Spatrick }
2321e5dd7070Spatrick (void)PreCondVars.apply(CGF);
2322e5dd7070Spatrick for (const Expr *E : S.dependent_inits()) {
2323e5dd7070Spatrick if (!E)
2324e5dd7070Spatrick continue;
2325e5dd7070Spatrick CGF.EmitIgnoredExpr(E);
2326e5dd7070Spatrick }
2327e5dd7070Spatrick // Check that loop is executed at least one time.
2328e5dd7070Spatrick CGF.EmitBranchOnBoolExpr(Cond, TrueBlock, FalseBlock, TrueCount);
2329e5dd7070Spatrick PreCondVars.restore(CGF);
2330e5dd7070Spatrick }
2331e5dd7070Spatrick
EmitOMPLinearClause(const OMPLoopDirective & D,CodeGenFunction::OMPPrivateScope & PrivateScope)2332e5dd7070Spatrick void CodeGenFunction::EmitOMPLinearClause(
2333e5dd7070Spatrick const OMPLoopDirective &D, CodeGenFunction::OMPPrivateScope &PrivateScope) {
2334e5dd7070Spatrick if (!HaveInsertPoint())
2335e5dd7070Spatrick return;
2336e5dd7070Spatrick llvm::DenseSet<const VarDecl *> SIMDLCVs;
2337e5dd7070Spatrick if (isOpenMPSimdDirective(D.getDirectiveKind())) {
2338e5dd7070Spatrick const auto *LoopDirective = cast<OMPLoopDirective>(&D);
2339e5dd7070Spatrick for (const Expr *C : LoopDirective->counters()) {
2340e5dd7070Spatrick SIMDLCVs.insert(
2341e5dd7070Spatrick cast<VarDecl>(cast<DeclRefExpr>(C)->getDecl())->getCanonicalDecl());
2342e5dd7070Spatrick }
2343e5dd7070Spatrick }
2344e5dd7070Spatrick for (const auto *C : D.getClausesOfKind<OMPLinearClause>()) {
2345e5dd7070Spatrick auto CurPrivate = C->privates().begin();
2346e5dd7070Spatrick for (const Expr *E : C->varlists()) {
2347e5dd7070Spatrick const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
2348e5dd7070Spatrick const auto *PrivateVD =
2349e5dd7070Spatrick cast<VarDecl>(cast<DeclRefExpr>(*CurPrivate)->getDecl());
2350e5dd7070Spatrick if (!SIMDLCVs.count(VD->getCanonicalDecl())) {
2351e5dd7070Spatrick // Emit private VarDecl with copy init.
2352e5dd7070Spatrick EmitVarDecl(*PrivateVD);
2353*12c85518Srobert bool IsRegistered =
2354*12c85518Srobert PrivateScope.addPrivate(VD, GetAddrOfLocalVar(PrivateVD));
2355e5dd7070Spatrick assert(IsRegistered && "linear var already registered as private");
2356e5dd7070Spatrick // Silence the warning about unused variable.
2357e5dd7070Spatrick (void)IsRegistered;
2358e5dd7070Spatrick } else {
2359e5dd7070Spatrick EmitVarDecl(*PrivateVD);
2360e5dd7070Spatrick }
2361e5dd7070Spatrick ++CurPrivate;
2362e5dd7070Spatrick }
2363e5dd7070Spatrick }
2364e5dd7070Spatrick }
2365e5dd7070Spatrick
emitSimdlenSafelenClause(CodeGenFunction & CGF,const OMPExecutableDirective & D)2366e5dd7070Spatrick static void emitSimdlenSafelenClause(CodeGenFunction &CGF,
2367a9ac8606Spatrick const OMPExecutableDirective &D) {
2368e5dd7070Spatrick if (!CGF.HaveInsertPoint())
2369e5dd7070Spatrick return;
2370e5dd7070Spatrick if (const auto *C = D.getSingleClause<OMPSimdlenClause>()) {
2371e5dd7070Spatrick RValue Len = CGF.EmitAnyExpr(C->getSimdlen(), AggValueSlot::ignored(),
2372e5dd7070Spatrick /*ignoreResult=*/true);
2373e5dd7070Spatrick auto *Val = cast<llvm::ConstantInt>(Len.getScalarVal());
2374e5dd7070Spatrick CGF.LoopStack.setVectorizeWidth(Val->getZExtValue());
2375e5dd7070Spatrick // In presence of finite 'safelen', it may be unsafe to mark all
2376e5dd7070Spatrick // the memory instructions parallel, because loop-carried
2377e5dd7070Spatrick // dependences of 'safelen' iterations are possible.
2378e5dd7070Spatrick CGF.LoopStack.setParallel(!D.getSingleClause<OMPSafelenClause>());
2379e5dd7070Spatrick } else if (const auto *C = D.getSingleClause<OMPSafelenClause>()) {
2380e5dd7070Spatrick RValue Len = CGF.EmitAnyExpr(C->getSafelen(), AggValueSlot::ignored(),
2381e5dd7070Spatrick /*ignoreResult=*/true);
2382e5dd7070Spatrick auto *Val = cast<llvm::ConstantInt>(Len.getScalarVal());
2383e5dd7070Spatrick CGF.LoopStack.setVectorizeWidth(Val->getZExtValue());
2384e5dd7070Spatrick // In presence of finite 'safelen', it may be unsafe to mark all
2385e5dd7070Spatrick // the memory instructions parallel, because loop-carried
2386e5dd7070Spatrick // dependences of 'safelen' iterations are possible.
2387e5dd7070Spatrick CGF.LoopStack.setParallel(/*Enable=*/false);
2388e5dd7070Spatrick }
2389e5dd7070Spatrick }
2390e5dd7070Spatrick
EmitOMPSimdInit(const OMPLoopDirective & D)2391a9ac8606Spatrick void CodeGenFunction::EmitOMPSimdInit(const OMPLoopDirective &D) {
2392e5dd7070Spatrick // Walk clauses and process safelen/lastprivate.
2393a9ac8606Spatrick LoopStack.setParallel(/*Enable=*/true);
2394e5dd7070Spatrick LoopStack.setVectorizeEnable();
2395a9ac8606Spatrick emitSimdlenSafelenClause(*this, D);
2396ec727ea7Spatrick if (const auto *C = D.getSingleClause<OMPOrderClause>())
2397ec727ea7Spatrick if (C->getKind() == OMPC_ORDER_concurrent)
2398ec727ea7Spatrick LoopStack.setParallel(/*Enable=*/true);
2399ec727ea7Spatrick if ((D.getDirectiveKind() == OMPD_simd ||
2400ec727ea7Spatrick (getLangOpts().OpenMPSimd &&
2401ec727ea7Spatrick isOpenMPSimdDirective(D.getDirectiveKind()))) &&
2402ec727ea7Spatrick llvm::any_of(D.getClausesOfKind<OMPReductionClause>(),
2403ec727ea7Spatrick [](const OMPReductionClause *C) {
2404ec727ea7Spatrick return C->getModifier() == OMPC_REDUCTION_inscan;
2405ec727ea7Spatrick }))
2406ec727ea7Spatrick // Disable parallel access in case of prefix sum.
2407ec727ea7Spatrick LoopStack.setParallel(/*Enable=*/false);
2408e5dd7070Spatrick }
2409e5dd7070Spatrick
EmitOMPSimdFinal(const OMPLoopDirective & D,const llvm::function_ref<llvm::Value * (CodeGenFunction &)> CondGen)2410e5dd7070Spatrick void CodeGenFunction::EmitOMPSimdFinal(
2411e5dd7070Spatrick const OMPLoopDirective &D,
2412e5dd7070Spatrick const llvm::function_ref<llvm::Value *(CodeGenFunction &)> CondGen) {
2413e5dd7070Spatrick if (!HaveInsertPoint())
2414e5dd7070Spatrick return;
2415e5dd7070Spatrick llvm::BasicBlock *DoneBB = nullptr;
2416e5dd7070Spatrick auto IC = D.counters().begin();
2417e5dd7070Spatrick auto IPC = D.private_counters().begin();
2418e5dd7070Spatrick for (const Expr *F : D.finals()) {
2419e5dd7070Spatrick const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>((*IC))->getDecl());
2420e5dd7070Spatrick const auto *PrivateVD = cast<VarDecl>(cast<DeclRefExpr>((*IPC))->getDecl());
2421e5dd7070Spatrick const auto *CED = dyn_cast<OMPCapturedExprDecl>(OrigVD);
2422e5dd7070Spatrick if (LocalDeclMap.count(OrigVD) || CapturedStmtInfo->lookup(OrigVD) ||
2423e5dd7070Spatrick OrigVD->hasGlobalStorage() || CED) {
2424e5dd7070Spatrick if (!DoneBB) {
2425e5dd7070Spatrick if (llvm::Value *Cond = CondGen(*this)) {
2426e5dd7070Spatrick // If the first post-update expression is found, emit conditional
2427e5dd7070Spatrick // block if it was requested.
2428e5dd7070Spatrick llvm::BasicBlock *ThenBB = createBasicBlock(".omp.final.then");
2429e5dd7070Spatrick DoneBB = createBasicBlock(".omp.final.done");
2430e5dd7070Spatrick Builder.CreateCondBr(Cond, ThenBB, DoneBB);
2431e5dd7070Spatrick EmitBlock(ThenBB);
2432e5dd7070Spatrick }
2433e5dd7070Spatrick }
2434e5dd7070Spatrick Address OrigAddr = Address::invalid();
2435e5dd7070Spatrick if (CED) {
2436e5dd7070Spatrick OrigAddr =
2437e5dd7070Spatrick EmitLValue(CED->getInit()->IgnoreImpCasts()).getAddress(*this);
2438e5dd7070Spatrick } else {
2439e5dd7070Spatrick DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(PrivateVD),
2440e5dd7070Spatrick /*RefersToEnclosingVariableOrCapture=*/false,
2441e5dd7070Spatrick (*IPC)->getType(), VK_LValue, (*IPC)->getExprLoc());
2442e5dd7070Spatrick OrigAddr = EmitLValue(&DRE).getAddress(*this);
2443e5dd7070Spatrick }
2444e5dd7070Spatrick OMPPrivateScope VarScope(*this);
2445*12c85518Srobert VarScope.addPrivate(OrigVD, OrigAddr);
2446e5dd7070Spatrick (void)VarScope.Privatize();
2447e5dd7070Spatrick EmitIgnoredExpr(F);
2448e5dd7070Spatrick }
2449e5dd7070Spatrick ++IC;
2450e5dd7070Spatrick ++IPC;
2451e5dd7070Spatrick }
2452e5dd7070Spatrick if (DoneBB)
2453e5dd7070Spatrick EmitBlock(DoneBB, /*IsFinished=*/true);
2454e5dd7070Spatrick }
2455e5dd7070Spatrick
emitOMPLoopBodyWithStopPoint(CodeGenFunction & CGF,const OMPLoopDirective & S,CodeGenFunction::JumpDest LoopExit)2456e5dd7070Spatrick static void emitOMPLoopBodyWithStopPoint(CodeGenFunction &CGF,
2457e5dd7070Spatrick const OMPLoopDirective &S,
2458e5dd7070Spatrick CodeGenFunction::JumpDest LoopExit) {
2459e5dd7070Spatrick CGF.EmitOMPLoopBody(S, LoopExit);
2460e5dd7070Spatrick CGF.EmitStopPoint(&S);
2461e5dd7070Spatrick }
2462e5dd7070Spatrick
2463e5dd7070Spatrick /// Emit a helper variable and return corresponding lvalue.
EmitOMPHelperVar(CodeGenFunction & CGF,const DeclRefExpr * Helper)2464e5dd7070Spatrick static LValue EmitOMPHelperVar(CodeGenFunction &CGF,
2465e5dd7070Spatrick const DeclRefExpr *Helper) {
2466e5dd7070Spatrick auto VDecl = cast<VarDecl>(Helper->getDecl());
2467e5dd7070Spatrick CGF.EmitVarDecl(*VDecl);
2468e5dd7070Spatrick return CGF.EmitLValue(Helper);
2469e5dd7070Spatrick }
2470e5dd7070Spatrick
emitCommonSimdLoop(CodeGenFunction & CGF,const OMPLoopDirective & S,const RegionCodeGenTy & SimdInitGen,const RegionCodeGenTy & BodyCodeGen)2471e5dd7070Spatrick static void emitCommonSimdLoop(CodeGenFunction &CGF, const OMPLoopDirective &S,
2472e5dd7070Spatrick const RegionCodeGenTy &SimdInitGen,
2473e5dd7070Spatrick const RegionCodeGenTy &BodyCodeGen) {
2474e5dd7070Spatrick auto &&ThenGen = [&S, &SimdInitGen, &BodyCodeGen](CodeGenFunction &CGF,
2475e5dd7070Spatrick PrePostActionTy &) {
2476e5dd7070Spatrick CGOpenMPRuntime::NontemporalDeclsRAII NontemporalsRegion(CGF.CGM, S);
2477e5dd7070Spatrick CodeGenFunction::OMPLocalDeclMapRAII Scope(CGF);
2478e5dd7070Spatrick SimdInitGen(CGF);
2479e5dd7070Spatrick
2480e5dd7070Spatrick BodyCodeGen(CGF);
2481e5dd7070Spatrick };
2482e5dd7070Spatrick auto &&ElseGen = [&BodyCodeGen](CodeGenFunction &CGF, PrePostActionTy &) {
2483e5dd7070Spatrick CodeGenFunction::OMPLocalDeclMapRAII Scope(CGF);
2484e5dd7070Spatrick CGF.LoopStack.setVectorizeEnable(/*Enable=*/false);
2485e5dd7070Spatrick
2486e5dd7070Spatrick BodyCodeGen(CGF);
2487e5dd7070Spatrick };
2488e5dd7070Spatrick const Expr *IfCond = nullptr;
2489ec727ea7Spatrick if (isOpenMPSimdDirective(S.getDirectiveKind())) {
2490e5dd7070Spatrick for (const auto *C : S.getClausesOfKind<OMPIfClause>()) {
2491e5dd7070Spatrick if (CGF.getLangOpts().OpenMP >= 50 &&
2492e5dd7070Spatrick (C->getNameModifier() == OMPD_unknown ||
2493e5dd7070Spatrick C->getNameModifier() == OMPD_simd)) {
2494e5dd7070Spatrick IfCond = C->getCondition();
2495e5dd7070Spatrick break;
2496e5dd7070Spatrick }
2497e5dd7070Spatrick }
2498ec727ea7Spatrick }
2499e5dd7070Spatrick if (IfCond) {
2500e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitIfClause(CGF, IfCond, ThenGen, ElseGen);
2501e5dd7070Spatrick } else {
2502e5dd7070Spatrick RegionCodeGenTy ThenRCG(ThenGen);
2503e5dd7070Spatrick ThenRCG(CGF);
2504e5dd7070Spatrick }
2505e5dd7070Spatrick }
2506e5dd7070Spatrick
emitOMPSimdRegion(CodeGenFunction & CGF,const OMPLoopDirective & S,PrePostActionTy & Action)2507e5dd7070Spatrick static void emitOMPSimdRegion(CodeGenFunction &CGF, const OMPLoopDirective &S,
2508e5dd7070Spatrick PrePostActionTy &Action) {
2509e5dd7070Spatrick Action.Enter(CGF);
2510e5dd7070Spatrick assert(isOpenMPSimdDirective(S.getDirectiveKind()) &&
2511e5dd7070Spatrick "Expected simd directive");
2512e5dd7070Spatrick OMPLoopScope PreInitScope(CGF, S);
2513e5dd7070Spatrick // if (PreCond) {
2514e5dd7070Spatrick // for (IV in 0..LastIteration) BODY;
2515e5dd7070Spatrick // <Final counter/linear vars updates>;
2516e5dd7070Spatrick // }
2517e5dd7070Spatrick //
2518e5dd7070Spatrick if (isOpenMPDistributeDirective(S.getDirectiveKind()) ||
2519e5dd7070Spatrick isOpenMPWorksharingDirective(S.getDirectiveKind()) ||
2520e5dd7070Spatrick isOpenMPTaskLoopDirective(S.getDirectiveKind())) {
2521e5dd7070Spatrick (void)EmitOMPHelperVar(CGF, cast<DeclRefExpr>(S.getLowerBoundVariable()));
2522e5dd7070Spatrick (void)EmitOMPHelperVar(CGF, cast<DeclRefExpr>(S.getUpperBoundVariable()));
2523e5dd7070Spatrick }
2524e5dd7070Spatrick
2525e5dd7070Spatrick // Emit: if (PreCond) - begin.
2526e5dd7070Spatrick // If the condition constant folds and can be elided, avoid emitting the
2527e5dd7070Spatrick // whole loop.
2528e5dd7070Spatrick bool CondConstant;
2529e5dd7070Spatrick llvm::BasicBlock *ContBlock = nullptr;
2530e5dd7070Spatrick if (CGF.ConstantFoldsToSimpleInteger(S.getPreCond(), CondConstant)) {
2531e5dd7070Spatrick if (!CondConstant)
2532e5dd7070Spatrick return;
2533e5dd7070Spatrick } else {
2534e5dd7070Spatrick llvm::BasicBlock *ThenBlock = CGF.createBasicBlock("simd.if.then");
2535e5dd7070Spatrick ContBlock = CGF.createBasicBlock("simd.if.end");
2536e5dd7070Spatrick emitPreCond(CGF, S, S.getPreCond(), ThenBlock, ContBlock,
2537e5dd7070Spatrick CGF.getProfileCount(&S));
2538e5dd7070Spatrick CGF.EmitBlock(ThenBlock);
2539e5dd7070Spatrick CGF.incrementProfileCounter(&S);
2540e5dd7070Spatrick }
2541e5dd7070Spatrick
2542e5dd7070Spatrick // Emit the loop iteration variable.
2543e5dd7070Spatrick const Expr *IVExpr = S.getIterationVariable();
2544e5dd7070Spatrick const auto *IVDecl = cast<VarDecl>(cast<DeclRefExpr>(IVExpr)->getDecl());
2545e5dd7070Spatrick CGF.EmitVarDecl(*IVDecl);
2546e5dd7070Spatrick CGF.EmitIgnoredExpr(S.getInit());
2547e5dd7070Spatrick
2548e5dd7070Spatrick // Emit the iterations count variable.
2549e5dd7070Spatrick // If it is not a variable, Sema decided to calculate iterations count on
2550e5dd7070Spatrick // each iteration (e.g., it is foldable into a constant).
2551e5dd7070Spatrick if (const auto *LIExpr = dyn_cast<DeclRefExpr>(S.getLastIteration())) {
2552e5dd7070Spatrick CGF.EmitVarDecl(*cast<VarDecl>(LIExpr->getDecl()));
2553e5dd7070Spatrick // Emit calculation of the iterations count.
2554e5dd7070Spatrick CGF.EmitIgnoredExpr(S.getCalcLastIteration());
2555e5dd7070Spatrick }
2556e5dd7070Spatrick
2557e5dd7070Spatrick emitAlignedClause(CGF, S);
2558e5dd7070Spatrick (void)CGF.EmitOMPLinearClauseInit(S);
2559e5dd7070Spatrick {
2560e5dd7070Spatrick CodeGenFunction::OMPPrivateScope LoopScope(CGF);
2561e5dd7070Spatrick CGF.EmitOMPPrivateLoopCounters(S, LoopScope);
2562e5dd7070Spatrick CGF.EmitOMPLinearClause(S, LoopScope);
2563e5dd7070Spatrick CGF.EmitOMPPrivateClause(S, LoopScope);
2564e5dd7070Spatrick CGF.EmitOMPReductionClauseInit(S, LoopScope);
2565e5dd7070Spatrick CGOpenMPRuntime::LastprivateConditionalRAII LPCRegion(
2566e5dd7070Spatrick CGF, S, CGF.EmitLValue(S.getIterationVariable()));
2567e5dd7070Spatrick bool HasLastprivateClause = CGF.EmitOMPLastprivateClauseInit(S, LoopScope);
2568e5dd7070Spatrick (void)LoopScope.Privatize();
2569e5dd7070Spatrick if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()))
2570e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().adjustTargetSpecificDataForLambdas(CGF, S);
2571e5dd7070Spatrick
2572e5dd7070Spatrick emitCommonSimdLoop(
2573e5dd7070Spatrick CGF, S,
2574e5dd7070Spatrick [&S](CodeGenFunction &CGF, PrePostActionTy &) {
2575e5dd7070Spatrick CGF.EmitOMPSimdInit(S);
2576e5dd7070Spatrick },
2577e5dd7070Spatrick [&S, &LoopScope](CodeGenFunction &CGF, PrePostActionTy &) {
2578e5dd7070Spatrick CGF.EmitOMPInnerLoop(
2579e5dd7070Spatrick S, LoopScope.requiresCleanups(), S.getCond(), S.getInc(),
2580e5dd7070Spatrick [&S](CodeGenFunction &CGF) {
2581ec727ea7Spatrick emitOMPLoopBodyWithStopPoint(CGF, S,
2582ec727ea7Spatrick CodeGenFunction::JumpDest());
2583e5dd7070Spatrick },
2584e5dd7070Spatrick [](CodeGenFunction &) {});
2585e5dd7070Spatrick });
2586e5dd7070Spatrick CGF.EmitOMPSimdFinal(S, [](CodeGenFunction &) { return nullptr; });
2587e5dd7070Spatrick // Emit final copy of the lastprivate variables at the end of loops.
2588e5dd7070Spatrick if (HasLastprivateClause)
2589e5dd7070Spatrick CGF.EmitOMPLastprivateClauseFinal(S, /*NoFinals=*/true);
2590e5dd7070Spatrick CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_simd);
2591e5dd7070Spatrick emitPostUpdateForReductionClause(CGF, S,
2592e5dd7070Spatrick [](CodeGenFunction &) { return nullptr; });
2593*12c85518Srobert LoopScope.restoreMap();
2594e5dd7070Spatrick CGF.EmitOMPLinearClauseFinal(S, [](CodeGenFunction &) { return nullptr; });
2595*12c85518Srobert }
2596e5dd7070Spatrick // Emit: if (PreCond) - end.
2597e5dd7070Spatrick if (ContBlock) {
2598e5dd7070Spatrick CGF.EmitBranch(ContBlock);
2599e5dd7070Spatrick CGF.EmitBlock(ContBlock, true);
2600e5dd7070Spatrick }
2601e5dd7070Spatrick }
2602e5dd7070Spatrick
isSupportedByOpenMPIRBuilder(const OMPSimdDirective & S)2603*12c85518Srobert static bool isSupportedByOpenMPIRBuilder(const OMPSimdDirective &S) {
2604*12c85518Srobert // Check for unsupported clauses
2605*12c85518Srobert for (OMPClause *C : S.clauses()) {
2606*12c85518Srobert // Currently only order, simdlen and safelen clauses are supported
2607*12c85518Srobert if (!(isa<OMPSimdlenClause>(C) || isa<OMPSafelenClause>(C) ||
2608*12c85518Srobert isa<OMPOrderClause>(C) || isa<OMPAlignedClause>(C)))
2609*12c85518Srobert return false;
2610*12c85518Srobert }
2611*12c85518Srobert
2612*12c85518Srobert // Check if we have a statement with the ordered directive.
2613*12c85518Srobert // Visit the statement hierarchy to find a compound statement
2614*12c85518Srobert // with a ordered directive in it.
2615*12c85518Srobert if (const auto *CanonLoop = dyn_cast<OMPCanonicalLoop>(S.getRawStmt())) {
2616*12c85518Srobert if (const Stmt *SyntacticalLoop = CanonLoop->getLoopStmt()) {
2617*12c85518Srobert for (const Stmt *SubStmt : SyntacticalLoop->children()) {
2618*12c85518Srobert if (!SubStmt)
2619*12c85518Srobert continue;
2620*12c85518Srobert if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(SubStmt)) {
2621*12c85518Srobert for (const Stmt *CSSubStmt : CS->children()) {
2622*12c85518Srobert if (!CSSubStmt)
2623*12c85518Srobert continue;
2624*12c85518Srobert if (isa<OMPOrderedDirective>(CSSubStmt)) {
2625*12c85518Srobert return false;
2626*12c85518Srobert }
2627*12c85518Srobert }
2628*12c85518Srobert }
2629*12c85518Srobert }
2630*12c85518Srobert }
2631*12c85518Srobert }
2632*12c85518Srobert return true;
2633*12c85518Srobert }
2634*12c85518Srobert static llvm::MapVector<llvm::Value *, llvm::Value *>
GetAlignedMapping(const OMPSimdDirective & S,CodeGenFunction & CGF)2635*12c85518Srobert GetAlignedMapping(const OMPSimdDirective &S, CodeGenFunction &CGF) {
2636*12c85518Srobert llvm::MapVector<llvm::Value *, llvm::Value *> AlignedVars;
2637*12c85518Srobert for (const auto *Clause : S.getClausesOfKind<OMPAlignedClause>()) {
2638*12c85518Srobert llvm::APInt ClauseAlignment(64, 0);
2639*12c85518Srobert if (const Expr *AlignmentExpr = Clause->getAlignment()) {
2640*12c85518Srobert auto *AlignmentCI =
2641*12c85518Srobert cast<llvm::ConstantInt>(CGF.EmitScalarExpr(AlignmentExpr));
2642*12c85518Srobert ClauseAlignment = AlignmentCI->getValue();
2643*12c85518Srobert }
2644*12c85518Srobert for (const Expr *E : Clause->varlists()) {
2645*12c85518Srobert llvm::APInt Alignment(ClauseAlignment);
2646*12c85518Srobert if (Alignment == 0) {
2647*12c85518Srobert // OpenMP [2.8.1, Description]
2648*12c85518Srobert // If no optional parameter is specified, implementation-defined default
2649*12c85518Srobert // alignments for SIMD instructions on the target platforms are assumed.
2650*12c85518Srobert Alignment =
2651*12c85518Srobert CGF.getContext()
2652*12c85518Srobert .toCharUnitsFromBits(CGF.getContext().getOpenMPDefaultSimdAlign(
2653*12c85518Srobert E->getType()->getPointeeType()))
2654*12c85518Srobert .getQuantity();
2655*12c85518Srobert }
2656*12c85518Srobert assert((Alignment == 0 || Alignment.isPowerOf2()) &&
2657*12c85518Srobert "alignment is not power of 2");
2658*12c85518Srobert llvm::Value *PtrValue = CGF.EmitScalarExpr(E);
2659*12c85518Srobert AlignedVars[PtrValue] = CGF.Builder.getInt64(Alignment.getSExtValue());
2660*12c85518Srobert }
2661*12c85518Srobert }
2662*12c85518Srobert return AlignedVars;
2663*12c85518Srobert }
2664*12c85518Srobert
EmitOMPSimdDirective(const OMPSimdDirective & S)2665e5dd7070Spatrick void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) {
2666*12c85518Srobert bool UseOMPIRBuilder =
2667*12c85518Srobert CGM.getLangOpts().OpenMPIRBuilder && isSupportedByOpenMPIRBuilder(S);
2668*12c85518Srobert if (UseOMPIRBuilder) {
2669*12c85518Srobert auto &&CodeGenIRBuilder = [this, &S, UseOMPIRBuilder](CodeGenFunction &CGF,
2670*12c85518Srobert PrePostActionTy &) {
2671*12c85518Srobert // Use the OpenMPIRBuilder if enabled.
2672*12c85518Srobert if (UseOMPIRBuilder) {
2673*12c85518Srobert llvm::MapVector<llvm::Value *, llvm::Value *> AlignedVars =
2674*12c85518Srobert GetAlignedMapping(S, CGF);
2675*12c85518Srobert // Emit the associated statement and get its loop representation.
2676*12c85518Srobert const Stmt *Inner = S.getRawStmt();
2677*12c85518Srobert llvm::CanonicalLoopInfo *CLI =
2678*12c85518Srobert EmitOMPCollapsedCanonicalLoopNest(Inner, 1);
2679*12c85518Srobert
2680*12c85518Srobert llvm::OpenMPIRBuilder &OMPBuilder =
2681*12c85518Srobert CGM.getOpenMPRuntime().getOMPBuilder();
2682*12c85518Srobert // Add SIMD specific metadata
2683*12c85518Srobert llvm::ConstantInt *Simdlen = nullptr;
2684*12c85518Srobert if (const auto *C = S.getSingleClause<OMPSimdlenClause>()) {
2685*12c85518Srobert RValue Len =
2686*12c85518Srobert this->EmitAnyExpr(C->getSimdlen(), AggValueSlot::ignored(),
2687*12c85518Srobert /*ignoreResult=*/true);
2688*12c85518Srobert auto *Val = cast<llvm::ConstantInt>(Len.getScalarVal());
2689*12c85518Srobert Simdlen = Val;
2690*12c85518Srobert }
2691*12c85518Srobert llvm::ConstantInt *Safelen = nullptr;
2692*12c85518Srobert if (const auto *C = S.getSingleClause<OMPSafelenClause>()) {
2693*12c85518Srobert RValue Len =
2694*12c85518Srobert this->EmitAnyExpr(C->getSafelen(), AggValueSlot::ignored(),
2695*12c85518Srobert /*ignoreResult=*/true);
2696*12c85518Srobert auto *Val = cast<llvm::ConstantInt>(Len.getScalarVal());
2697*12c85518Srobert Safelen = Val;
2698*12c85518Srobert }
2699*12c85518Srobert llvm::omp::OrderKind Order = llvm::omp::OrderKind::OMP_ORDER_unknown;
2700*12c85518Srobert if (const auto *C = S.getSingleClause<OMPOrderClause>()) {
2701*12c85518Srobert if (C->getKind() == OpenMPOrderClauseKind ::OMPC_ORDER_concurrent) {
2702*12c85518Srobert Order = llvm::omp::OrderKind::OMP_ORDER_concurrent;
2703*12c85518Srobert }
2704*12c85518Srobert }
2705*12c85518Srobert // Add simd metadata to the collapsed loop. Do not generate
2706*12c85518Srobert // another loop for if clause. Support for if clause is done earlier.
2707*12c85518Srobert OMPBuilder.applySimd(CLI, AlignedVars,
2708*12c85518Srobert /*IfCond*/ nullptr, Order, Simdlen, Safelen);
2709*12c85518Srobert return;
2710*12c85518Srobert }
2711*12c85518Srobert };
2712*12c85518Srobert {
2713*12c85518Srobert auto LPCRegion =
2714*12c85518Srobert CGOpenMPRuntime::LastprivateConditionalRAII::disable(*this, S);
2715*12c85518Srobert OMPLexicalScope Scope(*this, S, OMPD_unknown);
2716*12c85518Srobert CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_simd,
2717*12c85518Srobert CodeGenIRBuilder);
2718*12c85518Srobert }
2719*12c85518Srobert return;
2720*12c85518Srobert }
2721*12c85518Srobert
2722ec727ea7Spatrick ParentLoopDirectiveForScanRegion ScanRegion(*this, S);
2723ec727ea7Spatrick OMPFirstScanLoop = true;
2724e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
2725e5dd7070Spatrick emitOMPSimdRegion(CGF, S, Action);
2726e5dd7070Spatrick };
2727ec727ea7Spatrick {
2728ec727ea7Spatrick auto LPCRegion =
2729ec727ea7Spatrick CGOpenMPRuntime::LastprivateConditionalRAII::disable(*this, S);
2730e5dd7070Spatrick OMPLexicalScope Scope(*this, S, OMPD_unknown);
2731e5dd7070Spatrick CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_simd, CodeGen);
2732e5dd7070Spatrick }
2733ec727ea7Spatrick // Check for outer lastprivate conditional update.
2734ec727ea7Spatrick checkForLastprivateConditionalUpdate(*this, S);
2735ec727ea7Spatrick }
2736e5dd7070Spatrick
EmitOMPTileDirective(const OMPTileDirective & S)2737a9ac8606Spatrick void CodeGenFunction::EmitOMPTileDirective(const OMPTileDirective &S) {
2738a9ac8606Spatrick // Emit the de-sugared statement.
2739a9ac8606Spatrick OMPTransformDirectiveScopeRAII TileScope(*this, &S);
2740a9ac8606Spatrick EmitStmt(S.getTransformedStmt());
2741a9ac8606Spatrick }
2742a9ac8606Spatrick
EmitOMPUnrollDirective(const OMPUnrollDirective & S)2743a9ac8606Spatrick void CodeGenFunction::EmitOMPUnrollDirective(const OMPUnrollDirective &S) {
2744*12c85518Srobert bool UseOMPIRBuilder = CGM.getLangOpts().OpenMPIRBuilder;
2745*12c85518Srobert
2746*12c85518Srobert if (UseOMPIRBuilder) {
2747*12c85518Srobert auto DL = SourceLocToDebugLoc(S.getBeginLoc());
2748*12c85518Srobert const Stmt *Inner = S.getRawStmt();
2749*12c85518Srobert
2750*12c85518Srobert // Consume nested loop. Clear the entire remaining loop stack because a
2751*12c85518Srobert // fully unrolled loop is non-transformable. For partial unrolling the
2752*12c85518Srobert // generated outer loop is pushed back to the stack.
2753*12c85518Srobert llvm::CanonicalLoopInfo *CLI = EmitOMPCollapsedCanonicalLoopNest(Inner, 1);
2754*12c85518Srobert OMPLoopNestStack.clear();
2755*12c85518Srobert
2756*12c85518Srobert llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
2757*12c85518Srobert
2758*12c85518Srobert bool NeedsUnrolledCLI = ExpectedOMPLoopDepth >= 1;
2759*12c85518Srobert llvm::CanonicalLoopInfo *UnrolledCLI = nullptr;
2760*12c85518Srobert
2761*12c85518Srobert if (S.hasClausesOfKind<OMPFullClause>()) {
2762*12c85518Srobert assert(ExpectedOMPLoopDepth == 0);
2763*12c85518Srobert OMPBuilder.unrollLoopFull(DL, CLI);
2764*12c85518Srobert } else if (auto *PartialClause = S.getSingleClause<OMPPartialClause>()) {
2765*12c85518Srobert uint64_t Factor = 0;
2766*12c85518Srobert if (Expr *FactorExpr = PartialClause->getFactor()) {
2767*12c85518Srobert Factor = FactorExpr->EvaluateKnownConstInt(getContext()).getZExtValue();
2768*12c85518Srobert assert(Factor >= 1 && "Only positive factors are valid");
2769*12c85518Srobert }
2770*12c85518Srobert OMPBuilder.unrollLoopPartial(DL, CLI, Factor,
2771*12c85518Srobert NeedsUnrolledCLI ? &UnrolledCLI : nullptr);
2772*12c85518Srobert } else {
2773*12c85518Srobert OMPBuilder.unrollLoopHeuristic(DL, CLI);
2774*12c85518Srobert }
2775*12c85518Srobert
2776*12c85518Srobert assert((!NeedsUnrolledCLI || UnrolledCLI) &&
2777*12c85518Srobert "NeedsUnrolledCLI implies UnrolledCLI to be set");
2778*12c85518Srobert if (UnrolledCLI)
2779*12c85518Srobert OMPLoopNestStack.push_back(UnrolledCLI);
2780*12c85518Srobert
2781*12c85518Srobert return;
2782*12c85518Srobert }
2783*12c85518Srobert
2784a9ac8606Spatrick // This function is only called if the unrolled loop is not consumed by any
2785a9ac8606Spatrick // other loop-associated construct. Such a loop-associated construct will have
2786a9ac8606Spatrick // used the transformed AST.
2787a9ac8606Spatrick
2788a9ac8606Spatrick // Set the unroll metadata for the next emitted loop.
2789a9ac8606Spatrick LoopStack.setUnrollState(LoopAttributes::Enable);
2790a9ac8606Spatrick
2791a9ac8606Spatrick if (S.hasClausesOfKind<OMPFullClause>()) {
2792a9ac8606Spatrick LoopStack.setUnrollState(LoopAttributes::Full);
2793a9ac8606Spatrick } else if (auto *PartialClause = S.getSingleClause<OMPPartialClause>()) {
2794a9ac8606Spatrick if (Expr *FactorExpr = PartialClause->getFactor()) {
2795a9ac8606Spatrick uint64_t Factor =
2796a9ac8606Spatrick FactorExpr->EvaluateKnownConstInt(getContext()).getZExtValue();
2797a9ac8606Spatrick assert(Factor >= 1 && "Only positive factors are valid");
2798a9ac8606Spatrick LoopStack.setUnrollCount(Factor);
2799a9ac8606Spatrick }
2800a9ac8606Spatrick }
2801a9ac8606Spatrick
2802a9ac8606Spatrick EmitStmt(S.getAssociatedStmt());
2803a9ac8606Spatrick }
2804a9ac8606Spatrick
EmitOMPOuterLoop(bool DynamicOrOrdered,bool IsMonotonic,const OMPLoopDirective & S,CodeGenFunction::OMPPrivateScope & LoopScope,const CodeGenFunction::OMPLoopArguments & LoopArgs,const CodeGenFunction::CodeGenLoopTy & CodeGenLoop,const CodeGenFunction::CodeGenOrderedTy & CodeGenOrdered)2805e5dd7070Spatrick void CodeGenFunction::EmitOMPOuterLoop(
2806e5dd7070Spatrick bool DynamicOrOrdered, bool IsMonotonic, const OMPLoopDirective &S,
2807e5dd7070Spatrick CodeGenFunction::OMPPrivateScope &LoopScope,
2808e5dd7070Spatrick const CodeGenFunction::OMPLoopArguments &LoopArgs,
2809e5dd7070Spatrick const CodeGenFunction::CodeGenLoopTy &CodeGenLoop,
2810e5dd7070Spatrick const CodeGenFunction::CodeGenOrderedTy &CodeGenOrdered) {
2811e5dd7070Spatrick CGOpenMPRuntime &RT = CGM.getOpenMPRuntime();
2812e5dd7070Spatrick
2813e5dd7070Spatrick const Expr *IVExpr = S.getIterationVariable();
2814e5dd7070Spatrick const unsigned IVSize = getContext().getTypeSize(IVExpr->getType());
2815e5dd7070Spatrick const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation();
2816e5dd7070Spatrick
2817e5dd7070Spatrick JumpDest LoopExit = getJumpDestInCurrentScope("omp.dispatch.end");
2818e5dd7070Spatrick
2819e5dd7070Spatrick // Start the loop with a block that tests the condition.
2820e5dd7070Spatrick llvm::BasicBlock *CondBlock = createBasicBlock("omp.dispatch.cond");
2821e5dd7070Spatrick EmitBlock(CondBlock);
2822e5dd7070Spatrick const SourceRange R = S.getSourceRange();
2823a9ac8606Spatrick OMPLoopNestStack.clear();
2824e5dd7070Spatrick LoopStack.push(CondBlock, SourceLocToDebugLoc(R.getBegin()),
2825e5dd7070Spatrick SourceLocToDebugLoc(R.getEnd()));
2826e5dd7070Spatrick
2827e5dd7070Spatrick llvm::Value *BoolCondVal = nullptr;
2828e5dd7070Spatrick if (!DynamicOrOrdered) {
2829e5dd7070Spatrick // UB = min(UB, GlobalUB) or
2830e5dd7070Spatrick // UB = min(UB, PrevUB) for combined loop sharing constructs (e.g.
2831e5dd7070Spatrick // 'distribute parallel for')
2832e5dd7070Spatrick EmitIgnoredExpr(LoopArgs.EUB);
2833e5dd7070Spatrick // IV = LB
2834e5dd7070Spatrick EmitIgnoredExpr(LoopArgs.Init);
2835e5dd7070Spatrick // IV < UB
2836e5dd7070Spatrick BoolCondVal = EvaluateExprAsBool(LoopArgs.Cond);
2837e5dd7070Spatrick } else {
2838e5dd7070Spatrick BoolCondVal =
2839e5dd7070Spatrick RT.emitForNext(*this, S.getBeginLoc(), IVSize, IVSigned, LoopArgs.IL,
2840e5dd7070Spatrick LoopArgs.LB, LoopArgs.UB, LoopArgs.ST);
2841e5dd7070Spatrick }
2842e5dd7070Spatrick
2843e5dd7070Spatrick // If there are any cleanups between here and the loop-exit scope,
2844e5dd7070Spatrick // create a block to stage a loop exit along.
2845e5dd7070Spatrick llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
2846e5dd7070Spatrick if (LoopScope.requiresCleanups())
2847e5dd7070Spatrick ExitBlock = createBasicBlock("omp.dispatch.cleanup");
2848e5dd7070Spatrick
2849e5dd7070Spatrick llvm::BasicBlock *LoopBody = createBasicBlock("omp.dispatch.body");
2850e5dd7070Spatrick Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock);
2851e5dd7070Spatrick if (ExitBlock != LoopExit.getBlock()) {
2852e5dd7070Spatrick EmitBlock(ExitBlock);
2853e5dd7070Spatrick EmitBranchThroughCleanup(LoopExit);
2854e5dd7070Spatrick }
2855e5dd7070Spatrick EmitBlock(LoopBody);
2856e5dd7070Spatrick
2857e5dd7070Spatrick // Emit "IV = LB" (in case of static schedule, we have already calculated new
2858e5dd7070Spatrick // LB for loop condition and emitted it above).
2859e5dd7070Spatrick if (DynamicOrOrdered)
2860e5dd7070Spatrick EmitIgnoredExpr(LoopArgs.Init);
2861e5dd7070Spatrick
2862e5dd7070Spatrick // Create a block for the increment.
2863e5dd7070Spatrick JumpDest Continue = getJumpDestInCurrentScope("omp.dispatch.inc");
2864e5dd7070Spatrick BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
2865e5dd7070Spatrick
2866e5dd7070Spatrick emitCommonSimdLoop(
2867e5dd7070Spatrick *this, S,
2868e5dd7070Spatrick [&S, IsMonotonic](CodeGenFunction &CGF, PrePostActionTy &) {
2869e5dd7070Spatrick // Generate !llvm.loop.parallel metadata for loads and stores for loops
2870e5dd7070Spatrick // with dynamic/guided scheduling and without ordered clause.
2871ec727ea7Spatrick if (!isOpenMPSimdDirective(S.getDirectiveKind())) {
2872e5dd7070Spatrick CGF.LoopStack.setParallel(!IsMonotonic);
2873ec727ea7Spatrick if (const auto *C = S.getSingleClause<OMPOrderClause>())
2874ec727ea7Spatrick if (C->getKind() == OMPC_ORDER_concurrent)
2875ec727ea7Spatrick CGF.LoopStack.setParallel(/*Enable=*/true);
2876ec727ea7Spatrick } else {
2877a9ac8606Spatrick CGF.EmitOMPSimdInit(S);
2878ec727ea7Spatrick }
2879e5dd7070Spatrick },
2880e5dd7070Spatrick [&S, &LoopArgs, LoopExit, &CodeGenLoop, IVSize, IVSigned, &CodeGenOrdered,
2881e5dd7070Spatrick &LoopScope](CodeGenFunction &CGF, PrePostActionTy &) {
2882e5dd7070Spatrick SourceLocation Loc = S.getBeginLoc();
2883e5dd7070Spatrick // when 'distribute' is not combined with a 'for':
2884e5dd7070Spatrick // while (idx <= UB) { BODY; ++idx; }
2885e5dd7070Spatrick // when 'distribute' is combined with a 'for'
2886e5dd7070Spatrick // (e.g. 'distribute parallel for')
2887e5dd7070Spatrick // while (idx <= UB) { <CodeGen rest of pragma>; idx += ST; }
2888e5dd7070Spatrick CGF.EmitOMPInnerLoop(
2889e5dd7070Spatrick S, LoopScope.requiresCleanups(), LoopArgs.Cond, LoopArgs.IncExpr,
2890e5dd7070Spatrick [&S, LoopExit, &CodeGenLoop](CodeGenFunction &CGF) {
2891e5dd7070Spatrick CodeGenLoop(CGF, S, LoopExit);
2892e5dd7070Spatrick },
2893e5dd7070Spatrick [IVSize, IVSigned, Loc, &CodeGenOrdered](CodeGenFunction &CGF) {
2894e5dd7070Spatrick CodeGenOrdered(CGF, Loc, IVSize, IVSigned);
2895e5dd7070Spatrick });
2896e5dd7070Spatrick });
2897e5dd7070Spatrick
2898e5dd7070Spatrick EmitBlock(Continue.getBlock());
2899e5dd7070Spatrick BreakContinueStack.pop_back();
2900e5dd7070Spatrick if (!DynamicOrOrdered) {
2901e5dd7070Spatrick // Emit "LB = LB + Stride", "UB = UB + Stride".
2902e5dd7070Spatrick EmitIgnoredExpr(LoopArgs.NextLB);
2903e5dd7070Spatrick EmitIgnoredExpr(LoopArgs.NextUB);
2904e5dd7070Spatrick }
2905e5dd7070Spatrick
2906e5dd7070Spatrick EmitBranch(CondBlock);
2907a9ac8606Spatrick OMPLoopNestStack.clear();
2908e5dd7070Spatrick LoopStack.pop();
2909e5dd7070Spatrick // Emit the fall-through block.
2910e5dd7070Spatrick EmitBlock(LoopExit.getBlock());
2911e5dd7070Spatrick
2912e5dd7070Spatrick // Tell the runtime we are done.
2913e5dd7070Spatrick auto &&CodeGen = [DynamicOrOrdered, &S](CodeGenFunction &CGF) {
2914e5dd7070Spatrick if (!DynamicOrOrdered)
2915e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getEndLoc(),
2916e5dd7070Spatrick S.getDirectiveKind());
2917e5dd7070Spatrick };
2918e5dd7070Spatrick OMPCancelStack.emitExit(*this, S.getDirectiveKind(), CodeGen);
2919e5dd7070Spatrick }
2920e5dd7070Spatrick
EmitOMPForOuterLoop(const OpenMPScheduleTy & ScheduleKind,bool IsMonotonic,const OMPLoopDirective & S,OMPPrivateScope & LoopScope,bool Ordered,const OMPLoopArguments & LoopArgs,const CodeGenDispatchBoundsTy & CGDispatchBounds)2921e5dd7070Spatrick void CodeGenFunction::EmitOMPForOuterLoop(
2922e5dd7070Spatrick const OpenMPScheduleTy &ScheduleKind, bool IsMonotonic,
2923e5dd7070Spatrick const OMPLoopDirective &S, OMPPrivateScope &LoopScope, bool Ordered,
2924e5dd7070Spatrick const OMPLoopArguments &LoopArgs,
2925e5dd7070Spatrick const CodeGenDispatchBoundsTy &CGDispatchBounds) {
2926e5dd7070Spatrick CGOpenMPRuntime &RT = CGM.getOpenMPRuntime();
2927e5dd7070Spatrick
2928e5dd7070Spatrick // Dynamic scheduling of the outer loop (dynamic, guided, auto, runtime).
2929*12c85518Srobert const bool DynamicOrOrdered = Ordered || RT.isDynamic(ScheduleKind.Schedule);
2930e5dd7070Spatrick
2931*12c85518Srobert assert((Ordered || !RT.isStaticNonchunked(ScheduleKind.Schedule,
2932e5dd7070Spatrick LoopArgs.Chunk != nullptr)) &&
2933e5dd7070Spatrick "static non-chunked schedule does not need outer loop");
2934e5dd7070Spatrick
2935e5dd7070Spatrick // Emit outer loop.
2936e5dd7070Spatrick //
2937e5dd7070Spatrick // OpenMP [2.7.1, Loop Construct, Description, table 2-1]
2938e5dd7070Spatrick // When schedule(dynamic,chunk_size) is specified, the iterations are
2939e5dd7070Spatrick // distributed to threads in the team in chunks as the threads request them.
2940e5dd7070Spatrick // Each thread executes a chunk of iterations, then requests another chunk,
2941e5dd7070Spatrick // until no chunks remain to be distributed. Each chunk contains chunk_size
2942e5dd7070Spatrick // iterations, except for the last chunk to be distributed, which may have
2943e5dd7070Spatrick // fewer iterations. When no chunk_size is specified, it defaults to 1.
2944e5dd7070Spatrick //
2945e5dd7070Spatrick // When schedule(guided,chunk_size) is specified, the iterations are assigned
2946e5dd7070Spatrick // to threads in the team in chunks as the executing threads request them.
2947e5dd7070Spatrick // Each thread executes a chunk of iterations, then requests another chunk,
2948e5dd7070Spatrick // until no chunks remain to be assigned. For a chunk_size of 1, the size of
2949e5dd7070Spatrick // each chunk is proportional to the number of unassigned iterations divided
2950e5dd7070Spatrick // by the number of threads in the team, decreasing to 1. For a chunk_size
2951e5dd7070Spatrick // with value k (greater than 1), the size of each chunk is determined in the
2952e5dd7070Spatrick // same way, with the restriction that the chunks do not contain fewer than k
2953e5dd7070Spatrick // iterations (except for the last chunk to be assigned, which may have fewer
2954e5dd7070Spatrick // than k iterations).
2955e5dd7070Spatrick //
2956e5dd7070Spatrick // When schedule(auto) is specified, the decision regarding scheduling is
2957e5dd7070Spatrick // delegated to the compiler and/or runtime system. The programmer gives the
2958e5dd7070Spatrick // implementation the freedom to choose any possible mapping of iterations to
2959e5dd7070Spatrick // threads in the team.
2960e5dd7070Spatrick //
2961e5dd7070Spatrick // When schedule(runtime) is specified, the decision regarding scheduling is
2962e5dd7070Spatrick // deferred until run time, and the schedule and chunk size are taken from the
2963e5dd7070Spatrick // run-sched-var ICV. If the ICV is set to auto, the schedule is
2964e5dd7070Spatrick // implementation defined
2965e5dd7070Spatrick //
2966e5dd7070Spatrick // while(__kmpc_dispatch_next(&LB, &UB)) {
2967e5dd7070Spatrick // idx = LB;
2968e5dd7070Spatrick // while (idx <= UB) { BODY; ++idx;
2969e5dd7070Spatrick // __kmpc_dispatch_fini_(4|8)[u](); // For ordered loops only.
2970e5dd7070Spatrick // } // inner loop
2971e5dd7070Spatrick // }
2972e5dd7070Spatrick //
2973e5dd7070Spatrick // OpenMP [2.7.1, Loop Construct, Description, table 2-1]
2974e5dd7070Spatrick // When schedule(static, chunk_size) is specified, iterations are divided into
2975e5dd7070Spatrick // chunks of size chunk_size, and the chunks are assigned to the threads in
2976e5dd7070Spatrick // the team in a round-robin fashion in the order of the thread number.
2977e5dd7070Spatrick //
2978e5dd7070Spatrick // while(UB = min(UB, GlobalUB), idx = LB, idx < UB) {
2979e5dd7070Spatrick // while (idx <= UB) { BODY; ++idx; } // inner loop
2980e5dd7070Spatrick // LB = LB + ST;
2981e5dd7070Spatrick // UB = UB + ST;
2982e5dd7070Spatrick // }
2983e5dd7070Spatrick //
2984e5dd7070Spatrick
2985e5dd7070Spatrick const Expr *IVExpr = S.getIterationVariable();
2986e5dd7070Spatrick const unsigned IVSize = getContext().getTypeSize(IVExpr->getType());
2987e5dd7070Spatrick const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation();
2988e5dd7070Spatrick
2989e5dd7070Spatrick if (DynamicOrOrdered) {
2990e5dd7070Spatrick const std::pair<llvm::Value *, llvm::Value *> DispatchBounds =
2991e5dd7070Spatrick CGDispatchBounds(*this, S, LoopArgs.LB, LoopArgs.UB);
2992e5dd7070Spatrick llvm::Value *LBVal = DispatchBounds.first;
2993e5dd7070Spatrick llvm::Value *UBVal = DispatchBounds.second;
2994e5dd7070Spatrick CGOpenMPRuntime::DispatchRTInput DipatchRTInputValues = {LBVal, UBVal,
2995e5dd7070Spatrick LoopArgs.Chunk};
2996e5dd7070Spatrick RT.emitForDispatchInit(*this, S.getBeginLoc(), ScheduleKind, IVSize,
2997e5dd7070Spatrick IVSigned, Ordered, DipatchRTInputValues);
2998e5dd7070Spatrick } else {
2999e5dd7070Spatrick CGOpenMPRuntime::StaticRTInput StaticInit(
3000e5dd7070Spatrick IVSize, IVSigned, Ordered, LoopArgs.IL, LoopArgs.LB, LoopArgs.UB,
3001e5dd7070Spatrick LoopArgs.ST, LoopArgs.Chunk);
3002e5dd7070Spatrick RT.emitForStaticInit(*this, S.getBeginLoc(), S.getDirectiveKind(),
3003e5dd7070Spatrick ScheduleKind, StaticInit);
3004e5dd7070Spatrick }
3005e5dd7070Spatrick
3006e5dd7070Spatrick auto &&CodeGenOrdered = [Ordered](CodeGenFunction &CGF, SourceLocation Loc,
3007e5dd7070Spatrick const unsigned IVSize,
3008e5dd7070Spatrick const bool IVSigned) {
3009e5dd7070Spatrick if (Ordered) {
3010e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitForOrderedIterationEnd(CGF, Loc, IVSize,
3011e5dd7070Spatrick IVSigned);
3012e5dd7070Spatrick }
3013e5dd7070Spatrick };
3014e5dd7070Spatrick
3015e5dd7070Spatrick OMPLoopArguments OuterLoopArgs(LoopArgs.LB, LoopArgs.UB, LoopArgs.ST,
3016e5dd7070Spatrick LoopArgs.IL, LoopArgs.Chunk, LoopArgs.EUB);
3017e5dd7070Spatrick OuterLoopArgs.IncExpr = S.getInc();
3018e5dd7070Spatrick OuterLoopArgs.Init = S.getInit();
3019e5dd7070Spatrick OuterLoopArgs.Cond = S.getCond();
3020e5dd7070Spatrick OuterLoopArgs.NextLB = S.getNextLowerBound();
3021e5dd7070Spatrick OuterLoopArgs.NextUB = S.getNextUpperBound();
3022e5dd7070Spatrick EmitOMPOuterLoop(DynamicOrOrdered, IsMonotonic, S, LoopScope, OuterLoopArgs,
3023e5dd7070Spatrick emitOMPLoopBodyWithStopPoint, CodeGenOrdered);
3024e5dd7070Spatrick }
3025e5dd7070Spatrick
emitEmptyOrdered(CodeGenFunction &,SourceLocation Loc,const unsigned IVSize,const bool IVSigned)3026e5dd7070Spatrick static void emitEmptyOrdered(CodeGenFunction &, SourceLocation Loc,
3027e5dd7070Spatrick const unsigned IVSize, const bool IVSigned) {}
3028e5dd7070Spatrick
EmitOMPDistributeOuterLoop(OpenMPDistScheduleClauseKind ScheduleKind,const OMPLoopDirective & S,OMPPrivateScope & LoopScope,const OMPLoopArguments & LoopArgs,const CodeGenLoopTy & CodeGenLoopContent)3029e5dd7070Spatrick void CodeGenFunction::EmitOMPDistributeOuterLoop(
3030e5dd7070Spatrick OpenMPDistScheduleClauseKind ScheduleKind, const OMPLoopDirective &S,
3031e5dd7070Spatrick OMPPrivateScope &LoopScope, const OMPLoopArguments &LoopArgs,
3032e5dd7070Spatrick const CodeGenLoopTy &CodeGenLoopContent) {
3033e5dd7070Spatrick
3034e5dd7070Spatrick CGOpenMPRuntime &RT = CGM.getOpenMPRuntime();
3035e5dd7070Spatrick
3036e5dd7070Spatrick // Emit outer loop.
3037e5dd7070Spatrick // Same behavior as a OMPForOuterLoop, except that schedule cannot be
3038e5dd7070Spatrick // dynamic
3039e5dd7070Spatrick //
3040e5dd7070Spatrick
3041e5dd7070Spatrick const Expr *IVExpr = S.getIterationVariable();
3042e5dd7070Spatrick const unsigned IVSize = getContext().getTypeSize(IVExpr->getType());
3043e5dd7070Spatrick const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation();
3044e5dd7070Spatrick
3045e5dd7070Spatrick CGOpenMPRuntime::StaticRTInput StaticInit(
3046e5dd7070Spatrick IVSize, IVSigned, /* Ordered = */ false, LoopArgs.IL, LoopArgs.LB,
3047e5dd7070Spatrick LoopArgs.UB, LoopArgs.ST, LoopArgs.Chunk);
3048e5dd7070Spatrick RT.emitDistributeStaticInit(*this, S.getBeginLoc(), ScheduleKind, StaticInit);
3049e5dd7070Spatrick
3050e5dd7070Spatrick // for combined 'distribute' and 'for' the increment expression of distribute
3051e5dd7070Spatrick // is stored in DistInc. For 'distribute' alone, it is in Inc.
3052e5dd7070Spatrick Expr *IncExpr;
3053e5dd7070Spatrick if (isOpenMPLoopBoundSharingDirective(S.getDirectiveKind()))
3054e5dd7070Spatrick IncExpr = S.getDistInc();
3055e5dd7070Spatrick else
3056e5dd7070Spatrick IncExpr = S.getInc();
3057e5dd7070Spatrick
3058e5dd7070Spatrick // this routine is shared by 'omp distribute parallel for' and
3059e5dd7070Spatrick // 'omp distribute': select the right EUB expression depending on the
3060e5dd7070Spatrick // directive
3061e5dd7070Spatrick OMPLoopArguments OuterLoopArgs;
3062e5dd7070Spatrick OuterLoopArgs.LB = LoopArgs.LB;
3063e5dd7070Spatrick OuterLoopArgs.UB = LoopArgs.UB;
3064e5dd7070Spatrick OuterLoopArgs.ST = LoopArgs.ST;
3065e5dd7070Spatrick OuterLoopArgs.IL = LoopArgs.IL;
3066e5dd7070Spatrick OuterLoopArgs.Chunk = LoopArgs.Chunk;
3067e5dd7070Spatrick OuterLoopArgs.EUB = isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
3068e5dd7070Spatrick ? S.getCombinedEnsureUpperBound()
3069e5dd7070Spatrick : S.getEnsureUpperBound();
3070e5dd7070Spatrick OuterLoopArgs.IncExpr = IncExpr;
3071e5dd7070Spatrick OuterLoopArgs.Init = isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
3072e5dd7070Spatrick ? S.getCombinedInit()
3073e5dd7070Spatrick : S.getInit();
3074e5dd7070Spatrick OuterLoopArgs.Cond = isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
3075e5dd7070Spatrick ? S.getCombinedCond()
3076e5dd7070Spatrick : S.getCond();
3077e5dd7070Spatrick OuterLoopArgs.NextLB = isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
3078e5dd7070Spatrick ? S.getCombinedNextLowerBound()
3079e5dd7070Spatrick : S.getNextLowerBound();
3080e5dd7070Spatrick OuterLoopArgs.NextUB = isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
3081e5dd7070Spatrick ? S.getCombinedNextUpperBound()
3082e5dd7070Spatrick : S.getNextUpperBound();
3083e5dd7070Spatrick
3084e5dd7070Spatrick EmitOMPOuterLoop(/* DynamicOrOrdered = */ false, /* IsMonotonic = */ false, S,
3085e5dd7070Spatrick LoopScope, OuterLoopArgs, CodeGenLoopContent,
3086e5dd7070Spatrick emitEmptyOrdered);
3087e5dd7070Spatrick }
3088e5dd7070Spatrick
3089e5dd7070Spatrick static std::pair<LValue, LValue>
emitDistributeParallelForInnerBounds(CodeGenFunction & CGF,const OMPExecutableDirective & S)3090e5dd7070Spatrick emitDistributeParallelForInnerBounds(CodeGenFunction &CGF,
3091e5dd7070Spatrick const OMPExecutableDirective &S) {
3092e5dd7070Spatrick const OMPLoopDirective &LS = cast<OMPLoopDirective>(S);
3093e5dd7070Spatrick LValue LB =
3094e5dd7070Spatrick EmitOMPHelperVar(CGF, cast<DeclRefExpr>(LS.getLowerBoundVariable()));
3095e5dd7070Spatrick LValue UB =
3096e5dd7070Spatrick EmitOMPHelperVar(CGF, cast<DeclRefExpr>(LS.getUpperBoundVariable()));
3097e5dd7070Spatrick
3098e5dd7070Spatrick // When composing 'distribute' with 'for' (e.g. as in 'distribute
3099e5dd7070Spatrick // parallel for') we need to use the 'distribute'
3100e5dd7070Spatrick // chunk lower and upper bounds rather than the whole loop iteration
3101e5dd7070Spatrick // space. These are parameters to the outlined function for 'parallel'
3102e5dd7070Spatrick // and we copy the bounds of the previous schedule into the
3103e5dd7070Spatrick // the current ones.
3104e5dd7070Spatrick LValue PrevLB = CGF.EmitLValue(LS.getPrevLowerBoundVariable());
3105e5dd7070Spatrick LValue PrevUB = CGF.EmitLValue(LS.getPrevUpperBoundVariable());
3106e5dd7070Spatrick llvm::Value *PrevLBVal = CGF.EmitLoadOfScalar(
3107e5dd7070Spatrick PrevLB, LS.getPrevLowerBoundVariable()->getExprLoc());
3108e5dd7070Spatrick PrevLBVal = CGF.EmitScalarConversion(
3109e5dd7070Spatrick PrevLBVal, LS.getPrevLowerBoundVariable()->getType(),
3110e5dd7070Spatrick LS.getIterationVariable()->getType(),
3111e5dd7070Spatrick LS.getPrevLowerBoundVariable()->getExprLoc());
3112e5dd7070Spatrick llvm::Value *PrevUBVal = CGF.EmitLoadOfScalar(
3113e5dd7070Spatrick PrevUB, LS.getPrevUpperBoundVariable()->getExprLoc());
3114e5dd7070Spatrick PrevUBVal = CGF.EmitScalarConversion(
3115e5dd7070Spatrick PrevUBVal, LS.getPrevUpperBoundVariable()->getType(),
3116e5dd7070Spatrick LS.getIterationVariable()->getType(),
3117e5dd7070Spatrick LS.getPrevUpperBoundVariable()->getExprLoc());
3118e5dd7070Spatrick
3119e5dd7070Spatrick CGF.EmitStoreOfScalar(PrevLBVal, LB);
3120e5dd7070Spatrick CGF.EmitStoreOfScalar(PrevUBVal, UB);
3121e5dd7070Spatrick
3122e5dd7070Spatrick return {LB, UB};
3123e5dd7070Spatrick }
3124e5dd7070Spatrick
3125e5dd7070Spatrick /// if the 'for' loop has a dispatch schedule (e.g. dynamic, guided) then
3126e5dd7070Spatrick /// we need to use the LB and UB expressions generated by the worksharing
3127e5dd7070Spatrick /// code generation support, whereas in non combined situations we would
3128e5dd7070Spatrick /// just emit 0 and the LastIteration expression
3129e5dd7070Spatrick /// This function is necessary due to the difference of the LB and UB
3130e5dd7070Spatrick /// types for the RT emission routines for 'for_static_init' and
3131e5dd7070Spatrick /// 'for_dispatch_init'
3132e5dd7070Spatrick static std::pair<llvm::Value *, llvm::Value *>
emitDistributeParallelForDispatchBounds(CodeGenFunction & CGF,const OMPExecutableDirective & S,Address LB,Address UB)3133e5dd7070Spatrick emitDistributeParallelForDispatchBounds(CodeGenFunction &CGF,
3134e5dd7070Spatrick const OMPExecutableDirective &S,
3135e5dd7070Spatrick Address LB, Address UB) {
3136e5dd7070Spatrick const OMPLoopDirective &LS = cast<OMPLoopDirective>(S);
3137e5dd7070Spatrick const Expr *IVExpr = LS.getIterationVariable();
3138e5dd7070Spatrick // when implementing a dynamic schedule for a 'for' combined with a
3139e5dd7070Spatrick // 'distribute' (e.g. 'distribute parallel for'), the 'for' loop
3140e5dd7070Spatrick // is not normalized as each team only executes its own assigned
3141e5dd7070Spatrick // distribute chunk
3142e5dd7070Spatrick QualType IteratorTy = IVExpr->getType();
3143e5dd7070Spatrick llvm::Value *LBVal =
3144e5dd7070Spatrick CGF.EmitLoadOfScalar(LB, /*Volatile=*/false, IteratorTy, S.getBeginLoc());
3145e5dd7070Spatrick llvm::Value *UBVal =
3146e5dd7070Spatrick CGF.EmitLoadOfScalar(UB, /*Volatile=*/false, IteratorTy, S.getBeginLoc());
3147e5dd7070Spatrick return {LBVal, UBVal};
3148e5dd7070Spatrick }
3149e5dd7070Spatrick
emitDistributeParallelForDistributeInnerBoundParams(CodeGenFunction & CGF,const OMPExecutableDirective & S,llvm::SmallVectorImpl<llvm::Value * > & CapturedVars)3150e5dd7070Spatrick static void emitDistributeParallelForDistributeInnerBoundParams(
3151e5dd7070Spatrick CodeGenFunction &CGF, const OMPExecutableDirective &S,
3152e5dd7070Spatrick llvm::SmallVectorImpl<llvm::Value *> &CapturedVars) {
3153e5dd7070Spatrick const auto &Dir = cast<OMPLoopDirective>(S);
3154e5dd7070Spatrick LValue LB =
3155e5dd7070Spatrick CGF.EmitLValue(cast<DeclRefExpr>(Dir.getCombinedLowerBoundVariable()));
3156e5dd7070Spatrick llvm::Value *LBCast =
3157e5dd7070Spatrick CGF.Builder.CreateIntCast(CGF.Builder.CreateLoad(LB.getAddress(CGF)),
3158e5dd7070Spatrick CGF.SizeTy, /*isSigned=*/false);
3159e5dd7070Spatrick CapturedVars.push_back(LBCast);
3160e5dd7070Spatrick LValue UB =
3161e5dd7070Spatrick CGF.EmitLValue(cast<DeclRefExpr>(Dir.getCombinedUpperBoundVariable()));
3162e5dd7070Spatrick
3163e5dd7070Spatrick llvm::Value *UBCast =
3164e5dd7070Spatrick CGF.Builder.CreateIntCast(CGF.Builder.CreateLoad(UB.getAddress(CGF)),
3165e5dd7070Spatrick CGF.SizeTy, /*isSigned=*/false);
3166e5dd7070Spatrick CapturedVars.push_back(UBCast);
3167e5dd7070Spatrick }
3168e5dd7070Spatrick
3169e5dd7070Spatrick static void
emitInnerParallelForWhenCombined(CodeGenFunction & CGF,const OMPLoopDirective & S,CodeGenFunction::JumpDest LoopExit)3170e5dd7070Spatrick emitInnerParallelForWhenCombined(CodeGenFunction &CGF,
3171e5dd7070Spatrick const OMPLoopDirective &S,
3172e5dd7070Spatrick CodeGenFunction::JumpDest LoopExit) {
3173e5dd7070Spatrick auto &&CGInlinedWorksharingLoop = [&S](CodeGenFunction &CGF,
3174e5dd7070Spatrick PrePostActionTy &Action) {
3175e5dd7070Spatrick Action.Enter(CGF);
3176e5dd7070Spatrick bool HasCancel = false;
3177e5dd7070Spatrick if (!isOpenMPSimdDirective(S.getDirectiveKind())) {
3178e5dd7070Spatrick if (const auto *D = dyn_cast<OMPTeamsDistributeParallelForDirective>(&S))
3179e5dd7070Spatrick HasCancel = D->hasCancel();
3180e5dd7070Spatrick else if (const auto *D = dyn_cast<OMPDistributeParallelForDirective>(&S))
3181e5dd7070Spatrick HasCancel = D->hasCancel();
3182e5dd7070Spatrick else if (const auto *D =
3183e5dd7070Spatrick dyn_cast<OMPTargetTeamsDistributeParallelForDirective>(&S))
3184e5dd7070Spatrick HasCancel = D->hasCancel();
3185e5dd7070Spatrick }
3186e5dd7070Spatrick CodeGenFunction::OMPCancelStackRAII CancelRegion(CGF, S.getDirectiveKind(),
3187e5dd7070Spatrick HasCancel);
3188e5dd7070Spatrick CGF.EmitOMPWorksharingLoop(S, S.getPrevEnsureUpperBound(),
3189e5dd7070Spatrick emitDistributeParallelForInnerBounds,
3190e5dd7070Spatrick emitDistributeParallelForDispatchBounds);
3191e5dd7070Spatrick };
3192e5dd7070Spatrick
3193e5dd7070Spatrick emitCommonOMPParallelDirective(
3194e5dd7070Spatrick CGF, S,
3195e5dd7070Spatrick isOpenMPSimdDirective(S.getDirectiveKind()) ? OMPD_for_simd : OMPD_for,
3196e5dd7070Spatrick CGInlinedWorksharingLoop,
3197e5dd7070Spatrick emitDistributeParallelForDistributeInnerBoundParams);
3198e5dd7070Spatrick }
3199e5dd7070Spatrick
EmitOMPDistributeParallelForDirective(const OMPDistributeParallelForDirective & S)3200e5dd7070Spatrick void CodeGenFunction::EmitOMPDistributeParallelForDirective(
3201e5dd7070Spatrick const OMPDistributeParallelForDirective &S) {
3202e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
3203e5dd7070Spatrick CGF.EmitOMPDistributeLoop(S, emitInnerParallelForWhenCombined,
3204e5dd7070Spatrick S.getDistInc());
3205e5dd7070Spatrick };
3206e5dd7070Spatrick OMPLexicalScope Scope(*this, S, OMPD_parallel);
3207e5dd7070Spatrick CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_distribute, CodeGen);
3208e5dd7070Spatrick }
3209e5dd7070Spatrick
EmitOMPDistributeParallelForSimdDirective(const OMPDistributeParallelForSimdDirective & S)3210e5dd7070Spatrick void CodeGenFunction::EmitOMPDistributeParallelForSimdDirective(
3211e5dd7070Spatrick const OMPDistributeParallelForSimdDirective &S) {
3212e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
3213e5dd7070Spatrick CGF.EmitOMPDistributeLoop(S, emitInnerParallelForWhenCombined,
3214e5dd7070Spatrick S.getDistInc());
3215e5dd7070Spatrick };
3216e5dd7070Spatrick OMPLexicalScope Scope(*this, S, OMPD_parallel);
3217e5dd7070Spatrick CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_distribute, CodeGen);
3218e5dd7070Spatrick }
3219e5dd7070Spatrick
EmitOMPDistributeSimdDirective(const OMPDistributeSimdDirective & S)3220e5dd7070Spatrick void CodeGenFunction::EmitOMPDistributeSimdDirective(
3221e5dd7070Spatrick const OMPDistributeSimdDirective &S) {
3222e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
3223e5dd7070Spatrick CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc());
3224e5dd7070Spatrick };
3225e5dd7070Spatrick OMPLexicalScope Scope(*this, S, OMPD_unknown);
3226e5dd7070Spatrick CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_simd, CodeGen);
3227e5dd7070Spatrick }
3228e5dd7070Spatrick
EmitOMPTargetSimdDeviceFunction(CodeGenModule & CGM,StringRef ParentName,const OMPTargetSimdDirective & S)3229e5dd7070Spatrick void CodeGenFunction::EmitOMPTargetSimdDeviceFunction(
3230e5dd7070Spatrick CodeGenModule &CGM, StringRef ParentName, const OMPTargetSimdDirective &S) {
3231e5dd7070Spatrick // Emit SPMD target parallel for region as a standalone region.
3232e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
3233e5dd7070Spatrick emitOMPSimdRegion(CGF, S, Action);
3234e5dd7070Spatrick };
3235e5dd7070Spatrick llvm::Function *Fn;
3236e5dd7070Spatrick llvm::Constant *Addr;
3237e5dd7070Spatrick // Emit target region as a standalone region.
3238e5dd7070Spatrick CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
3239e5dd7070Spatrick S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
3240e5dd7070Spatrick assert(Fn && Addr && "Target device function emission failed.");
3241e5dd7070Spatrick }
3242e5dd7070Spatrick
EmitOMPTargetSimdDirective(const OMPTargetSimdDirective & S)3243e5dd7070Spatrick void CodeGenFunction::EmitOMPTargetSimdDirective(
3244e5dd7070Spatrick const OMPTargetSimdDirective &S) {
3245e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
3246e5dd7070Spatrick emitOMPSimdRegion(CGF, S, Action);
3247e5dd7070Spatrick };
3248e5dd7070Spatrick emitCommonOMPTargetDirective(*this, S, CodeGen);
3249e5dd7070Spatrick }
3250e5dd7070Spatrick
3251e5dd7070Spatrick namespace {
3252e5dd7070Spatrick struct ScheduleKindModifiersTy {
3253e5dd7070Spatrick OpenMPScheduleClauseKind Kind;
3254e5dd7070Spatrick OpenMPScheduleClauseModifier M1;
3255e5dd7070Spatrick OpenMPScheduleClauseModifier M2;
ScheduleKindModifiersTy__anon20b8c0362811::ScheduleKindModifiersTy3256e5dd7070Spatrick ScheduleKindModifiersTy(OpenMPScheduleClauseKind Kind,
3257e5dd7070Spatrick OpenMPScheduleClauseModifier M1,
3258e5dd7070Spatrick OpenMPScheduleClauseModifier M2)
3259e5dd7070Spatrick : Kind(Kind), M1(M1), M2(M2) {}
3260e5dd7070Spatrick };
3261e5dd7070Spatrick } // namespace
3262e5dd7070Spatrick
EmitOMPWorksharingLoop(const OMPLoopDirective & S,Expr * EUB,const CodeGenLoopBoundsTy & CodeGenLoopBounds,const CodeGenDispatchBoundsTy & CGDispatchBounds)3263e5dd7070Spatrick bool CodeGenFunction::EmitOMPWorksharingLoop(
3264e5dd7070Spatrick const OMPLoopDirective &S, Expr *EUB,
3265e5dd7070Spatrick const CodeGenLoopBoundsTy &CodeGenLoopBounds,
3266e5dd7070Spatrick const CodeGenDispatchBoundsTy &CGDispatchBounds) {
3267e5dd7070Spatrick // Emit the loop iteration variable.
3268e5dd7070Spatrick const auto *IVExpr = cast<DeclRefExpr>(S.getIterationVariable());
3269e5dd7070Spatrick const auto *IVDecl = cast<VarDecl>(IVExpr->getDecl());
3270e5dd7070Spatrick EmitVarDecl(*IVDecl);
3271e5dd7070Spatrick
3272e5dd7070Spatrick // Emit the iterations count variable.
3273e5dd7070Spatrick // If it is not a variable, Sema decided to calculate iterations count on each
3274e5dd7070Spatrick // iteration (e.g., it is foldable into a constant).
3275e5dd7070Spatrick if (const auto *LIExpr = dyn_cast<DeclRefExpr>(S.getLastIteration())) {
3276e5dd7070Spatrick EmitVarDecl(*cast<VarDecl>(LIExpr->getDecl()));
3277e5dd7070Spatrick // Emit calculation of the iterations count.
3278e5dd7070Spatrick EmitIgnoredExpr(S.getCalcLastIteration());
3279e5dd7070Spatrick }
3280e5dd7070Spatrick
3281e5dd7070Spatrick CGOpenMPRuntime &RT = CGM.getOpenMPRuntime();
3282e5dd7070Spatrick
3283e5dd7070Spatrick bool HasLastprivateClause;
3284e5dd7070Spatrick // Check pre-condition.
3285e5dd7070Spatrick {
3286e5dd7070Spatrick OMPLoopScope PreInitScope(*this, S);
3287e5dd7070Spatrick // Skip the entire loop if we don't meet the precondition.
3288e5dd7070Spatrick // If the condition constant folds and can be elided, avoid emitting the
3289e5dd7070Spatrick // whole loop.
3290e5dd7070Spatrick bool CondConstant;
3291e5dd7070Spatrick llvm::BasicBlock *ContBlock = nullptr;
3292e5dd7070Spatrick if (ConstantFoldsToSimpleInteger(S.getPreCond(), CondConstant)) {
3293e5dd7070Spatrick if (!CondConstant)
3294e5dd7070Spatrick return false;
3295e5dd7070Spatrick } else {
3296e5dd7070Spatrick llvm::BasicBlock *ThenBlock = createBasicBlock("omp.precond.then");
3297e5dd7070Spatrick ContBlock = createBasicBlock("omp.precond.end");
3298e5dd7070Spatrick emitPreCond(*this, S, S.getPreCond(), ThenBlock, ContBlock,
3299e5dd7070Spatrick getProfileCount(&S));
3300e5dd7070Spatrick EmitBlock(ThenBlock);
3301e5dd7070Spatrick incrementProfileCounter(&S);
3302e5dd7070Spatrick }
3303e5dd7070Spatrick
3304e5dd7070Spatrick RunCleanupsScope DoacrossCleanupScope(*this);
3305e5dd7070Spatrick bool Ordered = false;
3306e5dd7070Spatrick if (const auto *OrderedClause = S.getSingleClause<OMPOrderedClause>()) {
3307e5dd7070Spatrick if (OrderedClause->getNumForLoops())
3308e5dd7070Spatrick RT.emitDoacrossInit(*this, S, OrderedClause->getLoopNumIterations());
3309e5dd7070Spatrick else
3310e5dd7070Spatrick Ordered = true;
3311e5dd7070Spatrick }
3312e5dd7070Spatrick
3313e5dd7070Spatrick llvm::DenseSet<const Expr *> EmittedFinals;
3314e5dd7070Spatrick emitAlignedClause(*this, S);
3315e5dd7070Spatrick bool HasLinears = EmitOMPLinearClauseInit(S);
3316e5dd7070Spatrick // Emit helper vars inits.
3317e5dd7070Spatrick
3318e5dd7070Spatrick std::pair<LValue, LValue> Bounds = CodeGenLoopBounds(*this, S);
3319e5dd7070Spatrick LValue LB = Bounds.first;
3320e5dd7070Spatrick LValue UB = Bounds.second;
3321e5dd7070Spatrick LValue ST =
3322e5dd7070Spatrick EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getStrideVariable()));
3323e5dd7070Spatrick LValue IL =
3324e5dd7070Spatrick EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getIsLastIterVariable()));
3325e5dd7070Spatrick
3326e5dd7070Spatrick // Emit 'then' code.
3327e5dd7070Spatrick {
3328e5dd7070Spatrick OMPPrivateScope LoopScope(*this);
3329e5dd7070Spatrick if (EmitOMPFirstprivateClause(S, LoopScope) || HasLinears) {
3330e5dd7070Spatrick // Emit implicit barrier to synchronize threads and avoid data races on
3331e5dd7070Spatrick // initialization of firstprivate variables and post-update of
3332e5dd7070Spatrick // lastprivate variables.
3333e5dd7070Spatrick CGM.getOpenMPRuntime().emitBarrierCall(
3334e5dd7070Spatrick *this, S.getBeginLoc(), OMPD_unknown, /*EmitChecks=*/false,
3335e5dd7070Spatrick /*ForceSimpleCall=*/true);
3336e5dd7070Spatrick }
3337e5dd7070Spatrick EmitOMPPrivateClause(S, LoopScope);
3338e5dd7070Spatrick CGOpenMPRuntime::LastprivateConditionalRAII LPCRegion(
3339e5dd7070Spatrick *this, S, EmitLValue(S.getIterationVariable()));
3340e5dd7070Spatrick HasLastprivateClause = EmitOMPLastprivateClauseInit(S, LoopScope);
3341e5dd7070Spatrick EmitOMPReductionClauseInit(S, LoopScope);
3342e5dd7070Spatrick EmitOMPPrivateLoopCounters(S, LoopScope);
3343e5dd7070Spatrick EmitOMPLinearClause(S, LoopScope);
3344e5dd7070Spatrick (void)LoopScope.Privatize();
3345e5dd7070Spatrick if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()))
3346e5dd7070Spatrick CGM.getOpenMPRuntime().adjustTargetSpecificDataForLambdas(*this, S);
3347e5dd7070Spatrick
3348e5dd7070Spatrick // Detect the loop schedule kind and chunk.
3349e5dd7070Spatrick const Expr *ChunkExpr = nullptr;
3350e5dd7070Spatrick OpenMPScheduleTy ScheduleKind;
3351e5dd7070Spatrick if (const auto *C = S.getSingleClause<OMPScheduleClause>()) {
3352e5dd7070Spatrick ScheduleKind.Schedule = C->getScheduleKind();
3353e5dd7070Spatrick ScheduleKind.M1 = C->getFirstScheduleModifier();
3354e5dd7070Spatrick ScheduleKind.M2 = C->getSecondScheduleModifier();
3355e5dd7070Spatrick ChunkExpr = C->getChunkSize();
3356e5dd7070Spatrick } else {
3357e5dd7070Spatrick // Default behaviour for schedule clause.
3358e5dd7070Spatrick CGM.getOpenMPRuntime().getDefaultScheduleAndChunk(
3359e5dd7070Spatrick *this, S, ScheduleKind.Schedule, ChunkExpr);
3360e5dd7070Spatrick }
3361e5dd7070Spatrick bool HasChunkSizeOne = false;
3362e5dd7070Spatrick llvm::Value *Chunk = nullptr;
3363e5dd7070Spatrick if (ChunkExpr) {
3364e5dd7070Spatrick Chunk = EmitScalarExpr(ChunkExpr);
3365e5dd7070Spatrick Chunk = EmitScalarConversion(Chunk, ChunkExpr->getType(),
3366e5dd7070Spatrick S.getIterationVariable()->getType(),
3367e5dd7070Spatrick S.getBeginLoc());
3368e5dd7070Spatrick Expr::EvalResult Result;
3369e5dd7070Spatrick if (ChunkExpr->EvaluateAsInt(Result, getContext())) {
3370e5dd7070Spatrick llvm::APSInt EvaluatedChunk = Result.Val.getInt();
3371e5dd7070Spatrick HasChunkSizeOne = (EvaluatedChunk.getLimitedValue() == 1);
3372e5dd7070Spatrick }
3373e5dd7070Spatrick }
3374e5dd7070Spatrick const unsigned IVSize = getContext().getTypeSize(IVExpr->getType());
3375e5dd7070Spatrick const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation();
3376e5dd7070Spatrick // OpenMP 4.5, 2.7.1 Loop Construct, Description.
3377e5dd7070Spatrick // If the static schedule kind is specified or if the ordered clause is
3378e5dd7070Spatrick // specified, and if no monotonic modifier is specified, the effect will
3379e5dd7070Spatrick // be as if the monotonic modifier was specified.
3380*12c85518Srobert bool StaticChunkedOne =
3381*12c85518Srobert RT.isStaticChunked(ScheduleKind.Schedule,
3382*12c85518Srobert /* Chunked */ Chunk != nullptr) &&
3383*12c85518Srobert HasChunkSizeOne &&
3384e5dd7070Spatrick isOpenMPLoopBoundSharingDirective(S.getDirectiveKind());
3385ec727ea7Spatrick bool IsMonotonic =
3386ec727ea7Spatrick Ordered ||
3387a9ac8606Spatrick (ScheduleKind.Schedule == OMPC_SCHEDULE_static &&
3388ec727ea7Spatrick !(ScheduleKind.M1 == OMPC_SCHEDULE_MODIFIER_nonmonotonic ||
3389a9ac8606Spatrick ScheduleKind.M2 == OMPC_SCHEDULE_MODIFIER_nonmonotonic)) ||
3390ec727ea7Spatrick ScheduleKind.M1 == OMPC_SCHEDULE_MODIFIER_monotonic ||
3391ec727ea7Spatrick ScheduleKind.M2 == OMPC_SCHEDULE_MODIFIER_monotonic;
3392e5dd7070Spatrick if ((RT.isStaticNonchunked(ScheduleKind.Schedule,
3393e5dd7070Spatrick /* Chunked */ Chunk != nullptr) ||
3394e5dd7070Spatrick StaticChunkedOne) &&
3395e5dd7070Spatrick !Ordered) {
3396e5dd7070Spatrick JumpDest LoopExit =
3397e5dd7070Spatrick getJumpDestInCurrentScope(createBasicBlock("omp.loop.exit"));
3398e5dd7070Spatrick emitCommonSimdLoop(
3399e5dd7070Spatrick *this, S,
3400a9ac8606Spatrick [&S](CodeGenFunction &CGF, PrePostActionTy &) {
3401ec727ea7Spatrick if (isOpenMPSimdDirective(S.getDirectiveKind())) {
3402a9ac8606Spatrick CGF.EmitOMPSimdInit(S);
3403ec727ea7Spatrick } else if (const auto *C = S.getSingleClause<OMPOrderClause>()) {
3404ec727ea7Spatrick if (C->getKind() == OMPC_ORDER_concurrent)
3405ec727ea7Spatrick CGF.LoopStack.setParallel(/*Enable=*/true);
3406ec727ea7Spatrick }
3407e5dd7070Spatrick },
3408e5dd7070Spatrick [IVSize, IVSigned, Ordered, IL, LB, UB, ST, StaticChunkedOne, Chunk,
3409e5dd7070Spatrick &S, ScheduleKind, LoopExit,
3410e5dd7070Spatrick &LoopScope](CodeGenFunction &CGF, PrePostActionTy &) {
3411e5dd7070Spatrick // OpenMP [2.7.1, Loop Construct, Description, table 2-1]
3412e5dd7070Spatrick // When no chunk_size is specified, the iteration space is divided
3413e5dd7070Spatrick // into chunks that are approximately equal in size, and at most
3414e5dd7070Spatrick // one chunk is distributed to each thread. Note that the size of
3415e5dd7070Spatrick // the chunks is unspecified in this case.
3416e5dd7070Spatrick CGOpenMPRuntime::StaticRTInput StaticInit(
3417e5dd7070Spatrick IVSize, IVSigned, Ordered, IL.getAddress(CGF),
3418e5dd7070Spatrick LB.getAddress(CGF), UB.getAddress(CGF), ST.getAddress(CGF),
3419e5dd7070Spatrick StaticChunkedOne ? Chunk : nullptr);
3420e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitForStaticInit(
3421e5dd7070Spatrick CGF, S.getBeginLoc(), S.getDirectiveKind(), ScheduleKind,
3422e5dd7070Spatrick StaticInit);
3423e5dd7070Spatrick // UB = min(UB, GlobalUB);
3424e5dd7070Spatrick if (!StaticChunkedOne)
3425e5dd7070Spatrick CGF.EmitIgnoredExpr(S.getEnsureUpperBound());
3426e5dd7070Spatrick // IV = LB;
3427e5dd7070Spatrick CGF.EmitIgnoredExpr(S.getInit());
3428e5dd7070Spatrick // For unchunked static schedule generate:
3429e5dd7070Spatrick //
3430e5dd7070Spatrick // while (idx <= UB) {
3431e5dd7070Spatrick // BODY;
3432e5dd7070Spatrick // ++idx;
3433e5dd7070Spatrick // }
3434e5dd7070Spatrick //
3435e5dd7070Spatrick // For static schedule with chunk one:
3436e5dd7070Spatrick //
3437e5dd7070Spatrick // while (IV <= PrevUB) {
3438e5dd7070Spatrick // BODY;
3439e5dd7070Spatrick // IV += ST;
3440e5dd7070Spatrick // }
3441e5dd7070Spatrick CGF.EmitOMPInnerLoop(
3442e5dd7070Spatrick S, LoopScope.requiresCleanups(),
3443e5dd7070Spatrick StaticChunkedOne ? S.getCombinedParForInDistCond()
3444e5dd7070Spatrick : S.getCond(),
3445e5dd7070Spatrick StaticChunkedOne ? S.getDistInc() : S.getInc(),
3446e5dd7070Spatrick [&S, LoopExit](CodeGenFunction &CGF) {
3447ec727ea7Spatrick emitOMPLoopBodyWithStopPoint(CGF, S, LoopExit);
3448e5dd7070Spatrick },
3449e5dd7070Spatrick [](CodeGenFunction &) {});
3450e5dd7070Spatrick });
3451e5dd7070Spatrick EmitBlock(LoopExit.getBlock());
3452e5dd7070Spatrick // Tell the runtime we are done.
3453e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF) {
3454e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getEndLoc(),
3455e5dd7070Spatrick S.getDirectiveKind());
3456e5dd7070Spatrick };
3457e5dd7070Spatrick OMPCancelStack.emitExit(*this, S.getDirectiveKind(), CodeGen);
3458e5dd7070Spatrick } else {
3459e5dd7070Spatrick // Emit the outer loop, which requests its work chunk [LB..UB] from
3460e5dd7070Spatrick // runtime and runs the inner loop to process it.
3461e5dd7070Spatrick const OMPLoopArguments LoopArguments(
3462e5dd7070Spatrick LB.getAddress(*this), UB.getAddress(*this), ST.getAddress(*this),
3463e5dd7070Spatrick IL.getAddress(*this), Chunk, EUB);
3464e5dd7070Spatrick EmitOMPForOuterLoop(ScheduleKind, IsMonotonic, S, LoopScope, Ordered,
3465e5dd7070Spatrick LoopArguments, CGDispatchBounds);
3466e5dd7070Spatrick }
3467e5dd7070Spatrick if (isOpenMPSimdDirective(S.getDirectiveKind())) {
3468e5dd7070Spatrick EmitOMPSimdFinal(S, [IL, &S](CodeGenFunction &CGF) {
3469e5dd7070Spatrick return CGF.Builder.CreateIsNotNull(
3470e5dd7070Spatrick CGF.EmitLoadOfScalar(IL, S.getBeginLoc()));
3471e5dd7070Spatrick });
3472e5dd7070Spatrick }
3473e5dd7070Spatrick EmitOMPReductionClauseFinal(
3474e5dd7070Spatrick S, /*ReductionKind=*/isOpenMPSimdDirective(S.getDirectiveKind())
3475e5dd7070Spatrick ? /*Parallel and Simd*/ OMPD_parallel_for_simd
3476e5dd7070Spatrick : /*Parallel only*/ OMPD_parallel);
3477e5dd7070Spatrick // Emit post-update of the reduction variables if IsLastIter != 0.
3478e5dd7070Spatrick emitPostUpdateForReductionClause(
3479e5dd7070Spatrick *this, S, [IL, &S](CodeGenFunction &CGF) {
3480e5dd7070Spatrick return CGF.Builder.CreateIsNotNull(
3481e5dd7070Spatrick CGF.EmitLoadOfScalar(IL, S.getBeginLoc()));
3482e5dd7070Spatrick });
3483e5dd7070Spatrick // Emit final copy of the lastprivate variables if IsLastIter != 0.
3484e5dd7070Spatrick if (HasLastprivateClause)
3485e5dd7070Spatrick EmitOMPLastprivateClauseFinal(
3486e5dd7070Spatrick S, isOpenMPSimdDirective(S.getDirectiveKind()),
3487e5dd7070Spatrick Builder.CreateIsNotNull(EmitLoadOfScalar(IL, S.getBeginLoc())));
3488*12c85518Srobert LoopScope.restoreMap();
3489e5dd7070Spatrick EmitOMPLinearClauseFinal(S, [IL, &S](CodeGenFunction &CGF) {
3490e5dd7070Spatrick return CGF.Builder.CreateIsNotNull(
3491e5dd7070Spatrick CGF.EmitLoadOfScalar(IL, S.getBeginLoc()));
3492e5dd7070Spatrick });
3493*12c85518Srobert }
3494e5dd7070Spatrick DoacrossCleanupScope.ForceCleanup();
3495e5dd7070Spatrick // We're now done with the loop, so jump to the continuation block.
3496e5dd7070Spatrick if (ContBlock) {
3497e5dd7070Spatrick EmitBranch(ContBlock);
3498e5dd7070Spatrick EmitBlock(ContBlock, /*IsFinished=*/true);
3499e5dd7070Spatrick }
3500e5dd7070Spatrick }
3501e5dd7070Spatrick return HasLastprivateClause;
3502e5dd7070Spatrick }
3503e5dd7070Spatrick
3504e5dd7070Spatrick /// The following two functions generate expressions for the loop lower
3505e5dd7070Spatrick /// and upper bounds in case of static and dynamic (dispatch) schedule
3506e5dd7070Spatrick /// of the associated 'for' or 'distribute' loop.
3507e5dd7070Spatrick static std::pair<LValue, LValue>
emitForLoopBounds(CodeGenFunction & CGF,const OMPExecutableDirective & S)3508e5dd7070Spatrick emitForLoopBounds(CodeGenFunction &CGF, const OMPExecutableDirective &S) {
3509e5dd7070Spatrick const auto &LS = cast<OMPLoopDirective>(S);
3510e5dd7070Spatrick LValue LB =
3511e5dd7070Spatrick EmitOMPHelperVar(CGF, cast<DeclRefExpr>(LS.getLowerBoundVariable()));
3512e5dd7070Spatrick LValue UB =
3513e5dd7070Spatrick EmitOMPHelperVar(CGF, cast<DeclRefExpr>(LS.getUpperBoundVariable()));
3514e5dd7070Spatrick return {LB, UB};
3515e5dd7070Spatrick }
3516e5dd7070Spatrick
3517e5dd7070Spatrick /// When dealing with dispatch schedules (e.g. dynamic, guided) we do not
3518e5dd7070Spatrick /// consider the lower and upper bound expressions generated by the
3519e5dd7070Spatrick /// worksharing loop support, but we use 0 and the iteration space size as
3520e5dd7070Spatrick /// constants
3521e5dd7070Spatrick static std::pair<llvm::Value *, llvm::Value *>
emitDispatchForLoopBounds(CodeGenFunction & CGF,const OMPExecutableDirective & S,Address LB,Address UB)3522e5dd7070Spatrick emitDispatchForLoopBounds(CodeGenFunction &CGF, const OMPExecutableDirective &S,
3523e5dd7070Spatrick Address LB, Address UB) {
3524e5dd7070Spatrick const auto &LS = cast<OMPLoopDirective>(S);
3525e5dd7070Spatrick const Expr *IVExpr = LS.getIterationVariable();
3526e5dd7070Spatrick const unsigned IVSize = CGF.getContext().getTypeSize(IVExpr->getType());
3527e5dd7070Spatrick llvm::Value *LBVal = CGF.Builder.getIntN(IVSize, 0);
3528e5dd7070Spatrick llvm::Value *UBVal = CGF.EmitScalarExpr(LS.getLastIteration());
3529e5dd7070Spatrick return {LBVal, UBVal};
3530e5dd7070Spatrick }
3531e5dd7070Spatrick
3532a9ac8606Spatrick /// Emits internal temp array declarations for the directive with inscan
3533a9ac8606Spatrick /// reductions.
3534ec727ea7Spatrick /// The code is the following:
3535ec727ea7Spatrick /// \code
3536ec727ea7Spatrick /// size num_iters = <num_iters>;
3537ec727ea7Spatrick /// <type> buffer[num_iters];
3538ec727ea7Spatrick /// \endcode
emitScanBasedDirectiveDecls(CodeGenFunction & CGF,const OMPLoopDirective & S,llvm::function_ref<llvm::Value * (CodeGenFunction &)> NumIteratorsGen)3539a9ac8606Spatrick static void emitScanBasedDirectiveDecls(
3540ec727ea7Spatrick CodeGenFunction &CGF, const OMPLoopDirective &S,
3541a9ac8606Spatrick llvm::function_ref<llvm::Value *(CodeGenFunction &)> NumIteratorsGen) {
3542ec727ea7Spatrick llvm::Value *OMPScanNumIterations = CGF.Builder.CreateIntCast(
3543ec727ea7Spatrick NumIteratorsGen(CGF), CGF.SizeTy, /*isSigned=*/false);
3544ec727ea7Spatrick SmallVector<const Expr *, 4> Shareds;
3545ec727ea7Spatrick SmallVector<const Expr *, 4> Privates;
3546ec727ea7Spatrick SmallVector<const Expr *, 4> ReductionOps;
3547ec727ea7Spatrick SmallVector<const Expr *, 4> CopyArrayTemps;
3548ec727ea7Spatrick for (const auto *C : S.getClausesOfKind<OMPReductionClause>()) {
3549ec727ea7Spatrick assert(C->getModifier() == OMPC_REDUCTION_inscan &&
3550ec727ea7Spatrick "Only inscan reductions are expected.");
3551ec727ea7Spatrick Shareds.append(C->varlist_begin(), C->varlist_end());
3552ec727ea7Spatrick Privates.append(C->privates().begin(), C->privates().end());
3553ec727ea7Spatrick ReductionOps.append(C->reduction_ops().begin(), C->reduction_ops().end());
3554ec727ea7Spatrick CopyArrayTemps.append(C->copy_array_temps().begin(),
3555ec727ea7Spatrick C->copy_array_temps().end());
3556ec727ea7Spatrick }
3557ec727ea7Spatrick {
3558ec727ea7Spatrick // Emit buffers for each reduction variables.
3559ec727ea7Spatrick // ReductionCodeGen is required to emit correctly the code for array
3560ec727ea7Spatrick // reductions.
3561ec727ea7Spatrick ReductionCodeGen RedCG(Shareds, Shareds, Privates, ReductionOps);
3562ec727ea7Spatrick unsigned Count = 0;
3563ec727ea7Spatrick auto *ITA = CopyArrayTemps.begin();
3564ec727ea7Spatrick for (const Expr *IRef : Privates) {
3565ec727ea7Spatrick const auto *PrivateVD = cast<VarDecl>(cast<DeclRefExpr>(IRef)->getDecl());
3566ec727ea7Spatrick // Emit variably modified arrays, used for arrays/array sections
3567ec727ea7Spatrick // reductions.
3568ec727ea7Spatrick if (PrivateVD->getType()->isVariablyModifiedType()) {
3569ec727ea7Spatrick RedCG.emitSharedOrigLValue(CGF, Count);
3570ec727ea7Spatrick RedCG.emitAggregateType(CGF, Count);
3571ec727ea7Spatrick }
3572ec727ea7Spatrick CodeGenFunction::OpaqueValueMapping DimMapping(
3573ec727ea7Spatrick CGF,
3574ec727ea7Spatrick cast<OpaqueValueExpr>(
3575ec727ea7Spatrick cast<VariableArrayType>((*ITA)->getType()->getAsArrayTypeUnsafe())
3576ec727ea7Spatrick ->getSizeExpr()),
3577ec727ea7Spatrick RValue::get(OMPScanNumIterations));
3578ec727ea7Spatrick // Emit temp buffer.
3579ec727ea7Spatrick CGF.EmitVarDecl(*cast<VarDecl>(cast<DeclRefExpr>(*ITA)->getDecl()));
3580ec727ea7Spatrick ++ITA;
3581ec727ea7Spatrick ++Count;
3582ec727ea7Spatrick }
3583ec727ea7Spatrick }
3584a9ac8606Spatrick }
3585a9ac8606Spatrick
3586*12c85518Srobert /// Copies final inscan reductions values to the original variables.
3587*12c85518Srobert /// The code is the following:
3588*12c85518Srobert /// \code
3589*12c85518Srobert /// <orig_var> = buffer[num_iters-1];
3590*12c85518Srobert /// \endcode
emitScanBasedDirectiveFinals(CodeGenFunction & CGF,const OMPLoopDirective & S,llvm::function_ref<llvm::Value * (CodeGenFunction &)> NumIteratorsGen)3591*12c85518Srobert static void emitScanBasedDirectiveFinals(
3592*12c85518Srobert CodeGenFunction &CGF, const OMPLoopDirective &S,
3593*12c85518Srobert llvm::function_ref<llvm::Value *(CodeGenFunction &)> NumIteratorsGen) {
3594*12c85518Srobert llvm::Value *OMPScanNumIterations = CGF.Builder.CreateIntCast(
3595*12c85518Srobert NumIteratorsGen(CGF), CGF.SizeTy, /*isSigned=*/false);
3596*12c85518Srobert SmallVector<const Expr *, 4> Shareds;
3597*12c85518Srobert SmallVector<const Expr *, 4> LHSs;
3598*12c85518Srobert SmallVector<const Expr *, 4> RHSs;
3599*12c85518Srobert SmallVector<const Expr *, 4> Privates;
3600*12c85518Srobert SmallVector<const Expr *, 4> CopyOps;
3601*12c85518Srobert SmallVector<const Expr *, 4> CopyArrayElems;
3602*12c85518Srobert for (const auto *C : S.getClausesOfKind<OMPReductionClause>()) {
3603*12c85518Srobert assert(C->getModifier() == OMPC_REDUCTION_inscan &&
3604*12c85518Srobert "Only inscan reductions are expected.");
3605*12c85518Srobert Shareds.append(C->varlist_begin(), C->varlist_end());
3606*12c85518Srobert LHSs.append(C->lhs_exprs().begin(), C->lhs_exprs().end());
3607*12c85518Srobert RHSs.append(C->rhs_exprs().begin(), C->rhs_exprs().end());
3608*12c85518Srobert Privates.append(C->privates().begin(), C->privates().end());
3609*12c85518Srobert CopyOps.append(C->copy_ops().begin(), C->copy_ops().end());
3610*12c85518Srobert CopyArrayElems.append(C->copy_array_elems().begin(),
3611*12c85518Srobert C->copy_array_elems().end());
3612*12c85518Srobert }
3613*12c85518Srobert // Create temp var and copy LHS value to this temp value.
3614*12c85518Srobert // LHS = TMP[LastIter];
3615*12c85518Srobert llvm::Value *OMPLast = CGF.Builder.CreateNSWSub(
3616*12c85518Srobert OMPScanNumIterations,
3617*12c85518Srobert llvm::ConstantInt::get(CGF.SizeTy, 1, /*isSigned=*/false));
3618*12c85518Srobert for (unsigned I = 0, E = CopyArrayElems.size(); I < E; ++I) {
3619*12c85518Srobert const Expr *PrivateExpr = Privates[I];
3620*12c85518Srobert const Expr *OrigExpr = Shareds[I];
3621*12c85518Srobert const Expr *CopyArrayElem = CopyArrayElems[I];
3622*12c85518Srobert CodeGenFunction::OpaqueValueMapping IdxMapping(
3623*12c85518Srobert CGF,
3624*12c85518Srobert cast<OpaqueValueExpr>(
3625*12c85518Srobert cast<ArraySubscriptExpr>(CopyArrayElem)->getIdx()),
3626*12c85518Srobert RValue::get(OMPLast));
3627*12c85518Srobert LValue DestLVal = CGF.EmitLValue(OrigExpr);
3628*12c85518Srobert LValue SrcLVal = CGF.EmitLValue(CopyArrayElem);
3629*12c85518Srobert CGF.EmitOMPCopy(PrivateExpr->getType(), DestLVal.getAddress(CGF),
3630*12c85518Srobert SrcLVal.getAddress(CGF),
3631*12c85518Srobert cast<VarDecl>(cast<DeclRefExpr>(LHSs[I])->getDecl()),
3632*12c85518Srobert cast<VarDecl>(cast<DeclRefExpr>(RHSs[I])->getDecl()),
3633*12c85518Srobert CopyOps[I]);
3634*12c85518Srobert }
3635*12c85518Srobert }
3636*12c85518Srobert
3637a9ac8606Spatrick /// Emits the code for the directive with inscan reductions.
3638a9ac8606Spatrick /// The code is the following:
3639a9ac8606Spatrick /// \code
3640a9ac8606Spatrick /// #pragma omp ...
3641a9ac8606Spatrick /// for (i: 0..<num_iters>) {
3642a9ac8606Spatrick /// <input phase>;
3643a9ac8606Spatrick /// buffer[i] = red;
3644a9ac8606Spatrick /// }
3645a9ac8606Spatrick /// #pragma omp master // in parallel region
3646a9ac8606Spatrick /// for (int k = 0; k != ceil(log2(num_iters)); ++k)
3647a9ac8606Spatrick /// for (size cnt = last_iter; cnt >= pow(2, k); --k)
3648a9ac8606Spatrick /// buffer[i] op= buffer[i-pow(2,k)];
3649a9ac8606Spatrick /// #pragma omp barrier // in parallel region
3650a9ac8606Spatrick /// #pragma omp ...
3651a9ac8606Spatrick /// for (0..<num_iters>) {
3652a9ac8606Spatrick /// red = InclusiveScan ? buffer[i] : buffer[i-1];
3653a9ac8606Spatrick /// <scan phase>;
3654a9ac8606Spatrick /// }
3655a9ac8606Spatrick /// \endcode
emitScanBasedDirective(CodeGenFunction & CGF,const OMPLoopDirective & S,llvm::function_ref<llvm::Value * (CodeGenFunction &)> NumIteratorsGen,llvm::function_ref<void (CodeGenFunction &)> FirstGen,llvm::function_ref<void (CodeGenFunction &)> SecondGen)3656a9ac8606Spatrick static void emitScanBasedDirective(
3657a9ac8606Spatrick CodeGenFunction &CGF, const OMPLoopDirective &S,
3658a9ac8606Spatrick llvm::function_ref<llvm::Value *(CodeGenFunction &)> NumIteratorsGen,
3659a9ac8606Spatrick llvm::function_ref<void(CodeGenFunction &)> FirstGen,
3660a9ac8606Spatrick llvm::function_ref<void(CodeGenFunction &)> SecondGen) {
3661a9ac8606Spatrick llvm::Value *OMPScanNumIterations = CGF.Builder.CreateIntCast(
3662a9ac8606Spatrick NumIteratorsGen(CGF), CGF.SizeTy, /*isSigned=*/false);
3663a9ac8606Spatrick SmallVector<const Expr *, 4> Privates;
3664a9ac8606Spatrick SmallVector<const Expr *, 4> ReductionOps;
3665a9ac8606Spatrick SmallVector<const Expr *, 4> LHSs;
3666a9ac8606Spatrick SmallVector<const Expr *, 4> RHSs;
3667a9ac8606Spatrick SmallVector<const Expr *, 4> CopyArrayElems;
3668a9ac8606Spatrick for (const auto *C : S.getClausesOfKind<OMPReductionClause>()) {
3669a9ac8606Spatrick assert(C->getModifier() == OMPC_REDUCTION_inscan &&
3670a9ac8606Spatrick "Only inscan reductions are expected.");
3671a9ac8606Spatrick Privates.append(C->privates().begin(), C->privates().end());
3672a9ac8606Spatrick ReductionOps.append(C->reduction_ops().begin(), C->reduction_ops().end());
3673a9ac8606Spatrick LHSs.append(C->lhs_exprs().begin(), C->lhs_exprs().end());
3674a9ac8606Spatrick RHSs.append(C->rhs_exprs().begin(), C->rhs_exprs().end());
3675a9ac8606Spatrick CopyArrayElems.append(C->copy_array_elems().begin(),
3676a9ac8606Spatrick C->copy_array_elems().end());
3677a9ac8606Spatrick }
3678ec727ea7Spatrick CodeGenFunction::ParentLoopDirectiveForScanRegion ScanRegion(CGF, S);
3679ec727ea7Spatrick {
3680ec727ea7Spatrick // Emit loop with input phase:
3681ec727ea7Spatrick // #pragma omp ...
3682ec727ea7Spatrick // for (i: 0..<num_iters>) {
3683ec727ea7Spatrick // <input phase>;
3684ec727ea7Spatrick // buffer[i] = red;
3685ec727ea7Spatrick // }
3686ec727ea7Spatrick CGF.OMPFirstScanLoop = true;
3687ec727ea7Spatrick CodeGenFunction::OMPLocalDeclMapRAII Scope(CGF);
3688ec727ea7Spatrick FirstGen(CGF);
3689ec727ea7Spatrick }
3690a9ac8606Spatrick // #pragma omp barrier // in parallel region
3691a9ac8606Spatrick auto &&CodeGen = [&S, OMPScanNumIterations, &LHSs, &RHSs, &CopyArrayElems,
3692a9ac8606Spatrick &ReductionOps,
3693a9ac8606Spatrick &Privates](CodeGenFunction &CGF, PrePostActionTy &Action) {
3694a9ac8606Spatrick Action.Enter(CGF);
3695ec727ea7Spatrick // Emit prefix reduction:
3696a9ac8606Spatrick // #pragma omp master // in parallel region
3697ec727ea7Spatrick // for (int k = 0; k <= ceil(log2(n)); ++k)
3698ec727ea7Spatrick llvm::BasicBlock *InputBB = CGF.Builder.GetInsertBlock();
3699ec727ea7Spatrick llvm::BasicBlock *LoopBB = CGF.createBasicBlock("omp.outer.log.scan.body");
3700ec727ea7Spatrick llvm::BasicBlock *ExitBB = CGF.createBasicBlock("omp.outer.log.scan.exit");
3701a9ac8606Spatrick llvm::Function *F =
3702a9ac8606Spatrick CGF.CGM.getIntrinsic(llvm::Intrinsic::log2, CGF.DoubleTy);
3703ec727ea7Spatrick llvm::Value *Arg =
3704ec727ea7Spatrick CGF.Builder.CreateUIToFP(OMPScanNumIterations, CGF.DoubleTy);
3705ec727ea7Spatrick llvm::Value *LogVal = CGF.EmitNounwindRuntimeCall(F, Arg);
3706ec727ea7Spatrick F = CGF.CGM.getIntrinsic(llvm::Intrinsic::ceil, CGF.DoubleTy);
3707ec727ea7Spatrick LogVal = CGF.EmitNounwindRuntimeCall(F, LogVal);
3708ec727ea7Spatrick LogVal = CGF.Builder.CreateFPToUI(LogVal, CGF.IntTy);
3709ec727ea7Spatrick llvm::Value *NMin1 = CGF.Builder.CreateNUWSub(
3710ec727ea7Spatrick OMPScanNumIterations, llvm::ConstantInt::get(CGF.SizeTy, 1));
3711ec727ea7Spatrick auto DL = ApplyDebugLocation::CreateDefaultArtificial(CGF, S.getBeginLoc());
3712ec727ea7Spatrick CGF.EmitBlock(LoopBB);
3713ec727ea7Spatrick auto *Counter = CGF.Builder.CreatePHI(CGF.IntTy, 2);
3714ec727ea7Spatrick // size pow2k = 1;
3715ec727ea7Spatrick auto *Pow2K = CGF.Builder.CreatePHI(CGF.SizeTy, 2);
3716ec727ea7Spatrick Counter->addIncoming(llvm::ConstantInt::get(CGF.IntTy, 0), InputBB);
3717ec727ea7Spatrick Pow2K->addIncoming(llvm::ConstantInt::get(CGF.SizeTy, 1), InputBB);
3718ec727ea7Spatrick // for (size i = n - 1; i >= 2 ^ k; --i)
3719ec727ea7Spatrick // tmp[i] op= tmp[i-pow2k];
3720ec727ea7Spatrick llvm::BasicBlock *InnerLoopBB =
3721ec727ea7Spatrick CGF.createBasicBlock("omp.inner.log.scan.body");
3722ec727ea7Spatrick llvm::BasicBlock *InnerExitBB =
3723ec727ea7Spatrick CGF.createBasicBlock("omp.inner.log.scan.exit");
3724ec727ea7Spatrick llvm::Value *CmpI = CGF.Builder.CreateICmpUGE(NMin1, Pow2K);
3725ec727ea7Spatrick CGF.Builder.CreateCondBr(CmpI, InnerLoopBB, InnerExitBB);
3726ec727ea7Spatrick CGF.EmitBlock(InnerLoopBB);
3727ec727ea7Spatrick auto *IVal = CGF.Builder.CreatePHI(CGF.SizeTy, 2);
3728ec727ea7Spatrick IVal->addIncoming(NMin1, LoopBB);
3729ec727ea7Spatrick {
3730ec727ea7Spatrick CodeGenFunction::OMPPrivateScope PrivScope(CGF);
3731ec727ea7Spatrick auto *ILHS = LHSs.begin();
3732ec727ea7Spatrick auto *IRHS = RHSs.begin();
3733ec727ea7Spatrick for (const Expr *CopyArrayElem : CopyArrayElems) {
3734ec727ea7Spatrick const auto *LHSVD = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
3735ec727ea7Spatrick const auto *RHSVD = cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
3736ec727ea7Spatrick Address LHSAddr = Address::invalid();
3737ec727ea7Spatrick {
3738ec727ea7Spatrick CodeGenFunction::OpaqueValueMapping IdxMapping(
3739ec727ea7Spatrick CGF,
3740ec727ea7Spatrick cast<OpaqueValueExpr>(
3741ec727ea7Spatrick cast<ArraySubscriptExpr>(CopyArrayElem)->getIdx()),
3742ec727ea7Spatrick RValue::get(IVal));
3743ec727ea7Spatrick LHSAddr = CGF.EmitLValue(CopyArrayElem).getAddress(CGF);
3744ec727ea7Spatrick }
3745*12c85518Srobert PrivScope.addPrivate(LHSVD, LHSAddr);
3746ec727ea7Spatrick Address RHSAddr = Address::invalid();
3747ec727ea7Spatrick {
3748ec727ea7Spatrick llvm::Value *OffsetIVal = CGF.Builder.CreateNUWSub(IVal, Pow2K);
3749ec727ea7Spatrick CodeGenFunction::OpaqueValueMapping IdxMapping(
3750ec727ea7Spatrick CGF,
3751ec727ea7Spatrick cast<OpaqueValueExpr>(
3752ec727ea7Spatrick cast<ArraySubscriptExpr>(CopyArrayElem)->getIdx()),
3753ec727ea7Spatrick RValue::get(OffsetIVal));
3754ec727ea7Spatrick RHSAddr = CGF.EmitLValue(CopyArrayElem).getAddress(CGF);
3755ec727ea7Spatrick }
3756*12c85518Srobert PrivScope.addPrivate(RHSVD, RHSAddr);
3757ec727ea7Spatrick ++ILHS;
3758ec727ea7Spatrick ++IRHS;
3759ec727ea7Spatrick }
3760ec727ea7Spatrick PrivScope.Privatize();
3761ec727ea7Spatrick CGF.CGM.getOpenMPRuntime().emitReduction(
3762ec727ea7Spatrick CGF, S.getEndLoc(), Privates, LHSs, RHSs, ReductionOps,
3763ec727ea7Spatrick {/*WithNowait=*/true, /*SimpleReduction=*/true, OMPD_unknown});
3764ec727ea7Spatrick }
3765ec727ea7Spatrick llvm::Value *NextIVal =
3766ec727ea7Spatrick CGF.Builder.CreateNUWSub(IVal, llvm::ConstantInt::get(CGF.SizeTy, 1));
3767ec727ea7Spatrick IVal->addIncoming(NextIVal, CGF.Builder.GetInsertBlock());
3768ec727ea7Spatrick CmpI = CGF.Builder.CreateICmpUGE(NextIVal, Pow2K);
3769ec727ea7Spatrick CGF.Builder.CreateCondBr(CmpI, InnerLoopBB, InnerExitBB);
3770ec727ea7Spatrick CGF.EmitBlock(InnerExitBB);
3771ec727ea7Spatrick llvm::Value *Next =
3772ec727ea7Spatrick CGF.Builder.CreateNUWAdd(Counter, llvm::ConstantInt::get(CGF.IntTy, 1));
3773ec727ea7Spatrick Counter->addIncoming(Next, CGF.Builder.GetInsertBlock());
3774ec727ea7Spatrick // pow2k <<= 1;
3775a9ac8606Spatrick llvm::Value *NextPow2K =
3776a9ac8606Spatrick CGF.Builder.CreateShl(Pow2K, 1, "", /*HasNUW=*/true);
3777ec727ea7Spatrick Pow2K->addIncoming(NextPow2K, CGF.Builder.GetInsertBlock());
3778ec727ea7Spatrick llvm::Value *Cmp = CGF.Builder.CreateICmpNE(Next, LogVal);
3779ec727ea7Spatrick CGF.Builder.CreateCondBr(Cmp, LoopBB, ExitBB);
3780ec727ea7Spatrick auto DL1 = ApplyDebugLocation::CreateDefaultArtificial(CGF, S.getEndLoc());
3781ec727ea7Spatrick CGF.EmitBlock(ExitBB);
3782a9ac8606Spatrick };
3783a9ac8606Spatrick if (isOpenMPParallelDirective(S.getDirectiveKind())) {
3784a9ac8606Spatrick CGF.CGM.getOpenMPRuntime().emitMasterRegion(CGF, CodeGen, S.getBeginLoc());
3785a9ac8606Spatrick CGF.CGM.getOpenMPRuntime().emitBarrierCall(
3786a9ac8606Spatrick CGF, S.getBeginLoc(), OMPD_unknown, /*EmitChecks=*/false,
3787a9ac8606Spatrick /*ForceSimpleCall=*/true);
3788a9ac8606Spatrick } else {
3789a9ac8606Spatrick RegionCodeGenTy RCG(CodeGen);
3790a9ac8606Spatrick RCG(CGF);
3791a9ac8606Spatrick }
3792ec727ea7Spatrick
3793ec727ea7Spatrick CGF.OMPFirstScanLoop = false;
3794ec727ea7Spatrick SecondGen(CGF);
3795ec727ea7Spatrick }
3796ec727ea7Spatrick
emitWorksharingDirective(CodeGenFunction & CGF,const OMPLoopDirective & S,bool HasCancel)3797ec727ea7Spatrick static bool emitWorksharingDirective(CodeGenFunction &CGF,
3798ec727ea7Spatrick const OMPLoopDirective &S,
3799ec727ea7Spatrick bool HasCancel) {
3800ec727ea7Spatrick bool HasLastprivates;
3801ec727ea7Spatrick if (llvm::any_of(S.getClausesOfKind<OMPReductionClause>(),
3802ec727ea7Spatrick [](const OMPReductionClause *C) {
3803ec727ea7Spatrick return C->getModifier() == OMPC_REDUCTION_inscan;
3804ec727ea7Spatrick })) {
3805ec727ea7Spatrick const auto &&NumIteratorsGen = [&S](CodeGenFunction &CGF) {
3806ec727ea7Spatrick CodeGenFunction::OMPLocalDeclMapRAII Scope(CGF);
3807ec727ea7Spatrick OMPLoopScope LoopScope(CGF, S);
3808ec727ea7Spatrick return CGF.EmitScalarExpr(S.getNumIterations());
3809ec727ea7Spatrick };
3810ec727ea7Spatrick const auto &&FirstGen = [&S, HasCancel](CodeGenFunction &CGF) {
3811ec727ea7Spatrick CodeGenFunction::OMPCancelStackRAII CancelRegion(
3812ec727ea7Spatrick CGF, S.getDirectiveKind(), HasCancel);
3813ec727ea7Spatrick (void)CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(),
3814ec727ea7Spatrick emitForLoopBounds,
3815ec727ea7Spatrick emitDispatchForLoopBounds);
3816ec727ea7Spatrick // Emit an implicit barrier at the end.
3817ec727ea7Spatrick CGF.CGM.getOpenMPRuntime().emitBarrierCall(CGF, S.getBeginLoc(),
3818ec727ea7Spatrick OMPD_for);
3819ec727ea7Spatrick };
3820ec727ea7Spatrick const auto &&SecondGen = [&S, HasCancel,
3821ec727ea7Spatrick &HasLastprivates](CodeGenFunction &CGF) {
3822ec727ea7Spatrick CodeGenFunction::OMPCancelStackRAII CancelRegion(
3823ec727ea7Spatrick CGF, S.getDirectiveKind(), HasCancel);
3824e5dd7070Spatrick HasLastprivates = CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(),
3825e5dd7070Spatrick emitForLoopBounds,
3826e5dd7070Spatrick emitDispatchForLoopBounds);
3827e5dd7070Spatrick };
3828a9ac8606Spatrick if (!isOpenMPParallelDirective(S.getDirectiveKind()))
3829a9ac8606Spatrick emitScanBasedDirectiveDecls(CGF, S, NumIteratorsGen);
3830ec727ea7Spatrick emitScanBasedDirective(CGF, S, NumIteratorsGen, FirstGen, SecondGen);
3831*12c85518Srobert if (!isOpenMPParallelDirective(S.getDirectiveKind()))
3832*12c85518Srobert emitScanBasedDirectiveFinals(CGF, S, NumIteratorsGen);
3833ec727ea7Spatrick } else {
3834ec727ea7Spatrick CodeGenFunction::OMPCancelStackRAII CancelRegion(CGF, S.getDirectiveKind(),
3835ec727ea7Spatrick HasCancel);
3836ec727ea7Spatrick HasLastprivates = CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(),
3837ec727ea7Spatrick emitForLoopBounds,
3838ec727ea7Spatrick emitDispatchForLoopBounds);
3839ec727ea7Spatrick }
3840ec727ea7Spatrick return HasLastprivates;
3841ec727ea7Spatrick }
3842ec727ea7Spatrick
isSupportedByOpenMPIRBuilder(const OMPForDirective & S)3843a9ac8606Spatrick static bool isSupportedByOpenMPIRBuilder(const OMPForDirective &S) {
3844a9ac8606Spatrick if (S.hasCancel())
3845a9ac8606Spatrick return false;
3846*12c85518Srobert for (OMPClause *C : S.clauses()) {
3847*12c85518Srobert if (isa<OMPNowaitClause>(C))
3848*12c85518Srobert continue;
3849*12c85518Srobert
3850*12c85518Srobert if (auto *SC = dyn_cast<OMPScheduleClause>(C)) {
3851*12c85518Srobert if (SC->getFirstScheduleModifier() != OMPC_SCHEDULE_MODIFIER_unknown)
3852a9ac8606Spatrick return false;
3853*12c85518Srobert if (SC->getSecondScheduleModifier() != OMPC_SCHEDULE_MODIFIER_unknown)
3854*12c85518Srobert return false;
3855*12c85518Srobert switch (SC->getScheduleKind()) {
3856*12c85518Srobert case OMPC_SCHEDULE_auto:
3857*12c85518Srobert case OMPC_SCHEDULE_dynamic:
3858*12c85518Srobert case OMPC_SCHEDULE_runtime:
3859*12c85518Srobert case OMPC_SCHEDULE_guided:
3860*12c85518Srobert case OMPC_SCHEDULE_static:
3861*12c85518Srobert continue;
3862*12c85518Srobert case OMPC_SCHEDULE_unknown:
3863*12c85518Srobert return false;
3864*12c85518Srobert }
3865*12c85518Srobert }
3866*12c85518Srobert
3867*12c85518Srobert return false;
3868*12c85518Srobert }
3869a9ac8606Spatrick
3870a9ac8606Spatrick return true;
3871a9ac8606Spatrick }
3872a9ac8606Spatrick
3873*12c85518Srobert static llvm::omp::ScheduleKind
convertClauseKindToSchedKind(OpenMPScheduleClauseKind ScheduleClauseKind)3874*12c85518Srobert convertClauseKindToSchedKind(OpenMPScheduleClauseKind ScheduleClauseKind) {
3875*12c85518Srobert switch (ScheduleClauseKind) {
3876*12c85518Srobert case OMPC_SCHEDULE_unknown:
3877*12c85518Srobert return llvm::omp::OMP_SCHEDULE_Default;
3878*12c85518Srobert case OMPC_SCHEDULE_auto:
3879*12c85518Srobert return llvm::omp::OMP_SCHEDULE_Auto;
3880*12c85518Srobert case OMPC_SCHEDULE_dynamic:
3881*12c85518Srobert return llvm::omp::OMP_SCHEDULE_Dynamic;
3882*12c85518Srobert case OMPC_SCHEDULE_guided:
3883*12c85518Srobert return llvm::omp::OMP_SCHEDULE_Guided;
3884*12c85518Srobert case OMPC_SCHEDULE_runtime:
3885*12c85518Srobert return llvm::omp::OMP_SCHEDULE_Runtime;
3886*12c85518Srobert case OMPC_SCHEDULE_static:
3887*12c85518Srobert return llvm::omp::OMP_SCHEDULE_Static;
3888*12c85518Srobert }
3889*12c85518Srobert llvm_unreachable("Unhandled schedule kind");
3890*12c85518Srobert }
3891*12c85518Srobert
EmitOMPForDirective(const OMPForDirective & S)3892ec727ea7Spatrick void CodeGenFunction::EmitOMPForDirective(const OMPForDirective &S) {
3893ec727ea7Spatrick bool HasLastprivates = false;
3894a9ac8606Spatrick bool UseOMPIRBuilder =
3895a9ac8606Spatrick CGM.getLangOpts().OpenMPIRBuilder && isSupportedByOpenMPIRBuilder(S);
3896a9ac8606Spatrick auto &&CodeGen = [this, &S, &HasLastprivates,
3897a9ac8606Spatrick UseOMPIRBuilder](CodeGenFunction &CGF, PrePostActionTy &) {
3898a9ac8606Spatrick // Use the OpenMPIRBuilder if enabled.
3899a9ac8606Spatrick if (UseOMPIRBuilder) {
3900*12c85518Srobert bool NeedsBarrier = !S.getSingleClause<OMPNowaitClause>();
3901*12c85518Srobert
3902*12c85518Srobert llvm::omp::ScheduleKind SchedKind = llvm::omp::OMP_SCHEDULE_Default;
3903*12c85518Srobert llvm::Value *ChunkSize = nullptr;
3904*12c85518Srobert if (auto *SchedClause = S.getSingleClause<OMPScheduleClause>()) {
3905*12c85518Srobert SchedKind =
3906*12c85518Srobert convertClauseKindToSchedKind(SchedClause->getScheduleKind());
3907*12c85518Srobert if (const Expr *ChunkSizeExpr = SchedClause->getChunkSize())
3908*12c85518Srobert ChunkSize = EmitScalarExpr(ChunkSizeExpr);
3909*12c85518Srobert }
3910*12c85518Srobert
3911a9ac8606Spatrick // Emit the associated statement and get its loop representation.
3912a9ac8606Spatrick const Stmt *Inner = S.getRawStmt();
3913a9ac8606Spatrick llvm::CanonicalLoopInfo *CLI =
3914a9ac8606Spatrick EmitOMPCollapsedCanonicalLoopNest(Inner, 1);
3915a9ac8606Spatrick
3916a9ac8606Spatrick llvm::OpenMPIRBuilder &OMPBuilder =
3917a9ac8606Spatrick CGM.getOpenMPRuntime().getOMPBuilder();
3918a9ac8606Spatrick llvm::OpenMPIRBuilder::InsertPointTy AllocaIP(
3919a9ac8606Spatrick AllocaInsertPt->getParent(), AllocaInsertPt->getIterator());
3920*12c85518Srobert OMPBuilder.applyWorkshareLoop(
3921*12c85518Srobert Builder.getCurrentDebugLocation(), CLI, AllocaIP, NeedsBarrier,
3922*12c85518Srobert SchedKind, ChunkSize, /*HasSimdModifier=*/false,
3923*12c85518Srobert /*HasMonotonicModifier=*/false, /*HasNonmonotonicModifier=*/false,
3924*12c85518Srobert /*HasOrderedClause=*/false);
3925a9ac8606Spatrick return;
3926a9ac8606Spatrick }
3927a9ac8606Spatrick
3928ec727ea7Spatrick HasLastprivates = emitWorksharingDirective(CGF, S, S.hasCancel());
3929ec727ea7Spatrick };
3930e5dd7070Spatrick {
3931ec727ea7Spatrick auto LPCRegion =
3932ec727ea7Spatrick CGOpenMPRuntime::LastprivateConditionalRAII::disable(*this, S);
3933e5dd7070Spatrick OMPLexicalScope Scope(*this, S, OMPD_unknown);
3934e5dd7070Spatrick CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_for, CodeGen,
3935e5dd7070Spatrick S.hasCancel());
3936e5dd7070Spatrick }
3937e5dd7070Spatrick
3938a9ac8606Spatrick if (!UseOMPIRBuilder) {
3939e5dd7070Spatrick // Emit an implicit barrier at the end.
3940e5dd7070Spatrick if (!S.getSingleClause<OMPNowaitClause>() || HasLastprivates)
3941e5dd7070Spatrick CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getBeginLoc(), OMPD_for);
3942a9ac8606Spatrick }
3943ec727ea7Spatrick // Check for outer lastprivate conditional update.
3944ec727ea7Spatrick checkForLastprivateConditionalUpdate(*this, S);
3945e5dd7070Spatrick }
3946e5dd7070Spatrick
EmitOMPForSimdDirective(const OMPForSimdDirective & S)3947e5dd7070Spatrick void CodeGenFunction::EmitOMPForSimdDirective(const OMPForSimdDirective &S) {
3948e5dd7070Spatrick bool HasLastprivates = false;
3949e5dd7070Spatrick auto &&CodeGen = [&S, &HasLastprivates](CodeGenFunction &CGF,
3950e5dd7070Spatrick PrePostActionTy &) {
3951ec727ea7Spatrick HasLastprivates = emitWorksharingDirective(CGF, S, /*HasCancel=*/false);
3952e5dd7070Spatrick };
3953e5dd7070Spatrick {
3954ec727ea7Spatrick auto LPCRegion =
3955ec727ea7Spatrick CGOpenMPRuntime::LastprivateConditionalRAII::disable(*this, S);
3956e5dd7070Spatrick OMPLexicalScope Scope(*this, S, OMPD_unknown);
3957e5dd7070Spatrick CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_simd, CodeGen);
3958e5dd7070Spatrick }
3959e5dd7070Spatrick
3960e5dd7070Spatrick // Emit an implicit barrier at the end.
3961e5dd7070Spatrick if (!S.getSingleClause<OMPNowaitClause>() || HasLastprivates)
3962e5dd7070Spatrick CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getBeginLoc(), OMPD_for);
3963ec727ea7Spatrick // Check for outer lastprivate conditional update.
3964ec727ea7Spatrick checkForLastprivateConditionalUpdate(*this, S);
3965e5dd7070Spatrick }
3966e5dd7070Spatrick
createSectionLVal(CodeGenFunction & CGF,QualType Ty,const Twine & Name,llvm::Value * Init=nullptr)3967e5dd7070Spatrick static LValue createSectionLVal(CodeGenFunction &CGF, QualType Ty,
3968e5dd7070Spatrick const Twine &Name,
3969e5dd7070Spatrick llvm::Value *Init = nullptr) {
3970e5dd7070Spatrick LValue LVal = CGF.MakeAddrLValue(CGF.CreateMemTemp(Ty, Name), Ty);
3971e5dd7070Spatrick if (Init)
3972e5dd7070Spatrick CGF.EmitStoreThroughLValue(RValue::get(Init), LVal, /*isInit*/ true);
3973e5dd7070Spatrick return LVal;
3974e5dd7070Spatrick }
3975e5dd7070Spatrick
EmitSections(const OMPExecutableDirective & S)3976e5dd7070Spatrick void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) {
3977e5dd7070Spatrick const Stmt *CapturedStmt = S.getInnermostCapturedStmt()->getCapturedStmt();
3978e5dd7070Spatrick const auto *CS = dyn_cast<CompoundStmt>(CapturedStmt);
3979e5dd7070Spatrick bool HasLastprivates = false;
3980e5dd7070Spatrick auto &&CodeGen = [&S, CapturedStmt, CS,
3981e5dd7070Spatrick &HasLastprivates](CodeGenFunction &CGF, PrePostActionTy &) {
3982ec727ea7Spatrick const ASTContext &C = CGF.getContext();
3983e5dd7070Spatrick QualType KmpInt32Ty =
3984e5dd7070Spatrick C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1);
3985e5dd7070Spatrick // Emit helper vars inits.
3986e5dd7070Spatrick LValue LB = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.lb.",
3987e5dd7070Spatrick CGF.Builder.getInt32(0));
3988e5dd7070Spatrick llvm::ConstantInt *GlobalUBVal = CS != nullptr
3989e5dd7070Spatrick ? CGF.Builder.getInt32(CS->size() - 1)
3990e5dd7070Spatrick : CGF.Builder.getInt32(0);
3991e5dd7070Spatrick LValue UB =
3992e5dd7070Spatrick createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.ub.", GlobalUBVal);
3993e5dd7070Spatrick LValue ST = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.st.",
3994e5dd7070Spatrick CGF.Builder.getInt32(1));
3995e5dd7070Spatrick LValue IL = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.il.",
3996e5dd7070Spatrick CGF.Builder.getInt32(0));
3997e5dd7070Spatrick // Loop counter.
3998e5dd7070Spatrick LValue IV = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.iv.");
3999e5dd7070Spatrick OpaqueValueExpr IVRefExpr(S.getBeginLoc(), KmpInt32Ty, VK_LValue);
4000e5dd7070Spatrick CodeGenFunction::OpaqueValueMapping OpaqueIV(CGF, &IVRefExpr, IV);
4001e5dd7070Spatrick OpaqueValueExpr UBRefExpr(S.getBeginLoc(), KmpInt32Ty, VK_LValue);
4002e5dd7070Spatrick CodeGenFunction::OpaqueValueMapping OpaqueUB(CGF, &UBRefExpr, UB);
4003e5dd7070Spatrick // Generate condition for loop.
4004ec727ea7Spatrick BinaryOperator *Cond = BinaryOperator::Create(
4005a9ac8606Spatrick C, &IVRefExpr, &UBRefExpr, BO_LE, C.BoolTy, VK_PRValue, OK_Ordinary,
4006ec727ea7Spatrick S.getBeginLoc(), FPOptionsOverride());
4007e5dd7070Spatrick // Increment for loop counter.
4008ec727ea7Spatrick UnaryOperator *Inc = UnaryOperator::Create(
4009a9ac8606Spatrick C, &IVRefExpr, UO_PreInc, KmpInt32Ty, VK_PRValue, OK_Ordinary,
4010ec727ea7Spatrick S.getBeginLoc(), true, FPOptionsOverride());
4011e5dd7070Spatrick auto &&BodyGen = [CapturedStmt, CS, &S, &IV](CodeGenFunction &CGF) {
4012e5dd7070Spatrick // Iterate through all sections and emit a switch construct:
4013e5dd7070Spatrick // switch (IV) {
4014e5dd7070Spatrick // case 0:
4015e5dd7070Spatrick // <SectionStmt[0]>;
4016e5dd7070Spatrick // break;
4017e5dd7070Spatrick // ...
4018e5dd7070Spatrick // case <NumSection> - 1:
4019e5dd7070Spatrick // <SectionStmt[<NumSection> - 1]>;
4020e5dd7070Spatrick // break;
4021e5dd7070Spatrick // }
4022e5dd7070Spatrick // .omp.sections.exit:
4023e5dd7070Spatrick llvm::BasicBlock *ExitBB = CGF.createBasicBlock(".omp.sections.exit");
4024e5dd7070Spatrick llvm::SwitchInst *SwitchStmt =
4025e5dd7070Spatrick CGF.Builder.CreateSwitch(CGF.EmitLoadOfScalar(IV, S.getBeginLoc()),
4026e5dd7070Spatrick ExitBB, CS == nullptr ? 1 : CS->size());
4027e5dd7070Spatrick if (CS) {
4028e5dd7070Spatrick unsigned CaseNumber = 0;
4029e5dd7070Spatrick for (const Stmt *SubStmt : CS->children()) {
4030e5dd7070Spatrick auto CaseBB = CGF.createBasicBlock(".omp.sections.case");
4031e5dd7070Spatrick CGF.EmitBlock(CaseBB);
4032e5dd7070Spatrick SwitchStmt->addCase(CGF.Builder.getInt32(CaseNumber), CaseBB);
4033e5dd7070Spatrick CGF.EmitStmt(SubStmt);
4034e5dd7070Spatrick CGF.EmitBranch(ExitBB);
4035e5dd7070Spatrick ++CaseNumber;
4036e5dd7070Spatrick }
4037e5dd7070Spatrick } else {
4038e5dd7070Spatrick llvm::BasicBlock *CaseBB = CGF.createBasicBlock(".omp.sections.case");
4039e5dd7070Spatrick CGF.EmitBlock(CaseBB);
4040e5dd7070Spatrick SwitchStmt->addCase(CGF.Builder.getInt32(0), CaseBB);
4041e5dd7070Spatrick CGF.EmitStmt(CapturedStmt);
4042e5dd7070Spatrick CGF.EmitBranch(ExitBB);
4043e5dd7070Spatrick }
4044e5dd7070Spatrick CGF.EmitBlock(ExitBB, /*IsFinished=*/true);
4045e5dd7070Spatrick };
4046e5dd7070Spatrick
4047e5dd7070Spatrick CodeGenFunction::OMPPrivateScope LoopScope(CGF);
4048e5dd7070Spatrick if (CGF.EmitOMPFirstprivateClause(S, LoopScope)) {
4049e5dd7070Spatrick // Emit implicit barrier to synchronize threads and avoid data races on
4050e5dd7070Spatrick // initialization of firstprivate variables and post-update of lastprivate
4051e5dd7070Spatrick // variables.
4052e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitBarrierCall(
4053e5dd7070Spatrick CGF, S.getBeginLoc(), OMPD_unknown, /*EmitChecks=*/false,
4054e5dd7070Spatrick /*ForceSimpleCall=*/true);
4055e5dd7070Spatrick }
4056e5dd7070Spatrick CGF.EmitOMPPrivateClause(S, LoopScope);
4057e5dd7070Spatrick CGOpenMPRuntime::LastprivateConditionalRAII LPCRegion(CGF, S, IV);
4058e5dd7070Spatrick HasLastprivates = CGF.EmitOMPLastprivateClauseInit(S, LoopScope);
4059e5dd7070Spatrick CGF.EmitOMPReductionClauseInit(S, LoopScope);
4060e5dd7070Spatrick (void)LoopScope.Privatize();
4061e5dd7070Spatrick if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()))
4062e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().adjustTargetSpecificDataForLambdas(CGF, S);
4063e5dd7070Spatrick
4064e5dd7070Spatrick // Emit static non-chunked loop.
4065e5dd7070Spatrick OpenMPScheduleTy ScheduleKind;
4066e5dd7070Spatrick ScheduleKind.Schedule = OMPC_SCHEDULE_static;
4067e5dd7070Spatrick CGOpenMPRuntime::StaticRTInput StaticInit(
4068e5dd7070Spatrick /*IVSize=*/32, /*IVSigned=*/true, /*Ordered=*/false, IL.getAddress(CGF),
4069e5dd7070Spatrick LB.getAddress(CGF), UB.getAddress(CGF), ST.getAddress(CGF));
4070e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitForStaticInit(
4071e5dd7070Spatrick CGF, S.getBeginLoc(), S.getDirectiveKind(), ScheduleKind, StaticInit);
4072e5dd7070Spatrick // UB = min(UB, GlobalUB);
4073e5dd7070Spatrick llvm::Value *UBVal = CGF.EmitLoadOfScalar(UB, S.getBeginLoc());
4074e5dd7070Spatrick llvm::Value *MinUBGlobalUB = CGF.Builder.CreateSelect(
4075e5dd7070Spatrick CGF.Builder.CreateICmpSLT(UBVal, GlobalUBVal), UBVal, GlobalUBVal);
4076e5dd7070Spatrick CGF.EmitStoreOfScalar(MinUBGlobalUB, UB);
4077e5dd7070Spatrick // IV = LB;
4078e5dd7070Spatrick CGF.EmitStoreOfScalar(CGF.EmitLoadOfScalar(LB, S.getBeginLoc()), IV);
4079e5dd7070Spatrick // while (idx <= UB) { BODY; ++idx; }
4080ec727ea7Spatrick CGF.EmitOMPInnerLoop(S, /*RequiresCleanup=*/false, Cond, Inc, BodyGen,
4081e5dd7070Spatrick [](CodeGenFunction &) {});
4082e5dd7070Spatrick // Tell the runtime we are done.
4083e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF) {
4084e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getEndLoc(),
4085e5dd7070Spatrick S.getDirectiveKind());
4086e5dd7070Spatrick };
4087e5dd7070Spatrick CGF.OMPCancelStack.emitExit(CGF, S.getDirectiveKind(), CodeGen);
4088e5dd7070Spatrick CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_parallel);
4089e5dd7070Spatrick // Emit post-update of the reduction variables if IsLastIter != 0.
4090e5dd7070Spatrick emitPostUpdateForReductionClause(CGF, S, [IL, &S](CodeGenFunction &CGF) {
4091e5dd7070Spatrick return CGF.Builder.CreateIsNotNull(
4092e5dd7070Spatrick CGF.EmitLoadOfScalar(IL, S.getBeginLoc()));
4093e5dd7070Spatrick });
4094e5dd7070Spatrick
4095e5dd7070Spatrick // Emit final copy of the lastprivate variables if IsLastIter != 0.
4096e5dd7070Spatrick if (HasLastprivates)
4097e5dd7070Spatrick CGF.EmitOMPLastprivateClauseFinal(
4098e5dd7070Spatrick S, /*NoFinals=*/false,
4099e5dd7070Spatrick CGF.Builder.CreateIsNotNull(
4100e5dd7070Spatrick CGF.EmitLoadOfScalar(IL, S.getBeginLoc())));
4101e5dd7070Spatrick };
4102e5dd7070Spatrick
4103e5dd7070Spatrick bool HasCancel = false;
4104e5dd7070Spatrick if (auto *OSD = dyn_cast<OMPSectionsDirective>(&S))
4105e5dd7070Spatrick HasCancel = OSD->hasCancel();
4106e5dd7070Spatrick else if (auto *OPSD = dyn_cast<OMPParallelSectionsDirective>(&S))
4107e5dd7070Spatrick HasCancel = OPSD->hasCancel();
4108e5dd7070Spatrick OMPCancelStackRAII CancelRegion(*this, S.getDirectiveKind(), HasCancel);
4109e5dd7070Spatrick CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_sections, CodeGen,
4110e5dd7070Spatrick HasCancel);
4111e5dd7070Spatrick // Emit barrier for lastprivates only if 'sections' directive has 'nowait'
4112e5dd7070Spatrick // clause. Otherwise the barrier will be generated by the codegen for the
4113e5dd7070Spatrick // directive.
4114e5dd7070Spatrick if (HasLastprivates && S.getSingleClause<OMPNowaitClause>()) {
4115e5dd7070Spatrick // Emit implicit barrier to synchronize threads and avoid data races on
4116e5dd7070Spatrick // initialization of firstprivate variables.
4117e5dd7070Spatrick CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getBeginLoc(),
4118e5dd7070Spatrick OMPD_unknown);
4119e5dd7070Spatrick }
4120e5dd7070Spatrick }
4121e5dd7070Spatrick
EmitOMPSectionsDirective(const OMPSectionsDirective & S)4122e5dd7070Spatrick void CodeGenFunction::EmitOMPSectionsDirective(const OMPSectionsDirective &S) {
4123a9ac8606Spatrick if (CGM.getLangOpts().OpenMPIRBuilder) {
4124a9ac8606Spatrick llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
4125a9ac8606Spatrick using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
4126a9ac8606Spatrick using BodyGenCallbackTy = llvm::OpenMPIRBuilder::StorableBodyGenCallbackTy;
4127a9ac8606Spatrick
4128a9ac8606Spatrick auto FiniCB = [this](InsertPointTy IP) {
4129a9ac8606Spatrick OMPBuilderCBHelpers::FinalizeOMPRegion(*this, IP);
4130a9ac8606Spatrick };
4131a9ac8606Spatrick
4132a9ac8606Spatrick const CapturedStmt *ICS = S.getInnermostCapturedStmt();
4133a9ac8606Spatrick const Stmt *CapturedStmt = S.getInnermostCapturedStmt()->getCapturedStmt();
4134a9ac8606Spatrick const auto *CS = dyn_cast<CompoundStmt>(CapturedStmt);
4135a9ac8606Spatrick llvm::SmallVector<BodyGenCallbackTy, 4> SectionCBVector;
4136a9ac8606Spatrick if (CS) {
4137a9ac8606Spatrick for (const Stmt *SubStmt : CS->children()) {
4138a9ac8606Spatrick auto SectionCB = [this, SubStmt](InsertPointTy AllocaIP,
4139*12c85518Srobert InsertPointTy CodeGenIP) {
4140*12c85518Srobert OMPBuilderCBHelpers::EmitOMPInlinedRegionBody(
4141*12c85518Srobert *this, SubStmt, AllocaIP, CodeGenIP, "section");
4142a9ac8606Spatrick };
4143a9ac8606Spatrick SectionCBVector.push_back(SectionCB);
4144a9ac8606Spatrick }
4145a9ac8606Spatrick } else {
4146a9ac8606Spatrick auto SectionCB = [this, CapturedStmt](InsertPointTy AllocaIP,
4147*12c85518Srobert InsertPointTy CodeGenIP) {
4148*12c85518Srobert OMPBuilderCBHelpers::EmitOMPInlinedRegionBody(
4149*12c85518Srobert *this, CapturedStmt, AllocaIP, CodeGenIP, "section");
4150a9ac8606Spatrick };
4151a9ac8606Spatrick SectionCBVector.push_back(SectionCB);
4152a9ac8606Spatrick }
4153a9ac8606Spatrick
4154a9ac8606Spatrick // Privatization callback that performs appropriate action for
4155a9ac8606Spatrick // shared/private/firstprivate/lastprivate/copyin/... variables.
4156a9ac8606Spatrick //
4157a9ac8606Spatrick // TODO: This defaults to shared right now.
4158a9ac8606Spatrick auto PrivCB = [](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
4159a9ac8606Spatrick llvm::Value &, llvm::Value &Val, llvm::Value *&ReplVal) {
4160a9ac8606Spatrick // The next line is appropriate only for variables (Val) with the
4161a9ac8606Spatrick // data-sharing attribute "shared".
4162a9ac8606Spatrick ReplVal = &Val;
4163a9ac8606Spatrick
4164a9ac8606Spatrick return CodeGenIP;
4165a9ac8606Spatrick };
4166a9ac8606Spatrick
4167a9ac8606Spatrick CGCapturedStmtInfo CGSI(*ICS, CR_OpenMP);
4168a9ac8606Spatrick CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(*this, &CGSI);
4169a9ac8606Spatrick llvm::OpenMPIRBuilder::InsertPointTy AllocaIP(
4170a9ac8606Spatrick AllocaInsertPt->getParent(), AllocaInsertPt->getIterator());
4171a9ac8606Spatrick Builder.restoreIP(OMPBuilder.createSections(
4172a9ac8606Spatrick Builder, AllocaIP, SectionCBVector, PrivCB, FiniCB, S.hasCancel(),
4173a9ac8606Spatrick S.getSingleClause<OMPNowaitClause>()));
4174a9ac8606Spatrick return;
4175a9ac8606Spatrick }
4176e5dd7070Spatrick {
4177ec727ea7Spatrick auto LPCRegion =
4178ec727ea7Spatrick CGOpenMPRuntime::LastprivateConditionalRAII::disable(*this, S);
4179e5dd7070Spatrick OMPLexicalScope Scope(*this, S, OMPD_unknown);
4180e5dd7070Spatrick EmitSections(S);
4181e5dd7070Spatrick }
4182e5dd7070Spatrick // Emit an implicit barrier at the end.
4183e5dd7070Spatrick if (!S.getSingleClause<OMPNowaitClause>()) {
4184e5dd7070Spatrick CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getBeginLoc(),
4185e5dd7070Spatrick OMPD_sections);
4186e5dd7070Spatrick }
4187ec727ea7Spatrick // Check for outer lastprivate conditional update.
4188ec727ea7Spatrick checkForLastprivateConditionalUpdate(*this, S);
4189e5dd7070Spatrick }
4190e5dd7070Spatrick
EmitOMPSectionDirective(const OMPSectionDirective & S)4191e5dd7070Spatrick void CodeGenFunction::EmitOMPSectionDirective(const OMPSectionDirective &S) {
4192a9ac8606Spatrick if (CGM.getLangOpts().OpenMPIRBuilder) {
4193a9ac8606Spatrick llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
4194a9ac8606Spatrick using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
4195a9ac8606Spatrick
4196a9ac8606Spatrick const Stmt *SectionRegionBodyStmt = S.getAssociatedStmt();
4197a9ac8606Spatrick auto FiniCB = [this](InsertPointTy IP) {
4198a9ac8606Spatrick OMPBuilderCBHelpers::FinalizeOMPRegion(*this, IP);
4199e5dd7070Spatrick };
4200a9ac8606Spatrick
4201a9ac8606Spatrick auto BodyGenCB = [SectionRegionBodyStmt, this](InsertPointTy AllocaIP,
4202*12c85518Srobert InsertPointTy CodeGenIP) {
4203*12c85518Srobert OMPBuilderCBHelpers::EmitOMPInlinedRegionBody(
4204*12c85518Srobert *this, SectionRegionBodyStmt, AllocaIP, CodeGenIP, "section");
4205a9ac8606Spatrick };
4206a9ac8606Spatrick
4207a9ac8606Spatrick LexicalScope Scope(*this, S.getSourceRange());
4208a9ac8606Spatrick EmitStopPoint(&S);
4209a9ac8606Spatrick Builder.restoreIP(OMPBuilder.createSection(Builder, BodyGenCB, FiniCB));
4210a9ac8606Spatrick
4211a9ac8606Spatrick return;
4212a9ac8606Spatrick }
4213a9ac8606Spatrick LexicalScope Scope(*this, S.getSourceRange());
4214a9ac8606Spatrick EmitStopPoint(&S);
4215a9ac8606Spatrick EmitStmt(S.getAssociatedStmt());
4216e5dd7070Spatrick }
4217e5dd7070Spatrick
EmitOMPSingleDirective(const OMPSingleDirective & S)4218e5dd7070Spatrick void CodeGenFunction::EmitOMPSingleDirective(const OMPSingleDirective &S) {
4219e5dd7070Spatrick llvm::SmallVector<const Expr *, 8> CopyprivateVars;
4220e5dd7070Spatrick llvm::SmallVector<const Expr *, 8> DestExprs;
4221e5dd7070Spatrick llvm::SmallVector<const Expr *, 8> SrcExprs;
4222e5dd7070Spatrick llvm::SmallVector<const Expr *, 8> AssignmentOps;
4223e5dd7070Spatrick // Check if there are any 'copyprivate' clauses associated with this
4224e5dd7070Spatrick // 'single' construct.
4225e5dd7070Spatrick // Build a list of copyprivate variables along with helper expressions
4226e5dd7070Spatrick // (<source>, <destination>, <destination>=<source> expressions)
4227e5dd7070Spatrick for (const auto *C : S.getClausesOfKind<OMPCopyprivateClause>()) {
4228e5dd7070Spatrick CopyprivateVars.append(C->varlists().begin(), C->varlists().end());
4229e5dd7070Spatrick DestExprs.append(C->destination_exprs().begin(),
4230e5dd7070Spatrick C->destination_exprs().end());
4231e5dd7070Spatrick SrcExprs.append(C->source_exprs().begin(), C->source_exprs().end());
4232e5dd7070Spatrick AssignmentOps.append(C->assignment_ops().begin(),
4233e5dd7070Spatrick C->assignment_ops().end());
4234e5dd7070Spatrick }
4235e5dd7070Spatrick // Emit code for 'single' region along with 'copyprivate' clauses
4236e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
4237e5dd7070Spatrick Action.Enter(CGF);
4238e5dd7070Spatrick OMPPrivateScope SingleScope(CGF);
4239e5dd7070Spatrick (void)CGF.EmitOMPFirstprivateClause(S, SingleScope);
4240e5dd7070Spatrick CGF.EmitOMPPrivateClause(S, SingleScope);
4241e5dd7070Spatrick (void)SingleScope.Privatize();
4242e5dd7070Spatrick CGF.EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt());
4243e5dd7070Spatrick };
4244e5dd7070Spatrick {
4245ec727ea7Spatrick auto LPCRegion =
4246ec727ea7Spatrick CGOpenMPRuntime::LastprivateConditionalRAII::disable(*this, S);
4247e5dd7070Spatrick OMPLexicalScope Scope(*this, S, OMPD_unknown);
4248e5dd7070Spatrick CGM.getOpenMPRuntime().emitSingleRegion(*this, CodeGen, S.getBeginLoc(),
4249e5dd7070Spatrick CopyprivateVars, DestExprs,
4250e5dd7070Spatrick SrcExprs, AssignmentOps);
4251e5dd7070Spatrick }
4252e5dd7070Spatrick // Emit an implicit barrier at the end (to avoid data race on firstprivate
4253e5dd7070Spatrick // init or if no 'nowait' clause was specified and no 'copyprivate' clause).
4254e5dd7070Spatrick if (!S.getSingleClause<OMPNowaitClause>() && CopyprivateVars.empty()) {
4255e5dd7070Spatrick CGM.getOpenMPRuntime().emitBarrierCall(
4256e5dd7070Spatrick *this, S.getBeginLoc(),
4257e5dd7070Spatrick S.getSingleClause<OMPNowaitClause>() ? OMPD_unknown : OMPD_single);
4258e5dd7070Spatrick }
4259ec727ea7Spatrick // Check for outer lastprivate conditional update.
4260ec727ea7Spatrick checkForLastprivateConditionalUpdate(*this, S);
4261e5dd7070Spatrick }
4262e5dd7070Spatrick
emitMaster(CodeGenFunction & CGF,const OMPExecutableDirective & S)4263e5dd7070Spatrick static void emitMaster(CodeGenFunction &CGF, const OMPExecutableDirective &S) {
4264e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
4265e5dd7070Spatrick Action.Enter(CGF);
4266a9ac8606Spatrick CGF.EmitStmt(S.getRawStmt());
4267e5dd7070Spatrick };
4268e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitMasterRegion(CGF, CodeGen, S.getBeginLoc());
4269e5dd7070Spatrick }
4270e5dd7070Spatrick
EmitOMPMasterDirective(const OMPMasterDirective & S)4271e5dd7070Spatrick void CodeGenFunction::EmitOMPMasterDirective(const OMPMasterDirective &S) {
4272ec727ea7Spatrick if (CGM.getLangOpts().OpenMPIRBuilder) {
4273ec727ea7Spatrick llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
4274ec727ea7Spatrick using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
4275ec727ea7Spatrick
4276a9ac8606Spatrick const Stmt *MasterRegionBodyStmt = S.getAssociatedStmt();
4277ec727ea7Spatrick
4278ec727ea7Spatrick auto FiniCB = [this](InsertPointTy IP) {
4279ec727ea7Spatrick OMPBuilderCBHelpers::FinalizeOMPRegion(*this, IP);
4280ec727ea7Spatrick };
4281ec727ea7Spatrick
4282ec727ea7Spatrick auto BodyGenCB = [MasterRegionBodyStmt, this](InsertPointTy AllocaIP,
4283*12c85518Srobert InsertPointTy CodeGenIP) {
4284*12c85518Srobert OMPBuilderCBHelpers::EmitOMPInlinedRegionBody(
4285*12c85518Srobert *this, MasterRegionBodyStmt, AllocaIP, CodeGenIP, "master");
4286ec727ea7Spatrick };
4287ec727ea7Spatrick
4288a9ac8606Spatrick LexicalScope Scope(*this, S.getSourceRange());
4289a9ac8606Spatrick EmitStopPoint(&S);
4290a9ac8606Spatrick Builder.restoreIP(OMPBuilder.createMaster(Builder, BodyGenCB, FiniCB));
4291ec727ea7Spatrick
4292ec727ea7Spatrick return;
4293ec727ea7Spatrick }
4294a9ac8606Spatrick LexicalScope Scope(*this, S.getSourceRange());
4295a9ac8606Spatrick EmitStopPoint(&S);
4296e5dd7070Spatrick emitMaster(*this, S);
4297e5dd7070Spatrick }
4298e5dd7070Spatrick
emitMasked(CodeGenFunction & CGF,const OMPExecutableDirective & S)4299a9ac8606Spatrick static void emitMasked(CodeGenFunction &CGF, const OMPExecutableDirective &S) {
4300a9ac8606Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
4301a9ac8606Spatrick Action.Enter(CGF);
4302a9ac8606Spatrick CGF.EmitStmt(S.getRawStmt());
4303a9ac8606Spatrick };
4304a9ac8606Spatrick Expr *Filter = nullptr;
4305a9ac8606Spatrick if (const auto *FilterClause = S.getSingleClause<OMPFilterClause>())
4306a9ac8606Spatrick Filter = FilterClause->getThreadID();
4307a9ac8606Spatrick CGF.CGM.getOpenMPRuntime().emitMaskedRegion(CGF, CodeGen, S.getBeginLoc(),
4308a9ac8606Spatrick Filter);
4309a9ac8606Spatrick }
4310a9ac8606Spatrick
EmitOMPMaskedDirective(const OMPMaskedDirective & S)4311a9ac8606Spatrick void CodeGenFunction::EmitOMPMaskedDirective(const OMPMaskedDirective &S) {
4312a9ac8606Spatrick if (CGM.getLangOpts().OpenMPIRBuilder) {
4313a9ac8606Spatrick llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
4314a9ac8606Spatrick using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
4315a9ac8606Spatrick
4316a9ac8606Spatrick const Stmt *MaskedRegionBodyStmt = S.getAssociatedStmt();
4317a9ac8606Spatrick const Expr *Filter = nullptr;
4318a9ac8606Spatrick if (const auto *FilterClause = S.getSingleClause<OMPFilterClause>())
4319a9ac8606Spatrick Filter = FilterClause->getThreadID();
4320a9ac8606Spatrick llvm::Value *FilterVal = Filter
4321a9ac8606Spatrick ? EmitScalarExpr(Filter, CGM.Int32Ty)
4322a9ac8606Spatrick : llvm::ConstantInt::get(CGM.Int32Ty, /*V=*/0);
4323a9ac8606Spatrick
4324a9ac8606Spatrick auto FiniCB = [this](InsertPointTy IP) {
4325a9ac8606Spatrick OMPBuilderCBHelpers::FinalizeOMPRegion(*this, IP);
4326a9ac8606Spatrick };
4327a9ac8606Spatrick
4328a9ac8606Spatrick auto BodyGenCB = [MaskedRegionBodyStmt, this](InsertPointTy AllocaIP,
4329*12c85518Srobert InsertPointTy CodeGenIP) {
4330*12c85518Srobert OMPBuilderCBHelpers::EmitOMPInlinedRegionBody(
4331*12c85518Srobert *this, MaskedRegionBodyStmt, AllocaIP, CodeGenIP, "masked");
4332a9ac8606Spatrick };
4333a9ac8606Spatrick
4334a9ac8606Spatrick LexicalScope Scope(*this, S.getSourceRange());
4335a9ac8606Spatrick EmitStopPoint(&S);
4336a9ac8606Spatrick Builder.restoreIP(
4337a9ac8606Spatrick OMPBuilder.createMasked(Builder, BodyGenCB, FiniCB, FilterVal));
4338a9ac8606Spatrick
4339a9ac8606Spatrick return;
4340a9ac8606Spatrick }
4341a9ac8606Spatrick LexicalScope Scope(*this, S.getSourceRange());
4342a9ac8606Spatrick EmitStopPoint(&S);
4343a9ac8606Spatrick emitMasked(*this, S);
4344a9ac8606Spatrick }
4345a9ac8606Spatrick
EmitOMPCriticalDirective(const OMPCriticalDirective & S)4346e5dd7070Spatrick void CodeGenFunction::EmitOMPCriticalDirective(const OMPCriticalDirective &S) {
4347ec727ea7Spatrick if (CGM.getLangOpts().OpenMPIRBuilder) {
4348ec727ea7Spatrick llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
4349ec727ea7Spatrick using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
4350ec727ea7Spatrick
4351a9ac8606Spatrick const Stmt *CriticalRegionBodyStmt = S.getAssociatedStmt();
4352ec727ea7Spatrick const Expr *Hint = nullptr;
4353ec727ea7Spatrick if (const auto *HintClause = S.getSingleClause<OMPHintClause>())
4354ec727ea7Spatrick Hint = HintClause->getHint();
4355ec727ea7Spatrick
4356ec727ea7Spatrick // TODO: This is slightly different from what's currently being done in
4357ec727ea7Spatrick // clang. Fix the Int32Ty to IntPtrTy (pointer width size) when everything
4358ec727ea7Spatrick // about typing is final.
4359ec727ea7Spatrick llvm::Value *HintInst = nullptr;
4360ec727ea7Spatrick if (Hint)
4361ec727ea7Spatrick HintInst =
4362ec727ea7Spatrick Builder.CreateIntCast(EmitScalarExpr(Hint), CGM.Int32Ty, false);
4363ec727ea7Spatrick
4364ec727ea7Spatrick auto FiniCB = [this](InsertPointTy IP) {
4365ec727ea7Spatrick OMPBuilderCBHelpers::FinalizeOMPRegion(*this, IP);
4366ec727ea7Spatrick };
4367ec727ea7Spatrick
4368ec727ea7Spatrick auto BodyGenCB = [CriticalRegionBodyStmt, this](InsertPointTy AllocaIP,
4369*12c85518Srobert InsertPointTy CodeGenIP) {
4370*12c85518Srobert OMPBuilderCBHelpers::EmitOMPInlinedRegionBody(
4371*12c85518Srobert *this, CriticalRegionBodyStmt, AllocaIP, CodeGenIP, "critical");
4372ec727ea7Spatrick };
4373ec727ea7Spatrick
4374a9ac8606Spatrick LexicalScope Scope(*this, S.getSourceRange());
4375a9ac8606Spatrick EmitStopPoint(&S);
4376a9ac8606Spatrick Builder.restoreIP(OMPBuilder.createCritical(
4377ec727ea7Spatrick Builder, BodyGenCB, FiniCB, S.getDirectiveName().getAsString(),
4378ec727ea7Spatrick HintInst));
4379ec727ea7Spatrick
4380ec727ea7Spatrick return;
4381ec727ea7Spatrick }
4382ec727ea7Spatrick
4383e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
4384e5dd7070Spatrick Action.Enter(CGF);
4385a9ac8606Spatrick CGF.EmitStmt(S.getAssociatedStmt());
4386e5dd7070Spatrick };
4387e5dd7070Spatrick const Expr *Hint = nullptr;
4388e5dd7070Spatrick if (const auto *HintClause = S.getSingleClause<OMPHintClause>())
4389e5dd7070Spatrick Hint = HintClause->getHint();
4390a9ac8606Spatrick LexicalScope Scope(*this, S.getSourceRange());
4391a9ac8606Spatrick EmitStopPoint(&S);
4392e5dd7070Spatrick CGM.getOpenMPRuntime().emitCriticalRegion(*this,
4393e5dd7070Spatrick S.getDirectiveName().getAsString(),
4394e5dd7070Spatrick CodeGen, S.getBeginLoc(), Hint);
4395e5dd7070Spatrick }
4396e5dd7070Spatrick
EmitOMPParallelForDirective(const OMPParallelForDirective & S)4397e5dd7070Spatrick void CodeGenFunction::EmitOMPParallelForDirective(
4398e5dd7070Spatrick const OMPParallelForDirective &S) {
4399e5dd7070Spatrick // Emit directive as a combined directive that consists of two implicit
4400e5dd7070Spatrick // directives: 'parallel' with 'for' directive.
4401e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
4402e5dd7070Spatrick Action.Enter(CGF);
4403*12c85518Srobert emitOMPCopyinClause(CGF, S);
4404ec727ea7Spatrick (void)emitWorksharingDirective(CGF, S, S.hasCancel());
4405e5dd7070Spatrick };
4406ec727ea7Spatrick {
4407a9ac8606Spatrick const auto &&NumIteratorsGen = [&S](CodeGenFunction &CGF) {
4408a9ac8606Spatrick CodeGenFunction::OMPLocalDeclMapRAII Scope(CGF);
4409a9ac8606Spatrick CGCapturedStmtInfo CGSI(CR_OpenMP);
4410a9ac8606Spatrick CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGSI);
4411a9ac8606Spatrick OMPLoopScope LoopScope(CGF, S);
4412a9ac8606Spatrick return CGF.EmitScalarExpr(S.getNumIterations());
4413a9ac8606Spatrick };
4414*12c85518Srobert bool IsInscan = llvm::any_of(S.getClausesOfKind<OMPReductionClause>(),
4415*12c85518Srobert [](const OMPReductionClause *C) {
4416*12c85518Srobert return C->getModifier() == OMPC_REDUCTION_inscan;
4417*12c85518Srobert });
4418*12c85518Srobert if (IsInscan)
4419a9ac8606Spatrick emitScanBasedDirectiveDecls(*this, S, NumIteratorsGen);
4420ec727ea7Spatrick auto LPCRegion =
4421ec727ea7Spatrick CGOpenMPRuntime::LastprivateConditionalRAII::disable(*this, S);
4422e5dd7070Spatrick emitCommonOMPParallelDirective(*this, S, OMPD_for, CodeGen,
4423e5dd7070Spatrick emitEmptyBoundParameters);
4424*12c85518Srobert if (IsInscan)
4425*12c85518Srobert emitScanBasedDirectiveFinals(*this, S, NumIteratorsGen);
4426e5dd7070Spatrick }
4427ec727ea7Spatrick // Check for outer lastprivate conditional update.
4428ec727ea7Spatrick checkForLastprivateConditionalUpdate(*this, S);
4429ec727ea7Spatrick }
4430e5dd7070Spatrick
EmitOMPParallelForSimdDirective(const OMPParallelForSimdDirective & S)4431e5dd7070Spatrick void CodeGenFunction::EmitOMPParallelForSimdDirective(
4432e5dd7070Spatrick const OMPParallelForSimdDirective &S) {
4433e5dd7070Spatrick // Emit directive as a combined directive that consists of two implicit
4434e5dd7070Spatrick // directives: 'parallel' with 'for' directive.
4435e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
4436e5dd7070Spatrick Action.Enter(CGF);
4437*12c85518Srobert emitOMPCopyinClause(CGF, S);
4438ec727ea7Spatrick (void)emitWorksharingDirective(CGF, S, /*HasCancel=*/false);
4439e5dd7070Spatrick };
4440ec727ea7Spatrick {
4441a9ac8606Spatrick const auto &&NumIteratorsGen = [&S](CodeGenFunction &CGF) {
4442a9ac8606Spatrick CodeGenFunction::OMPLocalDeclMapRAII Scope(CGF);
4443a9ac8606Spatrick CGCapturedStmtInfo CGSI(CR_OpenMP);
4444a9ac8606Spatrick CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGSI);
4445a9ac8606Spatrick OMPLoopScope LoopScope(CGF, S);
4446a9ac8606Spatrick return CGF.EmitScalarExpr(S.getNumIterations());
4447a9ac8606Spatrick };
4448*12c85518Srobert bool IsInscan = llvm::any_of(S.getClausesOfKind<OMPReductionClause>(),
4449*12c85518Srobert [](const OMPReductionClause *C) {
4450*12c85518Srobert return C->getModifier() == OMPC_REDUCTION_inscan;
4451*12c85518Srobert });
4452*12c85518Srobert if (IsInscan)
4453a9ac8606Spatrick emitScanBasedDirectiveDecls(*this, S, NumIteratorsGen);
4454ec727ea7Spatrick auto LPCRegion =
4455ec727ea7Spatrick CGOpenMPRuntime::LastprivateConditionalRAII::disable(*this, S);
4456ec727ea7Spatrick emitCommonOMPParallelDirective(*this, S, OMPD_for_simd, CodeGen,
4457e5dd7070Spatrick emitEmptyBoundParameters);
4458*12c85518Srobert if (IsInscan)
4459*12c85518Srobert emitScanBasedDirectiveFinals(*this, S, NumIteratorsGen);
4460e5dd7070Spatrick }
4461ec727ea7Spatrick // Check for outer lastprivate conditional update.
4462ec727ea7Spatrick checkForLastprivateConditionalUpdate(*this, S);
4463ec727ea7Spatrick }
4464e5dd7070Spatrick
EmitOMPParallelMasterDirective(const OMPParallelMasterDirective & S)4465e5dd7070Spatrick void CodeGenFunction::EmitOMPParallelMasterDirective(
4466e5dd7070Spatrick const OMPParallelMasterDirective &S) {
4467e5dd7070Spatrick // Emit directive as a combined directive that consists of two implicit
4468e5dd7070Spatrick // directives: 'parallel' with 'master' directive.
4469e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
4470e5dd7070Spatrick Action.Enter(CGF);
4471e5dd7070Spatrick OMPPrivateScope PrivateScope(CGF);
4472*12c85518Srobert emitOMPCopyinClause(CGF, S);
4473e5dd7070Spatrick (void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
4474e5dd7070Spatrick CGF.EmitOMPPrivateClause(S, PrivateScope);
4475e5dd7070Spatrick CGF.EmitOMPReductionClauseInit(S, PrivateScope);
4476e5dd7070Spatrick (void)PrivateScope.Privatize();
4477e5dd7070Spatrick emitMaster(CGF, S);
4478e5dd7070Spatrick CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_parallel);
4479e5dd7070Spatrick };
4480ec727ea7Spatrick {
4481ec727ea7Spatrick auto LPCRegion =
4482ec727ea7Spatrick CGOpenMPRuntime::LastprivateConditionalRAII::disable(*this, S);
4483e5dd7070Spatrick emitCommonOMPParallelDirective(*this, S, OMPD_master, CodeGen,
4484e5dd7070Spatrick emitEmptyBoundParameters);
4485e5dd7070Spatrick emitPostUpdateForReductionClause(*this, S,
4486e5dd7070Spatrick [](CodeGenFunction &) { return nullptr; });
4487e5dd7070Spatrick }
4488ec727ea7Spatrick // Check for outer lastprivate conditional update.
4489ec727ea7Spatrick checkForLastprivateConditionalUpdate(*this, S);
4490ec727ea7Spatrick }
4491e5dd7070Spatrick
EmitOMPParallelSectionsDirective(const OMPParallelSectionsDirective & S)4492e5dd7070Spatrick void CodeGenFunction::EmitOMPParallelSectionsDirective(
4493e5dd7070Spatrick const OMPParallelSectionsDirective &S) {
4494e5dd7070Spatrick // Emit directive as a combined directive that consists of two implicit
4495e5dd7070Spatrick // directives: 'parallel' with 'sections' directive.
4496e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
4497e5dd7070Spatrick Action.Enter(CGF);
4498*12c85518Srobert emitOMPCopyinClause(CGF, S);
4499e5dd7070Spatrick CGF.EmitSections(S);
4500e5dd7070Spatrick };
4501ec727ea7Spatrick {
4502ec727ea7Spatrick auto LPCRegion =
4503ec727ea7Spatrick CGOpenMPRuntime::LastprivateConditionalRAII::disable(*this, S);
4504e5dd7070Spatrick emitCommonOMPParallelDirective(*this, S, OMPD_sections, CodeGen,
4505e5dd7070Spatrick emitEmptyBoundParameters);
4506e5dd7070Spatrick }
4507ec727ea7Spatrick // Check for outer lastprivate conditional update.
4508ec727ea7Spatrick checkForLastprivateConditionalUpdate(*this, S);
4509ec727ea7Spatrick }
4510e5dd7070Spatrick
4511a9ac8606Spatrick namespace {
4512a9ac8606Spatrick /// Get the list of variables declared in the context of the untied tasks.
4513a9ac8606Spatrick class CheckVarsEscapingUntiedTaskDeclContext final
4514a9ac8606Spatrick : public ConstStmtVisitor<CheckVarsEscapingUntiedTaskDeclContext> {
4515a9ac8606Spatrick llvm::SmallVector<const VarDecl *, 4> PrivateDecls;
4516a9ac8606Spatrick
4517a9ac8606Spatrick public:
4518a9ac8606Spatrick explicit CheckVarsEscapingUntiedTaskDeclContext() = default;
4519a9ac8606Spatrick virtual ~CheckVarsEscapingUntiedTaskDeclContext() = default;
VisitDeclStmt(const DeclStmt * S)4520a9ac8606Spatrick void VisitDeclStmt(const DeclStmt *S) {
4521a9ac8606Spatrick if (!S)
4522a9ac8606Spatrick return;
4523a9ac8606Spatrick // Need to privatize only local vars, static locals can be processed as is.
4524a9ac8606Spatrick for (const Decl *D : S->decls()) {
4525a9ac8606Spatrick if (const auto *VD = dyn_cast_or_null<VarDecl>(D))
4526a9ac8606Spatrick if (VD->hasLocalStorage())
4527a9ac8606Spatrick PrivateDecls.push_back(VD);
4528a9ac8606Spatrick }
4529a9ac8606Spatrick }
VisitOMPExecutableDirective(const OMPExecutableDirective *)4530*12c85518Srobert void VisitOMPExecutableDirective(const OMPExecutableDirective *) {}
VisitCapturedStmt(const CapturedStmt *)4531*12c85518Srobert void VisitCapturedStmt(const CapturedStmt *) {}
VisitLambdaExpr(const LambdaExpr *)4532*12c85518Srobert void VisitLambdaExpr(const LambdaExpr *) {}
VisitBlockExpr(const BlockExpr *)4533*12c85518Srobert void VisitBlockExpr(const BlockExpr *) {}
VisitStmt(const Stmt * S)4534a9ac8606Spatrick void VisitStmt(const Stmt *S) {
4535a9ac8606Spatrick if (!S)
4536a9ac8606Spatrick return;
4537a9ac8606Spatrick for (const Stmt *Child : S->children())
4538a9ac8606Spatrick if (Child)
4539a9ac8606Spatrick Visit(Child);
4540a9ac8606Spatrick }
4541a9ac8606Spatrick
4542a9ac8606Spatrick /// Swaps list of vars with the provided one.
getPrivateDecls() const4543a9ac8606Spatrick ArrayRef<const VarDecl *> getPrivateDecls() const { return PrivateDecls; }
4544a9ac8606Spatrick };
4545a9ac8606Spatrick } // anonymous namespace
4546a9ac8606Spatrick
buildDependences(const OMPExecutableDirective & S,OMPTaskDataTy & Data)4547*12c85518Srobert static void buildDependences(const OMPExecutableDirective &S,
4548*12c85518Srobert OMPTaskDataTy &Data) {
4549*12c85518Srobert
4550*12c85518Srobert // First look for 'omp_all_memory' and add this first.
4551*12c85518Srobert bool OmpAllMemory = false;
4552*12c85518Srobert if (llvm::any_of(
4553*12c85518Srobert S.getClausesOfKind<OMPDependClause>(), [](const OMPDependClause *C) {
4554*12c85518Srobert return C->getDependencyKind() == OMPC_DEPEND_outallmemory ||
4555*12c85518Srobert C->getDependencyKind() == OMPC_DEPEND_inoutallmemory;
4556*12c85518Srobert })) {
4557*12c85518Srobert OmpAllMemory = true;
4558*12c85518Srobert // Since both OMPC_DEPEND_outallmemory and OMPC_DEPEND_inoutallmemory are
4559*12c85518Srobert // equivalent to the runtime, always use OMPC_DEPEND_outallmemory to
4560*12c85518Srobert // simplify.
4561*12c85518Srobert OMPTaskDataTy::DependData &DD =
4562*12c85518Srobert Data.Dependences.emplace_back(OMPC_DEPEND_outallmemory,
4563*12c85518Srobert /*IteratorExpr=*/nullptr);
4564*12c85518Srobert // Add a nullptr Expr to simplify the codegen in emitDependData.
4565*12c85518Srobert DD.DepExprs.push_back(nullptr);
4566*12c85518Srobert }
4567*12c85518Srobert // Add remaining dependences skipping any 'out' or 'inout' if they are
4568*12c85518Srobert // overridden by 'omp_all_memory'.
4569*12c85518Srobert for (const auto *C : S.getClausesOfKind<OMPDependClause>()) {
4570*12c85518Srobert OpenMPDependClauseKind Kind = C->getDependencyKind();
4571*12c85518Srobert if (Kind == OMPC_DEPEND_outallmemory || Kind == OMPC_DEPEND_inoutallmemory)
4572*12c85518Srobert continue;
4573*12c85518Srobert if (OmpAllMemory && (Kind == OMPC_DEPEND_out || Kind == OMPC_DEPEND_inout))
4574*12c85518Srobert continue;
4575*12c85518Srobert OMPTaskDataTy::DependData &DD =
4576*12c85518Srobert Data.Dependences.emplace_back(C->getDependencyKind(), C->getModifier());
4577*12c85518Srobert DD.DepExprs.append(C->varlist_begin(), C->varlist_end());
4578*12c85518Srobert }
4579*12c85518Srobert }
4580*12c85518Srobert
EmitOMPTaskBasedDirective(const OMPExecutableDirective & S,const OpenMPDirectiveKind CapturedRegion,const RegionCodeGenTy & BodyGen,const TaskGenTy & TaskGen,OMPTaskDataTy & Data)4581e5dd7070Spatrick void CodeGenFunction::EmitOMPTaskBasedDirective(
4582e5dd7070Spatrick const OMPExecutableDirective &S, const OpenMPDirectiveKind CapturedRegion,
4583e5dd7070Spatrick const RegionCodeGenTy &BodyGen, const TaskGenTy &TaskGen,
4584e5dd7070Spatrick OMPTaskDataTy &Data) {
4585e5dd7070Spatrick // Emit outlined function for task construct.
4586e5dd7070Spatrick const CapturedStmt *CS = S.getCapturedStmt(CapturedRegion);
4587e5dd7070Spatrick auto I = CS->getCapturedDecl()->param_begin();
4588e5dd7070Spatrick auto PartId = std::next(I);
4589e5dd7070Spatrick auto TaskT = std::next(I, 4);
4590e5dd7070Spatrick // Check if the task is final
4591e5dd7070Spatrick if (const auto *Clause = S.getSingleClause<OMPFinalClause>()) {
4592e5dd7070Spatrick // If the condition constant folds and can be elided, try to avoid emitting
4593e5dd7070Spatrick // the condition and the dead arm of the if/else.
4594e5dd7070Spatrick const Expr *Cond = Clause->getCondition();
4595e5dd7070Spatrick bool CondConstant;
4596e5dd7070Spatrick if (ConstantFoldsToSimpleInteger(Cond, CondConstant))
4597e5dd7070Spatrick Data.Final.setInt(CondConstant);
4598e5dd7070Spatrick else
4599e5dd7070Spatrick Data.Final.setPointer(EvaluateExprAsBool(Cond));
4600e5dd7070Spatrick } else {
4601e5dd7070Spatrick // By default the task is not final.
4602e5dd7070Spatrick Data.Final.setInt(/*IntVal=*/false);
4603e5dd7070Spatrick }
4604e5dd7070Spatrick // Check if the task has 'priority' clause.
4605e5dd7070Spatrick if (const auto *Clause = S.getSingleClause<OMPPriorityClause>()) {
4606e5dd7070Spatrick const Expr *Prio = Clause->getPriority();
4607e5dd7070Spatrick Data.Priority.setInt(/*IntVal=*/true);
4608e5dd7070Spatrick Data.Priority.setPointer(EmitScalarConversion(
4609e5dd7070Spatrick EmitScalarExpr(Prio), Prio->getType(),
4610e5dd7070Spatrick getContext().getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1),
4611e5dd7070Spatrick Prio->getExprLoc()));
4612e5dd7070Spatrick }
4613e5dd7070Spatrick // The first function argument for tasks is a thread id, the second one is a
4614e5dd7070Spatrick // part id (0 for tied tasks, >=0 for untied task).
4615e5dd7070Spatrick llvm::DenseSet<const VarDecl *> EmittedAsPrivate;
4616e5dd7070Spatrick // Get list of private variables.
4617e5dd7070Spatrick for (const auto *C : S.getClausesOfKind<OMPPrivateClause>()) {
4618e5dd7070Spatrick auto IRef = C->varlist_begin();
4619e5dd7070Spatrick for (const Expr *IInit : C->private_copies()) {
4620e5dd7070Spatrick const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
4621e5dd7070Spatrick if (EmittedAsPrivate.insert(OrigVD->getCanonicalDecl()).second) {
4622e5dd7070Spatrick Data.PrivateVars.push_back(*IRef);
4623e5dd7070Spatrick Data.PrivateCopies.push_back(IInit);
4624e5dd7070Spatrick }
4625e5dd7070Spatrick ++IRef;
4626e5dd7070Spatrick }
4627e5dd7070Spatrick }
4628e5dd7070Spatrick EmittedAsPrivate.clear();
4629e5dd7070Spatrick // Get list of firstprivate variables.
4630e5dd7070Spatrick for (const auto *C : S.getClausesOfKind<OMPFirstprivateClause>()) {
4631e5dd7070Spatrick auto IRef = C->varlist_begin();
4632e5dd7070Spatrick auto IElemInitRef = C->inits().begin();
4633e5dd7070Spatrick for (const Expr *IInit : C->private_copies()) {
4634e5dd7070Spatrick const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
4635e5dd7070Spatrick if (EmittedAsPrivate.insert(OrigVD->getCanonicalDecl()).second) {
4636e5dd7070Spatrick Data.FirstprivateVars.push_back(*IRef);
4637e5dd7070Spatrick Data.FirstprivateCopies.push_back(IInit);
4638e5dd7070Spatrick Data.FirstprivateInits.push_back(*IElemInitRef);
4639e5dd7070Spatrick }
4640e5dd7070Spatrick ++IRef;
4641e5dd7070Spatrick ++IElemInitRef;
4642e5dd7070Spatrick }
4643e5dd7070Spatrick }
4644e5dd7070Spatrick // Get list of lastprivate variables (for taskloops).
4645a9ac8606Spatrick llvm::MapVector<const VarDecl *, const DeclRefExpr *> LastprivateDstsOrigs;
4646e5dd7070Spatrick for (const auto *C : S.getClausesOfKind<OMPLastprivateClause>()) {
4647e5dd7070Spatrick auto IRef = C->varlist_begin();
4648e5dd7070Spatrick auto ID = C->destination_exprs().begin();
4649e5dd7070Spatrick for (const Expr *IInit : C->private_copies()) {
4650e5dd7070Spatrick const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
4651e5dd7070Spatrick if (EmittedAsPrivate.insert(OrigVD->getCanonicalDecl()).second) {
4652e5dd7070Spatrick Data.LastprivateVars.push_back(*IRef);
4653e5dd7070Spatrick Data.LastprivateCopies.push_back(IInit);
4654e5dd7070Spatrick }
4655e5dd7070Spatrick LastprivateDstsOrigs.insert(
4656a9ac8606Spatrick std::make_pair(cast<VarDecl>(cast<DeclRefExpr>(*ID)->getDecl()),
4657a9ac8606Spatrick cast<DeclRefExpr>(*IRef)));
4658e5dd7070Spatrick ++IRef;
4659e5dd7070Spatrick ++ID;
4660e5dd7070Spatrick }
4661e5dd7070Spatrick }
4662e5dd7070Spatrick SmallVector<const Expr *, 4> LHSs;
4663e5dd7070Spatrick SmallVector<const Expr *, 4> RHSs;
4664e5dd7070Spatrick for (const auto *C : S.getClausesOfKind<OMPReductionClause>()) {
4665ec727ea7Spatrick Data.ReductionVars.append(C->varlist_begin(), C->varlist_end());
4666ec727ea7Spatrick Data.ReductionOrigs.append(C->varlist_begin(), C->varlist_end());
4667ec727ea7Spatrick Data.ReductionCopies.append(C->privates().begin(), C->privates().end());
4668ec727ea7Spatrick Data.ReductionOps.append(C->reduction_ops().begin(),
4669ec727ea7Spatrick C->reduction_ops().end());
4670ec727ea7Spatrick LHSs.append(C->lhs_exprs().begin(), C->lhs_exprs().end());
4671ec727ea7Spatrick RHSs.append(C->rhs_exprs().begin(), C->rhs_exprs().end());
4672e5dd7070Spatrick }
4673e5dd7070Spatrick Data.Reductions = CGM.getOpenMPRuntime().emitTaskReductionInit(
4674e5dd7070Spatrick *this, S.getBeginLoc(), LHSs, RHSs, Data);
4675e5dd7070Spatrick // Build list of dependences.
4676*12c85518Srobert buildDependences(S, Data);
4677a9ac8606Spatrick // Get list of local vars for untied tasks.
4678a9ac8606Spatrick if (!Data.Tied) {
4679a9ac8606Spatrick CheckVarsEscapingUntiedTaskDeclContext Checker;
4680a9ac8606Spatrick Checker.Visit(S.getInnermostCapturedStmt()->getCapturedStmt());
4681a9ac8606Spatrick Data.PrivateLocals.append(Checker.getPrivateDecls().begin(),
4682a9ac8606Spatrick Checker.getPrivateDecls().end());
4683a9ac8606Spatrick }
4684e5dd7070Spatrick auto &&CodeGen = [&Data, &S, CS, &BodyGen, &LastprivateDstsOrigs,
4685e5dd7070Spatrick CapturedRegion](CodeGenFunction &CGF,
4686e5dd7070Spatrick PrePostActionTy &Action) {
4687a9ac8606Spatrick llvm::MapVector<CanonicalDeclPtr<const VarDecl>,
4688a9ac8606Spatrick std::pair<Address, Address>>
4689a9ac8606Spatrick UntiedLocalVars;
4690e5dd7070Spatrick // Set proper addresses for generated private copies.
4691e5dd7070Spatrick OMPPrivateScope Scope(CGF);
4692*12c85518Srobert // Generate debug info for variables present in shared clause.
4693*12c85518Srobert if (auto *DI = CGF.getDebugInfo()) {
4694*12c85518Srobert llvm::SmallDenseMap<const VarDecl *, FieldDecl *> CaptureFields =
4695*12c85518Srobert CGF.CapturedStmtInfo->getCaptureFields();
4696*12c85518Srobert llvm::Value *ContextValue = CGF.CapturedStmtInfo->getContextValue();
4697*12c85518Srobert if (CaptureFields.size() && ContextValue) {
4698*12c85518Srobert unsigned CharWidth = CGF.getContext().getCharWidth();
4699*12c85518Srobert // The shared variables are packed together as members of structure.
4700*12c85518Srobert // So the address of each shared variable can be computed by adding
4701*12c85518Srobert // offset of it (within record) to the base address of record. For each
4702*12c85518Srobert // shared variable, debug intrinsic llvm.dbg.declare is generated with
4703*12c85518Srobert // appropriate expressions (DIExpression).
4704*12c85518Srobert // Ex:
4705*12c85518Srobert // %12 = load %struct.anon*, %struct.anon** %__context.addr.i
4706*12c85518Srobert // call void @llvm.dbg.declare(metadata %struct.anon* %12,
4707*12c85518Srobert // metadata !svar1,
4708*12c85518Srobert // metadata !DIExpression(DW_OP_deref))
4709*12c85518Srobert // call void @llvm.dbg.declare(metadata %struct.anon* %12,
4710*12c85518Srobert // metadata !svar2,
4711*12c85518Srobert // metadata !DIExpression(DW_OP_plus_uconst, 8, DW_OP_deref))
4712*12c85518Srobert for (auto It = CaptureFields.begin(); It != CaptureFields.end(); ++It) {
4713*12c85518Srobert const VarDecl *SharedVar = It->first;
4714*12c85518Srobert RecordDecl *CaptureRecord = It->second->getParent();
4715*12c85518Srobert const ASTRecordLayout &Layout =
4716*12c85518Srobert CGF.getContext().getASTRecordLayout(CaptureRecord);
4717*12c85518Srobert unsigned Offset =
4718*12c85518Srobert Layout.getFieldOffset(It->second->getFieldIndex()) / CharWidth;
4719*12c85518Srobert if (CGF.CGM.getCodeGenOpts().hasReducedDebugInfo())
4720*12c85518Srobert (void)DI->EmitDeclareOfAutoVariable(SharedVar, ContextValue,
4721*12c85518Srobert CGF.Builder, false);
4722*12c85518Srobert llvm::Instruction &Last = CGF.Builder.GetInsertBlock()->back();
4723*12c85518Srobert // Get the call dbg.declare instruction we just created and update
4724*12c85518Srobert // its DIExpression to add offset to base address.
4725*12c85518Srobert if (auto DDI = dyn_cast<llvm::DbgVariableIntrinsic>(&Last)) {
4726*12c85518Srobert SmallVector<uint64_t, 8> Ops;
4727*12c85518Srobert // Add offset to the base address if non zero.
4728*12c85518Srobert if (Offset) {
4729*12c85518Srobert Ops.push_back(llvm::dwarf::DW_OP_plus_uconst);
4730*12c85518Srobert Ops.push_back(Offset);
4731*12c85518Srobert }
4732*12c85518Srobert Ops.push_back(llvm::dwarf::DW_OP_deref);
4733*12c85518Srobert auto &Ctx = DDI->getContext();
4734*12c85518Srobert llvm::DIExpression *DIExpr = llvm::DIExpression::get(Ctx, Ops);
4735*12c85518Srobert Last.setOperand(2, llvm::MetadataAsValue::get(Ctx, DIExpr));
4736*12c85518Srobert }
4737*12c85518Srobert }
4738*12c85518Srobert }
4739*12c85518Srobert }
4740ec727ea7Spatrick llvm::SmallVector<std::pair<const VarDecl *, Address>, 16> FirstprivatePtrs;
4741e5dd7070Spatrick if (!Data.PrivateVars.empty() || !Data.FirstprivateVars.empty() ||
4742a9ac8606Spatrick !Data.LastprivateVars.empty() || !Data.PrivateLocals.empty()) {
4743e5dd7070Spatrick enum { PrivatesParam = 2, CopyFnParam = 3 };
4744e5dd7070Spatrick llvm::Value *CopyFn = CGF.Builder.CreateLoad(
4745e5dd7070Spatrick CGF.GetAddrOfLocalVar(CS->getCapturedDecl()->getParam(CopyFnParam)));
4746e5dd7070Spatrick llvm::Value *PrivatesPtr = CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(
4747e5dd7070Spatrick CS->getCapturedDecl()->getParam(PrivatesParam)));
4748e5dd7070Spatrick // Map privates.
4749e5dd7070Spatrick llvm::SmallVector<std::pair<const VarDecl *, Address>, 16> PrivatePtrs;
4750e5dd7070Spatrick llvm::SmallVector<llvm::Value *, 16> CallArgs;
4751a9ac8606Spatrick llvm::SmallVector<llvm::Type *, 4> ParamTypes;
4752e5dd7070Spatrick CallArgs.push_back(PrivatesPtr);
4753a9ac8606Spatrick ParamTypes.push_back(PrivatesPtr->getType());
4754e5dd7070Spatrick for (const Expr *E : Data.PrivateVars) {
4755e5dd7070Spatrick const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
4756e5dd7070Spatrick Address PrivatePtr = CGF.CreateMemTemp(
4757e5dd7070Spatrick CGF.getContext().getPointerType(E->getType()), ".priv.ptr.addr");
4758e5dd7070Spatrick PrivatePtrs.emplace_back(VD, PrivatePtr);
4759e5dd7070Spatrick CallArgs.push_back(PrivatePtr.getPointer());
4760a9ac8606Spatrick ParamTypes.push_back(PrivatePtr.getType());
4761e5dd7070Spatrick }
4762e5dd7070Spatrick for (const Expr *E : Data.FirstprivateVars) {
4763e5dd7070Spatrick const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
4764e5dd7070Spatrick Address PrivatePtr =
4765e5dd7070Spatrick CGF.CreateMemTemp(CGF.getContext().getPointerType(E->getType()),
4766e5dd7070Spatrick ".firstpriv.ptr.addr");
4767e5dd7070Spatrick PrivatePtrs.emplace_back(VD, PrivatePtr);
4768ec727ea7Spatrick FirstprivatePtrs.emplace_back(VD, PrivatePtr);
4769e5dd7070Spatrick CallArgs.push_back(PrivatePtr.getPointer());
4770a9ac8606Spatrick ParamTypes.push_back(PrivatePtr.getType());
4771e5dd7070Spatrick }
4772e5dd7070Spatrick for (const Expr *E : Data.LastprivateVars) {
4773e5dd7070Spatrick const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
4774e5dd7070Spatrick Address PrivatePtr =
4775e5dd7070Spatrick CGF.CreateMemTemp(CGF.getContext().getPointerType(E->getType()),
4776e5dd7070Spatrick ".lastpriv.ptr.addr");
4777e5dd7070Spatrick PrivatePtrs.emplace_back(VD, PrivatePtr);
4778e5dd7070Spatrick CallArgs.push_back(PrivatePtr.getPointer());
4779a9ac8606Spatrick ParamTypes.push_back(PrivatePtr.getType());
4780e5dd7070Spatrick }
4781a9ac8606Spatrick for (const VarDecl *VD : Data.PrivateLocals) {
4782a9ac8606Spatrick QualType Ty = VD->getType().getNonReferenceType();
4783a9ac8606Spatrick if (VD->getType()->isLValueReferenceType())
4784a9ac8606Spatrick Ty = CGF.getContext().getPointerType(Ty);
4785a9ac8606Spatrick if (isAllocatableDecl(VD))
4786a9ac8606Spatrick Ty = CGF.getContext().getPointerType(Ty);
4787a9ac8606Spatrick Address PrivatePtr = CGF.CreateMemTemp(
4788a9ac8606Spatrick CGF.getContext().getPointerType(Ty), ".local.ptr.addr");
4789a9ac8606Spatrick auto Result = UntiedLocalVars.insert(
4790a9ac8606Spatrick std::make_pair(VD, std::make_pair(PrivatePtr, Address::invalid())));
4791a9ac8606Spatrick // If key exists update in place.
4792a9ac8606Spatrick if (Result.second == false)
4793a9ac8606Spatrick *Result.first = std::make_pair(
4794a9ac8606Spatrick VD, std::make_pair(PrivatePtr, Address::invalid()));
4795a9ac8606Spatrick CallArgs.push_back(PrivatePtr.getPointer());
4796a9ac8606Spatrick ParamTypes.push_back(PrivatePtr.getType());
4797a9ac8606Spatrick }
4798a9ac8606Spatrick auto *CopyFnTy = llvm::FunctionType::get(CGF.Builder.getVoidTy(),
4799a9ac8606Spatrick ParamTypes, /*isVarArg=*/false);
4800a9ac8606Spatrick CopyFn = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
4801a9ac8606Spatrick CopyFn, CopyFnTy->getPointerTo());
4802e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitOutlinedFunctionCall(
4803e5dd7070Spatrick CGF, S.getBeginLoc(), {CopyFnTy, CopyFn}, CallArgs);
4804e5dd7070Spatrick for (const auto &Pair : LastprivateDstsOrigs) {
4805e5dd7070Spatrick const auto *OrigVD = cast<VarDecl>(Pair.second->getDecl());
4806e5dd7070Spatrick DeclRefExpr DRE(CGF.getContext(), const_cast<VarDecl *>(OrigVD),
4807e5dd7070Spatrick /*RefersToEnclosingVariableOrCapture=*/
4808e5dd7070Spatrick CGF.CapturedStmtInfo->lookup(OrigVD) != nullptr,
4809e5dd7070Spatrick Pair.second->getType(), VK_LValue,
4810e5dd7070Spatrick Pair.second->getExprLoc());
4811*12c85518Srobert Scope.addPrivate(Pair.first, CGF.EmitLValue(&DRE).getAddress(CGF));
4812e5dd7070Spatrick }
4813e5dd7070Spatrick for (const auto &Pair : PrivatePtrs) {
4814*12c85518Srobert Address Replacement = Address(
4815*12c85518Srobert CGF.Builder.CreateLoad(Pair.second),
4816*12c85518Srobert CGF.ConvertTypeForMem(Pair.first->getType().getNonReferenceType()),
4817e5dd7070Spatrick CGF.getContext().getDeclAlign(Pair.first));
4818*12c85518Srobert Scope.addPrivate(Pair.first, Replacement);
4819*12c85518Srobert if (auto *DI = CGF.getDebugInfo())
4820*12c85518Srobert if (CGF.CGM.getCodeGenOpts().hasReducedDebugInfo())
4821*12c85518Srobert (void)DI->EmitDeclareOfAutoVariable(
4822*12c85518Srobert Pair.first, Pair.second.getPointer(), CGF.Builder,
4823*12c85518Srobert /*UsePointerValue*/ true);
4824e5dd7070Spatrick }
4825a9ac8606Spatrick // Adjust mapping for internal locals by mapping actual memory instead of
4826a9ac8606Spatrick // a pointer to this memory.
4827a9ac8606Spatrick for (auto &Pair : UntiedLocalVars) {
4828*12c85518Srobert QualType VDType = Pair.first->getType().getNonReferenceType();
4829a9ac8606Spatrick if (isAllocatableDecl(Pair.first)) {
4830a9ac8606Spatrick llvm::Value *Ptr = CGF.Builder.CreateLoad(Pair.second.first);
4831*12c85518Srobert Address Replacement(
4832*12c85518Srobert Ptr,
4833*12c85518Srobert CGF.ConvertTypeForMem(CGF.getContext().getPointerType(VDType)),
4834*12c85518Srobert CGF.getPointerAlign());
4835a9ac8606Spatrick Pair.second.first = Replacement;
4836a9ac8606Spatrick Ptr = CGF.Builder.CreateLoad(Replacement);
4837*12c85518Srobert Replacement = Address(Ptr, CGF.ConvertTypeForMem(VDType),
4838*12c85518Srobert CGF.getContext().getDeclAlign(Pair.first));
4839a9ac8606Spatrick Pair.second.second = Replacement;
4840a9ac8606Spatrick } else {
4841a9ac8606Spatrick llvm::Value *Ptr = CGF.Builder.CreateLoad(Pair.second.first);
4842*12c85518Srobert Address Replacement(Ptr, CGF.ConvertTypeForMem(VDType),
4843*12c85518Srobert CGF.getContext().getDeclAlign(Pair.first));
4844a9ac8606Spatrick Pair.second.first = Replacement;
4845a9ac8606Spatrick }
4846a9ac8606Spatrick }
4847e5dd7070Spatrick }
4848e5dd7070Spatrick if (Data.Reductions) {
4849ec727ea7Spatrick OMPPrivateScope FirstprivateScope(CGF);
4850ec727ea7Spatrick for (const auto &Pair : FirstprivatePtrs) {
4851*12c85518Srobert Address Replacement(
4852*12c85518Srobert CGF.Builder.CreateLoad(Pair.second),
4853*12c85518Srobert CGF.ConvertTypeForMem(Pair.first->getType().getNonReferenceType()),
4854ec727ea7Spatrick CGF.getContext().getDeclAlign(Pair.first));
4855*12c85518Srobert FirstprivateScope.addPrivate(Pair.first, Replacement);
4856ec727ea7Spatrick }
4857ec727ea7Spatrick (void)FirstprivateScope.Privatize();
4858e5dd7070Spatrick OMPLexicalScope LexScope(CGF, S, CapturedRegion);
4859ec727ea7Spatrick ReductionCodeGen RedCG(Data.ReductionVars, Data.ReductionVars,
4860ec727ea7Spatrick Data.ReductionCopies, Data.ReductionOps);
4861e5dd7070Spatrick llvm::Value *ReductionsPtr = CGF.Builder.CreateLoad(
4862e5dd7070Spatrick CGF.GetAddrOfLocalVar(CS->getCapturedDecl()->getParam(9)));
4863e5dd7070Spatrick for (unsigned Cnt = 0, E = Data.ReductionVars.size(); Cnt < E; ++Cnt) {
4864ec727ea7Spatrick RedCG.emitSharedOrigLValue(CGF, Cnt);
4865e5dd7070Spatrick RedCG.emitAggregateType(CGF, Cnt);
4866e5dd7070Spatrick // FIXME: This must removed once the runtime library is fixed.
4867e5dd7070Spatrick // Emit required threadprivate variables for
4868e5dd7070Spatrick // initializer/combiner/finalizer.
4869e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitTaskReductionFixups(CGF, S.getBeginLoc(),
4870e5dd7070Spatrick RedCG, Cnt);
4871e5dd7070Spatrick Address Replacement = CGF.CGM.getOpenMPRuntime().getTaskReductionItem(
4872e5dd7070Spatrick CGF, S.getBeginLoc(), ReductionsPtr, RedCG.getSharedLValue(Cnt));
4873e5dd7070Spatrick Replacement =
4874e5dd7070Spatrick Address(CGF.EmitScalarConversion(
4875e5dd7070Spatrick Replacement.getPointer(), CGF.getContext().VoidPtrTy,
4876e5dd7070Spatrick CGF.getContext().getPointerType(
4877e5dd7070Spatrick Data.ReductionCopies[Cnt]->getType()),
4878e5dd7070Spatrick Data.ReductionCopies[Cnt]->getExprLoc()),
4879*12c85518Srobert CGF.ConvertTypeForMem(Data.ReductionCopies[Cnt]->getType()),
4880e5dd7070Spatrick Replacement.getAlignment());
4881e5dd7070Spatrick Replacement = RedCG.adjustPrivateAddress(CGF, Cnt, Replacement);
4882*12c85518Srobert Scope.addPrivate(RedCG.getBaseDecl(Cnt), Replacement);
4883e5dd7070Spatrick }
4884e5dd7070Spatrick }
4885e5dd7070Spatrick // Privatize all private variables except for in_reduction items.
4886e5dd7070Spatrick (void)Scope.Privatize();
4887e5dd7070Spatrick SmallVector<const Expr *, 4> InRedVars;
4888e5dd7070Spatrick SmallVector<const Expr *, 4> InRedPrivs;
4889e5dd7070Spatrick SmallVector<const Expr *, 4> InRedOps;
4890e5dd7070Spatrick SmallVector<const Expr *, 4> TaskgroupDescriptors;
4891e5dd7070Spatrick for (const auto *C : S.getClausesOfKind<OMPInReductionClause>()) {
4892e5dd7070Spatrick auto IPriv = C->privates().begin();
4893e5dd7070Spatrick auto IRed = C->reduction_ops().begin();
4894e5dd7070Spatrick auto ITD = C->taskgroup_descriptors().begin();
4895e5dd7070Spatrick for (const Expr *Ref : C->varlists()) {
4896e5dd7070Spatrick InRedVars.emplace_back(Ref);
4897e5dd7070Spatrick InRedPrivs.emplace_back(*IPriv);
4898e5dd7070Spatrick InRedOps.emplace_back(*IRed);
4899e5dd7070Spatrick TaskgroupDescriptors.emplace_back(*ITD);
4900e5dd7070Spatrick std::advance(IPriv, 1);
4901e5dd7070Spatrick std::advance(IRed, 1);
4902e5dd7070Spatrick std::advance(ITD, 1);
4903e5dd7070Spatrick }
4904e5dd7070Spatrick }
4905e5dd7070Spatrick // Privatize in_reduction items here, because taskgroup descriptors must be
4906e5dd7070Spatrick // privatized earlier.
4907e5dd7070Spatrick OMPPrivateScope InRedScope(CGF);
4908e5dd7070Spatrick if (!InRedVars.empty()) {
4909ec727ea7Spatrick ReductionCodeGen RedCG(InRedVars, InRedVars, InRedPrivs, InRedOps);
4910e5dd7070Spatrick for (unsigned Cnt = 0, E = InRedVars.size(); Cnt < E; ++Cnt) {
4911ec727ea7Spatrick RedCG.emitSharedOrigLValue(CGF, Cnt);
4912e5dd7070Spatrick RedCG.emitAggregateType(CGF, Cnt);
4913e5dd7070Spatrick // The taskgroup descriptor variable is always implicit firstprivate and
4914e5dd7070Spatrick // privatized already during processing of the firstprivates.
4915e5dd7070Spatrick // FIXME: This must removed once the runtime library is fixed.
4916e5dd7070Spatrick // Emit required threadprivate variables for
4917e5dd7070Spatrick // initializer/combiner/finalizer.
4918e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitTaskReductionFixups(CGF, S.getBeginLoc(),
4919e5dd7070Spatrick RedCG, Cnt);
4920ec727ea7Spatrick llvm::Value *ReductionsPtr;
4921ec727ea7Spatrick if (const Expr *TRExpr = TaskgroupDescriptors[Cnt]) {
4922ec727ea7Spatrick ReductionsPtr = CGF.EmitLoadOfScalar(CGF.EmitLValue(TRExpr),
4923ec727ea7Spatrick TRExpr->getExprLoc());
4924ec727ea7Spatrick } else {
4925ec727ea7Spatrick ReductionsPtr = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
4926ec727ea7Spatrick }
4927e5dd7070Spatrick Address Replacement = CGF.CGM.getOpenMPRuntime().getTaskReductionItem(
4928e5dd7070Spatrick CGF, S.getBeginLoc(), ReductionsPtr, RedCG.getSharedLValue(Cnt));
4929e5dd7070Spatrick Replacement = Address(
4930e5dd7070Spatrick CGF.EmitScalarConversion(
4931e5dd7070Spatrick Replacement.getPointer(), CGF.getContext().VoidPtrTy,
4932e5dd7070Spatrick CGF.getContext().getPointerType(InRedPrivs[Cnt]->getType()),
4933e5dd7070Spatrick InRedPrivs[Cnt]->getExprLoc()),
4934*12c85518Srobert CGF.ConvertTypeForMem(InRedPrivs[Cnt]->getType()),
4935e5dd7070Spatrick Replacement.getAlignment());
4936e5dd7070Spatrick Replacement = RedCG.adjustPrivateAddress(CGF, Cnt, Replacement);
4937*12c85518Srobert InRedScope.addPrivate(RedCG.getBaseDecl(Cnt), Replacement);
4938e5dd7070Spatrick }
4939e5dd7070Spatrick }
4940e5dd7070Spatrick (void)InRedScope.Privatize();
4941e5dd7070Spatrick
4942a9ac8606Spatrick CGOpenMPRuntime::UntiedTaskLocalDeclsRAII LocalVarsScope(CGF,
4943a9ac8606Spatrick UntiedLocalVars);
4944e5dd7070Spatrick Action.Enter(CGF);
4945e5dd7070Spatrick BodyGen(CGF);
4946e5dd7070Spatrick };
4947e5dd7070Spatrick llvm::Function *OutlinedFn = CGM.getOpenMPRuntime().emitTaskOutlinedFunction(
4948e5dd7070Spatrick S, *I, *PartId, *TaskT, S.getDirectiveKind(), CodeGen, Data.Tied,
4949e5dd7070Spatrick Data.NumberOfParts);
4950*12c85518Srobert OMPLexicalScope Scope(*this, S, std::nullopt,
4951e5dd7070Spatrick !isOpenMPParallelDirective(S.getDirectiveKind()) &&
4952e5dd7070Spatrick !isOpenMPSimdDirective(S.getDirectiveKind()));
4953e5dd7070Spatrick TaskGen(*this, OutlinedFn, Data);
4954e5dd7070Spatrick }
4955e5dd7070Spatrick
4956e5dd7070Spatrick static ImplicitParamDecl *
createImplicitFirstprivateForType(ASTContext & C,OMPTaskDataTy & Data,QualType Ty,CapturedDecl * CD,SourceLocation Loc)4957e5dd7070Spatrick createImplicitFirstprivateForType(ASTContext &C, OMPTaskDataTy &Data,
4958e5dd7070Spatrick QualType Ty, CapturedDecl *CD,
4959e5dd7070Spatrick SourceLocation Loc) {
4960e5dd7070Spatrick auto *OrigVD = ImplicitParamDecl::Create(C, CD, Loc, /*Id=*/nullptr, Ty,
4961e5dd7070Spatrick ImplicitParamDecl::Other);
4962e5dd7070Spatrick auto *OrigRef = DeclRefExpr::Create(
4963e5dd7070Spatrick C, NestedNameSpecifierLoc(), SourceLocation(), OrigVD,
4964e5dd7070Spatrick /*RefersToEnclosingVariableOrCapture=*/false, Loc, Ty, VK_LValue);
4965e5dd7070Spatrick auto *PrivateVD = ImplicitParamDecl::Create(C, CD, Loc, /*Id=*/nullptr, Ty,
4966e5dd7070Spatrick ImplicitParamDecl::Other);
4967e5dd7070Spatrick auto *PrivateRef = DeclRefExpr::Create(
4968e5dd7070Spatrick C, NestedNameSpecifierLoc(), SourceLocation(), PrivateVD,
4969e5dd7070Spatrick /*RefersToEnclosingVariableOrCapture=*/false, Loc, Ty, VK_LValue);
4970e5dd7070Spatrick QualType ElemType = C.getBaseElementType(Ty);
4971e5dd7070Spatrick auto *InitVD = ImplicitParamDecl::Create(C, CD, Loc, /*Id=*/nullptr, ElemType,
4972e5dd7070Spatrick ImplicitParamDecl::Other);
4973e5dd7070Spatrick auto *InitRef = DeclRefExpr::Create(
4974e5dd7070Spatrick C, NestedNameSpecifierLoc(), SourceLocation(), InitVD,
4975e5dd7070Spatrick /*RefersToEnclosingVariableOrCapture=*/false, Loc, ElemType, VK_LValue);
4976e5dd7070Spatrick PrivateVD->setInitStyle(VarDecl::CInit);
4977e5dd7070Spatrick PrivateVD->setInit(ImplicitCastExpr::Create(C, ElemType, CK_LValueToRValue,
4978e5dd7070Spatrick InitRef, /*BasePath=*/nullptr,
4979a9ac8606Spatrick VK_PRValue, FPOptionsOverride()));
4980e5dd7070Spatrick Data.FirstprivateVars.emplace_back(OrigRef);
4981e5dd7070Spatrick Data.FirstprivateCopies.emplace_back(PrivateRef);
4982e5dd7070Spatrick Data.FirstprivateInits.emplace_back(InitRef);
4983e5dd7070Spatrick return OrigVD;
4984e5dd7070Spatrick }
4985e5dd7070Spatrick
EmitOMPTargetTaskBasedDirective(const OMPExecutableDirective & S,const RegionCodeGenTy & BodyGen,OMPTargetDataInfo & InputInfo)4986e5dd7070Spatrick void CodeGenFunction::EmitOMPTargetTaskBasedDirective(
4987e5dd7070Spatrick const OMPExecutableDirective &S, const RegionCodeGenTy &BodyGen,
4988e5dd7070Spatrick OMPTargetDataInfo &InputInfo) {
4989e5dd7070Spatrick // Emit outlined function for task construct.
4990e5dd7070Spatrick const CapturedStmt *CS = S.getCapturedStmt(OMPD_task);
4991e5dd7070Spatrick Address CapturedStruct = GenerateCapturedStmtArgument(*CS);
4992e5dd7070Spatrick QualType SharedsTy = getContext().getRecordType(CS->getCapturedRecordDecl());
4993e5dd7070Spatrick auto I = CS->getCapturedDecl()->param_begin();
4994e5dd7070Spatrick auto PartId = std::next(I);
4995e5dd7070Spatrick auto TaskT = std::next(I, 4);
4996e5dd7070Spatrick OMPTaskDataTy Data;
4997e5dd7070Spatrick // The task is not final.
4998e5dd7070Spatrick Data.Final.setInt(/*IntVal=*/false);
4999e5dd7070Spatrick // Get list of firstprivate variables.
5000e5dd7070Spatrick for (const auto *C : S.getClausesOfKind<OMPFirstprivateClause>()) {
5001e5dd7070Spatrick auto IRef = C->varlist_begin();
5002e5dd7070Spatrick auto IElemInitRef = C->inits().begin();
5003e5dd7070Spatrick for (auto *IInit : C->private_copies()) {
5004e5dd7070Spatrick Data.FirstprivateVars.push_back(*IRef);
5005e5dd7070Spatrick Data.FirstprivateCopies.push_back(IInit);
5006e5dd7070Spatrick Data.FirstprivateInits.push_back(*IElemInitRef);
5007e5dd7070Spatrick ++IRef;
5008e5dd7070Spatrick ++IElemInitRef;
5009e5dd7070Spatrick }
5010e5dd7070Spatrick }
5011*12c85518Srobert SmallVector<const Expr *, 4> LHSs;
5012*12c85518Srobert SmallVector<const Expr *, 4> RHSs;
5013*12c85518Srobert for (const auto *C : S.getClausesOfKind<OMPInReductionClause>()) {
5014*12c85518Srobert Data.ReductionVars.append(C->varlist_begin(), C->varlist_end());
5015*12c85518Srobert Data.ReductionOrigs.append(C->varlist_begin(), C->varlist_end());
5016*12c85518Srobert Data.ReductionCopies.append(C->privates().begin(), C->privates().end());
5017*12c85518Srobert Data.ReductionOps.append(C->reduction_ops().begin(),
5018*12c85518Srobert C->reduction_ops().end());
5019*12c85518Srobert LHSs.append(C->lhs_exprs().begin(), C->lhs_exprs().end());
5020*12c85518Srobert RHSs.append(C->rhs_exprs().begin(), C->rhs_exprs().end());
5021*12c85518Srobert }
5022e5dd7070Spatrick OMPPrivateScope TargetScope(*this);
5023e5dd7070Spatrick VarDecl *BPVD = nullptr;
5024e5dd7070Spatrick VarDecl *PVD = nullptr;
5025e5dd7070Spatrick VarDecl *SVD = nullptr;
5026a9ac8606Spatrick VarDecl *MVD = nullptr;
5027e5dd7070Spatrick if (InputInfo.NumberOfTargetItems > 0) {
5028e5dd7070Spatrick auto *CD = CapturedDecl::Create(
5029e5dd7070Spatrick getContext(), getContext().getTranslationUnitDecl(), /*NumParams=*/0);
5030e5dd7070Spatrick llvm::APInt ArrSize(/*numBits=*/32, InputInfo.NumberOfTargetItems);
5031a9ac8606Spatrick QualType BaseAndPointerAndMapperType = getContext().getConstantArrayType(
5032e5dd7070Spatrick getContext().VoidPtrTy, ArrSize, nullptr, ArrayType::Normal,
5033e5dd7070Spatrick /*IndexTypeQuals=*/0);
5034e5dd7070Spatrick BPVD = createImplicitFirstprivateForType(
5035a9ac8606Spatrick getContext(), Data, BaseAndPointerAndMapperType, CD, S.getBeginLoc());
5036e5dd7070Spatrick PVD = createImplicitFirstprivateForType(
5037a9ac8606Spatrick getContext(), Data, BaseAndPointerAndMapperType, CD, S.getBeginLoc());
5038e5dd7070Spatrick QualType SizesType = getContext().getConstantArrayType(
5039e5dd7070Spatrick getContext().getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1),
5040e5dd7070Spatrick ArrSize, nullptr, ArrayType::Normal,
5041e5dd7070Spatrick /*IndexTypeQuals=*/0);
5042e5dd7070Spatrick SVD = createImplicitFirstprivateForType(getContext(), Data, SizesType, CD,
5043e5dd7070Spatrick S.getBeginLoc());
5044*12c85518Srobert TargetScope.addPrivate(BPVD, InputInfo.BasePointersArray);
5045*12c85518Srobert TargetScope.addPrivate(PVD, InputInfo.PointersArray);
5046*12c85518Srobert TargetScope.addPrivate(SVD, InputInfo.SizesArray);
5047a9ac8606Spatrick // If there is no user-defined mapper, the mapper array will be nullptr. In
5048a9ac8606Spatrick // this case, we don't need to privatize it.
5049*12c85518Srobert if (!isa_and_nonnull<llvm::ConstantPointerNull>(
5050a9ac8606Spatrick InputInfo.MappersArray.getPointer())) {
5051a9ac8606Spatrick MVD = createImplicitFirstprivateForType(
5052a9ac8606Spatrick getContext(), Data, BaseAndPointerAndMapperType, CD, S.getBeginLoc());
5053*12c85518Srobert TargetScope.addPrivate(MVD, InputInfo.MappersArray);
5054a9ac8606Spatrick }
5055e5dd7070Spatrick }
5056e5dd7070Spatrick (void)TargetScope.Privatize();
5057*12c85518Srobert buildDependences(S, Data);
5058a9ac8606Spatrick auto &&CodeGen = [&Data, &S, CS, &BodyGen, BPVD, PVD, SVD, MVD,
5059e5dd7070Spatrick &InputInfo](CodeGenFunction &CGF, PrePostActionTy &Action) {
5060e5dd7070Spatrick // Set proper addresses for generated private copies.
5061e5dd7070Spatrick OMPPrivateScope Scope(CGF);
5062e5dd7070Spatrick if (!Data.FirstprivateVars.empty()) {
5063e5dd7070Spatrick enum { PrivatesParam = 2, CopyFnParam = 3 };
5064e5dd7070Spatrick llvm::Value *CopyFn = CGF.Builder.CreateLoad(
5065e5dd7070Spatrick CGF.GetAddrOfLocalVar(CS->getCapturedDecl()->getParam(CopyFnParam)));
5066e5dd7070Spatrick llvm::Value *PrivatesPtr = CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(
5067e5dd7070Spatrick CS->getCapturedDecl()->getParam(PrivatesParam)));
5068e5dd7070Spatrick // Map privates.
5069e5dd7070Spatrick llvm::SmallVector<std::pair<const VarDecl *, Address>, 16> PrivatePtrs;
5070e5dd7070Spatrick llvm::SmallVector<llvm::Value *, 16> CallArgs;
5071a9ac8606Spatrick llvm::SmallVector<llvm::Type *, 4> ParamTypes;
5072e5dd7070Spatrick CallArgs.push_back(PrivatesPtr);
5073a9ac8606Spatrick ParamTypes.push_back(PrivatesPtr->getType());
5074e5dd7070Spatrick for (const Expr *E : Data.FirstprivateVars) {
5075e5dd7070Spatrick const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
5076e5dd7070Spatrick Address PrivatePtr =
5077e5dd7070Spatrick CGF.CreateMemTemp(CGF.getContext().getPointerType(E->getType()),
5078e5dd7070Spatrick ".firstpriv.ptr.addr");
5079e5dd7070Spatrick PrivatePtrs.emplace_back(VD, PrivatePtr);
5080e5dd7070Spatrick CallArgs.push_back(PrivatePtr.getPointer());
5081a9ac8606Spatrick ParamTypes.push_back(PrivatePtr.getType());
5082e5dd7070Spatrick }
5083a9ac8606Spatrick auto *CopyFnTy = llvm::FunctionType::get(CGF.Builder.getVoidTy(),
5084a9ac8606Spatrick ParamTypes, /*isVarArg=*/false);
5085a9ac8606Spatrick CopyFn = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
5086a9ac8606Spatrick CopyFn, CopyFnTy->getPointerTo());
5087e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitOutlinedFunctionCall(
5088e5dd7070Spatrick CGF, S.getBeginLoc(), {CopyFnTy, CopyFn}, CallArgs);
5089e5dd7070Spatrick for (const auto &Pair : PrivatePtrs) {
5090*12c85518Srobert Address Replacement(
5091*12c85518Srobert CGF.Builder.CreateLoad(Pair.second),
5092*12c85518Srobert CGF.ConvertTypeForMem(Pair.first->getType().getNonReferenceType()),
5093e5dd7070Spatrick CGF.getContext().getDeclAlign(Pair.first));
5094*12c85518Srobert Scope.addPrivate(Pair.first, Replacement);
5095e5dd7070Spatrick }
5096e5dd7070Spatrick }
5097*12c85518Srobert CGF.processInReduction(S, Data, CGF, CS, Scope);
5098e5dd7070Spatrick if (InputInfo.NumberOfTargetItems > 0) {
5099e5dd7070Spatrick InputInfo.BasePointersArray = CGF.Builder.CreateConstArrayGEP(
5100e5dd7070Spatrick CGF.GetAddrOfLocalVar(BPVD), /*Index=*/0);
5101e5dd7070Spatrick InputInfo.PointersArray = CGF.Builder.CreateConstArrayGEP(
5102e5dd7070Spatrick CGF.GetAddrOfLocalVar(PVD), /*Index=*/0);
5103e5dd7070Spatrick InputInfo.SizesArray = CGF.Builder.CreateConstArrayGEP(
5104e5dd7070Spatrick CGF.GetAddrOfLocalVar(SVD), /*Index=*/0);
5105a9ac8606Spatrick // If MVD is nullptr, the mapper array is not privatized
5106a9ac8606Spatrick if (MVD)
5107a9ac8606Spatrick InputInfo.MappersArray = CGF.Builder.CreateConstArrayGEP(
5108a9ac8606Spatrick CGF.GetAddrOfLocalVar(MVD), /*Index=*/0);
5109e5dd7070Spatrick }
5110e5dd7070Spatrick
5111e5dd7070Spatrick Action.Enter(CGF);
5112e5dd7070Spatrick OMPLexicalScope LexScope(CGF, S, OMPD_task, /*EmitPreInitStmt=*/false);
5113e5dd7070Spatrick BodyGen(CGF);
5114e5dd7070Spatrick };
5115e5dd7070Spatrick llvm::Function *OutlinedFn = CGM.getOpenMPRuntime().emitTaskOutlinedFunction(
5116e5dd7070Spatrick S, *I, *PartId, *TaskT, S.getDirectiveKind(), CodeGen, /*Tied=*/true,
5117e5dd7070Spatrick Data.NumberOfParts);
5118e5dd7070Spatrick llvm::APInt TrueOrFalse(32, S.hasClausesOfKind<OMPNowaitClause>() ? 1 : 0);
5119e5dd7070Spatrick IntegerLiteral IfCond(getContext(), TrueOrFalse,
5120e5dd7070Spatrick getContext().getIntTypeForBitwidth(32, /*Signed=*/0),
5121e5dd7070Spatrick SourceLocation());
5122e5dd7070Spatrick CGM.getOpenMPRuntime().emitTaskCall(*this, S.getBeginLoc(), S, OutlinedFn,
5123e5dd7070Spatrick SharedsTy, CapturedStruct, &IfCond, Data);
5124e5dd7070Spatrick }
5125e5dd7070Spatrick
processInReduction(const OMPExecutableDirective & S,OMPTaskDataTy & Data,CodeGenFunction & CGF,const CapturedStmt * CS,OMPPrivateScope & Scope)5126*12c85518Srobert void CodeGenFunction::processInReduction(const OMPExecutableDirective &S,
5127*12c85518Srobert OMPTaskDataTy &Data,
5128*12c85518Srobert CodeGenFunction &CGF,
5129*12c85518Srobert const CapturedStmt *CS,
5130*12c85518Srobert OMPPrivateScope &Scope) {
5131*12c85518Srobert if (Data.Reductions) {
5132*12c85518Srobert OpenMPDirectiveKind CapturedRegion = S.getDirectiveKind();
5133*12c85518Srobert OMPLexicalScope LexScope(CGF, S, CapturedRegion);
5134*12c85518Srobert ReductionCodeGen RedCG(Data.ReductionVars, Data.ReductionVars,
5135*12c85518Srobert Data.ReductionCopies, Data.ReductionOps);
5136*12c85518Srobert llvm::Value *ReductionsPtr = CGF.Builder.CreateLoad(
5137*12c85518Srobert CGF.GetAddrOfLocalVar(CS->getCapturedDecl()->getParam(4)));
5138*12c85518Srobert for (unsigned Cnt = 0, E = Data.ReductionVars.size(); Cnt < E; ++Cnt) {
5139*12c85518Srobert RedCG.emitSharedOrigLValue(CGF, Cnt);
5140*12c85518Srobert RedCG.emitAggregateType(CGF, Cnt);
5141*12c85518Srobert // FIXME: This must removed once the runtime library is fixed.
5142*12c85518Srobert // Emit required threadprivate variables for
5143*12c85518Srobert // initializer/combiner/finalizer.
5144*12c85518Srobert CGF.CGM.getOpenMPRuntime().emitTaskReductionFixups(CGF, S.getBeginLoc(),
5145*12c85518Srobert RedCG, Cnt);
5146*12c85518Srobert Address Replacement = CGF.CGM.getOpenMPRuntime().getTaskReductionItem(
5147*12c85518Srobert CGF, S.getBeginLoc(), ReductionsPtr, RedCG.getSharedLValue(Cnt));
5148*12c85518Srobert Replacement =
5149*12c85518Srobert Address(CGF.EmitScalarConversion(
5150*12c85518Srobert Replacement.getPointer(), CGF.getContext().VoidPtrTy,
5151*12c85518Srobert CGF.getContext().getPointerType(
5152*12c85518Srobert Data.ReductionCopies[Cnt]->getType()),
5153*12c85518Srobert Data.ReductionCopies[Cnt]->getExprLoc()),
5154*12c85518Srobert CGF.ConvertTypeForMem(Data.ReductionCopies[Cnt]->getType()),
5155*12c85518Srobert Replacement.getAlignment());
5156*12c85518Srobert Replacement = RedCG.adjustPrivateAddress(CGF, Cnt, Replacement);
5157*12c85518Srobert Scope.addPrivate(RedCG.getBaseDecl(Cnt), Replacement);
5158*12c85518Srobert }
5159*12c85518Srobert }
5160*12c85518Srobert (void)Scope.Privatize();
5161*12c85518Srobert SmallVector<const Expr *, 4> InRedVars;
5162*12c85518Srobert SmallVector<const Expr *, 4> InRedPrivs;
5163*12c85518Srobert SmallVector<const Expr *, 4> InRedOps;
5164*12c85518Srobert SmallVector<const Expr *, 4> TaskgroupDescriptors;
5165*12c85518Srobert for (const auto *C : S.getClausesOfKind<OMPInReductionClause>()) {
5166*12c85518Srobert auto IPriv = C->privates().begin();
5167*12c85518Srobert auto IRed = C->reduction_ops().begin();
5168*12c85518Srobert auto ITD = C->taskgroup_descriptors().begin();
5169*12c85518Srobert for (const Expr *Ref : C->varlists()) {
5170*12c85518Srobert InRedVars.emplace_back(Ref);
5171*12c85518Srobert InRedPrivs.emplace_back(*IPriv);
5172*12c85518Srobert InRedOps.emplace_back(*IRed);
5173*12c85518Srobert TaskgroupDescriptors.emplace_back(*ITD);
5174*12c85518Srobert std::advance(IPriv, 1);
5175*12c85518Srobert std::advance(IRed, 1);
5176*12c85518Srobert std::advance(ITD, 1);
5177*12c85518Srobert }
5178*12c85518Srobert }
5179*12c85518Srobert OMPPrivateScope InRedScope(CGF);
5180*12c85518Srobert if (!InRedVars.empty()) {
5181*12c85518Srobert ReductionCodeGen RedCG(InRedVars, InRedVars, InRedPrivs, InRedOps);
5182*12c85518Srobert for (unsigned Cnt = 0, E = InRedVars.size(); Cnt < E; ++Cnt) {
5183*12c85518Srobert RedCG.emitSharedOrigLValue(CGF, Cnt);
5184*12c85518Srobert RedCG.emitAggregateType(CGF, Cnt);
5185*12c85518Srobert // FIXME: This must removed once the runtime library is fixed.
5186*12c85518Srobert // Emit required threadprivate variables for
5187*12c85518Srobert // initializer/combiner/finalizer.
5188*12c85518Srobert CGF.CGM.getOpenMPRuntime().emitTaskReductionFixups(CGF, S.getBeginLoc(),
5189*12c85518Srobert RedCG, Cnt);
5190*12c85518Srobert llvm::Value *ReductionsPtr;
5191*12c85518Srobert if (const Expr *TRExpr = TaskgroupDescriptors[Cnt]) {
5192*12c85518Srobert ReductionsPtr =
5193*12c85518Srobert CGF.EmitLoadOfScalar(CGF.EmitLValue(TRExpr), TRExpr->getExprLoc());
5194*12c85518Srobert } else {
5195*12c85518Srobert ReductionsPtr = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
5196*12c85518Srobert }
5197*12c85518Srobert Address Replacement = CGF.CGM.getOpenMPRuntime().getTaskReductionItem(
5198*12c85518Srobert CGF, S.getBeginLoc(), ReductionsPtr, RedCG.getSharedLValue(Cnt));
5199*12c85518Srobert Replacement = Address(
5200*12c85518Srobert CGF.EmitScalarConversion(
5201*12c85518Srobert Replacement.getPointer(), CGF.getContext().VoidPtrTy,
5202*12c85518Srobert CGF.getContext().getPointerType(InRedPrivs[Cnt]->getType()),
5203*12c85518Srobert InRedPrivs[Cnt]->getExprLoc()),
5204*12c85518Srobert CGF.ConvertTypeForMem(InRedPrivs[Cnt]->getType()),
5205*12c85518Srobert Replacement.getAlignment());
5206*12c85518Srobert Replacement = RedCG.adjustPrivateAddress(CGF, Cnt, Replacement);
5207*12c85518Srobert InRedScope.addPrivate(RedCG.getBaseDecl(Cnt), Replacement);
5208*12c85518Srobert }
5209*12c85518Srobert }
5210*12c85518Srobert (void)InRedScope.Privatize();
5211*12c85518Srobert }
5212*12c85518Srobert
EmitOMPTaskDirective(const OMPTaskDirective & S)5213e5dd7070Spatrick void CodeGenFunction::EmitOMPTaskDirective(const OMPTaskDirective &S) {
5214e5dd7070Spatrick // Emit outlined function for task construct.
5215e5dd7070Spatrick const CapturedStmt *CS = S.getCapturedStmt(OMPD_task);
5216e5dd7070Spatrick Address CapturedStruct = GenerateCapturedStmtArgument(*CS);
5217e5dd7070Spatrick QualType SharedsTy = getContext().getRecordType(CS->getCapturedRecordDecl());
5218e5dd7070Spatrick const Expr *IfCond = nullptr;
5219e5dd7070Spatrick for (const auto *C : S.getClausesOfKind<OMPIfClause>()) {
5220e5dd7070Spatrick if (C->getNameModifier() == OMPD_unknown ||
5221e5dd7070Spatrick C->getNameModifier() == OMPD_task) {
5222e5dd7070Spatrick IfCond = C->getCondition();
5223e5dd7070Spatrick break;
5224e5dd7070Spatrick }
5225e5dd7070Spatrick }
5226e5dd7070Spatrick
5227e5dd7070Spatrick OMPTaskDataTy Data;
5228e5dd7070Spatrick // Check if we should emit tied or untied task.
5229e5dd7070Spatrick Data.Tied = !S.getSingleClause<OMPUntiedClause>();
5230e5dd7070Spatrick auto &&BodyGen = [CS](CodeGenFunction &CGF, PrePostActionTy &) {
5231e5dd7070Spatrick CGF.EmitStmt(CS->getCapturedStmt());
5232e5dd7070Spatrick };
5233e5dd7070Spatrick auto &&TaskGen = [&S, SharedsTy, CapturedStruct,
5234e5dd7070Spatrick IfCond](CodeGenFunction &CGF, llvm::Function *OutlinedFn,
5235e5dd7070Spatrick const OMPTaskDataTy &Data) {
5236e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitTaskCall(CGF, S.getBeginLoc(), S, OutlinedFn,
5237e5dd7070Spatrick SharedsTy, CapturedStruct, IfCond,
5238e5dd7070Spatrick Data);
5239e5dd7070Spatrick };
5240ec727ea7Spatrick auto LPCRegion =
5241ec727ea7Spatrick CGOpenMPRuntime::LastprivateConditionalRAII::disable(*this, S);
5242e5dd7070Spatrick EmitOMPTaskBasedDirective(S, OMPD_task, BodyGen, TaskGen, Data);
5243e5dd7070Spatrick }
5244e5dd7070Spatrick
EmitOMPTaskyieldDirective(const OMPTaskyieldDirective & S)5245e5dd7070Spatrick void CodeGenFunction::EmitOMPTaskyieldDirective(
5246e5dd7070Spatrick const OMPTaskyieldDirective &S) {
5247e5dd7070Spatrick CGM.getOpenMPRuntime().emitTaskyieldCall(*this, S.getBeginLoc());
5248e5dd7070Spatrick }
5249e5dd7070Spatrick
EmitOMPErrorDirective(const OMPErrorDirective & S)5250*12c85518Srobert void CodeGenFunction::EmitOMPErrorDirective(const OMPErrorDirective &S) {
5251*12c85518Srobert const OMPMessageClause *MC = S.getSingleClause<OMPMessageClause>();
5252*12c85518Srobert Expr *ME = MC ? MC->getMessageString() : nullptr;
5253*12c85518Srobert const OMPSeverityClause *SC = S.getSingleClause<OMPSeverityClause>();
5254*12c85518Srobert bool IsFatal = false;
5255*12c85518Srobert if (!SC || SC->getSeverityKind() == OMPC_SEVERITY_fatal)
5256*12c85518Srobert IsFatal = true;
5257*12c85518Srobert CGM.getOpenMPRuntime().emitErrorCall(*this, S.getBeginLoc(), ME, IsFatal);
5258*12c85518Srobert }
5259*12c85518Srobert
EmitOMPBarrierDirective(const OMPBarrierDirective & S)5260e5dd7070Spatrick void CodeGenFunction::EmitOMPBarrierDirective(const OMPBarrierDirective &S) {
5261e5dd7070Spatrick CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getBeginLoc(), OMPD_barrier);
5262e5dd7070Spatrick }
5263e5dd7070Spatrick
EmitOMPTaskwaitDirective(const OMPTaskwaitDirective & S)5264e5dd7070Spatrick void CodeGenFunction::EmitOMPTaskwaitDirective(const OMPTaskwaitDirective &S) {
5265*12c85518Srobert OMPTaskDataTy Data;
5266*12c85518Srobert // Build list of dependences
5267*12c85518Srobert buildDependences(S, Data);
5268*12c85518Srobert Data.HasNowaitClause = S.hasClausesOfKind<OMPNowaitClause>();
5269*12c85518Srobert CGM.getOpenMPRuntime().emitTaskwaitCall(*this, S.getBeginLoc(), Data);
5270*12c85518Srobert }
5271*12c85518Srobert
isSupportedByOpenMPIRBuilder(const OMPTaskgroupDirective & T)5272*12c85518Srobert bool isSupportedByOpenMPIRBuilder(const OMPTaskgroupDirective &T) {
5273*12c85518Srobert return T.clauses().empty();
5274e5dd7070Spatrick }
5275e5dd7070Spatrick
EmitOMPTaskgroupDirective(const OMPTaskgroupDirective & S)5276e5dd7070Spatrick void CodeGenFunction::EmitOMPTaskgroupDirective(
5277e5dd7070Spatrick const OMPTaskgroupDirective &S) {
5278*12c85518Srobert OMPLexicalScope Scope(*this, S, OMPD_unknown);
5279*12c85518Srobert if (CGM.getLangOpts().OpenMPIRBuilder && isSupportedByOpenMPIRBuilder(S)) {
5280*12c85518Srobert llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
5281*12c85518Srobert using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
5282*12c85518Srobert InsertPointTy AllocaIP(AllocaInsertPt->getParent(),
5283*12c85518Srobert AllocaInsertPt->getIterator());
5284*12c85518Srobert
5285*12c85518Srobert auto BodyGenCB = [&, this](InsertPointTy AllocaIP,
5286*12c85518Srobert InsertPointTy CodeGenIP) {
5287*12c85518Srobert Builder.restoreIP(CodeGenIP);
5288*12c85518Srobert EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt());
5289*12c85518Srobert };
5290*12c85518Srobert CodeGenFunction::CGCapturedStmtInfo CapStmtInfo;
5291*12c85518Srobert if (!CapturedStmtInfo)
5292*12c85518Srobert CapturedStmtInfo = &CapStmtInfo;
5293*12c85518Srobert Builder.restoreIP(OMPBuilder.createTaskgroup(Builder, AllocaIP, BodyGenCB));
5294*12c85518Srobert return;
5295*12c85518Srobert }
5296e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
5297e5dd7070Spatrick Action.Enter(CGF);
5298e5dd7070Spatrick if (const Expr *E = S.getReductionRef()) {
5299e5dd7070Spatrick SmallVector<const Expr *, 4> LHSs;
5300e5dd7070Spatrick SmallVector<const Expr *, 4> RHSs;
5301e5dd7070Spatrick OMPTaskDataTy Data;
5302e5dd7070Spatrick for (const auto *C : S.getClausesOfKind<OMPTaskReductionClause>()) {
5303ec727ea7Spatrick Data.ReductionVars.append(C->varlist_begin(), C->varlist_end());
5304ec727ea7Spatrick Data.ReductionOrigs.append(C->varlist_begin(), C->varlist_end());
5305ec727ea7Spatrick Data.ReductionCopies.append(C->privates().begin(), C->privates().end());
5306ec727ea7Spatrick Data.ReductionOps.append(C->reduction_ops().begin(),
5307ec727ea7Spatrick C->reduction_ops().end());
5308ec727ea7Spatrick LHSs.append(C->lhs_exprs().begin(), C->lhs_exprs().end());
5309ec727ea7Spatrick RHSs.append(C->rhs_exprs().begin(), C->rhs_exprs().end());
5310e5dd7070Spatrick }
5311e5dd7070Spatrick llvm::Value *ReductionDesc =
5312e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitTaskReductionInit(CGF, S.getBeginLoc(),
5313e5dd7070Spatrick LHSs, RHSs, Data);
5314e5dd7070Spatrick const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
5315e5dd7070Spatrick CGF.EmitVarDecl(*VD);
5316e5dd7070Spatrick CGF.EmitStoreOfScalar(ReductionDesc, CGF.GetAddrOfLocalVar(VD),
5317e5dd7070Spatrick /*Volatile=*/false, E->getType());
5318e5dd7070Spatrick }
5319e5dd7070Spatrick CGF.EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt());
5320e5dd7070Spatrick };
5321e5dd7070Spatrick CGM.getOpenMPRuntime().emitTaskgroupRegion(*this, CodeGen, S.getBeginLoc());
5322e5dd7070Spatrick }
5323e5dd7070Spatrick
EmitOMPFlushDirective(const OMPFlushDirective & S)5324e5dd7070Spatrick void CodeGenFunction::EmitOMPFlushDirective(const OMPFlushDirective &S) {
5325ec727ea7Spatrick llvm::AtomicOrdering AO = S.getSingleClause<OMPFlushClause>()
5326ec727ea7Spatrick ? llvm::AtomicOrdering::NotAtomic
5327ec727ea7Spatrick : llvm::AtomicOrdering::AcquireRelease;
5328e5dd7070Spatrick CGM.getOpenMPRuntime().emitFlush(
5329e5dd7070Spatrick *this,
5330e5dd7070Spatrick [&S]() -> ArrayRef<const Expr *> {
5331e5dd7070Spatrick if (const auto *FlushClause = S.getSingleClause<OMPFlushClause>())
5332*12c85518Srobert return llvm::ArrayRef(FlushClause->varlist_begin(),
5333e5dd7070Spatrick FlushClause->varlist_end());
5334*12c85518Srobert return std::nullopt;
5335e5dd7070Spatrick }(),
5336ec727ea7Spatrick S.getBeginLoc(), AO);
5337ec727ea7Spatrick }
5338ec727ea7Spatrick
EmitOMPDepobjDirective(const OMPDepobjDirective & S)5339ec727ea7Spatrick void CodeGenFunction::EmitOMPDepobjDirective(const OMPDepobjDirective &S) {
5340ec727ea7Spatrick const auto *DO = S.getSingleClause<OMPDepobjClause>();
5341ec727ea7Spatrick LValue DOLVal = EmitLValue(DO->getDepobj());
5342ec727ea7Spatrick if (const auto *DC = S.getSingleClause<OMPDependClause>()) {
5343ec727ea7Spatrick OMPTaskDataTy::DependData Dependencies(DC->getDependencyKind(),
5344ec727ea7Spatrick DC->getModifier());
5345ec727ea7Spatrick Dependencies.DepExprs.append(DC->varlist_begin(), DC->varlist_end());
5346ec727ea7Spatrick Address DepAddr = CGM.getOpenMPRuntime().emitDepobjDependClause(
5347ec727ea7Spatrick *this, Dependencies, DC->getBeginLoc());
5348ec727ea7Spatrick EmitStoreOfScalar(DepAddr.getPointer(), DOLVal);
5349ec727ea7Spatrick return;
5350ec727ea7Spatrick }
5351ec727ea7Spatrick if (const auto *DC = S.getSingleClause<OMPDestroyClause>()) {
5352ec727ea7Spatrick CGM.getOpenMPRuntime().emitDestroyClause(*this, DOLVal, DC->getBeginLoc());
5353ec727ea7Spatrick return;
5354ec727ea7Spatrick }
5355ec727ea7Spatrick if (const auto *UC = S.getSingleClause<OMPUpdateClause>()) {
5356ec727ea7Spatrick CGM.getOpenMPRuntime().emitUpdateClause(
5357ec727ea7Spatrick *this, DOLVal, UC->getDependencyKind(), UC->getBeginLoc());
5358ec727ea7Spatrick return;
5359ec727ea7Spatrick }
5360ec727ea7Spatrick }
5361ec727ea7Spatrick
EmitOMPScanDirective(const OMPScanDirective & S)5362ec727ea7Spatrick void CodeGenFunction::EmitOMPScanDirective(const OMPScanDirective &S) {
5363ec727ea7Spatrick if (!OMPParentLoopDirectiveForScan)
5364ec727ea7Spatrick return;
5365ec727ea7Spatrick const OMPExecutableDirective &ParentDir = *OMPParentLoopDirectiveForScan;
5366ec727ea7Spatrick bool IsInclusive = S.hasClausesOfKind<OMPInclusiveClause>();
5367ec727ea7Spatrick SmallVector<const Expr *, 4> Shareds;
5368ec727ea7Spatrick SmallVector<const Expr *, 4> Privates;
5369ec727ea7Spatrick SmallVector<const Expr *, 4> LHSs;
5370ec727ea7Spatrick SmallVector<const Expr *, 4> RHSs;
5371ec727ea7Spatrick SmallVector<const Expr *, 4> ReductionOps;
5372ec727ea7Spatrick SmallVector<const Expr *, 4> CopyOps;
5373ec727ea7Spatrick SmallVector<const Expr *, 4> CopyArrayTemps;
5374ec727ea7Spatrick SmallVector<const Expr *, 4> CopyArrayElems;
5375ec727ea7Spatrick for (const auto *C : ParentDir.getClausesOfKind<OMPReductionClause>()) {
5376ec727ea7Spatrick if (C->getModifier() != OMPC_REDUCTION_inscan)
5377ec727ea7Spatrick continue;
5378ec727ea7Spatrick Shareds.append(C->varlist_begin(), C->varlist_end());
5379ec727ea7Spatrick Privates.append(C->privates().begin(), C->privates().end());
5380ec727ea7Spatrick LHSs.append(C->lhs_exprs().begin(), C->lhs_exprs().end());
5381ec727ea7Spatrick RHSs.append(C->rhs_exprs().begin(), C->rhs_exprs().end());
5382ec727ea7Spatrick ReductionOps.append(C->reduction_ops().begin(), C->reduction_ops().end());
5383ec727ea7Spatrick CopyOps.append(C->copy_ops().begin(), C->copy_ops().end());
5384ec727ea7Spatrick CopyArrayTemps.append(C->copy_array_temps().begin(),
5385ec727ea7Spatrick C->copy_array_temps().end());
5386ec727ea7Spatrick CopyArrayElems.append(C->copy_array_elems().begin(),
5387ec727ea7Spatrick C->copy_array_elems().end());
5388ec727ea7Spatrick }
5389ec727ea7Spatrick if (ParentDir.getDirectiveKind() == OMPD_simd ||
5390ec727ea7Spatrick (getLangOpts().OpenMPSimd &&
5391ec727ea7Spatrick isOpenMPSimdDirective(ParentDir.getDirectiveKind()))) {
5392ec727ea7Spatrick // For simd directive and simd-based directives in simd only mode, use the
5393ec727ea7Spatrick // following codegen:
5394ec727ea7Spatrick // int x = 0;
5395ec727ea7Spatrick // #pragma omp simd reduction(inscan, +: x)
5396ec727ea7Spatrick // for (..) {
5397ec727ea7Spatrick // <first part>
5398ec727ea7Spatrick // #pragma omp scan inclusive(x)
5399ec727ea7Spatrick // <second part>
5400ec727ea7Spatrick // }
5401ec727ea7Spatrick // is transformed to:
5402ec727ea7Spatrick // int x = 0;
5403ec727ea7Spatrick // for (..) {
5404ec727ea7Spatrick // int x_priv = 0;
5405ec727ea7Spatrick // <first part>
5406ec727ea7Spatrick // x = x_priv + x;
5407ec727ea7Spatrick // x_priv = x;
5408ec727ea7Spatrick // <second part>
5409ec727ea7Spatrick // }
5410ec727ea7Spatrick // and
5411ec727ea7Spatrick // int x = 0;
5412ec727ea7Spatrick // #pragma omp simd reduction(inscan, +: x)
5413ec727ea7Spatrick // for (..) {
5414ec727ea7Spatrick // <first part>
5415ec727ea7Spatrick // #pragma omp scan exclusive(x)
5416ec727ea7Spatrick // <second part>
5417ec727ea7Spatrick // }
5418ec727ea7Spatrick // to
5419ec727ea7Spatrick // int x = 0;
5420ec727ea7Spatrick // for (..) {
5421ec727ea7Spatrick // int x_priv = 0;
5422ec727ea7Spatrick // <second part>
5423ec727ea7Spatrick // int temp = x;
5424ec727ea7Spatrick // x = x_priv + x;
5425ec727ea7Spatrick // x_priv = temp;
5426ec727ea7Spatrick // <first part>
5427ec727ea7Spatrick // }
5428ec727ea7Spatrick llvm::BasicBlock *OMPScanReduce = createBasicBlock("omp.inscan.reduce");
5429ec727ea7Spatrick EmitBranch(IsInclusive
5430ec727ea7Spatrick ? OMPScanReduce
5431ec727ea7Spatrick : BreakContinueStack.back().ContinueBlock.getBlock());
5432ec727ea7Spatrick EmitBlock(OMPScanDispatch);
5433ec727ea7Spatrick {
5434ec727ea7Spatrick // New scope for correct construction/destruction of temp variables for
5435ec727ea7Spatrick // exclusive scan.
5436ec727ea7Spatrick LexicalScope Scope(*this, S.getSourceRange());
5437ec727ea7Spatrick EmitBranch(IsInclusive ? OMPBeforeScanBlock : OMPAfterScanBlock);
5438ec727ea7Spatrick EmitBlock(OMPScanReduce);
5439ec727ea7Spatrick if (!IsInclusive) {
5440ec727ea7Spatrick // Create temp var and copy LHS value to this temp value.
5441ec727ea7Spatrick // TMP = LHS;
5442ec727ea7Spatrick for (unsigned I = 0, E = CopyArrayElems.size(); I < E; ++I) {
5443ec727ea7Spatrick const Expr *PrivateExpr = Privates[I];
5444ec727ea7Spatrick const Expr *TempExpr = CopyArrayTemps[I];
5445ec727ea7Spatrick EmitAutoVarDecl(
5446ec727ea7Spatrick *cast<VarDecl>(cast<DeclRefExpr>(TempExpr)->getDecl()));
5447ec727ea7Spatrick LValue DestLVal = EmitLValue(TempExpr);
5448ec727ea7Spatrick LValue SrcLVal = EmitLValue(LHSs[I]);
5449ec727ea7Spatrick EmitOMPCopy(PrivateExpr->getType(), DestLVal.getAddress(*this),
5450ec727ea7Spatrick SrcLVal.getAddress(*this),
5451ec727ea7Spatrick cast<VarDecl>(cast<DeclRefExpr>(LHSs[I])->getDecl()),
5452ec727ea7Spatrick cast<VarDecl>(cast<DeclRefExpr>(RHSs[I])->getDecl()),
5453ec727ea7Spatrick CopyOps[I]);
5454ec727ea7Spatrick }
5455ec727ea7Spatrick }
5456ec727ea7Spatrick CGM.getOpenMPRuntime().emitReduction(
5457ec727ea7Spatrick *this, ParentDir.getEndLoc(), Privates, LHSs, RHSs, ReductionOps,
5458ec727ea7Spatrick {/*WithNowait=*/true, /*SimpleReduction=*/true, OMPD_simd});
5459ec727ea7Spatrick for (unsigned I = 0, E = CopyArrayElems.size(); I < E; ++I) {
5460ec727ea7Spatrick const Expr *PrivateExpr = Privates[I];
5461ec727ea7Spatrick LValue DestLVal;
5462ec727ea7Spatrick LValue SrcLVal;
5463ec727ea7Spatrick if (IsInclusive) {
5464ec727ea7Spatrick DestLVal = EmitLValue(RHSs[I]);
5465ec727ea7Spatrick SrcLVal = EmitLValue(LHSs[I]);
5466ec727ea7Spatrick } else {
5467ec727ea7Spatrick const Expr *TempExpr = CopyArrayTemps[I];
5468ec727ea7Spatrick DestLVal = EmitLValue(RHSs[I]);
5469ec727ea7Spatrick SrcLVal = EmitLValue(TempExpr);
5470ec727ea7Spatrick }
5471ec727ea7Spatrick EmitOMPCopy(PrivateExpr->getType(), DestLVal.getAddress(*this),
5472ec727ea7Spatrick SrcLVal.getAddress(*this),
5473ec727ea7Spatrick cast<VarDecl>(cast<DeclRefExpr>(LHSs[I])->getDecl()),
5474ec727ea7Spatrick cast<VarDecl>(cast<DeclRefExpr>(RHSs[I])->getDecl()),
5475ec727ea7Spatrick CopyOps[I]);
5476ec727ea7Spatrick }
5477ec727ea7Spatrick }
5478ec727ea7Spatrick EmitBranch(IsInclusive ? OMPAfterScanBlock : OMPBeforeScanBlock);
5479ec727ea7Spatrick OMPScanExitBlock = IsInclusive
5480ec727ea7Spatrick ? BreakContinueStack.back().ContinueBlock.getBlock()
5481ec727ea7Spatrick : OMPScanReduce;
5482ec727ea7Spatrick EmitBlock(OMPAfterScanBlock);
5483ec727ea7Spatrick return;
5484ec727ea7Spatrick }
5485ec727ea7Spatrick if (!IsInclusive) {
5486ec727ea7Spatrick EmitBranch(BreakContinueStack.back().ContinueBlock.getBlock());
5487ec727ea7Spatrick EmitBlock(OMPScanExitBlock);
5488ec727ea7Spatrick }
5489ec727ea7Spatrick if (OMPFirstScanLoop) {
5490ec727ea7Spatrick // Emit buffer[i] = red; at the end of the input phase.
5491ec727ea7Spatrick const auto *IVExpr = cast<OMPLoopDirective>(ParentDir)
5492ec727ea7Spatrick .getIterationVariable()
5493ec727ea7Spatrick ->IgnoreParenImpCasts();
5494ec727ea7Spatrick LValue IdxLVal = EmitLValue(IVExpr);
5495ec727ea7Spatrick llvm::Value *IdxVal = EmitLoadOfScalar(IdxLVal, IVExpr->getExprLoc());
5496ec727ea7Spatrick IdxVal = Builder.CreateIntCast(IdxVal, SizeTy, /*isSigned=*/false);
5497ec727ea7Spatrick for (unsigned I = 0, E = CopyArrayElems.size(); I < E; ++I) {
5498ec727ea7Spatrick const Expr *PrivateExpr = Privates[I];
5499ec727ea7Spatrick const Expr *OrigExpr = Shareds[I];
5500ec727ea7Spatrick const Expr *CopyArrayElem = CopyArrayElems[I];
5501ec727ea7Spatrick OpaqueValueMapping IdxMapping(
5502ec727ea7Spatrick *this,
5503ec727ea7Spatrick cast<OpaqueValueExpr>(
5504ec727ea7Spatrick cast<ArraySubscriptExpr>(CopyArrayElem)->getIdx()),
5505ec727ea7Spatrick RValue::get(IdxVal));
5506ec727ea7Spatrick LValue DestLVal = EmitLValue(CopyArrayElem);
5507ec727ea7Spatrick LValue SrcLVal = EmitLValue(OrigExpr);
5508ec727ea7Spatrick EmitOMPCopy(PrivateExpr->getType(), DestLVal.getAddress(*this),
5509ec727ea7Spatrick SrcLVal.getAddress(*this),
5510ec727ea7Spatrick cast<VarDecl>(cast<DeclRefExpr>(LHSs[I])->getDecl()),
5511ec727ea7Spatrick cast<VarDecl>(cast<DeclRefExpr>(RHSs[I])->getDecl()),
5512ec727ea7Spatrick CopyOps[I]);
5513ec727ea7Spatrick }
5514ec727ea7Spatrick }
5515ec727ea7Spatrick EmitBranch(BreakContinueStack.back().ContinueBlock.getBlock());
5516ec727ea7Spatrick if (IsInclusive) {
5517ec727ea7Spatrick EmitBlock(OMPScanExitBlock);
5518ec727ea7Spatrick EmitBranch(BreakContinueStack.back().ContinueBlock.getBlock());
5519ec727ea7Spatrick }
5520ec727ea7Spatrick EmitBlock(OMPScanDispatch);
5521ec727ea7Spatrick if (!OMPFirstScanLoop) {
5522ec727ea7Spatrick // Emit red = buffer[i]; at the entrance to the scan phase.
5523ec727ea7Spatrick const auto *IVExpr = cast<OMPLoopDirective>(ParentDir)
5524ec727ea7Spatrick .getIterationVariable()
5525ec727ea7Spatrick ->IgnoreParenImpCasts();
5526ec727ea7Spatrick LValue IdxLVal = EmitLValue(IVExpr);
5527ec727ea7Spatrick llvm::Value *IdxVal = EmitLoadOfScalar(IdxLVal, IVExpr->getExprLoc());
5528ec727ea7Spatrick IdxVal = Builder.CreateIntCast(IdxVal, SizeTy, /*isSigned=*/false);
5529ec727ea7Spatrick llvm::BasicBlock *ExclusiveExitBB = nullptr;
5530ec727ea7Spatrick if (!IsInclusive) {
5531ec727ea7Spatrick llvm::BasicBlock *ContBB = createBasicBlock("omp.exclusive.dec");
5532ec727ea7Spatrick ExclusiveExitBB = createBasicBlock("omp.exclusive.copy.exit");
5533ec727ea7Spatrick llvm::Value *Cmp = Builder.CreateIsNull(IdxVal);
5534ec727ea7Spatrick Builder.CreateCondBr(Cmp, ExclusiveExitBB, ContBB);
5535ec727ea7Spatrick EmitBlock(ContBB);
5536ec727ea7Spatrick // Use idx - 1 iteration for exclusive scan.
5537ec727ea7Spatrick IdxVal = Builder.CreateNUWSub(IdxVal, llvm::ConstantInt::get(SizeTy, 1));
5538ec727ea7Spatrick }
5539ec727ea7Spatrick for (unsigned I = 0, E = CopyArrayElems.size(); I < E; ++I) {
5540ec727ea7Spatrick const Expr *PrivateExpr = Privates[I];
5541ec727ea7Spatrick const Expr *OrigExpr = Shareds[I];
5542ec727ea7Spatrick const Expr *CopyArrayElem = CopyArrayElems[I];
5543ec727ea7Spatrick OpaqueValueMapping IdxMapping(
5544ec727ea7Spatrick *this,
5545ec727ea7Spatrick cast<OpaqueValueExpr>(
5546ec727ea7Spatrick cast<ArraySubscriptExpr>(CopyArrayElem)->getIdx()),
5547ec727ea7Spatrick RValue::get(IdxVal));
5548ec727ea7Spatrick LValue SrcLVal = EmitLValue(CopyArrayElem);
5549ec727ea7Spatrick LValue DestLVal = EmitLValue(OrigExpr);
5550ec727ea7Spatrick EmitOMPCopy(PrivateExpr->getType(), DestLVal.getAddress(*this),
5551ec727ea7Spatrick SrcLVal.getAddress(*this),
5552ec727ea7Spatrick cast<VarDecl>(cast<DeclRefExpr>(LHSs[I])->getDecl()),
5553ec727ea7Spatrick cast<VarDecl>(cast<DeclRefExpr>(RHSs[I])->getDecl()),
5554ec727ea7Spatrick CopyOps[I]);
5555ec727ea7Spatrick }
5556ec727ea7Spatrick if (!IsInclusive) {
5557ec727ea7Spatrick EmitBlock(ExclusiveExitBB);
5558ec727ea7Spatrick }
5559ec727ea7Spatrick }
5560ec727ea7Spatrick EmitBranch((OMPFirstScanLoop == IsInclusive) ? OMPBeforeScanBlock
5561ec727ea7Spatrick : OMPAfterScanBlock);
5562ec727ea7Spatrick EmitBlock(OMPAfterScanBlock);
5563e5dd7070Spatrick }
5564e5dd7070Spatrick
EmitOMPDistributeLoop(const OMPLoopDirective & S,const CodeGenLoopTy & CodeGenLoop,Expr * IncExpr)5565e5dd7070Spatrick void CodeGenFunction::EmitOMPDistributeLoop(const OMPLoopDirective &S,
5566e5dd7070Spatrick const CodeGenLoopTy &CodeGenLoop,
5567e5dd7070Spatrick Expr *IncExpr) {
5568e5dd7070Spatrick // Emit the loop iteration variable.
5569e5dd7070Spatrick const auto *IVExpr = cast<DeclRefExpr>(S.getIterationVariable());
5570e5dd7070Spatrick const auto *IVDecl = cast<VarDecl>(IVExpr->getDecl());
5571e5dd7070Spatrick EmitVarDecl(*IVDecl);
5572e5dd7070Spatrick
5573e5dd7070Spatrick // Emit the iterations count variable.
5574e5dd7070Spatrick // If it is not a variable, Sema decided to calculate iterations count on each
5575e5dd7070Spatrick // iteration (e.g., it is foldable into a constant).
5576e5dd7070Spatrick if (const auto *LIExpr = dyn_cast<DeclRefExpr>(S.getLastIteration())) {
5577e5dd7070Spatrick EmitVarDecl(*cast<VarDecl>(LIExpr->getDecl()));
5578e5dd7070Spatrick // Emit calculation of the iterations count.
5579e5dd7070Spatrick EmitIgnoredExpr(S.getCalcLastIteration());
5580e5dd7070Spatrick }
5581e5dd7070Spatrick
5582e5dd7070Spatrick CGOpenMPRuntime &RT = CGM.getOpenMPRuntime();
5583e5dd7070Spatrick
5584e5dd7070Spatrick bool HasLastprivateClause = false;
5585e5dd7070Spatrick // Check pre-condition.
5586e5dd7070Spatrick {
5587e5dd7070Spatrick OMPLoopScope PreInitScope(*this, S);
5588e5dd7070Spatrick // Skip the entire loop if we don't meet the precondition.
5589e5dd7070Spatrick // If the condition constant folds and can be elided, avoid emitting the
5590e5dd7070Spatrick // whole loop.
5591e5dd7070Spatrick bool CondConstant;
5592e5dd7070Spatrick llvm::BasicBlock *ContBlock = nullptr;
5593e5dd7070Spatrick if (ConstantFoldsToSimpleInteger(S.getPreCond(), CondConstant)) {
5594e5dd7070Spatrick if (!CondConstant)
5595e5dd7070Spatrick return;
5596e5dd7070Spatrick } else {
5597e5dd7070Spatrick llvm::BasicBlock *ThenBlock = createBasicBlock("omp.precond.then");
5598e5dd7070Spatrick ContBlock = createBasicBlock("omp.precond.end");
5599e5dd7070Spatrick emitPreCond(*this, S, S.getPreCond(), ThenBlock, ContBlock,
5600e5dd7070Spatrick getProfileCount(&S));
5601e5dd7070Spatrick EmitBlock(ThenBlock);
5602e5dd7070Spatrick incrementProfileCounter(&S);
5603e5dd7070Spatrick }
5604e5dd7070Spatrick
5605e5dd7070Spatrick emitAlignedClause(*this, S);
5606e5dd7070Spatrick // Emit 'then' code.
5607e5dd7070Spatrick {
5608e5dd7070Spatrick // Emit helper vars inits.
5609e5dd7070Spatrick
5610e5dd7070Spatrick LValue LB = EmitOMPHelperVar(
5611e5dd7070Spatrick *this, cast<DeclRefExpr>(
5612e5dd7070Spatrick (isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
5613e5dd7070Spatrick ? S.getCombinedLowerBoundVariable()
5614e5dd7070Spatrick : S.getLowerBoundVariable())));
5615e5dd7070Spatrick LValue UB = EmitOMPHelperVar(
5616e5dd7070Spatrick *this, cast<DeclRefExpr>(
5617e5dd7070Spatrick (isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
5618e5dd7070Spatrick ? S.getCombinedUpperBoundVariable()
5619e5dd7070Spatrick : S.getUpperBoundVariable())));
5620e5dd7070Spatrick LValue ST =
5621e5dd7070Spatrick EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getStrideVariable()));
5622e5dd7070Spatrick LValue IL =
5623e5dd7070Spatrick EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getIsLastIterVariable()));
5624e5dd7070Spatrick
5625e5dd7070Spatrick OMPPrivateScope LoopScope(*this);
5626e5dd7070Spatrick if (EmitOMPFirstprivateClause(S, LoopScope)) {
5627e5dd7070Spatrick // Emit implicit barrier to synchronize threads and avoid data races
5628e5dd7070Spatrick // on initialization of firstprivate variables and post-update of
5629e5dd7070Spatrick // lastprivate variables.
5630e5dd7070Spatrick CGM.getOpenMPRuntime().emitBarrierCall(
5631e5dd7070Spatrick *this, S.getBeginLoc(), OMPD_unknown, /*EmitChecks=*/false,
5632e5dd7070Spatrick /*ForceSimpleCall=*/true);
5633e5dd7070Spatrick }
5634e5dd7070Spatrick EmitOMPPrivateClause(S, LoopScope);
5635e5dd7070Spatrick if (isOpenMPSimdDirective(S.getDirectiveKind()) &&
5636e5dd7070Spatrick !isOpenMPParallelDirective(S.getDirectiveKind()) &&
5637e5dd7070Spatrick !isOpenMPTeamsDirective(S.getDirectiveKind()))
5638e5dd7070Spatrick EmitOMPReductionClauseInit(S, LoopScope);
5639e5dd7070Spatrick HasLastprivateClause = EmitOMPLastprivateClauseInit(S, LoopScope);
5640e5dd7070Spatrick EmitOMPPrivateLoopCounters(S, LoopScope);
5641e5dd7070Spatrick (void)LoopScope.Privatize();
5642e5dd7070Spatrick if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()))
5643e5dd7070Spatrick CGM.getOpenMPRuntime().adjustTargetSpecificDataForLambdas(*this, S);
5644e5dd7070Spatrick
5645e5dd7070Spatrick // Detect the distribute schedule kind and chunk.
5646e5dd7070Spatrick llvm::Value *Chunk = nullptr;
5647e5dd7070Spatrick OpenMPDistScheduleClauseKind ScheduleKind = OMPC_DIST_SCHEDULE_unknown;
5648e5dd7070Spatrick if (const auto *C = S.getSingleClause<OMPDistScheduleClause>()) {
5649e5dd7070Spatrick ScheduleKind = C->getDistScheduleKind();
5650e5dd7070Spatrick if (const Expr *Ch = C->getChunkSize()) {
5651e5dd7070Spatrick Chunk = EmitScalarExpr(Ch);
5652e5dd7070Spatrick Chunk = EmitScalarConversion(Chunk, Ch->getType(),
5653e5dd7070Spatrick S.getIterationVariable()->getType(),
5654e5dd7070Spatrick S.getBeginLoc());
5655e5dd7070Spatrick }
5656e5dd7070Spatrick } else {
5657e5dd7070Spatrick // Default behaviour for dist_schedule clause.
5658e5dd7070Spatrick CGM.getOpenMPRuntime().getDefaultDistScheduleAndChunk(
5659e5dd7070Spatrick *this, S, ScheduleKind, Chunk);
5660e5dd7070Spatrick }
5661e5dd7070Spatrick const unsigned IVSize = getContext().getTypeSize(IVExpr->getType());
5662e5dd7070Spatrick const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation();
5663e5dd7070Spatrick
5664e5dd7070Spatrick // OpenMP [2.10.8, distribute Construct, Description]
5665e5dd7070Spatrick // If dist_schedule is specified, kind must be static. If specified,
5666e5dd7070Spatrick // iterations are divided into chunks of size chunk_size, chunks are
5667e5dd7070Spatrick // assigned to the teams of the league in a round-robin fashion in the
5668e5dd7070Spatrick // order of the team number. When no chunk_size is specified, the
5669e5dd7070Spatrick // iteration space is divided into chunks that are approximately equal
5670e5dd7070Spatrick // in size, and at most one chunk is distributed to each team of the
5671e5dd7070Spatrick // league. The size of the chunks is unspecified in this case.
5672*12c85518Srobert bool StaticChunked =
5673*12c85518Srobert RT.isStaticChunked(ScheduleKind, /* Chunked */ Chunk != nullptr) &&
5674e5dd7070Spatrick isOpenMPLoopBoundSharingDirective(S.getDirectiveKind());
5675e5dd7070Spatrick if (RT.isStaticNonchunked(ScheduleKind,
5676e5dd7070Spatrick /* Chunked */ Chunk != nullptr) ||
5677e5dd7070Spatrick StaticChunked) {
5678e5dd7070Spatrick CGOpenMPRuntime::StaticRTInput StaticInit(
5679e5dd7070Spatrick IVSize, IVSigned, /* Ordered = */ false, IL.getAddress(*this),
5680e5dd7070Spatrick LB.getAddress(*this), UB.getAddress(*this), ST.getAddress(*this),
5681e5dd7070Spatrick StaticChunked ? Chunk : nullptr);
5682e5dd7070Spatrick RT.emitDistributeStaticInit(*this, S.getBeginLoc(), ScheduleKind,
5683e5dd7070Spatrick StaticInit);
5684e5dd7070Spatrick JumpDest LoopExit =
5685e5dd7070Spatrick getJumpDestInCurrentScope(createBasicBlock("omp.loop.exit"));
5686e5dd7070Spatrick // UB = min(UB, GlobalUB);
5687e5dd7070Spatrick EmitIgnoredExpr(isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
5688e5dd7070Spatrick ? S.getCombinedEnsureUpperBound()
5689e5dd7070Spatrick : S.getEnsureUpperBound());
5690e5dd7070Spatrick // IV = LB;
5691e5dd7070Spatrick EmitIgnoredExpr(isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
5692e5dd7070Spatrick ? S.getCombinedInit()
5693e5dd7070Spatrick : S.getInit());
5694e5dd7070Spatrick
5695e5dd7070Spatrick const Expr *Cond =
5696e5dd7070Spatrick isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
5697e5dd7070Spatrick ? S.getCombinedCond()
5698e5dd7070Spatrick : S.getCond();
5699e5dd7070Spatrick
5700e5dd7070Spatrick if (StaticChunked)
5701e5dd7070Spatrick Cond = S.getCombinedDistCond();
5702e5dd7070Spatrick
5703e5dd7070Spatrick // For static unchunked schedules generate:
5704e5dd7070Spatrick //
5705e5dd7070Spatrick // 1. For distribute alone, codegen
5706e5dd7070Spatrick // while (idx <= UB) {
5707e5dd7070Spatrick // BODY;
5708e5dd7070Spatrick // ++idx;
5709e5dd7070Spatrick // }
5710e5dd7070Spatrick //
5711e5dd7070Spatrick // 2. When combined with 'for' (e.g. as in 'distribute parallel for')
5712e5dd7070Spatrick // while (idx <= UB) {
5713e5dd7070Spatrick // <CodeGen rest of pragma>(LB, UB);
5714e5dd7070Spatrick // idx += ST;
5715e5dd7070Spatrick // }
5716e5dd7070Spatrick //
5717e5dd7070Spatrick // For static chunk one schedule generate:
5718e5dd7070Spatrick //
5719e5dd7070Spatrick // while (IV <= GlobalUB) {
5720e5dd7070Spatrick // <CodeGen rest of pragma>(LB, UB);
5721e5dd7070Spatrick // LB += ST;
5722e5dd7070Spatrick // UB += ST;
5723e5dd7070Spatrick // UB = min(UB, GlobalUB);
5724e5dd7070Spatrick // IV = LB;
5725e5dd7070Spatrick // }
5726e5dd7070Spatrick //
5727e5dd7070Spatrick emitCommonSimdLoop(
5728e5dd7070Spatrick *this, S,
5729e5dd7070Spatrick [&S](CodeGenFunction &CGF, PrePostActionTy &) {
5730e5dd7070Spatrick if (isOpenMPSimdDirective(S.getDirectiveKind()))
5731a9ac8606Spatrick CGF.EmitOMPSimdInit(S);
5732e5dd7070Spatrick },
5733e5dd7070Spatrick [&S, &LoopScope, Cond, IncExpr, LoopExit, &CodeGenLoop,
5734e5dd7070Spatrick StaticChunked](CodeGenFunction &CGF, PrePostActionTy &) {
5735e5dd7070Spatrick CGF.EmitOMPInnerLoop(
5736e5dd7070Spatrick S, LoopScope.requiresCleanups(), Cond, IncExpr,
5737e5dd7070Spatrick [&S, LoopExit, &CodeGenLoop](CodeGenFunction &CGF) {
5738e5dd7070Spatrick CodeGenLoop(CGF, S, LoopExit);
5739e5dd7070Spatrick },
5740e5dd7070Spatrick [&S, StaticChunked](CodeGenFunction &CGF) {
5741e5dd7070Spatrick if (StaticChunked) {
5742e5dd7070Spatrick CGF.EmitIgnoredExpr(S.getCombinedNextLowerBound());
5743e5dd7070Spatrick CGF.EmitIgnoredExpr(S.getCombinedNextUpperBound());
5744e5dd7070Spatrick CGF.EmitIgnoredExpr(S.getCombinedEnsureUpperBound());
5745e5dd7070Spatrick CGF.EmitIgnoredExpr(S.getCombinedInit());
5746e5dd7070Spatrick }
5747e5dd7070Spatrick });
5748e5dd7070Spatrick });
5749e5dd7070Spatrick EmitBlock(LoopExit.getBlock());
5750e5dd7070Spatrick // Tell the runtime we are done.
5751ec727ea7Spatrick RT.emitForStaticFinish(*this, S.getEndLoc(), S.getDirectiveKind());
5752e5dd7070Spatrick } else {
5753e5dd7070Spatrick // Emit the outer loop, which requests its work chunk [LB..UB] from
5754e5dd7070Spatrick // runtime and runs the inner loop to process it.
5755e5dd7070Spatrick const OMPLoopArguments LoopArguments = {
5756e5dd7070Spatrick LB.getAddress(*this), UB.getAddress(*this), ST.getAddress(*this),
5757e5dd7070Spatrick IL.getAddress(*this), Chunk};
5758e5dd7070Spatrick EmitOMPDistributeOuterLoop(ScheduleKind, S, LoopScope, LoopArguments,
5759e5dd7070Spatrick CodeGenLoop);
5760e5dd7070Spatrick }
5761e5dd7070Spatrick if (isOpenMPSimdDirective(S.getDirectiveKind())) {
5762e5dd7070Spatrick EmitOMPSimdFinal(S, [IL, &S](CodeGenFunction &CGF) {
5763e5dd7070Spatrick return CGF.Builder.CreateIsNotNull(
5764e5dd7070Spatrick CGF.EmitLoadOfScalar(IL, S.getBeginLoc()));
5765e5dd7070Spatrick });
5766e5dd7070Spatrick }
5767e5dd7070Spatrick if (isOpenMPSimdDirective(S.getDirectiveKind()) &&
5768e5dd7070Spatrick !isOpenMPParallelDirective(S.getDirectiveKind()) &&
5769e5dd7070Spatrick !isOpenMPTeamsDirective(S.getDirectiveKind())) {
5770e5dd7070Spatrick EmitOMPReductionClauseFinal(S, OMPD_simd);
5771e5dd7070Spatrick // Emit post-update of the reduction variables if IsLastIter != 0.
5772e5dd7070Spatrick emitPostUpdateForReductionClause(
5773e5dd7070Spatrick *this, S, [IL, &S](CodeGenFunction &CGF) {
5774e5dd7070Spatrick return CGF.Builder.CreateIsNotNull(
5775e5dd7070Spatrick CGF.EmitLoadOfScalar(IL, S.getBeginLoc()));
5776e5dd7070Spatrick });
5777e5dd7070Spatrick }
5778e5dd7070Spatrick // Emit final copy of the lastprivate variables if IsLastIter != 0.
5779e5dd7070Spatrick if (HasLastprivateClause) {
5780e5dd7070Spatrick EmitOMPLastprivateClauseFinal(
5781e5dd7070Spatrick S, /*NoFinals=*/false,
5782e5dd7070Spatrick Builder.CreateIsNotNull(EmitLoadOfScalar(IL, S.getBeginLoc())));
5783e5dd7070Spatrick }
5784e5dd7070Spatrick }
5785e5dd7070Spatrick
5786e5dd7070Spatrick // We're now done with the loop, so jump to the continuation block.
5787e5dd7070Spatrick if (ContBlock) {
5788e5dd7070Spatrick EmitBranch(ContBlock);
5789e5dd7070Spatrick EmitBlock(ContBlock, true);
5790e5dd7070Spatrick }
5791e5dd7070Spatrick }
5792e5dd7070Spatrick }
5793e5dd7070Spatrick
EmitOMPDistributeDirective(const OMPDistributeDirective & S)5794e5dd7070Spatrick void CodeGenFunction::EmitOMPDistributeDirective(
5795e5dd7070Spatrick const OMPDistributeDirective &S) {
5796e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
5797e5dd7070Spatrick CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc());
5798e5dd7070Spatrick };
5799e5dd7070Spatrick OMPLexicalScope Scope(*this, S, OMPD_unknown);
5800e5dd7070Spatrick CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_distribute, CodeGen);
5801e5dd7070Spatrick }
5802e5dd7070Spatrick
emitOutlinedOrderedFunction(CodeGenModule & CGM,const CapturedStmt * S,SourceLocation Loc)5803e5dd7070Spatrick static llvm::Function *emitOutlinedOrderedFunction(CodeGenModule &CGM,
5804ec727ea7Spatrick const CapturedStmt *S,
5805ec727ea7Spatrick SourceLocation Loc) {
5806e5dd7070Spatrick CodeGenFunction CGF(CGM, /*suppressNewContext=*/true);
5807e5dd7070Spatrick CodeGenFunction::CGCapturedStmtInfo CapStmtInfo;
5808e5dd7070Spatrick CGF.CapturedStmtInfo = &CapStmtInfo;
5809ec727ea7Spatrick llvm::Function *Fn = CGF.GenerateOpenMPCapturedStmtFunction(*S, Loc);
5810e5dd7070Spatrick Fn->setDoesNotRecurse();
5811e5dd7070Spatrick return Fn;
5812e5dd7070Spatrick }
5813e5dd7070Spatrick
EmitOMPOrderedDirective(const OMPOrderedDirective & S)5814e5dd7070Spatrick void CodeGenFunction::EmitOMPOrderedDirective(const OMPOrderedDirective &S) {
5815*12c85518Srobert if (CGM.getLangOpts().OpenMPIRBuilder) {
5816*12c85518Srobert llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
5817*12c85518Srobert using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
5818*12c85518Srobert
5819*12c85518Srobert if (S.hasClausesOfKind<OMPDependClause>()) {
5820*12c85518Srobert // The ordered directive with depend clause.
5821*12c85518Srobert assert(!S.hasAssociatedStmt() &&
5822*12c85518Srobert "No associated statement must be in ordered depend construct.");
5823*12c85518Srobert InsertPointTy AllocaIP(AllocaInsertPt->getParent(),
5824*12c85518Srobert AllocaInsertPt->getIterator());
5825*12c85518Srobert for (const auto *DC : S.getClausesOfKind<OMPDependClause>()) {
5826*12c85518Srobert unsigned NumLoops = DC->getNumLoops();
5827*12c85518Srobert QualType Int64Ty = CGM.getContext().getIntTypeForBitwidth(
5828*12c85518Srobert /*DestWidth=*/64, /*Signed=*/1);
5829*12c85518Srobert llvm::SmallVector<llvm::Value *> StoreValues;
5830*12c85518Srobert for (unsigned I = 0; I < NumLoops; I++) {
5831*12c85518Srobert const Expr *CounterVal = DC->getLoopData(I);
5832*12c85518Srobert assert(CounterVal);
5833*12c85518Srobert llvm::Value *StoreValue = EmitScalarConversion(
5834*12c85518Srobert EmitScalarExpr(CounterVal), CounterVal->getType(), Int64Ty,
5835*12c85518Srobert CounterVal->getExprLoc());
5836*12c85518Srobert StoreValues.emplace_back(StoreValue);
5837*12c85518Srobert }
5838*12c85518Srobert bool IsDependSource = false;
5839*12c85518Srobert if (DC->getDependencyKind() == OMPC_DEPEND_source)
5840*12c85518Srobert IsDependSource = true;
5841*12c85518Srobert Builder.restoreIP(OMPBuilder.createOrderedDepend(
5842*12c85518Srobert Builder, AllocaIP, NumLoops, StoreValues, ".cnt.addr",
5843*12c85518Srobert IsDependSource));
5844*12c85518Srobert }
5845*12c85518Srobert } else {
5846*12c85518Srobert // The ordered directive with threads or simd clause, or without clause.
5847*12c85518Srobert // Without clause, it behaves as if the threads clause is specified.
5848*12c85518Srobert const auto *C = S.getSingleClause<OMPSIMDClause>();
5849*12c85518Srobert
5850*12c85518Srobert auto FiniCB = [this](InsertPointTy IP) {
5851*12c85518Srobert OMPBuilderCBHelpers::FinalizeOMPRegion(*this, IP);
5852*12c85518Srobert };
5853*12c85518Srobert
5854*12c85518Srobert auto BodyGenCB = [&S, C, this](InsertPointTy AllocaIP,
5855*12c85518Srobert InsertPointTy CodeGenIP) {
5856*12c85518Srobert Builder.restoreIP(CodeGenIP);
5857*12c85518Srobert
5858*12c85518Srobert const CapturedStmt *CS = S.getInnermostCapturedStmt();
5859*12c85518Srobert if (C) {
5860*12c85518Srobert llvm::BasicBlock *FiniBB = splitBBWithSuffix(
5861*12c85518Srobert Builder, /*CreateBranch=*/false, ".ordered.after");
5862*12c85518Srobert llvm::SmallVector<llvm::Value *, 16> CapturedVars;
5863*12c85518Srobert GenerateOpenMPCapturedVars(*CS, CapturedVars);
5864*12c85518Srobert llvm::Function *OutlinedFn =
5865*12c85518Srobert emitOutlinedOrderedFunction(CGM, CS, S.getBeginLoc());
5866*12c85518Srobert assert(S.getBeginLoc().isValid() &&
5867*12c85518Srobert "Outlined function call location must be valid.");
5868*12c85518Srobert ApplyDebugLocation::CreateDefaultArtificial(*this, S.getBeginLoc());
5869*12c85518Srobert OMPBuilderCBHelpers::EmitCaptureStmt(*this, CodeGenIP, *FiniBB,
5870*12c85518Srobert OutlinedFn, CapturedVars);
5871*12c85518Srobert } else {
5872*12c85518Srobert OMPBuilderCBHelpers::EmitOMPInlinedRegionBody(
5873*12c85518Srobert *this, CS->getCapturedStmt(), AllocaIP, CodeGenIP, "ordered");
5874*12c85518Srobert }
5875*12c85518Srobert };
5876*12c85518Srobert
5877*12c85518Srobert OMPLexicalScope Scope(*this, S, OMPD_unknown);
5878*12c85518Srobert Builder.restoreIP(
5879*12c85518Srobert OMPBuilder.createOrderedThreadsSimd(Builder, BodyGenCB, FiniCB, !C));
5880*12c85518Srobert }
5881*12c85518Srobert return;
5882*12c85518Srobert }
5883*12c85518Srobert
5884e5dd7070Spatrick if (S.hasClausesOfKind<OMPDependClause>()) {
5885a9ac8606Spatrick assert(!S.hasAssociatedStmt() &&
5886e5dd7070Spatrick "No associated statement must be in ordered depend construct.");
5887e5dd7070Spatrick for (const auto *DC : S.getClausesOfKind<OMPDependClause>())
5888e5dd7070Spatrick CGM.getOpenMPRuntime().emitDoacrossOrdered(*this, DC);
5889e5dd7070Spatrick return;
5890e5dd7070Spatrick }
5891e5dd7070Spatrick const auto *C = S.getSingleClause<OMPSIMDClause>();
5892e5dd7070Spatrick auto &&CodeGen = [&S, C, this](CodeGenFunction &CGF,
5893e5dd7070Spatrick PrePostActionTy &Action) {
5894e5dd7070Spatrick const CapturedStmt *CS = S.getInnermostCapturedStmt();
5895e5dd7070Spatrick if (C) {
5896e5dd7070Spatrick llvm::SmallVector<llvm::Value *, 16> CapturedVars;
5897e5dd7070Spatrick CGF.GenerateOpenMPCapturedVars(*CS, CapturedVars);
5898ec727ea7Spatrick llvm::Function *OutlinedFn =
5899ec727ea7Spatrick emitOutlinedOrderedFunction(CGM, CS, S.getBeginLoc());
5900e5dd7070Spatrick CGM.getOpenMPRuntime().emitOutlinedFunctionCall(CGF, S.getBeginLoc(),
5901e5dd7070Spatrick OutlinedFn, CapturedVars);
5902e5dd7070Spatrick } else {
5903e5dd7070Spatrick Action.Enter(CGF);
5904e5dd7070Spatrick CGF.EmitStmt(CS->getCapturedStmt());
5905e5dd7070Spatrick }
5906e5dd7070Spatrick };
5907e5dd7070Spatrick OMPLexicalScope Scope(*this, S, OMPD_unknown);
5908e5dd7070Spatrick CGM.getOpenMPRuntime().emitOrderedRegion(*this, CodeGen, S.getBeginLoc(), !C);
5909e5dd7070Spatrick }
5910e5dd7070Spatrick
convertToScalarValue(CodeGenFunction & CGF,RValue Val,QualType SrcType,QualType DestType,SourceLocation Loc)5911e5dd7070Spatrick static llvm::Value *convertToScalarValue(CodeGenFunction &CGF, RValue Val,
5912e5dd7070Spatrick QualType SrcType, QualType DestType,
5913e5dd7070Spatrick SourceLocation Loc) {
5914e5dd7070Spatrick assert(CGF.hasScalarEvaluationKind(DestType) &&
5915e5dd7070Spatrick "DestType must have scalar evaluation kind.");
5916e5dd7070Spatrick assert(!Val.isAggregate() && "Must be a scalar or complex.");
5917e5dd7070Spatrick return Val.isScalar() ? CGF.EmitScalarConversion(Val.getScalarVal(), SrcType,
5918e5dd7070Spatrick DestType, Loc)
5919e5dd7070Spatrick : CGF.EmitComplexToScalarConversion(
5920e5dd7070Spatrick Val.getComplexVal(), SrcType, DestType, Loc);
5921e5dd7070Spatrick }
5922e5dd7070Spatrick
5923e5dd7070Spatrick static CodeGenFunction::ComplexPairTy
convertToComplexValue(CodeGenFunction & CGF,RValue Val,QualType SrcType,QualType DestType,SourceLocation Loc)5924e5dd7070Spatrick convertToComplexValue(CodeGenFunction &CGF, RValue Val, QualType SrcType,
5925e5dd7070Spatrick QualType DestType, SourceLocation Loc) {
5926e5dd7070Spatrick assert(CGF.getEvaluationKind(DestType) == TEK_Complex &&
5927e5dd7070Spatrick "DestType must have complex evaluation kind.");
5928e5dd7070Spatrick CodeGenFunction::ComplexPairTy ComplexVal;
5929e5dd7070Spatrick if (Val.isScalar()) {
5930e5dd7070Spatrick // Convert the input element to the element type of the complex.
5931e5dd7070Spatrick QualType DestElementType =
5932e5dd7070Spatrick DestType->castAs<ComplexType>()->getElementType();
5933e5dd7070Spatrick llvm::Value *ScalarVal = CGF.EmitScalarConversion(
5934e5dd7070Spatrick Val.getScalarVal(), SrcType, DestElementType, Loc);
5935e5dd7070Spatrick ComplexVal = CodeGenFunction::ComplexPairTy(
5936e5dd7070Spatrick ScalarVal, llvm::Constant::getNullValue(ScalarVal->getType()));
5937e5dd7070Spatrick } else {
5938e5dd7070Spatrick assert(Val.isComplex() && "Must be a scalar or complex.");
5939e5dd7070Spatrick QualType SrcElementType = SrcType->castAs<ComplexType>()->getElementType();
5940e5dd7070Spatrick QualType DestElementType =
5941e5dd7070Spatrick DestType->castAs<ComplexType>()->getElementType();
5942e5dd7070Spatrick ComplexVal.first = CGF.EmitScalarConversion(
5943e5dd7070Spatrick Val.getComplexVal().first, SrcElementType, DestElementType, Loc);
5944e5dd7070Spatrick ComplexVal.second = CGF.EmitScalarConversion(
5945e5dd7070Spatrick Val.getComplexVal().second, SrcElementType, DestElementType, Loc);
5946e5dd7070Spatrick }
5947e5dd7070Spatrick return ComplexVal;
5948e5dd7070Spatrick }
5949e5dd7070Spatrick
emitSimpleAtomicStore(CodeGenFunction & CGF,llvm::AtomicOrdering AO,LValue LVal,RValue RVal)5950ec727ea7Spatrick static void emitSimpleAtomicStore(CodeGenFunction &CGF, llvm::AtomicOrdering AO,
5951e5dd7070Spatrick LValue LVal, RValue RVal) {
5952ec727ea7Spatrick if (LVal.isGlobalReg())
5953e5dd7070Spatrick CGF.EmitStoreThroughGlobalRegLValue(RVal, LVal);
5954ec727ea7Spatrick else
5955ec727ea7Spatrick CGF.EmitAtomicStore(RVal, LVal, AO, LVal.isVolatile(), /*isInit=*/false);
5956e5dd7070Spatrick }
5957ec727ea7Spatrick
emitSimpleAtomicLoad(CodeGenFunction & CGF,llvm::AtomicOrdering AO,LValue LVal,SourceLocation Loc)5958ec727ea7Spatrick static RValue emitSimpleAtomicLoad(CodeGenFunction &CGF,
5959ec727ea7Spatrick llvm::AtomicOrdering AO, LValue LVal,
5960ec727ea7Spatrick SourceLocation Loc) {
5961ec727ea7Spatrick if (LVal.isGlobalReg())
5962ec727ea7Spatrick return CGF.EmitLoadOfLValue(LVal, Loc);
5963ec727ea7Spatrick return CGF.EmitAtomicLoad(
5964ec727ea7Spatrick LVal, Loc, llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(AO),
5965ec727ea7Spatrick LVal.isVolatile());
5966e5dd7070Spatrick }
5967e5dd7070Spatrick
emitOMPSimpleStore(LValue LVal,RValue RVal,QualType RValTy,SourceLocation Loc)5968e5dd7070Spatrick void CodeGenFunction::emitOMPSimpleStore(LValue LVal, RValue RVal,
5969e5dd7070Spatrick QualType RValTy, SourceLocation Loc) {
5970e5dd7070Spatrick switch (getEvaluationKind(LVal.getType())) {
5971e5dd7070Spatrick case TEK_Scalar:
5972e5dd7070Spatrick EmitStoreThroughLValue(RValue::get(convertToScalarValue(
5973e5dd7070Spatrick *this, RVal, RValTy, LVal.getType(), Loc)),
5974e5dd7070Spatrick LVal);
5975e5dd7070Spatrick break;
5976e5dd7070Spatrick case TEK_Complex:
5977e5dd7070Spatrick EmitStoreOfComplex(
5978e5dd7070Spatrick convertToComplexValue(*this, RVal, RValTy, LVal.getType(), Loc), LVal,
5979e5dd7070Spatrick /*isInit=*/false);
5980e5dd7070Spatrick break;
5981e5dd7070Spatrick case TEK_Aggregate:
5982e5dd7070Spatrick llvm_unreachable("Must be a scalar or complex.");
5983e5dd7070Spatrick }
5984e5dd7070Spatrick }
5985e5dd7070Spatrick
emitOMPAtomicReadExpr(CodeGenFunction & CGF,llvm::AtomicOrdering AO,const Expr * X,const Expr * V,SourceLocation Loc)5986ec727ea7Spatrick static void emitOMPAtomicReadExpr(CodeGenFunction &CGF, llvm::AtomicOrdering AO,
5987e5dd7070Spatrick const Expr *X, const Expr *V,
5988e5dd7070Spatrick SourceLocation Loc) {
5989e5dd7070Spatrick // v = x;
5990e5dd7070Spatrick assert(V->isLValue() && "V of 'omp atomic read' is not lvalue");
5991e5dd7070Spatrick assert(X->isLValue() && "X of 'omp atomic read' is not lvalue");
5992e5dd7070Spatrick LValue XLValue = CGF.EmitLValue(X);
5993e5dd7070Spatrick LValue VLValue = CGF.EmitLValue(V);
5994ec727ea7Spatrick RValue Res = emitSimpleAtomicLoad(CGF, AO, XLValue, Loc);
5995ec727ea7Spatrick // OpenMP, 2.17.7, atomic Construct
5996ec727ea7Spatrick // If the read or capture clause is specified and the acquire, acq_rel, or
5997ec727ea7Spatrick // seq_cst clause is specified then the strong flush on exit from the atomic
5998ec727ea7Spatrick // operation is also an acquire flush.
5999ec727ea7Spatrick switch (AO) {
6000ec727ea7Spatrick case llvm::AtomicOrdering::Acquire:
6001ec727ea7Spatrick case llvm::AtomicOrdering::AcquireRelease:
6002ec727ea7Spatrick case llvm::AtomicOrdering::SequentiallyConsistent:
6003*12c85518Srobert CGF.CGM.getOpenMPRuntime().emitFlush(CGF, std::nullopt, Loc,
6004ec727ea7Spatrick llvm::AtomicOrdering::Acquire);
6005ec727ea7Spatrick break;
6006ec727ea7Spatrick case llvm::AtomicOrdering::Monotonic:
6007ec727ea7Spatrick case llvm::AtomicOrdering::Release:
6008ec727ea7Spatrick break;
6009ec727ea7Spatrick case llvm::AtomicOrdering::NotAtomic:
6010ec727ea7Spatrick case llvm::AtomicOrdering::Unordered:
6011ec727ea7Spatrick llvm_unreachable("Unexpected ordering.");
6012ec727ea7Spatrick }
6013e5dd7070Spatrick CGF.emitOMPSimpleStore(VLValue, Res, X->getType().getNonReferenceType(), Loc);
6014ec727ea7Spatrick CGF.CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(CGF, V);
6015e5dd7070Spatrick }
6016e5dd7070Spatrick
emitOMPAtomicWriteExpr(CodeGenFunction & CGF,llvm::AtomicOrdering AO,const Expr * X,const Expr * E,SourceLocation Loc)6017ec727ea7Spatrick static void emitOMPAtomicWriteExpr(CodeGenFunction &CGF,
6018ec727ea7Spatrick llvm::AtomicOrdering AO, const Expr *X,
6019ec727ea7Spatrick const Expr *E, SourceLocation Loc) {
6020e5dd7070Spatrick // x = expr;
6021e5dd7070Spatrick assert(X->isLValue() && "X of 'omp atomic write' is not lvalue");
6022ec727ea7Spatrick emitSimpleAtomicStore(CGF, AO, CGF.EmitLValue(X), CGF.EmitAnyExpr(E));
6023ec727ea7Spatrick CGF.CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(CGF, X);
6024ec727ea7Spatrick // OpenMP, 2.17.7, atomic Construct
6025ec727ea7Spatrick // If the write, update, or capture clause is specified and the release,
6026ec727ea7Spatrick // acq_rel, or seq_cst clause is specified then the strong flush on entry to
6027ec727ea7Spatrick // the atomic operation is also a release flush.
6028ec727ea7Spatrick switch (AO) {
6029ec727ea7Spatrick case llvm::AtomicOrdering::Release:
6030ec727ea7Spatrick case llvm::AtomicOrdering::AcquireRelease:
6031ec727ea7Spatrick case llvm::AtomicOrdering::SequentiallyConsistent:
6032*12c85518Srobert CGF.CGM.getOpenMPRuntime().emitFlush(CGF, std::nullopt, Loc,
6033ec727ea7Spatrick llvm::AtomicOrdering::Release);
6034ec727ea7Spatrick break;
6035ec727ea7Spatrick case llvm::AtomicOrdering::Acquire:
6036ec727ea7Spatrick case llvm::AtomicOrdering::Monotonic:
6037ec727ea7Spatrick break;
6038ec727ea7Spatrick case llvm::AtomicOrdering::NotAtomic:
6039ec727ea7Spatrick case llvm::AtomicOrdering::Unordered:
6040ec727ea7Spatrick llvm_unreachable("Unexpected ordering.");
6041ec727ea7Spatrick }
6042e5dd7070Spatrick }
6043e5dd7070Spatrick
emitOMPAtomicRMW(CodeGenFunction & CGF,LValue X,RValue Update,BinaryOperatorKind BO,llvm::AtomicOrdering AO,bool IsXLHSInRHSPart)6044e5dd7070Spatrick static std::pair<bool, RValue> emitOMPAtomicRMW(CodeGenFunction &CGF, LValue X,
6045e5dd7070Spatrick RValue Update,
6046e5dd7070Spatrick BinaryOperatorKind BO,
6047e5dd7070Spatrick llvm::AtomicOrdering AO,
6048e5dd7070Spatrick bool IsXLHSInRHSPart) {
6049e5dd7070Spatrick ASTContext &Context = CGF.getContext();
6050e5dd7070Spatrick // Allow atomicrmw only if 'x' and 'update' are integer values, lvalue for 'x'
6051e5dd7070Spatrick // expression is simple and atomic is allowed for the given type for the
6052e5dd7070Spatrick // target platform.
6053*12c85518Srobert if (BO == BO_Comma || !Update.isScalar() || !X.isSimple() ||
6054e5dd7070Spatrick (!isa<llvm::ConstantInt>(Update.getScalarVal()) &&
6055e5dd7070Spatrick (Update.getScalarVal()->getType() !=
6056e5dd7070Spatrick X.getAddress(CGF).getElementType())) ||
6057e5dd7070Spatrick !Context.getTargetInfo().hasBuiltinAtomic(
6058e5dd7070Spatrick Context.getTypeSize(X.getType()), Context.toBits(X.getAlignment())))
6059e5dd7070Spatrick return std::make_pair(false, RValue::get(nullptr));
6060e5dd7070Spatrick
6061*12c85518Srobert auto &&CheckAtomicSupport = [&CGF](llvm::Type *T, BinaryOperatorKind BO) {
6062*12c85518Srobert if (T->isIntegerTy())
6063*12c85518Srobert return true;
6064*12c85518Srobert
6065*12c85518Srobert if (T->isFloatingPointTy() && (BO == BO_Add || BO == BO_Sub))
6066*12c85518Srobert return llvm::isPowerOf2_64(CGF.CGM.getDataLayout().getTypeStoreSize(T));
6067*12c85518Srobert
6068*12c85518Srobert return false;
6069*12c85518Srobert };
6070*12c85518Srobert
6071*12c85518Srobert if (!CheckAtomicSupport(Update.getScalarVal()->getType(), BO) ||
6072*12c85518Srobert !CheckAtomicSupport(X.getAddress(CGF).getElementType(), BO))
6073*12c85518Srobert return std::make_pair(false, RValue::get(nullptr));
6074*12c85518Srobert
6075*12c85518Srobert bool IsInteger = X.getAddress(CGF).getElementType()->isIntegerTy();
6076e5dd7070Spatrick llvm::AtomicRMWInst::BinOp RMWOp;
6077e5dd7070Spatrick switch (BO) {
6078e5dd7070Spatrick case BO_Add:
6079*12c85518Srobert RMWOp = IsInteger ? llvm::AtomicRMWInst::Add : llvm::AtomicRMWInst::FAdd;
6080e5dd7070Spatrick break;
6081e5dd7070Spatrick case BO_Sub:
6082e5dd7070Spatrick if (!IsXLHSInRHSPart)
6083e5dd7070Spatrick return std::make_pair(false, RValue::get(nullptr));
6084*12c85518Srobert RMWOp = IsInteger ? llvm::AtomicRMWInst::Sub : llvm::AtomicRMWInst::FSub;
6085e5dd7070Spatrick break;
6086e5dd7070Spatrick case BO_And:
6087e5dd7070Spatrick RMWOp = llvm::AtomicRMWInst::And;
6088e5dd7070Spatrick break;
6089e5dd7070Spatrick case BO_Or:
6090e5dd7070Spatrick RMWOp = llvm::AtomicRMWInst::Or;
6091e5dd7070Spatrick break;
6092e5dd7070Spatrick case BO_Xor:
6093e5dd7070Spatrick RMWOp = llvm::AtomicRMWInst::Xor;
6094e5dd7070Spatrick break;
6095e5dd7070Spatrick case BO_LT:
6096*12c85518Srobert if (IsInteger)
6097e5dd7070Spatrick RMWOp = X.getType()->hasSignedIntegerRepresentation()
6098e5dd7070Spatrick ? (IsXLHSInRHSPart ? llvm::AtomicRMWInst::Min
6099e5dd7070Spatrick : llvm::AtomicRMWInst::Max)
6100e5dd7070Spatrick : (IsXLHSInRHSPart ? llvm::AtomicRMWInst::UMin
6101e5dd7070Spatrick : llvm::AtomicRMWInst::UMax);
6102*12c85518Srobert else
6103*12c85518Srobert RMWOp = IsXLHSInRHSPart ? llvm::AtomicRMWInst::FMin
6104*12c85518Srobert : llvm::AtomicRMWInst::FMax;
6105e5dd7070Spatrick break;
6106e5dd7070Spatrick case BO_GT:
6107*12c85518Srobert if (IsInteger)
6108e5dd7070Spatrick RMWOp = X.getType()->hasSignedIntegerRepresentation()
6109e5dd7070Spatrick ? (IsXLHSInRHSPart ? llvm::AtomicRMWInst::Max
6110e5dd7070Spatrick : llvm::AtomicRMWInst::Min)
6111e5dd7070Spatrick : (IsXLHSInRHSPart ? llvm::AtomicRMWInst::UMax
6112e5dd7070Spatrick : llvm::AtomicRMWInst::UMin);
6113*12c85518Srobert else
6114*12c85518Srobert RMWOp = IsXLHSInRHSPart ? llvm::AtomicRMWInst::FMax
6115*12c85518Srobert : llvm::AtomicRMWInst::FMin;
6116e5dd7070Spatrick break;
6117e5dd7070Spatrick case BO_Assign:
6118e5dd7070Spatrick RMWOp = llvm::AtomicRMWInst::Xchg;
6119e5dd7070Spatrick break;
6120e5dd7070Spatrick case BO_Mul:
6121e5dd7070Spatrick case BO_Div:
6122e5dd7070Spatrick case BO_Rem:
6123e5dd7070Spatrick case BO_Shl:
6124e5dd7070Spatrick case BO_Shr:
6125e5dd7070Spatrick case BO_LAnd:
6126e5dd7070Spatrick case BO_LOr:
6127e5dd7070Spatrick return std::make_pair(false, RValue::get(nullptr));
6128e5dd7070Spatrick case BO_PtrMemD:
6129e5dd7070Spatrick case BO_PtrMemI:
6130e5dd7070Spatrick case BO_LE:
6131e5dd7070Spatrick case BO_GE:
6132e5dd7070Spatrick case BO_EQ:
6133e5dd7070Spatrick case BO_NE:
6134e5dd7070Spatrick case BO_Cmp:
6135e5dd7070Spatrick case BO_AddAssign:
6136e5dd7070Spatrick case BO_SubAssign:
6137e5dd7070Spatrick case BO_AndAssign:
6138e5dd7070Spatrick case BO_OrAssign:
6139e5dd7070Spatrick case BO_XorAssign:
6140e5dd7070Spatrick case BO_MulAssign:
6141e5dd7070Spatrick case BO_DivAssign:
6142e5dd7070Spatrick case BO_RemAssign:
6143e5dd7070Spatrick case BO_ShlAssign:
6144e5dd7070Spatrick case BO_ShrAssign:
6145e5dd7070Spatrick case BO_Comma:
6146e5dd7070Spatrick llvm_unreachable("Unsupported atomic update operation");
6147e5dd7070Spatrick }
6148e5dd7070Spatrick llvm::Value *UpdateVal = Update.getScalarVal();
6149e5dd7070Spatrick if (auto *IC = dyn_cast<llvm::ConstantInt>(UpdateVal)) {
6150*12c85518Srobert if (IsInteger)
6151e5dd7070Spatrick UpdateVal = CGF.Builder.CreateIntCast(
6152e5dd7070Spatrick IC, X.getAddress(CGF).getElementType(),
6153e5dd7070Spatrick X.getType()->hasSignedIntegerRepresentation());
6154*12c85518Srobert else
6155*12c85518Srobert UpdateVal = CGF.Builder.CreateCast(llvm::Instruction::CastOps::UIToFP, IC,
6156*12c85518Srobert X.getAddress(CGF).getElementType());
6157e5dd7070Spatrick }
6158e5dd7070Spatrick llvm::Value *Res =
6159e5dd7070Spatrick CGF.Builder.CreateAtomicRMW(RMWOp, X.getPointer(CGF), UpdateVal, AO);
6160e5dd7070Spatrick return std::make_pair(true, RValue::get(Res));
6161e5dd7070Spatrick }
6162e5dd7070Spatrick
EmitOMPAtomicSimpleUpdateExpr(LValue X,RValue E,BinaryOperatorKind BO,bool IsXLHSInRHSPart,llvm::AtomicOrdering AO,SourceLocation Loc,const llvm::function_ref<RValue (RValue)> CommonGen)6163e5dd7070Spatrick std::pair<bool, RValue> CodeGenFunction::EmitOMPAtomicSimpleUpdateExpr(
6164e5dd7070Spatrick LValue X, RValue E, BinaryOperatorKind BO, bool IsXLHSInRHSPart,
6165e5dd7070Spatrick llvm::AtomicOrdering AO, SourceLocation Loc,
6166e5dd7070Spatrick const llvm::function_ref<RValue(RValue)> CommonGen) {
6167e5dd7070Spatrick // Update expressions are allowed to have the following forms:
6168e5dd7070Spatrick // x binop= expr; -> xrval + expr;
6169e5dd7070Spatrick // x++, ++x -> xrval + 1;
6170e5dd7070Spatrick // x--, --x -> xrval - 1;
6171e5dd7070Spatrick // x = x binop expr; -> xrval binop expr
6172e5dd7070Spatrick // x = expr Op x; - > expr binop xrval;
6173e5dd7070Spatrick auto Res = emitOMPAtomicRMW(*this, X, E, BO, AO, IsXLHSInRHSPart);
6174e5dd7070Spatrick if (!Res.first) {
6175e5dd7070Spatrick if (X.isGlobalReg()) {
6176e5dd7070Spatrick // Emit an update expression: 'xrval' binop 'expr' or 'expr' binop
6177e5dd7070Spatrick // 'xrval'.
6178e5dd7070Spatrick EmitStoreThroughLValue(CommonGen(EmitLoadOfLValue(X, Loc)), X);
6179e5dd7070Spatrick } else {
6180e5dd7070Spatrick // Perform compare-and-swap procedure.
6181e5dd7070Spatrick EmitAtomicUpdate(X, AO, CommonGen, X.getType().isVolatileQualified());
6182e5dd7070Spatrick }
6183e5dd7070Spatrick }
6184e5dd7070Spatrick return Res;
6185e5dd7070Spatrick }
6186e5dd7070Spatrick
emitOMPAtomicUpdateExpr(CodeGenFunction & CGF,llvm::AtomicOrdering AO,const Expr * X,const Expr * E,const Expr * UE,bool IsXLHSInRHSPart,SourceLocation Loc)6187ec727ea7Spatrick static void emitOMPAtomicUpdateExpr(CodeGenFunction &CGF,
6188ec727ea7Spatrick llvm::AtomicOrdering AO, const Expr *X,
6189ec727ea7Spatrick const Expr *E, const Expr *UE,
6190ec727ea7Spatrick bool IsXLHSInRHSPart, SourceLocation Loc) {
6191e5dd7070Spatrick assert(isa<BinaryOperator>(UE->IgnoreImpCasts()) &&
6192e5dd7070Spatrick "Update expr in 'atomic update' must be a binary operator.");
6193e5dd7070Spatrick const auto *BOUE = cast<BinaryOperator>(UE->IgnoreImpCasts());
6194e5dd7070Spatrick // Update expressions are allowed to have the following forms:
6195e5dd7070Spatrick // x binop= expr; -> xrval + expr;
6196e5dd7070Spatrick // x++, ++x -> xrval + 1;
6197e5dd7070Spatrick // x--, --x -> xrval - 1;
6198e5dd7070Spatrick // x = x binop expr; -> xrval binop expr
6199e5dd7070Spatrick // x = expr Op x; - > expr binop xrval;
6200e5dd7070Spatrick assert(X->isLValue() && "X of 'omp atomic update' is not lvalue");
6201e5dd7070Spatrick LValue XLValue = CGF.EmitLValue(X);
6202e5dd7070Spatrick RValue ExprRValue = CGF.EmitAnyExpr(E);
6203e5dd7070Spatrick const auto *LHS = cast<OpaqueValueExpr>(BOUE->getLHS()->IgnoreImpCasts());
6204e5dd7070Spatrick const auto *RHS = cast<OpaqueValueExpr>(BOUE->getRHS()->IgnoreImpCasts());
6205e5dd7070Spatrick const OpaqueValueExpr *XRValExpr = IsXLHSInRHSPart ? LHS : RHS;
6206e5dd7070Spatrick const OpaqueValueExpr *ERValExpr = IsXLHSInRHSPart ? RHS : LHS;
6207e5dd7070Spatrick auto &&Gen = [&CGF, UE, ExprRValue, XRValExpr, ERValExpr](RValue XRValue) {
6208e5dd7070Spatrick CodeGenFunction::OpaqueValueMapping MapExpr(CGF, ERValExpr, ExprRValue);
6209e5dd7070Spatrick CodeGenFunction::OpaqueValueMapping MapX(CGF, XRValExpr, XRValue);
6210e5dd7070Spatrick return CGF.EmitAnyExpr(UE);
6211e5dd7070Spatrick };
6212e5dd7070Spatrick (void)CGF.EmitOMPAtomicSimpleUpdateExpr(
6213e5dd7070Spatrick XLValue, ExprRValue, BOUE->getOpcode(), IsXLHSInRHSPart, AO, Loc, Gen);
6214ec727ea7Spatrick CGF.CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(CGF, X);
6215ec727ea7Spatrick // OpenMP, 2.17.7, atomic Construct
6216ec727ea7Spatrick // If the write, update, or capture clause is specified and the release,
6217ec727ea7Spatrick // acq_rel, or seq_cst clause is specified then the strong flush on entry to
6218ec727ea7Spatrick // the atomic operation is also a release flush.
6219ec727ea7Spatrick switch (AO) {
6220ec727ea7Spatrick case llvm::AtomicOrdering::Release:
6221ec727ea7Spatrick case llvm::AtomicOrdering::AcquireRelease:
6222ec727ea7Spatrick case llvm::AtomicOrdering::SequentiallyConsistent:
6223*12c85518Srobert CGF.CGM.getOpenMPRuntime().emitFlush(CGF, std::nullopt, Loc,
6224ec727ea7Spatrick llvm::AtomicOrdering::Release);
6225ec727ea7Spatrick break;
6226ec727ea7Spatrick case llvm::AtomicOrdering::Acquire:
6227ec727ea7Spatrick case llvm::AtomicOrdering::Monotonic:
6228ec727ea7Spatrick break;
6229ec727ea7Spatrick case llvm::AtomicOrdering::NotAtomic:
6230ec727ea7Spatrick case llvm::AtomicOrdering::Unordered:
6231ec727ea7Spatrick llvm_unreachable("Unexpected ordering.");
6232ec727ea7Spatrick }
6233e5dd7070Spatrick }
6234e5dd7070Spatrick
convertToType(CodeGenFunction & CGF,RValue Value,QualType SourceType,QualType ResType,SourceLocation Loc)6235e5dd7070Spatrick static RValue convertToType(CodeGenFunction &CGF, RValue Value,
6236e5dd7070Spatrick QualType SourceType, QualType ResType,
6237e5dd7070Spatrick SourceLocation Loc) {
6238e5dd7070Spatrick switch (CGF.getEvaluationKind(ResType)) {
6239e5dd7070Spatrick case TEK_Scalar:
6240e5dd7070Spatrick return RValue::get(
6241e5dd7070Spatrick convertToScalarValue(CGF, Value, SourceType, ResType, Loc));
6242e5dd7070Spatrick case TEK_Complex: {
6243e5dd7070Spatrick auto Res = convertToComplexValue(CGF, Value, SourceType, ResType, Loc);
6244e5dd7070Spatrick return RValue::getComplex(Res.first, Res.second);
6245e5dd7070Spatrick }
6246e5dd7070Spatrick case TEK_Aggregate:
6247e5dd7070Spatrick break;
6248e5dd7070Spatrick }
6249e5dd7070Spatrick llvm_unreachable("Must be a scalar or complex.");
6250e5dd7070Spatrick }
6251e5dd7070Spatrick
emitOMPAtomicCaptureExpr(CodeGenFunction & CGF,llvm::AtomicOrdering AO,bool IsPostfixUpdate,const Expr * V,const Expr * X,const Expr * E,const Expr * UE,bool IsXLHSInRHSPart,SourceLocation Loc)6252ec727ea7Spatrick static void emitOMPAtomicCaptureExpr(CodeGenFunction &CGF,
6253ec727ea7Spatrick llvm::AtomicOrdering AO,
6254e5dd7070Spatrick bool IsPostfixUpdate, const Expr *V,
6255e5dd7070Spatrick const Expr *X, const Expr *E,
6256e5dd7070Spatrick const Expr *UE, bool IsXLHSInRHSPart,
6257e5dd7070Spatrick SourceLocation Loc) {
6258e5dd7070Spatrick assert(X->isLValue() && "X of 'omp atomic capture' is not lvalue");
6259e5dd7070Spatrick assert(V->isLValue() && "V of 'omp atomic capture' is not lvalue");
6260e5dd7070Spatrick RValue NewVVal;
6261e5dd7070Spatrick LValue VLValue = CGF.EmitLValue(V);
6262e5dd7070Spatrick LValue XLValue = CGF.EmitLValue(X);
6263e5dd7070Spatrick RValue ExprRValue = CGF.EmitAnyExpr(E);
6264e5dd7070Spatrick QualType NewVValType;
6265e5dd7070Spatrick if (UE) {
6266e5dd7070Spatrick // 'x' is updated with some additional value.
6267e5dd7070Spatrick assert(isa<BinaryOperator>(UE->IgnoreImpCasts()) &&
6268e5dd7070Spatrick "Update expr in 'atomic capture' must be a binary operator.");
6269e5dd7070Spatrick const auto *BOUE = cast<BinaryOperator>(UE->IgnoreImpCasts());
6270e5dd7070Spatrick // Update expressions are allowed to have the following forms:
6271e5dd7070Spatrick // x binop= expr; -> xrval + expr;
6272e5dd7070Spatrick // x++, ++x -> xrval + 1;
6273e5dd7070Spatrick // x--, --x -> xrval - 1;
6274e5dd7070Spatrick // x = x binop expr; -> xrval binop expr
6275e5dd7070Spatrick // x = expr Op x; - > expr binop xrval;
6276e5dd7070Spatrick const auto *LHS = cast<OpaqueValueExpr>(BOUE->getLHS()->IgnoreImpCasts());
6277e5dd7070Spatrick const auto *RHS = cast<OpaqueValueExpr>(BOUE->getRHS()->IgnoreImpCasts());
6278e5dd7070Spatrick const OpaqueValueExpr *XRValExpr = IsXLHSInRHSPart ? LHS : RHS;
6279e5dd7070Spatrick NewVValType = XRValExpr->getType();
6280e5dd7070Spatrick const OpaqueValueExpr *ERValExpr = IsXLHSInRHSPart ? RHS : LHS;
6281e5dd7070Spatrick auto &&Gen = [&CGF, &NewVVal, UE, ExprRValue, XRValExpr, ERValExpr,
6282e5dd7070Spatrick IsPostfixUpdate](RValue XRValue) {
6283e5dd7070Spatrick CodeGenFunction::OpaqueValueMapping MapExpr(CGF, ERValExpr, ExprRValue);
6284e5dd7070Spatrick CodeGenFunction::OpaqueValueMapping MapX(CGF, XRValExpr, XRValue);
6285e5dd7070Spatrick RValue Res = CGF.EmitAnyExpr(UE);
6286e5dd7070Spatrick NewVVal = IsPostfixUpdate ? XRValue : Res;
6287e5dd7070Spatrick return Res;
6288e5dd7070Spatrick };
6289e5dd7070Spatrick auto Res = CGF.EmitOMPAtomicSimpleUpdateExpr(
6290e5dd7070Spatrick XLValue, ExprRValue, BOUE->getOpcode(), IsXLHSInRHSPart, AO, Loc, Gen);
6291ec727ea7Spatrick CGF.CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(CGF, X);
6292e5dd7070Spatrick if (Res.first) {
6293e5dd7070Spatrick // 'atomicrmw' instruction was generated.
6294e5dd7070Spatrick if (IsPostfixUpdate) {
6295e5dd7070Spatrick // Use old value from 'atomicrmw'.
6296e5dd7070Spatrick NewVVal = Res.second;
6297e5dd7070Spatrick } else {
6298e5dd7070Spatrick // 'atomicrmw' does not provide new value, so evaluate it using old
6299e5dd7070Spatrick // value of 'x'.
6300e5dd7070Spatrick CodeGenFunction::OpaqueValueMapping MapExpr(CGF, ERValExpr, ExprRValue);
6301e5dd7070Spatrick CodeGenFunction::OpaqueValueMapping MapX(CGF, XRValExpr, Res.second);
6302e5dd7070Spatrick NewVVal = CGF.EmitAnyExpr(UE);
6303e5dd7070Spatrick }
6304e5dd7070Spatrick }
6305e5dd7070Spatrick } else {
6306e5dd7070Spatrick // 'x' is simply rewritten with some 'expr'.
6307e5dd7070Spatrick NewVValType = X->getType().getNonReferenceType();
6308e5dd7070Spatrick ExprRValue = convertToType(CGF, ExprRValue, E->getType(),
6309e5dd7070Spatrick X->getType().getNonReferenceType(), Loc);
6310e5dd7070Spatrick auto &&Gen = [&NewVVal, ExprRValue](RValue XRValue) {
6311e5dd7070Spatrick NewVVal = XRValue;
6312e5dd7070Spatrick return ExprRValue;
6313e5dd7070Spatrick };
6314e5dd7070Spatrick // Try to perform atomicrmw xchg, otherwise simple exchange.
6315e5dd7070Spatrick auto Res = CGF.EmitOMPAtomicSimpleUpdateExpr(
6316e5dd7070Spatrick XLValue, ExprRValue, /*BO=*/BO_Assign, /*IsXLHSInRHSPart=*/false, AO,
6317e5dd7070Spatrick Loc, Gen);
6318ec727ea7Spatrick CGF.CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(CGF, X);
6319e5dd7070Spatrick if (Res.first) {
6320e5dd7070Spatrick // 'atomicrmw' instruction was generated.
6321e5dd7070Spatrick NewVVal = IsPostfixUpdate ? Res.second : ExprRValue;
6322e5dd7070Spatrick }
6323e5dd7070Spatrick }
6324e5dd7070Spatrick // Emit post-update store to 'v' of old/new 'x' value.
6325e5dd7070Spatrick CGF.emitOMPSimpleStore(VLValue, NewVVal, NewVValType, Loc);
6326ec727ea7Spatrick CGF.CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(CGF, V);
6327a9ac8606Spatrick // OpenMP 5.1 removes the required flush for capture clause.
6328a9ac8606Spatrick if (CGF.CGM.getLangOpts().OpenMP < 51) {
6329ec727ea7Spatrick // OpenMP, 2.17.7, atomic Construct
6330ec727ea7Spatrick // If the write, update, or capture clause is specified and the release,
6331ec727ea7Spatrick // acq_rel, or seq_cst clause is specified then the strong flush on entry to
6332ec727ea7Spatrick // the atomic operation is also a release flush.
6333ec727ea7Spatrick // If the read or capture clause is specified and the acquire, acq_rel, or
6334ec727ea7Spatrick // seq_cst clause is specified then the strong flush on exit from the atomic
6335ec727ea7Spatrick // operation is also an acquire flush.
6336ec727ea7Spatrick switch (AO) {
6337ec727ea7Spatrick case llvm::AtomicOrdering::Release:
6338*12c85518Srobert CGF.CGM.getOpenMPRuntime().emitFlush(CGF, std::nullopt, Loc,
6339ec727ea7Spatrick llvm::AtomicOrdering::Release);
6340ec727ea7Spatrick break;
6341ec727ea7Spatrick case llvm::AtomicOrdering::Acquire:
6342*12c85518Srobert CGF.CGM.getOpenMPRuntime().emitFlush(CGF, std::nullopt, Loc,
6343ec727ea7Spatrick llvm::AtomicOrdering::Acquire);
6344ec727ea7Spatrick break;
6345ec727ea7Spatrick case llvm::AtomicOrdering::AcquireRelease:
6346ec727ea7Spatrick case llvm::AtomicOrdering::SequentiallyConsistent:
6347a9ac8606Spatrick CGF.CGM.getOpenMPRuntime().emitFlush(
6348*12c85518Srobert CGF, std::nullopt, Loc, llvm::AtomicOrdering::AcquireRelease);
6349ec727ea7Spatrick break;
6350ec727ea7Spatrick case llvm::AtomicOrdering::Monotonic:
6351ec727ea7Spatrick break;
6352ec727ea7Spatrick case llvm::AtomicOrdering::NotAtomic:
6353ec727ea7Spatrick case llvm::AtomicOrdering::Unordered:
6354ec727ea7Spatrick llvm_unreachable("Unexpected ordering.");
6355ec727ea7Spatrick }
6356e5dd7070Spatrick }
6357a9ac8606Spatrick }
6358e5dd7070Spatrick
emitOMPAtomicCompareExpr(CodeGenFunction & CGF,llvm::AtomicOrdering AO,const Expr * X,const Expr * V,const Expr * R,const Expr * E,const Expr * D,const Expr * CE,bool IsXBinopExpr,bool IsPostfixUpdate,bool IsFailOnly,SourceLocation Loc)6359*12c85518Srobert static void emitOMPAtomicCompareExpr(CodeGenFunction &CGF,
6360*12c85518Srobert llvm::AtomicOrdering AO, const Expr *X,
6361*12c85518Srobert const Expr *V, const Expr *R,
6362*12c85518Srobert const Expr *E, const Expr *D,
6363*12c85518Srobert const Expr *CE, bool IsXBinopExpr,
6364*12c85518Srobert bool IsPostfixUpdate, bool IsFailOnly,
6365*12c85518Srobert SourceLocation Loc) {
6366*12c85518Srobert llvm::OpenMPIRBuilder &OMPBuilder =
6367*12c85518Srobert CGF.CGM.getOpenMPRuntime().getOMPBuilder();
6368*12c85518Srobert
6369*12c85518Srobert OMPAtomicCompareOp Op;
6370*12c85518Srobert assert(isa<BinaryOperator>(CE) && "CE is not a BinaryOperator");
6371*12c85518Srobert switch (cast<BinaryOperator>(CE)->getOpcode()) {
6372*12c85518Srobert case BO_EQ:
6373*12c85518Srobert Op = OMPAtomicCompareOp::EQ;
6374*12c85518Srobert break;
6375*12c85518Srobert case BO_LT:
6376*12c85518Srobert Op = OMPAtomicCompareOp::MIN;
6377*12c85518Srobert break;
6378*12c85518Srobert case BO_GT:
6379*12c85518Srobert Op = OMPAtomicCompareOp::MAX;
6380*12c85518Srobert break;
6381*12c85518Srobert default:
6382*12c85518Srobert llvm_unreachable("unsupported atomic compare binary operator");
6383*12c85518Srobert }
6384*12c85518Srobert
6385*12c85518Srobert LValue XLVal = CGF.EmitLValue(X);
6386*12c85518Srobert Address XAddr = XLVal.getAddress(CGF);
6387*12c85518Srobert
6388*12c85518Srobert auto EmitRValueWithCastIfNeeded = [&CGF, Loc](const Expr *X, const Expr *E) {
6389*12c85518Srobert if (X->getType() == E->getType())
6390*12c85518Srobert return CGF.EmitScalarExpr(E);
6391*12c85518Srobert const Expr *NewE = E->IgnoreImplicitAsWritten();
6392*12c85518Srobert llvm::Value *V = CGF.EmitScalarExpr(NewE);
6393*12c85518Srobert if (NewE->getType() == X->getType())
6394*12c85518Srobert return V;
6395*12c85518Srobert return CGF.EmitScalarConversion(V, NewE->getType(), X->getType(), Loc);
6396*12c85518Srobert };
6397*12c85518Srobert
6398*12c85518Srobert llvm::Value *EVal = EmitRValueWithCastIfNeeded(X, E);
6399*12c85518Srobert llvm::Value *DVal = D ? EmitRValueWithCastIfNeeded(X, D) : nullptr;
6400*12c85518Srobert if (auto *CI = dyn_cast<llvm::ConstantInt>(EVal))
6401*12c85518Srobert EVal = CGF.Builder.CreateIntCast(
6402*12c85518Srobert CI, XLVal.getAddress(CGF).getElementType(),
6403*12c85518Srobert E->getType()->hasSignedIntegerRepresentation());
6404*12c85518Srobert if (DVal)
6405*12c85518Srobert if (auto *CI = dyn_cast<llvm::ConstantInt>(DVal))
6406*12c85518Srobert DVal = CGF.Builder.CreateIntCast(
6407*12c85518Srobert CI, XLVal.getAddress(CGF).getElementType(),
6408*12c85518Srobert D->getType()->hasSignedIntegerRepresentation());
6409*12c85518Srobert
6410*12c85518Srobert llvm::OpenMPIRBuilder::AtomicOpValue XOpVal{
6411*12c85518Srobert XAddr.getPointer(), XAddr.getElementType(),
6412*12c85518Srobert X->getType()->hasSignedIntegerRepresentation(),
6413*12c85518Srobert X->getType().isVolatileQualified()};
6414*12c85518Srobert llvm::OpenMPIRBuilder::AtomicOpValue VOpVal, ROpVal;
6415*12c85518Srobert if (V) {
6416*12c85518Srobert LValue LV = CGF.EmitLValue(V);
6417*12c85518Srobert Address Addr = LV.getAddress(CGF);
6418*12c85518Srobert VOpVal = {Addr.getPointer(), Addr.getElementType(),
6419*12c85518Srobert V->getType()->hasSignedIntegerRepresentation(),
6420*12c85518Srobert V->getType().isVolatileQualified()};
6421*12c85518Srobert }
6422*12c85518Srobert if (R) {
6423*12c85518Srobert LValue LV = CGF.EmitLValue(R);
6424*12c85518Srobert Address Addr = LV.getAddress(CGF);
6425*12c85518Srobert ROpVal = {Addr.getPointer(), Addr.getElementType(),
6426*12c85518Srobert R->getType()->hasSignedIntegerRepresentation(),
6427*12c85518Srobert R->getType().isVolatileQualified()};
6428*12c85518Srobert }
6429*12c85518Srobert
6430*12c85518Srobert CGF.Builder.restoreIP(OMPBuilder.createAtomicCompare(
6431*12c85518Srobert CGF.Builder, XOpVal, VOpVal, ROpVal, EVal, DVal, AO, Op, IsXBinopExpr,
6432*12c85518Srobert IsPostfixUpdate, IsFailOnly));
6433*12c85518Srobert }
6434*12c85518Srobert
emitOMPAtomicExpr(CodeGenFunction & CGF,OpenMPClauseKind Kind,llvm::AtomicOrdering AO,bool IsPostfixUpdate,const Expr * X,const Expr * V,const Expr * R,const Expr * E,const Expr * UE,const Expr * D,const Expr * CE,bool IsXLHSInRHSPart,bool IsFailOnly,SourceLocation Loc)6435e5dd7070Spatrick static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind,
6436ec727ea7Spatrick llvm::AtomicOrdering AO, bool IsPostfixUpdate,
6437*12c85518Srobert const Expr *X, const Expr *V, const Expr *R,
6438*12c85518Srobert const Expr *E, const Expr *UE, const Expr *D,
6439*12c85518Srobert const Expr *CE, bool IsXLHSInRHSPart,
6440*12c85518Srobert bool IsFailOnly, SourceLocation Loc) {
6441e5dd7070Spatrick switch (Kind) {
6442e5dd7070Spatrick case OMPC_read:
6443ec727ea7Spatrick emitOMPAtomicReadExpr(CGF, AO, X, V, Loc);
6444e5dd7070Spatrick break;
6445e5dd7070Spatrick case OMPC_write:
6446ec727ea7Spatrick emitOMPAtomicWriteExpr(CGF, AO, X, E, Loc);
6447e5dd7070Spatrick break;
6448e5dd7070Spatrick case OMPC_unknown:
6449e5dd7070Spatrick case OMPC_update:
6450ec727ea7Spatrick emitOMPAtomicUpdateExpr(CGF, AO, X, E, UE, IsXLHSInRHSPart, Loc);
6451e5dd7070Spatrick break;
6452e5dd7070Spatrick case OMPC_capture:
6453ec727ea7Spatrick emitOMPAtomicCaptureExpr(CGF, AO, IsPostfixUpdate, V, X, E, UE,
6454e5dd7070Spatrick IsXLHSInRHSPart, Loc);
6455e5dd7070Spatrick break;
6456*12c85518Srobert case OMPC_compare: {
6457*12c85518Srobert emitOMPAtomicCompareExpr(CGF, AO, X, V, R, E, D, CE, IsXLHSInRHSPart,
6458*12c85518Srobert IsPostfixUpdate, IsFailOnly, Loc);
6459*12c85518Srobert break;
6460*12c85518Srobert }
6461*12c85518Srobert default:
6462e5dd7070Spatrick llvm_unreachable("Clause is not allowed in 'omp atomic'.");
6463e5dd7070Spatrick }
6464e5dd7070Spatrick }
6465e5dd7070Spatrick
EmitOMPAtomicDirective(const OMPAtomicDirective & S)6466e5dd7070Spatrick void CodeGenFunction::EmitOMPAtomicDirective(const OMPAtomicDirective &S) {
6467ec727ea7Spatrick llvm::AtomicOrdering AO = llvm::AtomicOrdering::Monotonic;
6468ec727ea7Spatrick bool MemOrderingSpecified = false;
6469ec727ea7Spatrick if (S.getSingleClause<OMPSeqCstClause>()) {
6470ec727ea7Spatrick AO = llvm::AtomicOrdering::SequentiallyConsistent;
6471ec727ea7Spatrick MemOrderingSpecified = true;
6472ec727ea7Spatrick } else if (S.getSingleClause<OMPAcqRelClause>()) {
6473ec727ea7Spatrick AO = llvm::AtomicOrdering::AcquireRelease;
6474ec727ea7Spatrick MemOrderingSpecified = true;
6475ec727ea7Spatrick } else if (S.getSingleClause<OMPAcquireClause>()) {
6476ec727ea7Spatrick AO = llvm::AtomicOrdering::Acquire;
6477ec727ea7Spatrick MemOrderingSpecified = true;
6478ec727ea7Spatrick } else if (S.getSingleClause<OMPReleaseClause>()) {
6479ec727ea7Spatrick AO = llvm::AtomicOrdering::Release;
6480ec727ea7Spatrick MemOrderingSpecified = true;
6481ec727ea7Spatrick } else if (S.getSingleClause<OMPRelaxedClause>()) {
6482ec727ea7Spatrick AO = llvm::AtomicOrdering::Monotonic;
6483ec727ea7Spatrick MemOrderingSpecified = true;
6484ec727ea7Spatrick }
6485*12c85518Srobert llvm::SmallSet<OpenMPClauseKind, 2> KindsEncountered;
6486e5dd7070Spatrick OpenMPClauseKind Kind = OMPC_unknown;
6487e5dd7070Spatrick for (const OMPClause *C : S.clauses()) {
6488ec727ea7Spatrick // Find first clause (skip seq_cst|acq_rel|aqcuire|release|relaxed clause,
6489ec727ea7Spatrick // if it is first).
6490*12c85518Srobert OpenMPClauseKind K = C->getClauseKind();
6491*12c85518Srobert if (K == OMPC_seq_cst || K == OMPC_acq_rel || K == OMPC_acquire ||
6492*12c85518Srobert K == OMPC_release || K == OMPC_relaxed || K == OMPC_hint)
6493*12c85518Srobert continue;
6494*12c85518Srobert Kind = K;
6495*12c85518Srobert KindsEncountered.insert(K);
6496e5dd7070Spatrick }
6497*12c85518Srobert // We just need to correct Kind here. No need to set a bool saying it is
6498*12c85518Srobert // actually compare capture because we can tell from whether V and R are
6499*12c85518Srobert // nullptr.
6500*12c85518Srobert if (KindsEncountered.contains(OMPC_compare) &&
6501*12c85518Srobert KindsEncountered.contains(OMPC_capture))
6502*12c85518Srobert Kind = OMPC_compare;
6503ec727ea7Spatrick if (!MemOrderingSpecified) {
6504ec727ea7Spatrick llvm::AtomicOrdering DefaultOrder =
6505ec727ea7Spatrick CGM.getOpenMPRuntime().getDefaultMemoryOrdering();
6506ec727ea7Spatrick if (DefaultOrder == llvm::AtomicOrdering::Monotonic ||
6507ec727ea7Spatrick DefaultOrder == llvm::AtomicOrdering::SequentiallyConsistent ||
6508ec727ea7Spatrick (DefaultOrder == llvm::AtomicOrdering::AcquireRelease &&
6509ec727ea7Spatrick Kind == OMPC_capture)) {
6510ec727ea7Spatrick AO = DefaultOrder;
6511ec727ea7Spatrick } else if (DefaultOrder == llvm::AtomicOrdering::AcquireRelease) {
6512ec727ea7Spatrick if (Kind == OMPC_unknown || Kind == OMPC_update || Kind == OMPC_write) {
6513ec727ea7Spatrick AO = llvm::AtomicOrdering::Release;
6514ec727ea7Spatrick } else if (Kind == OMPC_read) {
6515ec727ea7Spatrick assert(Kind == OMPC_read && "Unexpected atomic kind.");
6516ec727ea7Spatrick AO = llvm::AtomicOrdering::Acquire;
6517ec727ea7Spatrick }
6518ec727ea7Spatrick }
6519ec727ea7Spatrick }
6520e5dd7070Spatrick
6521a9ac8606Spatrick LexicalScope Scope(*this, S.getSourceRange());
6522a9ac8606Spatrick EmitStopPoint(S.getAssociatedStmt());
6523a9ac8606Spatrick emitOMPAtomicExpr(*this, Kind, AO, S.isPostfixUpdate(), S.getX(), S.getV(),
6524*12c85518Srobert S.getR(), S.getExpr(), S.getUpdateExpr(), S.getD(),
6525*12c85518Srobert S.getCondExpr(), S.isXLHSInRHSPart(), S.isFailOnly(),
6526ec727ea7Spatrick S.getBeginLoc());
6527e5dd7070Spatrick }
6528e5dd7070Spatrick
emitCommonOMPTargetDirective(CodeGenFunction & CGF,const OMPExecutableDirective & S,const RegionCodeGenTy & CodeGen)6529e5dd7070Spatrick static void emitCommonOMPTargetDirective(CodeGenFunction &CGF,
6530e5dd7070Spatrick const OMPExecutableDirective &S,
6531e5dd7070Spatrick const RegionCodeGenTy &CodeGen) {
6532e5dd7070Spatrick assert(isOpenMPTargetExecutionDirective(S.getDirectiveKind()));
6533e5dd7070Spatrick CodeGenModule &CGM = CGF.CGM;
6534e5dd7070Spatrick
6535e5dd7070Spatrick // On device emit this construct as inlined code.
6536e5dd7070Spatrick if (CGM.getLangOpts().OpenMPIsDevice) {
6537e5dd7070Spatrick OMPLexicalScope Scope(CGF, S, OMPD_target);
6538e5dd7070Spatrick CGM.getOpenMPRuntime().emitInlinedDirective(
6539e5dd7070Spatrick CGF, OMPD_target, [&S](CodeGenFunction &CGF, PrePostActionTy &) {
6540e5dd7070Spatrick CGF.EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt());
6541e5dd7070Spatrick });
6542e5dd7070Spatrick return;
6543e5dd7070Spatrick }
6544e5dd7070Spatrick
6545*12c85518Srobert auto LPCRegion = CGOpenMPRuntime::LastprivateConditionalRAII::disable(CGF, S);
6546e5dd7070Spatrick llvm::Function *Fn = nullptr;
6547e5dd7070Spatrick llvm::Constant *FnID = nullptr;
6548e5dd7070Spatrick
6549e5dd7070Spatrick const Expr *IfCond = nullptr;
6550e5dd7070Spatrick // Check for the at most one if clause associated with the target region.
6551e5dd7070Spatrick for (const auto *C : S.getClausesOfKind<OMPIfClause>()) {
6552e5dd7070Spatrick if (C->getNameModifier() == OMPD_unknown ||
6553e5dd7070Spatrick C->getNameModifier() == OMPD_target) {
6554e5dd7070Spatrick IfCond = C->getCondition();
6555e5dd7070Spatrick break;
6556e5dd7070Spatrick }
6557e5dd7070Spatrick }
6558e5dd7070Spatrick
6559e5dd7070Spatrick // Check if we have any device clause associated with the directive.
6560ec727ea7Spatrick llvm::PointerIntPair<const Expr *, 2, OpenMPDeviceClauseModifier> Device(
6561ec727ea7Spatrick nullptr, OMPC_DEVICE_unknown);
6562e5dd7070Spatrick if (auto *C = S.getSingleClause<OMPDeviceClause>())
6563ec727ea7Spatrick Device.setPointerAndInt(C->getDevice(), C->getModifier());
6564e5dd7070Spatrick
6565e5dd7070Spatrick // Check if we have an if clause whose conditional always evaluates to false
6566e5dd7070Spatrick // or if we do not have any targets specified. If so the target region is not
6567e5dd7070Spatrick // an offload entry point.
6568e5dd7070Spatrick bool IsOffloadEntry = true;
6569e5dd7070Spatrick if (IfCond) {
6570e5dd7070Spatrick bool Val;
6571e5dd7070Spatrick if (CGF.ConstantFoldsToSimpleInteger(IfCond, Val) && !Val)
6572e5dd7070Spatrick IsOffloadEntry = false;
6573e5dd7070Spatrick }
6574e5dd7070Spatrick if (CGM.getLangOpts().OMPTargetTriples.empty())
6575e5dd7070Spatrick IsOffloadEntry = false;
6576e5dd7070Spatrick
6577*12c85518Srobert if (CGM.getLangOpts().OpenMPOffloadMandatory && !IsOffloadEntry) {
6578*12c85518Srobert unsigned DiagID = CGM.getDiags().getCustomDiagID(
6579*12c85518Srobert DiagnosticsEngine::Error,
6580*12c85518Srobert "No offloading entry generated while offloading is mandatory.");
6581*12c85518Srobert CGM.getDiags().Report(DiagID);
6582*12c85518Srobert }
6583*12c85518Srobert
6584e5dd7070Spatrick assert(CGF.CurFuncDecl && "No parent declaration for target region!");
6585e5dd7070Spatrick StringRef ParentName;
6586e5dd7070Spatrick // In case we have Ctors/Dtors we use the complete type variant to produce
6587e5dd7070Spatrick // the mangling of the device outlined kernel.
6588e5dd7070Spatrick if (const auto *D = dyn_cast<CXXConstructorDecl>(CGF.CurFuncDecl))
6589e5dd7070Spatrick ParentName = CGM.getMangledName(GlobalDecl(D, Ctor_Complete));
6590e5dd7070Spatrick else if (const auto *D = dyn_cast<CXXDestructorDecl>(CGF.CurFuncDecl))
6591e5dd7070Spatrick ParentName = CGM.getMangledName(GlobalDecl(D, Dtor_Complete));
6592e5dd7070Spatrick else
6593e5dd7070Spatrick ParentName =
6594e5dd7070Spatrick CGM.getMangledName(GlobalDecl(cast<FunctionDecl>(CGF.CurFuncDecl)));
6595e5dd7070Spatrick
6596e5dd7070Spatrick // Emit target region as a standalone region.
6597e5dd7070Spatrick CGM.getOpenMPRuntime().emitTargetOutlinedFunction(S, ParentName, Fn, FnID,
6598e5dd7070Spatrick IsOffloadEntry, CodeGen);
6599e5dd7070Spatrick OMPLexicalScope Scope(CGF, S, OMPD_task);
6600e5dd7070Spatrick auto &&SizeEmitter =
6601e5dd7070Spatrick [IsOffloadEntry](CodeGenFunction &CGF,
6602e5dd7070Spatrick const OMPLoopDirective &D) -> llvm::Value * {
6603e5dd7070Spatrick if (IsOffloadEntry) {
6604e5dd7070Spatrick OMPLoopScope(CGF, D);
6605e5dd7070Spatrick // Emit calculation of the iterations count.
6606e5dd7070Spatrick llvm::Value *NumIterations = CGF.EmitScalarExpr(D.getNumIterations());
6607e5dd7070Spatrick NumIterations = CGF.Builder.CreateIntCast(NumIterations, CGF.Int64Ty,
6608e5dd7070Spatrick /*isSigned=*/false);
6609e5dd7070Spatrick return NumIterations;
6610e5dd7070Spatrick }
6611e5dd7070Spatrick return nullptr;
6612e5dd7070Spatrick };
6613e5dd7070Spatrick CGM.getOpenMPRuntime().emitTargetCall(CGF, S, Fn, FnID, IfCond, Device,
6614e5dd7070Spatrick SizeEmitter);
6615e5dd7070Spatrick }
6616e5dd7070Spatrick
emitTargetRegion(CodeGenFunction & CGF,const OMPTargetDirective & S,PrePostActionTy & Action)6617e5dd7070Spatrick static void emitTargetRegion(CodeGenFunction &CGF, const OMPTargetDirective &S,
6618e5dd7070Spatrick PrePostActionTy &Action) {
6619e5dd7070Spatrick Action.Enter(CGF);
6620e5dd7070Spatrick CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
6621e5dd7070Spatrick (void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
6622e5dd7070Spatrick CGF.EmitOMPPrivateClause(S, PrivateScope);
6623e5dd7070Spatrick (void)PrivateScope.Privatize();
6624e5dd7070Spatrick if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()))
6625e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().adjustTargetSpecificDataForLambdas(CGF, S);
6626e5dd7070Spatrick
6627e5dd7070Spatrick CGF.EmitStmt(S.getCapturedStmt(OMPD_target)->getCapturedStmt());
6628a9ac8606Spatrick CGF.EnsureInsertPoint();
6629e5dd7070Spatrick }
6630e5dd7070Spatrick
EmitOMPTargetDeviceFunction(CodeGenModule & CGM,StringRef ParentName,const OMPTargetDirective & S)6631e5dd7070Spatrick void CodeGenFunction::EmitOMPTargetDeviceFunction(CodeGenModule &CGM,
6632e5dd7070Spatrick StringRef ParentName,
6633e5dd7070Spatrick const OMPTargetDirective &S) {
6634e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
6635e5dd7070Spatrick emitTargetRegion(CGF, S, Action);
6636e5dd7070Spatrick };
6637e5dd7070Spatrick llvm::Function *Fn;
6638e5dd7070Spatrick llvm::Constant *Addr;
6639e5dd7070Spatrick // Emit target region as a standalone region.
6640e5dd7070Spatrick CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
6641e5dd7070Spatrick S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
6642e5dd7070Spatrick assert(Fn && Addr && "Target device function emission failed.");
6643e5dd7070Spatrick }
6644e5dd7070Spatrick
EmitOMPTargetDirective(const OMPTargetDirective & S)6645e5dd7070Spatrick void CodeGenFunction::EmitOMPTargetDirective(const OMPTargetDirective &S) {
6646e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
6647e5dd7070Spatrick emitTargetRegion(CGF, S, Action);
6648e5dd7070Spatrick };
6649e5dd7070Spatrick emitCommonOMPTargetDirective(*this, S, CodeGen);
6650e5dd7070Spatrick }
6651e5dd7070Spatrick
emitCommonOMPTeamsDirective(CodeGenFunction & CGF,const OMPExecutableDirective & S,OpenMPDirectiveKind InnermostKind,const RegionCodeGenTy & CodeGen)6652e5dd7070Spatrick static void emitCommonOMPTeamsDirective(CodeGenFunction &CGF,
6653e5dd7070Spatrick const OMPExecutableDirective &S,
6654e5dd7070Spatrick OpenMPDirectiveKind InnermostKind,
6655e5dd7070Spatrick const RegionCodeGenTy &CodeGen) {
6656e5dd7070Spatrick const CapturedStmt *CS = S.getCapturedStmt(OMPD_teams);
6657e5dd7070Spatrick llvm::Function *OutlinedFn =
6658e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitTeamsOutlinedFunction(
6659e5dd7070Spatrick S, *CS->getCapturedDecl()->param_begin(), InnermostKind, CodeGen);
6660e5dd7070Spatrick
6661e5dd7070Spatrick const auto *NT = S.getSingleClause<OMPNumTeamsClause>();
6662e5dd7070Spatrick const auto *TL = S.getSingleClause<OMPThreadLimitClause>();
6663e5dd7070Spatrick if (NT || TL) {
6664e5dd7070Spatrick const Expr *NumTeams = NT ? NT->getNumTeams() : nullptr;
6665e5dd7070Spatrick const Expr *ThreadLimit = TL ? TL->getThreadLimit() : nullptr;
6666e5dd7070Spatrick
6667e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitNumTeamsClause(CGF, NumTeams, ThreadLimit,
6668e5dd7070Spatrick S.getBeginLoc());
6669e5dd7070Spatrick }
6670e5dd7070Spatrick
6671e5dd7070Spatrick OMPTeamsScope Scope(CGF, S);
6672e5dd7070Spatrick llvm::SmallVector<llvm::Value *, 16> CapturedVars;
6673e5dd7070Spatrick CGF.GenerateOpenMPCapturedVars(*CS, CapturedVars);
6674e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitTeamsCall(CGF, S, S.getBeginLoc(), OutlinedFn,
6675e5dd7070Spatrick CapturedVars);
6676e5dd7070Spatrick }
6677e5dd7070Spatrick
EmitOMPTeamsDirective(const OMPTeamsDirective & S)6678e5dd7070Spatrick void CodeGenFunction::EmitOMPTeamsDirective(const OMPTeamsDirective &S) {
6679e5dd7070Spatrick // Emit teams region as a standalone region.
6680e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
6681e5dd7070Spatrick Action.Enter(CGF);
6682e5dd7070Spatrick OMPPrivateScope PrivateScope(CGF);
6683e5dd7070Spatrick (void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
6684e5dd7070Spatrick CGF.EmitOMPPrivateClause(S, PrivateScope);
6685e5dd7070Spatrick CGF.EmitOMPReductionClauseInit(S, PrivateScope);
6686e5dd7070Spatrick (void)PrivateScope.Privatize();
6687e5dd7070Spatrick CGF.EmitStmt(S.getCapturedStmt(OMPD_teams)->getCapturedStmt());
6688e5dd7070Spatrick CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
6689e5dd7070Spatrick };
6690e5dd7070Spatrick emitCommonOMPTeamsDirective(*this, S, OMPD_distribute, CodeGen);
6691e5dd7070Spatrick emitPostUpdateForReductionClause(*this, S,
6692e5dd7070Spatrick [](CodeGenFunction &) { return nullptr; });
6693e5dd7070Spatrick }
6694e5dd7070Spatrick
emitTargetTeamsRegion(CodeGenFunction & CGF,PrePostActionTy & Action,const OMPTargetTeamsDirective & S)6695e5dd7070Spatrick static void emitTargetTeamsRegion(CodeGenFunction &CGF, PrePostActionTy &Action,
6696e5dd7070Spatrick const OMPTargetTeamsDirective &S) {
6697e5dd7070Spatrick auto *CS = S.getCapturedStmt(OMPD_teams);
6698e5dd7070Spatrick Action.Enter(CGF);
6699e5dd7070Spatrick // Emit teams region as a standalone region.
6700e5dd7070Spatrick auto &&CodeGen = [&S, CS](CodeGenFunction &CGF, PrePostActionTy &Action) {
6701e5dd7070Spatrick Action.Enter(CGF);
6702e5dd7070Spatrick CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
6703e5dd7070Spatrick (void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
6704e5dd7070Spatrick CGF.EmitOMPPrivateClause(S, PrivateScope);
6705e5dd7070Spatrick CGF.EmitOMPReductionClauseInit(S, PrivateScope);
6706e5dd7070Spatrick (void)PrivateScope.Privatize();
6707e5dd7070Spatrick if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()))
6708e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().adjustTargetSpecificDataForLambdas(CGF, S);
6709e5dd7070Spatrick CGF.EmitStmt(CS->getCapturedStmt());
6710e5dd7070Spatrick CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
6711e5dd7070Spatrick };
6712e5dd7070Spatrick emitCommonOMPTeamsDirective(CGF, S, OMPD_teams, CodeGen);
6713e5dd7070Spatrick emitPostUpdateForReductionClause(CGF, S,
6714e5dd7070Spatrick [](CodeGenFunction &) { return nullptr; });
6715e5dd7070Spatrick }
6716e5dd7070Spatrick
EmitOMPTargetTeamsDeviceFunction(CodeGenModule & CGM,StringRef ParentName,const OMPTargetTeamsDirective & S)6717e5dd7070Spatrick void CodeGenFunction::EmitOMPTargetTeamsDeviceFunction(
6718e5dd7070Spatrick CodeGenModule &CGM, StringRef ParentName,
6719e5dd7070Spatrick const OMPTargetTeamsDirective &S) {
6720e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
6721e5dd7070Spatrick emitTargetTeamsRegion(CGF, Action, S);
6722e5dd7070Spatrick };
6723e5dd7070Spatrick llvm::Function *Fn;
6724e5dd7070Spatrick llvm::Constant *Addr;
6725e5dd7070Spatrick // Emit target region as a standalone region.
6726e5dd7070Spatrick CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
6727e5dd7070Spatrick S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
6728e5dd7070Spatrick assert(Fn && Addr && "Target device function emission failed.");
6729e5dd7070Spatrick }
6730e5dd7070Spatrick
EmitOMPTargetTeamsDirective(const OMPTargetTeamsDirective & S)6731e5dd7070Spatrick void CodeGenFunction::EmitOMPTargetTeamsDirective(
6732e5dd7070Spatrick const OMPTargetTeamsDirective &S) {
6733e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
6734e5dd7070Spatrick emitTargetTeamsRegion(CGF, Action, S);
6735e5dd7070Spatrick };
6736e5dd7070Spatrick emitCommonOMPTargetDirective(*this, S, CodeGen);
6737e5dd7070Spatrick }
6738e5dd7070Spatrick
6739e5dd7070Spatrick static void
emitTargetTeamsDistributeRegion(CodeGenFunction & CGF,PrePostActionTy & Action,const OMPTargetTeamsDistributeDirective & S)6740e5dd7070Spatrick emitTargetTeamsDistributeRegion(CodeGenFunction &CGF, PrePostActionTy &Action,
6741e5dd7070Spatrick const OMPTargetTeamsDistributeDirective &S) {
6742e5dd7070Spatrick Action.Enter(CGF);
6743e5dd7070Spatrick auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
6744e5dd7070Spatrick CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc());
6745e5dd7070Spatrick };
6746e5dd7070Spatrick
6747e5dd7070Spatrick // Emit teams region as a standalone region.
6748e5dd7070Spatrick auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
6749e5dd7070Spatrick PrePostActionTy &Action) {
6750e5dd7070Spatrick Action.Enter(CGF);
6751e5dd7070Spatrick CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
6752e5dd7070Spatrick CGF.EmitOMPReductionClauseInit(S, PrivateScope);
6753e5dd7070Spatrick (void)PrivateScope.Privatize();
6754e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_distribute,
6755e5dd7070Spatrick CodeGenDistribute);
6756e5dd7070Spatrick CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
6757e5dd7070Spatrick };
6758e5dd7070Spatrick emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute, CodeGen);
6759e5dd7070Spatrick emitPostUpdateForReductionClause(CGF, S,
6760e5dd7070Spatrick [](CodeGenFunction &) { return nullptr; });
6761e5dd7070Spatrick }
6762e5dd7070Spatrick
EmitOMPTargetTeamsDistributeDeviceFunction(CodeGenModule & CGM,StringRef ParentName,const OMPTargetTeamsDistributeDirective & S)6763e5dd7070Spatrick void CodeGenFunction::EmitOMPTargetTeamsDistributeDeviceFunction(
6764e5dd7070Spatrick CodeGenModule &CGM, StringRef ParentName,
6765e5dd7070Spatrick const OMPTargetTeamsDistributeDirective &S) {
6766e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
6767e5dd7070Spatrick emitTargetTeamsDistributeRegion(CGF, Action, S);
6768e5dd7070Spatrick };
6769e5dd7070Spatrick llvm::Function *Fn;
6770e5dd7070Spatrick llvm::Constant *Addr;
6771e5dd7070Spatrick // Emit target region as a standalone region.
6772e5dd7070Spatrick CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
6773e5dd7070Spatrick S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
6774e5dd7070Spatrick assert(Fn && Addr && "Target device function emission failed.");
6775e5dd7070Spatrick }
6776e5dd7070Spatrick
EmitOMPTargetTeamsDistributeDirective(const OMPTargetTeamsDistributeDirective & S)6777e5dd7070Spatrick void CodeGenFunction::EmitOMPTargetTeamsDistributeDirective(
6778e5dd7070Spatrick const OMPTargetTeamsDistributeDirective &S) {
6779e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
6780e5dd7070Spatrick emitTargetTeamsDistributeRegion(CGF, Action, S);
6781e5dd7070Spatrick };
6782e5dd7070Spatrick emitCommonOMPTargetDirective(*this, S, CodeGen);
6783e5dd7070Spatrick }
6784e5dd7070Spatrick
emitTargetTeamsDistributeSimdRegion(CodeGenFunction & CGF,PrePostActionTy & Action,const OMPTargetTeamsDistributeSimdDirective & S)6785e5dd7070Spatrick static void emitTargetTeamsDistributeSimdRegion(
6786e5dd7070Spatrick CodeGenFunction &CGF, PrePostActionTy &Action,
6787e5dd7070Spatrick const OMPTargetTeamsDistributeSimdDirective &S) {
6788e5dd7070Spatrick Action.Enter(CGF);
6789e5dd7070Spatrick auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
6790e5dd7070Spatrick CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc());
6791e5dd7070Spatrick };
6792e5dd7070Spatrick
6793e5dd7070Spatrick // Emit teams region as a standalone region.
6794e5dd7070Spatrick auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
6795e5dd7070Spatrick PrePostActionTy &Action) {
6796e5dd7070Spatrick Action.Enter(CGF);
6797e5dd7070Spatrick CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
6798e5dd7070Spatrick CGF.EmitOMPReductionClauseInit(S, PrivateScope);
6799e5dd7070Spatrick (void)PrivateScope.Privatize();
6800e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_distribute,
6801e5dd7070Spatrick CodeGenDistribute);
6802e5dd7070Spatrick CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
6803e5dd7070Spatrick };
6804e5dd7070Spatrick emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute_simd, CodeGen);
6805e5dd7070Spatrick emitPostUpdateForReductionClause(CGF, S,
6806e5dd7070Spatrick [](CodeGenFunction &) { return nullptr; });
6807e5dd7070Spatrick }
6808e5dd7070Spatrick
EmitOMPTargetTeamsDistributeSimdDeviceFunction(CodeGenModule & CGM,StringRef ParentName,const OMPTargetTeamsDistributeSimdDirective & S)6809e5dd7070Spatrick void CodeGenFunction::EmitOMPTargetTeamsDistributeSimdDeviceFunction(
6810e5dd7070Spatrick CodeGenModule &CGM, StringRef ParentName,
6811e5dd7070Spatrick const OMPTargetTeamsDistributeSimdDirective &S) {
6812e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
6813e5dd7070Spatrick emitTargetTeamsDistributeSimdRegion(CGF, Action, S);
6814e5dd7070Spatrick };
6815e5dd7070Spatrick llvm::Function *Fn;
6816e5dd7070Spatrick llvm::Constant *Addr;
6817e5dd7070Spatrick // Emit target region as a standalone region.
6818e5dd7070Spatrick CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
6819e5dd7070Spatrick S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
6820e5dd7070Spatrick assert(Fn && Addr && "Target device function emission failed.");
6821e5dd7070Spatrick }
6822e5dd7070Spatrick
EmitOMPTargetTeamsDistributeSimdDirective(const OMPTargetTeamsDistributeSimdDirective & S)6823e5dd7070Spatrick void CodeGenFunction::EmitOMPTargetTeamsDistributeSimdDirective(
6824e5dd7070Spatrick const OMPTargetTeamsDistributeSimdDirective &S) {
6825e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
6826e5dd7070Spatrick emitTargetTeamsDistributeSimdRegion(CGF, Action, S);
6827e5dd7070Spatrick };
6828e5dd7070Spatrick emitCommonOMPTargetDirective(*this, S, CodeGen);
6829e5dd7070Spatrick }
6830e5dd7070Spatrick
EmitOMPTeamsDistributeDirective(const OMPTeamsDistributeDirective & S)6831e5dd7070Spatrick void CodeGenFunction::EmitOMPTeamsDistributeDirective(
6832e5dd7070Spatrick const OMPTeamsDistributeDirective &S) {
6833e5dd7070Spatrick
6834e5dd7070Spatrick auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
6835e5dd7070Spatrick CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc());
6836e5dd7070Spatrick };
6837e5dd7070Spatrick
6838e5dd7070Spatrick // Emit teams region as a standalone region.
6839e5dd7070Spatrick auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
6840e5dd7070Spatrick PrePostActionTy &Action) {
6841e5dd7070Spatrick Action.Enter(CGF);
6842e5dd7070Spatrick OMPPrivateScope PrivateScope(CGF);
6843e5dd7070Spatrick CGF.EmitOMPReductionClauseInit(S, PrivateScope);
6844e5dd7070Spatrick (void)PrivateScope.Privatize();
6845e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_distribute,
6846e5dd7070Spatrick CodeGenDistribute);
6847e5dd7070Spatrick CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
6848e5dd7070Spatrick };
6849e5dd7070Spatrick emitCommonOMPTeamsDirective(*this, S, OMPD_distribute, CodeGen);
6850e5dd7070Spatrick emitPostUpdateForReductionClause(*this, S,
6851e5dd7070Spatrick [](CodeGenFunction &) { return nullptr; });
6852e5dd7070Spatrick }
6853e5dd7070Spatrick
EmitOMPTeamsDistributeSimdDirective(const OMPTeamsDistributeSimdDirective & S)6854e5dd7070Spatrick void CodeGenFunction::EmitOMPTeamsDistributeSimdDirective(
6855e5dd7070Spatrick const OMPTeamsDistributeSimdDirective &S) {
6856e5dd7070Spatrick auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
6857e5dd7070Spatrick CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc());
6858e5dd7070Spatrick };
6859e5dd7070Spatrick
6860e5dd7070Spatrick // Emit teams region as a standalone region.
6861e5dd7070Spatrick auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
6862e5dd7070Spatrick PrePostActionTy &Action) {
6863e5dd7070Spatrick Action.Enter(CGF);
6864e5dd7070Spatrick OMPPrivateScope PrivateScope(CGF);
6865e5dd7070Spatrick CGF.EmitOMPReductionClauseInit(S, PrivateScope);
6866e5dd7070Spatrick (void)PrivateScope.Privatize();
6867e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_simd,
6868e5dd7070Spatrick CodeGenDistribute);
6869e5dd7070Spatrick CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
6870e5dd7070Spatrick };
6871e5dd7070Spatrick emitCommonOMPTeamsDirective(*this, S, OMPD_distribute_simd, CodeGen);
6872e5dd7070Spatrick emitPostUpdateForReductionClause(*this, S,
6873e5dd7070Spatrick [](CodeGenFunction &) { return nullptr; });
6874e5dd7070Spatrick }
6875e5dd7070Spatrick
EmitOMPTeamsDistributeParallelForDirective(const OMPTeamsDistributeParallelForDirective & S)6876e5dd7070Spatrick void CodeGenFunction::EmitOMPTeamsDistributeParallelForDirective(
6877e5dd7070Spatrick const OMPTeamsDistributeParallelForDirective &S) {
6878e5dd7070Spatrick auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
6879e5dd7070Spatrick CGF.EmitOMPDistributeLoop(S, emitInnerParallelForWhenCombined,
6880e5dd7070Spatrick S.getDistInc());
6881e5dd7070Spatrick };
6882e5dd7070Spatrick
6883e5dd7070Spatrick // Emit teams region as a standalone region.
6884e5dd7070Spatrick auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
6885e5dd7070Spatrick PrePostActionTy &Action) {
6886e5dd7070Spatrick Action.Enter(CGF);
6887e5dd7070Spatrick OMPPrivateScope PrivateScope(CGF);
6888e5dd7070Spatrick CGF.EmitOMPReductionClauseInit(S, PrivateScope);
6889e5dd7070Spatrick (void)PrivateScope.Privatize();
6890e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_distribute,
6891e5dd7070Spatrick CodeGenDistribute);
6892e5dd7070Spatrick CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
6893e5dd7070Spatrick };
6894e5dd7070Spatrick emitCommonOMPTeamsDirective(*this, S, OMPD_distribute_parallel_for, CodeGen);
6895e5dd7070Spatrick emitPostUpdateForReductionClause(*this, S,
6896e5dd7070Spatrick [](CodeGenFunction &) { return nullptr; });
6897e5dd7070Spatrick }
6898e5dd7070Spatrick
EmitOMPTeamsDistributeParallelForSimdDirective(const OMPTeamsDistributeParallelForSimdDirective & S)6899e5dd7070Spatrick void CodeGenFunction::EmitOMPTeamsDistributeParallelForSimdDirective(
6900e5dd7070Spatrick const OMPTeamsDistributeParallelForSimdDirective &S) {
6901e5dd7070Spatrick auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
6902e5dd7070Spatrick CGF.EmitOMPDistributeLoop(S, emitInnerParallelForWhenCombined,
6903e5dd7070Spatrick S.getDistInc());
6904e5dd7070Spatrick };
6905e5dd7070Spatrick
6906e5dd7070Spatrick // Emit teams region as a standalone region.
6907e5dd7070Spatrick auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
6908e5dd7070Spatrick PrePostActionTy &Action) {
6909e5dd7070Spatrick Action.Enter(CGF);
6910e5dd7070Spatrick OMPPrivateScope PrivateScope(CGF);
6911e5dd7070Spatrick CGF.EmitOMPReductionClauseInit(S, PrivateScope);
6912e5dd7070Spatrick (void)PrivateScope.Privatize();
6913e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitInlinedDirective(
6914e5dd7070Spatrick CGF, OMPD_distribute, CodeGenDistribute, /*HasCancel=*/false);
6915e5dd7070Spatrick CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
6916e5dd7070Spatrick };
6917e5dd7070Spatrick emitCommonOMPTeamsDirective(*this, S, OMPD_distribute_parallel_for_simd,
6918e5dd7070Spatrick CodeGen);
6919e5dd7070Spatrick emitPostUpdateForReductionClause(*this, S,
6920e5dd7070Spatrick [](CodeGenFunction &) { return nullptr; });
6921e5dd7070Spatrick }
6922e5dd7070Spatrick
EmitOMPInteropDirective(const OMPInteropDirective & S)6923*12c85518Srobert void CodeGenFunction::EmitOMPInteropDirective(const OMPInteropDirective &S) {
6924*12c85518Srobert llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
6925*12c85518Srobert llvm::Value *Device = nullptr;
6926*12c85518Srobert if (const auto *C = S.getSingleClause<OMPDeviceClause>())
6927*12c85518Srobert Device = EmitScalarExpr(C->getDevice());
6928*12c85518Srobert
6929*12c85518Srobert llvm::Value *NumDependences = nullptr;
6930*12c85518Srobert llvm::Value *DependenceAddress = nullptr;
6931*12c85518Srobert if (const auto *DC = S.getSingleClause<OMPDependClause>()) {
6932*12c85518Srobert OMPTaskDataTy::DependData Dependencies(DC->getDependencyKind(),
6933*12c85518Srobert DC->getModifier());
6934*12c85518Srobert Dependencies.DepExprs.append(DC->varlist_begin(), DC->varlist_end());
6935*12c85518Srobert std::pair<llvm::Value *, Address> DependencePair =
6936*12c85518Srobert CGM.getOpenMPRuntime().emitDependClause(*this, Dependencies,
6937*12c85518Srobert DC->getBeginLoc());
6938*12c85518Srobert NumDependences = DependencePair.first;
6939*12c85518Srobert DependenceAddress = Builder.CreatePointerCast(
6940*12c85518Srobert DependencePair.second.getPointer(), CGM.Int8PtrTy);
6941*12c85518Srobert }
6942*12c85518Srobert
6943*12c85518Srobert assert(!(S.hasClausesOfKind<OMPNowaitClause>() &&
6944*12c85518Srobert !(S.getSingleClause<OMPInitClause>() ||
6945*12c85518Srobert S.getSingleClause<OMPDestroyClause>() ||
6946*12c85518Srobert S.getSingleClause<OMPUseClause>())) &&
6947*12c85518Srobert "OMPNowaitClause clause is used separately in OMPInteropDirective.");
6948*12c85518Srobert
6949*12c85518Srobert if (const auto *C = S.getSingleClause<OMPInitClause>()) {
6950*12c85518Srobert llvm::Value *InteropvarPtr =
6951*12c85518Srobert EmitLValue(C->getInteropVar()).getPointer(*this);
6952*12c85518Srobert llvm::omp::OMPInteropType InteropType = llvm::omp::OMPInteropType::Unknown;
6953*12c85518Srobert if (C->getIsTarget()) {
6954*12c85518Srobert InteropType = llvm::omp::OMPInteropType::Target;
6955*12c85518Srobert } else {
6956*12c85518Srobert assert(C->getIsTargetSync() && "Expected interop-type target/targetsync");
6957*12c85518Srobert InteropType = llvm::omp::OMPInteropType::TargetSync;
6958*12c85518Srobert }
6959*12c85518Srobert OMPBuilder.createOMPInteropInit(Builder, InteropvarPtr, InteropType, Device,
6960*12c85518Srobert NumDependences, DependenceAddress,
6961*12c85518Srobert S.hasClausesOfKind<OMPNowaitClause>());
6962*12c85518Srobert } else if (const auto *C = S.getSingleClause<OMPDestroyClause>()) {
6963*12c85518Srobert llvm::Value *InteropvarPtr =
6964*12c85518Srobert EmitLValue(C->getInteropVar()).getPointer(*this);
6965*12c85518Srobert OMPBuilder.createOMPInteropDestroy(Builder, InteropvarPtr, Device,
6966*12c85518Srobert NumDependences, DependenceAddress,
6967*12c85518Srobert S.hasClausesOfKind<OMPNowaitClause>());
6968*12c85518Srobert } else if (const auto *C = S.getSingleClause<OMPUseClause>()) {
6969*12c85518Srobert llvm::Value *InteropvarPtr =
6970*12c85518Srobert EmitLValue(C->getInteropVar()).getPointer(*this);
6971*12c85518Srobert OMPBuilder.createOMPInteropUse(Builder, InteropvarPtr, Device,
6972*12c85518Srobert NumDependences, DependenceAddress,
6973*12c85518Srobert S.hasClausesOfKind<OMPNowaitClause>());
6974*12c85518Srobert }
6975*12c85518Srobert }
6976*12c85518Srobert
emitTargetTeamsDistributeParallelForRegion(CodeGenFunction & CGF,const OMPTargetTeamsDistributeParallelForDirective & S,PrePostActionTy & Action)6977e5dd7070Spatrick static void emitTargetTeamsDistributeParallelForRegion(
6978e5dd7070Spatrick CodeGenFunction &CGF, const OMPTargetTeamsDistributeParallelForDirective &S,
6979e5dd7070Spatrick PrePostActionTy &Action) {
6980e5dd7070Spatrick Action.Enter(CGF);
6981e5dd7070Spatrick auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
6982e5dd7070Spatrick CGF.EmitOMPDistributeLoop(S, emitInnerParallelForWhenCombined,
6983e5dd7070Spatrick S.getDistInc());
6984e5dd7070Spatrick };
6985e5dd7070Spatrick
6986e5dd7070Spatrick // Emit teams region as a standalone region.
6987e5dd7070Spatrick auto &&CodeGenTeams = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
6988e5dd7070Spatrick PrePostActionTy &Action) {
6989e5dd7070Spatrick Action.Enter(CGF);
6990e5dd7070Spatrick CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
6991e5dd7070Spatrick CGF.EmitOMPReductionClauseInit(S, PrivateScope);
6992e5dd7070Spatrick (void)PrivateScope.Privatize();
6993e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitInlinedDirective(
6994e5dd7070Spatrick CGF, OMPD_distribute, CodeGenDistribute, /*HasCancel=*/false);
6995e5dd7070Spatrick CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
6996e5dd7070Spatrick };
6997e5dd7070Spatrick
6998e5dd7070Spatrick emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute_parallel_for,
6999e5dd7070Spatrick CodeGenTeams);
7000e5dd7070Spatrick emitPostUpdateForReductionClause(CGF, S,
7001e5dd7070Spatrick [](CodeGenFunction &) { return nullptr; });
7002e5dd7070Spatrick }
7003e5dd7070Spatrick
EmitOMPTargetTeamsDistributeParallelForDeviceFunction(CodeGenModule & CGM,StringRef ParentName,const OMPTargetTeamsDistributeParallelForDirective & S)7004e5dd7070Spatrick void CodeGenFunction::EmitOMPTargetTeamsDistributeParallelForDeviceFunction(
7005e5dd7070Spatrick CodeGenModule &CGM, StringRef ParentName,
7006e5dd7070Spatrick const OMPTargetTeamsDistributeParallelForDirective &S) {
7007e5dd7070Spatrick // Emit SPMD target teams distribute parallel for region as a standalone
7008e5dd7070Spatrick // region.
7009e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7010e5dd7070Spatrick emitTargetTeamsDistributeParallelForRegion(CGF, S, Action);
7011e5dd7070Spatrick };
7012e5dd7070Spatrick llvm::Function *Fn;
7013e5dd7070Spatrick llvm::Constant *Addr;
7014e5dd7070Spatrick // Emit target region as a standalone region.
7015e5dd7070Spatrick CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
7016e5dd7070Spatrick S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
7017e5dd7070Spatrick assert(Fn && Addr && "Target device function emission failed.");
7018e5dd7070Spatrick }
7019e5dd7070Spatrick
EmitOMPTargetTeamsDistributeParallelForDirective(const OMPTargetTeamsDistributeParallelForDirective & S)7020e5dd7070Spatrick void CodeGenFunction::EmitOMPTargetTeamsDistributeParallelForDirective(
7021e5dd7070Spatrick const OMPTargetTeamsDistributeParallelForDirective &S) {
7022e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7023e5dd7070Spatrick emitTargetTeamsDistributeParallelForRegion(CGF, S, Action);
7024e5dd7070Spatrick };
7025e5dd7070Spatrick emitCommonOMPTargetDirective(*this, S, CodeGen);
7026e5dd7070Spatrick }
7027e5dd7070Spatrick
emitTargetTeamsDistributeParallelForSimdRegion(CodeGenFunction & CGF,const OMPTargetTeamsDistributeParallelForSimdDirective & S,PrePostActionTy & Action)7028e5dd7070Spatrick static void emitTargetTeamsDistributeParallelForSimdRegion(
7029e5dd7070Spatrick CodeGenFunction &CGF,
7030e5dd7070Spatrick const OMPTargetTeamsDistributeParallelForSimdDirective &S,
7031e5dd7070Spatrick PrePostActionTy &Action) {
7032e5dd7070Spatrick Action.Enter(CGF);
7033e5dd7070Spatrick auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
7034e5dd7070Spatrick CGF.EmitOMPDistributeLoop(S, emitInnerParallelForWhenCombined,
7035e5dd7070Spatrick S.getDistInc());
7036e5dd7070Spatrick };
7037e5dd7070Spatrick
7038e5dd7070Spatrick // Emit teams region as a standalone region.
7039e5dd7070Spatrick auto &&CodeGenTeams = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
7040e5dd7070Spatrick PrePostActionTy &Action) {
7041e5dd7070Spatrick Action.Enter(CGF);
7042e5dd7070Spatrick CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
7043e5dd7070Spatrick CGF.EmitOMPReductionClauseInit(S, PrivateScope);
7044e5dd7070Spatrick (void)PrivateScope.Privatize();
7045e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitInlinedDirective(
7046e5dd7070Spatrick CGF, OMPD_distribute, CodeGenDistribute, /*HasCancel=*/false);
7047e5dd7070Spatrick CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
7048e5dd7070Spatrick };
7049e5dd7070Spatrick
7050e5dd7070Spatrick emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute_parallel_for_simd,
7051e5dd7070Spatrick CodeGenTeams);
7052e5dd7070Spatrick emitPostUpdateForReductionClause(CGF, S,
7053e5dd7070Spatrick [](CodeGenFunction &) { return nullptr; });
7054e5dd7070Spatrick }
7055e5dd7070Spatrick
EmitOMPTargetTeamsDistributeParallelForSimdDeviceFunction(CodeGenModule & CGM,StringRef ParentName,const OMPTargetTeamsDistributeParallelForSimdDirective & S)7056e5dd7070Spatrick void CodeGenFunction::EmitOMPTargetTeamsDistributeParallelForSimdDeviceFunction(
7057e5dd7070Spatrick CodeGenModule &CGM, StringRef ParentName,
7058e5dd7070Spatrick const OMPTargetTeamsDistributeParallelForSimdDirective &S) {
7059e5dd7070Spatrick // Emit SPMD target teams distribute parallel for simd region as a standalone
7060e5dd7070Spatrick // region.
7061e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7062e5dd7070Spatrick emitTargetTeamsDistributeParallelForSimdRegion(CGF, S, Action);
7063e5dd7070Spatrick };
7064e5dd7070Spatrick llvm::Function *Fn;
7065e5dd7070Spatrick llvm::Constant *Addr;
7066e5dd7070Spatrick // Emit target region as a standalone region.
7067e5dd7070Spatrick CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
7068e5dd7070Spatrick S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
7069e5dd7070Spatrick assert(Fn && Addr && "Target device function emission failed.");
7070e5dd7070Spatrick }
7071e5dd7070Spatrick
EmitOMPTargetTeamsDistributeParallelForSimdDirective(const OMPTargetTeamsDistributeParallelForSimdDirective & S)7072e5dd7070Spatrick void CodeGenFunction::EmitOMPTargetTeamsDistributeParallelForSimdDirective(
7073e5dd7070Spatrick const OMPTargetTeamsDistributeParallelForSimdDirective &S) {
7074e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7075e5dd7070Spatrick emitTargetTeamsDistributeParallelForSimdRegion(CGF, S, Action);
7076e5dd7070Spatrick };
7077e5dd7070Spatrick emitCommonOMPTargetDirective(*this, S, CodeGen);
7078e5dd7070Spatrick }
7079e5dd7070Spatrick
EmitOMPCancellationPointDirective(const OMPCancellationPointDirective & S)7080e5dd7070Spatrick void CodeGenFunction::EmitOMPCancellationPointDirective(
7081e5dd7070Spatrick const OMPCancellationPointDirective &S) {
7082e5dd7070Spatrick CGM.getOpenMPRuntime().emitCancellationPointCall(*this, S.getBeginLoc(),
7083e5dd7070Spatrick S.getCancelRegion());
7084e5dd7070Spatrick }
7085e5dd7070Spatrick
EmitOMPCancelDirective(const OMPCancelDirective & S)7086e5dd7070Spatrick void CodeGenFunction::EmitOMPCancelDirective(const OMPCancelDirective &S) {
7087e5dd7070Spatrick const Expr *IfCond = nullptr;
7088e5dd7070Spatrick for (const auto *C : S.getClausesOfKind<OMPIfClause>()) {
7089e5dd7070Spatrick if (C->getNameModifier() == OMPD_unknown ||
7090e5dd7070Spatrick C->getNameModifier() == OMPD_cancel) {
7091e5dd7070Spatrick IfCond = C->getCondition();
7092e5dd7070Spatrick break;
7093e5dd7070Spatrick }
7094e5dd7070Spatrick }
7095ec727ea7Spatrick if (CGM.getLangOpts().OpenMPIRBuilder) {
7096ec727ea7Spatrick llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
7097e5dd7070Spatrick // TODO: This check is necessary as we only generate `omp parallel` through
7098e5dd7070Spatrick // the OpenMPIRBuilder for now.
7099a9ac8606Spatrick if (S.getCancelRegion() == OMPD_parallel ||
7100a9ac8606Spatrick S.getCancelRegion() == OMPD_sections ||
7101a9ac8606Spatrick S.getCancelRegion() == OMPD_section) {
7102e5dd7070Spatrick llvm::Value *IfCondition = nullptr;
7103e5dd7070Spatrick if (IfCond)
7104e5dd7070Spatrick IfCondition = EmitScalarExpr(IfCond,
7105e5dd7070Spatrick /*IgnoreResultAssign=*/true);
7106e5dd7070Spatrick return Builder.restoreIP(
7107a9ac8606Spatrick OMPBuilder.createCancel(Builder, IfCondition, S.getCancelRegion()));
7108e5dd7070Spatrick }
7109e5dd7070Spatrick }
7110e5dd7070Spatrick
7111e5dd7070Spatrick CGM.getOpenMPRuntime().emitCancelCall(*this, S.getBeginLoc(), IfCond,
7112e5dd7070Spatrick S.getCancelRegion());
7113e5dd7070Spatrick }
7114e5dd7070Spatrick
7115e5dd7070Spatrick CodeGenFunction::JumpDest
getOMPCancelDestination(OpenMPDirectiveKind Kind)7116e5dd7070Spatrick CodeGenFunction::getOMPCancelDestination(OpenMPDirectiveKind Kind) {
7117e5dd7070Spatrick if (Kind == OMPD_parallel || Kind == OMPD_task ||
7118ec727ea7Spatrick Kind == OMPD_target_parallel || Kind == OMPD_taskloop ||
7119ec727ea7Spatrick Kind == OMPD_master_taskloop || Kind == OMPD_parallel_master_taskloop)
7120e5dd7070Spatrick return ReturnBlock;
7121e5dd7070Spatrick assert(Kind == OMPD_for || Kind == OMPD_section || Kind == OMPD_sections ||
7122e5dd7070Spatrick Kind == OMPD_parallel_sections || Kind == OMPD_parallel_for ||
7123e5dd7070Spatrick Kind == OMPD_distribute_parallel_for ||
7124e5dd7070Spatrick Kind == OMPD_target_parallel_for ||
7125e5dd7070Spatrick Kind == OMPD_teams_distribute_parallel_for ||
7126e5dd7070Spatrick Kind == OMPD_target_teams_distribute_parallel_for);
7127e5dd7070Spatrick return OMPCancelStack.getExitBlock();
7128e5dd7070Spatrick }
7129e5dd7070Spatrick
EmitOMPUseDevicePtrClause(const OMPUseDevicePtrClause & C,OMPPrivateScope & PrivateScope,const llvm::DenseMap<const ValueDecl *,Address> & CaptureDeviceAddrMap)7130e5dd7070Spatrick void CodeGenFunction::EmitOMPUseDevicePtrClause(
7131ec727ea7Spatrick const OMPUseDevicePtrClause &C, OMPPrivateScope &PrivateScope,
7132e5dd7070Spatrick const llvm::DenseMap<const ValueDecl *, Address> &CaptureDeviceAddrMap) {
7133e5dd7070Spatrick auto OrigVarIt = C.varlist_begin();
7134e5dd7070Spatrick auto InitIt = C.inits().begin();
7135e5dd7070Spatrick for (const Expr *PvtVarIt : C.private_copies()) {
7136*12c85518Srobert const auto *OrigVD =
7137*12c85518Srobert cast<VarDecl>(cast<DeclRefExpr>(*OrigVarIt)->getDecl());
7138e5dd7070Spatrick const auto *InitVD = cast<VarDecl>(cast<DeclRefExpr>(*InitIt)->getDecl());
7139e5dd7070Spatrick const auto *PvtVD = cast<VarDecl>(cast<DeclRefExpr>(PvtVarIt)->getDecl());
7140e5dd7070Spatrick
7141e5dd7070Spatrick // In order to identify the right initializer we need to match the
7142e5dd7070Spatrick // declaration used by the mapping logic. In some cases we may get
7143e5dd7070Spatrick // OMPCapturedExprDecl that refers to the original declaration.
7144e5dd7070Spatrick const ValueDecl *MatchingVD = OrigVD;
7145e5dd7070Spatrick if (const auto *OED = dyn_cast<OMPCapturedExprDecl>(MatchingVD)) {
7146e5dd7070Spatrick // OMPCapturedExprDecl are used to privative fields of the current
7147e5dd7070Spatrick // structure.
7148e5dd7070Spatrick const auto *ME = cast<MemberExpr>(OED->getInit());
7149e5dd7070Spatrick assert(isa<CXXThisExpr>(ME->getBase()) &&
7150e5dd7070Spatrick "Base should be the current struct!");
7151e5dd7070Spatrick MatchingVD = ME->getMemberDecl();
7152e5dd7070Spatrick }
7153e5dd7070Spatrick
7154e5dd7070Spatrick // If we don't have information about the current list item, move on to
7155e5dd7070Spatrick // the next one.
7156e5dd7070Spatrick auto InitAddrIt = CaptureDeviceAddrMap.find(MatchingVD);
7157e5dd7070Spatrick if (InitAddrIt == CaptureDeviceAddrMap.end())
7158e5dd7070Spatrick continue;
7159e5dd7070Spatrick
7160*12c85518Srobert // Initialize the temporary initialization variable with the address
7161*12c85518Srobert // we get from the runtime library. We have to cast the source address
7162e5dd7070Spatrick // because it is always a void *. References are materialized in the
7163e5dd7070Spatrick // privatization scope, so the initialization here disregards the fact
7164e5dd7070Spatrick // the original variable is a reference.
7165*12c85518Srobert llvm::Type *Ty = ConvertTypeForMem(OrigVD->getType().getNonReferenceType());
7166*12c85518Srobert Address InitAddr = Builder.CreateElementBitCast(InitAddrIt->second, Ty);
7167e5dd7070Spatrick setAddrOfLocalVar(InitVD, InitAddr);
7168e5dd7070Spatrick
7169e5dd7070Spatrick // Emit private declaration, it will be initialized by the value we
7170e5dd7070Spatrick // declaration we just added to the local declarations map.
7171e5dd7070Spatrick EmitDecl(*PvtVD);
7172e5dd7070Spatrick
7173e5dd7070Spatrick // The initialization variables reached its purpose in the emission
7174e5dd7070Spatrick // of the previous declaration, so we don't need it anymore.
7175e5dd7070Spatrick LocalDeclMap.erase(InitVD);
7176e5dd7070Spatrick
7177e5dd7070Spatrick // Return the address of the private variable.
7178*12c85518Srobert bool IsRegistered =
7179*12c85518Srobert PrivateScope.addPrivate(OrigVD, GetAddrOfLocalVar(PvtVD));
7180e5dd7070Spatrick assert(IsRegistered && "firstprivate var already registered as private");
7181e5dd7070Spatrick // Silence the warning about unused variable.
7182e5dd7070Spatrick (void)IsRegistered;
7183e5dd7070Spatrick
7184e5dd7070Spatrick ++OrigVarIt;
7185e5dd7070Spatrick ++InitIt;
7186e5dd7070Spatrick }
7187e5dd7070Spatrick }
7188e5dd7070Spatrick
getBaseDecl(const Expr * Ref)7189ec727ea7Spatrick static const VarDecl *getBaseDecl(const Expr *Ref) {
7190ec727ea7Spatrick const Expr *Base = Ref->IgnoreParenImpCasts();
7191ec727ea7Spatrick while (const auto *OASE = dyn_cast<OMPArraySectionExpr>(Base))
7192ec727ea7Spatrick Base = OASE->getBase()->IgnoreParenImpCasts();
7193ec727ea7Spatrick while (const auto *ASE = dyn_cast<ArraySubscriptExpr>(Base))
7194ec727ea7Spatrick Base = ASE->getBase()->IgnoreParenImpCasts();
7195ec727ea7Spatrick return cast<VarDecl>(cast<DeclRefExpr>(Base)->getDecl());
7196ec727ea7Spatrick }
7197ec727ea7Spatrick
EmitOMPUseDeviceAddrClause(const OMPUseDeviceAddrClause & C,OMPPrivateScope & PrivateScope,const llvm::DenseMap<const ValueDecl *,Address> & CaptureDeviceAddrMap)7198ec727ea7Spatrick void CodeGenFunction::EmitOMPUseDeviceAddrClause(
7199ec727ea7Spatrick const OMPUseDeviceAddrClause &C, OMPPrivateScope &PrivateScope,
7200ec727ea7Spatrick const llvm::DenseMap<const ValueDecl *, Address> &CaptureDeviceAddrMap) {
7201ec727ea7Spatrick llvm::SmallDenseSet<CanonicalDeclPtr<const Decl>, 4> Processed;
7202ec727ea7Spatrick for (const Expr *Ref : C.varlists()) {
7203ec727ea7Spatrick const VarDecl *OrigVD = getBaseDecl(Ref);
7204ec727ea7Spatrick if (!Processed.insert(OrigVD).second)
7205ec727ea7Spatrick continue;
7206ec727ea7Spatrick // In order to identify the right initializer we need to match the
7207ec727ea7Spatrick // declaration used by the mapping logic. In some cases we may get
7208ec727ea7Spatrick // OMPCapturedExprDecl that refers to the original declaration.
7209ec727ea7Spatrick const ValueDecl *MatchingVD = OrigVD;
7210ec727ea7Spatrick if (const auto *OED = dyn_cast<OMPCapturedExprDecl>(MatchingVD)) {
7211ec727ea7Spatrick // OMPCapturedExprDecl are used to privative fields of the current
7212ec727ea7Spatrick // structure.
7213ec727ea7Spatrick const auto *ME = cast<MemberExpr>(OED->getInit());
7214ec727ea7Spatrick assert(isa<CXXThisExpr>(ME->getBase()) &&
7215ec727ea7Spatrick "Base should be the current struct!");
7216ec727ea7Spatrick MatchingVD = ME->getMemberDecl();
7217ec727ea7Spatrick }
7218ec727ea7Spatrick
7219ec727ea7Spatrick // If we don't have information about the current list item, move on to
7220ec727ea7Spatrick // the next one.
7221ec727ea7Spatrick auto InitAddrIt = CaptureDeviceAddrMap.find(MatchingVD);
7222ec727ea7Spatrick if (InitAddrIt == CaptureDeviceAddrMap.end())
7223ec727ea7Spatrick continue;
7224ec727ea7Spatrick
7225ec727ea7Spatrick Address PrivAddr = InitAddrIt->getSecond();
7226ec727ea7Spatrick // For declrefs and variable length array need to load the pointer for
7227ec727ea7Spatrick // correct mapping, since the pointer to the data was passed to the runtime.
7228ec727ea7Spatrick if (isa<DeclRefExpr>(Ref->IgnoreParenImpCasts()) ||
7229*12c85518Srobert MatchingVD->getType()->isArrayType()) {
7230*12c85518Srobert QualType PtrTy = getContext().getPointerType(
7231*12c85518Srobert OrigVD->getType().getNonReferenceType());
7232*12c85518Srobert PrivAddr = EmitLoadOfPointer(
7233*12c85518Srobert Builder.CreateElementBitCast(PrivAddr, ConvertTypeForMem(PtrTy)),
7234*12c85518Srobert PtrTy->castAs<PointerType>());
7235*12c85518Srobert }
7236ec727ea7Spatrick
7237*12c85518Srobert (void)PrivateScope.addPrivate(OrigVD, PrivAddr);
7238ec727ea7Spatrick }
7239ec727ea7Spatrick }
7240ec727ea7Spatrick
7241e5dd7070Spatrick // Generate the instructions for '#pragma omp target data' directive.
EmitOMPTargetDataDirective(const OMPTargetDataDirective & S)7242e5dd7070Spatrick void CodeGenFunction::EmitOMPTargetDataDirective(
7243e5dd7070Spatrick const OMPTargetDataDirective &S) {
7244a9ac8606Spatrick CGOpenMPRuntime::TargetDataInfo Info(/*RequiresDevicePointerInfo=*/true,
7245a9ac8606Spatrick /*SeparateBeginEndCalls=*/true);
7246e5dd7070Spatrick
7247e5dd7070Spatrick // Create a pre/post action to signal the privatization of the device pointer.
7248e5dd7070Spatrick // This action can be replaced by the OpenMP runtime code generation to
7249e5dd7070Spatrick // deactivate privatization.
7250e5dd7070Spatrick bool PrivatizeDevicePointers = false;
7251e5dd7070Spatrick class DevicePointerPrivActionTy : public PrePostActionTy {
7252e5dd7070Spatrick bool &PrivatizeDevicePointers;
7253e5dd7070Spatrick
7254e5dd7070Spatrick public:
7255e5dd7070Spatrick explicit DevicePointerPrivActionTy(bool &PrivatizeDevicePointers)
7256*12c85518Srobert : PrivatizeDevicePointers(PrivatizeDevicePointers) {}
7257e5dd7070Spatrick void Enter(CodeGenFunction &CGF) override {
7258e5dd7070Spatrick PrivatizeDevicePointers = true;
7259e5dd7070Spatrick }
7260e5dd7070Spatrick };
7261e5dd7070Spatrick DevicePointerPrivActionTy PrivAction(PrivatizeDevicePointers);
7262e5dd7070Spatrick
7263e5dd7070Spatrick auto &&CodeGen = [&S, &Info, &PrivatizeDevicePointers](
7264e5dd7070Spatrick CodeGenFunction &CGF, PrePostActionTy &Action) {
7265e5dd7070Spatrick auto &&InnermostCodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
7266e5dd7070Spatrick CGF.EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt());
7267e5dd7070Spatrick };
7268e5dd7070Spatrick
7269e5dd7070Spatrick // Codegen that selects whether to generate the privatization code or not.
7270e5dd7070Spatrick auto &&PrivCodeGen = [&S, &Info, &PrivatizeDevicePointers,
7271e5dd7070Spatrick &InnermostCodeGen](CodeGenFunction &CGF,
7272e5dd7070Spatrick PrePostActionTy &Action) {
7273e5dd7070Spatrick RegionCodeGenTy RCG(InnermostCodeGen);
7274e5dd7070Spatrick PrivatizeDevicePointers = false;
7275e5dd7070Spatrick
7276e5dd7070Spatrick // Call the pre-action to change the status of PrivatizeDevicePointers if
7277e5dd7070Spatrick // needed.
7278e5dd7070Spatrick Action.Enter(CGF);
7279e5dd7070Spatrick
7280e5dd7070Spatrick if (PrivatizeDevicePointers) {
7281e5dd7070Spatrick OMPPrivateScope PrivateScope(CGF);
7282e5dd7070Spatrick // Emit all instances of the use_device_ptr clause.
7283e5dd7070Spatrick for (const auto *C : S.getClausesOfKind<OMPUseDevicePtrClause>())
7284e5dd7070Spatrick CGF.EmitOMPUseDevicePtrClause(*C, PrivateScope,
7285e5dd7070Spatrick Info.CaptureDeviceAddrMap);
7286ec727ea7Spatrick for (const auto *C : S.getClausesOfKind<OMPUseDeviceAddrClause>())
7287ec727ea7Spatrick CGF.EmitOMPUseDeviceAddrClause(*C, PrivateScope,
7288ec727ea7Spatrick Info.CaptureDeviceAddrMap);
7289e5dd7070Spatrick (void)PrivateScope.Privatize();
7290e5dd7070Spatrick RCG(CGF);
7291e5dd7070Spatrick } else {
7292ec727ea7Spatrick OMPLexicalScope Scope(CGF, S, OMPD_unknown);
7293e5dd7070Spatrick RCG(CGF);
7294e5dd7070Spatrick }
7295e5dd7070Spatrick };
7296e5dd7070Spatrick
7297e5dd7070Spatrick // Forward the provided action to the privatization codegen.
7298e5dd7070Spatrick RegionCodeGenTy PrivRCG(PrivCodeGen);
7299e5dd7070Spatrick PrivRCG.setAction(Action);
7300e5dd7070Spatrick
7301e5dd7070Spatrick // Notwithstanding the body of the region is emitted as inlined directive,
7302e5dd7070Spatrick // we don't use an inline scope as changes in the references inside the
7303e5dd7070Spatrick // region are expected to be visible outside, so we do not privative them.
7304e5dd7070Spatrick OMPLexicalScope Scope(CGF, S);
7305e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_target_data,
7306e5dd7070Spatrick PrivRCG);
7307e5dd7070Spatrick };
7308e5dd7070Spatrick
7309e5dd7070Spatrick RegionCodeGenTy RCG(CodeGen);
7310e5dd7070Spatrick
7311e5dd7070Spatrick // If we don't have target devices, don't bother emitting the data mapping
7312e5dd7070Spatrick // code.
7313e5dd7070Spatrick if (CGM.getLangOpts().OMPTargetTriples.empty()) {
7314e5dd7070Spatrick RCG(*this);
7315e5dd7070Spatrick return;
7316e5dd7070Spatrick }
7317e5dd7070Spatrick
7318e5dd7070Spatrick // Check if we have any if clause associated with the directive.
7319e5dd7070Spatrick const Expr *IfCond = nullptr;
7320e5dd7070Spatrick if (const auto *C = S.getSingleClause<OMPIfClause>())
7321e5dd7070Spatrick IfCond = C->getCondition();
7322e5dd7070Spatrick
7323e5dd7070Spatrick // Check if we have any device clause associated with the directive.
7324e5dd7070Spatrick const Expr *Device = nullptr;
7325e5dd7070Spatrick if (const auto *C = S.getSingleClause<OMPDeviceClause>())
7326e5dd7070Spatrick Device = C->getDevice();
7327e5dd7070Spatrick
7328e5dd7070Spatrick // Set the action to signal privatization of device pointers.
7329e5dd7070Spatrick RCG.setAction(PrivAction);
7330e5dd7070Spatrick
7331e5dd7070Spatrick // Emit region code.
7332e5dd7070Spatrick CGM.getOpenMPRuntime().emitTargetDataCalls(*this, S, IfCond, Device, RCG,
7333e5dd7070Spatrick Info);
7334e5dd7070Spatrick }
7335e5dd7070Spatrick
EmitOMPTargetEnterDataDirective(const OMPTargetEnterDataDirective & S)7336e5dd7070Spatrick void CodeGenFunction::EmitOMPTargetEnterDataDirective(
7337e5dd7070Spatrick const OMPTargetEnterDataDirective &S) {
7338e5dd7070Spatrick // If we don't have target devices, don't bother emitting the data mapping
7339e5dd7070Spatrick // code.
7340e5dd7070Spatrick if (CGM.getLangOpts().OMPTargetTriples.empty())
7341e5dd7070Spatrick return;
7342e5dd7070Spatrick
7343e5dd7070Spatrick // Check if we have any if clause associated with the directive.
7344e5dd7070Spatrick const Expr *IfCond = nullptr;
7345e5dd7070Spatrick if (const auto *C = S.getSingleClause<OMPIfClause>())
7346e5dd7070Spatrick IfCond = C->getCondition();
7347e5dd7070Spatrick
7348e5dd7070Spatrick // Check if we have any device clause associated with the directive.
7349e5dd7070Spatrick const Expr *Device = nullptr;
7350e5dd7070Spatrick if (const auto *C = S.getSingleClause<OMPDeviceClause>())
7351e5dd7070Spatrick Device = C->getDevice();
7352e5dd7070Spatrick
7353e5dd7070Spatrick OMPLexicalScope Scope(*this, S, OMPD_task);
7354e5dd7070Spatrick CGM.getOpenMPRuntime().emitTargetDataStandAloneCall(*this, S, IfCond, Device);
7355e5dd7070Spatrick }
7356e5dd7070Spatrick
EmitOMPTargetExitDataDirective(const OMPTargetExitDataDirective & S)7357e5dd7070Spatrick void CodeGenFunction::EmitOMPTargetExitDataDirective(
7358e5dd7070Spatrick const OMPTargetExitDataDirective &S) {
7359e5dd7070Spatrick // If we don't have target devices, don't bother emitting the data mapping
7360e5dd7070Spatrick // code.
7361e5dd7070Spatrick if (CGM.getLangOpts().OMPTargetTriples.empty())
7362e5dd7070Spatrick return;
7363e5dd7070Spatrick
7364e5dd7070Spatrick // Check if we have any if clause associated with the directive.
7365e5dd7070Spatrick const Expr *IfCond = nullptr;
7366e5dd7070Spatrick if (const auto *C = S.getSingleClause<OMPIfClause>())
7367e5dd7070Spatrick IfCond = C->getCondition();
7368e5dd7070Spatrick
7369e5dd7070Spatrick // Check if we have any device clause associated with the directive.
7370e5dd7070Spatrick const Expr *Device = nullptr;
7371e5dd7070Spatrick if (const auto *C = S.getSingleClause<OMPDeviceClause>())
7372e5dd7070Spatrick Device = C->getDevice();
7373e5dd7070Spatrick
7374e5dd7070Spatrick OMPLexicalScope Scope(*this, S, OMPD_task);
7375e5dd7070Spatrick CGM.getOpenMPRuntime().emitTargetDataStandAloneCall(*this, S, IfCond, Device);
7376e5dd7070Spatrick }
7377e5dd7070Spatrick
emitTargetParallelRegion(CodeGenFunction & CGF,const OMPTargetParallelDirective & S,PrePostActionTy & Action)7378e5dd7070Spatrick static void emitTargetParallelRegion(CodeGenFunction &CGF,
7379e5dd7070Spatrick const OMPTargetParallelDirective &S,
7380e5dd7070Spatrick PrePostActionTy &Action) {
7381e5dd7070Spatrick // Get the captured statement associated with the 'parallel' region.
7382e5dd7070Spatrick const CapturedStmt *CS = S.getCapturedStmt(OMPD_parallel);
7383e5dd7070Spatrick Action.Enter(CGF);
7384e5dd7070Spatrick auto &&CodeGen = [&S, CS](CodeGenFunction &CGF, PrePostActionTy &Action) {
7385e5dd7070Spatrick Action.Enter(CGF);
7386e5dd7070Spatrick CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
7387e5dd7070Spatrick (void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
7388e5dd7070Spatrick CGF.EmitOMPPrivateClause(S, PrivateScope);
7389e5dd7070Spatrick CGF.EmitOMPReductionClauseInit(S, PrivateScope);
7390e5dd7070Spatrick (void)PrivateScope.Privatize();
7391e5dd7070Spatrick if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()))
7392e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().adjustTargetSpecificDataForLambdas(CGF, S);
7393e5dd7070Spatrick // TODO: Add support for clauses.
7394e5dd7070Spatrick CGF.EmitStmt(CS->getCapturedStmt());
7395e5dd7070Spatrick CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_parallel);
7396e5dd7070Spatrick };
7397e5dd7070Spatrick emitCommonOMPParallelDirective(CGF, S, OMPD_parallel, CodeGen,
7398e5dd7070Spatrick emitEmptyBoundParameters);
7399e5dd7070Spatrick emitPostUpdateForReductionClause(CGF, S,
7400e5dd7070Spatrick [](CodeGenFunction &) { return nullptr; });
7401e5dd7070Spatrick }
7402e5dd7070Spatrick
EmitOMPTargetParallelDeviceFunction(CodeGenModule & CGM,StringRef ParentName,const OMPTargetParallelDirective & S)7403e5dd7070Spatrick void CodeGenFunction::EmitOMPTargetParallelDeviceFunction(
7404e5dd7070Spatrick CodeGenModule &CGM, StringRef ParentName,
7405e5dd7070Spatrick const OMPTargetParallelDirective &S) {
7406e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7407e5dd7070Spatrick emitTargetParallelRegion(CGF, S, Action);
7408e5dd7070Spatrick };
7409e5dd7070Spatrick llvm::Function *Fn;
7410e5dd7070Spatrick llvm::Constant *Addr;
7411e5dd7070Spatrick // Emit target region as a standalone region.
7412e5dd7070Spatrick CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
7413e5dd7070Spatrick S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
7414e5dd7070Spatrick assert(Fn && Addr && "Target device function emission failed.");
7415e5dd7070Spatrick }
7416e5dd7070Spatrick
EmitOMPTargetParallelDirective(const OMPTargetParallelDirective & S)7417e5dd7070Spatrick void CodeGenFunction::EmitOMPTargetParallelDirective(
7418e5dd7070Spatrick const OMPTargetParallelDirective &S) {
7419e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7420e5dd7070Spatrick emitTargetParallelRegion(CGF, S, Action);
7421e5dd7070Spatrick };
7422e5dd7070Spatrick emitCommonOMPTargetDirective(*this, S, CodeGen);
7423e5dd7070Spatrick }
7424e5dd7070Spatrick
emitTargetParallelForRegion(CodeGenFunction & CGF,const OMPTargetParallelForDirective & S,PrePostActionTy & Action)7425e5dd7070Spatrick static void emitTargetParallelForRegion(CodeGenFunction &CGF,
7426e5dd7070Spatrick const OMPTargetParallelForDirective &S,
7427e5dd7070Spatrick PrePostActionTy &Action) {
7428e5dd7070Spatrick Action.Enter(CGF);
7429e5dd7070Spatrick // Emit directive as a combined directive that consists of two implicit
7430e5dd7070Spatrick // directives: 'parallel' with 'for' directive.
7431e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7432e5dd7070Spatrick Action.Enter(CGF);
7433e5dd7070Spatrick CodeGenFunction::OMPCancelStackRAII CancelRegion(
7434e5dd7070Spatrick CGF, OMPD_target_parallel_for, S.hasCancel());
7435e5dd7070Spatrick CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(), emitForLoopBounds,
7436e5dd7070Spatrick emitDispatchForLoopBounds);
7437e5dd7070Spatrick };
7438e5dd7070Spatrick emitCommonOMPParallelDirective(CGF, S, OMPD_for, CodeGen,
7439e5dd7070Spatrick emitEmptyBoundParameters);
7440e5dd7070Spatrick }
7441e5dd7070Spatrick
EmitOMPTargetParallelForDeviceFunction(CodeGenModule & CGM,StringRef ParentName,const OMPTargetParallelForDirective & S)7442e5dd7070Spatrick void CodeGenFunction::EmitOMPTargetParallelForDeviceFunction(
7443e5dd7070Spatrick CodeGenModule &CGM, StringRef ParentName,
7444e5dd7070Spatrick const OMPTargetParallelForDirective &S) {
7445e5dd7070Spatrick // Emit SPMD target parallel for region as a standalone region.
7446e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7447e5dd7070Spatrick emitTargetParallelForRegion(CGF, S, Action);
7448e5dd7070Spatrick };
7449e5dd7070Spatrick llvm::Function *Fn;
7450e5dd7070Spatrick llvm::Constant *Addr;
7451e5dd7070Spatrick // Emit target region as a standalone region.
7452e5dd7070Spatrick CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
7453e5dd7070Spatrick S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
7454e5dd7070Spatrick assert(Fn && Addr && "Target device function emission failed.");
7455e5dd7070Spatrick }
7456e5dd7070Spatrick
EmitOMPTargetParallelForDirective(const OMPTargetParallelForDirective & S)7457e5dd7070Spatrick void CodeGenFunction::EmitOMPTargetParallelForDirective(
7458e5dd7070Spatrick const OMPTargetParallelForDirective &S) {
7459e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7460e5dd7070Spatrick emitTargetParallelForRegion(CGF, S, Action);
7461e5dd7070Spatrick };
7462e5dd7070Spatrick emitCommonOMPTargetDirective(*this, S, CodeGen);
7463e5dd7070Spatrick }
7464e5dd7070Spatrick
7465e5dd7070Spatrick static void
emitTargetParallelForSimdRegion(CodeGenFunction & CGF,const OMPTargetParallelForSimdDirective & S,PrePostActionTy & Action)7466e5dd7070Spatrick emitTargetParallelForSimdRegion(CodeGenFunction &CGF,
7467e5dd7070Spatrick const OMPTargetParallelForSimdDirective &S,
7468e5dd7070Spatrick PrePostActionTy &Action) {
7469e5dd7070Spatrick Action.Enter(CGF);
7470e5dd7070Spatrick // Emit directive as a combined directive that consists of two implicit
7471e5dd7070Spatrick // directives: 'parallel' with 'for' directive.
7472e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7473e5dd7070Spatrick Action.Enter(CGF);
7474e5dd7070Spatrick CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(), emitForLoopBounds,
7475e5dd7070Spatrick emitDispatchForLoopBounds);
7476e5dd7070Spatrick };
7477e5dd7070Spatrick emitCommonOMPParallelDirective(CGF, S, OMPD_simd, CodeGen,
7478e5dd7070Spatrick emitEmptyBoundParameters);
7479e5dd7070Spatrick }
7480e5dd7070Spatrick
EmitOMPTargetParallelForSimdDeviceFunction(CodeGenModule & CGM,StringRef ParentName,const OMPTargetParallelForSimdDirective & S)7481e5dd7070Spatrick void CodeGenFunction::EmitOMPTargetParallelForSimdDeviceFunction(
7482e5dd7070Spatrick CodeGenModule &CGM, StringRef ParentName,
7483e5dd7070Spatrick const OMPTargetParallelForSimdDirective &S) {
7484e5dd7070Spatrick // Emit SPMD target parallel for region as a standalone region.
7485e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7486e5dd7070Spatrick emitTargetParallelForSimdRegion(CGF, S, Action);
7487e5dd7070Spatrick };
7488e5dd7070Spatrick llvm::Function *Fn;
7489e5dd7070Spatrick llvm::Constant *Addr;
7490e5dd7070Spatrick // Emit target region as a standalone region.
7491e5dd7070Spatrick CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
7492e5dd7070Spatrick S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
7493e5dd7070Spatrick assert(Fn && Addr && "Target device function emission failed.");
7494e5dd7070Spatrick }
7495e5dd7070Spatrick
EmitOMPTargetParallelForSimdDirective(const OMPTargetParallelForSimdDirective & S)7496e5dd7070Spatrick void CodeGenFunction::EmitOMPTargetParallelForSimdDirective(
7497e5dd7070Spatrick const OMPTargetParallelForSimdDirective &S) {
7498e5dd7070Spatrick auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7499e5dd7070Spatrick emitTargetParallelForSimdRegion(CGF, S, Action);
7500e5dd7070Spatrick };
7501e5dd7070Spatrick emitCommonOMPTargetDirective(*this, S, CodeGen);
7502e5dd7070Spatrick }
7503e5dd7070Spatrick
7504e5dd7070Spatrick /// Emit a helper variable and return corresponding lvalue.
mapParam(CodeGenFunction & CGF,const DeclRefExpr * Helper,const ImplicitParamDecl * PVD,CodeGenFunction::OMPPrivateScope & Privates)7505e5dd7070Spatrick static void mapParam(CodeGenFunction &CGF, const DeclRefExpr *Helper,
7506e5dd7070Spatrick const ImplicitParamDecl *PVD,
7507e5dd7070Spatrick CodeGenFunction::OMPPrivateScope &Privates) {
7508e5dd7070Spatrick const auto *VDecl = cast<VarDecl>(Helper->getDecl());
7509*12c85518Srobert Privates.addPrivate(VDecl, CGF.GetAddrOfLocalVar(PVD));
7510e5dd7070Spatrick }
7511e5dd7070Spatrick
EmitOMPTaskLoopBasedDirective(const OMPLoopDirective & S)7512e5dd7070Spatrick void CodeGenFunction::EmitOMPTaskLoopBasedDirective(const OMPLoopDirective &S) {
7513e5dd7070Spatrick assert(isOpenMPTaskLoopDirective(S.getDirectiveKind()));
7514e5dd7070Spatrick // Emit outlined function for task construct.
7515e5dd7070Spatrick const CapturedStmt *CS = S.getCapturedStmt(OMPD_taskloop);
7516ec727ea7Spatrick Address CapturedStruct = Address::invalid();
7517ec727ea7Spatrick {
7518ec727ea7Spatrick OMPLexicalScope Scope(*this, S, OMPD_taskloop, /*EmitPreInitStmt=*/false);
7519ec727ea7Spatrick CapturedStruct = GenerateCapturedStmtArgument(*CS);
7520ec727ea7Spatrick }
7521e5dd7070Spatrick QualType SharedsTy = getContext().getRecordType(CS->getCapturedRecordDecl());
7522e5dd7070Spatrick const Expr *IfCond = nullptr;
7523e5dd7070Spatrick for (const auto *C : S.getClausesOfKind<OMPIfClause>()) {
7524e5dd7070Spatrick if (C->getNameModifier() == OMPD_unknown ||
7525e5dd7070Spatrick C->getNameModifier() == OMPD_taskloop) {
7526e5dd7070Spatrick IfCond = C->getCondition();
7527e5dd7070Spatrick break;
7528e5dd7070Spatrick }
7529e5dd7070Spatrick }
7530e5dd7070Spatrick
7531e5dd7070Spatrick OMPTaskDataTy Data;
7532e5dd7070Spatrick // Check if taskloop must be emitted without taskgroup.
7533e5dd7070Spatrick Data.Nogroup = S.getSingleClause<OMPNogroupClause>();
7534e5dd7070Spatrick // TODO: Check if we should emit tied or untied task.
7535e5dd7070Spatrick Data.Tied = true;
7536e5dd7070Spatrick // Set scheduling for taskloop
7537e5dd7070Spatrick if (const auto *Clause = S.getSingleClause<OMPGrainsizeClause>()) {
7538e5dd7070Spatrick // grainsize clause
7539e5dd7070Spatrick Data.Schedule.setInt(/*IntVal=*/false);
7540e5dd7070Spatrick Data.Schedule.setPointer(EmitScalarExpr(Clause->getGrainsize()));
7541e5dd7070Spatrick } else if (const auto *Clause = S.getSingleClause<OMPNumTasksClause>()) {
7542e5dd7070Spatrick // num_tasks clause
7543e5dd7070Spatrick Data.Schedule.setInt(/*IntVal=*/true);
7544e5dd7070Spatrick Data.Schedule.setPointer(EmitScalarExpr(Clause->getNumTasks()));
7545e5dd7070Spatrick }
7546e5dd7070Spatrick
7547e5dd7070Spatrick auto &&BodyGen = [CS, &S](CodeGenFunction &CGF, PrePostActionTy &) {
7548e5dd7070Spatrick // if (PreCond) {
7549e5dd7070Spatrick // for (IV in 0..LastIteration) BODY;
7550e5dd7070Spatrick // <Final counter/linear vars updates>;
7551e5dd7070Spatrick // }
7552e5dd7070Spatrick //
7553e5dd7070Spatrick
7554e5dd7070Spatrick // Emit: if (PreCond) - begin.
7555e5dd7070Spatrick // If the condition constant folds and can be elided, avoid emitting the
7556e5dd7070Spatrick // whole loop.
7557e5dd7070Spatrick bool CondConstant;
7558e5dd7070Spatrick llvm::BasicBlock *ContBlock = nullptr;
7559e5dd7070Spatrick OMPLoopScope PreInitScope(CGF, S);
7560e5dd7070Spatrick if (CGF.ConstantFoldsToSimpleInteger(S.getPreCond(), CondConstant)) {
7561e5dd7070Spatrick if (!CondConstant)
7562e5dd7070Spatrick return;
7563e5dd7070Spatrick } else {
7564e5dd7070Spatrick llvm::BasicBlock *ThenBlock = CGF.createBasicBlock("taskloop.if.then");
7565e5dd7070Spatrick ContBlock = CGF.createBasicBlock("taskloop.if.end");
7566e5dd7070Spatrick emitPreCond(CGF, S, S.getPreCond(), ThenBlock, ContBlock,
7567e5dd7070Spatrick CGF.getProfileCount(&S));
7568e5dd7070Spatrick CGF.EmitBlock(ThenBlock);
7569e5dd7070Spatrick CGF.incrementProfileCounter(&S);
7570e5dd7070Spatrick }
7571e5dd7070Spatrick
7572e5dd7070Spatrick (void)CGF.EmitOMPLinearClauseInit(S);
7573e5dd7070Spatrick
7574e5dd7070Spatrick OMPPrivateScope LoopScope(CGF);
7575e5dd7070Spatrick // Emit helper vars inits.
7576e5dd7070Spatrick enum { LowerBound = 5, UpperBound, Stride, LastIter };
7577e5dd7070Spatrick auto *I = CS->getCapturedDecl()->param_begin();
7578e5dd7070Spatrick auto *LBP = std::next(I, LowerBound);
7579e5dd7070Spatrick auto *UBP = std::next(I, UpperBound);
7580e5dd7070Spatrick auto *STP = std::next(I, Stride);
7581e5dd7070Spatrick auto *LIP = std::next(I, LastIter);
7582e5dd7070Spatrick mapParam(CGF, cast<DeclRefExpr>(S.getLowerBoundVariable()), *LBP,
7583e5dd7070Spatrick LoopScope);
7584e5dd7070Spatrick mapParam(CGF, cast<DeclRefExpr>(S.getUpperBoundVariable()), *UBP,
7585e5dd7070Spatrick LoopScope);
7586e5dd7070Spatrick mapParam(CGF, cast<DeclRefExpr>(S.getStrideVariable()), *STP, LoopScope);
7587e5dd7070Spatrick mapParam(CGF, cast<DeclRefExpr>(S.getIsLastIterVariable()), *LIP,
7588e5dd7070Spatrick LoopScope);
7589e5dd7070Spatrick CGF.EmitOMPPrivateLoopCounters(S, LoopScope);
7590e5dd7070Spatrick CGF.EmitOMPLinearClause(S, LoopScope);
7591e5dd7070Spatrick bool HasLastprivateClause = CGF.EmitOMPLastprivateClauseInit(S, LoopScope);
7592e5dd7070Spatrick (void)LoopScope.Privatize();
7593e5dd7070Spatrick // Emit the loop iteration variable.
7594e5dd7070Spatrick const Expr *IVExpr = S.getIterationVariable();
7595e5dd7070Spatrick const auto *IVDecl = cast<VarDecl>(cast<DeclRefExpr>(IVExpr)->getDecl());
7596e5dd7070Spatrick CGF.EmitVarDecl(*IVDecl);
7597e5dd7070Spatrick CGF.EmitIgnoredExpr(S.getInit());
7598e5dd7070Spatrick
7599e5dd7070Spatrick // Emit the iterations count variable.
7600e5dd7070Spatrick // If it is not a variable, Sema decided to calculate iterations count on
7601e5dd7070Spatrick // each iteration (e.g., it is foldable into a constant).
7602e5dd7070Spatrick if (const auto *LIExpr = dyn_cast<DeclRefExpr>(S.getLastIteration())) {
7603e5dd7070Spatrick CGF.EmitVarDecl(*cast<VarDecl>(LIExpr->getDecl()));
7604e5dd7070Spatrick // Emit calculation of the iterations count.
7605e5dd7070Spatrick CGF.EmitIgnoredExpr(S.getCalcLastIteration());
7606e5dd7070Spatrick }
7607e5dd7070Spatrick
7608e5dd7070Spatrick {
7609e5dd7070Spatrick OMPLexicalScope Scope(CGF, S, OMPD_taskloop, /*EmitPreInitStmt=*/false);
7610e5dd7070Spatrick emitCommonSimdLoop(
7611e5dd7070Spatrick CGF, S,
7612e5dd7070Spatrick [&S](CodeGenFunction &CGF, PrePostActionTy &) {
7613e5dd7070Spatrick if (isOpenMPSimdDirective(S.getDirectiveKind()))
7614e5dd7070Spatrick CGF.EmitOMPSimdInit(S);
7615e5dd7070Spatrick },
7616e5dd7070Spatrick [&S, &LoopScope](CodeGenFunction &CGF, PrePostActionTy &) {
7617e5dd7070Spatrick CGF.EmitOMPInnerLoop(
7618e5dd7070Spatrick S, LoopScope.requiresCleanups(), S.getCond(), S.getInc(),
7619e5dd7070Spatrick [&S](CodeGenFunction &CGF) {
7620ec727ea7Spatrick emitOMPLoopBodyWithStopPoint(CGF, S,
7621ec727ea7Spatrick CodeGenFunction::JumpDest());
7622e5dd7070Spatrick },
7623e5dd7070Spatrick [](CodeGenFunction &) {});
7624e5dd7070Spatrick });
7625e5dd7070Spatrick }
7626e5dd7070Spatrick // Emit: if (PreCond) - end.
7627e5dd7070Spatrick if (ContBlock) {
7628e5dd7070Spatrick CGF.EmitBranch(ContBlock);
7629e5dd7070Spatrick CGF.EmitBlock(ContBlock, true);
7630e5dd7070Spatrick }
7631e5dd7070Spatrick // Emit final copy of the lastprivate variables if IsLastIter != 0.
7632e5dd7070Spatrick if (HasLastprivateClause) {
7633e5dd7070Spatrick CGF.EmitOMPLastprivateClauseFinal(
7634e5dd7070Spatrick S, isOpenMPSimdDirective(S.getDirectiveKind()),
7635e5dd7070Spatrick CGF.Builder.CreateIsNotNull(CGF.EmitLoadOfScalar(
7636e5dd7070Spatrick CGF.GetAddrOfLocalVar(*LIP), /*Volatile=*/false,
7637e5dd7070Spatrick (*LIP)->getType(), S.getBeginLoc())));
7638e5dd7070Spatrick }
7639*12c85518Srobert LoopScope.restoreMap();
7640e5dd7070Spatrick CGF.EmitOMPLinearClauseFinal(S, [LIP, &S](CodeGenFunction &CGF) {
7641e5dd7070Spatrick return CGF.Builder.CreateIsNotNull(
7642e5dd7070Spatrick CGF.EmitLoadOfScalar(CGF.GetAddrOfLocalVar(*LIP), /*Volatile=*/false,
7643e5dd7070Spatrick (*LIP)->getType(), S.getBeginLoc()));
7644e5dd7070Spatrick });
7645e5dd7070Spatrick };
7646e5dd7070Spatrick auto &&TaskGen = [&S, SharedsTy, CapturedStruct,
7647e5dd7070Spatrick IfCond](CodeGenFunction &CGF, llvm::Function *OutlinedFn,
7648e5dd7070Spatrick const OMPTaskDataTy &Data) {
7649e5dd7070Spatrick auto &&CodeGen = [&S, OutlinedFn, SharedsTy, CapturedStruct, IfCond,
7650e5dd7070Spatrick &Data](CodeGenFunction &CGF, PrePostActionTy &) {
7651e5dd7070Spatrick OMPLoopScope PreInitScope(CGF, S);
7652e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitTaskLoopCall(CGF, S.getBeginLoc(), S,
7653e5dd7070Spatrick OutlinedFn, SharedsTy,
7654e5dd7070Spatrick CapturedStruct, IfCond, Data);
7655e5dd7070Spatrick };
7656e5dd7070Spatrick CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_taskloop,
7657e5dd7070Spatrick CodeGen);
7658e5dd7070Spatrick };
7659e5dd7070Spatrick if (Data.Nogroup) {
7660e5dd7070Spatrick EmitOMPTaskBasedDirective(S, OMPD_taskloop, BodyGen, TaskGen, Data);
7661e5dd7070Spatrick } else {
7662e5dd7070Spatrick CGM.getOpenMPRuntime().emitTaskgroupRegion(
7663e5dd7070Spatrick *this,
7664e5dd7070Spatrick [&S, &BodyGen, &TaskGen, &Data](CodeGenFunction &CGF,
7665e5dd7070Spatrick PrePostActionTy &Action) {
7666e5dd7070Spatrick Action.Enter(CGF);
7667e5dd7070Spatrick CGF.EmitOMPTaskBasedDirective(S, OMPD_taskloop, BodyGen, TaskGen,
7668e5dd7070Spatrick Data);
7669e5dd7070Spatrick },
7670e5dd7070Spatrick S.getBeginLoc());
7671e5dd7070Spatrick }
7672e5dd7070Spatrick }
7673e5dd7070Spatrick
EmitOMPTaskLoopDirective(const OMPTaskLoopDirective & S)7674e5dd7070Spatrick void CodeGenFunction::EmitOMPTaskLoopDirective(const OMPTaskLoopDirective &S) {
7675ec727ea7Spatrick auto LPCRegion =
7676ec727ea7Spatrick CGOpenMPRuntime::LastprivateConditionalRAII::disable(*this, S);
7677e5dd7070Spatrick EmitOMPTaskLoopBasedDirective(S);
7678e5dd7070Spatrick }
7679e5dd7070Spatrick
EmitOMPTaskLoopSimdDirective(const OMPTaskLoopSimdDirective & S)7680e5dd7070Spatrick void CodeGenFunction::EmitOMPTaskLoopSimdDirective(
7681e5dd7070Spatrick const OMPTaskLoopSimdDirective &S) {
7682ec727ea7Spatrick auto LPCRegion =
7683ec727ea7Spatrick CGOpenMPRuntime::LastprivateConditionalRAII::disable(*this, S);
7684e5dd7070Spatrick OMPLexicalScope Scope(*this, S);
7685e5dd7070Spatrick EmitOMPTaskLoopBasedDirective(S);
7686e5dd7070Spatrick }
7687e5dd7070Spatrick
EmitOMPMasterTaskLoopDirective(const OMPMasterTaskLoopDirective & S)7688e5dd7070Spatrick void CodeGenFunction::EmitOMPMasterTaskLoopDirective(
7689e5dd7070Spatrick const OMPMasterTaskLoopDirective &S) {
7690e5dd7070Spatrick auto &&CodeGen = [this, &S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7691e5dd7070Spatrick Action.Enter(CGF);
7692e5dd7070Spatrick EmitOMPTaskLoopBasedDirective(S);
7693e5dd7070Spatrick };
7694ec727ea7Spatrick auto LPCRegion =
7695ec727ea7Spatrick CGOpenMPRuntime::LastprivateConditionalRAII::disable(*this, S);
7696*12c85518Srobert OMPLexicalScope Scope(*this, S, std::nullopt, /*EmitPreInitStmt=*/false);
7697e5dd7070Spatrick CGM.getOpenMPRuntime().emitMasterRegion(*this, CodeGen, S.getBeginLoc());
7698e5dd7070Spatrick }
7699e5dd7070Spatrick
EmitOMPMasterTaskLoopSimdDirective(const OMPMasterTaskLoopSimdDirective & S)7700e5dd7070Spatrick void CodeGenFunction::EmitOMPMasterTaskLoopSimdDirective(
7701e5dd7070Spatrick const OMPMasterTaskLoopSimdDirective &S) {
7702e5dd7070Spatrick auto &&CodeGen = [this, &S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7703e5dd7070Spatrick Action.Enter(CGF);
7704e5dd7070Spatrick EmitOMPTaskLoopBasedDirective(S);
7705e5dd7070Spatrick };
7706ec727ea7Spatrick auto LPCRegion =
7707ec727ea7Spatrick CGOpenMPRuntime::LastprivateConditionalRAII::disable(*this, S);
7708e5dd7070Spatrick OMPLexicalScope Scope(*this, S);
7709e5dd7070Spatrick CGM.getOpenMPRuntime().emitMasterRegion(*this, CodeGen, S.getBeginLoc());
7710e5dd7070Spatrick }
7711e5dd7070Spatrick
EmitOMPParallelMasterTaskLoopDirective(const OMPParallelMasterTaskLoopDirective & S)7712e5dd7070Spatrick void CodeGenFunction::EmitOMPParallelMasterTaskLoopDirective(
7713e5dd7070Spatrick const OMPParallelMasterTaskLoopDirective &S) {
7714e5dd7070Spatrick auto &&CodeGen = [this, &S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7715e5dd7070Spatrick auto &&TaskLoopCodeGen = [&S](CodeGenFunction &CGF,
7716e5dd7070Spatrick PrePostActionTy &Action) {
7717e5dd7070Spatrick Action.Enter(CGF);
7718e5dd7070Spatrick CGF.EmitOMPTaskLoopBasedDirective(S);
7719e5dd7070Spatrick };
7720ec727ea7Spatrick OMPLexicalScope Scope(CGF, S, OMPD_parallel, /*EmitPreInitStmt=*/false);
7721e5dd7070Spatrick CGM.getOpenMPRuntime().emitMasterRegion(CGF, TaskLoopCodeGen,
7722e5dd7070Spatrick S.getBeginLoc());
7723e5dd7070Spatrick };
7724ec727ea7Spatrick auto LPCRegion =
7725ec727ea7Spatrick CGOpenMPRuntime::LastprivateConditionalRAII::disable(*this, S);
7726e5dd7070Spatrick emitCommonOMPParallelDirective(*this, S, OMPD_master_taskloop, CodeGen,
7727e5dd7070Spatrick emitEmptyBoundParameters);
7728e5dd7070Spatrick }
7729e5dd7070Spatrick
EmitOMPParallelMasterTaskLoopSimdDirective(const OMPParallelMasterTaskLoopSimdDirective & S)7730e5dd7070Spatrick void CodeGenFunction::EmitOMPParallelMasterTaskLoopSimdDirective(
7731e5dd7070Spatrick const OMPParallelMasterTaskLoopSimdDirective &S) {
7732e5dd7070Spatrick auto &&CodeGen = [this, &S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7733e5dd7070Spatrick auto &&TaskLoopCodeGen = [&S](CodeGenFunction &CGF,
7734e5dd7070Spatrick PrePostActionTy &Action) {
7735e5dd7070Spatrick Action.Enter(CGF);
7736e5dd7070Spatrick CGF.EmitOMPTaskLoopBasedDirective(S);
7737e5dd7070Spatrick };
7738e5dd7070Spatrick OMPLexicalScope Scope(CGF, S, OMPD_parallel, /*EmitPreInitStmt=*/false);
7739e5dd7070Spatrick CGM.getOpenMPRuntime().emitMasterRegion(CGF, TaskLoopCodeGen,
7740e5dd7070Spatrick S.getBeginLoc());
7741e5dd7070Spatrick };
7742ec727ea7Spatrick auto LPCRegion =
7743ec727ea7Spatrick CGOpenMPRuntime::LastprivateConditionalRAII::disable(*this, S);
7744e5dd7070Spatrick emitCommonOMPParallelDirective(*this, S, OMPD_master_taskloop_simd, CodeGen,
7745e5dd7070Spatrick emitEmptyBoundParameters);
7746e5dd7070Spatrick }
7747e5dd7070Spatrick
7748e5dd7070Spatrick // Generate the instructions for '#pragma omp target update' directive.
EmitOMPTargetUpdateDirective(const OMPTargetUpdateDirective & S)7749e5dd7070Spatrick void CodeGenFunction::EmitOMPTargetUpdateDirective(
7750e5dd7070Spatrick const OMPTargetUpdateDirective &S) {
7751e5dd7070Spatrick // If we don't have target devices, don't bother emitting the data mapping
7752e5dd7070Spatrick // code.
7753e5dd7070Spatrick if (CGM.getLangOpts().OMPTargetTriples.empty())
7754e5dd7070Spatrick return;
7755e5dd7070Spatrick
7756e5dd7070Spatrick // Check if we have any if clause associated with the directive.
7757e5dd7070Spatrick const Expr *IfCond = nullptr;
7758e5dd7070Spatrick if (const auto *C = S.getSingleClause<OMPIfClause>())
7759e5dd7070Spatrick IfCond = C->getCondition();
7760e5dd7070Spatrick
7761e5dd7070Spatrick // Check if we have any device clause associated with the directive.
7762e5dd7070Spatrick const Expr *Device = nullptr;
7763e5dd7070Spatrick if (const auto *C = S.getSingleClause<OMPDeviceClause>())
7764e5dd7070Spatrick Device = C->getDevice();
7765e5dd7070Spatrick
7766e5dd7070Spatrick OMPLexicalScope Scope(*this, S, OMPD_task);
7767e5dd7070Spatrick CGM.getOpenMPRuntime().emitTargetDataStandAloneCall(*this, S, IfCond, Device);
7768e5dd7070Spatrick }
7769e5dd7070Spatrick
EmitOMPGenericLoopDirective(const OMPGenericLoopDirective & S)7770*12c85518Srobert void CodeGenFunction::EmitOMPGenericLoopDirective(
7771*12c85518Srobert const OMPGenericLoopDirective &S) {
7772*12c85518Srobert // Unimplemented, just inline the underlying statement for now.
7773*12c85518Srobert auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7774*12c85518Srobert // Emit the loop iteration variable.
7775*12c85518Srobert const Stmt *CS =
7776*12c85518Srobert cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt();
7777*12c85518Srobert const auto *ForS = dyn_cast<ForStmt>(CS);
7778*12c85518Srobert if (ForS && !isa<DeclStmt>(ForS->getInit())) {
7779*12c85518Srobert OMPPrivateScope LoopScope(CGF);
7780*12c85518Srobert CGF.EmitOMPPrivateLoopCounters(S, LoopScope);
7781*12c85518Srobert (void)LoopScope.Privatize();
7782*12c85518Srobert CGF.EmitStmt(CS);
7783*12c85518Srobert LoopScope.restoreMap();
7784*12c85518Srobert } else {
7785*12c85518Srobert CGF.EmitStmt(CS);
7786*12c85518Srobert }
7787*12c85518Srobert };
7788*12c85518Srobert OMPLexicalScope Scope(*this, S, OMPD_unknown);
7789*12c85518Srobert CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_loop, CodeGen);
7790*12c85518Srobert }
7791*12c85518Srobert
EmitSimpleOMPExecutableDirective(const OMPExecutableDirective & D)7792e5dd7070Spatrick void CodeGenFunction::EmitSimpleOMPExecutableDirective(
7793e5dd7070Spatrick const OMPExecutableDirective &D) {
7794ec727ea7Spatrick if (const auto *SD = dyn_cast<OMPScanDirective>(&D)) {
7795ec727ea7Spatrick EmitOMPScanDirective(*SD);
7796ec727ea7Spatrick return;
7797ec727ea7Spatrick }
7798e5dd7070Spatrick if (!D.hasAssociatedStmt() || !D.getAssociatedStmt())
7799e5dd7070Spatrick return;
7800e5dd7070Spatrick auto &&CodeGen = [&D](CodeGenFunction &CGF, PrePostActionTy &Action) {
7801ec727ea7Spatrick OMPPrivateScope GlobalsScope(CGF);
7802ec727ea7Spatrick if (isOpenMPTaskingDirective(D.getDirectiveKind())) {
7803ec727ea7Spatrick // Capture global firstprivates to avoid crash.
7804ec727ea7Spatrick for (const auto *C : D.getClausesOfKind<OMPFirstprivateClause>()) {
7805ec727ea7Spatrick for (const Expr *Ref : C->varlists()) {
7806ec727ea7Spatrick const auto *DRE = cast<DeclRefExpr>(Ref->IgnoreParenImpCasts());
7807ec727ea7Spatrick if (!DRE)
7808ec727ea7Spatrick continue;
7809ec727ea7Spatrick const auto *VD = dyn_cast<VarDecl>(DRE->getDecl());
7810ec727ea7Spatrick if (!VD || VD->hasLocalStorage())
7811ec727ea7Spatrick continue;
7812ec727ea7Spatrick if (!CGF.LocalDeclMap.count(VD)) {
7813ec727ea7Spatrick LValue GlobLVal = CGF.EmitLValue(Ref);
7814*12c85518Srobert GlobalsScope.addPrivate(VD, GlobLVal.getAddress(CGF));
7815ec727ea7Spatrick }
7816ec727ea7Spatrick }
7817ec727ea7Spatrick }
7818ec727ea7Spatrick }
7819e5dd7070Spatrick if (isOpenMPSimdDirective(D.getDirectiveKind())) {
7820ec727ea7Spatrick (void)GlobalsScope.Privatize();
7821ec727ea7Spatrick ParentLoopDirectiveForScanRegion ScanRegion(CGF, D);
7822e5dd7070Spatrick emitOMPSimdRegion(CGF, cast<OMPLoopDirective>(D), Action);
7823e5dd7070Spatrick } else {
7824e5dd7070Spatrick if (const auto *LD = dyn_cast<OMPLoopDirective>(&D)) {
7825e5dd7070Spatrick for (const Expr *E : LD->counters()) {
7826e5dd7070Spatrick const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
7827e5dd7070Spatrick if (!VD->hasLocalStorage() && !CGF.LocalDeclMap.count(VD)) {
7828e5dd7070Spatrick LValue GlobLVal = CGF.EmitLValue(E);
7829*12c85518Srobert GlobalsScope.addPrivate(VD, GlobLVal.getAddress(CGF));
7830e5dd7070Spatrick }
7831e5dd7070Spatrick if (isa<OMPCapturedExprDecl>(VD)) {
7832e5dd7070Spatrick // Emit only those that were not explicitly referenced in clauses.
7833e5dd7070Spatrick if (!CGF.LocalDeclMap.count(VD))
7834e5dd7070Spatrick CGF.EmitVarDecl(*VD);
7835e5dd7070Spatrick }
7836e5dd7070Spatrick }
7837e5dd7070Spatrick for (const auto *C : D.getClausesOfKind<OMPOrderedClause>()) {
7838e5dd7070Spatrick if (!C->getNumForLoops())
7839e5dd7070Spatrick continue;
7840a9ac8606Spatrick for (unsigned I = LD->getLoopsNumber(),
7841e5dd7070Spatrick E = C->getLoopNumIterations().size();
7842e5dd7070Spatrick I < E; ++I) {
7843e5dd7070Spatrick if (const auto *VD = dyn_cast<OMPCapturedExprDecl>(
7844e5dd7070Spatrick cast<DeclRefExpr>(C->getLoopCounter(I))->getDecl())) {
7845e5dd7070Spatrick // Emit only those that were not explicitly referenced in clauses.
7846e5dd7070Spatrick if (!CGF.LocalDeclMap.count(VD))
7847e5dd7070Spatrick CGF.EmitVarDecl(*VD);
7848e5dd7070Spatrick }
7849e5dd7070Spatrick }
7850e5dd7070Spatrick }
7851e5dd7070Spatrick }
7852ec727ea7Spatrick (void)GlobalsScope.Privatize();
7853e5dd7070Spatrick CGF.EmitStmt(D.getInnermostCapturedStmt()->getCapturedStmt());
7854e5dd7070Spatrick }
7855e5dd7070Spatrick };
7856a9ac8606Spatrick if (D.getDirectiveKind() == OMPD_atomic ||
7857a9ac8606Spatrick D.getDirectiveKind() == OMPD_critical ||
7858a9ac8606Spatrick D.getDirectiveKind() == OMPD_section ||
7859a9ac8606Spatrick D.getDirectiveKind() == OMPD_master ||
7860a9ac8606Spatrick D.getDirectiveKind() == OMPD_masked) {
7861a9ac8606Spatrick EmitStmt(D.getAssociatedStmt());
7862a9ac8606Spatrick } else {
7863ec727ea7Spatrick auto LPCRegion =
7864ec727ea7Spatrick CGOpenMPRuntime::LastprivateConditionalRAII::disable(*this, D);
7865e5dd7070Spatrick OMPSimdLexicalScope Scope(*this, D);
7866e5dd7070Spatrick CGM.getOpenMPRuntime().emitInlinedDirective(
7867e5dd7070Spatrick *this,
7868e5dd7070Spatrick isOpenMPSimdDirective(D.getDirectiveKind()) ? OMPD_simd
7869e5dd7070Spatrick : D.getDirectiveKind(),
7870e5dd7070Spatrick CodeGen);
7871e5dd7070Spatrick }
7872ec727ea7Spatrick // Check for outer lastprivate conditional update.
7873ec727ea7Spatrick checkForLastprivateConditionalUpdate(*this, D);
7874ec727ea7Spatrick }
7875