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