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