Thanks to visit codestin.com
Credit goes to clang.llvm.org

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