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