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