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