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 llvm::Function *OutlinedFn =
1627 CGF, S, *CS->getCapturedDecl()->param_begin(), InnermostKind,
1628 CodeGen);
1629 if (const auto *NumThreadsClause = S.getSingleClause<OMPNumThreadsClause>()) {
1630 CodeGenFunction::RunCleanupsScope NumThreadsScope(CGF);
1631 NumThreads = CGF.EmitScalarExpr(NumThreadsClause->getNumThreads(),
1632 /*IgnoreResultAssign=*/true);
1633 Modifier = NumThreadsClause->getModifier();
1634 if (const auto *MessageClause = S.getSingleClause<OMPMessageClause>())
1635 Message = MessageClause->getMessageString();
1636 if (const auto *SeverityClause = S.getSingleClause<OMPSeverityClause>())
1637 Severity = SeverityClause->getSeverityKind();
1639 CGF, NumThreads, NumThreadsClause->getBeginLoc(), Modifier, Severity,
1640 Message);
1641 }
1642 if (const auto *ProcBindClause = S.getSingleClause<OMPProcBindClause>()) {
1643 CodeGenFunction::RunCleanupsScope ProcBindScope(CGF);
1645 CGF, ProcBindClause->getProcBindKind(), ProcBindClause->getBeginLoc());
1646 }
1647 const Expr *IfCond = nullptr;
1648 for (const auto *C : S.getClausesOfKind<OMPIfClause>()) {
1649 if (C->getNameModifier() == OMPD_unknown ||
1650 C->getNameModifier() == OMPD_parallel) {
1651 IfCond = C->getCondition();
1652 break;
1653 }
1654 }
1655
1656 OMPParallelScope Scope(CGF, S);
1658 // Combining 'distribute' with 'for' requires sharing each 'distribute' chunk
1659 // lower and upper bounds with the pragma 'for' chunking mechanism.
1660 // The following lambda takes care of appending the lower and upper bound
1661 // parameters when necessary
1662 CodeGenBoundParameters(CGF, S, CapturedVars);
1663 CGF.GenerateOpenMPCapturedVars(*CS, CapturedVars);
1664 CGF.CGM.getOpenMPRuntime().emitParallelCall(CGF, S.getBeginLoc(), OutlinedFn,
1665 CapturedVars, IfCond, NumThreads,
1666 Modifier, Severity, Message);
1667}
1668
1669static bool isAllocatableDecl(const VarDecl *VD) {
1670 const VarDecl *CVD = VD->getCanonicalDecl();
1671 if (!CVD->hasAttr<OMPAllocateDeclAttr>())
1672 return false;
1673 const auto *AA = CVD->getAttr<OMPAllocateDeclAttr>();
1674 // Use the default allocation.
1675 return !((AA->getAllocatorType() == OMPAllocateDeclAttr::OMPDefaultMemAlloc ||
1676 AA->getAllocatorType() == OMPAllocateDeclAttr::OMPNullMemAlloc) &&
1677 !AA->getAllocator());
1678}
1679
1683
1685 const OMPExecutableDirective &S) {
1686 bool Copyins = CGF.EmitOMPCopyinClause(S);
1687 if (Copyins) {
1688 // Emit implicit barrier to synchronize threads and avoid data races on
1689 // propagation master's thread values of threadprivate variables to local
1690 // instances of that variables of all other implicit threads.
1692 CGF, S.getBeginLoc(), OMPD_unknown, /*EmitChecks=*/false,
1693 /*ForceSimpleCall=*/true);
1694 }
1695}
1696
1698 CodeGenFunction &CGF, const VarDecl *VD) {
1699 CodeGenModule &CGM = CGF.CGM;
1700 auto &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
1701
1702 if (!VD)
1703 return Address::invalid();
1704 const VarDecl *CVD = VD->getCanonicalDecl();
1705 if (!isAllocatableDecl(CVD))
1706 return Address::invalid();
1707 llvm::Value *Size;
1708 CharUnits Align = CGM.getContext().getDeclAlign(CVD);
1709 if (CVD->getType()->isVariablyModifiedType()) {
1710 Size = CGF.getTypeSize(CVD->getType());
1711 // Align the size: ((size + align - 1) / align) * align
1712 Size = CGF.Builder.CreateNUWAdd(
1713 Size, CGM.getSize(Align - CharUnits::fromQuantity(1)));
1714 Size = CGF.Builder.CreateUDiv(Size, CGM.getSize(Align));
1715 Size = CGF.Builder.CreateNUWMul(Size, CGM.getSize(Align));
1716 } else {
1717 CharUnits Sz = CGM.getContext().getTypeSizeInChars(CVD->getType());
1718 Size = CGM.getSize(Sz.alignTo(Align));
1719 }
1720
1721 const auto *AA = CVD->getAttr<OMPAllocateDeclAttr>();
1722 assert(AA->getAllocator() &&
1723 "Expected allocator expression for non-default allocator.");
1724 llvm::Value *Allocator = CGF.EmitScalarExpr(AA->getAllocator());
1725 // According to the standard, the original allocator type is a enum (integer).
1726 // Convert to pointer type, if required.
1727 if (Allocator->getType()->isIntegerTy())
1728 Allocator = CGF.Builder.CreateIntToPtr(Allocator, CGM.VoidPtrTy);
1729 else if (Allocator->getType()->isPointerTy())
1730 Allocator = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(Allocator,
1731 CGM.VoidPtrTy);
1732
1733 llvm::Value *Addr = OMPBuilder.createOMPAlloc(
1734 CGF.Builder, Size, Allocator,
1735 getNameWithSeparators({CVD->getName(), ".void.addr"}, ".", "."));
1736 llvm::CallInst *FreeCI =
1737 OMPBuilder.createOMPFree(CGF.Builder, Addr, Allocator);
1738
1739 CGF.EHStack.pushCleanup<OMPAllocateCleanupTy>(NormalAndEHCleanup, FreeCI);
1741 Addr,
1742 CGF.ConvertTypeForMem(CGM.getContext().getPointerType(CVD->getType())),
1743 getNameWithSeparators({CVD->getName(), ".addr"}, ".", "."));
1744 return Address(Addr, CGF.ConvertTypeForMem(CVD->getType()), Align);
1745}
1746
1748 CodeGenFunction &CGF, const VarDecl *VD, Address VDAddr,
1749 SourceLocation Loc) {
1750 CodeGenModule &CGM = CGF.CGM;
1751 if (CGM.getLangOpts().OpenMPUseTLS &&
1752 CGM.getContext().getTargetInfo().isTLSSupported())
1753 return VDAddr;
1754
1755 llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
1756
1757 llvm::Type *VarTy = VDAddr.getElementType();
1758 llvm::Value *Data =
1759 CGF.Builder.CreatePointerCast(VDAddr.emitRawPointer(CGF), CGM.Int8PtrTy);
1760 llvm::ConstantInt *Size = CGM.getSize(CGM.GetTargetTypeStoreSize(VarTy));
1761 std::string Suffix = getNameWithSeparators({"cache", ""});
1762 llvm::Twine CacheName = Twine(CGM.getMangledName(VD)).concat(Suffix);
1763
1764 llvm::CallInst *ThreadPrivateCacheCall =
1765 OMPBuilder.createCachedThreadPrivate(CGF.Builder, Data, Size, CacheName);
1766
1767 return Address(ThreadPrivateCacheCall, CGM.Int8Ty, VDAddr.getAlignment());
1768}
1769
1771 ArrayRef<StringRef> Parts, StringRef FirstSeparator, StringRef Separator) {
1772 SmallString<128> Buffer;
1773 llvm::raw_svector_ostream OS(Buffer);
1774 StringRef Sep = FirstSeparator;
1775 for (StringRef Part : Parts) {
1776 OS << Sep << Part;
1777 Sep = Separator;
1778 }
1779 return OS.str().str();
1780}
1781
1783 CodeGenFunction &CGF, const Stmt *RegionBodyStmt, InsertPointTy AllocaIP,
1784 InsertPointTy CodeGenIP, Twine RegionName) {
1786 Builder.restoreIP(CodeGenIP);
1787 llvm::BasicBlock *FiniBB = splitBBWithSuffix(Builder, /*CreateBranch=*/false,
1788 "." + RegionName + ".after");
1789
1790 {
1791 OMPBuilderCBHelpers::InlinedRegionBodyRAII IRB(CGF, AllocaIP, *FiniBB);
1792 CGF.EmitStmt(RegionBodyStmt);
1793 }
1794
1795 if (Builder.saveIP().isSet())
1796 Builder.CreateBr(FiniBB);
1797}
1798
1800 CodeGenFunction &CGF, const Stmt *RegionBodyStmt, InsertPointTy AllocaIP,
1801 InsertPointTy CodeGenIP, Twine RegionName) {
1803 Builder.restoreIP(CodeGenIP);
1804 llvm::BasicBlock *FiniBB = splitBBWithSuffix(Builder, /*CreateBranch=*/false,
1805 "." + RegionName + ".after");
1806
1807 {
1808 OMPBuilderCBHelpers::OutlinedRegionBodyRAII IRB(CGF, AllocaIP, *FiniBB);
1809 CGF.EmitStmt(RegionBodyStmt);
1810 }
1811
1812 if (Builder.saveIP().isSet())
1813 Builder.CreateBr(FiniBB);
1814}
1815
1816void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) {
1817 if (CGM.getLangOpts().OpenMPIRBuilder) {
1818 llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
1819 // Check if we have any if clause associated with the directive.
1820 llvm::Value *IfCond = nullptr;
1821 if (const auto *C = S.getSingleClause<OMPIfClause>())
1822 IfCond = EmitScalarExpr(C->getCondition(),
1823 /*IgnoreResultAssign=*/true);
1824
1825 llvm::Value *NumThreads = nullptr;
1826 if (const auto *NumThreadsClause = S.getSingleClause<OMPNumThreadsClause>())
1827 NumThreads = EmitScalarExpr(NumThreadsClause->getNumThreads(),
1828 /*IgnoreResultAssign=*/true);
1829
1830 ProcBindKind ProcBind = OMP_PROC_BIND_default;
1831 if (const auto *ProcBindClause = S.getSingleClause<OMPProcBindClause>())
1832 ProcBind = ProcBindClause->getProcBindKind();
1833
1834 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
1835
1836 // The cleanup callback that finalizes all variables at the given location,
1837 // thus calls destructors etc.
1838 auto FiniCB = [this](InsertPointTy IP) {
1840 return llvm::Error::success();
1841 };
1842
1843 // Privatization callback that performs appropriate action for
1844 // shared/private/firstprivate/lastprivate/copyin/... variables.
1845 //
1846 // TODO: This defaults to shared right now.
1847 auto PrivCB = [](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
1848 llvm::Value &, llvm::Value &Val, llvm::Value *&ReplVal) {
1849 // The next line is appropriate only for variables (Val) with the
1850 // data-sharing attribute "shared".
1851 ReplVal = &Val;
1852
1853 return CodeGenIP;
1854 };
1855
1856 const CapturedStmt *CS = S.getCapturedStmt(OMPD_parallel);
1857 const Stmt *ParallelRegionBodyStmt = CS->getCapturedStmt();
1858
1859 auto BodyGenCB = [&, this](InsertPointTy AllocaIP,
1860 InsertPointTy CodeGenIP) {
1862 *this, ParallelRegionBodyStmt, AllocaIP, CodeGenIP, "parallel");
1863 return llvm::Error::success();
1864 };
1865
1866 CGCapturedStmtInfo CGSI(*CS, CR_OpenMP);
1867 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(*this, &CGSI);
1868 llvm::OpenMPIRBuilder::InsertPointTy AllocaIP(
1869 AllocaInsertPt->getParent(), AllocaInsertPt->getIterator());
1870 llvm::OpenMPIRBuilder::InsertPointTy AfterIP = cantFail(
1871 OMPBuilder.createParallel(Builder, AllocaIP, BodyGenCB, PrivCB, FiniCB,
1872 IfCond, NumThreads, ProcBind, S.hasCancel()));
1873 Builder.restoreIP(AfterIP);
1874 return;
1875 }
1876
1877 // Emit parallel region as a standalone region.
1878 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
1879 Action.Enter(CGF);
1880 OMPPrivateScope PrivateScope(CGF);
1881 emitOMPCopyinClause(CGF, S);
1882 (void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
1883 CGF.EmitOMPPrivateClause(S, PrivateScope);
1884 CGF.EmitOMPReductionClauseInit(S, PrivateScope);
1885 (void)PrivateScope.Privatize();
1886 CGF.EmitStmt(S.getCapturedStmt(OMPD_parallel)->getCapturedStmt());
1887 CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_parallel);
1888 };
1889 {
1890 auto LPCRegion =
1892 emitCommonOMPParallelDirective(*this, S, OMPD_parallel, CodeGen,
1895 [](CodeGenFunction &) { return nullptr; });
1896 }
1897 // Check for outer lastprivate conditional update.
1899}
1900
1904
1905namespace {
1906/// RAII to handle scopes for loop transformation directives.
1907class OMPTransformDirectiveScopeRAII {
1908 OMPLoopScope *Scope = nullptr;
1910 CodeGenFunction::CGCapturedStmtRAII *CapInfoRAII = nullptr;
1911
1912 OMPTransformDirectiveScopeRAII(const OMPTransformDirectiveScopeRAII &) =
1913 delete;
1914 OMPTransformDirectiveScopeRAII &
1915 operator=(const OMPTransformDirectiveScopeRAII &) = delete;
1916
1917public:
1918 OMPTransformDirectiveScopeRAII(CodeGenFunction &CGF, const Stmt *S) {
1919 if (const auto *Dir = dyn_cast<OMPLoopBasedDirective>(S)) {
1920 Scope = new OMPLoopScope(CGF, *Dir);
1922 CapInfoRAII = new CodeGenFunction::CGCapturedStmtRAII(CGF, CGSI);
1923 }
1924 }
1925 ~OMPTransformDirectiveScopeRAII() {
1926 if (!Scope)
1927 return;
1928 delete CapInfoRAII;
1929 delete CGSI;
1930 delete Scope;
1931 }
1932};
1933} // namespace
1934
1935static void emitBody(CodeGenFunction &CGF, const Stmt *S, const Stmt *NextLoop,
1936 int MaxLevel, int Level = 0) {
1937 assert(Level < MaxLevel && "Too deep lookup during loop body codegen.");
1938 const Stmt *SimplifiedS = S->IgnoreContainers();
1939 if (const auto *CS = dyn_cast<CompoundStmt>(SimplifiedS)) {
1940 PrettyStackTraceLoc CrashInfo(
1941 CGF.getContext().getSourceManager(), CS->getLBracLoc(),
1942 "LLVM IR generation of compound statement ('{}')");
1943
1944 // Keep track of the current cleanup stack depth, including debug scopes.
1946 for (const Stmt *CurStmt : CS->body())
1947 emitBody(CGF, CurStmt, NextLoop, MaxLevel, Level);
1948 return;
1949 }
1950 if (SimplifiedS == NextLoop) {
1951 if (auto *Dir =
1952 dyn_cast<OMPCanonicalLoopNestTransformationDirective>(SimplifiedS))
1953 SimplifiedS = Dir->getTransformedStmt();
1954 if (const auto *CanonLoop = dyn_cast<OMPCanonicalLoop>(SimplifiedS))
1955 SimplifiedS = CanonLoop->getLoopStmt();
1956 if (const auto *For = dyn_cast<ForStmt>(SimplifiedS)) {
1957 S = For->getBody();
1958 } else {
1959 assert(isa<CXXForRangeStmt>(SimplifiedS) &&
1960 "Expected canonical for loop or range-based for loop.");
1961 const auto *CXXFor = cast<CXXForRangeStmt>(SimplifiedS);
1962 CGF.EmitStmt(CXXFor->getLoopVarStmt());
1963 S = CXXFor->getBody();
1964 }
1965 if (Level + 1 < MaxLevel) {
1966 NextLoop = OMPLoopDirective::tryToFindNextInnerLoop(
1967 S, /*TryImperfectlyNestedLoops=*/true);
1968 emitBody(CGF, S, NextLoop, MaxLevel, Level + 1);
1969 return;
1970 }
1971 }
1972 CGF.EmitStmt(S);
1973}
1974
1977 RunCleanupsScope BodyScope(*this);
1978 // Update counters values on current iteration.
1979 for (const Expr *UE : D.updates())
1980 EmitIgnoredExpr(UE);
1981 // Update the linear variables.
1982 // In distribute directives only loop counters may be marked as linear, no
1983 // need to generate the code for them.
1985 if (!isOpenMPDistributeDirective(EKind)) {
1986 for (const auto *C : D.getClausesOfKind<OMPLinearClause>()) {
1987 for (const Expr *UE : C->updates())
1988 EmitIgnoredExpr(UE);
1989 }
1990 }
1991
1992 // On a continue in the body, jump to the end.
1993 JumpDest Continue = getJumpDestInCurrentScope("omp.body.continue");
1994 BreakContinueStack.push_back(BreakContinue(D, LoopExit, Continue));
1995 for (const Expr *E : D.finals_conditions()) {
1996 if (!E)
1997 continue;
1998 // Check that loop counter in non-rectangular nest fits into the iteration
1999 // space.
2000 llvm::BasicBlock *NextBB = createBasicBlock("omp.body.next");
2001 EmitBranchOnBoolExpr(E, NextBB, Continue.getBlock(),
2002 getProfileCount(D.getBody()));
2003 EmitBlock(NextBB);
2004 }
2005
2006 OMPPrivateScope InscanScope(*this);
2007 EmitOMPReductionClauseInit(D, InscanScope, /*ForInscan=*/true);
2008 bool IsInscanRegion = InscanScope.Privatize();
2009 if (IsInscanRegion) {
2010 // Need to remember the block before and after scan directive
2011 // to dispatch them correctly depending on the clause used in
2012 // this directive, inclusive or exclusive. For inclusive scan the natural
2013 // order of the blocks is used, for exclusive clause the blocks must be
2014 // executed in reverse order.
2015 OMPBeforeScanBlock = createBasicBlock("omp.before.scan.bb");
2016 OMPAfterScanBlock = createBasicBlock("omp.after.scan.bb");
2017 // No need to allocate inscan exit block, in simd mode it is selected in the
2018 // codegen for the scan directive.
2019 if (EKind != OMPD_simd && !getLangOpts().OpenMPSimd)
2020 OMPScanExitBlock = createBasicBlock("omp.exit.inscan.bb");
2021 OMPScanDispatch = createBasicBlock("omp.inscan.dispatch");
2024 }
2025
2026 // Emit loop variables for C++ range loops.
2027 const Stmt *Body =
2028 D.getInnermostCapturedStmt()->getCapturedStmt()->IgnoreContainers();
2029 // Emit loop body.
2030 emitBody(*this, Body,
2031 OMPLoopBasedDirective::tryToFindNextInnerLoop(
2032 Body, /*TryImperfectlyNestedLoops=*/true),
2033 D.getLoopsNumber());
2034
2035 // Jump to the dispatcher at the end of the loop body.
2036 if (IsInscanRegion)
2038
2039 // The end (updates/cleanups).
2040 EmitBlock(Continue.getBlock());
2041 BreakContinueStack.pop_back();
2042}
2043
2044using EmittedClosureTy = std::pair<llvm::Function *, llvm::Value *>;
2045
2046/// Emit a captured statement and return the function as well as its captured
2047/// closure context.
2049 const CapturedStmt *S) {
2050 LValue CapStruct = ParentCGF.InitCapturedStruct(*S);
2051 CodeGenFunction CGF(ParentCGF.CGM, /*suppressNewContext=*/true);
2052 std::unique_ptr<CodeGenFunction::CGCapturedStmtInfo> CSI =
2053 std::make_unique<CodeGenFunction::CGCapturedStmtInfo>(*S);
2054 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, CSI.get());
2055 llvm::Function *F = CGF.GenerateCapturedStmtFunction(*S);
2056
2057 return {F, CapStruct.getPointer(ParentCGF)};
2058}
2059
2060/// Emit a call to a previously captured closure.
2061static llvm::CallInst *
2064 // Append the closure context to the argument.
2065 SmallVector<llvm::Value *> EffectiveArgs;
2066 EffectiveArgs.reserve(Args.size() + 1);
2067 llvm::append_range(EffectiveArgs, Args);
2068 EffectiveArgs.push_back(Cap.second);
2069
2070 return ParentCGF.Builder.CreateCall(Cap.first, EffectiveArgs);
2071}
2072
2073llvm::CanonicalLoopInfo *
2075 assert(Depth == 1 && "Nested loops with OpenMPIRBuilder not yet implemented");
2076
2077 // The caller is processing the loop-associated directive processing the \p
2078 // Depth loops nested in \p S. Put the previous pending loop-associated
2079 // directive to the stack. If the current loop-associated directive is a loop
2080 // transformation directive, it will push its generated loops onto the stack
2081 // such that together with the loops left here they form the combined loop
2082 // nest for the parent loop-associated directive.
2083 int ParentExpectedOMPLoopDepth = ExpectedOMPLoopDepth;
2084 ExpectedOMPLoopDepth = Depth;
2085
2086 EmitStmt(S);
2087 assert(OMPLoopNestStack.size() >= (size_t)Depth && "Found too few loops");
2088
2089 // The last added loop is the outermost one.
2090 llvm::CanonicalLoopInfo *Result = OMPLoopNestStack.back();
2091
2092 // Pop the \p Depth loops requested by the call from that stack and restore
2093 // the previous context.
2094 OMPLoopNestStack.pop_back_n(Depth);
2095 ExpectedOMPLoopDepth = ParentExpectedOMPLoopDepth;
2096
2097 return Result;
2098}
2099
2100void CodeGenFunction::EmitOMPCanonicalLoop(const OMPCanonicalLoop *S) {
2101 const Stmt *SyntacticalLoop = S->getLoopStmt();
2102 if (!getLangOpts().OpenMPIRBuilder) {
2103 // Ignore if OpenMPIRBuilder is not enabled.
2104 EmitStmt(SyntacticalLoop);
2105 return;
2106 }
2107
2108 LexicalScope ForScope(*this, S->getSourceRange());
2109
2110 // Emit init statements. The Distance/LoopVar funcs may reference variable
2111 // declarations they contain.
2112 const Stmt *BodyStmt;
2113 if (const auto *For = dyn_cast<ForStmt>(SyntacticalLoop)) {
2114 if (const Stmt *InitStmt = For->getInit())
2115 EmitStmt(InitStmt);
2116 BodyStmt = For->getBody();
2117 } else if (const auto *RangeFor =
2118 dyn_cast<CXXForRangeStmt>(SyntacticalLoop)) {
2119 if (const DeclStmt *RangeStmt = RangeFor->getRangeStmt())
2120 EmitStmt(RangeStmt);
2121 if (const DeclStmt *BeginStmt = RangeFor->getBeginStmt())
2122 EmitStmt(BeginStmt);
2123 if (const DeclStmt *EndStmt = RangeFor->getEndStmt())
2124 EmitStmt(EndStmt);
2125 if (const DeclStmt *LoopVarStmt = RangeFor->getLoopVarStmt())
2126 EmitStmt(LoopVarStmt);
2127 BodyStmt = RangeFor->getBody();
2128 } else
2129 llvm_unreachable("Expected for-stmt or range-based for-stmt");
2130
2131 // Emit closure for later use. By-value captures will be captured here.
2132 const CapturedStmt *DistanceFunc = S->getDistanceFunc();
2133 EmittedClosureTy DistanceClosure = emitCapturedStmtFunc(*this, DistanceFunc);
2134 const CapturedStmt *LoopVarFunc = S->getLoopVarFunc();
2135 EmittedClosureTy LoopVarClosure = emitCapturedStmtFunc(*this, LoopVarFunc);
2136
2137 // Call the distance function to get the number of iterations of the loop to
2138 // come.
2139 QualType LogicalTy = DistanceFunc->getCapturedDecl()
2140 ->getParam(0)
2141 ->getType()
2143 RawAddress CountAddr = CreateMemTemp(LogicalTy, ".count.addr");
2144 emitCapturedStmtCall(*this, DistanceClosure, {CountAddr.getPointer()});
2145 llvm::Value *DistVal = Builder.CreateLoad(CountAddr, ".count");
2146
2147 // Emit the loop structure.
2148 llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
2149 auto BodyGen = [&, this](llvm::OpenMPIRBuilder::InsertPointTy CodeGenIP,
2150 llvm::Value *IndVar) {
2151 Builder.restoreIP(CodeGenIP);
2152
2153 // Emit the loop body: Convert the logical iteration number to the loop
2154 // variable and emit the body.
2155 const DeclRefExpr *LoopVarRef = S->getLoopVarRef();
2156 LValue LCVal = EmitLValue(LoopVarRef);
2157 Address LoopVarAddress = LCVal.getAddress();
2158 emitCapturedStmtCall(*this, LoopVarClosure,
2159 {LoopVarAddress.emitRawPointer(*this), IndVar});
2160
2161 RunCleanupsScope BodyScope(*this);
2162 EmitStmt(BodyStmt);
2163 return llvm::Error::success();
2164 };
2165
2166 llvm::CanonicalLoopInfo *CL =
2167 cantFail(OMPBuilder.createCanonicalLoop(Builder, BodyGen, DistVal));
2168
2169 // Finish up the loop.
2170 Builder.restoreIP(CL->getAfterIP());
2171 ForScope.ForceCleanup();
2172
2173 // Remember the CanonicalLoopInfo for parent AST nodes consuming it.
2174 OMPLoopNestStack.push_back(CL);
2175}
2176
2178 const OMPExecutableDirective &S, bool RequiresCleanup, const Expr *LoopCond,
2179 const Expr *IncExpr,
2180 const llvm::function_ref<void(CodeGenFunction &)> BodyGen,
2181 const llvm::function_ref<void(CodeGenFunction &)> PostIncGen) {
2182 auto LoopExit = getJumpDestInCurrentScope("omp.inner.for.end");
2183
2184 // Start the loop with a block that tests the condition.
2185 auto CondBlock = createBasicBlock("omp.inner.for.cond");
2186 EmitBlock(CondBlock);
2187 const SourceRange R = S.getSourceRange();
2188
2189 // If attributes are attached, push to the basic block with them.
2190 const auto &OMPED = cast<OMPExecutableDirective>(S);
2191 const CapturedStmt *ICS = OMPED.getInnermostCapturedStmt();
2192 const Stmt *SS = ICS->getCapturedStmt();
2193 const AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(SS);
2194 OMPLoopNestStack.clear();
2195 if (AS)
2196 LoopStack.push(CondBlock, CGM.getContext(), CGM.getCodeGenOpts(),
2199 else
2200 LoopStack.push(CondBlock, SourceLocToDebugLoc(R.getBegin()),
2202
2203 // If there are any cleanups between here and the loop-exit scope,
2204 // create a block to stage a loop exit along.
2205 llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
2206 if (RequiresCleanup)
2207 ExitBlock = createBasicBlock("omp.inner.for.cond.cleanup");
2208
2209 llvm::BasicBlock *LoopBody = createBasicBlock("omp.inner.for.body");
2210
2211 // Emit condition.
2212 EmitBranchOnBoolExpr(LoopCond, LoopBody, ExitBlock, getProfileCount(&S));
2213 if (ExitBlock != LoopExit.getBlock()) {
2214 EmitBlock(ExitBlock);
2216 }
2217
2218 EmitBlock(LoopBody);
2220
2221 // Create a block for the increment.
2222 JumpDest Continue = getJumpDestInCurrentScope("omp.inner.for.inc");
2223 BreakContinueStack.push_back(BreakContinue(S, LoopExit, Continue));
2224
2225 BodyGen(*this);
2226
2227 // Emit "IV = IV + 1" and a back-edge to the condition block.
2228 EmitBlock(Continue.getBlock());
2229 EmitIgnoredExpr(IncExpr);
2230 PostIncGen(*this);
2231 BreakContinueStack.pop_back();
2232 EmitBranch(CondBlock);
2233 LoopStack.pop();
2234 // Emit the fall-through block.
2235 EmitBlock(LoopExit.getBlock());
2236}
2237
2239 if (!HaveInsertPoint())
2240 return false;
2241 // Emit inits for the linear variables.
2242 bool HasLinears = false;
2243 for (const auto *C : D.getClausesOfKind<OMPLinearClause>()) {
2244 for (const Expr *Init : C->inits()) {
2245 HasLinears = true;
2246 const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(Init)->getDecl());
2247 if (const auto *Ref =
2248 dyn_cast<DeclRefExpr>(VD->getInit()->IgnoreImpCasts())) {
2249 AutoVarEmission Emission = EmitAutoVarAlloca(*VD);
2250 const auto *OrigVD = cast<VarDecl>(Ref->getDecl());
2251 DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(OrigVD),
2252 CapturedStmtInfo->lookup(OrigVD) != nullptr,
2253 VD->getInit()->getType(), VK_LValue,
2254 VD->getInit()->getExprLoc());
2256 &DRE, VD,
2257 MakeAddrLValue(Emission.getAllocatedAddress(), VD->getType()),
2258 /*capturedByInit=*/false);
2259 EmitAutoVarCleanups(Emission);
2260 } else {
2261 EmitVarDecl(*VD);
2262 }
2263 }
2264 // Emit the linear steps for the linear clauses.
2265 // If a step is not constant, it is pre-calculated before the loop.
2266 if (const auto *CS = cast_or_null<BinaryOperator>(C->getCalcStep()))
2267 if (const auto *SaveRef = cast<DeclRefExpr>(CS->getLHS())) {
2268 EmitVarDecl(*cast<VarDecl>(SaveRef->getDecl()));
2269 // Emit calculation of the linear step.
2270 EmitIgnoredExpr(CS);
2271 }
2272 }
2273 return HasLinears;
2274}
2275
2277 const OMPLoopDirective &D,
2278 const llvm::function_ref<llvm::Value *(CodeGenFunction &)> CondGen) {
2279 if (!HaveInsertPoint())
2280 return;
2281 llvm::BasicBlock *DoneBB = nullptr;
2282 // Emit the final values of the linear variables.
2283 for (const auto *C : D.getClausesOfKind<OMPLinearClause>()) {
2284 auto IC = C->varlist_begin();
2285 for (const Expr *F : C->finals()) {
2286 if (!DoneBB) {
2287 if (llvm::Value *Cond = CondGen(*this)) {
2288 // If the first post-update expression is found, emit conditional
2289 // block if it was requested.
2290 llvm::BasicBlock *ThenBB = createBasicBlock(".omp.linear.pu");
2291 DoneBB = createBasicBlock(".omp.linear.pu.done");
2292 Builder.CreateCondBr(Cond, ThenBB, DoneBB);
2293 EmitBlock(ThenBB);
2294 }
2295 }
2296 const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IC)->getDecl());
2297 DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(OrigVD),
2298 CapturedStmtInfo->lookup(OrigVD) != nullptr,
2299 (*IC)->getType(), VK_LValue, (*IC)->getExprLoc());
2300 Address OrigAddr = EmitLValue(&DRE).getAddress();
2301 CodeGenFunction::OMPPrivateScope VarScope(*this);
2302 VarScope.addPrivate(OrigVD, OrigAddr);
2303 (void)VarScope.Privatize();
2304 EmitIgnoredExpr(F);
2305 ++IC;
2306 }
2307 if (const Expr *PostUpdate = C->getPostUpdateExpr())
2308 EmitIgnoredExpr(PostUpdate);
2309 }
2310 if (DoneBB)
2311 EmitBlock(DoneBB, /*IsFinished=*/true);
2312}
2313
2315 const OMPExecutableDirective &D) {
2316 if (!CGF.HaveInsertPoint())
2317 return;
2318 for (const auto *Clause : D.getClausesOfKind<OMPAlignedClause>()) {
2319 llvm::APInt ClauseAlignment(64, 0);
2320 if (const Expr *AlignmentExpr = Clause->getAlignment()) {
2321 auto *AlignmentCI =
2322 cast<llvm::ConstantInt>(CGF.EmitScalarExpr(AlignmentExpr));
2323 ClauseAlignment = AlignmentCI->getValue();
2324 }
2325 for (const Expr *E : Clause->varlist()) {
2326 llvm::APInt Alignment(ClauseAlignment);
2327 if (Alignment == 0) {
2328 // OpenMP [2.8.1, Description]
2329 // If no optional parameter is specified, implementation-defined default
2330 // alignments for SIMD instructions on the target platforms are assumed.
2331 Alignment =
2332 CGF.getContext()
2334 E->getType()->getPointeeType()))
2335 .getQuantity();
2336 }
2337 assert((Alignment == 0 || Alignment.isPowerOf2()) &&
2338 "alignment is not power of 2");
2339 if (Alignment != 0) {
2340 llvm::Value *PtrValue = CGF.EmitScalarExpr(E);
2342 PtrValue, E, /*No second loc needed*/ SourceLocation(),
2343 llvm::ConstantInt::get(CGF.getLLVMContext(), Alignment));
2344 }
2345 }
2346 }
2347}
2348
2351 if (!HaveInsertPoint())
2352 return;
2353 auto I = S.private_counters().begin();
2354 for (const Expr *E : S.counters()) {
2355 const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
2356 const auto *PrivateVD = cast<VarDecl>(cast<DeclRefExpr>(*I)->getDecl());
2357 // Emit var without initialization.
2358 AutoVarEmission VarEmission = EmitAutoVarAlloca(*PrivateVD);
2359 EmitAutoVarCleanups(VarEmission);
2360 LocalDeclMap.erase(PrivateVD);
2361 (void)LoopScope.addPrivate(VD, VarEmission.getAllocatedAddress());
2362 if (LocalDeclMap.count(VD) || CapturedStmtInfo->lookup(VD) ||
2363 VD->hasGlobalStorage()) {
2364 DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(VD),
2365 LocalDeclMap.count(VD) || CapturedStmtInfo->lookup(VD),
2366 E->getType(), VK_LValue, E->getExprLoc());
2367 (void)LoopScope.addPrivate(PrivateVD, EmitLValue(&DRE).getAddress());
2368 } else {
2369 (void)LoopScope.addPrivate(PrivateVD, VarEmission.getAllocatedAddress());
2370 }
2371 ++I;
2372 }
2373 // Privatize extra loop counters used in loops for ordered(n) clauses.
2374 for (const auto *C : S.getClausesOfKind<OMPOrderedClause>()) {
2375 if (!C->getNumForLoops())
2376 continue;
2377 for (unsigned I = S.getLoopsNumber(), E = C->getLoopNumIterations().size();
2378 I < E; ++I) {
2379 const auto *DRE = cast<DeclRefExpr>(C->getLoopCounter(I));
2380 const auto *VD = cast<VarDecl>(DRE->getDecl());
2381 // Override only those variables that can be captured to avoid re-emission
2382 // of the variables declared within the loops.
2383 if (DRE->refersToEnclosingVariableOrCapture()) {
2384 (void)LoopScope.addPrivate(
2385 VD, CreateMemTemp(DRE->getType(), VD->getName()));
2386 }
2387 }
2388 }
2389}
2390
2392 const Expr *Cond, llvm::BasicBlock *TrueBlock,
2393 llvm::BasicBlock *FalseBlock, uint64_t TrueCount) {
2394 if (!CGF.HaveInsertPoint())
2395 return;
2396 {
2397 CodeGenFunction::OMPPrivateScope PreCondScope(CGF);
2398 CGF.EmitOMPPrivateLoopCounters(S, PreCondScope);
2399 (void)PreCondScope.Privatize();
2400 // Get initial values of real counters.
2401 for (const Expr *I : S.inits()) {
2402 CGF.EmitIgnoredExpr(I);
2403 }
2404 }
2405 // Create temp loop control variables with their init values to support
2406 // non-rectangular loops.
2407 CodeGenFunction::OMPMapVars PreCondVars;
2408 for (const Expr *E : S.dependent_counters()) {
2409 if (!E)
2410 continue;
2411 assert(!E->getType().getNonReferenceType()->isRecordType() &&
2412 "dependent counter must not be an iterator.");
2413 const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
2414 Address CounterAddr =
2416 (void)PreCondVars.setVarAddr(CGF, VD, CounterAddr);
2417 }
2418 (void)PreCondVars.apply(CGF);
2419 for (const Expr *E : S.dependent_inits()) {
2420 if (!E)
2421 continue;
2422 CGF.EmitIgnoredExpr(E);
2423 }
2424 // Check that loop is executed at least one time.
2425 CGF.EmitBranchOnBoolExpr(Cond, TrueBlock, FalseBlock, TrueCount);
2426 PreCondVars.restore(CGF);
2427}
2428
2430 const OMPLoopDirective &D, CodeGenFunction::OMPPrivateScope &PrivateScope) {
2431 if (!HaveInsertPoint())
2432 return;
2433 llvm::DenseSet<const VarDecl *> SIMDLCVs;
2435 if (isOpenMPSimdDirective(EKind)) {
2436 const auto *LoopDirective = cast<OMPLoopDirective>(&D);
2437 for (const Expr *C : LoopDirective->counters()) {
2438 SIMDLCVs.insert(
2440 }
2441 }
2442 for (const auto *C : D.getClausesOfKind<OMPLinearClause>()) {
2443 auto CurPrivate = C->privates().begin();
2444 for (const Expr *E : C->varlist()) {
2445 const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
2446 const auto *PrivateVD =
2447 cast<VarDecl>(cast<DeclRefExpr>(*CurPrivate)->getDecl());
2448 if (!SIMDLCVs.count(VD->getCanonicalDecl())) {
2449 // Emit private VarDecl with copy init.
2450 EmitVarDecl(*PrivateVD);
2451 bool IsRegistered =
2452 PrivateScope.addPrivate(VD, GetAddrOfLocalVar(PrivateVD));
2453 assert(IsRegistered && "linear var already registered as private");
2454 // Silence the warning about unused variable.
2455 (void)IsRegistered;
2456 } else {
2457 EmitVarDecl(*PrivateVD);
2458 }
2459 ++CurPrivate;
2460 }
2461 }
2462}
2463
2465 const OMPExecutableDirective &D) {
2466 if (!CGF.HaveInsertPoint())
2467 return;
2468 if (const auto *C = D.getSingleClause<OMPSimdlenClause>()) {
2469 RValue Len = CGF.EmitAnyExpr(C->getSimdlen(), AggValueSlot::ignored(),
2470 /*ignoreResult=*/true);
2471 auto *Val = cast<llvm::ConstantInt>(Len.getScalarVal());
2472 CGF.LoopStack.setVectorizeWidth(Val->getZExtValue());
2473 // In presence of finite 'safelen', it may be unsafe to mark all
2474 // the memory instructions parallel, because loop-carried
2475 // dependences of 'safelen' iterations are possible.
2476 CGF.LoopStack.setParallel(!D.getSingleClause<OMPSafelenClause>());
2477 } else if (const auto *C = D.getSingleClause<OMPSafelenClause>()) {
2478 RValue Len = CGF.EmitAnyExpr(C->getSafelen(), AggValueSlot::ignored(),
2479 /*ignoreResult=*/true);
2480 auto *Val = cast<llvm::ConstantInt>(Len.getScalarVal());
2481 CGF.LoopStack.setVectorizeWidth(Val->getZExtValue());
2482 // In presence of finite 'safelen', it may be unsafe to mark all
2483 // the memory instructions parallel, because loop-carried
2484 // dependences of 'safelen' iterations are possible.
2485 CGF.LoopStack.setParallel(/*Enable=*/false);
2486 }
2487}
2488
2489// Check for the presence of an `OMPOrderedDirective`,
2490// i.e., `ordered` in `#pragma omp ordered simd`.
2491//
2492// Consider the following source code:
2493// ```
2494// __attribute__((noinline)) void omp_simd_loop(float X[ARRAY_SIZE][ARRAY_SIZE])
2495// {
2496// for (int r = 1; r < ARRAY_SIZE; ++r) {
2497// for (int c = 1; c < ARRAY_SIZE; ++c) {
2498// #pragma omp simd
2499// for (int k = 2; k < ARRAY_SIZE; ++k) {
2500// #pragma omp ordered simd
2501// X[r][k] = X[r][k - 2] + sinf((float)(r / c));
2502// }
2503// }
2504// }
2505// }
2506// ```
2507//
2508// Suppose we are in `CodeGenFunction::EmitOMPSimdInit(const OMPLoopDirective
2509// &D)`. By examining `D.dump()` we have the following AST containing
2510// `OMPOrderedDirective`:
2511//
2512// ```
2513// OMPSimdDirective 0x1c32950
2514// `-CapturedStmt 0x1c32028
2515// |-CapturedDecl 0x1c310e8
2516// | |-ForStmt 0x1c31e30
2517// | | |-DeclStmt 0x1c31298
2518// | | | `-VarDecl 0x1c31208 used k 'int' cinit
2519// | | | `-IntegerLiteral 0x1c31278 'int' 2
2520// | | |-<<<NULL>>>
2521// | | |-BinaryOperator 0x1c31308 'int' '<'
2522// | | | |-ImplicitCastExpr 0x1c312f0 'int' <LValueToRValue>
2523// | | | | `-DeclRefExpr 0x1c312b0 'int' lvalue Var 0x1c31208 'k' 'int'
2524// | | | `-IntegerLiteral 0x1c312d0 'int' 256
2525// | | |-UnaryOperator 0x1c31348 'int' prefix '++'
2526// | | | `-DeclRefExpr 0x1c31328 'int' lvalue Var 0x1c31208 'k' 'int'
2527// | | `-CompoundStmt 0x1c31e18
2528// | | `-OMPOrderedDirective 0x1c31dd8
2529// | | |-OMPSimdClause 0x1c31380
2530// | | `-CapturedStmt 0x1c31cd0
2531// ```
2532//
2533// Note the presence of `OMPOrderedDirective` above:
2534// It's (transitively) nested in a `CapturedStmt` representing the pragma
2535// annotated compound statement. Thus, we need to consider this nesting and
2536// include checking the `getCapturedStmt` in this case.
2537static bool hasOrderedDirective(const Stmt *S) {
2539 return true;
2540
2541 if (const auto *CS = dyn_cast<CapturedStmt>(S))
2543
2544 for (const Stmt *Child : S->children()) {
2545 if (Child && hasOrderedDirective(Child))
2546 return true;
2547 }
2548
2549 return false;
2550}
2551
2552static void applyConservativeSimdOrderedDirective(const Stmt &AssociatedStmt,
2554 // Check for the presence of an `OMPOrderedDirective`
2555 // i.e., `ordered` in `#pragma omp ordered simd`
2556 bool HasOrderedDirective = hasOrderedDirective(&AssociatedStmt);
2557 // If present then conservatively disable loop vectorization
2558 // analogously to how `emitSimdlenSafelenClause` does.
2559 if (HasOrderedDirective)
2560 LoopStack.setParallel(/*Enable=*/false);
2561}
2562
2564 // Walk clauses and process safelen/lastprivate.
2565 LoopStack.setParallel(/*Enable=*/true);
2566 LoopStack.setVectorizeEnable();
2567 const Stmt *AssociatedStmt = D.getAssociatedStmt();
2569 emitSimdlenSafelenClause(*this, D);
2570 if (const auto *C = D.getSingleClause<OMPOrderClause>())
2571 if (C->getKind() == OMPC_ORDER_concurrent)
2572 LoopStack.setParallel(/*Enable=*/true);
2574 if ((EKind == OMPD_simd ||
2575 (getLangOpts().OpenMPSimd && isOpenMPSimdDirective(EKind))) &&
2576 llvm::any_of(D.getClausesOfKind<OMPReductionClause>(),
2577 [](const OMPReductionClause *C) {
2578 return C->getModifier() == OMPC_REDUCTION_inscan;
2579 }))
2580 // Disable parallel access in case of prefix sum.
2581 LoopStack.setParallel(/*Enable=*/false);
2582}
2583
2585 const OMPLoopDirective &D,
2586 const llvm::function_ref<llvm::Value *(CodeGenFunction &)> CondGen) {
2587 if (!HaveInsertPoint())
2588 return;
2589 llvm::BasicBlock *DoneBB = nullptr;
2590 auto IC = D.counters().begin();
2591 auto IPC = D.private_counters().begin();
2592 for (const Expr *F : D.finals()) {
2593 const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>((*IC))->getDecl());
2594 const auto *PrivateVD = cast<VarDecl>(cast<DeclRefExpr>((*IPC))->getDecl());
2595 const auto *CED = dyn_cast<OMPCapturedExprDecl>(OrigVD);
2596 if (LocalDeclMap.count(OrigVD) || CapturedStmtInfo->lookup(OrigVD) ||
2597 OrigVD->hasGlobalStorage() || CED) {
2598 if (!DoneBB) {
2599 if (llvm::Value *Cond = CondGen(*this)) {
2600 // If the first post-update expression is found, emit conditional
2601 // block if it was requested.
2602 llvm::BasicBlock *ThenBB = createBasicBlock(".omp.final.then");
2603 DoneBB = createBasicBlock(".omp.final.done");
2604 Builder.CreateCondBr(Cond, ThenBB, DoneBB);
2605 EmitBlock(ThenBB);
2606 }
2607 }
2608 Address OrigAddr = Address::invalid();
2609 if (CED) {
2610 OrigAddr = EmitLValue(CED->getInit()->IgnoreImpCasts()).getAddress();
2611 } else {
2612 DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(PrivateVD),
2613 /*RefersToEnclosingVariableOrCapture=*/false,
2614 (*IPC)->getType(), VK_LValue, (*IPC)->getExprLoc());
2615 OrigAddr = EmitLValue(&DRE).getAddress();
2616 }
2617 OMPPrivateScope VarScope(*this);
2618 VarScope.addPrivate(OrigVD, OrigAddr);
2619 (void)VarScope.Privatize();
2620 EmitIgnoredExpr(F);
2621 }
2622 ++IC;
2623 ++IPC;
2624 }
2625 if (DoneBB)
2626 EmitBlock(DoneBB, /*IsFinished=*/true);
2627}
2628
2635
2636/// Emit a helper variable and return corresponding lvalue.
2638 const DeclRefExpr *Helper) {
2639 auto VDecl = cast<VarDecl>(Helper->getDecl());
2640 CGF.EmitVarDecl(*VDecl);
2641 return CGF.EmitLValue(Helper);
2642}
2643
2645 const RegionCodeGenTy &SimdInitGen,
2646 const RegionCodeGenTy &BodyCodeGen) {
2647 auto &&ThenGen = [&S, &SimdInitGen, &BodyCodeGen](CodeGenFunction &CGF,
2648 PrePostActionTy &) {
2649 CGOpenMPRuntime::NontemporalDeclsRAII NontemporalsRegion(CGF.CGM, S);
2651 SimdInitGen(CGF);
2652
2653 BodyCodeGen(CGF);
2654 };
2655 auto &&ElseGen = [&BodyCodeGen](CodeGenFunction &CGF, PrePostActionTy &) {
2657 CGF.LoopStack.setVectorizeEnable(/*Enable=*/false);
2658
2659 BodyCodeGen(CGF);
2660 };
2661 const Expr *IfCond = nullptr;
2663 if (isOpenMPSimdDirective(EKind)) {
2664 for (const auto *C : S.getClausesOfKind<OMPIfClause>()) {
2665 if (CGF.getLangOpts().OpenMP >= 50 &&
2666 (C->getNameModifier() == OMPD_unknown ||
2667 C->getNameModifier() == OMPD_simd)) {
2668 IfCond = C->getCondition();
2669 break;
2670 }
2671 }
2672 }
2673 if (IfCond) {
2674 CGF.CGM.getOpenMPRuntime().emitIfClause(CGF, IfCond, ThenGen, ElseGen);
2675 } else {
2676 RegionCodeGenTy ThenRCG(ThenGen);
2677 ThenRCG(CGF);
2678 }
2679}
2680
2682 PrePostActionTy &Action) {
2683 Action.Enter(CGF);
2684 OMPLoopScope PreInitScope(CGF, S);
2685 // if (PreCond) {
2686 // for (IV in 0..LastIteration) BODY;
2687 // <Final counter/linear vars updates>;
2688 // }
2689
2690 // The presence of lower/upper bound variable depends on the actual directive
2691 // kind in the AST node. The variables must be emitted because some of the
2692 // expressions associated with the loop will use them.
2693 OpenMPDirectiveKind DKind = S.getDirectiveKind();
2694 if (isOpenMPDistributeDirective(DKind) ||
2697 (void)EmitOMPHelperVar(CGF, cast<DeclRefExpr>(S.getLowerBoundVariable()));
2698 (void)EmitOMPHelperVar(CGF, cast<DeclRefExpr>(S.getUpperBoundVariable()));
2699 }
2700
2702 // Emit: if (PreCond) - begin.
2703 // If the condition constant folds and can be elided, avoid emitting the
2704 // whole loop.
2705 bool CondConstant;
2706 llvm::BasicBlock *ContBlock = nullptr;
2707 if (CGF.ConstantFoldsToSimpleInteger(S.getPreCond(), CondConstant)) {
2708 if (!CondConstant)
2709 return;
2710 } else {
2711 llvm::BasicBlock *ThenBlock = CGF.createBasicBlock("simd.if.then");
2712 ContBlock = CGF.createBasicBlock("simd.if.end");
2713 emitPreCond(CGF, S, S.getPreCond(), ThenBlock, ContBlock,
2714 CGF.getProfileCount(&S));
2715 CGF.EmitBlock(ThenBlock);
2717 }
2718
2719 // Emit the loop iteration variable.
2720 const Expr *IVExpr = S.getIterationVariable();
2721 const auto *IVDecl = cast<VarDecl>(cast<DeclRefExpr>(IVExpr)->getDecl());
2722 CGF.EmitVarDecl(*IVDecl);
2723 CGF.EmitIgnoredExpr(S.getInit());
2724
2725 // Emit the iterations count variable.
2726 // If it is not a variable, Sema decided to calculate iterations count on
2727 // each iteration (e.g., it is foldable into a constant).
2728 if (const auto *LIExpr = dyn_cast<DeclRefExpr>(S.getLastIteration())) {
2729 CGF.EmitVarDecl(*cast<VarDecl>(LIExpr->getDecl()));
2730 // Emit calculation of the iterations count.
2731 CGF.EmitIgnoredExpr(S.getCalcLastIteration());
2732 }
2733
2734 emitAlignedClause(CGF, S);
2735 (void)CGF.EmitOMPLinearClauseInit(S);
2736 {
2737 CodeGenFunction::OMPPrivateScope LoopScope(CGF);
2738 CGF.EmitOMPPrivateClause(S, LoopScope);
2739 CGF.EmitOMPPrivateLoopCounters(S, LoopScope);
2740 CGF.EmitOMPLinearClause(S, LoopScope);
2741 CGF.EmitOMPReductionClauseInit(S, LoopScope);
2743 CGF, S, CGF.EmitLValue(S.getIterationVariable()));
2744 bool HasLastprivateClause = CGF.EmitOMPLastprivateClauseInit(S, LoopScope);
2745 (void)LoopScope.Privatize();
2748
2750 CGF, S,
2751 [&S](CodeGenFunction &CGF, PrePostActionTy &) {
2752 CGF.EmitOMPSimdInit(S);
2753 },
2754 [&S, &LoopScope](CodeGenFunction &CGF, PrePostActionTy &) {
2755 CGF.EmitOMPInnerLoop(
2756 S, LoopScope.requiresCleanups(), S.getCond(), S.getInc(),
2757 [&S](CodeGenFunction &CGF) {
2758 emitOMPLoopBodyWithStopPoint(CGF, S,
2759 CodeGenFunction::JumpDest());
2760 },
2761 [](CodeGenFunction &) {});
2762 });
2763 CGF.EmitOMPSimdFinal(S, [](CodeGenFunction &) { return nullptr; });
2764 // Emit final copy of the lastprivate variables at the end of loops.
2765 if (HasLastprivateClause)
2766 CGF.EmitOMPLastprivateClauseFinal(S, /*NoFinals=*/true);
2767 CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_simd);
2769 [](CodeGenFunction &) { return nullptr; });
2770 LoopScope.restoreMap();
2771 CGF.EmitOMPLinearClauseFinal(S, [](CodeGenFunction &) { return nullptr; });
2772 }
2773 // Emit: if (PreCond) - end.
2774 if (ContBlock) {
2775 CGF.EmitBranch(ContBlock);
2776 CGF.EmitBlock(ContBlock, true);
2777 }
2778}
2779
2780// Pass OMPLoopDirective (instead of OMPSimdDirective) to make this function
2781// available for "loop bind(thread)", which maps to "simd".
2783 // Check for unsupported clauses
2784 for (OMPClause *C : S.clauses()) {
2785 // Currently only order, simdlen and safelen clauses are supported
2788 return false;
2789 }
2790
2791 // Check if we have a statement with the ordered directive.
2792 // Visit the statement hierarchy to find a compound statement
2793 // with a ordered directive in it.
2794 if (const auto *CanonLoop = dyn_cast<OMPCanonicalLoop>(S.getRawStmt())) {
2795 if (const Stmt *SyntacticalLoop = CanonLoop->getLoopStmt()) {
2796 for (const Stmt *SubStmt : SyntacticalLoop->children()) {
2797 if (!SubStmt)
2798 continue;
2799 if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(SubStmt)) {
2800 for (const Stmt *CSSubStmt : CS->children()) {
2801 if (!CSSubStmt)
2802 continue;
2803 if (isa<OMPOrderedDirective>(CSSubStmt)) {
2804 return false;
2805 }
2806 }
2807 }
2808 }
2809 }
2810 }
2811 return true;
2812}
2813
2814static llvm::MapVector<llvm::Value *, llvm::Value *>
2816 llvm::MapVector<llvm::Value *, llvm::Value *> AlignedVars;
2817 for (const auto *Clause : S.getClausesOfKind<OMPAlignedClause>()) {
2818 llvm::APInt ClauseAlignment(64, 0);
2819 if (const Expr *AlignmentExpr = Clause->getAlignment()) {
2820 auto *AlignmentCI =
2821 cast<llvm::ConstantInt>(CGF.EmitScalarExpr(AlignmentExpr));
2822 ClauseAlignment = AlignmentCI->getValue();
2823 }
2824 for (const Expr *E : Clause->varlist()) {
2825 llvm::APInt Alignment(ClauseAlignment);
2826 if (Alignment == 0) {
2827 // OpenMP [2.8.1, Description]
2828 // If no optional parameter is specified, implementation-defined default
2829 // alignments for SIMD instructions on the target platforms are assumed.
2830 Alignment =
2831 CGF.getContext()
2833 E->getType()->getPointeeType()))
2834 .getQuantity();
2835 }
2836 assert((Alignment == 0 || Alignment.isPowerOf2()) &&
2837 "alignment is not power of 2");
2838 llvm::Value *PtrValue = CGF.EmitScalarExpr(E);
2839 AlignedVars[PtrValue] = CGF.Builder.getInt64(Alignment.getSExtValue());
2840 }
2841 }
2842 return AlignedVars;
2843}
2844
2845// Pass OMPLoopDirective (instead of OMPSimdDirective) to make this function
2846// available for "loop bind(thread)", which maps to "simd".
2849 bool UseOMPIRBuilder =
2850 CGM.getLangOpts().OpenMPIRBuilder && isSimdSupportedByOpenMPIRBuilder(S);
2851 if (UseOMPIRBuilder) {
2852 auto &&CodeGenIRBuilder = [&S, &CGM, UseOMPIRBuilder](CodeGenFunction &CGF,
2853 PrePostActionTy &) {
2854 // Use the OpenMPIRBuilder if enabled.
2855 if (UseOMPIRBuilder) {
2856 llvm::MapVector<llvm::Value *, llvm::Value *> AlignedVars =
2857 GetAlignedMapping(S, CGF);
2858 // Emit the associated statement and get its loop representation.
2859 const Stmt *Inner = S.getRawStmt();
2860 llvm::CanonicalLoopInfo *CLI =
2861 CGF.EmitOMPCollapsedCanonicalLoopNest(Inner, 1);
2862
2863 llvm::OpenMPIRBuilder &OMPBuilder =
2865 // Add SIMD specific metadata
2866 llvm::ConstantInt *Simdlen = nullptr;
2867 if (const auto *C = S.getSingleClause<OMPSimdlenClause>()) {
2868 RValue Len = CGF.EmitAnyExpr(C->getSimdlen(), AggValueSlot::ignored(),
2869 /*ignoreResult=*/true);
2870 auto *Val = cast<llvm::ConstantInt>(Len.getScalarVal());
2871 Simdlen = Val;
2872 }
2873 llvm::ConstantInt *Safelen = nullptr;
2874 if (const auto *C = S.getSingleClause<OMPSafelenClause>()) {
2875 RValue Len = CGF.EmitAnyExpr(C->getSafelen(), AggValueSlot::ignored(),
2876 /*ignoreResult=*/true);
2877 auto *Val = cast<llvm::ConstantInt>(Len.getScalarVal());
2878 Safelen = Val;
2879 }
2880 llvm::omp::OrderKind Order = llvm::omp::OrderKind::OMP_ORDER_unknown;
2881 if (const auto *C = S.getSingleClause<OMPOrderClause>()) {
2882 if (C->getKind() == OpenMPOrderClauseKind::OMPC_ORDER_concurrent) {
2883 Order = llvm::omp::OrderKind::OMP_ORDER_concurrent;
2884 }
2885 }
2886 // Add simd metadata to the collapsed loop. Do not generate
2887 // another loop for if clause. Support for if clause is done earlier.
2888 OMPBuilder.applySimd(CLI, AlignedVars,
2889 /*IfCond*/ nullptr, Order, Simdlen, Safelen);
2890 return;
2891 }
2892 };
2893 {
2894 auto LPCRegion =
2896 OMPLexicalScope Scope(CGF, S, OMPD_unknown);
2897 CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_simd,
2898 CodeGenIRBuilder);
2899 }
2900 return;
2901 }
2902
2904 CGF.OMPFirstScanLoop = true;
2905 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
2906 emitOMPSimdRegion(CGF, S, Action);
2907 };
2908 {
2909 auto LPCRegion =
2911 OMPLexicalScope Scope(CGF, S, OMPD_unknown);
2913 }
2914 // Check for outer lastprivate conditional update.
2916}
2917
2918void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) {
2919 emitOMPSimdDirective(S, *this, CGM);
2920}
2921
2923 // Emit the de-sugared statement.
2924 OMPTransformDirectiveScopeRAII TileScope(*this, &S);
2926}
2927
2929 // Emit the de-sugared statement.
2930 OMPTransformDirectiveScopeRAII StripeScope(*this, &S);
2932}
2933
2935 // Emit the de-sugared statement.
2936 OMPTransformDirectiveScopeRAII ReverseScope(*this, &S);
2938}
2939
2941 const OMPInterchangeDirective &S) {
2942 // Emit the de-sugared statement.
2943 OMPTransformDirectiveScopeRAII InterchangeScope(*this, &S);
2945}
2946
2948 bool UseOMPIRBuilder = CGM.getLangOpts().OpenMPIRBuilder;
2949
2950 if (UseOMPIRBuilder) {
2951 auto DL = SourceLocToDebugLoc(S.getBeginLoc());
2952 const Stmt *Inner = S.getRawStmt();
2953
2954 // Consume nested loop. Clear the entire remaining loop stack because a
2955 // fully unrolled loop is non-transformable. For partial unrolling the
2956 // generated outer loop is pushed back to the stack.
2957 llvm::CanonicalLoopInfo *CLI = EmitOMPCollapsedCanonicalLoopNest(Inner, 1);
2958 OMPLoopNestStack.clear();
2959
2960 llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
2961
2962 bool NeedsUnrolledCLI = ExpectedOMPLoopDepth >= 1;
2963 llvm::CanonicalLoopInfo *UnrolledCLI = nullptr;
2964
2965 if (S.hasClausesOfKind<OMPFullClause>()) {
2966 assert(ExpectedOMPLoopDepth == 0);
2967 OMPBuilder.unrollLoopFull(DL, CLI);
2968 } else if (auto *PartialClause = S.getSingleClause<OMPPartialClause>()) {
2969 uint64_t Factor = 0;
2970 if (Expr *FactorExpr = PartialClause->getFactor()) {
2971 Factor = FactorExpr->EvaluateKnownConstInt(getContext()).getZExtValue();
2972 assert(Factor >= 1 && "Only positive factors are valid");
2973 }
2974 OMPBuilder.unrollLoopPartial(DL, CLI, Factor,
2975 NeedsUnrolledCLI ? &UnrolledCLI : nullptr);
2976 } else {
2977 OMPBuilder.unrollLoopHeuristic(DL, CLI);
2978 }
2979
2980 assert((!NeedsUnrolledCLI || UnrolledCLI) &&
2981 "NeedsUnrolledCLI implies UnrolledCLI to be set");
2982 if (UnrolledCLI)
2983 OMPLoopNestStack.push_back(UnrolledCLI);
2984
2985 return;
2986 }
2987
2988 // This function is only called if the unrolled loop is not consumed by any
2989 // other loop-associated construct. Such a loop-associated construct will have
2990 // used the transformed AST.
2991
2992 // Set the unroll metadata for the next emitted loop.
2993 LoopStack.setUnrollState(LoopAttributes::Enable);
2994
2995 if (S.hasClausesOfKind<OMPFullClause>()) {
2996 LoopStack.setUnrollState(LoopAttributes::Full);
2997 } else if (auto *PartialClause = S.getSingleClause<OMPPartialClause>()) {
2998 if (Expr *FactorExpr = PartialClause->getFactor()) {
2999 uint64_t Factor =
3000 FactorExpr->EvaluateKnownConstInt(getContext()).getZExtValue();
3001 assert(Factor >= 1 && "Only positive factors are valid");
3002 LoopStack.setUnrollCount(Factor);
3003 }
3004 }
3005
3006 EmitStmt(S.getAssociatedStmt());
3007}
3008
3009void CodeGenFunction::EmitOMPOuterLoop(
3010 bool DynamicOrOrdered, bool IsMonotonic, const OMPLoopDirective &S,
3012 const CodeGenFunction::OMPLoopArguments &LoopArgs,
3013 const CodeGenFunction::CodeGenLoopTy &CodeGenLoop,
3014 const CodeGenFunction::CodeGenOrderedTy &CodeGenOrdered) {
3016
3017 const Expr *IVExpr = S.getIterationVariable();
3018 const unsigned IVSize = getContext().getTypeSize(IVExpr->getType());
3019 const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation();
3020
3021 JumpDest LoopExit = getJumpDestInCurrentScope("omp.dispatch.end");
3022
3023 // Start the loop with a block that tests the condition.
3024 llvm::BasicBlock *CondBlock = createBasicBlock("omp.dispatch.cond");
3025 EmitBlock(CondBlock);
3026 const SourceRange R = S.getSourceRange();
3027 OMPLoopNestStack.clear();
3030
3031 llvm::Value *BoolCondVal = nullptr;
3032 if (!DynamicOrOrdered) {
3033 // UB = min(UB, GlobalUB) or
3034 // UB = min(UB, PrevUB) for combined loop sharing constructs (e.g.
3035 // 'distribute parallel for')
3036 EmitIgnoredExpr(LoopArgs.EUB);
3037 // IV = LB
3038 EmitIgnoredExpr(LoopArgs.Init);
3039 // IV < UB
3040 BoolCondVal = EvaluateExprAsBool(LoopArgs.Cond);
3041 } else {
3042 BoolCondVal =
3043 RT.emitForNext(*this, S.getBeginLoc(), IVSize, IVSigned, LoopArgs.IL,
3044 LoopArgs.LB, LoopArgs.UB, LoopArgs.ST);
3045 }
3046
3047 // If there are any cleanups between here and the loop-exit scope,
3048 // create a block to stage a loop exit along.
3049 llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
3050 if (LoopScope.requiresCleanups())
3051 ExitBlock = createBasicBlock("omp.dispatch.cleanup");
3052
3053 llvm::BasicBlock *LoopBody = createBasicBlock("omp.dispatch.body");
3054 Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock);
3055 if (ExitBlock != LoopExit.getBlock()) {
3056 EmitBlock(ExitBlock);
3058 }
3059 EmitBlock(LoopBody);
3060
3061 // Emit "IV = LB" (in case of static schedule, we have already calculated new
3062 // LB for loop condition and emitted it above).
3063 if (DynamicOrOrdered)
3064 EmitIgnoredExpr(LoopArgs.Init);
3065
3066 // Create a block for the increment.
3067 JumpDest Continue = getJumpDestInCurrentScope("omp.dispatch.inc");
3068 BreakContinueStack.push_back(BreakContinue(S, LoopExit, Continue));
3069
3072 *this, S,
3073 [&S, IsMonotonic, EKind](CodeGenFunction &CGF, PrePostActionTy &) {
3074 // Generate !llvm.loop.parallel metadata for loads and stores for loops
3075 // with dynamic/guided scheduling and without ordered clause.
3076 if (!isOpenMPSimdDirective(EKind)) {
3077 CGF.LoopStack.setParallel(!IsMonotonic);
3078 if (const auto *C = S.getSingleClause<OMPOrderClause>())
3079 if (C->getKind() == OMPC_ORDER_concurrent)
3080 CGF.LoopStack.setParallel(/*Enable=*/true);
3081 } else {
3082 CGF.EmitOMPSimdInit(S);
3083 }
3084 },
3085 [&S, &LoopArgs, LoopExit, &CodeGenLoop, IVSize, IVSigned, &CodeGenOrdered,
3086 &LoopScope](CodeGenFunction &CGF, PrePostActionTy &) {
3087 SourceLocation Loc = S.getBeginLoc();
3088 // when 'distribute' is not combined with a 'for':
3089 // while (idx <= UB) { BODY; ++idx; }
3090 // when 'distribute' is combined with a 'for'
3091 // (e.g. 'distribute parallel for')
3092 // while (idx <= UB) { <CodeGen rest of pragma>; idx += ST; }
3093 CGF.EmitOMPInnerLoop(
3094 S, LoopScope.requiresCleanups(), LoopArgs.Cond, LoopArgs.IncExpr,
3095 [&S, LoopExit, &CodeGenLoop](CodeGenFunction &CGF) {
3096 CodeGenLoop(CGF, S, LoopExit);
3097 },
3098 [IVSize, IVSigned, Loc, &CodeGenOrdered](CodeGenFunction &CGF) {
3099 CodeGenOrdered(CGF, Loc, IVSize, IVSigned);
3100 });
3101 });
3102
3103 EmitBlock(Continue.getBlock());
3104 BreakContinueStack.pop_back();
3105 if (!DynamicOrOrdered) {
3106 // Emit "LB = LB + Stride", "UB = UB + Stride".
3107 EmitIgnoredExpr(LoopArgs.NextLB);
3108 EmitIgnoredExpr(LoopArgs.NextUB);
3109 }
3110
3111 EmitBranch(CondBlock);
3112 OMPLoopNestStack.clear();
3113 LoopStack.pop();
3114 // Emit the fall-through block.
3115 EmitBlock(LoopExit.getBlock());
3116
3117 // Tell the runtime we are done.
3118 auto &&CodeGen = [DynamicOrOrdered, &S, &LoopArgs](CodeGenFunction &CGF) {
3119 if (!DynamicOrOrdered)
3120 CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getEndLoc(),
3121 LoopArgs.DKind);
3122 };
3123 OMPCancelStack.emitExit(*this, EKind, CodeGen);
3124}
3125
3126void CodeGenFunction::EmitOMPForOuterLoop(
3127 const OpenMPScheduleTy &ScheduleKind, bool IsMonotonic,
3128 const OMPLoopDirective &S, OMPPrivateScope &LoopScope, bool Ordered,
3129 const OMPLoopArguments &LoopArgs,
3130 const CodeGenDispatchBoundsTy &CGDispatchBounds) {
3131 CGOpenMPRuntime &RT = CGM.getOpenMPRuntime();
3132
3133 // Dynamic scheduling of the outer loop (dynamic, guided, auto, runtime).
3134 const bool DynamicOrOrdered = Ordered || RT.isDynamic(ScheduleKind.Schedule);
3135
3136 assert((Ordered || !RT.isStaticNonchunked(ScheduleKind.Schedule,
3137 LoopArgs.Chunk != nullptr)) &&
3138 "static non-chunked schedule does not need outer loop");
3139
3140 // Emit outer loop.
3141 //
3142 // OpenMP [2.7.1, Loop Construct, Description, table 2-1]
3143 // When schedule(dynamic,chunk_size) is specified, the iterations are
3144 // distributed to threads in the team in chunks as the threads request them.
3145 // Each thread executes a chunk of iterations, then requests another chunk,
3146 // until no chunks remain to be distributed. Each chunk contains chunk_size
3147 // iterations, except for the last chunk to be distributed, which may have
3148 // fewer iterations. When no chunk_size is specified, it defaults to 1.
3149 //
3150 // When schedule(guided,chunk_size) is specified, the iterations are assigned
3151 // to threads in the team in chunks as the executing threads request them.
3152 // Each thread executes a chunk of iterations, then requests another chunk,
3153 // until no chunks remain to be assigned. For a chunk_size of 1, the size of
3154 // each chunk is proportional to the number of unassigned iterations divided
3155 // by the number of threads in the team, decreasing to 1. For a chunk_size
3156 // with value k (greater than 1), the size of each chunk is determined in the
3157 // same way, with the restriction that the chunks do not contain fewer than k
3158 // iterations (except for the last chunk to be assigned, which may have fewer
3159 // than k iterations).
3160 //
3161 // When schedule(auto) is specified, the decision regarding scheduling is
3162 // delegated to the compiler and/or runtime system. The programmer gives the
3163 // implementation the freedom to choose any possible mapping of iterations to
3164 // threads in the team.
3165 //
3166 // When schedule(runtime) is specified, the decision regarding scheduling is
3167 // deferred until run time, and the schedule and chunk size are taken from the
3168 // run-sched-var ICV. If the ICV is set to auto, the schedule is
3169 // implementation defined
3170 //
3171 // __kmpc_dispatch_init();
3172 // while(__kmpc_dispatch_next(&LB, &UB)) {
3173 // idx = LB;
3174 // while (idx <= UB) { BODY; ++idx;
3175 // __kmpc_dispatch_fini_(4|8)[u](); // For ordered loops only.
3176 // } // inner loop
3177 // }
3178 // __kmpc_dispatch_deinit();
3179 //
3180 // OpenMP [2.7.1, Loop Construct, Description, table 2-1]
3181 // When schedule(static, chunk_size) is specified, iterations are divided into
3182 // chunks of size chunk_size, and the chunks are assigned to the threads in
3183 // the team in a round-robin fashion in the order of the thread number.
3184 //
3185 // while(UB = min(UB, GlobalUB), idx = LB, idx < UB) {
3186 // while (idx <= UB) { BODY; ++idx; } // inner loop
3187 // LB = LB + ST;
3188 // UB = UB + ST;
3189 // }
3190 //
3191
3192 const Expr *IVExpr = S.getIterationVariable();
3193 const unsigned IVSize = getContext().getTypeSize(IVExpr->getType());
3194 const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation();
3195
3196 if (DynamicOrOrdered) {
3197 const std::pair<llvm::Value *, llvm::Value *> DispatchBounds =
3198 CGDispatchBounds(*this, S, LoopArgs.LB, LoopArgs.UB);
3199 llvm::Value *LBVal = DispatchBounds.first;
3200 llvm::Value *UBVal = DispatchBounds.second;
3201 CGOpenMPRuntime::DispatchRTInput DipatchRTInputValues = {LBVal, UBVal,
3202 LoopArgs.Chunk};
3203 RT.emitForDispatchInit(*this, S.getBeginLoc(), ScheduleKind, IVSize,
3204 IVSigned, Ordered, DipatchRTInputValues);
3205 } else {
3206 CGOpenMPRuntime::StaticRTInput StaticInit(
3207 IVSize, IVSigned, Ordered, LoopArgs.IL, LoopArgs.LB, LoopArgs.UB,
3208 LoopArgs.ST, LoopArgs.Chunk);
3210 RT.emitForStaticInit(*this, S.getBeginLoc(), EKind, ScheduleKind,
3211 StaticInit);
3212 }
3213
3214 auto &&CodeGenOrdered = [Ordered](CodeGenFunction &CGF, SourceLocation Loc,
3215 const unsigned IVSize,
3216 const bool IVSigned) {
3217 if (Ordered) {
3218 CGF.CGM.getOpenMPRuntime().emitForOrderedIterationEnd(CGF, Loc, IVSize,
3219 IVSigned);
3220 }
3221 };
3222
3223 OMPLoopArguments OuterLoopArgs(LoopArgs.LB, LoopArgs.UB, LoopArgs.ST,
3224 LoopArgs.IL, LoopArgs.Chunk, LoopArgs.EUB);
3225 OuterLoopArgs.IncExpr = S.getInc();
3226 OuterLoopArgs.Init = S.getInit();
3227 OuterLoopArgs.Cond = S.getCond();
3228 OuterLoopArgs.NextLB = S.getNextLowerBound();
3229 OuterLoopArgs.NextUB = S.getNextUpperBound();
3230 OuterLoopArgs.DKind = LoopArgs.DKind;
3231 EmitOMPOuterLoop(DynamicOrOrdered, IsMonotonic, S, LoopScope, OuterLoopArgs,
3232 emitOMPLoopBodyWithStopPoint, CodeGenOrdered);
3233 if (DynamicOrOrdered) {
3234 RT.emitForDispatchDeinit(*this, S.getBeginLoc());
3235 }
3236}
3237
3239 const unsigned IVSize, const bool IVSigned) {}
3240
3241void CodeGenFunction::EmitOMPDistributeOuterLoop(
3242 OpenMPDistScheduleClauseKind ScheduleKind, const OMPLoopDirective &S,
3243 OMPPrivateScope &LoopScope, const OMPLoopArguments &LoopArgs,
3244 const CodeGenLoopTy &CodeGenLoopContent) {
3245
3246 CGOpenMPRuntime &RT = CGM.getOpenMPRuntime();
3247
3248 // Emit outer loop.
3249 // Same behavior as a OMPForOuterLoop, except that schedule cannot be
3250 // dynamic
3251 //
3252
3253 const Expr *IVExpr = S.getIterationVariable();
3254 const unsigned IVSize = getContext().getTypeSize(IVExpr->getType());
3255 const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation();
3257
3258 CGOpenMPRuntime::StaticRTInput StaticInit(
3259 IVSize, IVSigned, /* Ordered = */ false, LoopArgs.IL, LoopArgs.LB,
3260 LoopArgs.UB, LoopArgs.ST, LoopArgs.Chunk);
3261 RT.emitDistributeStaticInit(*this, S.getBeginLoc(), ScheduleKind, StaticInit);
3262
3263 // for combined 'distribute' and 'for' the increment expression of distribute
3264 // is stored in DistInc. For 'distribute' alone, it is in Inc.
3265 Expr *IncExpr;
3267 IncExpr = S.getDistInc();
3268 else
3269 IncExpr = S.getInc();
3270
3271 // this routine is shared by 'omp distribute parallel for' and
3272 // 'omp distribute': select the right EUB expression depending on the
3273 // directive
3274 OMPLoopArguments OuterLoopArgs;
3275 OuterLoopArgs.LB = LoopArgs.LB;
3276 OuterLoopArgs.UB = LoopArgs.UB;
3277 OuterLoopArgs.ST = LoopArgs.ST;
3278 OuterLoopArgs.IL = LoopArgs.IL;
3279 OuterLoopArgs.Chunk = LoopArgs.Chunk;
3280 OuterLoopArgs.EUB = isOpenMPLoopBoundSharingDirective(EKind)
3281 ? S.getCombinedEnsureUpperBound()
3282 : S.getEnsureUpperBound();
3283 OuterLoopArgs.IncExpr = IncExpr;
3284 OuterLoopArgs.Init = isOpenMPLoopBoundSharingDirective(EKind)
3285 ? S.getCombinedInit()
3286 : S.getInit();
3287 OuterLoopArgs.Cond = isOpenMPLoopBoundSharingDirective(EKind)
3288 ? S.getCombinedCond()
3289 : S.getCond();
3290 OuterLoopArgs.NextLB = isOpenMPLoopBoundSharingDirective(EKind)
3291 ? S.getCombinedNextLowerBound()
3292 : S.getNextLowerBound();
3293 OuterLoopArgs.NextUB = isOpenMPLoopBoundSharingDirective(EKind)
3294 ? S.getCombinedNextUpperBound()
3295 : S.getNextUpperBound();
3296 OuterLoopArgs.DKind = OMPD_distribute;
3297
3298 EmitOMPOuterLoop(/* DynamicOrOrdered = */ false, /* IsMonotonic = */ false, S,
3299 LoopScope, OuterLoopArgs, CodeGenLoopContent,
3301}
3302
3303static std::pair<LValue, LValue>
3305 const OMPExecutableDirective &S) {
3307 LValue LB =
3308 EmitOMPHelperVar(CGF, cast<DeclRefExpr>(LS.getLowerBoundVariable()));
3309 LValue UB =
3310 EmitOMPHelperVar(CGF, cast<DeclRefExpr>(LS.getUpperBoundVariable()));
3311
3312 // When composing 'distribute' with 'for' (e.g. as in 'distribute
3313 // parallel for') we need to use the 'distribute'
3314 // chunk lower and upper bounds rather than the whole loop iteration
3315 // space. These are parameters to the outlined function for 'parallel'
3316 // and we copy the bounds of the previous schedule into the
3317 // the current ones.
3318 LValue PrevLB = CGF.EmitLValue(LS.getPrevLowerBoundVariable());
3319 LValue PrevUB = CGF.EmitLValue(LS.getPrevUpperBoundVariable());
3320 llvm::Value *PrevLBVal = CGF.EmitLoadOfScalar(
3321 PrevLB, LS.getPrevLowerBoundVariable()->getExprLoc());
3322 PrevLBVal = CGF.EmitScalarConversion(
3323 PrevLBVal, LS.getPrevLowerBoundVariable()->getType(),
3324 LS.getIterationVariable()->getType(),
3325 LS.getPrevLowerBoundVariable()->getExprLoc());
3326 llvm::Value *PrevUBVal = CGF.EmitLoadOfScalar(
3327 PrevUB, LS.getPrevUpperBoundVariable()->getExprLoc());
3328 PrevUBVal = CGF.EmitScalarConversion(
3329 PrevUBVal, LS.getPrevUpperBoundVariable()->getType(),
3330 LS.getIterationVariable()->getType(),
3331 LS.getPrevUpperBoundVariable()->getExprLoc());
3332
3333 CGF.EmitStoreOfScalar(PrevLBVal, LB);
3334 CGF.EmitStoreOfScalar(PrevUBVal, UB);
3335
3336 return {LB, UB};
3337}
3338
3339/// if the 'for' loop has a dispatch schedule (e.g. dynamic, guided) then
3340/// we need to use the LB and UB expressions generated by the worksharing
3341/// code generation support, whereas in non combined situations we would
3342/// just emit 0 and the LastIteration expression
3343/// This function is necessary due to the difference of the LB and UB
3344/// types for the RT emission routines for 'for_static_init' and
3345/// 'for_dispatch_init'
3346static std::pair<llvm::Value *, llvm::Value *>
3348 const OMPExecutableDirective &S,
3349 Address LB, Address UB) {
3351 const Expr *IVExpr = LS.getIterationVariable();
3352 // when implementing a dynamic schedule for a 'for' combined with a
3353 // 'distribute' (e.g. 'distribute parallel for'), the 'for' loop
3354 // is not normalized as each team only executes its own assigned
3355 // distribute chunk
3356 QualType IteratorTy = IVExpr->getType();
3357 llvm::Value *LBVal =
3358 CGF.EmitLoadOfScalar(LB, /*Volatile=*/false, IteratorTy, S.getBeginLoc());
3359 llvm::Value *UBVal =
3360 CGF.EmitLoadOfScalar(UB, /*Volatile=*/false, IteratorTy, S.getBeginLoc());
3361 return {LBVal, UBVal};
3362}
3363
3367 const auto &Dir = cast<OMPLoopDirective>(S);
3368 LValue LB =
3369 CGF.EmitLValue(cast<DeclRefExpr>(Dir.getCombinedLowerBoundVariable()));
3370 llvm::Value *LBCast = CGF.Builder.CreateIntCast(
3371 CGF.Builder.CreateLoad(LB.getAddress()), CGF.SizeTy, /*isSigned=*/false);
3372 CapturedVars.push_back(LBCast);
3373 LValue UB =
3374 CGF.EmitLValue(cast<DeclRefExpr>(Dir.getCombinedUpperBoundVariable()));
3375
3376 llvm::Value *UBCast = CGF.Builder.CreateIntCast(
3377 CGF.Builder.CreateLoad(UB.getAddress()), CGF.SizeTy, /*isSigned=*/false);
3378 CapturedVars.push_back(UBCast);
3379}
3380
3381static void
3383 const OMPLoopDirective &S,
3386 auto &&CGInlinedWorksharingLoop = [&S, EKind](CodeGenFunction &CGF,
3387 PrePostActionTy &Action) {
3388 Action.Enter(CGF);
3389 bool HasCancel = false;
3390 if (!isOpenMPSimdDirective(EKind)) {
3391 if (const auto *D = dyn_cast<OMPTeamsDistributeParallelForDirective>(&S))
3392 HasCancel = D->hasCancel();
3393 else if (const auto *D = dyn_cast<OMPDistributeParallelForDirective>(&S))
3394 HasCancel = D->hasCancel();
3395 else if (const auto *D =
3396 dyn_cast<OMPTargetTeamsDistributeParallelForDirective>(&S))
3397 HasCancel = D->hasCancel();
3398 }
3399 CodeGenFunction::OMPCancelStackRAII CancelRegion(CGF, EKind, HasCancel);
3400 CGF.EmitOMPWorksharingLoop(S, S.getPrevEnsureUpperBound(),
3403 };
3404
3406 CGF, S, isOpenMPSimdDirective(EKind) ? OMPD_for_simd : OMPD_for,
3407 CGInlinedWorksharingLoop,
3409}
3410
3413 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
3415 S.getDistInc());
3416 };
3417 OMPLexicalScope Scope(*this, S, OMPD_parallel);
3418 CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_distribute, CodeGen);
3419}
3420
3423 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
3425 S.getDistInc());
3426 };
3427 OMPLexicalScope Scope(*this, S, OMPD_parallel);
3428 CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_distribute, CodeGen);
3429}
3430
3432 const OMPDistributeSimdDirective &S) {
3433 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
3435 };
3436 OMPLexicalScope Scope(*this, S, OMPD_unknown);
3437 CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_simd, CodeGen);
3438}
3439
3441 CodeGenModule &CGM, StringRef ParentName, const OMPTargetSimdDirective &S) {
3442 // Emit SPMD target parallel for region as a standalone region.
3443 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
3444 emitOMPSimdRegion(CGF, S, Action);
3445 };
3446 llvm::Function *Fn;
3447 llvm::Constant *Addr;
3448 // Emit target region as a standalone region.
3449 CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
3450 S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
3451 assert(Fn && Addr && "Target device function emission failed.");
3452}
3453
3455 const OMPTargetSimdDirective &S) {
3456 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
3457 emitOMPSimdRegion(CGF, S, Action);
3458 };
3460}
3461
3462namespace {
3463struct ScheduleKindModifiersTy {
3467 ScheduleKindModifiersTy(OpenMPScheduleClauseKind Kind,
3470 : Kind(Kind), M1(M1), M2(M2) {}
3471};
3472} // namespace
3473
3475 const OMPLoopDirective &S, Expr *EUB,
3476 const CodeGenLoopBoundsTy &CodeGenLoopBounds,
3477 const CodeGenDispatchBoundsTy &CGDispatchBounds) {
3478 // Emit the loop iteration variable.
3479 const auto *IVExpr = cast<DeclRefExpr>(S.getIterationVariable());
3480 const auto *IVDecl = cast<VarDecl>(IVExpr->getDecl());
3481 EmitVarDecl(*IVDecl);
3482
3483 // Emit the iterations count variable.
3484 // If it is not a variable, Sema decided to calculate iterations count on each
3485 // iteration (e.g., it is foldable into a constant).
3486 if (const auto *LIExpr = dyn_cast<DeclRefExpr>(S.getLastIteration())) {
3487 EmitVarDecl(*cast<VarDecl>(LIExpr->getDecl()));
3488 // Emit calculation of the iterations count.
3489 EmitIgnoredExpr(S.getCalcLastIteration());
3490 }
3491
3492 CGOpenMPRuntime &RT = CGM.getOpenMPRuntime();
3493
3494 bool HasLastprivateClause;
3495 // Check pre-condition.
3496 {
3497 OMPLoopScope PreInitScope(*this, S);
3498 // Skip the entire loop if we don't meet the precondition.
3499 // If the condition constant folds and can be elided, avoid emitting the
3500 // whole loop.
3501 bool CondConstant;
3502 llvm::BasicBlock *ContBlock = nullptr;
3503 if (ConstantFoldsToSimpleInteger(S.getPreCond(), CondConstant)) {
3504 if (!CondConstant)
3505 return false;
3506 } else {
3507 llvm::BasicBlock *ThenBlock = createBasicBlock("omp.precond.then");
3508 ContBlock = createBasicBlock("omp.precond.end");
3509 emitPreCond(*this, S, S.getPreCond(), ThenBlock, ContBlock,
3510 getProfileCount(&S));
3511 EmitBlock(ThenBlock);
3513 }
3514
3515 RunCleanupsScope DoacrossCleanupScope(*this);
3516 bool Ordered = false;
3517 if (const auto *OrderedClause = S.getSingleClause<OMPOrderedClause>()) {
3518 if (OrderedClause->getNumForLoops())
3519 RT.emitDoacrossInit(*this, S, OrderedClause->getLoopNumIterations());
3520 else
3521 Ordered = true;
3522 }
3523
3524 emitAlignedClause(*this, S);
3525 bool HasLinears = EmitOMPLinearClauseInit(S);
3526 // Emit helper vars inits.
3527
3528 std::pair<LValue, LValue> Bounds = CodeGenLoopBounds(*this, S);
3529 LValue LB = Bounds.first;
3530 LValue UB = Bounds.second;
3531 LValue ST =
3532 EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getStrideVariable()));
3533 LValue IL =
3534 EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getIsLastIterVariable()));
3535
3536 // Emit 'then' code.
3537 {
3539 OMPPrivateScope LoopScope(*this);
3540 if (EmitOMPFirstprivateClause(S, LoopScope) || HasLinears) {
3541 // Emit implicit barrier to synchronize threads and avoid data races on
3542 // initialization of firstprivate variables and post-update of
3543 // lastprivate variables.
3544 CGM.getOpenMPRuntime().emitBarrierCall(
3545 *this, S.getBeginLoc(), OMPD_unknown, /*EmitChecks=*/false,
3546 /*ForceSimpleCall=*/true);
3547 }
3548 EmitOMPPrivateClause(S, LoopScope);
3550 *this, S, EmitLValue(S.getIterationVariable()));
3551 HasLastprivateClause = EmitOMPLastprivateClauseInit(S, LoopScope);
3552 EmitOMPReductionClauseInit(S, LoopScope);
3553 EmitOMPPrivateLoopCounters(S, LoopScope);
3554 EmitOMPLinearClause(S, LoopScope);
3555 (void)LoopScope.Privatize();
3557 CGM.getOpenMPRuntime().adjustTargetSpecificDataForLambdas(*this, S);
3558
3559 // Detect the loop schedule kind and chunk.
3560 const Expr *ChunkExpr = nullptr;
3561 OpenMPScheduleTy ScheduleKind;
3562 if (const auto *C = S.getSingleClause<OMPScheduleClause>()) {
3563 ScheduleKind.Schedule = C->getScheduleKind();
3564 ScheduleKind.M1 = C->getFirstScheduleModifier();
3565 ScheduleKind.M2 = C->getSecondScheduleModifier();
3566 ChunkExpr = C->getChunkSize();
3567 } else {
3568 // Default behaviour for schedule clause.
3569 CGM.getOpenMPRuntime().getDefaultScheduleAndChunk(
3570 *this, S, ScheduleKind.Schedule, ChunkExpr);
3571 }
3572 bool HasChunkSizeOne = false;
3573 llvm::Value *Chunk = nullptr;
3574 if (ChunkExpr) {
3575 Chunk = EmitScalarExpr(ChunkExpr);
3576 Chunk = EmitScalarConversion(Chunk, ChunkExpr->getType(),
3577 S.getIterationVariable()->getType(),
3578 S.getBeginLoc());
3580 if (ChunkExpr->EvaluateAsInt(Result, getContext())) {
3581 llvm::APSInt EvaluatedChunk = Result.Val.getInt();
3582 HasChunkSizeOne = (EvaluatedChunk.getLimitedValue() == 1);
3583 }
3584 }
3585 const unsigned IVSize = getContext().getTypeSize(IVExpr->getType());
3586 const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation();
3587 // OpenMP 4.5, 2.7.1 Loop Construct, Description.
3588 // If the static schedule kind is specified or if the ordered clause is
3589 // specified, and if no monotonic modifier is specified, the effect will
3590 // be as if the monotonic modifier was specified.
3591 bool StaticChunkedOne =
3592 RT.isStaticChunked(ScheduleKind.Schedule,
3593 /* Chunked */ Chunk != nullptr) &&
3594 HasChunkSizeOne && isOpenMPLoopBoundSharingDirective(EKind);
3595 bool IsMonotonic =
3596 Ordered ||
3597 (ScheduleKind.Schedule == OMPC_SCHEDULE_static &&
3598 !(ScheduleKind.M1 == OMPC_SCHEDULE_MODIFIER_nonmonotonic ||
3599 ScheduleKind.M2 == OMPC_SCHEDULE_MODIFIER_nonmonotonic)) ||
3600 ScheduleKind.M1 == OMPC_SCHEDULE_MODIFIER_monotonic ||
3601 ScheduleKind.M2 == OMPC_SCHEDULE_MODIFIER_monotonic;
3602 if ((RT.isStaticNonchunked(ScheduleKind.Schedule,
3603 /* Chunked */ Chunk != nullptr) ||
3604 StaticChunkedOne) &&
3605 !Ordered) {
3609 *this, S,
3610 [&S, EKind](CodeGenFunction &CGF, PrePostActionTy &) {
3611 if (isOpenMPSimdDirective(EKind)) {
3612 CGF.EmitOMPSimdInit(S);
3613 } else if (const auto *C = S.getSingleClause<OMPOrderClause>()) {
3614 if (C->getKind() == OMPC_ORDER_concurrent)
3615 CGF.LoopStack.setParallel(/*Enable=*/true);
3616 }
3617 },
3618 [IVSize, IVSigned, Ordered, IL, LB, UB, ST, StaticChunkedOne, Chunk,
3619 &S, ScheduleKind, LoopExit, EKind,
3620 &LoopScope](CodeGenFunction &CGF, PrePostActionTy &) {
3621 // OpenMP [2.7.1, Loop Construct, Description, table 2-1]
3622 // When no chunk_size is specified, the iteration space is divided
3623 // into chunks that are approximately equal in size, and at most
3624 // one chunk is distributed to each thread. Note that the size of
3625 // the chunks is unspecified in this case.
3627 IVSize, IVSigned, Ordered, IL.getAddress(), LB.getAddress(),
3628 UB.getAddress(), ST.getAddress(),
3629 StaticChunkedOne ? Chunk : nullptr);
3631 CGF, S.getBeginLoc(), EKind, ScheduleKind, StaticInit);
3632 // UB = min(UB, GlobalUB);
3633 if (!StaticChunkedOne)
3634 CGF.EmitIgnoredExpr(S.getEnsureUpperBound());
3635 // IV = LB;
3636 CGF.EmitIgnoredExpr(S.getInit());
3637 // For unchunked static schedule generate:
3638 //
3639 // while (idx <= UB) {
3640 // BODY;
3641 // ++idx;
3642 // }
3643 //
3644 // For static schedule with chunk one:
3645 //
3646 // while (IV <= PrevUB) {
3647 // BODY;
3648 // IV += ST;
3649 // }
3650 CGF.EmitOMPInnerLoop(
3651 S, LoopScope.requiresCleanups(),
3652 StaticChunkedOne ? S.getCombinedParForInDistCond()
3653 : S.getCond(),
3654 StaticChunkedOne ? S.getDistInc() : S.getInc(),
3655 [&S, LoopExit](CodeGenFunction &CGF) {
3656 emitOMPLoopBodyWithStopPoint(CGF, S, LoopExit);
3657 },
3658 [](CodeGenFunction &) {});
3659 });
3660 EmitBlock(LoopExit.getBlock());
3661 // Tell the runtime we are done.
3662 auto &&CodeGen = [&S](CodeGenFunction &CGF) {
3663 CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getEndLoc(),
3664 OMPD_for);
3665 };
3666 OMPCancelStack.emitExit(*this, EKind, CodeGen);
3667 } else {
3668 // Emit the outer loop, which requests its work chunk [LB..UB] from
3669 // runtime and runs the inner loop to process it.
3670 OMPLoopArguments LoopArguments(LB.getAddress(), UB.getAddress(),
3671 ST.getAddress(), IL.getAddress(), Chunk,
3672 EUB);
3673 LoopArguments.DKind = OMPD_for;
3674 EmitOMPForOuterLoop(ScheduleKind, IsMonotonic, S, LoopScope, Ordered,
3675 LoopArguments, CGDispatchBounds);
3676 }
3677 if (isOpenMPSimdDirective(EKind)) {
3678 EmitOMPSimdFinal(S, [IL, &S](CodeGenFunction &CGF) {
3679 return CGF.Builder.CreateIsNotNull(
3680 CGF.EmitLoadOfScalar(IL, S.getBeginLoc()));
3681 });
3682 }
3684 S, /*ReductionKind=*/isOpenMPSimdDirective(EKind)
3685 ? /*Parallel and Simd*/ OMPD_parallel_for_simd
3686 : /*Parallel only*/ OMPD_parallel);
3687 // Emit post-update of the reduction variables if IsLastIter != 0.
3689 *this, S, [IL, &S](CodeGenFunction &CGF) {
3690 return CGF.Builder.CreateIsNotNull(
3691 CGF.EmitLoadOfScalar(IL, S.getBeginLoc()));
3692 });
3693 // Emit final copy of the lastprivate variables if IsLastIter != 0.
3694 if (HasLastprivateClause)
3696 S, isOpenMPSimdDirective(EKind),
3697 Builder.CreateIsNotNull(EmitLoadOfScalar(IL, S.getBeginLoc())));
3698 LoopScope.restoreMap();
3699 EmitOMPLinearClauseFinal(S, [IL, &S](CodeGenFunction &CGF) {
3700 return CGF.Builder.CreateIsNotNull(
3701 CGF.EmitLoadOfScalar(IL, S.getBeginLoc()));
3702 });
3703 }
3704 DoacrossCleanupScope.ForceCleanup();
3705 // We're now done with the loop, so jump to the continuation block.
3706 if (ContBlock) {
3707 EmitBranch(ContBlock);
3708 EmitBlock(ContBlock, /*IsFinished=*/true);
3709 }
3710 }
3711 return HasLastprivateClause;
3712}
3713
3714/// The following two functions generate expressions for the loop lower
3715/// and upper bounds in case of static and dynamic (dispatch) schedule
3716/// of the associated 'for' or 'distribute' loop.
3717static std::pair<LValue, LValue>
3719 const auto &LS = cast<OMPLoopDirective>(S);
3720 LValue LB =
3721 EmitOMPHelperVar(CGF, cast<DeclRefExpr>(LS.getLowerBoundVariable()));
3722 LValue UB =
3723 EmitOMPHelperVar(CGF, cast<DeclRefExpr>(LS.getUpperBoundVariable()));
3724 return {LB, UB};
3725}
3726
3727/// When dealing with dispatch schedules (e.g. dynamic, guided) we do not
3728/// consider the lower and upper bound expressions generated by the
3729/// worksharing loop support, but we use 0 and the iteration space size as
3730/// constants
3731static std::pair<llvm::Value *, llvm::Value *>
3733 Address LB, Address UB) {
3734 const auto &LS = cast<OMPLoopDirective>(S);
3735 const Expr *IVExpr = LS.getIterationVariable();
3736 const unsigned IVSize = CGF.getContext().getTypeSize(IVExpr->getType());
3737 llvm::Value *LBVal = CGF.Builder.getIntN(IVSize, 0);
3738 llvm::Value *UBVal = CGF.EmitScalarExpr(LS.getLastIteration());
3739 return {LBVal, UBVal};
3740}
3741
3742/// Emits internal temp array declarations for the directive with inscan
3743/// reductions.
3744/// The code is the following:
3745/// \code
3746/// size num_iters = <num_iters>;
3747/// <type> buffer[num_iters];
3748/// \endcode
3750 CodeGenFunction &CGF, const OMPLoopDirective &S,
3751 llvm::function_ref<llvm::Value *(CodeGenFunction &)> NumIteratorsGen) {
3752 llvm::Value *OMPScanNumIterations = CGF.Builder.CreateIntCast(
3753 NumIteratorsGen(CGF), CGF.SizeTy, /*isSigned=*/false);
3756 SmallVector<const Expr *, 4> ReductionOps;
3757 SmallVector<const Expr *, 4> CopyArrayTemps;
3758 for (const auto *C : S.getClausesOfKind<OMPReductionClause>()) {
3759 assert(C->getModifier() == OMPC_REDUCTION_inscan &&
3760 "Only inscan reductions are expected.");
3761 Shareds.append(C->varlist_begin(), C->varlist_end());
3762 Privates.append(C->privates().begin(), C->privates().end());
3763 ReductionOps.append(C->reduction_ops().begin(), C->reduction_ops().end());
3764 CopyArrayTemps.append(C->copy_array_temps().begin(),
3765 C->copy_array_temps().end());
3766 }
3767 {
3768 // Emit buffers for each reduction variables.
3769 // ReductionCodeGen is required to emit correctly the code for array
3770 // reductions.
3771 ReductionCodeGen RedCG(Shareds, Shareds, Privates, ReductionOps);
3772 unsigned Count = 0;
3773 auto *ITA = CopyArrayTemps.begin();
3774 for (const Expr *IRef : Privates) {
3775 const auto *PrivateVD = cast<VarDecl>(cast<DeclRefExpr>(IRef)->getDecl());
3776 // Emit variably modified arrays, used for arrays/array sections
3777 // reductions.
3778 if (PrivateVD->getType()->isVariablyModifiedType()) {
3779 RedCG.emitSharedOrigLValue(CGF, Count);
3780 RedCG.emitAggregateType(CGF, Count);
3781 }
3783 CGF,
3785 cast<VariableArrayType>((*ITA)->getType()->getAsArrayTypeUnsafe())
3786 ->getSizeExpr()),
3787 RValue::get(OMPScanNumIterations));
3788 // Emit temp buffer.
3789 CGF.EmitVarDecl(*cast<VarDecl>(cast<DeclRefExpr>(*ITA)->getDecl()));
3790 ++ITA;
3791 ++Count;
3792 }
3793 }
3794}
3795
3796/// Copies final inscan reductions values to the original variables.
3797/// The code is the following:
3798/// \code
3799/// <orig_var> = buffer[num_iters-1];
3800/// \endcode
3802 CodeGenFunction &CGF, const OMPLoopDirective &S,
3803 llvm::function_ref<llvm::Value *(CodeGenFunction &)> NumIteratorsGen) {
3804 llvm::Value *OMPScanNumIterations = CGF.Builder.CreateIntCast(
3805 NumIteratorsGen(CGF), CGF.SizeTy, /*isSigned=*/false);
3811 SmallVector<const Expr *, 4> CopyArrayElems;
3812 for (const auto *C : S.getClausesOfKind<OMPReductionClause>()) {
3813 assert(C->getModifier() == OMPC_REDUCTION_inscan &&
3814 "Only inscan reductions are expected.");
3815 Shareds.append(C->varlist_begin(), C->varlist_end());
3816 LHSs.append(C->lhs_exprs().begin(), C->lhs_exprs().end());
3817 RHSs.append(C->rhs_exprs().begin(), C->rhs_exprs().end());
3818 Privates.append(C->privates().begin(), C->privates().end());
3819 CopyOps.append(C->copy_ops().begin(), C->copy_ops().end());
3820 CopyArrayElems.append(C->copy_array_elems().begin(),
3821 C->copy_array_elems().end());
3822 }
3823 // Create temp var and copy LHS value to this temp value.
3824 // LHS = TMP[LastIter];
3825 llvm::Value *OMPLast = CGF.Builder.CreateNSWSub(
3826 OMPScanNumIterations,
3827 llvm::ConstantInt::get(CGF.SizeTy, 1, /*isSigned=*/false));
3828 for (unsigned I = 0, E = CopyArrayElems.size(); I < E; ++I) {
3829 const Expr *PrivateExpr = Privates[I];
3830 const Expr *OrigExpr = Shareds[I];
3831 const Expr *CopyArrayElem = CopyArrayElems[I];
3833 CGF,
3835 cast<ArraySubscriptExpr>(CopyArrayElem)->getIdx()),
3836 RValue::get(OMPLast));
3837 LValue DestLVal = CGF.EmitLValue(OrigExpr);
3838 LValue SrcLVal = CGF.EmitLValue(CopyArrayElem);
3839 CGF.EmitOMPCopy(
3840 PrivateExpr->getType(), DestLVal.getAddress(), SrcLVal.getAddress(),
3841 cast<VarDecl>(cast<DeclRefExpr>(LHSs[I])->getDecl()),
3842 cast<VarDecl>(cast<DeclRefExpr>(RHSs[I])->getDecl()), CopyOps[I]);
3843 }
3844}
3845
3846/// Emits the code for the directive with inscan reductions.
3847/// The code is the following:
3848/// \code
3849/// #pragma omp ...
3850/// for (i: 0..<num_iters>) {
3851/// <input phase>;
3852/// buffer[i] = red;
3853/// }
3854/// #pragma omp master // in parallel region
3855/// for (int k = 0; k != ceil(log2(num_iters)); ++k)
3856/// for (size cnt = last_iter; cnt >= pow(2, k); --k)
3857/// buffer[i] op= buffer[i-pow(2,k)];
3858/// #pragma omp barrier // in parallel region
3859/// #pragma omp ...
3860/// for (0..<num_iters>) {
3861/// red = InclusiveScan ? buffer[i] : buffer[i-1];
3862/// <scan phase>;
3863/// }
3864/// \endcode
3866 CodeGenFunction &CGF, const OMPLoopDirective &S,
3867 llvm::function_ref<llvm::Value *(CodeGenFunction &)> NumIteratorsGen,
3868 llvm::function_ref<void(CodeGenFunction &)> FirstGen,
3869 llvm::function_ref<void(CodeGenFunction &)> SecondGen) {
3870 llvm::Value *OMPScanNumIterations = CGF.Builder.CreateIntCast(
3871 NumIteratorsGen(CGF), CGF.SizeTy, /*isSigned=*/false);
3873 SmallVector<const Expr *, 4> ReductionOps;
3876 SmallVector<const Expr *, 4> CopyArrayElems;
3877 for (const auto *C : S.getClausesOfKind<OMPReductionClause>()) {
3878 assert(C->getModifier() == OMPC_REDUCTION_inscan &&
3879 "Only inscan reductions are expected.");
3880 Privates.append(C->privates().begin(), C->privates().end());
3881 ReductionOps.append(C->reduction_ops().begin(), C->reduction_ops().end());
3882 LHSs.append(C->lhs_exprs().begin(), C->lhs_exprs().end());
3883 RHSs.append(C->rhs_exprs().begin(), C->rhs_exprs().end());
3884 CopyArrayElems.append(C->copy_array_elems().begin(),
3885 C->copy_array_elems().end());
3886 }
3888 {
3889 // Emit loop with input phase:
3890 // #pragma omp ...
3891 // for (i: 0..<num_iters>) {
3892 // <input phase>;
3893 // buffer[i] = red;
3894 // }
3895 CGF.OMPFirstScanLoop = true;
3897 FirstGen(CGF);
3898 }
3899 // #pragma omp barrier // in parallel region
3900 auto &&CodeGen = [&S, OMPScanNumIterations, &LHSs, &RHSs, &CopyArrayElems,
3901 &ReductionOps,
3902 &Privates](CodeGenFunction &CGF, PrePostActionTy &Action) {
3903 Action.Enter(CGF);
3904 // Emit prefix reduction:
3905 // #pragma omp master // in parallel region
3906 // for (int k = 0; k <= ceil(log2(n)); ++k)
3907 llvm::BasicBlock *InputBB = CGF.Builder.GetInsertBlock();
3908 llvm::BasicBlock *LoopBB = CGF.createBasicBlock("omp.outer.log.scan.body");
3909 llvm::BasicBlock *ExitBB = CGF.createBasicBlock("omp.outer.log.scan.exit");
3910 llvm::Function *F =
3911 CGF.CGM.getIntrinsic(llvm::Intrinsic::log2, CGF.DoubleTy);
3912 llvm::Value *Arg =
3913 CGF.Builder.CreateUIToFP(OMPScanNumIterations, CGF.DoubleTy);
3914 llvm::Value *LogVal = CGF.EmitNounwindRuntimeCall(F, Arg);
3915 F = CGF.CGM.getIntrinsic(llvm::Intrinsic::ceil, CGF.DoubleTy);
3916 LogVal = CGF.EmitNounwindRuntimeCall(F, LogVal);
3917 LogVal = CGF.Builder.CreateFPToUI(LogVal, CGF.IntTy);
3918 llvm::Value *NMin1 = CGF.Builder.CreateNUWSub(
3919 OMPScanNumIterations, llvm::ConstantInt::get(CGF.SizeTy, 1));
3920 auto DL = ApplyDebugLocation::CreateDefaultArtificial(CGF, S.getBeginLoc());
3921 CGF.EmitBlock(LoopBB);
3922 auto *Counter = CGF.Builder.CreatePHI(CGF.IntTy, 2);
3923 // size pow2k = 1;
3924 auto *Pow2K = CGF.Builder.CreatePHI(CGF.SizeTy, 2);
3925 Counter->addIncoming(llvm::ConstantInt::get(CGF.IntTy, 0), InputBB);
3926 Pow2K->addIncoming(llvm::ConstantInt::get(CGF.SizeTy, 1), InputBB);
3927 // for (size i = n - 1; i >= 2 ^ k; --i)
3928 // tmp[i] op= tmp[i-pow2k];
3929 llvm::BasicBlock *InnerLoopBB =
3930 CGF.createBasicBlock("omp.inner.log.scan.body");
3931 llvm::BasicBlock *InnerExitBB =
3932 CGF.createBasicBlock("omp.inner.log.scan.exit");
3933 llvm::Value *CmpI = CGF.Builder.CreateICmpUGE(NMin1, Pow2K);
3934 CGF.Builder.CreateCondBr(CmpI, InnerLoopBB, InnerExitBB);
3935 CGF.EmitBlock(InnerLoopBB);
3936 auto *IVal = CGF.Builder.CreatePHI(CGF.SizeTy, 2);
3937 IVal->addIncoming(NMin1, LoopBB);
3938 {
3939 CodeGenFunction::OMPPrivateScope PrivScope(CGF);
3940 auto *ILHS = LHSs.begin();
3941 auto *IRHS = RHSs.begin();
3942 for (const Expr *CopyArrayElem : CopyArrayElems) {
3943 const auto *LHSVD = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
3944 const auto *RHSVD = cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
3945 Address LHSAddr = Address::invalid();
3946 {
3948 CGF,
3950 cast<ArraySubscriptExpr>(CopyArrayElem)->getIdx()),
3951 RValue::get(IVal));
3952 LHSAddr = CGF.EmitLValue(CopyArrayElem).getAddress();
3953 }
3954 PrivScope.addPrivate(LHSVD, LHSAddr);
3955 Address RHSAddr = Address::invalid();
3956 {
3957 llvm::Value *OffsetIVal = CGF.Builder.CreateNUWSub(IVal, Pow2K);
3959 CGF,
3961 cast<ArraySubscriptExpr>(CopyArrayElem)->getIdx()),
3962 RValue::get(OffsetIVal));
3963 RHSAddr = CGF.EmitLValue(CopyArrayElem).getAddress();
3964 }
3965 PrivScope.addPrivate(RHSVD, RHSAddr);
3966 ++ILHS;
3967 ++IRHS;
3968 }
3969 PrivScope.Privatize();
3970 CGF.CGM.getOpenMPRuntime().emitReduction(
3971 CGF, S.getEndLoc(), Privates, LHSs, RHSs, ReductionOps,
3972 {/*WithNowait=*/true, /*SimpleReduction=*/true,
3973 /*IsPrivateVarReduction*/ {}, OMPD_unknown});
3974 }
3975 llvm::Value *NextIVal =
3976 CGF.Builder.CreateNUWSub(IVal, llvm::ConstantInt::get(CGF.SizeTy, 1));
3977 IVal->addIncoming(NextIVal, CGF.Builder.GetInsertBlock());
3978 CmpI = CGF.Builder.CreateICmpUGE(NextIVal, Pow2K);
3979 CGF.Builder.CreateCondBr(CmpI, InnerLoopBB, InnerExitBB);
3980 CGF.EmitBlock(InnerExitBB);
3981 llvm::Value *Next =
3982 CGF.Builder.CreateNUWAdd(Counter, llvm::ConstantInt::get(CGF.IntTy, 1));
3983 Counter->addIncoming(Next, CGF.Builder.GetInsertBlock());
3984 // pow2k <<= 1;
3985 llvm::Value *NextPow2K =
3986 CGF.Builder.CreateShl(Pow2K, 1, "", /*HasNUW=*/true);
3987 Pow2K->addIncoming(NextPow2K, CGF.Builder.GetInsertBlock());
3988 llvm::Value *Cmp = CGF.Builder.CreateICmpNE(Next, LogVal);
3989 CGF.Builder.CreateCondBr(Cmp, LoopBB, ExitBB);
3990 auto DL1 = ApplyDebugLocation::CreateDefaultArtificial(CGF, S.getEndLoc());
3991 CGF.EmitBlock(ExitBB);
3992 };
3994 if (isOpenMPParallelDirective(EKind)) {
3995 CGF.CGM.getOpenMPRuntime().emitMasterRegion(CGF, CodeGen, S.getBeginLoc());
3997 CGF, S.getBeginLoc(), OMPD_unknown, /*EmitChecks=*/false,
3998 /*ForceSimpleCall=*/true);
3999 } else {
4000 RegionCodeGenTy RCG(CodeGen);
4001 RCG(CGF);
4002 }
4003
4004 CGF.OMPFirstScanLoop = false;
4005 SecondGen(CGF);
4006}
4007
4009 const OMPLoopDirective &S,
4010 bool HasCancel) {
4011 bool HasLastprivates;
4013 if (llvm::any_of(S.getClausesOfKind<OMPReductionClause>(),
4014 [](const OMPReductionClause *C) {
4015 return C->getModifier() == OMPC_REDUCTION_inscan;
4016 })) {
4017 const auto &&NumIteratorsGen = [&S](CodeGenFunction &CGF) {
4019 OMPLoopScope LoopScope(CGF, S);
4020 return CGF.EmitScalarExpr(S.getNumIterations());
4021 };
4022 const auto &&FirstGen = [&S, HasCancel, EKind](CodeGenFunction &CGF) {
4023 CodeGenFunction::OMPCancelStackRAII CancelRegion(CGF, EKind, HasCancel);
4024 (void)CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(),
4027 // Emit an implicit barrier at the end.
4028 CGF.CGM.getOpenMPRuntime().emitBarrierCall(CGF, S.getBeginLoc(),
4029 OMPD_for);
4030 };
4031 const auto &&SecondGen = [&S, HasCancel, EKind,
4032 &HasLastprivates](CodeGenFunction &CGF) {
4033 CodeGenFunction::OMPCancelStackRAII CancelRegion(CGF, EKind, HasCancel);
4034 HasLastprivates = CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(),
4037 };
4038 if (!isOpenMPParallelDirective(EKind))
4039 emitScanBasedDirectiveDecls(CGF, S, NumIteratorsGen);
4040 emitScanBasedDirective(CGF, S, NumIteratorsGen, FirstGen, SecondGen);
4041 if (!isOpenMPParallelDirective(EKind))
4042 emitScanBasedDirectiveFinals(CGF, S, NumIteratorsGen);
4043 } else {
4044 CodeGenFunction::OMPCancelStackRAII CancelRegion(CGF, EKind, HasCancel);
4045 HasLastprivates = CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(),
4048 }
4049 return HasLastprivates;
4050}
4051
4052// Pass OMPLoopDirective (instead of OMPForDirective) to make this check
4053// available for "loop bind(parallel)", which maps to "for".
4055 bool HasCancel) {
4056 if (HasCancel)
4057 return false;
4058 for (OMPClause *C : S.clauses()) {
4060 continue;
4061
4062 if (auto *SC = dyn_cast<OMPScheduleClause>(C)) {
4063 if (SC->getFirstScheduleModifier() != OMPC_SCHEDULE_MODIFIER_unknown)
4064 return false;
4065 if (SC->getSecondScheduleModifier() != OMPC_SCHEDULE_MODIFIER_unknown)
4066 return false;
4067 switch (SC->getScheduleKind()) {
4068 case OMPC_SCHEDULE_auto:
4069 case OMPC_SCHEDULE_dynamic:
4070 case OMPC_SCHEDULE_runtime:
4071 case OMPC_SCHEDULE_guided:
4072 case OMPC_SCHEDULE_static:
4073 continue;
4075 return false;
4076 }
4077 }
4078
4079 return false;
4080 }
4081
4082 return true;
4083}
4084
4085static llvm::omp::ScheduleKind
4087 switch (ScheduleClauseKind) {
4089 return llvm::omp::OMP_SCHEDULE_Default;
4090 case OMPC_SCHEDULE_auto:
4091 return llvm::omp::OMP_SCHEDULE_Auto;
4092 case OMPC_SCHEDULE_dynamic:
4093 return llvm::omp::OMP_SCHEDULE_Dynamic;
4094 case OMPC_SCHEDULE_guided:
4095 return llvm::omp::OMP_SCHEDULE_Guided;
4096 case OMPC_SCHEDULE_runtime:
4097 return llvm::omp::OMP_SCHEDULE_Runtime;
4098 case OMPC_SCHEDULE_static:
4099 return llvm::omp::OMP_SCHEDULE_Static;
4100 }
4101 llvm_unreachable("Unhandled schedule kind");
4102}
4103
4104// Pass OMPLoopDirective (instead of OMPForDirective) to make this function
4105// available for "loop bind(parallel)", which maps to "for".
4107 CodeGenModule &CGM, bool HasCancel) {
4108 bool HasLastprivates = false;
4109 bool UseOMPIRBuilder = CGM.getLangOpts().OpenMPIRBuilder &&
4110 isForSupportedByOpenMPIRBuilder(S, HasCancel);
4111 auto &&CodeGen = [&S, &CGM, HasCancel, &HasLastprivates,
4112 UseOMPIRBuilder](CodeGenFunction &CGF, PrePostActionTy &) {
4113 // Use the OpenMPIRBuilder if enabled.
4114 if (UseOMPIRBuilder) {
4115 bool NeedsBarrier = !S.getSingleClause<OMPNowaitClause>();
4116
4117 llvm::omp::ScheduleKind SchedKind = llvm::omp::OMP_SCHEDULE_Default;
4118 llvm::Value *ChunkSize = nullptr;
4119 if (auto *SchedClause = S.getSingleClause<OMPScheduleClause>()) {
4120 SchedKind =
4121 convertClauseKindToSchedKind(SchedClause->getScheduleKind());
4122 if (const Expr *ChunkSizeExpr = SchedClause->getChunkSize())
4123 ChunkSize = CGF.EmitScalarExpr(ChunkSizeExpr);
4124 }
4125
4126 // Emit the associated statement and get its loop representation.
4127 const Stmt *Inner = S.getRawStmt();
4128 llvm::CanonicalLoopInfo *CLI =
4130
4131 llvm::OpenMPIRBuilder &OMPBuilder =
4133 llvm::OpenMPIRBuilder::InsertPointTy AllocaIP(
4134 CGF.AllocaInsertPt->getParent(), CGF.AllocaInsertPt->getIterator());
4135 cantFail(OMPBuilder.applyWorkshareLoop(
4136 CGF.Builder.getCurrentDebugLocation(), CLI, AllocaIP, NeedsBarrier,
4137 SchedKind, ChunkSize, /*HasSimdModifier=*/false,
4138 /*HasMonotonicModifier=*/false, /*HasNonmonotonicModifier=*/false,
4139 /*HasOrderedClause=*/false));
4140 return;
4141 }
4142
4143 HasLastprivates = emitWorksharingDirective(CGF, S, HasCancel);
4144 };
4145 {
4146 auto LPCRegion =
4148 OMPLexicalScope Scope(CGF, S, OMPD_unknown);
4150 HasCancel);
4151 }
4152
4153 if (!UseOMPIRBuilder) {
4154 // Emit an implicit barrier at the end.
4155 if (!S.getSingleClause<OMPNowaitClause>() || HasLastprivates)
4156 CGM.getOpenMPRuntime().emitBarrierCall(CGF, S.getBeginLoc(), OMPD_for);
4157 }
4158 // Check for outer lastprivate conditional update.
4160}
4161
4162void CodeGenFunction::EmitOMPForDirective(const OMPForDirective &S) {
4163 return emitOMPForDirective(S, *this, CGM, S.hasCancel());
4164}
4165
4166void CodeGenFunction::EmitOMPForSimdDirective(const OMPForSimdDirective &S) {
4167 bool HasLastprivates = false;
4168 auto &&CodeGen = [&S, &HasLastprivates](CodeGenFunction &CGF,
4169 PrePostActionTy &) {
4170 HasLastprivates = emitWorksharingDirective(CGF, S, /*HasCancel=*/false);
4171 };
4172 {
4173 auto LPCRegion =
4175 OMPLexicalScope Scope(*this, S, OMPD_unknown);
4176 CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_simd, CodeGen);
4177 }
4178
4179 // Emit an implicit barrier at the end.
4180 if (!S.getSingleClause<OMPNowaitClause>() || HasLastprivates)
4181 CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getBeginLoc(), OMPD_for);
4182 // Check for outer lastprivate conditional update.
4184}
4185
4187 const Twine &Name,
4188 llvm::Value *Init = nullptr) {
4189 LValue LVal = CGF.MakeAddrLValue(CGF.CreateMemTemp(Ty, Name), Ty);
4190 if (Init)
4191 CGF.EmitStoreThroughLValue(RValue::get(Init), LVal, /*isInit*/ true);
4192 return LVal;
4193}
4194
4195void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) {
4196 const Stmt *CapturedStmt = S.getInnermostCapturedStmt()->getCapturedStmt();
4197 const auto *CS = dyn_cast<CompoundStmt>(CapturedStmt);
4198 bool HasLastprivates = false;
4200 auto &&CodeGen = [&S, CapturedStmt, CS, EKind,
4201 &HasLastprivates](CodeGenFunction &CGF, PrePostActionTy &) {
4202 const ASTContext &C = CGF.getContext();
4203 QualType KmpInt32Ty =
4204 C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1);
4205 // Emit helper vars inits.
4206 LValue LB = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.lb.",
4207 CGF.Builder.getInt32(0));
4208 llvm::ConstantInt *GlobalUBVal = CS != nullptr
4209 ? CGF.Builder.getInt32(CS->size() - 1)
4210 : CGF.Builder.getInt32(0);
4211 LValue UB =
4212 createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.ub.", GlobalUBVal);
4213 LValue ST = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.st.",
4214 CGF.Builder.getInt32(1));
4215 LValue IL = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.il.",
4216 CGF.Builder.getInt32(0));
4217 // Loop counter.
4218 LValue IV = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.iv.");
4219 OpaqueValueExpr IVRefExpr(S.getBeginLoc(), KmpInt32Ty, VK_LValue);
4220 CodeGenFunction::OpaqueValueMapping OpaqueIV(CGF, &IVRefExpr, IV);
4221 OpaqueValueExpr UBRefExpr(S.getBeginLoc(), KmpInt32Ty, VK_LValue);
4222 CodeGenFunction::OpaqueValueMapping OpaqueUB(CGF, &UBRefExpr, UB);
4223 // Generate condition for loop.
4224 BinaryOperator *Cond = BinaryOperator::Create(
4225 C, &IVRefExpr, &UBRefExpr, BO_LE, C.BoolTy, VK_PRValue, OK_Ordinary,
4226 S.getBeginLoc(), FPOptionsOverride());
4227 // Increment for loop counter.
4228 UnaryOperator *Inc = UnaryOperator::Create(
4229 C, &IVRefExpr, UO_PreInc, KmpInt32Ty, VK_PRValue, OK_Ordinary,
4230 S.getBeginLoc(), true, FPOptionsOverride());
4231 auto &&BodyGen = [CapturedStmt, CS, &S, &IV](CodeGenFunction &CGF) {
4232 // Iterate through all sections and emit a switch construct:
4233 // switch (IV) {
4234 // case 0:
4235 // <SectionStmt[0]>;
4236 // break;
4237 // ...
4238 // case <NumSection> - 1:
4239 // <SectionStmt[<NumSection> - 1]>;
4240 // break;
4241 // }
4242 // .omp.sections.exit:
4243 llvm::BasicBlock *ExitBB = CGF.createBasicBlock(".omp.sections.exit");
4244 llvm::SwitchInst *SwitchStmt =
4245 CGF.Builder.CreateSwitch(CGF.EmitLoadOfScalar(IV, S.getBeginLoc()),
4246 ExitBB, CS == nullptr ? 1 : CS->size());
4247 if (CS) {
4248 unsigned CaseNumber = 0;
4249 for (const Stmt *SubStmt : CS->children()) {
4250 auto CaseBB = CGF.createBasicBlock(".omp.sections.case");
4251 CGF.EmitBlock(CaseBB);
4252 SwitchStmt->addCase(CGF.Builder.getInt32(CaseNumber), CaseBB);
4253 CGF.EmitStmt(SubStmt);
4254 CGF.EmitBranch(ExitBB);
4255 ++CaseNumber;
4256 }
4257 } else {
4258 llvm::BasicBlock *CaseBB = CGF.createBasicBlock(".omp.sections.case");
4259 CGF.EmitBlock(CaseBB);
4260 SwitchStmt->addCase(CGF.Builder.getInt32(0), CaseBB);
4261 CGF.EmitStmt(CapturedStmt);
4262 CGF.EmitBranch(ExitBB);
4263 }
4264 CGF.EmitBlock(ExitBB, /*IsFinished=*/true);
4265 };
4266
4267 CodeGenFunction::OMPPrivateScope LoopScope(CGF);
4268 if (CGF.EmitOMPFirstprivateClause(S, LoopScope)) {
4269 // Emit implicit barrier to synchronize threads and avoid data races on
4270 // initialization of firstprivate variables and post-update of lastprivate
4271 // variables.
4272 CGF.CGM.getOpenMPRuntime().emitBarrierCall(
4273 CGF, S.getBeginLoc(), OMPD_unknown, /*EmitChecks=*/false,
4274 /*ForceSimpleCall=*/true);
4275 }
4276 CGF.EmitOMPPrivateClause(S, LoopScope);
4277 CGOpenMPRuntime::LastprivateConditionalRAII LPCRegion(CGF, S, IV);
4278 HasLastprivates = CGF.EmitOMPLastprivateClauseInit(S, LoopScope);
4279 CGF.EmitOMPReductionClauseInit(S, LoopScope);
4280 (void)LoopScope.Privatize();
4282 CGF.CGM.getOpenMPRuntime().adjustTargetSpecificDataForLambdas(CGF, S);
4283
4284 // Emit static non-chunked loop.
4285 OpenMPScheduleTy ScheduleKind;
4286 ScheduleKind.Schedule = OMPC_SCHEDULE_static;
4287 CGOpenMPRuntime::StaticRTInput StaticInit(
4288 /*IVSize=*/32, /*IVSigned=*/true, /*Ordered=*/false, IL.getAddress(),
4289 LB.getAddress(), UB.getAddress(), ST.getAddress());
4290 CGF.CGM.getOpenMPRuntime().emitForStaticInit(CGF, S.getBeginLoc(), EKind,
4291 ScheduleKind, StaticInit);
4292 // UB = min(UB, GlobalUB);
4293 llvm::Value *UBVal = CGF.EmitLoadOfScalar(UB, S.getBeginLoc());
4294 llvm::Value *MinUBGlobalUB = CGF.Builder.CreateSelect(
4295 CGF.Builder.CreateICmpSLT(UBVal, GlobalUBVal), UBVal, GlobalUBVal);
4296 CGF.EmitStoreOfScalar(MinUBGlobalUB, UB);
4297 // IV = LB;
4298 CGF.EmitStoreOfScalar(CGF.EmitLoadOfScalar(LB, S.getBeginLoc()), IV);
4299 // while (idx <= UB) { BODY; ++idx; }
4300 CGF.EmitOMPInnerLoop(S, /*RequiresCleanup=*/false, Cond, Inc, BodyGen,
4301 [](CodeGenFunction &) {});
4302 // Tell the runtime we are done.
4303 auto &&CodeGen = [&S](CodeGenFunction &CGF) {
4304 CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getEndLoc(),
4305 OMPD_sections);
4306 };
4307 CGF.OMPCancelStack.emitExit(CGF, EKind, CodeGen);
4308 CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_parallel);
4309 // Emit post-update of the reduction variables if IsLastIter != 0.
4310 emitPostUpdateForReductionClause(CGF, S, [IL, &S](CodeGenFunction &CGF) {
4311 return CGF.Builder.CreateIsNotNull(
4312 CGF.EmitLoadOfScalar(IL, S.getBeginLoc()));
4313 });
4314
4315 // Emit final copy of the lastprivate variables if IsLastIter != 0.
4316 if (HasLastprivates)
4318 S, /*NoFinals=*/false,
4319 CGF.Builder.CreateIsNotNull(
4320 CGF.EmitLoadOfScalar(IL, S.getBeginLoc())));
4321 };
4322
4323 bool HasCancel = false;
4324 if (auto *OSD = dyn_cast<OMPSectionsDirective>(&S))
4325 HasCancel = OSD->hasCancel();
4326 else if (auto *OPSD = dyn_cast<OMPParallelSectionsDirective>(&S))
4327 HasCancel = OPSD->hasCancel();
4328 OMPCancelStackRAII CancelRegion(*this, EKind, HasCancel);
4329 CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_sections, CodeGen,
4330 HasCancel);
4331 // Emit barrier for lastprivates only if 'sections' directive has 'nowait'
4332 // clause. Otherwise the barrier will be generated by the codegen for the
4333 // directive.
4334 if (HasLastprivates && S.getSingleClause<OMPNowaitClause>()) {
4335 // Emit implicit barrier to synchronize threads and avoid data races on
4336 // initialization of firstprivate variables.
4337 CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getBeginLoc(),
4338 OMPD_unknown);
4339 }
4340}
4341
4342void CodeGenFunction::EmitOMPScopeDirective(const OMPScopeDirective &S) {
4343 {
4344 // Emit code for 'scope' region
4345 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
4346 Action.Enter(CGF);
4347 OMPPrivateScope PrivateScope(CGF);
4348 (void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
4349 CGF.EmitOMPPrivateClause(S, PrivateScope);
4350 CGF.EmitOMPReductionClauseInit(S, PrivateScope);
4351 (void)PrivateScope.Privatize();
4352 CGF.EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt());
4353 CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_parallel);
4354 };
4355 auto LPCRegion =
4357 OMPLexicalScope Scope(*this, S, OMPD_unknown);
4358 CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_scope, CodeGen);
4359 }
4360 // Emit an implicit barrier at the end.
4361 if (!S.getSingleClause<OMPNowaitClause>()) {
4362 CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getBeginLoc(), OMPD_scope);
4363 }
4364 // Check for outer lastprivate conditional update.
4366}
4367
4368void CodeGenFunction::EmitOMPSectionsDirective(const OMPSectionsDirective &S) {
4369 if (CGM.getLangOpts().OpenMPIRBuilder) {
4370 llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
4371 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
4372 using BodyGenCallbackTy = llvm::OpenMPIRBuilder::StorableBodyGenCallbackTy;
4373
4374 auto FiniCB = [](InsertPointTy IP) {
4375 // Don't FinalizeOMPRegion because this is done inside of OMPIRBuilder for
4376 // sections.
4377 return llvm::Error::success();
4378 };
4379
4380 const CapturedStmt *ICS = S.getInnermostCapturedStmt();
4381 const Stmt *CapturedStmt = S.getInnermostCapturedStmt()->getCapturedStmt();
4382 const auto *CS = dyn_cast<CompoundStmt>(CapturedStmt);
4384 if (CS) {
4385 for (const Stmt *SubStmt : CS->children()) {
4386 auto SectionCB = [this, SubStmt](InsertPointTy AllocaIP,
4387 InsertPointTy CodeGenIP) {
4389 *this, SubStmt, AllocaIP, CodeGenIP, "section");
4390 return llvm::Error::success();
4391 };
4392 SectionCBVector.push_back(SectionCB);
4393 }
4394 } else {
4395 auto SectionCB = [this, CapturedStmt](InsertPointTy AllocaIP,
4396 InsertPointTy CodeGenIP) {
4398 *this, CapturedStmt, AllocaIP, CodeGenIP, "section");
4399 return llvm::Error::success();
4400 };
4401 SectionCBVector.push_back(SectionCB);
4402 }
4403
4404 // Privatization callback that performs appropriate action for
4405 // shared/private/firstprivate/lastprivate/copyin/... variables.
4406 //
4407 // TODO: This defaults to shared right now.
4408 auto PrivCB = [](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
4409 llvm::Value &, llvm::Value &Val, llvm::Value *&ReplVal) {
4410 // The next line is appropriate only for variables (Val) with the
4411 // data-sharing attribute "shared".
4412 ReplVal = &Val;
4413
4414 return CodeGenIP;
4415 };
4416
4417 CGCapturedStmtInfo CGSI(*ICS, CR_OpenMP);
4418 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(*this, &CGSI);
4419 llvm::OpenMPIRBuilder::InsertPointTy AllocaIP(
4420 AllocaInsertPt->getParent(), AllocaInsertPt->getIterator());
4421 llvm::OpenMPIRBuilder::InsertPointTy AfterIP =
4422 cantFail(OMPBuilder.createSections(
4423 Builder, AllocaIP, SectionCBVector, PrivCB, FiniCB, S.hasCancel(),
4424 S.getSingleClause<OMPNowaitClause>()));
4425 Builder.restoreIP(AfterIP);
4426 return;
4427 }
4428 {
4429 auto LPCRegion =
4431 OMPLexicalScope Scope(*this, S, OMPD_unknown);
4432 EmitSections(S);
4433 }
4434 // Emit an implicit barrier at the end.
4435 if (!S.getSingleClause<OMPNowaitClause>()) {
4436 CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getBeginLoc(),
4437 OMPD_sections);
4438 }
4439 // Check for outer lastprivate conditional update.
4441}
4442
4443void CodeGenFunction::EmitOMPSectionDirective(const OMPSectionDirective &S) {
4444 if (CGM.getLangOpts().OpenMPIRBuilder) {
4445 llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
4446 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
4447
4448 const Stmt *SectionRegionBodyStmt = S.getAssociatedStmt();
4449 auto FiniCB = [this](InsertPointTy IP) {
4451 return llvm::Error::success();
4452 };
4453
4454 auto BodyGenCB = [SectionRegionBodyStmt, this](InsertPointTy AllocaIP,
4455 InsertPointTy CodeGenIP) {
4457 *this, SectionRegionBodyStmt, AllocaIP, CodeGenIP, "section");
4458 return llvm::Error::success();
4459 };
4460
4461 LexicalScope Scope(*this, S.getSourceRange());
4462 EmitStopPoint(&S);
4463 llvm::OpenMPIRBuilder::InsertPointTy AfterIP =
4464 cantFail(OMPBuilder.createSection(Builder, BodyGenCB, FiniCB));
4465 Builder.restoreIP(AfterIP);
4466
4467 return;
4468 }
4469 LexicalScope Scope(*this, S.getSourceRange());
4470 EmitStopPoint(&S);
4471 EmitStmt(S.getAssociatedStmt());
4472}
4473
4474void CodeGenFunction::EmitOMPSingleDirective(const OMPSingleDirective &S) {
4475 llvm::SmallVector<const Expr *, 8> CopyprivateVars;
4479 // Check if there are any 'copyprivate' clauses associated with this
4480 // 'single' construct.
4481 // Build a list of copyprivate variables along with helper expressions
4482 // (<source>, <destination>, <destination>=<source> expressions)
4483 for (const auto *C : S.getClausesOfKind<OMPCopyprivateClause>()) {
4484 CopyprivateVars.append(C->varlist_begin(), C->varlist_end());
4485 DestExprs.append(C->destination_exprs().begin(),
4486 C->destination_exprs().end());
4487 SrcExprs.append(C->source_exprs().begin(), C->source_exprs().end());
4488 AssignmentOps.append(C->assignment_ops().begin(),
4489 C->assignment_ops().end());
4490 }
4491 // Emit code for 'single' region along with 'copyprivate' clauses
4492 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
4493 Action.Enter(CGF);
4497 (void)SingleScope.Privatize();
4498 CGF.EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt());
4499 };
4500 {
4501 auto LPCRegion =
4503 OMPLexicalScope Scope(*this, S, OMPD_unknown);
4504 CGM.getOpenMPRuntime().emitSingleRegion(*this, CodeGen, S.getBeginLoc(),
4505 CopyprivateVars, DestExprs,
4506 SrcExprs, AssignmentOps);
4507 }
4508 // Emit an implicit barrier at the end (to avoid data race on firstprivate
4509 // init or if no 'nowait' clause was specified and no 'copyprivate' clause).
4510 if (!S.getSingleClause<OMPNowaitClause>() && CopyprivateVars.empty()) {
4511 CGM.getOpenMPRuntime().emitBarrierCall(
4512 *this, S.getBeginLoc(),
4513 S.getSingleClause<OMPNowaitClause>() ? OMPD_unknown : OMPD_single);
4514 }
4515 // Check for outer lastprivate conditional update.
4517}
4518
4520 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
4521 Action.Enter(CGF);
4522 CGF.EmitStmt(S.getRawStmt());
4523 };
4524 CGF.CGM.getOpenMPRuntime().emitMasterRegion(CGF, CodeGen, S.getBeginLoc());
4525}
4526
4527void CodeGenFunction::EmitOMPMasterDirective(const OMPMasterDirective &S) {
4528 if (CGM.getLangOpts().OpenMPIRBuilder) {
4529 llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
4530 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
4531
4532 const Stmt *MasterRegionBodyStmt = S.getAssociatedStmt();
4533
4534 auto FiniCB = [this](InsertPointTy IP) {
4536 return llvm::Error::success();
4537 };
4538
4539 auto BodyGenCB = [MasterRegionBodyStmt, this](InsertPointTy AllocaIP,
4540 InsertPointTy CodeGenIP) {
4542 *this, MasterRegionBodyStmt, AllocaIP, CodeGenIP, "master");
4543 return llvm::Error::success();
4544 };
4545
4546 LexicalScope Scope(*this, S.getSourceRange());
4547 EmitStopPoint(&S);
4548 llvm::OpenMPIRBuilder::InsertPointTy AfterIP =
4549 cantFail(OMPBuilder.createMaster(Builder, BodyGenCB, FiniCB));
4550 Builder.restoreIP(AfterIP);
4551
4552 return;
4553 }
4554 LexicalScope Scope(*this, S.getSourceRange());
4555 EmitStopPoint(&S);
4556 emitMaster(*this, S);
4557}
4558
4560 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
4561 Action.Enter(CGF);
4562 CGF.EmitStmt(S.getRawStmt());
4563 };
4564 Expr *Filter = nullptr;
4565 if (const auto *FilterClause = S.getSingleClause<OMPFilterClause>())
4566 Filter = FilterClause->getThreadID();
4567 CGF.CGM.getOpenMPRuntime().emitMaskedRegion(CGF, CodeGen, S.getBeginLoc(),
4568 Filter);
4569}
4570
4572 if (CGM.getLangOpts().OpenMPIRBuilder) {
4573 llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
4574 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
4575
4576 const Stmt *MaskedRegionBodyStmt = S.getAssociatedStmt();
4577 const Expr *Filter = nullptr;
4578 if (const auto *FilterClause = S.getSingleClause<OMPFilterClause>())
4579 Filter = FilterClause->getThreadID();
4580 llvm::Value *FilterVal = Filter
4581 ? EmitScalarExpr(Filter, CGM.Int32Ty)
4582 : llvm::ConstantInt::get(CGM.Int32Ty, /*V=*/0);
4583
4584 auto FiniCB = [this](InsertPointTy IP) {
4586 return llvm::Error::success();
4587 };
4588
4589 auto BodyGenCB = [MaskedRegionBodyStmt, this](InsertPointTy AllocaIP,
4590 InsertPointTy CodeGenIP) {
4592 *this, MaskedRegionBodyStmt, AllocaIP, CodeGenIP, "masked");
4593 return llvm::Error::success();
4594 };
4595
4596 LexicalScope Scope(*this, S.getSourceRange());
4597 EmitStopPoint(&S);
4598 llvm::OpenMPIRBuilder::InsertPointTy AfterIP = cantFail(
4599 OMPBuilder.createMasked(Builder, BodyGenCB, FiniCB, FilterVal));
4600 Builder.restoreIP(AfterIP);
4601
4602 return;
4603 }
4604 LexicalScope Scope(*this, S.getSourceRange());
4605 EmitStopPoint(&S);
4606 emitMasked(*this, S);
4607}
4608
4609void CodeGenFunction::EmitOMPCriticalDirective(const OMPCriticalDirective &S) {
4610 if (CGM.getLangOpts().OpenMPIRBuilder) {
4611 llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
4612 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
4613
4614 const Stmt *CriticalRegionBodyStmt = S.getAssociatedStmt();
4615 const Expr *Hint = nullptr;
4616 if (const auto *HintClause = S.getSingleClause<OMPHintClause>())
4617 Hint = HintClause->getHint();
4618
4619 // TODO: This is slightly different from what's currently being done in
4620 // clang. Fix the Int32Ty to IntPtrTy (pointer width size) when everything
4621 // about typing is final.
4622 llvm::Value *HintInst = nullptr;
4623 if (Hint)
4624 HintInst =
4625 Builder.CreateIntCast(EmitScalarExpr(Hint), CGM.Int32Ty, false);
4626
4627 auto FiniCB = [this](InsertPointTy IP) {
4629 return llvm::Error::success();
4630 };
4631
4632 auto BodyGenCB = [CriticalRegionBodyStmt, this](InsertPointTy AllocaIP,
4633 InsertPointTy CodeGenIP) {
4635 *this, CriticalRegionBodyStmt, AllocaIP, CodeGenIP, "critical");
4636 return llvm::Error::success();
4637 };
4638
4639 LexicalScope Scope(*this, S.getSourceRange());
4640 EmitStopPoint(&S);
4641 llvm::OpenMPIRBuilder::InsertPointTy AfterIP =
4642 cantFail(OMPBuilder.createCritical(Builder, BodyGenCB, FiniCB,
4643 S.getDirectiveName().getAsString(),
4644 HintInst));
4645 Builder.restoreIP(AfterIP);
4646
4647 return;
4648 }
4649
4650 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
4651 Action.Enter(CGF);
4652 CGF.EmitStmt(S.getAssociatedStmt());
4653 };
4654 const Expr *Hint = nullptr;
4655 if (const auto *HintClause = S.getSingleClause<OMPHintClause>())
4656 Hint = HintClause->getHint();
4657 LexicalScope Scope(*this, S.getSourceRange());
4658 EmitStopPoint(&S);
4659 CGM.getOpenMPRuntime().emitCriticalRegion(*this,
4660 S.getDirectiveName().getAsString(),
4661 CodeGen, S.getBeginLoc(), Hint);
4662}
4663
4665 const OMPParallelForDirective &S) {
4666 // Emit directive as a combined directive that consists of two implicit
4667 // directives: 'parallel' with 'for' directive.
4668 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
4669 Action.Enter(CGF);
4670 emitOMPCopyinClause(CGF, S);
4671 (void)emitWorksharingDirective(CGF, S, S.hasCancel());
4672 };
4673 {
4674 const auto &&NumIteratorsGen = [&S](CodeGenFunction &CGF) {
4677 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGSI);
4678 OMPLoopScope LoopScope(CGF, S);
4679 return CGF.EmitScalarExpr(S.getNumIterations());
4680 };
4681 bool IsInscan = llvm::any_of(S.getClausesOfKind<OMPReductionClause>(),
4682 [](const OMPReductionClause *C) {
4683 return C->getModifier() == OMPC_REDUCTION_inscan;
4684 });
4685 if (IsInscan)
4686 emitScanBasedDirectiveDecls(*this, S, NumIteratorsGen);
4687 auto LPCRegion =
4689 emitCommonOMPParallelDirective(*this, S, OMPD_for, CodeGen,
4691 if (IsInscan)
4692 emitScanBasedDirectiveFinals(*this, S, NumIteratorsGen);
4693 }
4694 // Check for outer lastprivate conditional update.
4696}
4697
4699 const OMPParallelForSimdDirective &S) {
4700 // Emit directive as a combined directive that consists of two implicit
4701 // directives: 'parallel' with 'for' directive.
4702 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
4703 Action.Enter(CGF);
4704 emitOMPCopyinClause(CGF, S);
4705 (void)emitWorksharingDirective(CGF, S, /*HasCancel=*/false);
4706 };
4707 {
4708 const auto &&NumIteratorsGen = [&S](CodeGenFunction &CGF) {
4711 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGSI);
4712 OMPLoopScope LoopScope(CGF, S);
4713 return CGF.EmitScalarExpr(S.getNumIterations());
4714 };
4715 bool IsInscan = llvm::any_of(S.getClausesOfKind<OMPReductionClause>(),
4716 [](const OMPReductionClause *C) {
4717 return C->getModifier() == OMPC_REDUCTION_inscan;
4718 });
4719 if (IsInscan)
4720 emitScanBasedDirectiveDecls(*this, S, NumIteratorsGen);
4721 auto LPCRegion =
4723 emitCommonOMPParallelDirective(*this, S, OMPD_for_simd, CodeGen,
4725 if (IsInscan)
4726 emitScanBasedDirectiveFinals(*this, S, NumIteratorsGen);
4727 }
4728 // Check for outer lastprivate conditional update.
4730}
4731
4733 const OMPParallelMasterDirective &S) {
4734 // Emit directive as a combined directive that consists of two implicit
4735 // directives: 'parallel' with 'master' directive.
4736 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
4737 Action.Enter(CGF);
4738 OMPPrivateScope PrivateScope(CGF);
4739 emitOMPCopyinClause(CGF, S);
4740 (void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
4741 CGF.EmitOMPPrivateClause(S, PrivateScope);
4742 CGF.EmitOMPReductionClauseInit(S, PrivateScope);
4743 (void)PrivateScope.Privatize();
4744 emitMaster(CGF, S);
4745 CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_parallel);
4746 };
4747 {
4748 auto LPCRegion =
4750 emitCommonOMPParallelDirective(*this, S, OMPD_master, CodeGen,
4753 [](CodeGenFunction &) { return nullptr; });
4754 }
4755 // Check for outer lastprivate conditional update.
4757}
4758
4760 const OMPParallelMaskedDirective &S) {
4761 // Emit directive as a combined directive that consists of two implicit
4762 // directives: 'parallel' with 'masked' directive.
4763 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
4764 Action.Enter(CGF);
4765 OMPPrivateScope PrivateScope(CGF);
4766 emitOMPCopyinClause(CGF, S);
4767 (void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
4768 CGF.EmitOMPPrivateClause(S, PrivateScope);
4769 CGF.EmitOMPReductionClauseInit(S, PrivateScope);
4770 (void)PrivateScope.Privatize();
4771 emitMasked(CGF, S);
4772 CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_parallel);
4773 };
4774 {
4775 auto LPCRegion =
4777 emitCommonOMPParallelDirective(*this, S, OMPD_masked, CodeGen,
4780 [](CodeGenFunction &) { return nullptr; });
4781 }
4782 // Check for outer lastprivate conditional update.
4784}
4785
4787 const OMPParallelSectionsDirective &S) {
4788 // Emit directive as a combined directive that consists of two implicit
4789 // directives: 'parallel' with 'sections' directive.
4790 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
4791 Action.Enter(CGF);
4792 emitOMPCopyinClause(CGF, S);
4793 CGF.EmitSections(S);
4794 };
4795 {
4796 auto LPCRegion =
4798 emitCommonOMPParallelDirective(*this, S, OMPD_sections, CodeGen,
4800 }
4801 // Check for outer lastprivate conditional update.
4803}
4804
4805namespace {
4806/// Get the list of variables declared in the context of the untied tasks.
4807class CheckVarsEscapingUntiedTaskDeclContext final
4808 : public ConstStmtVisitor<CheckVarsEscapingUntiedTaskDeclContext> {
4810
4811public:
4812 explicit CheckVarsEscapingUntiedTaskDeclContext() = default;
4813 ~CheckVarsEscapingUntiedTaskDeclContext() = default;
4814 void VisitDeclStmt(const DeclStmt *S) {
4815 if (!S)
4816 return;
4817 // Need to privatize only local vars, static locals can be processed as is.
4818 for (const Decl *D : S->decls()) {
4819 if (const auto *VD = dyn_cast_or_null<VarDecl>(D))
4820 if (VD->hasLocalStorage())
4821 PrivateDecls.push_back(VD);
4822 }
4823 }
4824 void VisitOMPExecutableDirective(const OMPExecutableDirective *) {}
4825 void VisitCapturedStmt(const CapturedStmt *) {}
4826 void VisitLambdaExpr(const LambdaExpr *) {}
4827 void VisitBlockExpr(const BlockExpr *) {}
4828 void VisitStmt(const Stmt *S) {
4829 if (!S)
4830 return;
4831 for (const Stmt *Child : S->children())
4832 if (Child)
4833 Visit(Child);
4834 }
4835
4836 /// Swaps list of vars with the provided one.
4837 ArrayRef<const VarDecl *> getPrivateDecls() const { return PrivateDecls; }
4838};
4839} // anonymous namespace
4840
4843
4844 // First look for 'omp_all_memory' and add this first.
4845 bool OmpAllMemory = false;
4846 if (llvm::any_of(
4847 S.getClausesOfKind<OMPDependClause>(), [](const OMPDependClause *C) {
4848 return C->getDependencyKind() == OMPC_DEPEND_outallmemory ||
4849 C->getDependencyKind() == OMPC_DEPEND_inoutallmemory;
4850 })) {
4851 OmpAllMemory = true;
4852 // Since both OMPC_DEPEND_outallmemory and OMPC_DEPEND_inoutallmemory are
4853 // equivalent to the runtime, always use OMPC_DEPEND_outallmemory to
4854 // simplify.
4856 Data.Dependences.emplace_back(OMPC_DEPEND_outallmemory,
4857 /*IteratorExpr=*/nullptr);
4858 // Add a nullptr Expr to simplify the codegen in emitDependData.
4859 DD.DepExprs.push_back(nullptr);
4860 }
4861 // Add remaining dependences skipping any 'out' or 'inout' if they are
4862 // overridden by 'omp_all_memory'.
4863 for (const auto *C : S.getClausesOfKind<OMPDependClause>()) {
4864 OpenMPDependClauseKind Kind = C->getDependencyKind();
4865 if (Kind == OMPC_DEPEND_outallmemory || Kind == OMPC_DEPEND_inoutallmemory)
4866 continue;
4867 if (OmpAllMemory && (Kind == OMPC_DEPEND_out || Kind == OMPC_DEPEND_inout))
4868 continue;
4870 Data.Dependences.emplace_back(C->getDependencyKind(), C->getModifier());
4871 DD.DepExprs.append(C->varlist_begin(), C->varlist_end());
4872 }
4873}
4874
4876 const OMPExecutableDirective &S, const OpenMPDirectiveKind CapturedRegion,
4877 const RegionCodeGenTy &BodyGen, const TaskGenTy &TaskGen,
4879 // Emit outlined function for task construct.
4880 const CapturedStmt *CS = S.getCapturedStmt(CapturedRegion);
4881 auto I = CS->getCapturedDecl()->param_begin();
4882 auto PartId = std::next(I);
4883 auto TaskT = std::next(I, 4);
4884 // Check if the task is final
4885 if (const auto *Clause = S.getSingleClause<OMPFinalClause>()) {
4886 // If the condition constant folds and can be elided, try to avoid emitting
4887 // the condition and the dead arm of the if/else.
4888 const Expr *Cond = Clause->getCondition();
4889 bool CondConstant;
4890 if (ConstantFoldsToSimpleInteger(Cond, CondConstant))
4891 Data.Final.setInt(CondConstant);
4892 else
4893 Data.Final.setPointer(EvaluateExprAsBool(Cond));
4894 } else {
4895 // By default the task is not final.
4896 Data.Final.setInt(/*IntVal=*/false);
4897 }
4898 // Check if the task has 'priority' clause.
4899 if (const auto *Clause = S.getSingleClause<OMPPriorityClause>()) {
4900 const Expr *Prio = Clause->getPriority();
4901 Data.Priority.setInt(/*IntVal=*/true);
4902 Data.Priority.setPointer(EmitScalarConversion(
4903 EmitScalarExpr(Prio), Prio->getType(),
4904 getContext().getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1),
4905 Prio->getExprLoc()));
4906 }
4907 // The first function argument for tasks is a thread id, the second one is a
4908 // part id (0 for tied tasks, >=0 for untied task).
4909 llvm::DenseSet<const VarDecl *> EmittedAsPrivate;
4910 // Get list of private variables.
4911 for (const auto *C : S.getClausesOfKind<OMPPrivateClause>()) {
4912 auto IRef = C->varlist_begin();
4913 for (const Expr *IInit : C->private_copies()) {
4914 const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
4915 if (EmittedAsPrivate.insert(OrigVD->getCanonicalDecl()).second) {
4916 Data.PrivateVars.push_back(*IRef);
4917 Data.PrivateCopies.push_back(IInit);
4918 }
4919 ++IRef;
4920 }
4921 }
4922 EmittedAsPrivate.clear();
4923 // Get list of firstprivate variables.
4924 for (const auto *C : S.getClausesOfKind<OMPFirstprivateClause>()) {
4925 auto IRef = C->varlist_begin();
4926 auto IElemInitRef = C->inits().begin();
4927 for (const Expr *IInit : C->private_copies()) {
4928 const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
4929 if (EmittedAsPrivate.insert(OrigVD->getCanonicalDecl()).second) {
4930 Data.FirstprivateVars.push_back(*IRef);
4931 Data.FirstprivateCopies.push_back(IInit);
4932 Data.FirstprivateInits.push_back(*IElemInitRef);
4933 }
4934 ++IRef;
4935 ++IElemInitRef;
4936 }
4937 }
4938 // Get list of lastprivate variables (for taskloops).
4939 llvm::MapVector<const VarDecl *, const DeclRefExpr *> LastprivateDstsOrigs;
4940 for (const auto *C : S.getClausesOfKind<OMPLastprivateClause>()) {
4941 auto IRef = C->varlist_begin();
4942 auto ID = C->destination_exprs().begin();
4943 for (const Expr *IInit : C->private_copies()) {
4944 const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
4945 if (EmittedAsPrivate.insert(OrigVD->getCanonicalDecl()).second) {
4946 Data.LastprivateVars.push_back(*IRef);
4947 Data.LastprivateCopies.push_back(IInit);
4948 }
4949 LastprivateDstsOrigs.insert(
4950 std::make_pair(cast<VarDecl>(cast<DeclRefExpr>(*ID)->getDecl()),
4951 cast<DeclRefExpr>(*IRef)));
4952 ++IRef;
4953 ++ID;
4954 }
4955 }
4958 for (const auto *C : S.getClausesOfKind<OMPReductionClause>()) {
4959 Data.ReductionVars.append(C->varlist_begin(), C->varlist_end());
4960 Data.ReductionOrigs.append(C->varlist_begin(), C->varlist_end());
4961 Data.ReductionCopies.append(C->privates().begin(), C->privates().end());
4962 Data.ReductionOps.append(C->reduction_ops().begin(),
4963 C->reduction_ops().end());
4964 LHSs.append(C->lhs_exprs().begin(), C->lhs_exprs().end());
4965 RHSs.append(C->rhs_exprs().begin(), C->rhs_exprs().end());
4966 }
4967 Data.Reductions = CGM.getOpenMPRuntime().emitTaskReductionInit(
4968 *this, S.getBeginLoc(), LHSs, RHSs, Data);
4969 // Build list of dependences.
4971 // Get list of local vars for untied tasks.
4972 if (!Data.Tied) {
4973 CheckVarsEscapingUntiedTaskDeclContext Checker;
4974 Checker.Visit(S.getInnermostCapturedStmt()->getCapturedStmt());
4975 Data.PrivateLocals.append(Checker.getPrivateDecls().begin(),
4976 Checker.getPrivateDecls().end());
4977 }
4978 auto &&CodeGen = [&Data, &S, CS, &BodyGen, &LastprivateDstsOrigs,
4979 CapturedRegion](CodeGenFunction &CGF,
4980 PrePostActionTy &Action) {
4981 llvm::MapVector<CanonicalDeclPtr<const VarDecl>,
4982 std::pair<Address, Address>>
4983 UntiedLocalVars;
4984 // Set proper addresses for generated private copies.
4986 // Generate debug info for variables present in shared clause.
4987 if (auto *DI = CGF.getDebugInfo()) {
4988 llvm::SmallDenseMap<const VarDecl *, FieldDecl *> CaptureFields =
4989 CGF.CapturedStmtInfo->getCaptureFields();
4990 llvm::Value *ContextValue = CGF.CapturedStmtInfo->getContextValue();
4991 if (CaptureFields.size() && ContextValue) {
4992 unsigned CharWidth = CGF.getContext().getCharWidth();
4993 // The shared variables are packed together as members of structure.
4994 // So the address of each shared variable can be computed by adding
4995 // offset of it (within record) to the base address of record. For each
4996 // shared variable, debug intrinsic llvm.dbg.declare is generated with
4997 // appropriate expressions (DIExpression).
4998 // Ex:
4999 // %12 = load %struct.anon*, %struct.anon** %__context.addr.i
5000 // call void @llvm.dbg.declare(metadata %struct.anon* %12,
5001 // metadata !svar1,
5002 // metadata !DIExpression(DW_OP_deref))
5003 // call void @llvm.dbg.declare(metadata %struct.anon* %12,
5004 // metadata !svar2,
5005 // metadata !DIExpression(DW_OP_plus_uconst, 8, DW_OP_deref))
5006 for (auto It = CaptureFields.begin(); It != CaptureFields.end(); ++It) {
5007 const VarDecl *SharedVar = It->first;
5008 RecordDecl *CaptureRecord = It->second->getParent();
5009 const ASTRecordLayout &Layout =
5010 CGF.getContext().getASTRecordLayout(CaptureRecord);
5011 unsigned Offset =
5012 Layout.getFieldOffset(It->second->getFieldIndex()) / CharWidth;
5013 if (CGF.CGM.getCodeGenOpts().hasReducedDebugInfo())
5014 (void)DI->EmitDeclareOfAutoVariable(SharedVar, ContextValue,
5015 CGF.Builder, false);
5016 // Get the call dbg.declare instruction we just created and update
5017 // its DIExpression to add offset to base address.
5018 auto UpdateExpr = [](llvm::LLVMContext &Ctx, auto *Declare,
5019 unsigned Offset) {
5021 // Add offset to the base address if non zero.
5022 if (Offset) {
5023 Ops.push_back(llvm::dwarf::DW_OP_plus_uconst);
5024 Ops.push_back(Offset);
5025 }
5026 Ops.push_back(llvm::dwarf::DW_OP_deref);
5027 Declare->setExpression(llvm::DIExpression::get(Ctx, Ops));
5028 };
5029 llvm::Instruction &Last = CGF.Builder.GetInsertBlock()->back();
5030 if (auto DDI = dyn_cast<llvm::DbgVariableIntrinsic>(&Last))
5031 UpdateExpr(DDI->getContext(), DDI, Offset);
5032 // If we're emitting using the new debug info format into a block
5033 // without a terminator, the record will be "trailing".
5034 assert(!Last.isTerminator() && "unexpected terminator");
5035 if (auto *Marker =
5036 CGF.Builder.GetInsertBlock()->getTrailingDbgRecords()) {
5037 for (llvm::DbgVariableRecord &DVR : llvm::reverse(
5038 llvm::filterDbgVars(Marker->getDbgRecordRange()))) {
5039 UpdateExpr(Last.getContext(), &DVR, Offset);
5040 break;
5041 }
5042 }
5043 }
5044 }
5045 }
5047 if (!Data.PrivateVars.empty() || !Data.FirstprivateVars.empty() ||
5048 !Data.LastprivateVars.empty() || !Data.PrivateLocals.empty()) {
5049 enum { PrivatesParam = 2, CopyFnParam = 3 };
5050 llvm::Value *CopyFn = CGF.Builder.CreateLoad(
5051 CGF.GetAddrOfLocalVar(CS->getCapturedDecl()->getParam(CopyFnParam)));
5052 llvm::Value *PrivatesPtr = CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(
5053 CS->getCapturedDecl()->getParam(PrivatesParam)));
5054 // Map privates.
5058 CallArgs.push_back(PrivatesPtr);
5059 ParamTypes.push_back(PrivatesPtr->getType());
5060 for (const Expr *E : Data.PrivateVars) {
5061 const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
5062 RawAddress PrivatePtr = CGF.CreateMemTemp(
5063 CGF.getContext().getPointerType(E->getType()), ".priv.ptr.addr");
5064 PrivatePtrs.emplace_back(VD, PrivatePtr);
5065 CallArgs.push_back(PrivatePtr.getPointer());
5066 ParamTypes.push_back(PrivatePtr.getType());
5067 }
5068 for (const Expr *E : Data.FirstprivateVars) {
5069 const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
5070 RawAddress PrivatePtr =
5071 CGF.CreateMemTemp(CGF.getContext().getPointerType(E->getType()),
5072 ".firstpriv.ptr.addr");
5073 PrivatePtrs.emplace_back(VD, PrivatePtr);
5074 FirstprivatePtrs.emplace_back(VD, PrivatePtr);
5075 CallArgs.push_back(PrivatePtr.getPointer());
5076 ParamTypes.push_back(PrivatePtr.getType());
5077 }
5078 for (const Expr *E : Data.LastprivateVars) {
5079 const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
5080 RawAddress PrivatePtr =
5081 CGF.CreateMemTemp(CGF.getContext().getPointerType(E->getType()),
5082 ".lastpriv.ptr.addr");
5083 PrivatePtrs.emplace_back(VD, PrivatePtr);
5084 CallArgs.push_back(PrivatePtr.getPointer());
5085 ParamTypes.push_back(PrivatePtr.getType());
5086 }
5087 for (const VarDecl *VD : Data.PrivateLocals) {
5089 if (VD->getType()->isLValueReferenceType())
5090 Ty = CGF.getContext().getPointerType(Ty);
5091 if (isAllocatableDecl(VD))
5092 Ty = CGF.getContext().getPointerType(Ty);
5093 RawAddress PrivatePtr = CGF.CreateMemTemp(
5094 CGF.getContext().getPointerType(Ty), ".local.ptr.addr");
5095 auto Result = UntiedLocalVars.insert(
5096 std::make_pair(VD, std::make_pair(PrivatePtr, Address::invalid())));
5097 // If key exists update in place.
5098 if (Result.second == false)
5099 *Result.first = std::make_pair(
5100 VD, std::make_pair(PrivatePtr, Address::invalid()));
5101 CallArgs.push_back(PrivatePtr.getPointer());
5102 ParamTypes.push_back(PrivatePtr.getType());
5103 }
5104 auto *CopyFnTy = llvm::FunctionType::get(CGF.Builder.getVoidTy(),
5105 ParamTypes, /*isVarArg=*/false);
5106 CGF.CGM.getOpenMPRuntime().emitOutlinedFunctionCall(
5107 CGF, S.getBeginLoc(), {CopyFnTy, CopyFn}, CallArgs);
5108 for (const auto &Pair : LastprivateDstsOrigs) {
5109 const auto *OrigVD = cast<VarDecl>(Pair.second->getDecl());
5110 DeclRefExpr DRE(CGF.getContext(), const_cast<VarDecl *>(OrigVD),
5111 /*RefersToEnclosingVariableOrCapture=*/
5112 CGF.CapturedStmtInfo->lookup(OrigVD) != nullptr,
5113 Pair.second->getType(), VK_LValue,
5114 Pair.second->getExprLoc());
5115 Scope.addPrivate(Pair.first, CGF.EmitLValue(&DRE).getAddress());
5116 }
5117 for (const auto &Pair : PrivatePtrs) {
5118 Address Replacement = Address(
5119 CGF.Builder.CreateLoad(Pair.second),
5120 CGF.ConvertTypeForMem(Pair.first->getType().getNonReferenceType()),
5121 CGF.getContext().getDeclAlign(Pair.first));
5122 Scope.addPrivate(Pair.first, Replacement);
5123 if (auto *DI = CGF.getDebugInfo())
5124 if (CGF.CGM.getCodeGenOpts().hasReducedDebugInfo())
5125 (void)DI->EmitDeclareOfAutoVariable(
5126 Pair.first, Pair.second.getBasePointer(), CGF.Builder,
5127 /*UsePointerValue*/ true);
5128 }
5129 // Adjust mapping for internal locals by mapping actual memory instead of
5130 // a pointer to this memory.
5131 for (auto &Pair : UntiedLocalVars) {
5132 QualType VDType = Pair.first->getType().getNonReferenceType();
5133 if (Pair.first->getType()->isLValueReferenceType())
5134 VDType = CGF.getContext().getPointerType(VDType);
5135 if (isAllocatableDecl(Pair.first)) {
5136 llvm::Value *Ptr = CGF.Builder.CreateLoad(Pair.second.first);
5137 Address Replacement(
5138 Ptr,
5139 CGF.ConvertTypeForMem(CGF.getContext().getPointerType(VDType)),
5140 CGF.getPointerAlign());
5141 Pair.second.first = Replacement;
5142 Ptr = CGF.Builder.CreateLoad(Replacement);
5143 Replacement = Address(Ptr, CGF.ConvertTypeForMem(VDType),
5144 CGF.getContext().getDeclAlign(Pair.first));
5145 Pair.second.second = Replacement;
5146 } else {
5147 llvm::Value *Ptr = CGF.Builder.CreateLoad(Pair.second.first);
5148 Address Replacement(Ptr, CGF.ConvertTypeForMem(VDType),
5149 CGF.getContext().getDeclAlign(Pair.first));
5150 Pair.second.first = Replacement;
5151 }
5152 }
5153 }
5154 if (Data.Reductions) {
5155 OMPPrivateScope FirstprivateScope(CGF);
5156 for (const auto &Pair : FirstprivatePtrs) {
5157 Address Replacement(
5158 CGF.Builder.CreateLoad(Pair.second),
5159 CGF.ConvertTypeForMem(Pair.first->getType().getNonReferenceType()),
5160 CGF.getContext().getDeclAlign(Pair.first));
5161 FirstprivateScope.addPrivate(Pair.first, Replacement);
5162 }
5163 (void)FirstprivateScope.Privatize();
5164 OMPLexicalScope LexScope(CGF, S, CapturedRegion);
5165 ReductionCodeGen RedCG(Data.ReductionVars, Data.ReductionVars,
5166 Data.ReductionCopies, Data.ReductionOps);
5167 llvm::Value *ReductionsPtr = CGF.Builder.CreateLoad(
5168 CGF.GetAddrOfLocalVar(CS->getCapturedDecl()->getParam(9)));
5169 for (unsigned Cnt = 0, E = Data.ReductionVars.size(); Cnt < E; ++Cnt) {
5170 RedCG.emitSharedOrigLValue(CGF, Cnt);
5171 RedCG.emitAggregateType(CGF, Cnt);
5172 // FIXME: This must removed once the runtime library is fixed.
5173 // Emit required threadprivate variables for
5174 // initializer/combiner/finalizer.
5175 CGF.CGM.getOpenMPRuntime().emitTaskReductionFixups(CGF, S.getBeginLoc(),
5176 RedCG, Cnt);
5177 Address Replacement = CGF.CGM.getOpenMPRuntime().getTaskReductionItem(
5178 CGF, S.getBeginLoc(), ReductionsPtr, RedCG.getSharedLValue(Cnt));
5179 Replacement = Address(
5180 CGF.EmitScalarConversion(Replacement.emitRawPointer(CGF),
5181 CGF.getContext().VoidPtrTy,
5182 CGF.getContext().getPointerType(
5183 Data.ReductionCopies[Cnt]->getType()),
5184 Data.ReductionCopies[Cnt]->getExprLoc()),
5185 CGF.ConvertTypeForMem(Data.ReductionCopies[Cnt]->getType()),
5186 Replacement.getAlignment());
5187 Replacement = RedCG.adjustPrivateAddress(CGF, Cnt, Replacement);
5188 Scope.addPrivate(RedCG.getBaseDecl(Cnt), Replacement);
5189 }
5190 }
5191 // Privatize all private variables except for in_reduction items.
5192 (void)Scope.Privatize();
5196 SmallVector<const Expr *, 4> TaskgroupDescriptors;
5197 for (const auto *C : S.getClausesOfKind<OMPInReductionClause>()) {
5198 auto IPriv = C->privates().begin();
5199 auto IRed = C->reduction_ops().begin();
5200 auto ITD = C->taskgroup_descriptors().begin();
5201 for (const Expr *Ref : C->varlist()) {
5202 InRedVars.emplace_back(Ref);
5203 InRedPrivs.emplace_back(*IPriv);
5204 InRedOps.emplace_back(*IRed);
5205 TaskgroupDescriptors.emplace_back(*ITD);
5206 std::advance(IPriv, 1);
5207 std::advance(IRed, 1);
5208 std::advance(ITD, 1);
5209 }
5210 }
5211 // Privatize in_reduction items here, because taskgroup descriptors must be
5212 // privatized earlier.
5213 OMPPrivateScope InRedScope(CGF);
5214 if (!InRedVars.empty()) {
5215 ReductionCodeGen RedCG(InRedVars, InRedVars, InRedPrivs, InRedOps);
5216 for (unsigned Cnt = 0, E = InRedVars.size(); Cnt < E; ++Cnt) {
5217 RedCG.emitSharedOrigLValue(CGF, Cnt);
5218 RedCG.emitAggregateType(CGF, Cnt);
5219 // The taskgroup descriptor variable is always implicit firstprivate and
5220 // privatized already during processing of the firstprivates.
5221 // FIXME: This must removed once the runtime library is fixed.
5222 // Emit required threadprivate variables for
5223 // initializer/combiner/finalizer.
5224 CGF.CGM.getOpenMPRuntime().emitTaskReductionFixups(CGF, S.getBeginLoc(),
5225 RedCG, Cnt);
5226 llvm::Value *ReductionsPtr;
5227 if (const Expr *TRExpr = TaskgroupDescriptors[Cnt]) {
5228 ReductionsPtr = CGF.EmitLoadOfScalar(CGF.EmitLValue(TRExpr),
5229 TRExpr->getExprLoc());
5230 } else {
5231 ReductionsPtr = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
5232 }
5233 Address Replacement = CGF.CGM.getOpenMPRuntime().getTaskReductionItem(
5234 CGF, S.getBeginLoc(), ReductionsPtr, RedCG.getSharedLValue(Cnt));
5235 Replacement = Address(
5236 CGF.EmitScalarConversion(
5237 Replacement.emitRawPointer(CGF), CGF.getContext().VoidPtrTy,
5238 CGF.getContext().getPointerType(InRedPrivs[Cnt]->getType()),
5239 InRedPrivs[Cnt]->getExprLoc()),
5240 CGF.ConvertTypeForMem(InRedPrivs[Cnt]->getType()),
5241 Replacement.getAlignment());
5242 Replacement = RedCG.adjustPrivateAddress(CGF, Cnt, Replacement);
5243 InRedScope.addPrivate(RedCG.getBaseDecl(Cnt), Replacement);
5244 }
5245 }
5246 (void)InRedScope.Privatize();
5247
5249 UntiedLocalVars);
5250 Action.Enter(CGF);
5251 BodyGen(CGF);
5252 };
5254 llvm::Function *OutlinedFn = CGM.getOpenMPRuntime().emitTaskOutlinedFunction(
5255 S, *I, *PartId, *TaskT, EKind, CodeGen, Data.Tied, Data.NumberOfParts);
5256 OMPLexicalScope Scope(*this, S, std::nullopt,
5257 !isOpenMPParallelDirective(EKind) &&
5258 !isOpenMPSimdDirective(EKind));
5259 TaskGen(*this, OutlinedFn, Data);
5260}
5261
5262static ImplicitParamDecl *
5264 QualType Ty, CapturedDecl *CD,
5265 SourceLocation Loc) {
5266 auto *OrigVD = ImplicitParamDecl::Create(C, CD, Loc, /*Id=*/nullptr, Ty,
5268 auto *OrigRef = DeclRefExpr::Create(
5270 /*RefersToEnclosingVariableOrCapture=*/false, Loc, Ty, VK_LValue);
5271 auto *PrivateVD = ImplicitParamDecl::Create(C, CD, Loc, /*Id=*/nullptr, Ty,
5273 auto *PrivateRef = DeclRefExpr::Create(
5274 C, NestedNameSpecifierLoc(), SourceLocation(), PrivateVD,
5275 /*RefersToEnclosingVariableOrCapture=*/false, Loc, Ty, VK_LValue);
5276 QualType ElemType = C.getBaseElementType(Ty);
5277 auto *InitVD = ImplicitParamDecl::Create(C, CD, Loc, /*Id=*/nullptr, ElemType,
5279 auto *InitRef = DeclRefExpr::Create(
5281 /*RefersToEnclosingVariableOrCapture=*/false, Loc, ElemType, VK_LValue);
5282 PrivateVD->setInitStyle(VarDecl::CInit);
5283 PrivateVD->setInit(ImplicitCastExpr::Create(C, ElemType, CK_LValueToRValue,
5284 InitRef, /*BasePath=*/nullptr,
5286 Data.FirstprivateVars.emplace_back(OrigRef);
5287 Data.FirstprivateCopies.emplace_back(PrivateRef);
5288 Data.FirstprivateInits.emplace_back(InitRef);
5289 return OrigVD;
5290}
5291
5293 const OMPExecutableDirective &S, const RegionCodeGenTy &BodyGen,
5294 OMPTargetDataInfo &InputInfo) {
5295 // Emit outlined function for task construct.
5296 const CapturedStmt *CS = S.getCapturedStmt(OMPD_task);
5297 Address CapturedStruct = GenerateCapturedStmtArgument(*CS);
5298 CanQualType SharedsTy =
5300 auto I = CS->getCapturedDecl()->param_begin();
5301 auto PartId = std::next(I);
5302 auto TaskT = std::next(I, 4);
5304 // The task is not final.
5305 Data.Final.setInt(/*IntVal=*/false);
5306 // Get list of firstprivate variables.
5307 for (const auto *C : S.getClausesOfKind<OMPFirstprivateClause>()) {
5308 auto IRef = C->varlist_begin();
5309 auto IElemInitRef = C->inits().begin();
5310 for (auto *IInit : C->private_copies()) {
5311 Data.FirstprivateVars.push_back(*IRef);
5312 Data.FirstprivateCopies.push_back(IInit);
5313 Data.FirstprivateInits.push_back(*IElemInitRef);
5314 ++IRef;
5315 ++IElemInitRef;
5316 }
5317 }
5320 for (const auto *C : S.getClausesOfKind<OMPInReductionClause>()) {
5321 Data.ReductionVars.append(C->varlist_begin(), C->varlist_end());
5322 Data.ReductionOrigs.append(C->varlist_begin(), C->varlist_end());
5323 Data.ReductionCopies.append(C->privates().begin(), C->privates().end());
5324 Data.ReductionOps.append(C->reduction_ops().begin(),
5325 C->reduction_ops().end());
5326 LHSs.append(C->lhs_exprs().begin(), C->lhs_exprs().end());
5327 RHSs.append(C->rhs_exprs().begin(), C->rhs_exprs().end());
5328 }
5329 OMPPrivateScope TargetScope(*this);
5330 VarDecl *BPVD = nullptr;
5331 VarDecl *PVD = nullptr;
5332 VarDecl *SVD = nullptr;
5333 VarDecl *MVD = nullptr;
5334 if (InputInfo.NumberOfTargetItems > 0) {
5335 auto *CD = CapturedDecl::Create(
5336 getContext(), getContext().getTranslationUnitDecl(), /*NumParams=*/0);
5337 llvm::APInt ArrSize(/*numBits=*/32, InputInfo.NumberOfTargetItems);
5338 QualType BaseAndPointerAndMapperType = getContext().getConstantArrayType(
5339 getContext().VoidPtrTy, ArrSize, nullptr, ArraySizeModifier::Normal,
5340 /*IndexTypeQuals=*/0);
5342 getContext(), Data, BaseAndPointerAndMapperType, CD, S.getBeginLoc());
5344 getContext(), Data, BaseAndPointerAndMapperType, CD, S.getBeginLoc());
5346 getContext().getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1),
5347 ArrSize, nullptr, ArraySizeModifier::Normal,
5348 /*IndexTypeQuals=*/0);
5349 SVD = createImplicitFirstprivateForType(getContext(), Data, SizesType, CD,
5350 S.getBeginLoc());
5351 TargetScope.addPrivate(BPVD, InputInfo.BasePointersArray);
5352 TargetScope.addPrivate(PVD, InputInfo.PointersArray);
5353 TargetScope.addPrivate(SVD, InputInfo.SizesArray);
5354 // If there is no user-defined mapper, the mapper array will be nullptr. In
5355 // this case, we don't need to privatize it.
5356 if (!isa_and_nonnull<llvm::ConstantPointerNull>(
5357 InputInfo.MappersArray.emitRawPointer(*this))) {
5359 getContext(), Data, BaseAndPointerAndMapperType, CD, S.getBeginLoc());
5360 TargetScope.addPrivate(MVD, InputInfo.MappersArray);
5361 }
5362 }
5363 (void)TargetScope.Privatize();
5366 auto &&CodeGen = [&Data, &S, CS, &BodyGen, BPVD, PVD, SVD, MVD, EKind,
5367 &InputInfo](CodeGenFunction &CGF, PrePostActionTy &Action) {
5368 // Set proper addresses for generated private copies.
5370 if (!Data.FirstprivateVars.empty()) {
5371 enum { PrivatesParam = 2, CopyFnParam = 3 };
5372 llvm::Value *CopyFn = CGF.Builder.CreateLoad(
5373 CGF.GetAddrOfLocalVar(CS->getCapturedDecl()->getParam(CopyFnParam)));
5374 llvm::Value *PrivatesPtr = CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(
5375 CS->getCapturedDecl()->getParam(PrivatesParam)));
5376 // Map privates.
5380 CallArgs.push_back(PrivatesPtr);
5381 ParamTypes.push_back(PrivatesPtr->getType());
5382 for (const Expr *E : Data.FirstprivateVars) {
5383 const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
5384 RawAddress PrivatePtr =
5385 CGF.CreateMemTemp(CGF.getContext().getPointerType(E->getType()),
5386 ".firstpriv.ptr.addr");
5387 PrivatePtrs.emplace_back(VD, PrivatePtr);
5388 CallArgs.push_back(PrivatePtr.getPointer());
5389 ParamTypes.push_back(PrivatePtr.getType());
5390 }
5391 auto *CopyFnTy = llvm::FunctionType::get(CGF.Builder.getVoidTy(),
5392 ParamTypes, /*isVarArg=*/false);
5393 CGF.CGM.getOpenMPRuntime().emitOutlinedFunctionCall(
5394 CGF, S.getBeginLoc(), {CopyFnTy, CopyFn}, CallArgs);
5395 for (const auto &Pair : PrivatePtrs) {
5396 Address Replacement(
5397 CGF.Builder.CreateLoad(Pair.second),
5398 CGF.ConvertTypeForMem(Pair.first->getType().getNonReferenceType()),
5399 CGF.getContext().getDeclAlign(Pair.first));
5400 Scope.addPrivate(Pair.first, Replacement);
5401 }
5402 }
5403 CGF.processInReduction(S, Data, CGF, CS, Scope);
5404 if (InputInfo.NumberOfTargetItems > 0) {
5405 InputInfo.BasePointersArray = CGF.Builder.CreateConstArrayGEP(
5406 CGF.GetAddrOfLocalVar(BPVD), /*Index=*/0);
5407 InputInfo.PointersArray = CGF.Builder.CreateConstArrayGEP(
5408 CGF.GetAddrOfLocalVar(PVD), /*Index=*/0);
5409 InputInfo.SizesArray = CGF.Builder.CreateConstArrayGEP(
5410 CGF.GetAddrOfLocalVar(SVD), /*Index=*/0);
5411 // If MVD is nullptr, the mapper array is not privatized
5412 if (MVD)
5413 InputInfo.MappersArray = CGF.Builder.CreateConstArrayGEP(
5414 CGF.GetAddrOfLocalVar(MVD), /*Index=*/0);
5415 }
5416
5417 Action.Enter(CGF);
5418 OMPLexicalScope LexScope(CGF, S, OMPD_task, /*EmitPreInitStmt=*/false);
5419 auto *TL = S.getSingleClause<OMPThreadLimitClause>();
5420 if (CGF.CGM.getLangOpts().OpenMP >= 51 &&
5421 needsTaskBasedThreadLimit(EKind) && TL) {
5422 // Emit __kmpc_set_thread_limit() to set the thread_limit for the task
5423 // enclosing this target region. This will indirectly set the thread_limit
5424 // for every applicable construct within target region.
5425 CGF.CGM.getOpenMPRuntime().emitThreadLimitClause(
5426 CGF, TL->getThreadLimit().front(), S.getBeginLoc());
5427 }
5428 BodyGen(CGF);
5429 };
5430 llvm::Function *OutlinedFn = CGM.getOpenMPRuntime().emitTaskOutlinedFunction(
5431 S, *I, *PartId, *TaskT, EKind, CodeGen, /*Tied=*/true,
5432 Data.NumberOfParts);
5433 llvm::APInt TrueOrFalse(32, S.hasClausesOfKind<OMPNowaitClause>() ? 1 : 0);
5434 IntegerLiteral IfCond(getContext(), TrueOrFalse,
5435 getContext().getIntTypeForBitwidth(32, /*Signed=*/0),
5436 SourceLocation());
5437 CGM.getOpenMPRuntime().emitTaskCall(*this, S.getBeginLoc(), S, OutlinedFn,
5438 SharedsTy, CapturedStruct, &IfCond, Data);
5439}
5440
5443 CodeGenFunction &CGF,
5444 const CapturedStmt *CS,
5447 if (Data.Reductions) {
5448 OpenMPDirectiveKind CapturedRegion = EKind;
5449 OMPLexicalScope LexScope(CGF, S, CapturedRegion);
5450 ReductionCodeGen RedCG(Data.ReductionVars, Data.ReductionVars,
5451 Data.ReductionCopies, Data.ReductionOps);
5452 llvm::Value *ReductionsPtr = CGF.Builder.CreateLoad(
5454 for (unsigned Cnt = 0, E = Data.ReductionVars.size(); Cnt < E; ++Cnt) {
5455 RedCG.emitSharedOrigLValue(CGF, Cnt);
5456 RedCG.emitAggregateType(CGF, Cnt);
5457 // FIXME: This must removed once the runtime library is fixed.
5458 // Emit required threadprivate variables for
5459 // initializer/combiner/finalizer.
5460 CGF.CGM.getOpenMPRuntime().emitTaskReductionFixups(CGF, S.getBeginLoc(),
5461 RedCG, Cnt);
5463 CGF, S.getBeginLoc(), ReductionsPtr, RedCG.getSharedLValue(Cnt));
5464 Replacement = Address(
5465 CGF.EmitScalarConversion(Replacement.emitRawPointer(CGF),
5466 CGF.getContext().VoidPtrTy,
5468 Data.ReductionCopies[Cnt]->getType()),
5469 Data.ReductionCopies[Cnt]->getExprLoc()),
5470 CGF.ConvertTypeForMem(Data.ReductionCopies[Cnt]->getType()),
5471 Replacement.getAlignment());
5472 Replacement = RedCG.adjustPrivateAddress(CGF, Cnt, Replacement);
5473 Scope.addPrivate(RedCG.getBaseDecl(Cnt), Replacement);
5474 }
5475 }
5476 (void)Scope.Privatize();
5480 SmallVector<const Expr *, 4> TaskgroupDescriptors;
5481 for (const auto *C : S.getClausesOfKind<OMPInReductionClause>()) {
5482 auto IPriv = C->privates().begin();
5483 auto IRed = C->reduction_ops().begin();
5484 auto ITD = C->taskgroup_descriptors().begin();
5485 for (const Expr *Ref : C->varlist()) {
5486 InRedVars.emplace_back(Ref);
5487 InRedPrivs.emplace_back(*IPriv);
5488 InRedOps.emplace_back(*IRed);
5489 TaskgroupDescriptors.emplace_back(*ITD);
5490 std::advance(IPriv, 1);
5491 std::advance(IRed, 1);
5492 std::advance(ITD, 1);
5493 }
5494 }
5495 OMPPrivateScope InRedScope(CGF);
5496 if (!InRedVars.empty()) {
5497 ReductionCodeGen RedCG(InRedVars, InRedVars, InRedPrivs, InRedOps);
5498 for (unsigned Cnt = 0, E = InRedVars.size(); Cnt < E; ++Cnt) {
5499 RedCG.emitSharedOrigLValue(CGF, Cnt);
5500 RedCG.emitAggregateType(CGF, Cnt);
5501 // FIXME: This must removed once the runtime library is fixed.
5502 // Emit required threadprivate variables for
5503 // initializer/combiner/finalizer.
5504 CGF.CGM.getOpenMPRuntime().emitTaskReductionFixups(CGF, S.getBeginLoc(),
5505 RedCG, Cnt);
5506 llvm::Value *ReductionsPtr;
5507 if (const Expr *TRExpr = TaskgroupDescriptors[Cnt]) {
5508 ReductionsPtr =
5509 CGF.EmitLoadOfScalar(CGF.EmitLValue(TRExpr), TRExpr->getExprLoc());
5510 } else {
5511 ReductionsPtr = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
5512 }
5514 CGF, S.getBeginLoc(), ReductionsPtr, RedCG.getSharedLValue(Cnt));
5515 Replacement = Address(
5517 Replacement.emitRawPointer(CGF), CGF.getContext().VoidPtrTy,
5518 CGF.getContext().getPointerType(InRedPrivs[Cnt]->getType()),
5519 InRedPrivs[Cnt]->getExprLoc()),
5520 CGF.ConvertTypeForMem(InRedPrivs[Cnt]->getType()),
5521 Replacement.getAlignment());
5522 Replacement = RedCG.adjustPrivateAddress(CGF, Cnt, Replacement);
5523 InRedScope.addPrivate(RedCG.getBaseDecl(Cnt), Replacement);
5524 }
5525 }
5526 (void)InRedScope.Privatize();
5527}
5528
5529void CodeGenFunction::EmitOMPTaskDirective(const OMPTaskDirective &S) {
5530 // Emit outlined function for task construct.
5531 const CapturedStmt *CS = S.getCapturedStmt(OMPD_task);
5532 Address CapturedStruct = GenerateCapturedStmtArgument(*CS);
5533 CanQualType SharedsTy =
5535 const Expr *IfCond = nullptr;
5536 for (const auto *C : S.getClausesOfKind<OMPIfClause>()) {
5537 if (C->getNameModifier() == OMPD_unknown ||
5538 C->getNameModifier() == OMPD_task) {
5539 IfCond = C->getCondition();
5540 break;
5541 }
5542 }
5543
5545 // Check if we should emit tied or untied task.
5546 Data.Tied = !S.getSingleClause<OMPUntiedClause>();
5547 auto &&BodyGen = [CS](CodeGenFunction &CGF, PrePostActionTy &) {
5548 CGF.EmitStmt(CS->getCapturedStmt());
5549 };
5550 auto &&TaskGen = [&S, SharedsTy, CapturedStruct,
5551 IfCond](CodeGenFunction &CGF, llvm::Function *OutlinedFn,
5552 const OMPTaskDataTy &Data) {
5553 CGF.CGM.getOpenMPRuntime().emitTaskCall(CGF, S.getBeginLoc(), S, OutlinedFn,
5554 SharedsTy, CapturedStruct, IfCond,
5555 Data);
5556 };
5557 auto LPCRegion =
5559 EmitOMPTaskBasedDirective(S, OMPD_task, BodyGen, TaskGen, Data);
5560}
5561
5563 const OMPTaskyieldDirective &S) {
5564 CGM.getOpenMPRuntime().emitTaskyieldCall(*this, S.getBeginLoc());
5565}
5566
5568 const OMPMessageClause *MC = S.getSingleClause<OMPMessageClause>();
5569 Expr *ME = MC ? MC->getMessageString() : nullptr;
5570 const OMPSeverityClause *SC = S.getSingleClause<OMPSeverityClause>();
5571 bool IsFatal = false;
5572 if (!SC || SC->getSeverityKind() == OMPC_SEVERITY_fatal)
5573 IsFatal = true;
5574 CGM.getOpenMPRuntime().emitErrorCall(*this, S.getBeginLoc(), ME, IsFatal);
5575}
5576
5577void CodeGenFunction::EmitOMPBarrierDirective(const OMPBarrierDirective &S) {
5578 CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getBeginLoc(), OMPD_barrier);
5579}
5580
5581void CodeGenFunction::EmitOMPTaskwaitDirective(const OMPTaskwaitDirective &S) {
5583 // Build list of dependences
5585 Data.HasNowaitClause = S.hasClausesOfKind<OMPNowaitClause>();
5586 CGM.getOpenMPRuntime().emitTaskwaitCall(*this, S.getBeginLoc(), Data);
5587}
5588
5589static bool isSupportedByOpenMPIRBuilder(const OMPTaskgroupDirective &T) {
5590 return T.clauses().empty();
5591}
5592
5594 const OMPTaskgroupDirective &S) {
5595 OMPLexicalScope Scope(*this, S, OMPD_unknown);
5596 if (CGM.getLangOpts().OpenMPIRBuilder && isSupportedByOpenMPIRBuilder(S)) {
5597 llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
5598 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
5599 InsertPointTy AllocaIP(AllocaInsertPt->getParent(),
5600 AllocaInsertPt->getIterator());
5601
5602 auto BodyGenCB = [&, this](InsertPointTy AllocaIP,
5603 InsertPointTy CodeGenIP) {
5604 Builder.restoreIP(CodeGenIP);
5605 EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt());
5606 return llvm::Error::success();
5607 };
5609 if (!CapturedStmtInfo)
5610 CapturedStmtInfo = &CapStmtInfo;
5611 llvm::OpenMPIRBuilder::InsertPointTy AfterIP =
5612 cantFail(OMPBuilder.createTaskgroup(Builder, AllocaIP, BodyGenCB));
5613 Builder.restoreIP(AfterIP);
5614 return;
5615 }
5616 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
5617 Action.Enter(CGF);
5618 if (const Expr *E = S.getReductionRef()) {
5622 for (const auto *C : S.getClausesOfKind<OMPTaskReductionClause>()) {
5623 Data.ReductionVars.append(C->varlist_begin(), C->varlist_end());
5624 Data.ReductionOrigs.append(C->varlist_begin(), C->varlist_end());
5625 Data.ReductionCopies.append(C->privates().begin(), C->privates().end());
5626 Data.ReductionOps.append(C->reduction_ops().begin(),
5627 C->reduction_ops().end());
5628 LHSs.append(C->lhs_exprs().begin(), C->lhs_exprs().end());
5629 RHSs.append(C->rhs_exprs().begin(), C->rhs_exprs().end());
5630 }
5631 llvm::Value *ReductionDesc =
5632 CGF.CGM.getOpenMPRuntime().emitTaskReductionInit(CGF, S.getBeginLoc(),
5633 LHSs, RHSs, Data);
5634 const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
5635 CGF.EmitVarDecl(*VD);
5636 CGF.EmitStoreOfScalar(ReductionDesc, CGF.GetAddrOfLocalVar(VD),
5637 /*Volatile=*/false, E->getType());
5638 }
5639 CGF.EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt());
5640 };
5641 CGM.getOpenMPRuntime().emitTaskgroupRegion(*this, CodeGen, S.getBeginLoc());
5642}
5643
5644void CodeGenFunction::EmitOMPFlushDirective(const OMPFlushDirective &S) {
5645 llvm::AtomicOrdering AO = S.getSingleClause<OMPFlushClause>()
5646 ? llvm::AtomicOrdering::NotAtomic
5647 : llvm::AtomicOrdering::AcquireRelease;
5648 CGM.getOpenMPRuntime().emitFlush(
5649 *this,
5650 [&S]() -> ArrayRef<const Expr *> {
5651 if (const auto *FlushClause = S.getSingleClause<OMPFlushClause>())
5652 return llvm::ArrayRef(FlushClause->varlist_begin(),
5653 FlushClause->varlist_end());
5654 return {};
5655 }(),
5656 S.getBeginLoc(), AO);
5657}
5658
5659void CodeGenFunction::EmitOMPDepobjDirective(const OMPDepobjDirective &S) {
5660 const auto *DO = S.getSingleClause<OMPDepobjClause>();
5661 LValue DOLVal = EmitLValue(DO->getDepobj());
5662 if (const auto *DC = S.getSingleClause<OMPDependClause>()) {
5663 // Build list and emit dependences
5666 for (auto &Dep : Data.Dependences) {
5667 Address DepAddr = CGM.getOpenMPRuntime().emitDepobjDependClause(
5668 *this, Dep, DC->getBeginLoc());
5669 EmitStoreOfScalar(DepAddr.emitRawPointer(*this), DOLVal);
5670 }
5671 return;
5672 }
5673 if (const auto *DC = S.getSingleClause<OMPDestroyClause>()) {
5674 CGM.getOpenMPRuntime().emitDestroyClause(*this, DOLVal, DC->getBeginLoc());
5675 return;
5676 }
5677 if (const auto *UC = S.getSingleClause<OMPUpdateClause>()) {
5678 CGM.getOpenMPRuntime().emitUpdateClause(
5679 *this, DOLVal, UC->getDependencyKind(), UC->getBeginLoc());
5680 return;
5681 }
5682}
5683
5686 return;
5688 bool IsInclusive = S.hasClausesOfKind<OMPInclusiveClause>();
5693 SmallVector<const Expr *, 4> ReductionOps;
5695 SmallVector<const Expr *, 4> CopyArrayTemps;
5696 SmallVector<const Expr *, 4> CopyArrayElems;
5697 for (const auto *C : ParentDir.getClausesOfKind<OMPReductionClause>()) {
5698 if (C->getModifier() != OMPC_REDUCTION_inscan)
5699 continue;
5700 Shareds.append(C->varlist_begin(), C->varlist_end());
5701 Privates.append(C->privates().begin(), C->privates().end());
5702 LHSs.append(C->lhs_exprs().begin(), C->lhs_exprs().end());
5703 RHSs.append(C->rhs_exprs().begin(), C->rhs_exprs().end());
5704 ReductionOps.append(C->reduction_ops().begin(), C->reduction_ops().end());
5705 CopyOps.append(C->copy_ops().begin(), C->copy_ops().end());
5706 CopyArrayTemps.append(C->copy_array_temps().begin(),
5707 C->copy_array_temps().end());
5708 CopyArrayElems.append(C->copy_array_elems().begin(),
5709 C->copy_array_elems().end());
5710 }
5711 if (ParentDir.getDirectiveKind() == OMPD_simd ||
5712 (getLangOpts().OpenMPSimd &&
5713 isOpenMPSimdDirective(ParentDir.getDirectiveKind()))) {
5714 // For simd directive and simd-based directives in simd only mode, use the
5715 // following codegen:
5716 // int x = 0;
5717 // #pragma omp simd reduction(inscan, +: x)
5718 // for (..) {
5719 // <first part>
5720 // #pragma omp scan inclusive(x)
5721 // <second part>
5722 // }
5723 // is transformed to:
5724 // int x = 0;
5725 // for (..) {
5726 // int x_priv = 0;
5727 // <first part>
5728 // x = x_priv + x;
5729 // x_priv = x;
5730 // <second part>
5731 // }
5732 // and
5733 // int x = 0;
5734 // #pragma omp simd reduction(inscan, +: x)
5735 // for (..) {
5736 // <first part>
5737 // #pragma omp scan exclusive(x)
5738 // <second part>
5739 // }
5740 // to
5741 // int x = 0;
5742 // for (..) {
5743 // int x_priv = 0;
5744 // <second part>
5745 // int temp = x;
5746 // x = x_priv + x;
5747 // x_priv = temp;
5748 // <first part>
5749 // }
5750 llvm::BasicBlock *OMPScanReduce = createBasicBlock("omp.inscan.reduce");
5751 EmitBranch(IsInclusive
5752 ? OMPScanReduce
5753 : BreakContinueStack.back().ContinueBlock.getBlock());
5755 {
5756 // New scope for correct construction/destruction of temp variables for
5757 // exclusive scan.
5758 LexicalScope Scope(*this, S.getSourceRange());
5760 EmitBlock(OMPScanReduce);
5761 if (!IsInclusive) {
5762 // Create temp var and copy LHS value to this temp value.
5763 // TMP = LHS;
5764 for (unsigned I = 0, E = CopyArrayElems.size(); I < E; ++I) {
5765 const Expr *PrivateExpr = Privates[I];
5766 const Expr *TempExpr = CopyArrayTemps[I];
5768 *cast<VarDecl>(cast<DeclRefExpr>(TempExpr)->getDecl()));
5769 LValue DestLVal = EmitLValue(TempExpr);
5770 LValue SrcLVal = EmitLValue(LHSs[I]);
5771 EmitOMPCopy(PrivateExpr->getType(), DestLVal.getAddress(),
5772 SrcLVal.getAddress(),
5773 cast<VarDecl>(cast<DeclRefExpr>(LHSs[I])->getDecl()),
5774 cast<VarDecl>(cast<DeclRefExpr>(RHSs[I])->getDecl()),
5775 CopyOps[I]);
5776 }
5777 }
5778 CGM.getOpenMPRuntime().emitReduction(
5779 *this, ParentDir.getEndLoc(), Privates, LHSs, RHSs, ReductionOps,
5780 {/*WithNowait=*/true, /*SimpleReduction=*/true,
5781 /*IsPrivateVarReduction*/ {}, OMPD_simd});
5782 for (unsigned I = 0, E = CopyArrayElems.size(); I < E; ++I) {
5783 const Expr *PrivateExpr = Privates[I];
5784 LValue DestLVal;
5785 LValue SrcLVal;
5786 if (IsInclusive) {
5787 DestLVal = EmitLValue(RHSs[I]);
5788 SrcLVal = EmitLValue(LHSs[I]);
5789 } else {
5790 const Expr *TempExpr = CopyArrayTemps[I];
5791 DestLVal = EmitLValue(RHSs[I]);
5792 SrcLVal = EmitLValue(TempExpr);
5793 }
5795 PrivateExpr->getType(), DestLVal.getAddress(), SrcLVal.getAddress(),
5796 cast<VarDecl>(cast<DeclRefExpr>(LHSs[I])->getDecl()),
5797 cast<VarDecl>(cast<DeclRefExpr>(RHSs[I])->getDecl()), CopyOps[I]);
5798 }
5799 }
5801 OMPScanExitBlock = IsInclusive
5802 ? BreakContinueStack.back().ContinueBlock.getBlock()
5803 : OMPScanReduce;
5805 return;
5806 }
5807 if (!IsInclusive) {
5808 EmitBranch(BreakContinueStack.back().ContinueBlock.getBlock());
5810 }
5811 if (OMPFirstScanLoop) {
5812 // Emit buffer[i] = red; at the end of the input phase.
5813 const auto *IVExpr = cast<OMPLoopDirective>(ParentDir)
5814 .getIterationVariable()
5815 ->IgnoreParenImpCasts();
5816 LValue IdxLVal = EmitLValue(IVExpr);
5817 llvm::Value *IdxVal = EmitLoadOfScalar(IdxLVal, IVExpr->getExprLoc());
5818 IdxVal = Builder.CreateIntCast(IdxVal, SizeTy, /*isSigned=*/false);
5819 for (unsigned I = 0, E = CopyArrayElems.size(); I < E; ++I) {
5820 const Expr *PrivateExpr = Privates[I];
5821 const Expr *OrigExpr = Shareds[I];
5822 const Expr *CopyArrayElem = CopyArrayElems[I];
5823 OpaqueValueMapping IdxMapping(
5824 *this,
5826 cast<ArraySubscriptExpr>(CopyArrayElem)->getIdx()),
5827 RValue::get(IdxVal));
5828 LValue DestLVal = EmitLValue(CopyArrayElem);
5829 LValue SrcLVal = EmitLValue(OrigExpr);
5831 PrivateExpr->getType(), DestLVal.getAddress(), SrcLVal.getAddress(),
5832 cast<VarDecl>(cast<DeclRefExpr>(LHSs[I])->getDecl()),
5833 cast<VarDecl>(cast<DeclRefExpr>(RHSs[I])->getDecl()), CopyOps[I]);
5834 }
5835 }
5836 EmitBranch(BreakContinueStack.back().ContinueBlock.getBlock());
5837 if (IsInclusive) {
5839 EmitBranch(BreakContinueStack.back().ContinueBlock.getBlock());
5840 }
5842 if (!OMPFirstScanLoop) {
5843 // Emit red = buffer[i]; at the entrance to the scan phase.
5844 const auto *IVExpr = cast<OMPLoopDirective>(ParentDir)
5845 .getIterationVariable()
5846 ->IgnoreParenImpCasts();
5847 LValue IdxLVal = EmitLValue(IVExpr);
5848 llvm::Value *IdxVal = EmitLoadOfScalar(IdxLVal, IVExpr->getExprLoc());
5849 IdxVal = Builder.CreateIntCast(IdxVal, SizeTy, /*isSigned=*/false);
5850 llvm::BasicBlock *ExclusiveExitBB = nullptr;
5851 if (!IsInclusive) {
5852 llvm::BasicBlock *ContBB = createBasicBlock("omp.exclusive.dec");
5853 ExclusiveExitBB = createBasicBlock("omp.exclusive.copy.exit");
5854 llvm::Value *Cmp = Builder.CreateIsNull(IdxVal);
5855 Builder.CreateCondBr(Cmp, ExclusiveExitBB, ContBB);
5856 EmitBlock(ContBB);
5857 // Use idx - 1 iteration for exclusive scan.
5858 IdxVal = Builder.CreateNUWSub(IdxVal, llvm::ConstantInt::get(SizeTy, 1));
5859 }
5860 for (unsigned I = 0, E = CopyArrayElems.size(); I < E; ++I) {
5861 const Expr *PrivateExpr = Privates[I];
5862 const Expr *OrigExpr = Shareds[I];
5863 const Expr *CopyArrayElem = CopyArrayElems[I];
5864 OpaqueValueMapping IdxMapping(
5865 *this,
5867 cast<ArraySubscriptExpr>(CopyArrayElem)->getIdx()),
5868 RValue::get(IdxVal));
5869 LValue SrcLVal = EmitLValue(CopyArrayElem);
5870 LValue DestLVal = EmitLValue(OrigExpr);
5872 PrivateExpr->getType(), DestLVal.getAddress(), SrcLVal.getAddress(),
5873 cast<VarDecl>(cast<DeclRefExpr>(LHSs[I])->getDecl()),
5874 cast<VarDecl>(cast<DeclRefExpr>(RHSs[I])->getDecl()), CopyOps[I]);
5875 }
5876 if (!IsInclusive) {
5877 EmitBlock(ExclusiveExitBB);
5878 }
5879 }
5883}
5884
5886 const CodeGenLoopTy &CodeGenLoop,
5887 Expr *IncExpr) {
5888 // Emit the loop iteration variable.
5889 const auto *IVExpr = cast<DeclRefExpr>(S.getIterationVariable());
5890 const auto *IVDecl = cast<VarDecl>(IVExpr->getDecl());
5891 EmitVarDecl(*IVDecl);
5892
5893 // Emit the iterations count variable.
5894 // If it is not a variable, Sema decided to calculate iterations count on each
5895 // iteration (e.g., it is foldable into a constant).
5896 if (const auto *LIExpr = dyn_cast<DeclRefExpr>(S.getLastIteration())) {
5897 EmitVarDecl(*cast<VarDecl>(LIExpr->getDecl()));
5898 // Emit calculation of the iterations count.
5899 EmitIgnoredExpr(S.getCalcLastIteration());
5900 }
5901
5902 CGOpenMPRuntime &RT = CGM.getOpenMPRuntime();
5903
5904 bool HasLastprivateClause = false;
5905 // Check pre-condition.
5906 {
5907 OMPLoopScope PreInitScope(*this, S);
5908 // Skip the entire loop if we don't meet the precondition.
5909 // If the condition constant folds and can be elided, avoid emitting the
5910 // whole loop.
5911 bool CondConstant;
5912 llvm::BasicBlock *ContBlock = nullptr;
5913 if (ConstantFoldsToSimpleInteger(S.getPreCond(), CondConstant)) {
5914 if (!CondConstant)
5915 return;
5916 } else {
5917 llvm::BasicBlock *ThenBlock = createBasicBlock("omp.precond.then");
5918 ContBlock = createBasicBlock("omp.precond.end");
5919 emitPreCond(*this, S, S.getPreCond(), ThenBlock, ContBlock,
5920 getProfileCount(&S));
5921 EmitBlock(ThenBlock);
5923 }
5924
5925 emitAlignedClause(*this, S);
5926 // Emit 'then' code.
5927 {
5928 // Emit helper vars inits.
5929
5931 *this, cast<DeclRefExpr>(
5932 (isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
5933 ? S.getCombinedLowerBoundVariable()
5934 : S.getLowerBoundVariable())));
5936 *this, cast<DeclRefExpr>(
5937 (isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
5938 ? S.getCombinedUpperBoundVariable()
5939 : S.getUpperBoundVariable())));
5940 LValue ST =
5941 EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getStrideVariable()));
5942 LValue IL =
5943 EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getIsLastIterVariable()));
5944
5945 OMPPrivateScope LoopScope(*this);
5946 if (EmitOMPFirstprivateClause(S, LoopScope)) {
5947 // Emit implicit barrier to synchronize threads and avoid data races
5948 // on initialization of firstprivate variables and post-update of
5949 // lastprivate variables.
5950 CGM.getOpenMPRuntime().emitBarrierCall(
5951 *this, S.getBeginLoc(), OMPD_unknown, /*EmitChecks=*/false,
5952 /*ForceSimpleCall=*/true);
5953 }
5954 EmitOMPPrivateClause(S, LoopScope);
5955 if (isOpenMPSimdDirective(S.getDirectiveKind()) &&
5956 !isOpenMPParallelDirective(S.getDirectiveKind()) &&
5957 !isOpenMPTeamsDirective(S.getDirectiveKind()))
5958 EmitOMPReductionClauseInit(S, LoopScope);
5959 HasLastprivateClause = EmitOMPLastprivateClauseInit(S, LoopScope);
5960 EmitOMPPrivateLoopCounters(S, LoopScope);
5961 (void)LoopScope.Privatize();
5962 if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()))
5963 CGM.getOpenMPRuntime().adjustTargetSpecificDataForLambdas(*this, S);
5964
5965 // Detect the distribute schedule kind and chunk.
5966 llvm::Value *Chunk = nullptr;
5968 if (const auto *C = S.getSingleClause<OMPDistScheduleClause>()) {
5969 ScheduleKind = C->getDistScheduleKind();
5970 if (const Expr *Ch = C->getChunkSize()) {
5971 Chunk = EmitScalarExpr(Ch);
5972 Chunk = EmitScalarConversion(Chunk, Ch->getType(),
5973 S.getIterationVariable()->getType(),
5974 S.getBeginLoc());
5975 }
5976 } else {
5977 // Default behaviour for dist_schedule clause.
5978 CGM.getOpenMPRuntime().getDefaultDistScheduleAndChunk(
5979 *this, S, ScheduleKind, Chunk);
5980 }
5981 const unsigned IVSize = getContext().getTypeSize(IVExpr->getType());
5982 const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation();
5983
5984 // OpenMP [2.10.8, distribute Construct, Description]
5985 // If dist_schedule is specified, kind must be static. If specified,
5986 // iterations are divided into chunks of size chunk_size, chunks are
5987 // assigned to the teams of the league in a round-robin fashion in the
5988 // order of the team number. When no chunk_size is specified, the
5989 // iteration space is divided into chunks that are approximately equal
5990 // in size, and at most one chunk is distributed to each team of the
5991 // league. The size of the chunks is unspecified in this case.
5992 bool StaticChunked =
5993 RT.isStaticChunked(ScheduleKind, /* Chunked */ Chunk != nullptr) &&
5994 isOpenMPLoopBoundSharingDirective(S.getDirectiveKind());
5995 if (RT.isStaticNonchunked(ScheduleKind,
5996 /* Chunked */ Chunk != nullptr) ||
5997 StaticChunked) {
5999 IVSize, IVSigned, /* Ordered = */ false, IL.getAddress(),
6000 LB.getAddress(), UB.getAddress(), ST.getAddress(),
6001 StaticChunked ? Chunk : nullptr);
6002 RT.emitDistributeStaticInit(*this, S.getBeginLoc(), ScheduleKind,
6003 StaticInit);
6006 // UB = min(UB, GlobalUB);
6008 ? S.getCombinedEnsureUpperBound()
6009 : S.getEnsureUpperBound());
6010 // IV = LB;
6012 ? S.getCombinedInit()
6013 : S.getInit());
6014
6015 const Expr *Cond =
6016 isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
6017 ? S.getCombinedCond()
6018 : S.getCond();
6019
6020 if (StaticChunked)
6021 Cond = S.getCombinedDistCond();
6022
6023 // For static unchunked schedules generate:
6024 //
6025 // 1. For distribute alone, codegen
6026 // while (idx <= UB) {
6027 // BODY;
6028 // ++idx;
6029 // }
6030 //
6031 // 2. When combined with 'for' (e.g. as in 'distribute parallel for')
6032 // while (idx <= UB) {
6033 // <CodeGen rest of pragma>(LB, UB);
6034 // idx += ST;
6035 // }
6036 //
6037 // For static chunk one schedule generate:
6038 //
6039 // while (IV <= GlobalUB) {
6040 // <CodeGen rest of pragma>(LB, UB);
6041 // LB += ST;
6042 // UB += ST;
6043 // UB = min(UB, GlobalUB);
6044 // IV = LB;
6045 // }
6046 //
6048 *this, S,
6049 [&S](CodeGenFunction &CGF, PrePostActionTy &) {
6050 if (isOpenMPSimdDirective(S.getDirectiveKind()))
6051 CGF.EmitOMPSimdInit(S);
6052 },
6053 [&S, &LoopScope, Cond, IncExpr, LoopExit, &CodeGenLoop,
6054 StaticChunked](CodeGenFunction &CGF, PrePostActionTy &) {
6055 CGF.EmitOMPInnerLoop(
6056 S, LoopScope.requiresCleanups(), Cond, IncExpr,
6057 [&S, LoopExit, &CodeGenLoop](CodeGenFunction &CGF) {
6058 CodeGenLoop(CGF, S, LoopExit);
6059 },
6060 [&S, StaticChunked](CodeGenFunction &CGF) {
6061 if (StaticChunked) {
6062 CGF.EmitIgnoredExpr(S.getCombinedNextLowerBound());
6063 CGF.EmitIgnoredExpr(S.getCombinedNextUpperBound());
6064 CGF.EmitIgnoredExpr(S.getCombinedEnsureUpperBound());
6065 CGF.EmitIgnoredExpr(S.getCombinedInit());
6066 }
6067 });
6068 });
6069 EmitBlock(LoopExit.getBlock());
6070 // Tell the runtime we are done.
6071 RT.emitForStaticFinish(*this, S.getEndLoc(), OMPD_distribute);
6072 } else {
6073 // Emit the outer loop, which requests its work chunk [LB..UB] from
6074 // runtime and runs the inner loop to process it.
6075 const OMPLoopArguments LoopArguments = {
6076 LB.getAddress(), UB.getAddress(), ST.getAddress(), IL.getAddress(),
6077 Chunk};
6078 EmitOMPDistributeOuterLoop(ScheduleKind, S, LoopScope, LoopArguments,
6079 CodeGenLoop);
6080 }
6081 if (isOpenMPSimdDirective(S.getDirectiveKind())) {
6082 EmitOMPSimdFinal(S, [IL, &S](CodeGenFunction &CGF) {
6083 return CGF.Builder.CreateIsNotNull(
6084 CGF.EmitLoadOfScalar(IL, S.getBeginLoc()));
6085 });
6086 }
6087 if (isOpenMPSimdDirective(S.getDirectiveKind()) &&
6088 !isOpenMPParallelDirective(S.getDirectiveKind()) &&
6089 !isOpenMPTeamsDirective(S.getDirectiveKind())) {
6090 EmitOMPReductionClauseFinal(S, OMPD_simd);
6091 // Emit post-update of the reduction variables if IsLastIter != 0.
6093 *this, S, [IL, &S](CodeGenFunction &CGF) {
6094 return CGF.Builder.CreateIsNotNull(
6095 CGF.EmitLoadOfScalar(IL, S.getBeginLoc()));
6096 });
6097 }
6098 // Emit final copy of the lastprivate variables if IsLastIter != 0.
6099 if (HasLastprivateClause) {
6101 S, /*NoFinals=*/false,
6102 Builder.CreateIsNotNull(EmitLoadOfScalar(IL, S.getBeginLoc())));
6103 }
6104 }
6105
6106 // We're now done with the loop, so jump to the continuation block.
6107 if (ContBlock) {
6108 EmitBranch(ContBlock);
6109 EmitBlock(ContBlock, true);
6110 }
6111 }
6112}
6113
6114// Pass OMPLoopDirective (instead of OMPDistributeDirective) to make this
6115// function available for "loop bind(teams)", which maps to "distribute".
6117 CodeGenFunction &CGF,
6118 CodeGenModule &CGM) {
6119 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
6121 };
6122 OMPLexicalScope Scope(CGF, S, OMPD_unknown);
6123 CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_distribute, CodeGen);
6124}
6125
6130
6131static llvm::Function *
6133 const OMPExecutableDirective &D) {
6134 CodeGenFunction CGF(CGM, /*suppressNewContext=*/true);
6136 CGF.CapturedStmtInfo = &CapStmtInfo;
6137 llvm::Function *Fn = CGF.GenerateOpenMPCapturedStmtFunction(*S, D);
6138 Fn->setDoesNotRecurse();
6139 return Fn;
6140}
6141
6142template <typename T>
6143static void emitRestoreIP(CodeGenFunction &CGF, const T *C,
6144 llvm::OpenMPIRBuilder::InsertPointTy AllocaIP,
6145 llvm::OpenMPIRBuilder &OMPBuilder) {
6146
6147 unsigned NumLoops = C->getNumLoops();
6149 /*DestWidth=*/64, /*Signed=*/1);
6151 for (unsigned I = 0; I < NumLoops; I++) {
6152 const Expr *CounterVal = C->getLoopData(I);
6153 assert(CounterVal);
6154 llvm::Value *StoreValue = CGF.EmitScalarConversion(
6155 CGF.EmitScalarExpr(CounterVal), CounterVal->getType(), Int64Ty,
6156 CounterVal->getExprLoc());
6157 StoreValues.emplace_back(StoreValue);
6158 }
6159 OMPDoacrossKind<T> ODK;
6160 bool IsDependSource = ODK.isSource(C);
6161 CGF.Builder.restoreIP(
6162 OMPBuilder.createOrderedDepend(CGF.Builder, AllocaIP, NumLoops,
6163 StoreValues, ".cnt.addr", IsDependSource));
6164}
6165
6166void CodeGenFunction::EmitOMPOrderedDirective(const OMPOrderedDirective &S) {
6167 if (CGM.getLangOpts().OpenMPIRBuilder) {
6168 llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
6169 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
6170
6171 if (S.hasClausesOfKind<OMPDependClause>() ||
6172 S.hasClausesOfKind<OMPDoacrossClause>()) {
6173 // The ordered directive with depend clause.
6174 assert(!S.hasAssociatedStmt() && "No associated statement must be in "
6175 "ordered depend|doacross construct.");
6176 InsertPointTy AllocaIP(AllocaInsertPt->getParent(),
6177 AllocaInsertPt->getIterator());
6178 for (const auto *DC : S.getClausesOfKind<OMPDependClause>())
6179 emitRestoreIP(*this, DC, AllocaIP, OMPBuilder);
6180 for (const auto *DC : S.getClausesOfKind<OMPDoacrossClause>())
6181 emitRestoreIP(*this, DC, AllocaIP, OMPBuilder);
6182 } else {
6183 // The ordered directive with threads or simd clause, or without clause.
6184 // Without clause, it behaves as if the threads clause is specified.
6185 const auto *C = S.getSingleClause<OMPSIMDClause>();
6186
6187 auto FiniCB = [this](InsertPointTy IP) {
6189 return llvm::Error::success();
6190 };
6191
6192 auto BodyGenCB = [&S, C, this](InsertPointTy AllocaIP,
6193 InsertPointTy CodeGenIP) {
6194 Builder.restoreIP(CodeGenIP);
6195
6196 const CapturedStmt *CS = S.getInnermostCapturedStmt();
6197 if (C) {
6198 llvm::BasicBlock *FiniBB = splitBBWithSuffix(
6199 Builder, /*CreateBranch=*/false, ".ordered.after");
6201 GenerateOpenMPCapturedVars(*CS, CapturedVars);
6202 llvm::Function *OutlinedFn = emitOutlinedOrderedFunction(CGM, CS, S);
6203 assert(S.getBeginLoc().isValid() &&
6204 "Outlined function call location must be valid.");
6205 ApplyDebugLocation::CreateDefaultArtificial(*this, S.getBeginLoc());
6206 OMPBuilderCBHelpers::EmitCaptureStmt(*this, CodeGenIP, *FiniBB,
6207 OutlinedFn, CapturedVars);
6208 } else {
6210 *this, CS->getCapturedStmt(), AllocaIP, CodeGenIP, "ordered");
6211 }
6212 return llvm::Error::success();
6213 };
6214
6215 OMPLexicalScope Scope(*this, S, OMPD_unknown);
6216 llvm::OpenMPIRBuilder::InsertPointTy AfterIP = cantFail(
6217 OMPBuilder.createOrderedThreadsSimd(Builder, BodyGenCB, FiniCB, !C));
6218 Builder.restoreIP(AfterIP);
6219 }
6220 return;
6221 }
6222
6223 if (S.hasClausesOfKind<OMPDependClause>()) {
6224 assert(!S.hasAssociatedStmt() &&
6225 "No associated statement must be in ordered depend construct.");
6226 for (const auto *DC : S.getClausesOfKind<OMPDependClause>())
6227 CGM.getOpenMPRuntime().emitDoacrossOrdered(*this, DC);
6228 return;
6229 }
6230 if (S.hasClausesOfKind<OMPDoacrossClause>()) {
6231 assert(!S.hasAssociatedStmt() &&
6232 "No associated statement must be in ordered doacross construct.");
6233 for (const auto *DC : S.getClausesOfKind<OMPDoacrossClause>())
6234 CGM.getOpenMPRuntime().emitDoacrossOrdered(*this, DC);
6235 return;
6236 }
6237 const auto *C = S.getSingleClause<OMPSIMDClause>();
6238 auto &&CodeGen = [&S, C, this](CodeGenFunction &CGF,
6239 PrePostActionTy &Action) {
6240 const CapturedStmt *CS = S.getInnermostCapturedStmt();
6241 if (C) {
6243 CGF.GenerateOpenMPCapturedVars(*CS, CapturedVars);
6244 llvm::Function *OutlinedFn = emitOutlinedOrderedFunction(CGM, CS, S);
6245 CGM.getOpenMPRuntime().emitOutlinedFunctionCall(CGF, S.getBeginLoc(),
6246 OutlinedFn, CapturedVars);
6247 } else {
6248 Action.Enter(CGF);
6249 CGF.EmitStmt(CS->getCapturedStmt());
6250 }
6251 };
6252 OMPLexicalScope Scope(*this, S, OMPD_unknown);
6253 CGM.getOpenMPRuntime().emitOrderedRegion(*this, CodeGen, S.getBeginLoc(), !C);
6254}
6255
6256static llvm::Value *convertToScalarValue(CodeGenFunction &CGF, RValue Val,
6257 QualType SrcType, QualType DestType,
6258 SourceLocation Loc) {
6259 assert(CGF.hasScalarEvaluationKind(DestType) &&
6260 "DestType must have scalar evaluation kind.");
6261 assert(!Val.isAggregate() && "Must be a scalar or complex.");
6262 return Val.isScalar() ? CGF.EmitScalarConversion(Val.getScalarVal(), SrcType,
6263 DestType, Loc)
6265 Val.getComplexVal(), SrcType, DestType, Loc);
6266}
6267
6270 QualType DestType, SourceLocation Loc) {
6271 assert(CGF.getEvaluationKind(DestType) == TEK_Complex &&
6272 "DestType must have complex evaluation kind.");
6274 if (Val.isScalar()) {
6275 // Convert the input element to the element type of the complex.
6276 QualType DestElementType =
6277 DestType->castAs<ComplexType>()->getElementType();
6278 llvm::Value *ScalarVal = CGF.EmitScalarConversion(
6279 Val.getScalarVal(), SrcType, DestElementType, Loc);
6280 ComplexVal = CodeGenFunction::ComplexPairTy(
6281 ScalarVal, llvm::Constant::getNullValue(ScalarVal->getType()));
6282 } else {
6283 assert(Val.isComplex() && "Must be a scalar or complex.");
6284 QualType SrcElementType = SrcType->castAs<ComplexType>()->getElementType();
6285 QualType DestElementType =
6286 DestType->castAs<ComplexType>()->getElementType();
6287 ComplexVal.first = CGF.EmitScalarConversion(
6288 Val.getComplexVal().first, SrcElementType, DestElementType, Loc);
6289 ComplexVal.second = CGF.EmitScalarConversion(
6290 Val.getComplexVal().second, SrcElementType, DestElementType, Loc);
6291 }
6292 return ComplexVal;
6293}
6294
6295static void emitSimpleAtomicStore(CodeGenFunction &CGF, llvm::AtomicOrdering AO,
6296 LValue LVal, RValue RVal) {
6297 if (LVal.isGlobalReg())
6298 CGF.EmitStoreThroughGlobalRegLValue(RVal, LVal);
6299 else
6300 CGF.EmitAtomicStore(RVal, LVal, AO, LVal.isVolatile(), /*isInit=*/false);
6301}
6302
6304 llvm::AtomicOrdering AO, LValue LVal,
6305 SourceLocation Loc) {
6306 if (LVal.isGlobalReg())
6307 return CGF.EmitLoadOfLValue(LVal, Loc);
6308 return CGF.EmitAtomicLoad(
6309 LVal, Loc, llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(AO),
6310 LVal.isVolatile());
6311}
6312
6314 QualType RValTy, SourceLocation Loc) {
6315 switch (getEvaluationKind(LVal.getType())) {
6316 case TEK_Scalar:
6318 *this, RVal, RValTy, LVal.getType(), Loc)),
6319 LVal);
6320 break;
6321 case TEK_Complex:
6323 convertToComplexValue(*this, RVal, RValTy, LVal.getType(), Loc), LVal,
6324 /*isInit=*/false);
6325 break;
6326 case TEK_Aggregate:
6327 llvm_unreachable("Must be a scalar or complex.");
6328 }
6329}
6330
6331static void emitOMPAtomicReadExpr(CodeGenFunction &CGF, llvm::AtomicOrdering AO,
6332 const Expr *X, const Expr *V,
6333 SourceLocation Loc) {
6334 // v = x;
6335 assert(V->isLValue() && "V of 'omp atomic read' is not lvalue");
6336 assert(X->isLValue() && "X of 'omp atomic read' is not lvalue");
6337 LValue XLValue = CGF.EmitLValue(X);
6338 LValue VLValue = CGF.EmitLValue(V);
6339 RValue Res = emitSimpleAtomicLoad(CGF, AO, XLValue, Loc);
6340 // OpenMP, 2.17.7, atomic Construct
6341 // If the read or capture clause is specified and the acquire, acq_rel, or
6342 // seq_cst clause is specified then the strong flush on exit from the atomic
6343 // operation is also an acquire flush.
6344 switch (AO) {
6345 case llvm::AtomicOrdering::Acquire:
6346 case llvm::AtomicOrdering::AcquireRelease:
6347 case llvm::AtomicOrdering::SequentiallyConsistent:
6348 CGF.CGM.getOpenMPRuntime().emitFlush(CGF, {}, Loc,
6349 llvm::AtomicOrdering::Acquire);
6350 break;
6351 case llvm::AtomicOrdering::Monotonic:
6352 case llvm::AtomicOrdering::Release:
6353 break;
6354 case llvm::AtomicOrdering::NotAtomic:
6355 case llvm::AtomicOrdering::Unordered:
6356 llvm_unreachable("Unexpected ordering.");
6357 }
6358 CGF.emitOMPSimpleStore(VLValue, Res, X->getType().getNonReferenceType(), Loc);
6360}
6361
6363 llvm::AtomicOrdering AO, const Expr *X,
6364 const Expr *E, SourceLocation Loc) {
6365 // x = expr;
6366 assert(X->isLValue() && "X of 'omp atomic write' is not lvalue");
6367 emitSimpleAtomicStore(CGF, AO, CGF.EmitLValue(X), CGF.EmitAnyExpr(E));
6369 // OpenMP, 2.17.7, atomic Construct
6370 // If the write, update, or capture clause is specified and the release,
6371 // acq_rel, or seq_cst clause is specified then the strong flush on entry to
6372 // the atomic operation is also a release flush.
6373 switch (AO) {
6374 case llvm::AtomicOrdering::Release:
6375 case llvm::AtomicOrdering::AcquireRelease:
6376 case llvm::AtomicOrdering::SequentiallyConsistent:
6377 CGF.CGM.getOpenMPRuntime().emitFlush(CGF, {}, Loc,
6378 llvm::AtomicOrdering::Release);
6379 break;
6380 case llvm::AtomicOrdering::Acquire:
6381 case llvm::AtomicOrdering::Monotonic:
6382 break;
6383 case llvm::AtomicOrdering::NotAtomic:
6384 case llvm::AtomicOrdering::Unordered:
6385 llvm_unreachable("Unexpected ordering.");
6386 }
6387}
6388
6389static std::pair<bool, RValue> emitOMPAtomicRMW(CodeGenFunction &CGF, LValue X,
6390 RValue Update,
6392 llvm::AtomicOrdering AO,
6393 bool IsXLHSInRHSPart) {
6394 ASTContext &Context = CGF.getContext();
6395 // Allow atomicrmw only if 'x' and 'update' are integer values, lvalue for 'x'
6396 // expression is simple and atomic is allowed for the given type for the
6397 // target platform.
6398 if (BO == BO_Comma || !Update.isScalar() || !X.isSimple() ||
6399 (!isa<llvm::ConstantInt>(Update.getScalarVal()) &&
6400 (Update.getScalarVal()->getType() != X.getAddress().getElementType())) ||
6401 !Context.getTargetInfo().hasBuiltinAtomic(
6402 Context.getTypeSize(X.getType()), Context.toBits(X.getAlignment())))
6403 return std::make_pair(false, RValue::get(nullptr));
6404
6405 auto &&CheckAtomicSupport = [&CGF](llvm::Type *T, BinaryOperatorKind BO) {
6406 if (T->isIntegerTy())
6407 return true;
6408
6409 if (T->isFloatingPointTy() && (BO == BO_Add || BO == BO_Sub))
6410 return llvm::isPowerOf2_64(CGF.CGM.getDataLayout().getTypeStoreSize(T));
6411
6412 return false;
6413 };
6414
6415 if (!CheckAtomicSupport(Update.getScalarVal()->getType(), BO) ||
6416 !CheckAtomicSupport(X.getAddress().getElementType(), BO))
6417 return std::make_pair(false, RValue::get(nullptr));
6418
6419 bool IsInteger = X.getAddress().getElementType()->isIntegerTy();
6420 llvm::AtomicRMWInst::BinOp RMWOp;
6421 switch (BO) {
6422 case BO_Add:
6423 RMWOp = IsInteger ? llvm::AtomicRMWInst::Add : llvm::AtomicRMWInst::FAdd;
6424 break;
6425 case BO_Sub:
6426 if (!IsXLHSInRHSPart)
6427 return std::make_pair(false, RValue::get(nullptr));
6428 RMWOp = IsInteger ? llvm::AtomicRMWInst::Sub : llvm::AtomicRMWInst::FSub;
6429 break;
6430 case BO_And:
6431 RMWOp = llvm::AtomicRMWInst::And;
6432 break;
6433 case BO_Or:
6434 RMWOp = llvm::AtomicRMWInst::Or;
6435 break;
6436 case BO_Xor:
6437 RMWOp = llvm::AtomicRMWInst::Xor;
6438 break;
6439 case BO_LT:
6440 if (IsInteger)
6441 RMWOp = X.getType()->hasSignedIntegerRepresentation()
6442 ? (IsXLHSInRHSPart ? llvm::AtomicRMWInst::Min
6443 : llvm::AtomicRMWInst::Max)
6444 : (IsXLHSInRHSPart ? llvm::AtomicRMWInst::UMin
6445 : llvm::AtomicRMWInst::UMax);
6446 else
6447 RMWOp = IsXLHSInRHSPart ? llvm::AtomicRMWInst::FMin
6448 : llvm::AtomicRMWInst::FMax;
6449 break;
6450 case BO_GT:
6451 if (IsInteger)
6452 RMWOp = X.getType()->hasSignedIntegerRepresentation()
6453 ? (IsXLHSInRHSPart ? llvm::AtomicRMWInst::Max
6454 : llvm::AtomicRMWInst::Min)
6455 : (IsXLHSInRHSPart ? llvm::AtomicRMWInst::UMax
6456 : llvm::AtomicRMWInst::UMin);
6457 else
6458 RMWOp = IsXLHSInRHSPart ? llvm::AtomicRMWInst::FMax
6459 : llvm::AtomicRMWInst::FMin;
6460 break;
6461 case BO_Assign:
6462 RMWOp = llvm::AtomicRMWInst::Xchg;
6463 break;
6464 case BO_Mul:
6465 case BO_Div:
6466 case BO_Rem:
6467 case BO_Shl:
6468 case BO_Shr:
6469 case BO_LAnd:
6470 case BO_LOr:
6471 return std::make_pair(false, RValue::get(nullptr));
6472 case BO_PtrMemD:
6473 case BO_PtrMemI:
6474 case BO_LE:
6475 case BO_GE:
6476 case BO_EQ:
6477 case BO_NE:
6478 case BO_Cmp:
6479 case BO_AddAssign:
6480 case BO_SubAssign:
6481 case BO_AndAssign:
6482 case BO_OrAssign:
6483 case BO_XorAssign:
6484 case BO_MulAssign:
6485 case BO_DivAssign:
6486 case BO_RemAssign:
6487 case BO_ShlAssign:
6488 case BO_ShrAssign:
6489 case BO_Comma:
6490 llvm_unreachable("Unsupported atomic update operation");
6491 }
6492 llvm::Value *UpdateVal = Update.getScalarVal();
6493 if (auto *IC = dyn_cast<llvm::ConstantInt>(UpdateVal)) {
6494 if (IsInteger)
6495 UpdateVal = CGF.Builder.CreateIntCast(
6496 IC, X.getAddress().getElementType(),
6497 X.getType()->hasSignedIntegerRepresentation());
6498 else
6499 UpdateVal = CGF.Builder.CreateCast(llvm::Instruction::CastOps::UIToFP, IC,
6500 X.getAddress().getElementType());
6501 }
6502 llvm::AtomicRMWInst *Res =
6503 CGF.emitAtomicRMWInst(RMWOp, X.getAddress(), UpdateVal, AO);
6504 return std::make_pair(true, RValue::get(Res));
6505}
6506
6509 llvm::AtomicOrdering AO, SourceLocation Loc,
6510 const llvm::function_ref<RValue(RValue)> CommonGen) {
6511 // Update expressions are allowed to have the following forms:
6512 // x binop= expr; -> xrval + expr;
6513 // x++, ++x -> xrval + 1;
6514 // x--, --x -> xrval - 1;
6515 // x = x binop expr; -> xrval binop expr
6516 // x = expr Op x; - > expr binop xrval;
6517 auto Res = emitOMPAtomicRMW(*this, X, E, BO, AO, IsXLHSInRHSPart);
6518 if (!Res.first) {
6519 if (X.isGlobalReg()) {
6520 // Emit an update expression: 'xrval' binop 'expr' or 'expr' binop
6521 // 'xrval'.
6522 EmitStoreThroughLValue(CommonGen(EmitLoadOfLValue(X, Loc)), X);
6523 } else {
6524 // Perform compare-and-swap procedure.
6525 EmitAtomicUpdate(X, AO, CommonGen, X.getType().isVolatileQualified());
6526 }
6527 }
6528 return Res;
6529}
6530
6532 llvm::AtomicOrdering AO, const Expr *X,
6533 const Expr *E, const Expr *UE,
6534 bool IsXLHSInRHSPart, SourceLocation Loc) {
6535 assert(isa<BinaryOperator>(UE->IgnoreImpCasts()) &&
6536 "Update expr in 'atomic update' must be a binary operator.");
6537 const auto *BOUE = cast<BinaryOperator>(UE->IgnoreImpCasts());
6538 // Update expressions are allowed to have the following forms:
6539 // x binop= expr; -> xrval + expr;
6540 // x++, ++x -> xrval + 1;
6541 // x--, --x -> xrval - 1;
6542 // x = x binop expr; -> xrval binop expr
6543 // x = expr Op x; - > expr binop xrval;
6544 assert(X->isLValue() && "X of 'omp atomic update' is not lvalue");
6545 LValue XLValue = CGF.EmitLValue(X);
6546 RValue ExprRValue = CGF.EmitAnyExpr(E);
6547 const auto *LHS = cast<OpaqueValueExpr>(BOUE->getLHS()->IgnoreImpCasts());
6548 const auto *RHS = cast<OpaqueValueExpr>(BOUE->getRHS()->IgnoreImpCasts());
6549 const OpaqueValueExpr *XRValExpr = IsXLHSInRHSPart ? LHS : RHS;
6550 const OpaqueValueExpr *ERValExpr = IsXLHSInRHSPart ? RHS : LHS;
6551 auto &&Gen = [&CGF, UE, ExprRValue, XRValExpr, ERValExpr](RValue XRValue) {
6552 CodeGenFunction::OpaqueValueMapping MapExpr(CGF, ERValExpr, ExprRValue);
6553 CodeGenFunction::OpaqueValueMapping MapX(CGF, XRValExpr, XRValue);
6554 return CGF.EmitAnyExpr(UE);
6555 };
6557 XLValue, ExprRValue, BOUE->getOpcode(), IsXLHSInRHSPart, AO, Loc, Gen);
6559 // OpenMP, 2.17.7, atomic Construct
6560 // If the write, update, or capture clause is specified and the release,
6561 // acq_rel, or seq_cst clause is specified then the strong flush on entry to
6562 // the atomic operation is also a release flush.
6563 switch (AO) {
6564 case llvm::AtomicOrdering::Release:
6565 case llvm::AtomicOrdering::AcquireRelease:
6566 case llvm::AtomicOrdering::SequentiallyConsistent:
6567 CGF.CGM.getOpenMPRuntime().emitFlush(CGF, {}, Loc,
6568 llvm::AtomicOrdering::Release);
6569 break;
6570 case llvm::AtomicOrdering::Acquire:
6571 case llvm::AtomicOrdering::Monotonic:
6572 break;
6573 case llvm::AtomicOrdering::NotAtomic:
6574 case llvm::AtomicOrdering::Unordered:
6575 llvm_unreachable("Unexpected ordering.");
6576 }
6577}
6578
6580 QualType SourceType, QualType ResType,
6581 SourceLocation Loc) {
6582 switch (CGF.getEvaluationKind(ResType)) {
6583 case TEK_Scalar:
6584 return RValue::get(
6585 convertToScalarValue(CGF, Value, SourceType, ResType, Loc));
6586 case TEK_Complex: {
6587 auto Res = convertToComplexValue(CGF, Value, SourceType, ResType, Loc);
6588 return RValue::getComplex(Res.first, Res.second);
6589 }
6590 case TEK_Aggregate:
6591 break;
6592 }
6593 llvm_unreachable("Must be a scalar or complex.");
6594}
6595
6597 llvm::AtomicOrdering AO,
6598 bool IsPostfixUpdate, const Expr *V,
6599 const Expr *X, const Expr *E,
6600 const Expr *UE, bool IsXLHSInRHSPart,
6601 SourceLocation Loc) {
6602 assert(X->isLValue() && "X of 'omp atomic capture' is not lvalue");
6603 assert(V->isLValue() && "V of 'omp atomic capture' is not lvalue");
6604 RValue NewVVal;
6605 LValue VLValue = CGF.EmitLValue(V);
6606 LValue XLValue = CGF.EmitLValue(X);
6607 RValue ExprRValue = CGF.EmitAnyExpr(E);
6608 QualType NewVValType;
6609 if (UE) {
6610 // 'x' is updated with some additional value.
6611 assert(isa<BinaryOperator>(UE->IgnoreImpCasts()) &&
6612 "Update expr in 'atomic capture' must be a binary operator.");
6613 const auto *BOUE = cast<BinaryOperator>(UE->IgnoreImpCasts());
6614 // Update expressions are allowed to have the following forms:
6615 // x binop= expr; -> xrval + expr;
6616 // x++, ++x -> xrval + 1;
6617 // x--, --x -> xrval - 1;
6618 // x = x binop expr; -> xrval binop expr
6619 // x = expr Op x; - > expr binop xrval;
6620 const auto *LHS = cast<OpaqueValueExpr>(BOUE->getLHS()->IgnoreImpCasts());
6621 const auto *RHS = cast<OpaqueValueExpr>(BOUE->getRHS()->IgnoreImpCasts());
6622 const OpaqueValueExpr *XRValExpr = IsXLHSInRHSPart ? LHS : RHS;
6623 NewVValType = XRValExpr->getType();
6624 const OpaqueValueExpr *ERValExpr = IsXLHSInRHSPart ? RHS : LHS;
6625 auto &&Gen = [&CGF, &NewVVal, UE, ExprRValue, XRValExpr, ERValExpr,
6626 IsPostfixUpdate](RValue XRValue) {
6627 CodeGenFunction::OpaqueValueMapping MapExpr(CGF, ERValExpr, ExprRValue);
6628 CodeGenFunction::OpaqueValueMapping MapX(CGF, XRValExpr, XRValue);
6629 RValue Res = CGF.EmitAnyExpr(UE);
6630 NewVVal = IsPostfixUpdate ? XRValue : Res;
6631 return Res;
6632 };
6633 auto Res = CGF.EmitOMPAtomicSimpleUpdateExpr(
6634 XLValue, ExprRValue, BOUE->getOpcode(), IsXLHSInRHSPart, AO, Loc, Gen);
6636 if (Res.first) {
6637 // 'atomicrmw' instruction was generated.
6638 if (IsPostfixUpdate) {
6639 // Use old value from 'atomicrmw'.
6640 NewVVal = Res.second;
6641 } else {
6642 // 'atomicrmw' does not provide new value, so evaluate it using old
6643 // value of 'x'.
6644 CodeGenFunction::OpaqueValueMapping MapExpr(CGF, ERValExpr, ExprRValue);
6645 CodeGenFunction::OpaqueValueMapping MapX(CGF, XRValExpr, Res.second);
6646 NewVVal = CGF.EmitAnyExpr(UE);
6647 }
6648 }
6649 } else {
6650 // 'x' is simply rewritten with some 'expr'.
6651 NewVValType = X->getType().getNonReferenceType();
6652 ExprRValue = convertToType(CGF, ExprRValue, E->getType(),
6653 X->getType().getNonReferenceType(), Loc);
6654 auto &&Gen = [&NewVVal, ExprRValue](RValue XRValue) {
6655 NewVVal = XRValue;
6656 return ExprRValue;
6657 };
6658 // Try to perform atomicrmw xchg, otherwise simple exchange.
6659 auto Res = CGF.EmitOMPAtomicSimpleUpdateExpr(
6660 XLValue, ExprRValue, /*BO=*/BO_Assign, /*IsXLHSInRHSPart=*/false, AO,
6661 Loc, Gen);
6663 if (Res.first) {
6664 // 'atomicrmw' instruction was generated.
6665 NewVVal = IsPostfixUpdate ? Res.second : ExprRValue;
6666 }
6667 }
6668 // Emit post-update store to 'v' of old/new 'x' value.
6669 CGF.emitOMPSimpleStore(VLValue, NewVVal, NewVValType, Loc);
6671 // OpenMP 5.1 removes the required flush for capture clause.
6672 if (CGF.CGM.getLangOpts().OpenMP < 51) {
6673 // OpenMP, 2.17.7, atomic Construct
6674 // If the write, update, or capture clause is specified and the release,
6675 // acq_rel, or seq_cst clause is specified then the strong flush on entry to
6676 // the atomic operation is also a release flush.
6677 // If the read or capture clause is specified and the acquire, acq_rel, or
6678 // seq_cst clause is specified then the strong flush on exit from the atomic
6679 // operation is also an acquire flush.
6680 switch (AO) {
6681 case llvm::AtomicOrdering::Release:
6682 CGF.CGM.getOpenMPRuntime().emitFlush(CGF, {}, Loc,
6683 llvm::AtomicOrdering::Release);
6684 break;
6685 case llvm::AtomicOrdering::Acquire:
6686 CGF.CGM.getOpenMPRuntime().emitFlush(CGF, {}, Loc,
6687 llvm::AtomicOrdering::Acquire);
6688 break;
6689 case llvm::AtomicOrdering::AcquireRelease:
6690 case llvm::AtomicOrdering::SequentiallyConsistent:
6692 CGF, {}, Loc, llvm::AtomicOrdering::AcquireRelease);
6693 break;
6694 case llvm::AtomicOrdering::Monotonic:
6695 break;
6696 case llvm::AtomicOrdering::NotAtomic:
6697 case llvm::AtomicOrdering::Unordered:
6698 llvm_unreachable("Unexpected ordering.");
6699 }
6700 }
6701}
6702
6704 CodeGenFunction &CGF, llvm::AtomicOrdering AO, llvm::AtomicOrdering FailAO,
6705 const Expr *X, const Expr *V, const Expr *R, const Expr *E, const Expr *D,
6706 const Expr *CE, bool IsXBinopExpr, bool IsPostfixUpdate, bool IsFailOnly,
6707 SourceLocation Loc) {
6708 llvm::OpenMPIRBuilder &OMPBuilder =
6710
6711 OMPAtomicCompareOp Op;
6712 assert(isa<BinaryOperator>(CE) && "CE is not a BinaryOperator");
6713 switch (cast<BinaryOperator>(CE)->getOpcode()) {
6714 case BO_EQ:
6715 Op = OMPAtomicCompareOp::EQ;
6716 break;
6717 case BO_LT:
6718 Op = OMPAtomicCompareOp::MIN;
6719 break;
6720 case BO_GT:
6721 Op = OMPAtomicCompareOp::MAX;
6722 break;
6723 default:
6724 llvm_unreachable("unsupported atomic compare binary operator");
6725 }
6726
6727 LValue XLVal = CGF.EmitLValue(X);
6728 Address XAddr = XLVal.getAddress();
6729
6730 auto EmitRValueWithCastIfNeeded = [&CGF, Loc](const Expr *X, const Expr *E) {
6731 if (X->getType() == E->getType())
6732 return CGF.EmitScalarExpr(E);
6733 const Expr *NewE = E->IgnoreImplicitAsWritten();
6734 llvm::Value *V = CGF.EmitScalarExpr(NewE);
6735 if (NewE->getType() == X->getType())
6736 return V;
6737 return CGF.EmitScalarConversion(V, NewE->getType(), X->getType(), Loc);
6738 };
6739
6740 llvm::Value *EVal = EmitRValueWithCastIfNeeded(X, E);
6741 llvm::Value *DVal = D ? EmitRValueWithCastIfNeeded(X, D) : nullptr;
6742 if (auto *CI = dyn_cast<llvm::ConstantInt>(EVal))
6743 EVal = CGF.Builder.CreateIntCast(
6744 CI, XLVal.getAddress().getElementType(),
6746 if (DVal)
6747 if (auto *CI = dyn_cast<llvm::ConstantInt>(DVal))
6748 DVal = CGF.Builder.CreateIntCast(
6749 CI, XLVal.getAddress().getElementType(),
6751
6752 llvm::OpenMPIRBuilder::AtomicOpValue XOpVal{
6753 XAddr.emitRawPointer(CGF), XAddr.getElementType(),
6754 X->getType()->hasSignedIntegerRepresentation(),
6755 X->getType().isVolatileQualified()};
6756 llvm::OpenMPIRBuilder::AtomicOpValue VOpVal, ROpVal;
6757 if (V) {
6758 LValue LV = CGF.EmitLValue(V);
6759 Address Addr = LV.getAddress();
6760 VOpVal = {Addr.emitRawPointer(CGF), Addr.getElementType(),
6761 V->getType()->hasSignedIntegerRepresentation(),
6762 V->getType().isVolatileQualified()};
6763 }
6764 if (R) {
6765 LValue LV = CGF.EmitLValue(R);
6766 Address Addr = LV.getAddress();
6767 ROpVal = {Addr.emitRawPointer(CGF), Addr.getElementType(),
6770 }
6771
6772 if (FailAO == llvm::AtomicOrdering::NotAtomic) {
6773 // fail clause was not mentioned on the
6774 // "#pragma omp atomic compare" construct.
6775 CGF.Builder.restoreIP(OMPBuilder.createAtomicCompare(
6776 CGF.Builder, XOpVal, VOpVal, ROpVal, EVal, DVal, AO, Op, IsXBinopExpr,
6778 } else
6779 CGF.Builder.restoreIP(OMPBuilder.createAtomicCompare(
6780 CGF.Builder, XOpVal, VOpVal, ROpVal, EVal, DVal, AO, Op, IsXBinopExpr,
6781 IsPostfixUpdate, IsFailOnly, FailAO));
6782}
6783
6785 llvm::AtomicOrdering AO,
6786 llvm::AtomicOrdering FailAO, bool IsPostfixUpdate,
6787 const Expr *X, const Expr *V, const Expr *R,
6788 const Expr *E, const Expr *UE, const Expr *D,
6789 const Expr *CE, bool IsXLHSInRHSPart,
6790 bool IsFailOnly, SourceLocation Loc) {
6791 switch (Kind) {
6792 case OMPC_read:
6793 emitOMPAtomicReadExpr(CGF, AO, X, V, Loc);
6794 break;
6795 case OMPC_write:
6796 emitOMPAtomicWriteExpr(CGF, AO, X, E, Loc);
6797 break;
6798 case OMPC_unknown:
6799 case OMPC_update:
6800 emitOMPAtomicUpdateExpr(CGF, AO, X, E, UE, IsXLHSInRHSPart, Loc);
6801 break;
6802 case OMPC_capture:
6803 emitOMPAtomicCaptureExpr(CGF, AO, IsPostfixUpdate, V, X, E, UE,
6804 IsXLHSInRHSPart, Loc);
6805 break;
6806 case OMPC_compare: {
6807 emitOMPAtomicCompareExpr(CGF, AO, FailAO, X, V, R, E, D, CE,
6809 break;
6810 }
6811 default:
6812 llvm_unreachable("Clause is not allowed in 'omp atomic'.");
6813 }
6814}
6815
6816void CodeGenFunction::EmitOMPAtomicDirective(const OMPAtomicDirective &S) {
6817 llvm::AtomicOrdering AO = CGM.getOpenMPRuntime().getDefaultMemoryOrdering();
6818 // Fail Memory Clause Ordering.
6819 llvm::AtomicOrdering FailAO = llvm::AtomicOrdering::NotAtomic;
6820 bool MemOrderingSpecified = false;
6821 if (S.getSingleClause<OMPSeqCstClause>()) {
6822 AO = llvm::AtomicOrdering::SequentiallyConsistent;
6823 MemOrderingSpecified = true;
6824 } else if (S.getSingleClause<OMPAcqRelClause>()) {
6825 AO = llvm::AtomicOrdering::AcquireRelease;
6826 MemOrderingSpecified = true;
6827 } else if (S.getSingleClause<OMPAcquireClause>()) {
6828 AO = llvm::AtomicOrdering::Acquire;
6829 MemOrderingSpecified = true;
6830 } else if (S.getSingleClause<OMPReleaseClause>()) {
6831 AO = llvm::AtomicOrdering::Release;
6832 MemOrderingSpecified = true;
6833 } else if (S.getSingleClause<OMPRelaxedClause>()) {
6834 AO = llvm::AtomicOrdering::Monotonic;
6835 MemOrderingSpecified = true;
6836 }
6837 llvm::SmallSet<OpenMPClauseKind, 2> KindsEncountered;
6838 OpenMPClauseKind Kind = OMPC_unknown;
6839 for (const OMPClause *C : S.clauses()) {
6840 // Find first clause (skip seq_cst|acq_rel|aqcuire|release|relaxed clause,
6841 // if it is first).
6842 OpenMPClauseKind K = C->getClauseKind();
6843 // TBD
6844 if (K == OMPC_weak)
6845 return;
6846 if (K == OMPC_seq_cst || K == OMPC_acq_rel || K == OMPC_acquire ||
6847 K == OMPC_release || K == OMPC_relaxed || K == OMPC_hint)
6848 continue;
6849 Kind = K;
6850 KindsEncountered.insert(K);
6851 }
6852 // We just need to correct Kind here. No need to set a bool saying it is
6853 // actually compare capture because we can tell from whether V and R are
6854 // nullptr.
6855 if (KindsEncountered.contains(OMPC_compare) &&
6856 KindsEncountered.contains(OMPC_capture))
6857 Kind = OMPC_compare;
6858 if (!MemOrderingSpecified) {
6859 llvm::AtomicOrdering DefaultOrder =
6860 CGM.getOpenMPRuntime().getDefaultMemoryOrdering();
6861 if (DefaultOrder == llvm::AtomicOrdering::Monotonic ||
6862 DefaultOrder == llvm::AtomicOrdering::SequentiallyConsistent ||
6863 (DefaultOrder == llvm::AtomicOrdering::AcquireRelease &&
6864 Kind == OMPC_capture)) {
6865 AO = DefaultOrder;
6866 } else if (DefaultOrder == llvm::AtomicOrdering::AcquireRelease) {
6867 if (Kind == OMPC_unknown || Kind == OMPC_update || Kind == OMPC_write) {
6868 AO = llvm::AtomicOrdering::Release;
6869 } else if (Kind == OMPC_read) {
6870 assert(Kind == OMPC_read && "Unexpected atomic kind.");
6871 AO = llvm::AtomicOrdering::Acquire;
6872 }
6873 }
6874 }
6875
6876 if (KindsEncountered.contains(OMPC_compare) &&
6877 KindsEncountered.contains(OMPC_fail)) {
6878 Kind = OMPC_compare;
6879 const auto *FailClause = S.getSingleClause<OMPFailClause>();
6880 if (FailClause) {
6881 OpenMPClauseKind FailParameter = FailClause->getFailParameter();
6882 if (FailParameter == llvm::omp::OMPC_relaxed)
6883 FailAO = llvm::AtomicOrdering::Monotonic;
6884 else if (FailParameter == llvm::omp::OMPC_acquire)
6885 FailAO = llvm::AtomicOrdering::Acquire;
6886 else if (FailParameter == llvm::omp::OMPC_seq_cst)
6887 FailAO = llvm::AtomicOrdering::SequentiallyConsistent;
6888 }
6889 }
6890
6891 LexicalScope Scope(*this, S.getSourceRange());
6892 EmitStopPoint(S.getAssociatedStmt());
6893 emitOMPAtomicExpr(*this, Kind, AO, FailAO, S.isPostfixUpdate(), S.getX(),
6894 S.getV(), S.getR(), S.getExpr(), S.getUpdateExpr(),
6895 S.getD(), S.getCondExpr(), S.isXLHSInRHSPart(),
6896 S.isFailOnly(), S.getBeginLoc());
6897}
6898
6900 const OMPExecutableDirective &S,
6901 const RegionCodeGenTy &CodeGen) {
6902 assert(isOpenMPTargetExecutionDirective(S.getDirectiveKind()));
6903 CodeGenModule &CGM = CGF.CGM;
6904
6905 // On device emit this construct as inlined code.
6906 if (CGM.getLangOpts().OpenMPIsTargetDevice) {
6907 OMPLexicalScope Scope(CGF, S, OMPD_target);
6909 CGF, OMPD_target, [&S](CodeGenFunction &CGF, PrePostActionTy &) {
6910 CGF.EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt());
6911 });
6912 return;
6913 }
6914
6916 llvm::Function *Fn = nullptr;
6917 llvm::Constant *FnID = nullptr;
6918
6919 const Expr *IfCond = nullptr;
6920 // Check for the at most one if clause associated with the target region.
6921 for (const auto *C : S.getClausesOfKind<OMPIfClause>()) {
6922 if (C->getNameModifier() == OMPD_unknown ||
6923 C->getNameModifier() == OMPD_target) {
6924 IfCond = C->getCondition();
6925 break;
6926 }
6927 }
6928
6929 // Check if we have any device clause associated with the directive.
6930 llvm::PointerIntPair<const Expr *, 2, OpenMPDeviceClauseModifier> Device(
6931 nullptr, OMPC_DEVICE_unknown);
6932 if (auto *C = S.getSingleClause<OMPDeviceClause>())
6933 Device.setPointerAndInt(C->getDevice(), C->getModifier());
6934
6935 // Check if we have an if clause whose conditional always evaluates to false
6936 // or if we do not have any targets specified. If so the target region is not
6937 // an offload entry point.
6938 bool IsOffloadEntry = true;
6939 if (IfCond) {
6940 bool Val;
6941 if (CGF.ConstantFoldsToSimpleInteger(IfCond, Val) && !Val)
6942 IsOffloadEntry = false;
6943 }
6944 if (CGM.getLangOpts().OMPTargetTriples.empty())
6945 IsOffloadEntry = false;
6946
6947 if (CGM.getLangOpts().OpenMPOffloadMandatory && !IsOffloadEntry) {
6948 unsigned DiagID = CGM.getDiags().getCustomDiagID(
6950 "No offloading entry generated while offloading is mandatory.");
6951 CGM.getDiags().Report(DiagID);
6952 }
6953
6954 assert(CGF.CurFuncDecl && "No parent declaration for target region!");
6955 StringRef ParentName;
6956 // In case we have Ctors/Dtors we use the complete type variant to produce
6957 // the mangling of the device outlined kernel.
6958 if (const auto *D = dyn_cast<CXXConstructorDecl>(CGF.CurFuncDecl))
6959 ParentName = CGM.getMangledName(GlobalDecl(D, Ctor_Complete));
6960 else if (const auto *D = dyn_cast<CXXDestructorDecl>(CGF.CurFuncDecl))
6961 ParentName = CGM.getMangledName(GlobalDecl(D, Dtor_Complete));
6962 else
6963 ParentName =
6965
6966 // Emit target region as a standalone region.
6967 CGM.getOpenMPRuntime().emitTargetOutlinedFunction(S, ParentName, Fn, FnID,
6968 IsOffloadEntry, CodeGen);
6969 OMPLexicalScope Scope(CGF, S, OMPD_task);
6970 auto &&SizeEmitter =
6971 [IsOffloadEntry](CodeGenFunction &CGF,
6972 const OMPLoopDirective &D) -> llvm::Value * {
6973 if (IsOffloadEntry) {
6974 OMPLoopScope(CGF, D);
6975 // Emit calculation of the iterations count.
6976 llvm::Value *NumIterations = CGF.EmitScalarExpr(D.getNumIterations());
6977 NumIterations = CGF.Builder.CreateIntCast(NumIterations, CGF.Int64Ty,
6978 /*isSigned=*/false);
6979 return NumIterations;
6980 }
6981 return nullptr;
6982 };
6983 CGM.getOpenMPRuntime().emitTargetCall(CGF, S, Fn, FnID, IfCond, Device,
6984 SizeEmitter);
6985}
6986
6988 PrePostActionTy &Action) {
6989 Action.Enter(CGF);
6990 CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
6991 (void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
6992 CGF.EmitOMPPrivateClause(S, PrivateScope);
6993 (void)PrivateScope.Privatize();
6994 if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()))
6996
6997 CGF.EmitStmt(S.getCapturedStmt(OMPD_target)->getCapturedStmt());
6998 CGF.EnsureInsertPoint();
6999}
7000
7002 StringRef ParentName,
7003 const OMPTargetDirective &S) {
7004 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7005 emitTargetRegion(CGF, S, Action);
7006 };
7007 llvm::Function *Fn;
7008 llvm::Constant *Addr;
7009 // Emit target region as a standalone region.
7010 CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
7011 S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
7012 assert(Fn && Addr && "Target device function emission failed.");
7013}
7014
7016 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7017 emitTargetRegion(CGF, S, Action);
7018 };
7020}
7021
7023 const OMPExecutableDirective &S,
7024 OpenMPDirectiveKind InnermostKind,
7025 const RegionCodeGenTy &CodeGen) {
7026 const CapturedStmt *CS = S.getCapturedStmt(OMPD_teams);
7027 llvm::Function *OutlinedFn =
7029 CGF, S, *CS->getCapturedDecl()->param_begin(), InnermostKind,
7030 CodeGen);
7031
7032 const auto *NT = S.getSingleClause<OMPNumTeamsClause>();
7033 const auto *TL = S.getSingleClause<OMPThreadLimitClause>();
7034 if (NT || TL) {
7035 const Expr *NumTeams = NT ? NT->getNumTeams().front() : nullptr;
7036 const Expr *ThreadLimit = TL ? TL->getThreadLimit().front() : nullptr;
7037
7038 CGF.CGM.getOpenMPRuntime().emitNumTeamsClause(CGF, NumTeams, ThreadLimit,
7039 S.getBeginLoc());
7040 }
7041
7042 OMPTeamsScope Scope(CGF, S);
7044 CGF.GenerateOpenMPCapturedVars(*CS, CapturedVars);
7045 CGF.CGM.getOpenMPRuntime().emitTeamsCall(CGF, S, S.getBeginLoc(), OutlinedFn,
7046 CapturedVars);
7047}
7048
7050 // Emit teams region as a standalone region.
7051 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7052 Action.Enter(CGF);
7053 OMPPrivateScope PrivateScope(CGF);
7054 (void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
7055 CGF.EmitOMPPrivateClause(S, PrivateScope);
7056 CGF.EmitOMPReductionClauseInit(S, PrivateScope);
7057 (void)PrivateScope.Privatize();
7058 CGF.EmitStmt(S.getCapturedStmt(OMPD_teams)->getCapturedStmt());
7059 CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
7060 };
7061 emitCommonOMPTeamsDirective(*this, S, OMPD_distribute, CodeGen);
7063 [](CodeGenFunction &) { return nullptr; });
7064}
7065
7067 const OMPTargetTeamsDirective &S) {
7068 auto *CS = S.getCapturedStmt(OMPD_teams);
7069 Action.Enter(CGF);
7070 // Emit teams region as a standalone region.
7071 auto &&CodeGen = [&S, CS](CodeGenFunction &CGF, PrePostActionTy &Action) {
7072 Action.Enter(CGF);
7073 CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
7074 (void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
7075 CGF.EmitOMPPrivateClause(S, PrivateScope);
7076 CGF.EmitOMPReductionClauseInit(S, PrivateScope);
7077 (void)PrivateScope.Privatize();
7078 if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()))
7080 CGF.EmitStmt(CS->getCapturedStmt());
7081 CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
7082 };
7083 emitCommonOMPTeamsDirective(CGF, S, OMPD_teams, CodeGen);
7085 [](CodeGenFunction &) { return nullptr; });
7086}
7087
7089 CodeGenModule &CGM, StringRef ParentName,
7090 const OMPTargetTeamsDirective &S) {
7091 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7092 emitTargetTeamsRegion(CGF, Action, S);
7093 };
7094 llvm::Function *Fn;
7095 llvm::Constant *Addr;
7096 // Emit target region as a standalone region.
7097 CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
7098 S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
7099 assert(Fn && Addr && "Target device function emission failed.");
7100}
7101
7103 const OMPTargetTeamsDirective &S) {
7104 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7105 emitTargetTeamsRegion(CGF, Action, S);
7106 };
7108}
7109
7110static void
7113 Action.Enter(CGF);
7114 auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
7116 };
7117
7118 // Emit teams region as a standalone region.
7119 auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
7120 PrePostActionTy &Action) {
7121 Action.Enter(CGF);
7122 CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
7123 CGF.EmitOMPReductionClauseInit(S, PrivateScope);
7124 (void)PrivateScope.Privatize();
7125 CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_distribute,
7126 CodeGenDistribute);
7127 CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
7128 };
7129 emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute, CodeGen);
7131 [](CodeGenFunction &) { return nullptr; });
7132}
7133
7135 CodeGenModule &CGM, StringRef ParentName,
7137 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7138 emitTargetTeamsDistributeRegion(CGF, Action, S);
7139 };
7140 llvm::Function *Fn;
7141 llvm::Constant *Addr;
7142 // Emit target region as a standalone region.
7143 CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
7144 S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
7145 assert(Fn && Addr && "Target device function emission failed.");
7146}
7147
7150 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7151 emitTargetTeamsDistributeRegion(CGF, Action, S);
7152 };
7154}
7155
7157 CodeGenFunction &CGF, PrePostActionTy &Action,
7159 Action.Enter(CGF);
7160 auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
7162 };
7163
7164 // Emit teams region as a standalone region.
7165 auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
7166 PrePostActionTy &Action) {
7167 Action.Enter(CGF);
7168 CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
7169 CGF.EmitOMPReductionClauseInit(S, PrivateScope);
7170 (void)PrivateScope.Privatize();
7171 CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_distribute,
7172 CodeGenDistribute);
7173 CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
7174 };
7175 emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute_simd, CodeGen);
7177 [](CodeGenFunction &) { return nullptr; });
7178}
7179
7181 CodeGenModule &CGM, StringRef ParentName,
7183 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7185 };
7186 llvm::Function *Fn;
7187 llvm::Constant *Addr;
7188 // Emit target region as a standalone region.
7189 CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
7190 S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
7191 assert(Fn && Addr && "Target device function emission failed.");
7192}
7193
7196 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7198 };
7200}
7201
7203 const OMPTeamsDistributeDirective &S) {
7204
7205 auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
7207 };
7208
7209 // Emit teams region as a standalone region.
7210 auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
7211 PrePostActionTy &Action) {
7212 Action.Enter(CGF);
7213 OMPPrivateScope PrivateScope(CGF);
7214 CGF.EmitOMPReductionClauseInit(S, PrivateScope);
7215 (void)PrivateScope.Privatize();
7216 CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_distribute,
7217 CodeGenDistribute);
7218 CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
7219 };
7220 emitCommonOMPTeamsDirective(*this, S, OMPD_distribute, CodeGen);
7222 [](CodeGenFunction &) { return nullptr; });
7223}
7224
7227 auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
7229 };
7230
7231 // Emit teams region as a standalone region.
7232 auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
7233 PrePostActionTy &Action) {
7234 Action.Enter(CGF);
7235 OMPPrivateScope PrivateScope(CGF);
7236 CGF.EmitOMPReductionClauseInit(S, PrivateScope);
7237 (void)PrivateScope.Privatize();
7238 CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_simd,
7239 CodeGenDistribute);
7240 CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
7241 };
7242 emitCommonOMPTeamsDirective(*this, S, OMPD_distribute_simd, CodeGen);
7244 [](CodeGenFunction &) { return nullptr; });
7245}
7246
7249 auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
7251 S.getDistInc());
7252 };
7253
7254 // Emit teams region as a standalone region.
7255 auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
7256 PrePostActionTy &Action) {
7257 Action.Enter(CGF);
7258 OMPPrivateScope PrivateScope(CGF);
7259 CGF.EmitOMPReductionClauseInit(S, PrivateScope);
7260 (void)PrivateScope.Privatize();
7261 CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_distribute,
7262 CodeGenDistribute);
7263 CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
7264 };
7265 emitCommonOMPTeamsDirective(*this, S, OMPD_distribute_parallel_for, CodeGen);
7267 [](CodeGenFunction &) { return nullptr; });
7268}
7269
7272 auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
7274 S.getDistInc());
7275 };
7276
7277 // Emit teams region as a standalone region.
7278 auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
7279 PrePostActionTy &Action) {
7280 Action.Enter(CGF);
7281 OMPPrivateScope PrivateScope(CGF);
7282 CGF.EmitOMPReductionClauseInit(S, PrivateScope);
7283 (void)PrivateScope.Privatize();
7285 CGF, OMPD_distribute, CodeGenDistribute, /*HasCancel=*/false);
7286 CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
7287 };
7288 emitCommonOMPTeamsDirective(*this, S, OMPD_distribute_parallel_for_simd,
7289 CodeGen);
7291 [](CodeGenFunction &) { return nullptr; });
7292}
7293
7295 llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
7296 llvm::Value *Device = nullptr;
7297 llvm::Value *NumDependences = nullptr;
7298 llvm::Value *DependenceList = nullptr;
7299
7300 if (const auto *C = S.getSingleClause<OMPDeviceClause>())
7301 Device = EmitScalarExpr(C->getDevice());
7302
7303 // Build list and emit dependences
7306 if (!Data.Dependences.empty()) {
7307 Address DependenciesArray = Address::invalid();
7308 std::tie(NumDependences, DependenciesArray) =
7309 CGM.getOpenMPRuntime().emitDependClause(*this, Data.Dependences,
7310 S.getBeginLoc());
7311 DependenceList = DependenciesArray.emitRawPointer(*this);
7312 }
7313 Data.HasNowaitClause = S.hasClausesOfKind<OMPNowaitClause>();
7314
7315 assert(!(Data.HasNowaitClause && !(S.getSingleClause<OMPInitClause>() ||
7316 S.getSingleClause<OMPDestroyClause>() ||
7317 S.getSingleClause<OMPUseClause>())) &&
7318 "OMPNowaitClause clause is used separately in OMPInteropDirective.");
7319
7320 auto ItOMPInitClause = S.getClausesOfKind<OMPInitClause>();
7321 if (!ItOMPInitClause.empty()) {
7322 // Look at the multiple init clauses
7323 for (const OMPInitClause *C : ItOMPInitClause) {
7324 llvm::Value *InteropvarPtr =
7325 EmitLValue(C->getInteropVar()).getPointer(*this);
7326 llvm::omp::OMPInteropType InteropType =
7327 llvm::omp::OMPInteropType::Unknown;
7328 if (C->getIsTarget()) {
7329 InteropType = llvm::omp::OMPInteropType::Target;
7330 } else {
7331 assert(C->getIsTargetSync() &&
7332 "Expected interop-type target/targetsync");
7333 InteropType = llvm::omp::OMPInteropType::TargetSync;
7334 }
7335 OMPBuilder.createOMPInteropInit(Builder, InteropvarPtr, InteropType,
7336 Device, NumDependences, DependenceList,
7337 Data.HasNowaitClause);
7338 }
7339 }
7340 auto ItOMPDestroyClause = S.getClausesOfKind<OMPDestroyClause>();
7341 if (!ItOMPDestroyClause.empty()) {
7342 // Look at the multiple destroy clauses
7343 for (const OMPDestroyClause *C : ItOMPDestroyClause) {
7344 llvm::Value *InteropvarPtr =
7345 EmitLValue(C->getInteropVar()).getPointer(*this);
7346 OMPBuilder.createOMPInteropDestroy(Builder, InteropvarPtr, Device,
7347 NumDependences, DependenceList,
7348 Data.HasNowaitClause);
7349 }
7350 }
7351 auto ItOMPUseClause = S.getClausesOfKind<OMPUseClause>();
7352 if (!ItOMPUseClause.empty()) {
7353 // Look at the multiple use clauses
7354 for (const OMPUseClause *C : ItOMPUseClause) {
7355 llvm::Value *InteropvarPtr =
7356 EmitLValue(C->getInteropVar()).getPointer(*this);
7357 OMPBuilder.createOMPInteropUse(Builder, InteropvarPtr, Device,
7358 NumDependences, DependenceList,
7359 Data.HasNowaitClause);
7360 }
7361 }
7362}
7363
7366 PrePostActionTy &Action) {
7367 Action.Enter(CGF);
7368 auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
7370 S.getDistInc());
7371 };
7372
7373 // Emit teams region as a standalone region.
7374 auto &&CodeGenTeams = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
7375 PrePostActionTy &Action) {
7376 Action.Enter(CGF);
7377 CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
7378 CGF.EmitOMPReductionClauseInit(S, PrivateScope);
7379 (void)PrivateScope.Privatize();
7381 CGF, OMPD_distribute, CodeGenDistribute, /*HasCancel=*/false);
7382 CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
7383 };
7384
7385 emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute_parallel_for,
7386 CodeGenTeams);
7388 [](CodeGenFunction &) { return nullptr; });
7389}
7390
7392 CodeGenModule &CGM, StringRef ParentName,
7394 // Emit SPMD target teams distribute parallel for region as a standalone
7395 // region.
7396 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7398 };
7399 llvm::Function *Fn;
7400 llvm::Constant *Addr;
7401 // Emit target region as a standalone region.
7402 CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
7403 S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
7404 assert(Fn && Addr && "Target device function emission failed.");
7405}
7406
7414
7416 CodeGenFunction &CGF,
7418 PrePostActionTy &Action) {
7419 Action.Enter(CGF);
7420 auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
7422 S.getDistInc());
7423 };
7424
7425 // Emit teams region as a standalone region.
7426 auto &&CodeGenTeams = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
7427 PrePostActionTy &Action) {
7428 Action.Enter(CGF);
7429 CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
7430 CGF.EmitOMPReductionClauseInit(S, PrivateScope);
7431 (void)PrivateScope.Privatize();
7433 CGF, OMPD_distribute, CodeGenDistribute, /*HasCancel=*/false);
7434 CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
7435 };
7436
7437 emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute_parallel_for_simd,
7438 CodeGenTeams);
7440 [](CodeGenFunction &) { return nullptr; });
7441}
7442
7444 CodeGenModule &CGM, StringRef ParentName,
7446 // Emit SPMD target teams distribute parallel for simd region as a standalone
7447 // region.
7448 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7450 };
7451 llvm::Function *Fn;
7452 llvm::Constant *Addr;
7453 // Emit target region as a standalone region.
7454 CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
7455 S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
7456 assert(Fn && Addr && "Target device function emission failed.");
7457}
7458
7466
7469 CGM.getOpenMPRuntime().emitCancellationPointCall(*this, S.getBeginLoc(),
7470 S.getCancelRegion());
7471}
7472
7474 const Expr *IfCond = nullptr;
7475 for (const auto *C : S.getClausesOfKind<OMPIfClause>()) {
7476 if (C->getNameModifier() == OMPD_unknown ||
7477 C->getNameModifier() == OMPD_cancel) {
7478 IfCond = C->getCondition();
7479 break;
7480 }
7481 }
7482 if (CGM.getLangOpts().OpenMPIRBuilder) {
7483 llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
7484 // TODO: This check is necessary as we only generate `omp parallel` through
7485 // the OpenMPIRBuilder for now.
7486 if (S.getCancelRegion() == OMPD_parallel ||
7487 S.getCancelRegion() == OMPD_sections ||
7488 S.getCancelRegion() == OMPD_section) {
7489 llvm::Value *IfCondition = nullptr;
7490 if (IfCond)
7491 IfCondition = EmitScalarExpr(IfCond,
7492 /*IgnoreResultAssign=*/true);
7493 llvm::OpenMPIRBuilder::InsertPointTy AfterIP = cantFail(
7494 OMPBuilder.createCancel(Builder, IfCondition, S.getCancelRegion()));
7495 return Builder.restoreIP(AfterIP);
7496 }
7497 }
7498
7499 CGM.getOpenMPRuntime().emitCancelCall(*this, S.getBeginLoc(), IfCond,
7500 S.getCancelRegion());
7501}
7502
7505 if (Kind == OMPD_parallel || Kind == OMPD_task ||
7506 Kind == OMPD_target_parallel || Kind == OMPD_taskloop ||
7507 Kind == OMPD_master_taskloop || Kind == OMPD_parallel_master_taskloop)
7508 return ReturnBlock;
7509 assert(Kind == OMPD_for || Kind == OMPD_section || Kind == OMPD_sections ||
7510 Kind == OMPD_parallel_sections || Kind == OMPD_parallel_for ||
7511 Kind == OMPD_distribute_parallel_for ||
7512 Kind == OMPD_target_parallel_for ||
7513 Kind == OMPD_teams_distribute_parallel_for ||
7514 Kind == OMPD_target_teams_distribute_parallel_for);
7515 return OMPCancelStack.getExitBlock();
7516}
7517
7519 const OMPUseDevicePtrClause &C, OMPPrivateScope &PrivateScope,
7520 const llvm::DenseMap<const ValueDecl *, llvm::Value *>
7521 CaptureDeviceAddrMap) {
7522 llvm::SmallDenseSet<CanonicalDeclPtr<const Decl>, 4> Processed;
7523 for (const Expr *OrigVarIt : C.varlist()) {
7524 const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(OrigVarIt)->getDecl());
7525 if (!Processed.insert(OrigVD).second)
7526 continue;
7527
7528 // In order to identify the right initializer we need to match the
7529 // declaration used by the mapping logic. In some cases we may get
7530 // OMPCapturedExprDecl that refers to the original declaration.
7531 const ValueDecl *MatchingVD = OrigVD;
7532 if (const auto *OED = dyn_cast<OMPCapturedExprDecl>(MatchingVD)) {
7533 // OMPCapturedExprDecl are used to privative fields of the current
7534 // structure.
7535 const auto *ME = cast<MemberExpr>(OED->getInit());
7536 assert(isa<CXXThisExpr>(ME->getBase()->IgnoreImpCasts()) &&
7537 "Base should be the current struct!");
7538 MatchingVD = ME->getMemberDecl();
7539 }
7540
7541 // If we don't have information about the current list item, move on to
7542 // the next one.
7543 auto InitAddrIt = CaptureDeviceAddrMap.find(MatchingVD);
7544 if (InitAddrIt == CaptureDeviceAddrMap.end())
7545 continue;
7546
7547 llvm::Type *Ty = ConvertTypeForMem(OrigVD->getType().getNonReferenceType());
7548
7549 // Return the address of the private variable.
7550 bool IsRegistered = PrivateScope.addPrivate(
7551 OrigVD,
7552 Address(InitAddrIt->second, Ty,
7553 getContext().getTypeAlignInChars(getContext().VoidPtrTy)));
7554 assert(IsRegistered && "firstprivate var already registered as private");
7555 // Silence the warning about unused variable.
7556 (void)IsRegistered;
7557 }
7558}
7559
7560static const VarDecl *getBaseDecl(const Expr *Ref) {
7561 const Expr *Base = Ref->IgnoreParenImpCasts();
7562 while (const auto *OASE = dyn_cast<ArraySectionExpr>(Base))
7563 Base = OASE->getBase()->IgnoreParenImpCasts();
7564 while (const auto *ASE = dyn_cast<ArraySubscriptExpr>(Base))
7565 Base = ASE->getBase()->IgnoreParenImpCasts();
7566 return cast<VarDecl>(cast<DeclRefExpr>(Base)->getDecl());
7567}
7568
7570 const OMPUseDeviceAddrClause &C, OMPPrivateScope &PrivateScope,
7571 const llvm::DenseMap<const ValueDecl *, llvm::Value *>
7572 CaptureDeviceAddrMap) {
7573 llvm::SmallDenseSet<CanonicalDeclPtr<const Decl>, 4> Processed;
7574 for (const Expr *Ref : C.varlist()) {
7575 const VarDecl *OrigVD = getBaseDecl(Ref);
7576 if (!Processed.insert(OrigVD).second)
7577 continue;
7578 // In order to identify the right initializer we need to match the
7579 // declaration used by the mapping logic. In some cases we may get
7580 // OMPCapturedExprDecl that refers to the original declaration.
7581 const ValueDecl *MatchingVD = OrigVD;
7582 if (const auto *OED = dyn_cast<OMPCapturedExprDecl>(MatchingVD)) {
7583 // OMPCapturedExprDecl are used to privative fields of the current
7584 // structure.
7585 const auto *ME = cast<MemberExpr>(OED->getInit());
7586 assert(isa<CXXThisExpr>(ME->getBase()) &&
7587 "Base should be the current struct!");
7588 MatchingVD = ME->getMemberDecl();
7589 }
7590
7591 // If we don't have information about the current list item, move on to
7592 // the next one.
7593 auto InitAddrIt = CaptureDeviceAddrMap.find(MatchingVD);
7594 if (InitAddrIt == CaptureDeviceAddrMap.end())
7595 continue;
7596
7597 llvm::Type *Ty = ConvertTypeForMem(OrigVD->getType().getNonReferenceType());
7598
7599 Address PrivAddr =
7600 Address(InitAddrIt->second, Ty,
7601 getContext().getTypeAlignInChars(getContext().VoidPtrTy));
7602 // For declrefs and variable length array need to load the pointer for
7603 // correct mapping, since the pointer to the data was passed to the runtime.
7604 if (isa<DeclRefExpr>(Ref->IgnoreParenImpCasts()) ||
7605 MatchingVD->getType()->isArrayType()) {
7607 OrigVD->getType().getNonReferenceType());
7608 PrivAddr =
7610 PtrTy->castAs<PointerType>());
7611 }
7612
7613 (void)PrivateScope.addPrivate(OrigVD, PrivAddr);
7614 }
7615}
7616
7617// Generate the instructions for '#pragma omp target data' directive.
7619 const OMPTargetDataDirective &S) {
7620 CGOpenMPRuntime::TargetDataInfo Info(/*RequiresDevicePointerInfo=*/true,
7621 /*SeparateBeginEndCalls=*/true);
7622
7623 // Create a pre/post action to signal the privatization of the device pointer.
7624 // This action can be replaced by the OpenMP runtime code generation to
7625 // deactivate privatization.
7626 bool PrivatizeDevicePointers = false;
7627 class DevicePointerPrivActionTy : public PrePostActionTy {
7628 bool &PrivatizeDevicePointers;
7629
7630 public:
7631 explicit DevicePointerPrivActionTy(bool &PrivatizeDevicePointers)
7632 : PrivatizeDevicePointers(PrivatizeDevicePointers) {}
7633 void Enter(CodeGenFunction &CGF) override {
7634 PrivatizeDevicePointers = true;
7635 }
7636 };
7637 DevicePointerPrivActionTy PrivAction(PrivatizeDevicePointers);
7638
7639 auto &&CodeGen = [&](CodeGenFunction &CGF, PrePostActionTy &Action) {
7640 auto &&InnermostCodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
7641 CGF.EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt());
7642 };
7643
7644 // Codegen that selects whether to generate the privatization code or not.
7645 auto &&PrivCodeGen = [&](CodeGenFunction &CGF, PrePostActionTy &Action) {
7646 RegionCodeGenTy RCG(InnermostCodeGen);
7647 PrivatizeDevicePointers = false;
7648
7649 // Call the pre-action to change the status of PrivatizeDevicePointers if
7650 // needed.
7651 Action.Enter(CGF);
7652
7653 if (PrivatizeDevicePointers) {
7654 OMPPrivateScope PrivateScope(CGF);
7655 // Emit all instances of the use_device_ptr clause.
7656 for (const auto *C : S.getClausesOfKind<OMPUseDevicePtrClause>())
7657 CGF.EmitOMPUseDevicePtrClause(*C, PrivateScope,
7659 for (const auto *C : S.getClausesOfKind<OMPUseDeviceAddrClause>())
7660 CGF.EmitOMPUseDeviceAddrClause(*C, PrivateScope,
7662 (void)PrivateScope.Privatize();
7663 RCG(CGF);
7664 } else {
7665 // If we don't have target devices, don't bother emitting the data
7666 // mapping code.
7667 std::optional<OpenMPDirectiveKind> CaptureRegion;
7668 if (CGM.getLangOpts().OMPTargetTriples.empty()) {
7669 // Emit helper decls of the use_device_ptr/use_device_addr clauses.
7670 for (const auto *C : S.getClausesOfKind<OMPUseDevicePtrClause>())
7671 for (const Expr *E : C->varlist()) {
7672 const Decl *D = cast<DeclRefExpr>(E)->getDecl();
7673 if (const auto *OED = dyn_cast<OMPCapturedExprDecl>(D))
7674 CGF.EmitVarDecl(*OED);
7675 }
7676 for (const auto *C : S.getClausesOfKind<OMPUseDeviceAddrClause>())
7677 for (const Expr *E : C->varlist()) {
7678 const Decl *D = getBaseDecl(E);
7679 if (const auto *OED = dyn_cast<OMPCapturedExprDecl>(D))
7680 CGF.EmitVarDecl(*OED);
7681 }
7682 } else {
7683 CaptureRegion = OMPD_unknown;
7684 }
7685
7686 OMPLexicalScope Scope(CGF, S, CaptureRegion);
7687 RCG(CGF);
7688 }
7689 };
7690
7691 // Forward the provided action to the privatization codegen.
7692 RegionCodeGenTy PrivRCG(PrivCodeGen);
7693 PrivRCG.setAction(Action);
7694
7695 // Notwithstanding the body of the region is emitted as inlined directive,
7696 // we don't use an inline scope as changes in the references inside the
7697 // region are expected to be visible outside, so we do not privative them.
7698 OMPLexicalScope Scope(CGF, S);
7699 CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_target_data,
7700 PrivRCG);
7701 };
7702
7704
7705 // If we don't have target devices, don't bother emitting the data mapping
7706 // code.
7707 if (CGM.getLangOpts().OMPTargetTriples.empty()) {
7708 RCG(*this);
7709 return;
7710 }
7711
7712 // Check if we have any if clause associated with the directive.
7713 const Expr *IfCond = nullptr;
7714 if (const auto *C = S.getSingleClause<OMPIfClause>())
7715 IfCond = C->getCondition();
7716
7717 // Check if we have any device clause associated with the directive.
7718 const Expr *Device = nullptr;
7719 if (const auto *C = S.getSingleClause<OMPDeviceClause>())
7720 Device = C->getDevice();
7721
7722 // Set the action to signal privatization of device pointers.
7723 RCG.setAction(PrivAction);
7724
7725 // Emit region code.
7726 CGM.getOpenMPRuntime().emitTargetDataCalls(*this, S, IfCond, Device, RCG,
7727 Info);
7728}
7729
7731 const OMPTargetEnterDataDirective &S) {
7732 // If we don't have target devices, don't bother emitting the data mapping
7733 // code.
7734 if (CGM.getLangOpts().OMPTargetTriples.empty())
7735 return;
7736
7737 // Check if we have any if clause associated with the directive.
7738 const Expr *IfCond = nullptr;
7739 if (const auto *C = S.getSingleClause<OMPIfClause>())
7740 IfCond = C->getCondition();
7741
7742 // Check if we have any device clause associated with the directive.
7743 const Expr *Device = nullptr;
7744 if (const auto *C = S.getSingleClause<OMPDeviceClause>())
7745 Device = C->getDevice();
7746
7747 OMPLexicalScope Scope(*this, S, OMPD_task);
7748 CGM.getOpenMPRuntime().emitTargetDataStandAloneCall(*this, S, IfCond, Device);
7749}
7750
7752 const OMPTargetExitDataDirective &S) {
7753 // If we don't have target devices, don't bother emitting the data mapping
7754 // code.
7755 if (CGM.getLangOpts().OMPTargetTriples.empty())
7756 return;
7757
7758 // Check if we have any if clause associated with the directive.
7759 const Expr *IfCond = nullptr;
7760 if (const auto *C = S.getSingleClause<OMPIfClause>())
7761 IfCond = C->getCondition();
7762
7763 // Check if we have any device clause associated with the directive.
7764 const Expr *Device = nullptr;
7765 if (const auto *C = S.getSingleClause<OMPDeviceClause>())
7766 Device = C->getDevice();
7767
7768 OMPLexicalScope Scope(*this, S, OMPD_task);
7769 CGM.getOpenMPRuntime().emitTargetDataStandAloneCall(*this, S, IfCond, Device);
7770}
7771
7774 PrePostActionTy &Action) {
7775 // Get the captured statement associated with the 'parallel' region.
7776 const CapturedStmt *CS = S.getCapturedStmt(OMPD_parallel);
7777 Action.Enter(CGF);
7778 auto &&CodeGen = [&S, CS](CodeGenFunction &CGF, PrePostActionTy &Action) {
7779 Action.Enter(CGF);
7780 CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
7781 (void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
7782 CGF.EmitOMPPrivateClause(S, PrivateScope);
7783 CGF.EmitOMPReductionClauseInit(S, PrivateScope);
7784 (void)PrivateScope.Privatize();
7785 if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()))
7787 // TODO: Add support for clauses.
7788 CGF.EmitStmt(CS->getCapturedStmt());
7789 CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_parallel);
7790 };
7791 emitCommonOMPParallelDirective(CGF, S, OMPD_parallel, CodeGen,
7794 [](CodeGenFunction &) { return nullptr; });
7795}
7796
7798 CodeGenModule &CGM, StringRef ParentName,
7799 const OMPTargetParallelDirective &S) {
7800 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7801 emitTargetParallelRegion(CGF, S, Action);
7802 };
7803 llvm::Function *Fn;
7804 llvm::Constant *Addr;
7805 // Emit target region as a standalone region.
7806 CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
7807 S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
7808 assert(Fn && Addr && "Target device function emission failed.");
7809}
7810
7812 const OMPTargetParallelDirective &S) {
7813 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7814 emitTargetParallelRegion(CGF, S, Action);
7815 };
7817}
7818
7821 PrePostActionTy &Action) {
7822 Action.Enter(CGF);
7823 // Emit directive as a combined directive that consists of two implicit
7824 // directives: 'parallel' with 'for' directive.
7825 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7826 Action.Enter(CGF);
7828 CGF, OMPD_target_parallel_for, S.hasCancel());
7829 CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(), emitForLoopBounds,
7831 };
7832 emitCommonOMPParallelDirective(CGF, S, OMPD_for, CodeGen,
7834}
7835
7837 CodeGenModule &CGM, StringRef ParentName,
7839 // Emit SPMD target parallel for region as a standalone region.
7840 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7841 emitTargetParallelForRegion(CGF, S, Action);
7842 };
7843 llvm::Function *Fn;
7844 llvm::Constant *Addr;
7845 // Emit target region as a standalone region.
7846 CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
7847 S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
7848 assert(Fn && Addr && "Target device function emission failed.");
7849}
7850
7853 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7854 emitTargetParallelForRegion(CGF, S, Action);
7855 };
7857}
7858
7859static void
7862 PrePostActionTy &Action) {
7863 Action.Enter(CGF);
7864 // Emit directive as a combined directive that consists of two implicit
7865 // directives: 'parallel' with 'for' directive.
7866 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7867 Action.Enter(CGF);
7868 CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(), emitForLoopBounds,
7870 };
7871 emitCommonOMPParallelDirective(CGF, S, OMPD_simd, CodeGen,
7873}
7874
7876 CodeGenModule &CGM, StringRef ParentName,
7878 // Emit SPMD target parallel for region as a standalone region.
7879 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7880 emitTargetParallelForSimdRegion(CGF, S, Action);
7881 };
7882 llvm::Function *Fn;
7883 llvm::Constant *Addr;
7884 // Emit target region as a standalone region.
7885 CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
7886 S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
7887 assert(Fn && Addr && "Target device function emission failed.");
7888}
7889
7892 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7893 emitTargetParallelForSimdRegion(CGF, S, Action);
7894 };
7896}
7897
7898/// Emit a helper variable and return corresponding lvalue.
7899static void mapParam(CodeGenFunction &CGF, const DeclRefExpr *Helper,
7900 const ImplicitParamDecl *PVD,
7902 const auto *VDecl = cast<VarDecl>(Helper->getDecl());
7903 Privates.addPrivate(VDecl, CGF.GetAddrOfLocalVar(PVD));
7904}
7905
7907 assert(isOpenMPTaskLoopDirective(S.getDirectiveKind()));
7908 // Emit outlined function for task construct.
7909 const CapturedStmt *CS = S.getCapturedStmt(OMPD_taskloop);
7910 Address CapturedStruct = Address::invalid();
7911 {
7912 OMPLexicalScope Scope(*this, S, OMPD_taskloop, /*EmitPreInitStmt=*/false);
7913 CapturedStruct = GenerateCapturedStmtArgument(*CS);
7914 }
7915 CanQualType SharedsTy =
7917 const Expr *IfCond = nullptr;
7918 for (const auto *C : S.getClausesOfKind<OMPIfClause>()) {
7919 if (C->getNameModifier() == OMPD_unknown ||
7920 C->getNameModifier() == OMPD_taskloop) {
7921 IfCond = C->getCondition();
7922 break;
7923 }
7924 }
7925
7927 // Check if taskloop must be emitted without taskgroup.
7928 Data.Nogroup = S.getSingleClause<OMPNogroupClause>();
7929 // TODO: Check if we should emit tied or untied task.
7930 Data.Tied = true;
7931 // Set scheduling for taskloop
7932 if (const auto *Clause = S.getSingleClause<OMPGrainsizeClause>()) {
7933 // grainsize clause
7934 Data.Schedule.setInt(/*IntVal=*/false);
7935 Data.Schedule.setPointer(EmitScalarExpr(Clause->getGrainsize()));
7936 Data.HasModifier =
7937 (Clause->getModifier() == OMPC_GRAINSIZE_strict) ? true : false;
7938 } else if (const auto *Clause = S.getSingleClause<OMPNumTasksClause>()) {
7939 // num_tasks clause
7940 Data.Schedule.setInt(/*IntVal=*/true);
7941 Data.Schedule.setPointer(EmitScalarExpr(Clause->getNumTasks()));
7942 Data.HasModifier =
7943 (Clause->getModifier() == OMPC_NUMTASKS_strict) ? true : false;
7944 }
7945
7946 auto &&BodyGen = [CS, &S](CodeGenFunction &CGF, PrePostActionTy &) {
7947 // if (PreCond) {
7948 // for (IV in 0..LastIteration) BODY;
7949 // <Final counter/linear vars updates>;
7950 // }
7951 //
7952
7953 // Emit: if (PreCond) - begin.
7954 // If the condition constant folds and can be elided, avoid emitting the
7955 // whole loop.
7956 bool CondConstant;
7957 llvm::BasicBlock *ContBlock = nullptr;
7958 OMPLoopScope PreInitScope(CGF, S);
7959 if (CGF.ConstantFoldsToSimpleInteger(S.getPreCond(), CondConstant)) {
7960 if (!CondConstant)
7961 return;
7962 } else {
7963 llvm::BasicBlock *ThenBlock = CGF.createBasicBlock("taskloop.if.then");
7964 ContBlock = CGF.createBasicBlock("taskloop.if.end");
7965 emitPreCond(CGF, S, S.getPreCond(), ThenBlock, ContBlock,
7966 CGF.getProfileCount(&S));
7967 CGF.EmitBlock(ThenBlock);
7968 CGF.incrementProfileCounter(&S);
7969 }
7970
7971 (void)CGF.EmitOMPLinearClauseInit(S);
7972
7973 OMPPrivateScope LoopScope(CGF);
7974 // Emit helper vars inits.
7975 enum { LowerBound = 5, UpperBound, Stride, LastIter };
7976 auto *I = CS->getCapturedDecl()->param_begin();
7977 auto *LBP = std::next(I, LowerBound);
7978 auto *UBP = std::next(I, UpperBound);
7979 auto *STP = std::next(I, Stride);
7980 auto *LIP = std::next(I, LastIter);
7981 mapParam(CGF, cast<DeclRefExpr>(S.getLowerBoundVariable()), *LBP,
7982 LoopScope);
7983 mapParam(CGF, cast<DeclRefExpr>(S.getUpperBoundVariable()), *UBP,
7984 LoopScope);
7985 mapParam(CGF, cast<DeclRefExpr>(S.getStrideVariable()), *STP, LoopScope);
7986 mapParam(CGF, cast<DeclRefExpr>(S.getIsLastIterVariable()), *LIP,
7987 LoopScope);
7988 CGF.EmitOMPPrivateLoopCounters(S, LoopScope);
7989 CGF.EmitOMPLinearClause(S, LoopScope);
7990 bool HasLastprivateClause = CGF.EmitOMPLastprivateClauseInit(S, LoopScope);
7991 (void)LoopScope.Privatize();
7992 // Emit the loop iteration variable.
7993 const Expr *IVExpr = S.getIterationVariable();
7994 const auto *IVDecl = cast<VarDecl>(cast<DeclRefExpr>(IVExpr)->getDecl());
7995 CGF.EmitVarDecl(*IVDecl);
7996 CGF.EmitIgnoredExpr(S.getInit());
7997
7998 // Emit the iterations count variable.
7999 // If it is not a variable, Sema decided to calculate iterations count on
8000 // each iteration (e.g., it is foldable into a constant).
8001 if (const auto *LIExpr = dyn_cast<DeclRefExpr>(S.getLastIteration())) {
8002 CGF.EmitVarDecl(*cast<VarDecl>(LIExpr->getDecl()));
8003 // Emit calculation of the iterations count.
8004 CGF.EmitIgnoredExpr(S.getCalcLastIteration());
8005 }
8006
8007 {
8008 OMPLexicalScope Scope(CGF, S, OMPD_taskloop, /*EmitPreInitStmt=*/false);
8010 CGF, S,
8011 [&S](CodeGenFunction &CGF, PrePostActionTy &) {
8012 if (isOpenMPSimdDirective(S.getDirectiveKind()))
8013 CGF.EmitOMPSimdInit(S);
8014 },
8015 [&S, &LoopScope](CodeGenFunction &CGF, PrePostActionTy &) {
8016 CGF.EmitOMPInnerLoop(
8017 S, LoopScope.requiresCleanups(), S.getCond(), S.getInc(),
8018 [&S](CodeGenFunction &CGF) {
8019 emitOMPLoopBodyWithStopPoint(CGF, S,
8020 CodeGenFunction::JumpDest());
8021 },
8022 [](CodeGenFunction &) {});
8023 });
8024 }
8025 // Emit: if (PreCond) - end.
8026 if (ContBlock) {
8027 CGF.EmitBranch(ContBlock);
8028 CGF.EmitBlock(ContBlock, true);
8029 }
8030 // Emit final copy of the lastprivate variables if IsLastIter != 0.
8031 if (HasLastprivateClause) {
8032 CGF.EmitOMPLastprivateClauseFinal(
8033 S, isOpenMPSimdDirective(S.getDirectiveKind()),
8034 CGF.Builder.CreateIsNotNull(CGF.EmitLoadOfScalar(
8035 CGF.GetAddrOfLocalVar(*LIP), /*Volatile=*/false,
8036 (*LIP)->getType(), S.getBeginLoc())));
8037 }
8038 LoopScope.restoreMap();
8039 CGF.EmitOMPLinearClauseFinal(S, [LIP, &S](CodeGenFunction &CGF) {
8040 return CGF.Builder.CreateIsNotNull(
8041 CGF.EmitLoadOfScalar(CGF.GetAddrOfLocalVar(*LIP), /*Volatile=*/false,
8042 (*LIP)->getType(), S.getBeginLoc()));
8043 });
8044 };
8045 auto &&TaskGen = [&S, SharedsTy, CapturedStruct,
8046 IfCond](CodeGenFunction &CGF, llvm::Function *OutlinedFn,
8047 const OMPTaskDataTy &Data) {
8048 auto &&CodeGen = [&S, OutlinedFn, SharedsTy, CapturedStruct, IfCond,
8049 &Data](CodeGenFunction &CGF, PrePostActionTy &) {
8050 OMPLoopScope PreInitScope(CGF, S);
8051 CGF.CGM.getOpenMPRuntime().emitTaskLoopCall(CGF, S.getBeginLoc(), S,
8052 OutlinedFn, SharedsTy,
8053 CapturedStruct, IfCond, Data);
8054 };
8055 CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_taskloop,
8056 CodeGen);
8057 };
8058 if (Data.Nogroup) {
8059 EmitOMPTaskBasedDirective(S, OMPD_taskloop, BodyGen, TaskGen, Data);
8060 } else {
8061 CGM.getOpenMPRuntime().emitTaskgroupRegion(
8062 *this,
8063 [&S, &BodyGen, &TaskGen, &Data](CodeGenFunction &CGF,
8064 PrePostActionTy &Action) {
8065 Action.Enter(CGF);
8066 CGF.EmitOMPTaskBasedDirective(S, OMPD_taskloop, BodyGen, TaskGen,
8067 Data);
8068 },
8069 S.getBeginLoc());
8070 }
8071}
8072
8078
8080 const OMPTaskLoopSimdDirective &S) {
8081 auto LPCRegion =
8083 OMPLexicalScope Scope(*this, S);
8085}
8086
8088 const OMPMasterTaskLoopDirective &S) {
8089 auto &&CodeGen = [this, &S](CodeGenFunction &CGF, PrePostActionTy &Action) {
8090 Action.Enter(CGF);
8092 };
8093 auto LPCRegion =
8095 OMPLexicalScope Scope(*this, S, std::nullopt, /*EmitPreInitStmt=*/false);
8096 CGM.getOpenMPRuntime().emitMasterRegion(*this, CodeGen, S.getBeginLoc());
8097}
8098
8100 const OMPMaskedTaskLoopDirective &S) {
8101 auto &&CodeGen = [this, &S](CodeGenFunction &CGF, PrePostActionTy &Action) {
8102 Action.Enter(CGF);
8104 };
8105 auto LPCRegion =
8107 OMPLexicalScope Scope(*this, S, std::nullopt, /*EmitPreInitStmt=*/false);
8108 CGM.getOpenMPRuntime().emitMaskedRegion(*this, CodeGen, S.getBeginLoc());
8109}
8110
8113 auto &&CodeGen = [this, &S](CodeGenFunction &CGF, PrePostActionTy &Action) {
8114 Action.Enter(CGF);
8116 };
8117 auto LPCRegion =
8119 OMPLexicalScope Scope(*this, S);
8120 CGM.getOpenMPRuntime().emitMasterRegion(*this, CodeGen, S.getBeginLoc());
8121}
8122
8125 auto &&CodeGen = [this, &S](CodeGenFunction &CGF, PrePostActionTy &Action) {
8126 Action.Enter(CGF);
8128 };
8129 auto LPCRegion =
8131 OMPLexicalScope Scope(*this, S);
8132 CGM.getOpenMPRuntime().emitMaskedRegion(*this, CodeGen, S.getBeginLoc());
8133}
8134
8137 auto &&CodeGen = [this, &S](CodeGenFunction &CGF, PrePostActionTy &Action) {
8138 auto &&TaskLoopCodeGen = [&S](CodeGenFunction &CGF,
8139 PrePostActionTy &Action) {
8140 Action.Enter(CGF);
8142 };
8143 OMPLexicalScope Scope(CGF, S, OMPD_parallel, /*EmitPreInitStmt=*/false);
8144 CGM.getOpenMPRuntime().emitMasterRegion(CGF, TaskLoopCodeGen,
8145 S.getBeginLoc());
8146 };
8147 auto LPCRegion =
8149 emitCommonOMPParallelDirective(*this, S, OMPD_master_taskloop, CodeGen,
8151}
8152
8155 auto &&CodeGen = [this, &S](CodeGenFunction &CGF, PrePostActionTy &Action) {
8156 auto &&TaskLoopCodeGen = [&S](CodeGenFunction &CGF,
8157 PrePostActionTy &Action) {
8158 Action.Enter(CGF);
8160 };
8161 OMPLexicalScope Scope(CGF, S, OMPD_parallel, /*EmitPreInitStmt=*/false);
8162 CGM.getOpenMPRuntime().emitMaskedRegion(CGF, TaskLoopCodeGen,
8163 S.getBeginLoc());
8164 };
8165 auto LPCRegion =
8167 emitCommonOMPParallelDirective(*this, S, OMPD_masked_taskloop, CodeGen,
8169}
8170
8173 auto &&CodeGen = [this, &S](CodeGenFunction &CGF, PrePostActionTy &Action) {
8174 auto &&TaskLoopCodeGen = [&S](CodeGenFunction &CGF,
8175 PrePostActionTy &Action) {
8176 Action.Enter(CGF);
8178 };
8179 OMPLexicalScope Scope(CGF, S, OMPD_parallel, /*EmitPreInitStmt=*/false);
8180 CGM.getOpenMPRuntime().emitMasterRegion(CGF, TaskLoopCodeGen,
8181 S.getBeginLoc());
8182 };
8183 auto LPCRegion =
8185 emitCommonOMPParallelDirective(*this, S, OMPD_master_taskloop_simd, CodeGen,
8187}
8188
8191 auto &&CodeGen = [this, &S](CodeGenFunction &CGF, PrePostActionTy &Action) {
8192 auto &&TaskLoopCodeGen = [&S](CodeGenFunction &CGF,
8193 PrePostActionTy &Action) {
8194 Action.Enter(CGF);
8196 };
8197 OMPLexicalScope Scope(CGF, S, OMPD_parallel, /*EmitPreInitStmt=*/false);
8198 CGM.getOpenMPRuntime().emitMaskedRegion(CGF, TaskLoopCodeGen,
8199 S.getBeginLoc());
8200 };
8201 auto LPCRegion =
8203 emitCommonOMPParallelDirective(*this, S, OMPD_masked_taskloop_simd, CodeGen,
8205}
8206
8207// Generate the instructions for '#pragma omp target update' directive.
8209 const OMPTargetUpdateDirective &S) {
8210 // If we don't have target devices, don't bother emitting the data mapping
8211 // code.
8212 if (CGM.getLangOpts().OMPTargetTriples.empty())
8213 return;
8214
8215 // Check if we have any if clause associated with the directive.
8216 const Expr *IfCond = nullptr;
8217 if (const auto *C = S.getSingleClause<OMPIfClause>())
8218 IfCond = C->getCondition();
8219
8220 // Check if we have any device clause associated with the directive.
8221 const Expr *Device = nullptr;
8222 if (const auto *C = S.getSingleClause<OMPDeviceClause>())
8223 Device = C->getDevice();
8224
8225 OMPLexicalScope Scope(*this, S, OMPD_task);
8226 CGM.getOpenMPRuntime().emitTargetDataStandAloneCall(*this, S, IfCond, Device);
8227}
8228
8230 const OMPGenericLoopDirective &S) {
8231 // Always expect a bind clause on the loop directive. It it wasn't
8232 // in the source, it should have been added in sema.
8233
8235 if (const auto *C = S.getSingleClause<OMPBindClause>())
8236 BindKind = C->getBindKind();
8237
8238 switch (BindKind) {
8239 case OMPC_BIND_parallel: // for
8240 return emitOMPForDirective(S, *this, CGM, /*HasCancel=*/false);
8241 case OMPC_BIND_teams: // distribute
8242 return emitOMPDistributeDirective(S, *this, CGM);
8243 case OMPC_BIND_thread: // simd
8244 return emitOMPSimdDirective(S, *this, CGM);
8245 case OMPC_BIND_unknown:
8246 break;
8247 }
8248
8249 // Unimplemented, just inline the underlying statement for now.
8250 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
8251 // Emit the loop iteration variable.
8252 const Stmt *CS =
8253 cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt();
8254 const auto *ForS = dyn_cast<ForStmt>(CS);
8255 if (ForS && !isa<DeclStmt>(ForS->getInit())) {
8256 OMPPrivateScope LoopScope(CGF);
8257 CGF.EmitOMPPrivateLoopCounters(S, LoopScope);
8258 (void)LoopScope.Privatize();
8259 CGF.EmitStmt(CS);
8260 LoopScope.restoreMap();
8261 } else {
8262 CGF.EmitStmt(CS);
8263 }
8264 };
8265 OMPLexicalScope Scope(*this, S, OMPD_unknown);
8266 CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_loop, CodeGen);
8267}
8268
8270 const OMPLoopDirective &S) {
8271 // Emit combined directive as if its constituent constructs are 'parallel'
8272 // and 'for'.
8273 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
8274 Action.Enter(CGF);
8275 emitOMPCopyinClause(CGF, S);
8276 (void)emitWorksharingDirective(CGF, S, /*HasCancel=*/false);
8277 };
8278 {
8279 auto LPCRegion =
8281 emitCommonOMPParallelDirective(*this, S, OMPD_for, CodeGen,
8283 }
8284 // Check for outer lastprivate conditional update.
8286}
8287
8290 // To be consistent with current behavior of 'target teams loop', emit
8291 // 'teams loop' as if its constituent constructs are 'teams' and 'distribute'.
8292 auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
8294 };
8295
8296 // Emit teams region as a standalone region.
8297 auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
8298 PrePostActionTy &Action) {
8299 Action.Enter(CGF);
8300 OMPPrivateScope PrivateScope(CGF);
8301 CGF.EmitOMPReductionClauseInit(S, PrivateScope);
8302 (void)PrivateScope.Privatize();
8303 CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_distribute,
8304 CodeGenDistribute);
8305 CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
8306 };
8307 emitCommonOMPTeamsDirective(*this, S, OMPD_distribute, CodeGen);
8309 [](CodeGenFunction &) { return nullptr; });
8310}
8311
8312#ifndef NDEBUG
8314 std::string StatusMsg,
8315 const OMPExecutableDirective &D) {
8316 bool IsDevice = CGF.CGM.getLangOpts().OpenMPIsTargetDevice;
8317 if (IsDevice)
8318 StatusMsg += ": DEVICE";
8319 else
8320 StatusMsg += ": HOST";
8321 SourceLocation L = D.getBeginLoc();
8322 auto &SM = CGF.getContext().getSourceManager();
8323 PresumedLoc PLoc = SM.getPresumedLoc(L);
8324 const char *FileName = PLoc.isValid() ? PLoc.getFilename() : nullptr;
8325 unsigned LineNo =
8326 PLoc.isValid() ? PLoc.getLine() : SM.getExpansionLineNumber(L);
8327 llvm::dbgs() << StatusMsg << ": " << FileName << ": " << LineNo << "\n";
8328}
8329#endif
8330
8332 CodeGenFunction &CGF, PrePostActionTy &Action,
8334 Action.Enter(CGF);
8335 // Emit 'teams loop' as if its constituent constructs are 'distribute,
8336 // 'parallel, and 'for'.
8337 auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
8339 S.getDistInc());
8340 };
8341
8342 // Emit teams region as a standalone region.
8343 auto &&CodeGenTeams = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
8344 PrePostActionTy &Action) {
8345 Action.Enter(CGF);
8346 CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
8347 CGF.EmitOMPReductionClauseInit(S, PrivateScope);
8348 (void)PrivateScope.Privatize();
8350 CGF, OMPD_distribute, CodeGenDistribute, /*HasCancel=*/false);
8351 CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
8352 };
8353 DEBUG_WITH_TYPE(TTL_CODEGEN_TYPE,
8355 CGF, TTL_CODEGEN_TYPE " as parallel for", S));
8356 emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute_parallel_for,
8357 CodeGenTeams);
8359 [](CodeGenFunction &) { return nullptr; });
8360}
8361
8363 CodeGenFunction &CGF, PrePostActionTy &Action,
8365 Action.Enter(CGF);
8366 // Emit 'teams loop' as if its constituent construct is 'distribute'.
8367 auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
8369 };
8370
8371 // Emit teams region as a standalone region.
8372 auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
8373 PrePostActionTy &Action) {
8374 Action.Enter(CGF);
8375 CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
8376 CGF.EmitOMPReductionClauseInit(S, PrivateScope);
8377 (void)PrivateScope.Privatize();
8379 CGF, OMPD_distribute, CodeGenDistribute, /*HasCancel=*/false);
8380 CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
8381 };
8382 DEBUG_WITH_TYPE(TTL_CODEGEN_TYPE,
8384 CGF, TTL_CODEGEN_TYPE " as distribute", S));
8385 emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute, CodeGen);
8387 [](CodeGenFunction &) { return nullptr; });
8388}
8389
8392 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
8393 if (S.canBeParallelFor())
8395 else
8397 };
8399}
8400
8402 CodeGenModule &CGM, StringRef ParentName,
8404 // Emit SPMD target parallel loop region as a standalone region.
8405 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
8406 if (S.canBeParallelFor())
8408 else
8410 };
8411 llvm::Function *Fn;
8412 llvm::Constant *Addr;
8413 // Emit target region as a standalone region.
8414 CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
8415 S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
8416 assert(Fn && Addr &&
8417 "Target device function emission failed for 'target teams loop'.");
8418}
8419
8422 PrePostActionTy &Action) {
8423 Action.Enter(CGF);
8424 // Emit as 'parallel for'.
8425 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
8426 Action.Enter(CGF);
8428 CGF, OMPD_target_parallel_loop, /*hasCancel=*/false);
8429 CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(), emitForLoopBounds,
8431 };
8432 emitCommonOMPParallelDirective(CGF, S, OMPD_for, CodeGen,
8434}
8435
8437 CodeGenModule &CGM, StringRef ParentName,
8439 // Emit target parallel loop region as a standalone region.
8440 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
8442 };
8443 llvm::Function *Fn;
8444 llvm::Constant *Addr;
8445 // Emit target region as a standalone region.
8446 CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
8447 S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
8448 assert(Fn && Addr && "Target device function emission failed.");
8449}
8450
8451/// Emit combined directive 'target parallel loop' as if its constituent
8452/// constructs are 'target', 'parallel', and 'for'.
8455 auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
8457 };
8459}
8460
8462 const OMPExecutableDirective &D) {
8463 if (const auto *SD = dyn_cast<OMPScanDirective>(&D)) {
8465 return;
8466 }
8467 if (!D.hasAssociatedStmt() || !D.getAssociatedStmt())
8468 return;
8469 auto &&CodeGen = [&D](CodeGenFunction &CGF, PrePostActionTy &Action) {
8470 OMPPrivateScope GlobalsScope(CGF);
8471 if (isOpenMPTaskingDirective(D.getDirectiveKind())) {
8472 // Capture global firstprivates to avoid crash.
8473 for (const auto *C : D.getClausesOfKind<OMPFirstprivateClause>()) {
8474 for (const Expr *Ref : C->varlist()) {
8475 const auto *DRE = cast<DeclRefExpr>(Ref->IgnoreParenImpCasts());
8476 if (!DRE)
8477 continue;
8478 const auto *VD = dyn_cast<VarDecl>(DRE->getDecl());
8479 if (!VD || VD->hasLocalStorage())
8480 continue;
8481 if (!CGF.LocalDeclMap.count(VD)) {
8482 LValue GlobLVal = CGF.EmitLValue(Ref);
8483 GlobalsScope.addPrivate(VD, GlobLVal.getAddress());
8484 }
8485 }
8486 }
8487 }
8488 if (isOpenMPSimdDirective(D.getDirectiveKind())) {
8489 (void)GlobalsScope.Privatize();
8490 ParentLoopDirectiveForScanRegion ScanRegion(CGF, D);
8492 } else {
8493 if (const auto *LD = dyn_cast<OMPLoopDirective>(&D)) {
8494 for (const Expr *E : LD->counters()) {
8495 const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
8496 if (!VD->hasLocalStorage() && !CGF.LocalDeclMap.count(VD)) {
8497 LValue GlobLVal = CGF.EmitLValue(E);
8498 GlobalsScope.addPrivate(VD, GlobLVal.getAddress());
8499 }
8500 if (isa<OMPCapturedExprDecl>(VD)) {
8501 // Emit only those that were not explicitly referenced in clauses.
8502 if (!CGF.LocalDeclMap.count(VD))
8503 CGF.EmitVarDecl(*VD);
8504 }
8505 }
8506 for (const auto *C : D.getClausesOfKind<OMPOrderedClause>()) {
8507 if (!C->getNumForLoops())
8508 continue;
8509 for (unsigned I = LD->getLoopsNumber(),
8510 E = C->getLoopNumIterations().size();
8511 I < E; ++I) {
8512 if (const auto *VD = dyn_cast<OMPCapturedExprDecl>(
8513 cast<DeclRefExpr>(C->getLoopCounter(I))->getDecl())) {
8514 // Emit only those that were not explicitly referenced in clauses.
8515 if (!CGF.LocalDeclMap.count(VD))
8516 CGF.EmitVarDecl(*VD);
8517 }
8518 }
8519 }
8520 }
8521 (void)GlobalsScope.Privatize();
8522 CGF.EmitStmt(D.getInnermostCapturedStmt()->getCapturedStmt());
8523 }
8524 };
8525 if (D.getDirectiveKind() == OMPD_atomic ||
8526 D.getDirectiveKind() == OMPD_critical ||
8527 D.getDirectiveKind() == OMPD_section ||
8528 D.getDirectiveKind() == OMPD_master ||
8529 D.getDirectiveKind() == OMPD_masked ||
8530 D.getDirectiveKind() == OMPD_unroll ||
8531 D.getDirectiveKind() == OMPD_assume) {
8532 EmitStmt(D.getAssociatedStmt());
8533 } else {
8534 auto LPCRegion =
8536 OMPSimdLexicalScope Scope(*this, D);
8537 CGM.getOpenMPRuntime().emitInlinedDirective(
8538 *this,
8539 isOpenMPSimdDirective(D.getDirectiveKind()) ? OMPD_simd
8540 : D.getDirectiveKind(),
8541 CodeGen);
8542 }
8543 // Check for outer lastprivate conditional update.
8545}
8546
8548 EmitStmt(S.getAssociatedStmt());
8549}
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:188
SourceManager & getSourceManager()
Definition ASTContext.h:798
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:737
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:4938
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 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 emitNumThreadsClause(CodeGenFunction &CGF, llvm::Value *NumThreads, SourceLocation Loc, OpenMPNumThreadsClauseModifier Modifier=OMPC_NUMTHREADS_unknown, OpenMPSeverityClauseKind Severity=OMPC_SEVERITY_fatal, const Expr *Message=nullptr)
Emits call to void __kmpc_push_num_threads(ident_t *loc, kmp_int32global_tid, kmp_int32 num_threads) ...
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:3294
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:3335
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:3342
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:3073
Expr * IgnoreImplicitAsWritten() LLVM_READONLY
Skip past any implicit AST nodes which might surround this expression until reaching a fixed point.
Definition Expr.cpp:3065
Expr * IgnoreImpCasts() LLVM_READONLY
Skip past any implicit casts which might surround this expression until reaching a fixed point.
Definition Expr.cpp:3053
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:4995
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