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