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