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