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