clang 23.0.0git
CGOpenMPRuntimeGPU.cpp
Go to the documentation of this file.
1//===---- CGOpenMPRuntimeGPU.cpp - Interface to OpenMP GPU Runtimes ----===//
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 provides a generalized class for OpenMP runtime code generation
10// specialized by GPU targets NVPTX, AMDGCN and SPIR-V.
11//
12//===----------------------------------------------------------------------===//
13
14#include "CGOpenMPRuntimeGPU.h"
15#include "CGDebugInfo.h"
16#include "CodeGenFunction.h"
17#include "clang/AST/Attr.h"
22#include "clang/Basic/Cuda.h"
23#include "llvm/ADT/SmallPtrSet.h"
24#include "llvm/Frontend/OpenMP/OMPDeviceConstants.h"
25#include "llvm/Frontend/OpenMP/OMPGridValues.h"
26
27using namespace clang;
28using namespace CodeGen;
29using namespace llvm::omp;
30
31namespace {
32/// Pre(post)-action for different OpenMP constructs specialized for NVPTX.
33class NVPTXActionTy final : public PrePostActionTy {
34 llvm::FunctionCallee EnterCallee = nullptr;
35 ArrayRef<llvm::Value *> EnterArgs;
36 llvm::FunctionCallee ExitCallee = nullptr;
37 ArrayRef<llvm::Value *> ExitArgs;
38 bool Conditional = false;
39 llvm::BasicBlock *ContBlock = nullptr;
40
41public:
42 NVPTXActionTy(llvm::FunctionCallee EnterCallee,
43 ArrayRef<llvm::Value *> EnterArgs,
44 llvm::FunctionCallee ExitCallee,
45 ArrayRef<llvm::Value *> ExitArgs, bool Conditional = false)
46 : EnterCallee(EnterCallee), EnterArgs(EnterArgs), ExitCallee(ExitCallee),
47 ExitArgs(ExitArgs), Conditional(Conditional) {}
48 void Enter(CodeGenFunction &CGF) override {
49 llvm::Value *EnterRes = CGF.EmitRuntimeCall(EnterCallee, EnterArgs);
50 if (Conditional) {
51 llvm::Value *CallBool = CGF.Builder.CreateIsNotNull(EnterRes);
52 auto *ThenBlock = CGF.createBasicBlock("omp_if.then");
53 ContBlock = CGF.createBasicBlock("omp_if.end");
54 // Generate the branch (If-stmt)
55 CGF.Builder.CreateCondBr(CallBool, ThenBlock, ContBlock);
56 CGF.EmitBlock(ThenBlock);
57 }
58 }
59 void Done(CodeGenFunction &CGF) {
60 // Emit the rest of blocks/branches
61 CGF.EmitBranch(ContBlock);
62 CGF.EmitBlock(ContBlock, true);
63 }
64 void Exit(CodeGenFunction &CGF) override {
65 CGF.EmitRuntimeCall(ExitCallee, ExitArgs);
66 }
67};
68
69/// A class to track the execution mode when codegening directives within
70/// a target region. The appropriate mode (SPMD|NON-SPMD) is set on entry
71/// to the target region and used by containing directives such as 'parallel'
72/// to emit optimized code.
73class ExecutionRuntimeModesRAII {
74private:
78
79public:
80 ExecutionRuntimeModesRAII(CGOpenMPRuntimeGPU::ExecutionMode &ExecMode,
82 : ExecMode(ExecMode) {
83 SavedExecMode = ExecMode;
84 ExecMode = EntryMode;
85 }
86 ~ExecutionRuntimeModesRAII() { ExecMode = SavedExecMode; }
87};
88
89static const ValueDecl *getPrivateItem(const Expr *RefExpr) {
90 RefExpr = RefExpr->IgnoreParens();
91 if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(RefExpr)) {
92 const Expr *Base = ASE->getBase()->IgnoreParenImpCasts();
93 while (const auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
94 Base = TempASE->getBase()->IgnoreParenImpCasts();
95 RefExpr = Base;
96 } else if (auto *OASE = dyn_cast<ArraySectionExpr>(RefExpr)) {
97 const Expr *Base = OASE->getBase()->IgnoreParenImpCasts();
98 while (const auto *TempOASE = dyn_cast<ArraySectionExpr>(Base))
99 Base = TempOASE->getBase()->IgnoreParenImpCasts();
100 while (const auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
101 Base = TempASE->getBase()->IgnoreParenImpCasts();
102 RefExpr = Base;
103 }
104 RefExpr = RefExpr->IgnoreParenImpCasts();
105 if (const auto *DE = dyn_cast<DeclRefExpr>(RefExpr))
106 return cast<ValueDecl>(DE->getDecl()->getCanonicalDecl());
107 const auto *ME = cast<MemberExpr>(RefExpr);
108 return cast<ValueDecl>(ME->getMemberDecl()->getCanonicalDecl());
109}
110
111static RecordDecl *buildRecordForGlobalizedVars(
113 ArrayRef<const ValueDecl *> EscapedDeclsForTeams,
114 llvm::SmallDenseMap<const ValueDecl *, const FieldDecl *>
115 &MappedDeclsFields,
116 int BufSize) {
117 using VarsDataTy = std::pair<CharUnits /*Align*/, const ValueDecl *>;
118 if (EscapedDecls.empty() && EscapedDeclsForTeams.empty())
119 return nullptr;
120 SmallVector<VarsDataTy, 4> GlobalizedVars;
121 for (const ValueDecl *D : EscapedDecls)
122 GlobalizedVars.emplace_back(C.getDeclAlign(D), D);
123 for (const ValueDecl *D : EscapedDeclsForTeams)
124 GlobalizedVars.emplace_back(C.getDeclAlign(D), D);
125
126 // Build struct _globalized_locals_ty {
127 // /* globalized vars */[WarSize] align (decl_align)
128 // /* globalized vars */ for EscapedDeclsForTeams
129 // };
130 RecordDecl *GlobalizedRD = C.buildImplicitRecord("_globalized_locals_ty");
131 GlobalizedRD->startDefinition();
132 llvm::SmallPtrSet<const ValueDecl *, 16> SingleEscaped(llvm::from_range,
133 EscapedDeclsForTeams);
134 for (const auto &Pair : GlobalizedVars) {
135 const ValueDecl *VD = Pair.second;
136 QualType Type = VD->getType();
138 Type = C.getPointerType(Type.getNonReferenceType());
139 else
140 Type = Type.getNonReferenceType();
141 SourceLocation Loc = VD->getLocation();
142 FieldDecl *Field;
143 if (SingleEscaped.count(VD)) {
144 Field = FieldDecl::Create(
145 C, GlobalizedRD, Loc, Loc, VD->getIdentifier(), Type,
146 C.getTrivialTypeSourceInfo(Type, SourceLocation()),
147 /*BW=*/nullptr, /*Mutable=*/false,
148 /*InitStyle=*/ICIS_NoInit);
149 Field->setAccess(AS_public);
150 if (VD->hasAttrs()) {
151 for (specific_attr_iterator<AlignedAttr> I(VD->getAttrs().begin()),
152 E(VD->getAttrs().end());
153 I != E; ++I)
154 Field->addAttr(*I);
155 }
156 } else {
157 if (BufSize > 1) {
158 llvm::APInt ArraySize(32, BufSize);
159 Type = C.getConstantArrayType(Type, ArraySize, nullptr,
161 }
162 Field = FieldDecl::Create(
163 C, GlobalizedRD, Loc, Loc, VD->getIdentifier(), Type,
164 C.getTrivialTypeSourceInfo(Type, SourceLocation()),
165 /*BW=*/nullptr, /*Mutable=*/false,
166 /*InitStyle=*/ICIS_NoInit);
167 Field->setAccess(AS_public);
168 llvm::APInt Align(32, Pair.first.getQuantity());
169 Field->addAttr(AlignedAttr::CreateImplicit(
170 C, /*IsAlignmentExpr=*/true,
172 C.getIntTypeForBitwidth(32, /*Signed=*/0),
174 {}, AlignedAttr::GNU_aligned));
175 }
176 GlobalizedRD->addDecl(Field);
177 MappedDeclsFields.try_emplace(VD, Field);
178 }
179 GlobalizedRD->completeDefinition();
180 return GlobalizedRD;
181}
182
183/// Get the list of variables that can escape their declaration context.
184class CheckVarsEscapingDeclContext final
185 : public ConstStmtVisitor<CheckVarsEscapingDeclContext> {
186 CodeGenFunction &CGF;
187 llvm::SetVector<const ValueDecl *> EscapedDecls;
188 llvm::SetVector<const ValueDecl *> EscapedVariableLengthDecls;
189 llvm::SetVector<const ValueDecl *> DelayedVariableLengthDecls;
190 llvm::SmallPtrSet<const Decl *, 4> EscapedParameters;
191 RecordDecl *GlobalizedRD = nullptr;
192 llvm::SmallDenseMap<const ValueDecl *, const FieldDecl *> MappedDeclsFields;
193 bool AllEscaped = false;
194 bool IsForCombinedParallelRegion = false;
195
196 void markAsEscaped(const ValueDecl *VD) {
197 // Do not globalize declare target variables.
198 if (!isa<VarDecl>(VD) ||
199 OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD))
200 return;
202 // Use user-specified allocation.
203 if (VD->hasAttrs() && VD->hasAttr<OMPAllocateDeclAttr>())
204 return;
205 // Variables captured by value must be globalized.
206 bool IsCaptured = false;
207 if (auto *CSI = CGF.CapturedStmtInfo) {
208 if (const FieldDecl *FD = CSI->lookup(cast<VarDecl>(VD))) {
209 // Check if need to capture the variable that was already captured by
210 // value in the outer region.
211 IsCaptured = true;
212 if (!IsForCombinedParallelRegion) {
213 if (!FD->hasAttrs())
214 return;
215 const auto *Attr = FD->getAttr<OMPCaptureKindAttr>();
216 if (!Attr)
217 return;
218 if (((Attr->getCaptureKind() != OMPC_map) &&
219 !isOpenMPPrivate(Attr->getCaptureKind())) ||
220 ((Attr->getCaptureKind() == OMPC_map) &&
221 !FD->getType()->isAnyPointerType()))
222 return;
223 }
224 if (!FD->getType()->isReferenceType()) {
225 assert(!VD->getType()->isVariablyModifiedType() &&
226 "Parameter captured by value with variably modified type");
227 EscapedParameters.insert(VD);
228 } else if (!IsForCombinedParallelRegion) {
229 return;
230 }
231 }
232 }
233 if ((!CGF.CapturedStmtInfo ||
234 (IsForCombinedParallelRegion && CGF.CapturedStmtInfo)) &&
235 VD->getType()->isReferenceType())
236 // Do not globalize variables with reference type.
237 return;
238 if (VD->getType()->isVariablyModifiedType()) {
239 // If not captured at the target region level then mark the escaped
240 // variable as delayed.
241 if (IsCaptured)
242 EscapedVariableLengthDecls.insert(VD);
243 else
244 DelayedVariableLengthDecls.insert(VD);
245 } else
246 EscapedDecls.insert(VD);
247 }
248
249 void VisitValueDecl(const ValueDecl *VD) {
250 if (VD->getType()->isLValueReferenceType())
251 markAsEscaped(VD);
252 if (const auto *VarD = dyn_cast<VarDecl>(VD)) {
253 if (!isa<ParmVarDecl>(VarD) && VarD->hasInit()) {
254 const bool SavedAllEscaped = AllEscaped;
255 AllEscaped = VD->getType()->isLValueReferenceType();
256 Visit(VarD->getInit());
257 AllEscaped = SavedAllEscaped;
258 }
259 }
260 }
261 void VisitOpenMPCapturedStmt(const CapturedStmt *S,
262 ArrayRef<OMPClause *> Clauses,
263 bool IsCombinedParallelRegion) {
264 if (!S)
265 return;
266 for (const CapturedStmt::Capture &C : S->captures()) {
267 if (C.capturesVariable() && !C.capturesVariableByCopy()) {
268 const ValueDecl *VD = C.getCapturedVar();
269 bool SavedIsForCombinedParallelRegion = IsForCombinedParallelRegion;
270 if (IsCombinedParallelRegion) {
271 // Check if the variable is privatized in the combined construct and
272 // those private copies must be shared in the inner parallel
273 // directive.
274 IsForCombinedParallelRegion = false;
275 for (const OMPClause *C : Clauses) {
276 if (!isOpenMPPrivate(C->getClauseKind()) ||
277 C->getClauseKind() == OMPC_reduction ||
278 C->getClauseKind() == OMPC_linear ||
279 C->getClauseKind() == OMPC_private)
280 continue;
281 ArrayRef<const Expr *> Vars;
282 if (const auto *PC = dyn_cast<OMPFirstprivateClause>(C))
283 Vars = PC->getVarRefs();
284 else if (const auto *PC = dyn_cast<OMPLastprivateClause>(C))
285 Vars = PC->getVarRefs();
286 else
287 llvm_unreachable("Unexpected clause.");
288 for (const auto *E : Vars) {
289 const Decl *D =
290 cast<DeclRefExpr>(E)->getDecl()->getCanonicalDecl();
291 if (D == VD->getCanonicalDecl()) {
292 IsForCombinedParallelRegion = true;
293 break;
294 }
295 }
296 if (IsForCombinedParallelRegion)
297 break;
298 }
299 }
300 markAsEscaped(VD);
302 VisitValueDecl(VD);
303 IsForCombinedParallelRegion = SavedIsForCombinedParallelRegion;
304 }
305 }
306 }
307
308 void buildRecordForGlobalizedVars(bool IsInTTDRegion) {
309 assert(!GlobalizedRD &&
310 "Record for globalized variables is built already.");
311 ArrayRef<const ValueDecl *> EscapedDeclsForParallel, EscapedDeclsForTeams;
312 unsigned WarpSize = CGF.getTarget().getGridValue().GV_Warp_Size;
313 if (IsInTTDRegion)
314 EscapedDeclsForTeams = EscapedDecls.getArrayRef();
315 else
316 EscapedDeclsForParallel = EscapedDecls.getArrayRef();
317 GlobalizedRD = ::buildRecordForGlobalizedVars(
318 CGF.getContext(), EscapedDeclsForParallel, EscapedDeclsForTeams,
319 MappedDeclsFields, WarpSize);
320 }
321
322public:
323 CheckVarsEscapingDeclContext(CodeGenFunction &CGF,
324 ArrayRef<const ValueDecl *> TeamsReductions)
325 : CGF(CGF), EscapedDecls(llvm::from_range, TeamsReductions) {}
326 ~CheckVarsEscapingDeclContext() = default;
327 void VisitDeclStmt(const DeclStmt *S) {
328 if (!S)
329 return;
330 for (const Decl *D : S->decls())
331 if (const auto *VD = dyn_cast_or_null<ValueDecl>(D))
332 VisitValueDecl(VD);
333 }
334 void VisitOMPExecutableDirective(const OMPExecutableDirective *D) {
335 if (!D)
336 return;
337 if (!D->hasAssociatedStmt())
338 return;
339 if (const auto *S =
340 dyn_cast_or_null<CapturedStmt>(D->getAssociatedStmt())) {
341 // Do not analyze directives that do not actually require capturing,
342 // like `omp for` or `omp simd` directives.
343 llvm::SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
344 getOpenMPCaptureRegions(CaptureRegions, D->getDirectiveKind());
345 if (CaptureRegions.size() == 1 && CaptureRegions.back() == OMPD_unknown) {
346 VisitStmt(S->getCapturedStmt());
347 return;
348 }
349 VisitOpenMPCapturedStmt(
350 S, D->clauses(),
351 CaptureRegions.back() == OMPD_parallel &&
352 isOpenMPDistributeDirective(D->getDirectiveKind()));
353 }
354 }
355 void VisitCapturedStmt(const CapturedStmt *S) {
356 if (!S)
357 return;
358 for (const CapturedStmt::Capture &C : S->captures()) {
359 if (C.capturesVariable() && !C.capturesVariableByCopy()) {
360 const ValueDecl *VD = C.getCapturedVar();
361 markAsEscaped(VD);
363 VisitValueDecl(VD);
364 }
365 }
366 }
367 void VisitLambdaExpr(const LambdaExpr *E) {
368 if (!E)
369 return;
370 for (const LambdaCapture &C : E->captures()) {
371 if (C.capturesVariable()) {
372 if (C.getCaptureKind() == LCK_ByRef) {
373 const ValueDecl *VD = C.getCapturedVar();
374 markAsEscaped(VD);
376 VisitValueDecl(VD);
377 }
378 }
379 }
380 }
381 void VisitBlockExpr(const BlockExpr *E) {
382 if (!E)
383 return;
384 for (const BlockDecl::Capture &C : E->getBlockDecl()->captures()) {
385 if (C.isByRef()) {
386 const VarDecl *VD = C.getVariable();
387 markAsEscaped(VD);
389 VisitValueDecl(VD);
390 }
391 }
392 }
393 void VisitCallExpr(const CallExpr *E) {
394 if (!E)
395 return;
396 for (const Expr *Arg : E->arguments()) {
397 if (!Arg)
398 continue;
399 if (Arg->isLValue()) {
400 const bool SavedAllEscaped = AllEscaped;
401 AllEscaped = true;
402 Visit(Arg);
403 AllEscaped = SavedAllEscaped;
404 } else {
405 Visit(Arg);
406 }
407 }
408 Visit(E->getCallee());
409 }
410 void VisitDeclRefExpr(const DeclRefExpr *E) {
411 if (!E)
412 return;
413 const ValueDecl *VD = E->getDecl();
414 if (AllEscaped)
415 markAsEscaped(VD);
417 VisitValueDecl(VD);
418 else if (VD->isInitCapture())
419 VisitValueDecl(VD);
420 }
421 void VisitUnaryOperator(const UnaryOperator *E) {
422 if (!E)
423 return;
424 if (E->getOpcode() == UO_AddrOf) {
425 const bool SavedAllEscaped = AllEscaped;
426 AllEscaped = true;
427 Visit(E->getSubExpr());
428 AllEscaped = SavedAllEscaped;
429 } else {
430 Visit(E->getSubExpr());
431 }
432 }
433 void VisitImplicitCastExpr(const ImplicitCastExpr *E) {
434 if (!E)
435 return;
436 if (E->getCastKind() == CK_ArrayToPointerDecay) {
437 const bool SavedAllEscaped = AllEscaped;
438 AllEscaped = true;
439 Visit(E->getSubExpr());
440 AllEscaped = SavedAllEscaped;
441 } else {
442 Visit(E->getSubExpr());
443 }
444 }
445 void VisitExpr(const Expr *E) {
446 if (!E)
447 return;
448 bool SavedAllEscaped = AllEscaped;
449 if (!E->isLValue())
450 AllEscaped = false;
451 for (const Stmt *Child : E->children())
452 if (Child)
453 Visit(Child);
454 AllEscaped = SavedAllEscaped;
455 }
456 void VisitStmt(const Stmt *S) {
457 if (!S)
458 return;
459 for (const Stmt *Child : S->children())
460 if (Child)
461 Visit(Child);
462 }
463
464 /// Returns the record that handles all the escaped local variables and used
465 /// instead of their original storage.
466 const RecordDecl *getGlobalizedRecord(bool IsInTTDRegion) {
467 if (!GlobalizedRD)
468 buildRecordForGlobalizedVars(IsInTTDRegion);
469 return GlobalizedRD;
470 }
471
472 /// Returns the field in the globalized record for the escaped variable.
473 const FieldDecl *getFieldForGlobalizedVar(const ValueDecl *VD) const {
474 assert(GlobalizedRD &&
475 "Record for globalized variables must be generated already.");
476 return MappedDeclsFields.lookup(VD);
477 }
478
479 /// Returns the list of the escaped local variables/parameters.
480 ArrayRef<const ValueDecl *> getEscapedDecls() const {
481 return EscapedDecls.getArrayRef();
482 }
483
484 /// Checks if the escaped local variable is actually a parameter passed by
485 /// value.
486 const llvm::SmallPtrSetImpl<const Decl *> &getEscapedParameters() const {
487 return EscapedParameters;
488 }
489
490 /// Returns the list of the escaped variables with the variably modified
491 /// types.
492 ArrayRef<const ValueDecl *> getEscapedVariableLengthDecls() const {
493 return EscapedVariableLengthDecls.getArrayRef();
494 }
495
496 /// Returns the list of the delayed variables with the variably modified
497 /// types.
498 ArrayRef<const ValueDecl *> getDelayedVariableLengthDecls() const {
499 return DelayedVariableLengthDecls.getArrayRef();
500 }
501};
502} // anonymous namespace
503
505CGOpenMPRuntimeGPU::getExecutionMode() const {
506 return CurrentExecutionMode;
507}
508
510CGOpenMPRuntimeGPU::getDataSharingMode() const {
511 return CurrentDataSharingMode;
512}
513
514/// Check for inner (nested) SPMD construct, if any
516 const OMPExecutableDirective &D) {
517 const auto *CS = D.getInnermostCapturedStmt();
518 const auto *Body =
519 CS->getCapturedStmt()->IgnoreContainers(/*IgnoreCaptured=*/true);
520 const Stmt *ChildStmt = CGOpenMPRuntime::getSingleCompoundChild(Ctx, Body);
521
522 if (const auto *NestedDir =
523 dyn_cast_or_null<OMPExecutableDirective>(ChildStmt)) {
524 OpenMPDirectiveKind DKind = NestedDir->getDirectiveKind();
525 switch (D.getDirectiveKind()) {
526 case OMPD_target:
527 if (isOpenMPParallelDirective(DKind))
528 return true;
529 if (DKind == OMPD_teams) {
530 Body = NestedDir->getInnermostCapturedStmt()->IgnoreContainers(
531 /*IgnoreCaptured=*/true);
532 if (!Body)
533 return false;
534 ChildStmt = CGOpenMPRuntime::getSingleCompoundChild(Ctx, Body);
535 if (const auto *NND =
536 dyn_cast_or_null<OMPExecutableDirective>(ChildStmt)) {
537 DKind = NND->getDirectiveKind();
538 if (isOpenMPParallelDirective(DKind))
539 return true;
540 }
541 }
542 return false;
543 case OMPD_target_teams:
544 return isOpenMPParallelDirective(DKind);
545 case OMPD_target_simd:
546 case OMPD_target_parallel:
547 case OMPD_target_parallel_for:
548 case OMPD_target_parallel_for_simd:
549 case OMPD_target_teams_distribute:
550 case OMPD_target_teams_distribute_simd:
551 case OMPD_target_teams_distribute_parallel_for:
552 case OMPD_target_teams_distribute_parallel_for_simd:
553 case OMPD_parallel:
554 case OMPD_for:
555 case OMPD_parallel_for:
556 case OMPD_parallel_master:
557 case OMPD_parallel_sections:
558 case OMPD_for_simd:
559 case OMPD_parallel_for_simd:
560 case OMPD_cancel:
561 case OMPD_cancellation_point:
562 case OMPD_ordered:
563 case OMPD_threadprivate:
564 case OMPD_allocate:
565 case OMPD_task:
566 case OMPD_simd:
567 case OMPD_sections:
568 case OMPD_section:
569 case OMPD_single:
570 case OMPD_master:
571 case OMPD_critical:
572 case OMPD_taskyield:
573 case OMPD_barrier:
574 case OMPD_taskwait:
575 case OMPD_taskgroup:
576 case OMPD_atomic:
577 case OMPD_flush:
578 case OMPD_depobj:
579 case OMPD_scan:
580 case OMPD_teams:
581 case OMPD_target_data:
582 case OMPD_target_exit_data:
583 case OMPD_target_enter_data:
584 case OMPD_distribute:
585 case OMPD_distribute_simd:
586 case OMPD_distribute_parallel_for:
587 case OMPD_distribute_parallel_for_simd:
588 case OMPD_teams_distribute:
589 case OMPD_teams_distribute_simd:
590 case OMPD_teams_distribute_parallel_for:
591 case OMPD_teams_distribute_parallel_for_simd:
592 case OMPD_target_update:
593 case OMPD_declare_simd:
594 case OMPD_declare_variant:
595 case OMPD_begin_declare_variant:
596 case OMPD_end_declare_variant:
597 case OMPD_declare_target:
598 case OMPD_end_declare_target:
599 case OMPD_declare_reduction:
600 case OMPD_declare_mapper:
601 case OMPD_taskloop:
602 case OMPD_taskloop_simd:
603 case OMPD_master_taskloop:
604 case OMPD_master_taskloop_simd:
605 case OMPD_parallel_master_taskloop:
606 case OMPD_parallel_master_taskloop_simd:
607 case OMPD_requires:
608 case OMPD_unknown:
609 default:
610 llvm_unreachable("Unexpected directive.");
611 }
612 }
613
614 return false;
615}
616
618 const OMPExecutableDirective &D) {
619 OpenMPDirectiveKind DirectiveKind = D.getDirectiveKind();
620 switch (DirectiveKind) {
621 case OMPD_target:
622 case OMPD_target_teams:
623 return hasNestedSPMDDirective(Ctx, D);
624 case OMPD_target_parallel_loop:
625 case OMPD_target_parallel:
626 case OMPD_target_parallel_for:
627 case OMPD_target_parallel_for_simd:
628 case OMPD_target_teams_distribute_parallel_for:
629 case OMPD_target_teams_distribute_parallel_for_simd:
630 case OMPD_target_simd:
631 case OMPD_target_teams_distribute_simd:
632 return true;
633 case OMPD_target_teams_distribute:
634 return false;
635 case OMPD_target_teams_loop:
636 // Whether this is true or not depends on how the directive will
637 // eventually be emitted.
638 if (auto *TTLD = dyn_cast<OMPTargetTeamsGenericLoopDirective>(&D))
639 return TTLD->canBeParallelFor();
640 return false;
641 case OMPD_parallel:
642 case OMPD_for:
643 case OMPD_parallel_for:
644 case OMPD_parallel_master:
645 case OMPD_parallel_sections:
646 case OMPD_for_simd:
647 case OMPD_parallel_for_simd:
648 case OMPD_cancel:
649 case OMPD_cancellation_point:
650 case OMPD_ordered:
651 case OMPD_threadprivate:
652 case OMPD_allocate:
653 case OMPD_task:
654 case OMPD_simd:
655 case OMPD_sections:
656 case OMPD_section:
657 case OMPD_single:
658 case OMPD_master:
659 case OMPD_critical:
660 case OMPD_taskyield:
661 case OMPD_barrier:
662 case OMPD_taskwait:
663 case OMPD_taskgroup:
664 case OMPD_atomic:
665 case OMPD_flush:
666 case OMPD_depobj:
667 case OMPD_scan:
668 case OMPD_teams:
669 case OMPD_target_data:
670 case OMPD_target_exit_data:
671 case OMPD_target_enter_data:
672 case OMPD_distribute:
673 case OMPD_distribute_simd:
674 case OMPD_distribute_parallel_for:
675 case OMPD_distribute_parallel_for_simd:
676 case OMPD_teams_distribute:
677 case OMPD_teams_distribute_simd:
678 case OMPD_teams_distribute_parallel_for:
679 case OMPD_teams_distribute_parallel_for_simd:
680 case OMPD_target_update:
681 case OMPD_declare_simd:
682 case OMPD_declare_variant:
683 case OMPD_begin_declare_variant:
684 case OMPD_end_declare_variant:
685 case OMPD_declare_target:
686 case OMPD_end_declare_target:
687 case OMPD_declare_reduction:
688 case OMPD_declare_mapper:
689 case OMPD_taskloop:
690 case OMPD_taskloop_simd:
691 case OMPD_master_taskloop:
692 case OMPD_master_taskloop_simd:
693 case OMPD_parallel_master_taskloop:
694 case OMPD_parallel_master_taskloop_simd:
695 case OMPD_requires:
696 case OMPD_unknown:
697 default:
698 break;
699 }
700 llvm_unreachable(
701 "Unknown programming model for OpenMP directive on NVPTX target.");
702}
703
704void CGOpenMPRuntimeGPU::emitNonSPMDKernel(const OMPExecutableDirective &D,
705 StringRef ParentName,
706 llvm::Function *&OutlinedFn,
707 llvm::Constant *&OutlinedFnID,
708 bool IsOffloadEntry,
709 const RegionCodeGenTy &CodeGen) {
710 ExecutionRuntimeModesRAII ModeRAII(CurrentExecutionMode, EM_NonSPMD);
711 EntryFunctionState EST;
712 WrapperFunctionsMap.clear();
713
714 [[maybe_unused]] bool IsBareKernel = D.getSingleClause<OMPXBareClause>();
715 assert(!IsBareKernel && "bare kernel should not be at generic mode");
716
717 // Emit target region as a standalone region.
718 class NVPTXPrePostActionTy : public PrePostActionTy {
719 CGOpenMPRuntimeGPU::EntryFunctionState &EST;
720 const OMPExecutableDirective &D;
721
722 public:
723 NVPTXPrePostActionTy(CGOpenMPRuntimeGPU::EntryFunctionState &EST,
724 const OMPExecutableDirective &D)
725 : EST(EST), D(D) {}
726 void Enter(CodeGenFunction &CGF) override {
727 auto &RT = static_cast<CGOpenMPRuntimeGPU &>(CGF.CGM.getOpenMPRuntime());
728 RT.emitKernelInit(D, CGF, EST, /* IsSPMD */ false);
729 // Skip target region initialization.
730 RT.setLocThreadIdInsertPt(CGF, /*AtCurrentPoint=*/true);
731 }
732 void Exit(CodeGenFunction &CGF) override {
733 auto &RT = static_cast<CGOpenMPRuntimeGPU &>(CGF.CGM.getOpenMPRuntime());
734 RT.clearLocThreadIdInsertPt(CGF);
735 RT.emitKernelDeinit(CGF, EST, /* IsSPMD */ false);
736 }
737 } Action(EST, D);
738 CodeGen.setAction(Action);
739 IsInTTDRegion = true;
740 emitTargetOutlinedFunctionHelper(D, ParentName, OutlinedFn, OutlinedFnID,
741 IsOffloadEntry, CodeGen);
742 IsInTTDRegion = false;
743}
744
745void CGOpenMPRuntimeGPU::emitKernelInit(const OMPExecutableDirective &D,
746 CodeGenFunction &CGF,
747 EntryFunctionState &EST, bool IsSPMD) {
748 llvm::OpenMPIRBuilder::TargetKernelDefaultAttrs Attrs;
749 Attrs.ExecFlags =
750 IsSPMD ? llvm::omp::OMPTgtExecModeFlags::OMP_TGT_EXEC_MODE_SPMD
751 : llvm::omp::OMPTgtExecModeFlags::OMP_TGT_EXEC_MODE_GENERIC;
752 computeMinAndMaxThreadsAndTeams(D, CGF, Attrs);
753
754 CGBuilderTy &Bld = CGF.Builder;
755 Bld.restoreIP(OMPBuilder.createTargetInit(Bld, Attrs));
756 if (!IsSPMD)
757 emitGenericVarsProlog(CGF, EST.Loc);
758}
759
760void CGOpenMPRuntimeGPU::emitKernelDeinit(CodeGenFunction &CGF,
761 EntryFunctionState &EST,
762 bool IsSPMD) {
763 if (!IsSPMD)
764 emitGenericVarsEpilog(CGF);
765
766 // This is temporary until we remove the fixed sized buffer.
767 ASTContext &C = CGM.getContext();
768 RecordDecl *StaticRD = C.buildImplicitRecord(
769 "_openmp_teams_reduction_type_$_", RecordDecl::TagKind::Union);
770 StaticRD->startDefinition();
771 for (const RecordDecl *TeamReductionRec : TeamsReductions) {
772 CanQualType RecTy = C.getCanonicalTagType(TeamReductionRec);
773 auto *Field = FieldDecl::Create(
774 C, StaticRD, SourceLocation(), SourceLocation(), nullptr, RecTy,
775 C.getTrivialTypeSourceInfo(RecTy, SourceLocation()),
776 /*BW=*/nullptr, /*Mutable=*/false,
777 /*InitStyle=*/ICIS_NoInit);
778 Field->setAccess(AS_public);
779 StaticRD->addDecl(Field);
780 }
781 StaticRD->completeDefinition();
782 CanQualType StaticTy = C.getCanonicalTagType(StaticRD);
783 llvm::Type *LLVMReductionsBufferTy =
784 CGM.getTypes().ConvertTypeForMem(StaticTy);
785 const auto &DL = CGM.getModule().getDataLayout();
786 uint64_t ReductionDataSize =
787 TeamsReductions.empty()
788 ? 0
789 : DL.getTypeAllocSize(LLVMReductionsBufferTy).getFixedValue();
790 CGBuilderTy &Bld = CGF.Builder;
791 OMPBuilder.createTargetDeinit(Bld, ReductionDataSize);
792 TeamsReductions.clear();
793}
794
795void CGOpenMPRuntimeGPU::emitSPMDKernel(const OMPExecutableDirective &D,
796 StringRef ParentName,
797 llvm::Function *&OutlinedFn,
798 llvm::Constant *&OutlinedFnID,
799 bool IsOffloadEntry,
800 const RegionCodeGenTy &CodeGen) {
801 ExecutionRuntimeModesRAII ModeRAII(CurrentExecutionMode, EM_SPMD);
802 EntryFunctionState EST;
803
804 bool IsBareKernel = D.getSingleClause<OMPXBareClause>();
805
806 // Emit target region as a standalone region.
807 class NVPTXPrePostActionTy : public PrePostActionTy {
808 CGOpenMPRuntimeGPU &RT;
809 CGOpenMPRuntimeGPU::EntryFunctionState &EST;
810 bool IsBareKernel;
811 DataSharingMode Mode;
812 const OMPExecutableDirective &D;
813
814 public:
815 NVPTXPrePostActionTy(CGOpenMPRuntimeGPU &RT,
816 CGOpenMPRuntimeGPU::EntryFunctionState &EST,
817 bool IsBareKernel, const OMPExecutableDirective &D)
818 : RT(RT), EST(EST), IsBareKernel(IsBareKernel),
819 Mode(RT.CurrentDataSharingMode), D(D) {}
820 void Enter(CodeGenFunction &CGF) override {
821 if (IsBareKernel) {
822 RT.CurrentDataSharingMode = DataSharingMode::DS_CUDA;
823 return;
824 }
825 RT.emitKernelInit(D, CGF, EST, /* IsSPMD */ true);
826 // Skip target region initialization.
827 RT.setLocThreadIdInsertPt(CGF, /*AtCurrentPoint=*/true);
828 }
829 void Exit(CodeGenFunction &CGF) override {
830 if (IsBareKernel) {
831 RT.CurrentDataSharingMode = Mode;
832 return;
833 }
834 RT.clearLocThreadIdInsertPt(CGF);
835 RT.emitKernelDeinit(CGF, EST, /* IsSPMD */ true);
836 }
837 } Action(*this, EST, IsBareKernel, D);
838 CodeGen.setAction(Action);
839 IsInTTDRegion = true;
840 emitTargetOutlinedFunctionHelper(D, ParentName, OutlinedFn, OutlinedFnID,
841 IsOffloadEntry, CodeGen);
842 IsInTTDRegion = false;
843}
844
845void CGOpenMPRuntimeGPU::emitTargetOutlinedFunction(
846 const OMPExecutableDirective &D, StringRef ParentName,
847 llvm::Function *&OutlinedFn, llvm::Constant *&OutlinedFnID,
848 bool IsOffloadEntry, const RegionCodeGenTy &CodeGen) {
849 if (!IsOffloadEntry) // Nothing to do.
850 return;
851
852 assert(!ParentName.empty() && "Invalid target region parent name!");
853
854 bool Mode = supportsSPMDExecutionMode(CGM.getContext(), D);
855 bool IsBareKernel = D.getSingleClause<OMPXBareClause>();
856 if (Mode || IsBareKernel)
857 emitSPMDKernel(D, ParentName, OutlinedFn, OutlinedFnID, IsOffloadEntry,
858 CodeGen);
859 else
860 emitNonSPMDKernel(D, ParentName, OutlinedFn, OutlinedFnID, IsOffloadEntry,
861 CodeGen);
862}
863
866 llvm::OpenMPIRBuilderConfig Config(
867 CGM.getLangOpts().OpenMPIsTargetDevice, isGPU(),
868 CGM.getLangOpts().OpenMPOffloadMandatory,
869 /*HasRequiresReverseOffload*/ false, /*HasRequiresUnifiedAddress*/ false,
870 hasRequiresUnifiedSharedMemory(), /*HasRequiresDynamicAllocators*/ false);
871 Config.setDefaultTargetAS(
872 CGM.getContext().getTargetInfo().getTargetAddressSpace(LangAS::Default));
873 Config.setRuntimeCC(CGM.getRuntimeCC());
874
875 OMPBuilder.setConfig(Config);
876
877 if (!CGM.getLangOpts().OpenMPIsTargetDevice)
878 llvm_unreachable("OpenMP can only handle device code.");
879
880 if (CGM.getLangOpts().OpenMPCUDAMode)
881 CurrentDataSharingMode = CGOpenMPRuntimeGPU::DS_CUDA;
882
883 llvm::OpenMPIRBuilder &OMPBuilder = getOMPBuilder();
884 if (CGM.getLangOpts().NoGPULib || CGM.getLangOpts().OMPHostIRFile.empty())
885 return;
886
887 OMPBuilder.createGlobalFlag(CGM.getLangOpts().OpenMPTargetDebug,
888 "__omp_rtl_debug_kind");
889 OMPBuilder.createGlobalFlag(CGM.getLangOpts().OpenMPTeamSubscription,
890 "__omp_rtl_assume_teams_oversubscription");
891 OMPBuilder.createGlobalFlag(CGM.getLangOpts().OpenMPThreadSubscription,
892 "__omp_rtl_assume_threads_oversubscription");
893 OMPBuilder.createGlobalFlag(CGM.getLangOpts().OpenMPNoThreadState,
894 "__omp_rtl_assume_no_thread_state");
895 OMPBuilder.createGlobalFlag(CGM.getLangOpts().OpenMPNoNestedParallelism,
896 "__omp_rtl_assume_no_nested_parallelism");
897}
898
900 ProcBindKind ProcBind,
901 SourceLocation Loc) {
902 // Nothing to do.
903}
904
906 const Expr *Message,
907 SourceLocation Loc) {
908 CGM.getDiags().Report(Loc, diag::warn_omp_gpu_unsupported_clause)
909 << getOpenMPClauseName(OMPC_message);
910 return nullptr;
911}
912
913llvm::Value *
915 SourceLocation Loc) {
916 CGM.getDiags().Report(Loc, diag::warn_omp_gpu_unsupported_clause)
917 << getOpenMPClauseName(OMPC_severity);
918 return nullptr;
919}
920
922 CodeGenFunction &CGF, llvm::Value *NumThreads, SourceLocation Loc,
924 SourceLocation SeverityLoc, const Expr *Message,
925 SourceLocation MessageLoc) {
926 if (Modifier == OMPC_NUMTHREADS_strict) {
927 CGM.getDiags().Report(Loc,
928 diag::warn_omp_gpu_unsupported_modifier_for_clause)
929 << "strict" << getOpenMPClauseName(OMPC_num_threads);
930 return;
931 }
932
933 // Nothing to do.
934}
935
937 const Expr *NumTeams,
938 const Expr *ThreadLimit,
939 SourceLocation Loc) {}
940
943 const VarDecl *ThreadIDVar, OpenMPDirectiveKind InnermostKind,
944 const RegionCodeGenTy &CodeGen) {
945 // Emit target region as a standalone region.
946 bool PrevIsInTTDRegion = IsInTTDRegion;
947 IsInTTDRegion = false;
948 auto *OutlinedFun =
950 CGF, D, ThreadIDVar, InnermostKind, CodeGen));
951 IsInTTDRegion = PrevIsInTTDRegion;
952 if (getExecutionMode() != CGOpenMPRuntimeGPU::EM_SPMD) {
953 llvm::Function *WrapperFun =
954 createParallelDataSharingWrapper(OutlinedFun, D);
955 WrapperFunctionsMap[OutlinedFun] = WrapperFun;
956 }
957
958 return OutlinedFun;
959}
960
961/// Get list of lastprivate variables from the teams distribute ... or
962/// teams {distribute ...} directives.
963static void
966 assert(isOpenMPTeamsDirective(D.getDirectiveKind()) &&
967 "expected teams directive.");
968 const OMPExecutableDirective *Dir = &D;
969 if (!isOpenMPDistributeDirective(D.getDirectiveKind())) {
971 Ctx,
972 D.getInnermostCapturedStmt()->getCapturedStmt()->IgnoreContainers(
973 /*IgnoreCaptured=*/true))) {
974 Dir = dyn_cast_or_null<OMPExecutableDirective>(S);
975 if (Dir && !isOpenMPDistributeDirective(Dir->getDirectiveKind()))
976 Dir = nullptr;
977 }
978 }
979 if (!Dir)
980 return;
981 for (const auto *C : Dir->getClausesOfKind<OMPLastprivateClause>()) {
982 for (const Expr *E : C->getVarRefs())
983 Vars.push_back(getPrivateItem(E));
984 }
985}
986
987/// Get list of reduction variables from the teams ... directives.
988static void
991 assert(isOpenMPTeamsDirective(D.getDirectiveKind()) &&
992 "expected teams directive.");
993 for (const auto *C : D.getClausesOfKind<OMPReductionClause>()) {
994 for (const Expr *E : C->privates())
995 Vars.push_back(getPrivateItem(E));
996 }
997}
998
1001 const VarDecl *ThreadIDVar, OpenMPDirectiveKind InnermostKind,
1002 const RegionCodeGenTy &CodeGen) {
1003 SourceLocation Loc = D.getBeginLoc();
1004
1005 const RecordDecl *GlobalizedRD = nullptr;
1006 llvm::SmallVector<const ValueDecl *, 4> LastPrivatesReductions;
1007 llvm::SmallDenseMap<const ValueDecl *, const FieldDecl *> MappedDeclsFields;
1008 unsigned WarpSize = CGM.getTarget().getGridValue().GV_Warp_Size;
1009 // Globalize team reductions variable unconditionally in all modes.
1010 if (getExecutionMode() != CGOpenMPRuntimeGPU::EM_SPMD)
1011 getTeamsReductionVars(CGM.getContext(), D, LastPrivatesReductions);
1012 if (getExecutionMode() == CGOpenMPRuntimeGPU::EM_SPMD) {
1013 getDistributeLastprivateVars(CGM.getContext(), D, LastPrivatesReductions);
1014 if (!LastPrivatesReductions.empty()) {
1015 GlobalizedRD = ::buildRecordForGlobalizedVars(
1016 CGM.getContext(), {}, LastPrivatesReductions, MappedDeclsFields,
1017 WarpSize);
1018 }
1019 } else if (!LastPrivatesReductions.empty()) {
1020 assert(!TeamAndReductions.first &&
1021 "Previous team declaration is not expected.");
1022 TeamAndReductions.first = D.getCapturedStmt(OMPD_teams)->getCapturedDecl();
1023 std::swap(TeamAndReductions.second, LastPrivatesReductions);
1024 }
1025
1026 // Emit target region as a standalone region.
1027 class NVPTXPrePostActionTy : public PrePostActionTy {
1028 SourceLocation &Loc;
1029 const RecordDecl *GlobalizedRD;
1030 llvm::SmallDenseMap<const ValueDecl *, const FieldDecl *>
1031 &MappedDeclsFields;
1032
1033 public:
1034 NVPTXPrePostActionTy(
1035 SourceLocation &Loc, const RecordDecl *GlobalizedRD,
1036 llvm::SmallDenseMap<const ValueDecl *, const FieldDecl *>
1037 &MappedDeclsFields)
1038 : Loc(Loc), GlobalizedRD(GlobalizedRD),
1039 MappedDeclsFields(MappedDeclsFields) {}
1040 void Enter(CodeGenFunction &CGF) override {
1041 auto &Rt =
1042 static_cast<CGOpenMPRuntimeGPU &>(CGF.CGM.getOpenMPRuntime());
1043 if (GlobalizedRD) {
1044 auto I = Rt.FunctionGlobalizedDecls.try_emplace(CGF.CurFn).first;
1045 I->getSecond().MappedParams =
1046 std::make_unique<CodeGenFunction::OMPMapVars>();
1047 DeclToAddrMapTy &Data = I->getSecond().LocalVarData;
1048 for (const auto &Pair : MappedDeclsFields) {
1049 assert(Pair.getFirst()->isCanonicalDecl() &&
1050 "Expected canonical declaration");
1051 Data.try_emplace(Pair.getFirst());
1052 }
1053 }
1054 Rt.emitGenericVarsProlog(CGF, Loc);
1055 }
1056 void Exit(CodeGenFunction &CGF) override {
1057 static_cast<CGOpenMPRuntimeGPU &>(CGF.CGM.getOpenMPRuntime())
1058 .emitGenericVarsEpilog(CGF);
1059 }
1060 } Action(Loc, GlobalizedRD, MappedDeclsFields);
1061 CodeGen.setAction(Action);
1062 llvm::Function *OutlinedFun = CGOpenMPRuntime::emitTeamsOutlinedFunction(
1063 CGF, D, ThreadIDVar, InnermostKind, CodeGen);
1064
1065 return OutlinedFun;
1066}
1067
1068void CGOpenMPRuntimeGPU::emitGenericVarsProlog(CodeGenFunction &CGF,
1069 SourceLocation Loc) {
1070 if (getDataSharingMode() != CGOpenMPRuntimeGPU::DS_Generic)
1071 return;
1072
1073 CGBuilderTy &Bld = CGF.Builder;
1074
1075 const auto I = FunctionGlobalizedDecls.find(CGF.CurFn);
1076 if (I == FunctionGlobalizedDecls.end())
1077 return;
1078
1079 for (auto &Rec : I->getSecond().LocalVarData) {
1080 const auto *VD = cast<VarDecl>(Rec.first);
1081 bool EscapedParam = I->getSecond().EscapedParameters.count(Rec.first);
1082 QualType VarTy = VD->getType();
1083
1084 // Get the local allocation of a firstprivate variable before sharing
1085 llvm::Value *ParValue;
1086 if (EscapedParam) {
1087 LValue ParLVal =
1088 CGF.MakeAddrLValue(CGF.GetAddrOfLocalVar(VD), VD->getType());
1089 ParValue = CGF.EmitLoadOfScalar(ParLVal, Loc);
1090 }
1091
1092 // Allocate space for the variable to be globalized
1093 llvm::Value *AllocArgs[] = {CGF.getTypeSize(VD->getType())};
1094 llvm::CallBase *VoidPtr =
1095 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
1096 CGM.getModule(), OMPRTL___kmpc_alloc_shared),
1097 AllocArgs, VD->getName());
1098 // FIXME: We should use the variables actual alignment as an argument.
1099 VoidPtr->addRetAttr(llvm::Attribute::get(
1100 CGM.getLLVMContext(), llvm::Attribute::Alignment,
1102
1103 // Cast the void pointer and get the address of the globalized variable.
1104 llvm::Value *CastedVoidPtr = Bld.CreatePointerBitCastOrAddrSpaceCast(
1105 VoidPtr, Bld.getPtrTy(0), VD->getName() + "_on_stack");
1106 LValue VarAddr =
1107 CGF.MakeNaturalAlignPointeeRawAddrLValue(CastedVoidPtr, VarTy);
1108 Rec.second.PrivateAddr = VarAddr.getAddress();
1109 Rec.second.GlobalizedVal = VoidPtr;
1110
1111 // Assign the local allocation to the newly globalized location.
1112 if (EscapedParam) {
1113 CGF.EmitStoreOfScalar(ParValue, VarAddr);
1114 I->getSecond().MappedParams->setVarAddr(CGF, VD, VarAddr.getAddress());
1115 }
1116 if (auto *DI = CGF.getDebugInfo())
1117 VoidPtr->setDebugLoc(DI->SourceLocToDebugLoc(VD->getLocation()));
1118 }
1119
1120 for (const auto *ValueD : I->getSecond().EscapedVariableLengthDecls) {
1121 const auto *VD = cast<VarDecl>(ValueD);
1122 std::pair<llvm::Value *, llvm::Value *> AddrSizePair =
1123 getKmpcAllocShared(CGF, VD);
1124 I->getSecond().EscapedVariableLengthDeclsAddrs.emplace_back(AddrSizePair);
1125 LValue Base = CGF.MakeAddrLValue(AddrSizePair.first, VD->getType(),
1126 CGM.getContext().getDeclAlign(VD),
1128 I->getSecond().MappedParams->setVarAddr(CGF, VD, Base.getAddress());
1129 }
1130 I->getSecond().MappedParams->apply(CGF);
1131}
1132
1134 const VarDecl *VD) const {
1135 const auto I = FunctionGlobalizedDecls.find(CGF.CurFn);
1136 if (I == FunctionGlobalizedDecls.end())
1137 return false;
1138
1139 // Check variable declaration is delayed:
1140 return llvm::is_contained(I->getSecond().DelayedVariableLengthDecls, VD);
1141}
1142
1143std::pair<llvm::Value *, llvm::Value *>
1145 const VarDecl *VD) {
1146 CGBuilderTy &Bld = CGF.Builder;
1147
1148 // Compute size and alignment.
1149 llvm::Value *Size = CGF.getTypeSize(VD->getType());
1150 CharUnits Align = CGM.getContext().getDeclAlign(VD);
1151 Size = Bld.CreateNUWAdd(
1152 Size, llvm::ConstantInt::get(CGF.SizeTy, Align.getQuantity() - 1));
1153 llvm::Value *AlignVal =
1154 llvm::ConstantInt::get(CGF.SizeTy, Align.getQuantity());
1155 Size = Bld.CreateUDiv(Size, AlignVal);
1156 Size = Bld.CreateNUWMul(Size, AlignVal);
1157
1158 // Allocate space for this VLA object to be globalized.
1159 llvm::Value *AllocArgs[] = {Size};
1160 llvm::CallBase *VoidPtr =
1161 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
1162 CGM.getModule(), OMPRTL___kmpc_alloc_shared),
1163 AllocArgs, VD->getName());
1164 VoidPtr->addRetAttr(llvm::Attribute::get(
1165 CGM.getLLVMContext(), llvm::Attribute::Alignment, Align.getQuantity()));
1166
1167 return std::make_pair(VoidPtr, Size);
1168}
1169
1171 CodeGenFunction &CGF,
1172 const std::pair<llvm::Value *, llvm::Value *> &AddrSizePair) {
1173 // Deallocate the memory for each globalized VLA object
1174 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
1175 CGM.getModule(), OMPRTL___kmpc_free_shared),
1176 {AddrSizePair.first, AddrSizePair.second});
1177}
1178
1179void CGOpenMPRuntimeGPU::emitGenericVarsEpilog(CodeGenFunction &CGF) {
1180 if (getDataSharingMode() != CGOpenMPRuntimeGPU::DS_Generic)
1181 return;
1182
1183 const auto I = FunctionGlobalizedDecls.find(CGF.CurFn);
1184 if (I != FunctionGlobalizedDecls.end()) {
1185 // Deallocate the memory for each globalized VLA object that was
1186 // globalized in the prolog (i.e. emitGenericVarsProlog).
1187 for (const auto &AddrSizePair :
1188 llvm::reverse(I->getSecond().EscapedVariableLengthDeclsAddrs)) {
1189 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
1190 CGM.getModule(), OMPRTL___kmpc_free_shared),
1191 {AddrSizePair.first, AddrSizePair.second});
1192 }
1193 // Deallocate the memory for each globalized value
1194 for (auto &Rec : llvm::reverse(I->getSecond().LocalVarData)) {
1195 const auto *VD = cast<VarDecl>(Rec.first);
1196 I->getSecond().MappedParams->restore(CGF);
1197
1198 llvm::Value *FreeArgs[] = {Rec.second.GlobalizedVal,
1199 CGF.getTypeSize(VD->getType())};
1200 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
1201 CGM.getModule(), OMPRTL___kmpc_free_shared),
1202 FreeArgs);
1203 }
1204 }
1205}
1206
1208 const OMPExecutableDirective &D,
1209 SourceLocation Loc,
1210 llvm::Function *OutlinedFn,
1211 ArrayRef<llvm::Value *> CapturedVars) {
1212 if (!CGF.HaveInsertPoint())
1213 return;
1214
1215 bool IsBareKernel = D.getSingleClause<OMPXBareClause>();
1216
1218 /*Name=*/".zero.addr");
1219 CGF.Builder.CreateStore(CGF.Builder.getInt32(/*C*/ 0), ZeroAddr);
1221 // We don't emit any thread id function call in bare kernel, but because the
1222 // outlined function has a pointer argument, we emit a nullptr here.
1223 if (IsBareKernel)
1224 OutlinedFnArgs.push_back(llvm::ConstantPointerNull::get(CGM.VoidPtrTy));
1225 else
1226 OutlinedFnArgs.push_back(emitThreadIDAddress(CGF, Loc).emitRawPointer(CGF));
1227 OutlinedFnArgs.push_back(ZeroAddr.getPointer());
1228 OutlinedFnArgs.append(CapturedVars.begin(), CapturedVars.end());
1229 emitOutlinedFunctionCall(CGF, Loc, OutlinedFn, OutlinedFnArgs);
1230}
1231
1233 CodeGenFunction &CGF, SourceLocation Loc, llvm::Function *OutlinedFn,
1234 ArrayRef<llvm::Value *> CapturedVars, const Expr *IfCond,
1235 llvm::Value *NumThreads, OpenMPNumThreadsClauseModifier NumThreadsModifier,
1236 OpenMPSeverityClauseKind Severity, const Expr *Message) {
1237 if (!CGF.HaveInsertPoint())
1238 return;
1239
1240 auto &&ParallelGen = [this, Loc, OutlinedFn, CapturedVars, IfCond,
1241 NumThreads](CodeGenFunction &CGF,
1242 PrePostActionTy &Action) {
1243 CGBuilderTy &Bld = CGF.Builder;
1244 llvm::Value *NumThreadsVal = NumThreads;
1245 llvm::Function *WFn = WrapperFunctionsMap[OutlinedFn];
1246 llvm::PointerType *FnPtrTy = llvm::PointerType::get(
1247 CGF.getLLVMContext(), CGM.getDataLayout().getProgramAddressSpace());
1248
1249 llvm::Value *ID = llvm::ConstantPointerNull::get(FnPtrTy);
1250 if (WFn)
1251 ID = Bld.CreateBitOrPointerCast(WFn, FnPtrTy);
1252
1253 llvm::Value *FnPtr = Bld.CreateBitOrPointerCast(OutlinedFn, FnPtrTy);
1254
1255 // Create a private scope that will globalize the arguments
1256 // passed from the outside of the target region.
1257 // TODO: Is that needed?
1258 CodeGenFunction::OMPPrivateScope PrivateArgScope(CGF);
1259
1260 Address CapturedVarsAddrs = CGF.CreateDefaultAlignTempAlloca(
1261 llvm::ArrayType::get(CGM.VoidPtrTy, CapturedVars.size()),
1262 "captured_vars_addrs");
1263 // There's something to share.
1264 if (!CapturedVars.empty()) {
1265 // Prepare for parallel region. Indicate the outlined function.
1266 ASTContext &Ctx = CGF.getContext();
1267 unsigned Idx = 0;
1268 for (llvm::Value *V : CapturedVars) {
1269 Address Dst = Bld.CreateConstArrayGEP(CapturedVarsAddrs, Idx);
1270 llvm::Value *PtrV;
1271 if (V->getType()->isIntegerTy())
1272 PtrV = Bld.CreateIntToPtr(V, CGF.VoidPtrTy);
1273 else
1275 CGF.EmitStoreOfScalar(PtrV, Dst, /*Volatile=*/false,
1276 Ctx.getPointerType(Ctx.VoidPtrTy));
1277 ++Idx;
1278 }
1279 }
1280
1281 llvm::Value *IfCondVal = nullptr;
1282 if (IfCond)
1283 IfCondVal = Bld.CreateIntCast(CGF.EvaluateExprAsBool(IfCond), CGF.Int32Ty,
1284 /* isSigned */ false);
1285 else
1286 IfCondVal = llvm::ConstantInt::get(CGF.Int32Ty, 1);
1287
1288 if (!NumThreadsVal)
1289 NumThreadsVal = llvm::ConstantInt::getAllOnesValue(CGF.Int32Ty);
1290 else
1291 NumThreadsVal = Bld.CreateZExtOrTrunc(NumThreadsVal, CGF.Int32Ty);
1292
1293 // No strict prescriptiveness for the number of threads.
1294 llvm::Value *StrictNumThreadsVal = llvm::ConstantInt::get(CGF.Int32Ty, 0);
1295
1296 assert(IfCondVal && "Expected a value");
1297 llvm::Value *RTLoc = emitUpdateLocation(CGF, Loc);
1298 llvm::Value *Args[] = {
1299 RTLoc,
1300 getThreadID(CGF, Loc),
1301 IfCondVal,
1302 NumThreadsVal,
1303 llvm::ConstantInt::getAllOnesValue(CGF.Int32Ty),
1304 FnPtr,
1305 ID,
1306 Bld.CreateBitOrPointerCast(CapturedVarsAddrs.emitRawPointer(CGF),
1307 CGF.VoidPtrPtrTy),
1308 llvm::ConstantInt::get(CGM.SizeTy, CapturedVars.size()),
1309 StrictNumThreadsVal};
1310
1311 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
1312 CGM.getModule(), OMPRTL___kmpc_parallel_60),
1313 Args);
1314 };
1315
1316 RegionCodeGenTy RCG(ParallelGen);
1317 RCG(CGF);
1318}
1319
1320void CGOpenMPRuntimeGPU::syncCTAThreads(CodeGenFunction &CGF) {
1321 // Always emit simple barriers!
1322 if (!CGF.HaveInsertPoint())
1323 return;
1324 // Build call __kmpc_barrier_simple_spmd(nullptr, 0);
1325 // This function does not use parameters, so we can emit just default values.
1326 llvm::Value *Args[] = {
1327 llvm::ConstantPointerNull::get(
1329 llvm::ConstantInt::get(CGF.Int32Ty, /*V=*/0, /*isSigned=*/true)};
1330 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
1331 CGM.getModule(), OMPRTL___kmpc_barrier_simple_spmd),
1332 Args);
1333}
1334
1336 SourceLocation Loc,
1337 OpenMPDirectiveKind Kind, bool,
1338 bool) {
1339 // Always emit simple barriers!
1340 if (!CGF.HaveInsertPoint())
1341 return;
1342 // Build call __kmpc_cancel_barrier(loc, thread_id);
1343 unsigned Flags = getDefaultFlagsForBarriers(Kind);
1344 llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc, Flags),
1345 getThreadID(CGF, Loc)};
1346
1347 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
1348 CGM.getModule(), OMPRTL___kmpc_barrier),
1349 Args);
1350}
1351
1353 CodeGenFunction &CGF, StringRef CriticalName,
1354 const RegionCodeGenTy &CriticalOpGen, SourceLocation Loc,
1355 const Expr *Hint) {
1356 llvm::BasicBlock *LoopBB = CGF.createBasicBlock("omp.critical.loop");
1357 llvm::BasicBlock *TestBB = CGF.createBasicBlock("omp.critical.test");
1358 llvm::BasicBlock *SyncBB = CGF.createBasicBlock("omp.critical.sync");
1359 llvm::BasicBlock *BodyBB = CGF.createBasicBlock("omp.critical.body");
1360 llvm::BasicBlock *ExitBB = CGF.createBasicBlock("omp.critical.exit");
1361
1362 auto &RT = static_cast<CGOpenMPRuntimeGPU &>(CGF.CGM.getOpenMPRuntime());
1363
1364 // Get the mask of active threads in the warp.
1365 llvm::Value *Mask = CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
1366 CGM.getModule(), OMPRTL___kmpc_warp_active_thread_mask));
1367 // Fetch team-local id of the thread.
1368 llvm::Value *ThreadID = RT.getGPUThreadID(CGF);
1369
1370 // Get the width of the team.
1371 llvm::Value *TeamWidth = RT.getGPUNumThreads(CGF);
1372
1373 // Initialize the counter variable for the loop.
1374 QualType Int32Ty =
1375 CGF.getContext().getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/0);
1376 Address Counter = CGF.CreateMemTempWithoutCast(Int32Ty, "critical_counter");
1377 LValue CounterLVal = CGF.MakeAddrLValue(Counter, Int32Ty);
1378 CGF.EmitStoreOfScalar(llvm::Constant::getNullValue(CGM.Int32Ty), CounterLVal,
1379 /*isInit=*/true);
1380
1381 // Block checks if loop counter exceeds upper bound.
1382 CGF.EmitBlock(LoopBB);
1383 llvm::Value *CounterVal = CGF.EmitLoadOfScalar(CounterLVal, Loc);
1384 llvm::Value *CmpLoopBound = CGF.Builder.CreateICmpSLT(CounterVal, TeamWidth);
1385 CGF.Builder.CreateCondBr(CmpLoopBound, TestBB, ExitBB);
1386
1387 // Block tests which single thread should execute region, and which threads
1388 // should go straight to synchronisation point.
1389 CGF.EmitBlock(TestBB);
1390 CounterVal = CGF.EmitLoadOfScalar(CounterLVal, Loc);
1391 llvm::Value *CmpThreadToCounter =
1392 CGF.Builder.CreateICmpEQ(ThreadID, CounterVal);
1393 CGF.Builder.CreateCondBr(CmpThreadToCounter, BodyBB, SyncBB);
1394
1395 // Block emits the body of the critical region.
1396 CGF.EmitBlock(BodyBB);
1397
1398 // Output the critical statement.
1399 CGOpenMPRuntime::emitCriticalRegion(CGF, CriticalName, CriticalOpGen, Loc,
1400 Hint);
1401
1402 // After the body surrounded by the critical region, the single executing
1403 // thread will jump to the synchronisation point.
1404 // Block waits for all threads in current team to finish then increments the
1405 // counter variable and returns to the loop.
1406 CGF.EmitBlock(SyncBB);
1407 // Reconverge active threads in the warp.
1408 (void)CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
1409 CGM.getModule(), OMPRTL___kmpc_syncwarp),
1410 Mask);
1411
1412 llvm::Value *IncCounterVal =
1413 CGF.Builder.CreateNSWAdd(CounterVal, CGF.Builder.getInt32(1));
1414 CGF.EmitStoreOfScalar(IncCounterVal, CounterLVal);
1415 CGF.EmitBranch(LoopBB);
1416
1417 // Block that is reached when all threads in the team complete the region.
1418 CGF.EmitBlock(ExitBB, /*IsFinished=*/true);
1419}
1420
1421/// Cast value to the specified type.
1422static llvm::Value *castValueToType(CodeGenFunction &CGF, llvm::Value *Val,
1423 QualType ValTy, QualType CastTy,
1424 SourceLocation Loc) {
1425 assert(!CGF.getContext().getTypeSizeInChars(CastTy).isZero() &&
1426 "Cast type must sized.");
1427 assert(!CGF.getContext().getTypeSizeInChars(ValTy).isZero() &&
1428 "Val type must sized.");
1429 llvm::Type *LLVMCastTy = CGF.ConvertTypeForMem(CastTy);
1430 if (ValTy == CastTy)
1431 return Val;
1432 if (CGF.getContext().getTypeSizeInChars(ValTy) ==
1433 CGF.getContext().getTypeSizeInChars(CastTy))
1434 return CGF.Builder.CreateBitCast(Val, LLVMCastTy);
1435 if (CastTy->isIntegerType() && ValTy->isIntegerType())
1436 return CGF.Builder.CreateIntCast(Val, LLVMCastTy,
1438 Address CastItem = CGF.CreateMemTempWithoutCast(CastTy);
1439 Address ValCastItem = CastItem.withElementType(Val->getType());
1440 CGF.EmitStoreOfScalar(Val, ValCastItem, /*Volatile=*/false, ValTy,
1442 TBAAAccessInfo());
1443 return CGF.EmitLoadOfScalar(CastItem, /*Volatile=*/false, CastTy, Loc,
1445 TBAAAccessInfo());
1446}
1447
1448///
1449/// Design of OpenMP reductions on the GPU
1450///
1451/// Consider a typical OpenMP program with one or more reduction
1452/// clauses:
1453///
1454/// float foo;
1455/// double bar;
1456/// #pragma omp target teams distribute parallel for \
1457/// reduction(+:foo) reduction(*:bar)
1458/// for (int i = 0; i < N; i++) {
1459/// foo += A[i]; bar *= B[i];
1460/// }
1461///
1462/// where 'foo' and 'bar' are reduced across all OpenMP threads in
1463/// all teams. In our OpenMP implementation on the NVPTX device an
1464/// OpenMP team is mapped to a CUDA threadblock and OpenMP threads
1465/// within a team are mapped to CUDA threads within a threadblock.
1466/// Our goal is to efficiently aggregate values across all OpenMP
1467/// threads such that:
1468///
1469/// - the compiler and runtime are logically concise, and
1470/// - the reduction is performed efficiently in a hierarchical
1471/// manner as follows: within OpenMP threads in the same warp,
1472/// across warps in a threadblock, and finally across teams on
1473/// the NVPTX device.
1474///
1475/// Introduction to Decoupling
1476///
1477/// We would like to decouple the compiler and the runtime so that the
1478/// latter is ignorant of the reduction variables (number, data types)
1479/// and the reduction operators. This allows a simpler interface
1480/// and implementation while still attaining good performance.
1481///
1482/// Pseudocode for the aforementioned OpenMP program generated by the
1483/// compiler is as follows:
1484///
1485/// 1. Create private copies of reduction variables on each OpenMP
1486/// thread: 'foo_private', 'bar_private'
1487/// 2. Each OpenMP thread reduces the chunk of 'A' and 'B' assigned
1488/// to it and writes the result in 'foo_private' and 'bar_private'
1489/// respectively.
1490/// 3. Call the OpenMP runtime on the GPU to reduce within a team
1491/// and store the result on the team master:
1492///
1493/// __kmpc_nvptx_parallel_reduce_nowait_v2(...,
1494/// reduceData, shuffleReduceFn, interWarpCpyFn)
1495///
1496/// where:
1497/// struct ReduceData {
1498/// double *foo;
1499/// double *bar;
1500/// } reduceData
1501/// reduceData.foo = &foo_private
1502/// reduceData.bar = &bar_private
1503///
1504/// 'shuffleReduceFn' and 'interWarpCpyFn' are pointers to two
1505/// auxiliary functions generated by the compiler that operate on
1506/// variables of type 'ReduceData'. They aid the runtime perform
1507/// algorithmic steps in a data agnostic manner.
1508///
1509/// 'shuffleReduceFn' is a pointer to a function that reduces data
1510/// of type 'ReduceData' across two OpenMP threads (lanes) in the
1511/// same warp. It takes the following arguments as input:
1512///
1513/// a. variable of type 'ReduceData' on the calling lane,
1514/// b. its lane_id,
1515/// c. an offset relative to the current lane_id to generate a
1516/// remote_lane_id. The remote lane contains the second
1517/// variable of type 'ReduceData' that is to be reduced.
1518/// d. an algorithm version parameter determining which reduction
1519/// algorithm to use.
1520///
1521/// 'shuffleReduceFn' retrieves data from the remote lane using
1522/// efficient GPU shuffle intrinsics and reduces, using the
1523/// algorithm specified by the 4th parameter, the two operands
1524/// element-wise. The result is written to the first operand.
1525///
1526/// Different reduction algorithms are implemented in different
1527/// runtime functions, all calling 'shuffleReduceFn' to perform
1528/// the essential reduction step. Therefore, based on the 4th
1529/// parameter, this function behaves slightly differently to
1530/// cooperate with the runtime to ensure correctness under
1531/// different circumstances.
1532///
1533/// 'InterWarpCpyFn' is a pointer to a function that transfers
1534/// reduced variables across warps. It tunnels, through CUDA
1535/// shared memory, the thread-private data of type 'ReduceData'
1536/// from lane 0 of each warp to a lane in the first warp.
1537/// 4. Call the OpenMP runtime on the GPU to reduce across teams.
1538/// The last team writes the global reduced value to memory.
1539///
1540/// ret = __kmpc_nvptx_teams_reduce_nowait(...,
1541/// reduceData, shuffleReduceFn, interWarpCpyFn,
1542/// scratchpadCopyFn, loadAndReduceFn)
1543///
1544/// 'scratchpadCopyFn' is a helper that stores reduced
1545/// data from the team master to a scratchpad array in
1546/// global memory.
1547///
1548/// 'loadAndReduceFn' is a helper that loads data from
1549/// the scratchpad array and reduces it with the input
1550/// operand.
1551///
1552/// These compiler generated functions hide address
1553/// calculation and alignment information from the runtime.
1554/// 5. if ret == 1:
1555/// The team master of the last team stores the reduced
1556/// result to the globals in memory.
1557/// foo += reduceData.foo; bar *= reduceData.bar
1558///
1559///
1560/// Warp Reduction Algorithms
1561///
1562/// On the warp level, we have three algorithms implemented in the
1563/// OpenMP runtime depending on the number of active lanes:
1564///
1565/// Full Warp Reduction
1566///
1567/// The reduce algorithm within a warp where all lanes are active
1568/// is implemented in the runtime as follows:
1569///
1570/// full_warp_reduce(void *reduce_data,
1571/// kmp_ShuffleReductFctPtr ShuffleReduceFn) {
1572/// for (int offset = WARPSIZE/2; offset > 0; offset /= 2)
1573/// ShuffleReduceFn(reduce_data, 0, offset, 0);
1574/// }
1575///
1576/// The algorithm completes in log(2, WARPSIZE) steps.
1577///
1578/// 'ShuffleReduceFn' is used here with lane_id set to 0 because it is
1579/// not used therefore we save instructions by not retrieving lane_id
1580/// from the corresponding special registers. The 4th parameter, which
1581/// represents the version of the algorithm being used, is set to 0 to
1582/// signify full warp reduction.
1583///
1584/// In this version, 'ShuffleReduceFn' behaves, per element, as follows:
1585///
1586/// #reduce_elem refers to an element in the local lane's data structure
1587/// #remote_elem is retrieved from a remote lane
1588/// remote_elem = shuffle_down(reduce_elem, offset, WARPSIZE);
1589/// reduce_elem = reduce_elem REDUCE_OP remote_elem;
1590///
1591/// Contiguous Partial Warp Reduction
1592///
1593/// This reduce algorithm is used within a warp where only the first
1594/// 'n' (n <= WARPSIZE) lanes are active. It is typically used when the
1595/// number of OpenMP threads in a parallel region is not a multiple of
1596/// WARPSIZE. The algorithm is implemented in the runtime as follows:
1597///
1598/// void
1599/// contiguous_partial_reduce(void *reduce_data,
1600/// kmp_ShuffleReductFctPtr ShuffleReduceFn,
1601/// int size, int lane_id) {
1602/// int curr_size;
1603/// int offset;
1604/// curr_size = size;
1605/// mask = curr_size/2;
1606/// while (offset>0) {
1607/// ShuffleReduceFn(reduce_data, lane_id, offset, 1);
1608/// curr_size = (curr_size+1)/2;
1609/// offset = curr_size/2;
1610/// }
1611/// }
1612///
1613/// In this version, 'ShuffleReduceFn' behaves, per element, as follows:
1614///
1615/// remote_elem = shuffle_down(reduce_elem, offset, WARPSIZE);
1616/// if (lane_id < offset)
1617/// reduce_elem = reduce_elem REDUCE_OP remote_elem
1618/// else
1619/// reduce_elem = remote_elem
1620///
1621/// This algorithm assumes that the data to be reduced are located in a
1622/// contiguous subset of lanes starting from the first. When there is
1623/// an odd number of active lanes, the data in the last lane is not
1624/// aggregated with any other lane's dat but is instead copied over.
1625///
1626/// Dispersed Partial Warp Reduction
1627///
1628/// This algorithm is used within a warp when any discontiguous subset of
1629/// lanes are active. It is used to implement the reduction operation
1630/// across lanes in an OpenMP simd region or in a nested parallel region.
1631///
1632/// void
1633/// dispersed_partial_reduce(void *reduce_data,
1634/// kmp_ShuffleReductFctPtr ShuffleReduceFn) {
1635/// int size, remote_id;
1636/// int logical_lane_id = number_of_active_lanes_before_me() * 2;
1637/// do {
1638/// remote_id = next_active_lane_id_right_after_me();
1639/// # the above function returns 0 of no active lane
1640/// # is present right after the current lane.
1641/// size = number_of_active_lanes_in_this_warp();
1642/// logical_lane_id /= 2;
1643/// ShuffleReduceFn(reduce_data, logical_lane_id,
1644/// remote_id-1-threadIdx.x, 2);
1645/// } while (logical_lane_id % 2 == 0 && size > 1);
1646/// }
1647///
1648/// There is no assumption made about the initial state of the reduction.
1649/// Any number of lanes (>=1) could be active at any position. The reduction
1650/// result is returned in the first active lane.
1651///
1652/// In this version, 'ShuffleReduceFn' behaves, per element, as follows:
1653///
1654/// remote_elem = shuffle_down(reduce_elem, offset, WARPSIZE);
1655/// if (lane_id % 2 == 0 && offset > 0)
1656/// reduce_elem = reduce_elem REDUCE_OP remote_elem
1657/// else
1658/// reduce_elem = remote_elem
1659///
1660///
1661/// Intra-Team Reduction
1662///
1663/// This function, as implemented in the runtime call
1664/// '__kmpc_nvptx_parallel_reduce_nowait_v2', aggregates data across OpenMP
1665/// threads in a team. It first reduces within a warp using the
1666/// aforementioned algorithms. We then proceed to gather all such
1667/// reduced values at the first warp.
1668///
1669/// The runtime makes use of the function 'InterWarpCpyFn', which copies
1670/// data from each of the "warp master" (zeroth lane of each warp, where
1671/// warp-reduced data is held) to the zeroth warp. This step reduces (in
1672/// a mathematical sense) the problem of reduction across warp masters in
1673/// a block to the problem of warp reduction.
1674///
1675///
1676/// Inter-Team Reduction
1677///
1678/// Once a team has reduced its data to a single value, it is stored in
1679/// a global scratchpad array. Since each team has a distinct slot, this
1680/// can be done without locking.
1681///
1682/// The last team to write to the scratchpad array proceeds to reduce the
1683/// scratchpad array. One or more workers in the last team use the helper
1684/// 'loadAndReduceDataFn' to load and reduce values from the array, i.e.,
1685/// the k'th worker reduces every k'th element.
1686///
1687/// Finally, a call is made to '__kmpc_nvptx_parallel_reduce_nowait_v2' to
1688/// reduce across workers and compute a globally reduced value.
1689///
1693 ArrayRef<const Expr *> ReductionOps, ReductionOptionsTy Options) {
1694 if (!CGF.HaveInsertPoint())
1695 return;
1696
1697 bool ParallelReduction = isOpenMPParallelDirective(Options.ReductionKind);
1698 bool TeamsReduction = isOpenMPTeamsDirective(Options.ReductionKind);
1699
1700 if (Options.SimpleReduction) {
1701 assert(!TeamsReduction && !ParallelReduction &&
1702 "Invalid reduction selection in emitReduction.");
1703 (void)ParallelReduction;
1704 CGOpenMPRuntime::emitReduction(CGF, Loc, Privates, LHSExprs, RHSExprs,
1705 ReductionOps, Options);
1706 return;
1707 }
1708
1709 llvm::SmallDenseMap<const ValueDecl *, const FieldDecl *> VarFieldMap;
1710 llvm::SmallVector<const ValueDecl *, 4> PrivatesReductions(Privates.size());
1711 int Cnt = 0;
1712 for (const Expr *DRE : Privates) {
1713 PrivatesReductions[Cnt] = cast<DeclRefExpr>(DRE)->getDecl();
1714 ++Cnt;
1715 }
1716 const RecordDecl *ReductionRec = ::buildRecordForGlobalizedVars(
1717 CGM.getContext(), PrivatesReductions, {}, VarFieldMap, 1);
1718
1719 if (TeamsReduction)
1720 TeamsReductions.push_back(ReductionRec);
1721
1722 // Source location for the ident struct
1723 llvm::Value *RTLoc = emitUpdateLocation(CGF, Loc);
1724
1725 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
1726 InsertPointTy AllocaIP(CGF.AllocaInsertPt->getParent(),
1727 CGF.AllocaInsertPt->getIterator());
1728 InsertPointTy CodeGenIP(CGF.Builder.GetInsertBlock(),
1729 CGF.Builder.GetInsertPoint());
1730 llvm::OpenMPIRBuilder::LocationDescription OmpLoc(
1731 CodeGenIP, CGF.SourceLocToDebugLoc(Loc));
1733
1735 unsigned Idx = 0;
1736 for (const Expr *Private : Privates) {
1737 llvm::Type *ElementType;
1738 llvm::Value *Variable;
1739 llvm::Value *PrivateVariable;
1740 llvm::OpenMPIRBuilder::ReductionGenAtomicCBTy AtomicReductionGen = nullptr;
1741 ElementType = CGF.ConvertTypeForMem(Private->getType());
1742 const auto *RHSVar =
1743 cast<VarDecl>(cast<DeclRefExpr>(RHSExprs[Idx])->getDecl());
1744 PrivateVariable = CGF.GetAddrOfLocalVar(RHSVar).emitRawPointer(CGF);
1745 const auto *LHSVar =
1746 cast<VarDecl>(cast<DeclRefExpr>(LHSExprs[Idx])->getDecl());
1747 Variable = CGF.GetAddrOfLocalVar(LHSVar).emitRawPointer(CGF);
1748 llvm::OpenMPIRBuilder::EvalKind EvalKind;
1749 switch (CGF.getEvaluationKind(Private->getType())) {
1750 case TEK_Scalar:
1751 EvalKind = llvm::OpenMPIRBuilder::EvalKind::Scalar;
1752 break;
1753 case TEK_Complex:
1754 EvalKind = llvm::OpenMPIRBuilder::EvalKind::Complex;
1755 break;
1756 case TEK_Aggregate:
1757 EvalKind = llvm::OpenMPIRBuilder::EvalKind::Aggregate;
1758 break;
1759 }
1760 auto ReductionGen = [&](InsertPointTy CodeGenIP, unsigned I,
1761 llvm::Value **LHSPtr, llvm::Value **RHSPtr,
1762 llvm::Function *NewFunc) {
1763 CGF.Builder.restoreIP(CodeGenIP);
1764 auto *CurFn = CGF.CurFn;
1765 CGF.CurFn = NewFunc;
1766
1767 *LHSPtr = CGF.GetAddrOfLocalVar(
1768 cast<VarDecl>(cast<DeclRefExpr>(LHSExprs[I])->getDecl()))
1769 .emitRawPointer(CGF);
1770 *RHSPtr = CGF.GetAddrOfLocalVar(
1771 cast<VarDecl>(cast<DeclRefExpr>(RHSExprs[I])->getDecl()))
1772 .emitRawPointer(CGF);
1773
1774 emitSingleReductionCombiner(CGF, ReductionOps[I], Privates[I],
1775 cast<DeclRefExpr>(LHSExprs[I]),
1776 cast<DeclRefExpr>(RHSExprs[I]));
1777
1778 CGF.CurFn = CurFn;
1779
1780 return InsertPointTy(CGF.Builder.GetInsertBlock(),
1781 CGF.Builder.GetInsertPoint());
1782 };
1783 ReductionInfos.emplace_back(llvm::OpenMPIRBuilder::ReductionInfo(
1784 ElementType, Variable, PrivateVariable, EvalKind,
1785 /*ReductionGen=*/nullptr, ReductionGen, AtomicReductionGen,
1786 /*DataPtrPtrGen=*/nullptr));
1787 Idx++;
1788 }
1789
1790 bool IsSPMD = getExecutionMode() == CGOpenMPRuntimeGPU::EM_SPMD;
1791 llvm::OpenMPIRBuilder::InsertPointTy AfterIP =
1792 cantFail(OMPBuilder.createReductionsGPU(
1793 OmpLoc, AllocaIP, CodeGenIP, ReductionInfos, /*IsByRef=*/{}, false,
1794 TeamsReduction, IsSPMD,
1795 llvm::OpenMPIRBuilder::ReductionGenCBKind::Clang,
1796 CGF.getTarget().getGridValue(), RTLoc));
1797 CGF.Builder.restoreIP(AfterIP);
1798}
1799
1800const VarDecl *
1802 const VarDecl *NativeParam) const {
1803 if (!NativeParam->getType()->isReferenceType())
1804 return NativeParam;
1805 QualType ArgType = NativeParam->getType();
1807 const Type *NonQualTy = QC.strip(ArgType);
1808 QualType PointeeTy = cast<ReferenceType>(NonQualTy)->getPointeeType();
1809 if (const auto *Attr = FD->getAttr<OMPCaptureKindAttr>()) {
1810 if (Attr->getCaptureKind() == OMPC_map) {
1811 PointeeTy = CGM.getContext().getAddrSpaceQualType(PointeeTy,
1813 }
1814 }
1815 ArgType = CGM.getContext().getPointerType(PointeeTy);
1816 QC.addRestrict();
1817 ArgType = QC.apply(CGM.getContext(), ArgType);
1818 if (isa<ImplicitParamDecl>(NativeParam))
1820 CGM.getContext(), /*DC=*/nullptr, NativeParam->getLocation(),
1822 return ParmVarDecl::Create(
1823 CGM.getContext(),
1824 const_cast<DeclContext *>(NativeParam->getDeclContext()),
1825 NativeParam->getBeginLoc(), NativeParam->getLocation(),
1826 NativeParam->getIdentifier(), ArgType,
1827 /*TInfo=*/nullptr, SC_None, /*DefArg=*/nullptr);
1828}
1829
1830Address
1832 const VarDecl *NativeParam,
1833 const VarDecl *TargetParam) const {
1834 assert(NativeParam != TargetParam &&
1835 NativeParam->getType()->isReferenceType() &&
1836 "Native arg must not be the same as target arg.");
1837 Address LocalAddr = CGF.GetAddrOfLocalVar(TargetParam);
1838 QualType NativeParamType = NativeParam->getType();
1840 const Type *NonQualTy = QC.strip(NativeParamType);
1841 QualType NativePointeeTy = cast<ReferenceType>(NonQualTy)->getPointeeType();
1842 unsigned NativePointeeAddrSpace =
1843 CGF.getTypes().getTargetAddressSpace(NativePointeeTy);
1844 QualType TargetTy = TargetParam->getType();
1845 llvm::Value *TargetAddr = CGF.EmitLoadOfScalar(LocalAddr, /*Volatile=*/false,
1846 TargetTy, SourceLocation());
1847 // Cast to native address space.
1849 TargetAddr,
1850 llvm::PointerType::get(CGF.getLLVMContext(), NativePointeeAddrSpace));
1851 Address NativeParamAddr = CGF.CreateMemTemp(NativeParamType);
1852 CGF.EmitStoreOfScalar(TargetAddr, NativeParamAddr, /*Volatile=*/false,
1853 NativeParamType);
1854 return NativeParamAddr;
1855}
1856
1858 CodeGenFunction &CGF, SourceLocation Loc, llvm::FunctionCallee OutlinedFn,
1859 ArrayRef<llvm::Value *> Args) const {
1861 TargetArgs.reserve(Args.size());
1862 auto *FnType = OutlinedFn.getFunctionType();
1863 for (unsigned I = 0, E = Args.size(); I < E; ++I) {
1864 if (FnType->isVarArg() && FnType->getNumParams() <= I) {
1865 TargetArgs.append(std::next(Args.begin(), I), Args.end());
1866 break;
1867 }
1868 llvm::Type *TargetType = FnType->getParamType(I);
1869 llvm::Value *NativeArg = Args[I];
1870 if (!TargetType->isPointerTy()) {
1871 TargetArgs.emplace_back(NativeArg);
1872 continue;
1873 }
1874 TargetArgs.emplace_back(
1875 CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(NativeArg, TargetType));
1876 }
1877 CGOpenMPRuntime::emitOutlinedFunctionCall(CGF, Loc, OutlinedFn, TargetArgs);
1878}
1879
1880/// Emit function which wraps the outline parallel region
1881/// and controls the arguments which are passed to this function.
1882/// The wrapper ensures that the outlined function is called
1883/// with the correct arguments when data is shared.
1884llvm::Function *CGOpenMPRuntimeGPU::createParallelDataSharingWrapper(
1885 llvm::Function *OutlinedParallelFn, const OMPExecutableDirective &D) {
1886 ASTContext &Ctx = CGM.getContext();
1887 const auto &CS = *D.getCapturedStmt(OMPD_parallel);
1888
1889 // Create a function that takes as argument the source thread.
1890 FunctionArgList WrapperArgs;
1891 QualType Int16QTy =
1892 Ctx.getIntTypeForBitwidth(/*DestWidth=*/16, /*Signed=*/false);
1893 QualType Int32QTy =
1894 Ctx.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/false);
1895 auto *ParallelLevelArg = ImplicitParamDecl::Create(
1896 Ctx, /*DC=*/nullptr, D.getBeginLoc(),
1897 /*Id=*/nullptr, Int16QTy, ImplicitParamKind::Other);
1898 auto *WrapperArg = ImplicitParamDecl::Create(
1899 Ctx, /*DC=*/nullptr, D.getBeginLoc(),
1900 /*Id=*/nullptr, Int32QTy, ImplicitParamKind::Other);
1901 WrapperArgs.emplace_back(ParallelLevelArg);
1902 WrapperArgs.emplace_back(WrapperArg);
1903
1904 const CGFunctionInfo &CGFI =
1906
1907 auto *Fn = llvm::Function::Create(
1908 CGM.getTypes().GetFunctionType(CGFI), llvm::GlobalValue::InternalLinkage,
1909 Twine(OutlinedParallelFn->getName(), "_wrapper"), &CGM.getModule());
1910
1911 // Ensure we do not inline the function. This is trivially true for the ones
1912 // passed to __kmpc_fork_call but the ones calles in serialized regions
1913 // could be inlined. This is not a perfect but it is closer to the invariant
1914 // we want, namely, every data environment starts with a new function.
1915 // TODO: We should pass the if condition to the runtime function and do the
1916 // handling there. Much cleaner code.
1917 Fn->addFnAttr(llvm::Attribute::NoInline);
1918
1920 Fn->setLinkage(llvm::GlobalValue::InternalLinkage);
1921 Fn->setDoesNotRecurse();
1922
1923 CodeGenFunction CGF(CGM, /*suppressNewContext=*/true);
1924 CGF.StartFunction(GlobalDecl(), Ctx.VoidTy, Fn, CGFI, WrapperArgs,
1925 D.getBeginLoc(), D.getBeginLoc());
1926
1927 const auto *RD = CS.getCapturedRecordDecl();
1928 auto CurField = RD->field_begin();
1929
1930 Address ZeroAddr = CGF.CreateDefaultAlignTempAlloca(CGF.Int32Ty,
1931 /*Name=*/".zero.addr");
1932 CGF.Builder.CreateStore(CGF.Builder.getInt32(/*C*/ 0), ZeroAddr);
1933 // Get the array of arguments.
1935
1936 Args.emplace_back(CGF.GetAddrOfLocalVar(WrapperArg).emitRawPointer(CGF));
1937 Args.emplace_back(ZeroAddr.emitRawPointer(CGF));
1938
1939 CGBuilderTy &Bld = CGF.Builder;
1940 auto CI = CS.capture_begin();
1941
1942 // Use global memory for data sharing.
1943 // Handle passing of global args to workers.
1944 RawAddress GlobalArgs =
1945 CGF.CreateDefaultAlignTempAlloca(CGF.VoidPtrPtrTy, "global_args");
1946 llvm::Value *GlobalArgsPtr = GlobalArgs.getPointer();
1947 llvm::Value *DataSharingArgs[] = {GlobalArgsPtr};
1948 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
1949 CGM.getModule(), OMPRTL___kmpc_get_shared_variables),
1950 DataSharingArgs);
1951
1952 // Retrieve the shared variables from the list of references returned
1953 // by the runtime. Pass the variables to the outlined function.
1954 Address SharedArgListAddress = Address::invalid();
1955 if (CS.capture_size() > 0 ||
1956 isOpenMPLoopBoundSharingDirective(D.getDirectiveKind())) {
1957 SharedArgListAddress = CGF.EmitLoadOfPointer(
1958 GlobalArgs, CGF.getContext()
1960 .castAs<PointerType>());
1961 }
1962 unsigned Idx = 0;
1963 if (isOpenMPLoopBoundSharingDirective(D.getDirectiveKind())) {
1964 Address Src = Bld.CreateConstInBoundsGEP(SharedArgListAddress, Idx);
1966 Src, Bld.getPtrTy(0), CGF.SizeTy);
1967 llvm::Value *LB = CGF.EmitLoadOfScalar(
1968 TypedAddress,
1969 /*Volatile=*/false,
1971 cast<OMPLoopDirective>(D).getLowerBoundVariable()->getExprLoc());
1972 Args.emplace_back(LB);
1973 ++Idx;
1974 Src = Bld.CreateConstInBoundsGEP(SharedArgListAddress, Idx);
1975 TypedAddress = Bld.CreatePointerBitCastOrAddrSpaceCast(Src, Bld.getPtrTy(0),
1976 CGF.SizeTy);
1977 llvm::Value *UB = CGF.EmitLoadOfScalar(
1978 TypedAddress,
1979 /*Volatile=*/false,
1981 cast<OMPLoopDirective>(D).getUpperBoundVariable()->getExprLoc());
1982 Args.emplace_back(UB);
1983 ++Idx;
1984 }
1985 if (CS.capture_size() > 0) {
1986 ASTContext &CGFContext = CGF.getContext();
1987 for (unsigned I = 0, E = CS.capture_size(); I < E; ++I, ++CI, ++CurField) {
1988 QualType ElemTy = CurField->getType();
1989 Address Src = Bld.CreateConstInBoundsGEP(SharedArgListAddress, I + Idx);
1991 Src, CGF.ConvertTypeForMem(CGFContext.getPointerType(ElemTy)),
1992 CGF.ConvertTypeForMem(ElemTy));
1993 llvm::Value *Arg = CGF.EmitLoadOfScalar(TypedAddress,
1994 /*Volatile=*/false,
1995 CGFContext.getPointerType(ElemTy),
1996 CI->getLocation());
1997 if (CI->capturesVariableByCopy() &&
1998 !CI->getCapturedVar()->getType()->isAnyPointerType()) {
1999 Arg = castValueToType(CGF, Arg, ElemTy, CGFContext.getUIntPtrType(),
2000 CI->getLocation());
2001 }
2002 Args.emplace_back(Arg);
2003 }
2004 }
2005
2006 emitOutlinedFunctionCall(CGF, D.getBeginLoc(), OutlinedParallelFn, Args);
2007 CGF.FinishFunction();
2008 return Fn;
2009}
2010
2012 const Decl *D) {
2013 if (getDataSharingMode() != CGOpenMPRuntimeGPU::DS_Generic)
2014 return;
2015
2016 assert(D && "Expected function or captured|block decl.");
2017 assert(FunctionGlobalizedDecls.count(CGF.CurFn) == 0 &&
2018 "Function is registered already.");
2019 assert((!TeamAndReductions.first || TeamAndReductions.first == D) &&
2020 "Team is set but not processed.");
2021 const Stmt *Body = nullptr;
2022 bool NeedToDelayGlobalization = false;
2023 if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
2024 Body = FD->getBody();
2025 } else if (const auto *BD = dyn_cast<BlockDecl>(D)) {
2026 Body = BD->getBody();
2027 } else if (const auto *CD = dyn_cast<CapturedDecl>(D)) {
2028 Body = CD->getBody();
2029 NeedToDelayGlobalization = CGF.CapturedStmtInfo->getKind() == CR_OpenMP;
2030 if (NeedToDelayGlobalization &&
2031 getExecutionMode() == CGOpenMPRuntimeGPU::EM_SPMD)
2032 return;
2033 }
2034 if (!Body)
2035 return;
2036 CheckVarsEscapingDeclContext VarChecker(CGF, TeamAndReductions.second);
2037 VarChecker.Visit(Body);
2038 const RecordDecl *GlobalizedVarsRecord =
2039 VarChecker.getGlobalizedRecord(IsInTTDRegion);
2040 TeamAndReductions.first = nullptr;
2041 TeamAndReductions.second.clear();
2042 ArrayRef<const ValueDecl *> EscapedVariableLengthDecls =
2043 VarChecker.getEscapedVariableLengthDecls();
2044 ArrayRef<const ValueDecl *> DelayedVariableLengthDecls =
2045 VarChecker.getDelayedVariableLengthDecls();
2046 if (!GlobalizedVarsRecord && EscapedVariableLengthDecls.empty() &&
2047 DelayedVariableLengthDecls.empty())
2048 return;
2049 auto I = FunctionGlobalizedDecls.try_emplace(CGF.CurFn).first;
2050 I->getSecond().MappedParams =
2051 std::make_unique<CodeGenFunction::OMPMapVars>();
2052 I->getSecond().EscapedParameters.insert(
2053 VarChecker.getEscapedParameters().begin(),
2054 VarChecker.getEscapedParameters().end());
2055 I->getSecond().EscapedVariableLengthDecls.append(
2056 EscapedVariableLengthDecls.begin(), EscapedVariableLengthDecls.end());
2057 I->getSecond().DelayedVariableLengthDecls.append(
2058 DelayedVariableLengthDecls.begin(), DelayedVariableLengthDecls.end());
2059 DeclToAddrMapTy &Data = I->getSecond().LocalVarData;
2060 for (const ValueDecl *VD : VarChecker.getEscapedDecls()) {
2061 assert(VD->isCanonicalDecl() && "Expected canonical declaration");
2062 Data.try_emplace(VD);
2063 }
2064 if (!NeedToDelayGlobalization) {
2065 emitGenericVarsProlog(CGF, D->getBeginLoc());
2066 struct GlobalizationScope final : EHScopeStack::Cleanup {
2067 GlobalizationScope() = default;
2068
2069 void Emit(CodeGenFunction &CGF, Flags flags) override {
2070 static_cast<CGOpenMPRuntimeGPU &>(CGF.CGM.getOpenMPRuntime())
2071 .emitGenericVarsEpilog(CGF);
2072 }
2073 };
2074 CGF.EHStack.pushCleanup<GlobalizationScope>(NormalAndEHCleanup);
2075 }
2076}
2077
2079 const VarDecl *VD) {
2080 if (VD && VD->hasAttr<OMPAllocateDeclAttr>()) {
2081 const auto *A = VD->getAttr<OMPAllocateDeclAttr>();
2082 auto AS = LangAS::Default;
2083 switch (A->getAllocatorType()) {
2084 case OMPAllocateDeclAttr::OMPNullMemAlloc:
2085 case OMPAllocateDeclAttr::OMPDefaultMemAlloc:
2086 case OMPAllocateDeclAttr::OMPHighBWMemAlloc:
2087 case OMPAllocateDeclAttr::OMPLowLatMemAlloc:
2088 break;
2089 case OMPAllocateDeclAttr::OMPThreadMemAlloc:
2090 return Address::invalid();
2091 case OMPAllocateDeclAttr::OMPUserDefinedMemAlloc:
2092 // TODO: implement aupport for user-defined allocators.
2093 return Address::invalid();
2094 case OMPAllocateDeclAttr::OMPConstMemAlloc:
2096 break;
2097 case OMPAllocateDeclAttr::OMPPTeamMemAlloc:
2099 break;
2100 case OMPAllocateDeclAttr::OMPLargeCapMemAlloc:
2101 case OMPAllocateDeclAttr::OMPCGroupMemAlloc:
2102 break;
2103 }
2104 llvm::Type *VarTy = CGF.ConvertTypeForMem(VD->getType());
2105 auto *GV = new llvm::GlobalVariable(
2106 CGM.getModule(), VarTy, /*isConstant=*/false,
2107 llvm::GlobalValue::InternalLinkage, llvm::PoisonValue::get(VarTy),
2108 VD->getName(),
2109 /*InsertBefore=*/nullptr, llvm::GlobalValue::NotThreadLocal,
2110 CGM.getContext().getTargetAddressSpace(AS));
2111 CharUnits Align = CGM.getContext().getDeclAlign(VD);
2112 GV->setAlignment(Align.getAsAlign());
2113 return Address(
2115 GV, CGF.Builder.getPtrTy(CGM.getContext().getTargetAddressSpace(
2116 VD->getType().getAddressSpace()))),
2117 VarTy, Align);
2118 }
2119
2120 if (getDataSharingMode() != CGOpenMPRuntimeGPU::DS_Generic)
2121 return Address::invalid();
2122
2123 VD = VD->getCanonicalDecl();
2124 auto I = FunctionGlobalizedDecls.find(CGF.CurFn);
2125 if (I == FunctionGlobalizedDecls.end())
2126 return Address::invalid();
2127 auto VDI = I->getSecond().LocalVarData.find(VD);
2128 if (VDI != I->getSecond().LocalVarData.end())
2129 return VDI->second.PrivateAddr;
2130 if (VD->hasAttrs()) {
2132 E(VD->attr_end());
2133 IT != E; ++IT) {
2134 auto VDI = I->getSecond().LocalVarData.find(
2135 cast<VarDecl>(cast<DeclRefExpr>(IT->getRef())->getDecl())
2136 ->getCanonicalDecl());
2137 if (VDI != I->getSecond().LocalVarData.end())
2138 return VDI->second.PrivateAddr;
2139 }
2140 }
2141
2142 return Address::invalid();
2143}
2144
2146 FunctionGlobalizedDecls.erase(CGF.CurFn);
2148}
2149
2151 CodeGenFunction &CGF, const OMPLoopDirective &S,
2152 OpenMPDistScheduleClauseKind &ScheduleKind,
2153 llvm::Value *&Chunk) const {
2154 auto &RT = static_cast<CGOpenMPRuntimeGPU &>(CGF.CGM.getOpenMPRuntime());
2155 if (getExecutionMode() == CGOpenMPRuntimeGPU::EM_SPMD) {
2156 ScheduleKind = OMPC_DIST_SCHEDULE_static;
2157 Chunk = CGF.EmitScalarConversion(
2158 RT.getGPUNumThreads(CGF),
2159 CGF.getContext().getIntTypeForBitwidth(32, /*Signed=*/0),
2160 S.getIterationVariable()->getType(), S.getBeginLoc());
2161 return;
2162 }
2164 CGF, S, ScheduleKind, Chunk);
2165}
2166
2168 CodeGenFunction &CGF, const OMPLoopDirective &S,
2169 OpenMPScheduleClauseKind &ScheduleKind,
2170 const Expr *&ChunkExpr) const {
2171 ScheduleKind = OMPC_SCHEDULE_static;
2172 // Chunk size is 1 in this case.
2173 llvm::APInt ChunkSize(32, 1);
2174 ChunkExpr = IntegerLiteral::Create(CGF.getContext(), ChunkSize,
2175 CGF.getContext().getIntTypeForBitwidth(32, /*Signed=*/0),
2176 SourceLocation());
2177}
2178
2180 CodeGenFunction &CGF, const OMPExecutableDirective &D) const {
2181 assert(isOpenMPTargetExecutionDirective(D.getDirectiveKind()) &&
2182 " Expected target-based directive.");
2183 const CapturedStmt *CS = D.getCapturedStmt(OMPD_target);
2184 for (const CapturedStmt::Capture &C : CS->captures()) {
2185 // Capture variables captured by reference in lambdas for target-based
2186 // directives.
2187 if (!C.capturesVariable())
2188 continue;
2189 const VarDecl *VD = C.getCapturedVar();
2190 const auto *RD = VD->getType()
2194 if (!RD || !RD->isLambda())
2195 continue;
2196 Address VDAddr = CGF.GetAddrOfLocalVar(VD);
2197 LValue VDLVal;
2199 VDLVal = CGF.EmitLoadOfReferenceLValue(VDAddr, VD->getType());
2200 else
2201 VDLVal = CGF.MakeAddrLValue(
2202 VDAddr, VD->getType().getCanonicalType().getNonReferenceType());
2203 llvm::DenseMap<const ValueDecl *, FieldDecl *> Captures;
2204 FieldDecl *ThisCapture = nullptr;
2205 RD->getCaptureFields(Captures, ThisCapture);
2206 if (ThisCapture && CGF.CapturedStmtInfo->isCXXThisExprCaptured()) {
2207 LValue ThisLVal =
2208 CGF.EmitLValueForFieldInitialization(VDLVal, ThisCapture);
2209 llvm::Value *CXXThis = CGF.LoadCXXThis();
2210 CGF.EmitStoreOfScalar(CXXThis, ThisLVal);
2211 }
2212 for (const LambdaCapture &LC : RD->captures()) {
2213 if (LC.getCaptureKind() != LCK_ByRef)
2214 continue;
2215 const ValueDecl *VD = LC.getCapturedVar();
2216 // FIXME: For now VD is always a VarDecl because OpenMP does not support
2217 // capturing structured bindings in lambdas yet.
2218 if (!CS->capturesVariable(cast<VarDecl>(VD)))
2219 continue;
2220 auto It = Captures.find(VD);
2221 assert(It != Captures.end() && "Found lambda capture without field.");
2222 LValue VarLVal = CGF.EmitLValueForFieldInitialization(VDLVal, It->second);
2223 Address VDAddr = CGF.GetAddrOfLocalVar(cast<VarDecl>(VD));
2225 VDAddr = CGF.EmitLoadOfReferenceLValue(VDAddr,
2226 VD->getType().getCanonicalType())
2227 .getAddress();
2228 CGF.EmitStoreOfScalar(VDAddr.emitRawPointer(CGF), VarLVal);
2229 }
2230 }
2231}
2232
2234 LangAS &AS) {
2235 if (!VD || !VD->hasAttr<OMPAllocateDeclAttr>())
2236 return false;
2237 const auto *A = VD->getAttr<OMPAllocateDeclAttr>();
2238 switch(A->getAllocatorType()) {
2239 case OMPAllocateDeclAttr::OMPNullMemAlloc:
2240 case OMPAllocateDeclAttr::OMPDefaultMemAlloc:
2241 // Not supported, fallback to the default mem space.
2242 case OMPAllocateDeclAttr::OMPLargeCapMemAlloc:
2243 case OMPAllocateDeclAttr::OMPCGroupMemAlloc:
2244 case OMPAllocateDeclAttr::OMPHighBWMemAlloc:
2245 case OMPAllocateDeclAttr::OMPLowLatMemAlloc:
2246 case OMPAllocateDeclAttr::OMPThreadMemAlloc:
2247 AS = LangAS::Default;
2248 return true;
2249 case OMPAllocateDeclAttr::OMPConstMemAlloc:
2251 return true;
2252 case OMPAllocateDeclAttr::OMPPTeamMemAlloc:
2254 return true;
2255 case OMPAllocateDeclAttr::OMPUserDefinedMemAlloc:
2256 llvm_unreachable("Expected predefined allocator for the variables with the "
2257 "static storage.");
2258 }
2259 return false;
2260}
2261
2263 // FIXME: This should not require parsing
2265}
2266
2267/// Check to see if target architecture supports unified addressing which is
2268/// a restriction for OpenMP requires clause "unified_shared_memory".
2270 for (const OMPClause *Clause : D->clauselists()) {
2271 if (Clause->getClauseKind() == OMPC_unified_shared_memory) {
2273 switch (Arch) {
2274 case OffloadArch::SM_20:
2275 case OffloadArch::SM_21:
2276 case OffloadArch::SM_30:
2278 case OffloadArch::SM_35:
2279 case OffloadArch::SM_37:
2280 case OffloadArch::SM_50:
2281 case OffloadArch::SM_52:
2282 case OffloadArch::SM_53: {
2283 SmallString<256> Buffer;
2284 llvm::raw_svector_ostream Out(Buffer);
2285 Out << "Target architecture " << OffloadArchToString(Arch)
2286 << " does not support unified addressing";
2287 CGM.Error(Clause->getBeginLoc(), Out.str());
2288 return;
2289 }
2290 case OffloadArch::SM_60:
2291 case OffloadArch::SM_61:
2292 case OffloadArch::SM_62:
2293 case OffloadArch::SM_70:
2294 case OffloadArch::SM_72:
2295 case OffloadArch::SM_75:
2296 case OffloadArch::SM_80:
2297 case OffloadArch::SM_86:
2298 case OffloadArch::SM_87:
2299 case OffloadArch::SM_88:
2300 case OffloadArch::SM_89:
2301 case OffloadArch::SM_90:
2388 break;
2389 }
2390 }
2391 }
2393}
2394
2396 CGBuilderTy &Bld = CGF.Builder;
2397 llvm::Module *M = &CGF.CGM.getModule();
2398 const char *LocSize = "__kmpc_get_hardware_num_threads_in_block";
2399 llvm::Function *F = M->getFunction(LocSize);
2400 if (!F) {
2401 F = llvm::Function::Create(llvm::FunctionType::get(CGF.Int32Ty, {}, false),
2402 llvm::GlobalVariable::ExternalLinkage, LocSize,
2403 &CGF.CGM.getModule());
2404 }
2405 return Bld.CreateCall(F, {}, "nvptx_num_threads");
2406}
2407
2410 return CGF.EmitRuntimeCall(
2411 OMPBuilder.getOrCreateRuntimeFunction(
2412 CGM.getModule(), OMPRTL___kmpc_get_hardware_thread_id_in_block),
2413 Args);
2414}
#define V(N, I)
static OffloadArch getOffloadArch(const CodeGenModule &CGM)
static void getTeamsReductionVars(ASTContext &Ctx, const OMPExecutableDirective &D, llvm::SmallVectorImpl< const ValueDecl * > &Vars)
Get list of reduction variables from the teams ... directives.
static llvm::Value * castValueToType(CodeGenFunction &CGF, llvm::Value *Val, QualType ValTy, QualType CastTy, SourceLocation Loc)
Cast value to the specified type.
static void getDistributeLastprivateVars(ASTContext &Ctx, const OMPExecutableDirective &D, llvm::SmallVectorImpl< const ValueDecl * > &Vars)
Get list of lastprivate variables from the teams distribute ... or teams {distribute ....
static bool hasNestedSPMDDirective(ASTContext &Ctx, const OMPExecutableDirective &D)
Check for inner (nested) SPMD construct, if any.
static bool supportsSPMDExecutionMode(ASTContext &Ctx, const OMPExecutableDirective &D)
This file defines OpenMP nodes for declarative directives.
This file defines OpenMP AST classes for clauses.
static std::pair< ValueDecl *, bool > getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc, SourceRange &ERange, bool AllowArraySection=false, bool AllowAssumedSizeArray=false, StringRef DiagType="")
This file defines OpenMP AST classes for executable directives and clauses.
static FieldDecl * Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, const IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable, InClassInitStyle InitStyle)
Definition Decl.cpp:4697
This represents 'ompx_bare' clause in the 'pragma omp target teams ...' directive.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:223
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
CanQualType VoidPtrTy
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,...
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
CanQualType VoidTy
QualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
const TargetInfo & getTargetInfo() const
Definition ASTContext.h:924
Attr - This represents one attribute.
Definition Attr.h:46
ArrayRef< Capture > captures() const
Definition Decl.h:4834
const BlockDecl * getBlockDecl() const
Definition Expr.h:6687
Expr * getCallee()
Definition Expr.h:3096
arg_range arguments()
Definition Expr.h:3201
Describes the capture of either a variable, or 'this', or variable-length array type.
Definition Stmt.h:3960
This captures a statement into a function.
Definition Stmt.h:3947
bool capturesVariable(const VarDecl *Var) const
True if this variable has been captured.
Definition Stmt.cpp:1517
capture_range captures()
Definition Stmt.h:4085
CastKind getCastKind() const
Definition Expr.h:3726
Expr * getSubExpr()
Definition Expr.h:3732
CharUnits - This is an opaque type for sizes expressed in character units.
Definition CharUnits.h:38
bool isZero() const
isZero - Test whether the quantity equals zero.
Definition CharUnits.h:122
llvm::Align getAsAlign() const
getAsAlign - Returns Quantity as a valid llvm::Align, Beware llvm::Align assumes power of two 8-bit b...
Definition CharUnits.h:189
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
Definition CharUnits.h:185
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
Address withElementType(llvm::Type *ElemTy) const
Return address with different element type, but same pointer and alignment.
Definition Address.h:276
llvm::StoreInst * CreateStore(llvm::Value *Val, Address Addr, bool IsVolatile=false)
Definition CGBuilder.h:146
Address CreatePointerBitCastOrAddrSpaceCast(Address Addr, llvm::Type *Ty, llvm::Type *ElementTy, const llvm::Twine &Name="")
Definition CGBuilder.h:213
Address CreateConstArrayGEP(Address Addr, uint64_t Index, const llvm::Twine &Name="")
Given addr = [n x T]* ... produce name = getelementptr inbounds addr, i64 0, i64 index where i64 is a...
Definition CGBuilder.h:251
Address CreateConstInBoundsGEP(Address Addr, uint64_t Index, const llvm::Twine &Name="")
Given addr = T* ... produce name = getelementptr inbounds addr, i64 index where i64 is actually the t...
Definition CGBuilder.h:271
CGFunctionInfo - Class to encapsulate the information about a function definition.
llvm::Function * emitTeamsOutlinedFunction(CodeGenFunction &CGF, const OMPExecutableDirective &D, const VarDecl *ThreadIDVar, OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen) override
Emits inlined function for the specified OpenMP teams.
void emitProcBindClause(CodeGenFunction &CGF, llvm::omp::ProcBindKind ProcBind, SourceLocation Loc) override
Emit call to void __kmpc_push_proc_bind(ident_t *loc, kmp_int32global_tid, int proc_bind) to generate...
void emitReduction(CodeGenFunction &CGF, SourceLocation Loc, ArrayRef< const Expr * > Privates, ArrayRef< const Expr * > LHSExprs, ArrayRef< const Expr * > RHSExprs, ArrayRef< const Expr * > ReductionOps, ReductionOptionsTy Options) override
Emit a code for reduction clause.
DataSharingMode
Target codegen is specialized based on two data-sharing modes: CUDA, in which the local variables are...
@ DS_Generic
Generic data-sharing mode.
void getDefaultDistScheduleAndChunk(CodeGenFunction &CGF, const OMPLoopDirective &S, OpenMPDistScheduleClauseKind &ScheduleKind, llvm::Value *&Chunk) const override
Choose a default value for the dist_schedule clause.
Address getAddressOfLocalVariable(CodeGenFunction &CGF, const VarDecl *VD) override
Gets the OpenMP-specific address of the local variable.
void emitFunctionProlog(CodeGenFunction &CGF, const Decl *D) override
Emits OpenMP-specific function prolog.
void getDefaultScheduleAndChunk(CodeGenFunction &CGF, const OMPLoopDirective &S, OpenMPScheduleClauseKind &ScheduleKind, const Expr *&ChunkExpr) const override
Choose a default value for the schedule clause.
void emitNumTeamsClause(CodeGenFunction &CGF, const Expr *NumTeams, const Expr *ThreadLimit, SourceLocation Loc) override
This function ought to emit, in the general case, a call to.
void emitCriticalRegion(CodeGenFunction &CGF, StringRef CriticalName, const RegionCodeGenTy &CriticalOpGen, SourceLocation Loc, const Expr *Hint=nullptr) override
Emits a critical region.
void emitTeamsCall(CodeGenFunction &CGF, const OMPExecutableDirective &D, SourceLocation Loc, llvm::Function *OutlinedFn, ArrayRef< llvm::Value * > CapturedVars) override
Emits code for teams call of the OutlinedFn with variables captured in a record which address is stor...
bool hasAllocateAttributeForGlobalVar(const VarDecl *VD, LangAS &AS) override
Checks if the variable has associated OMPAllocateDeclAttr attribute with the predefined allocator and...
void getKmpcFreeShared(CodeGenFunction &CGF, const std::pair< llvm::Value *, llvm::Value * > &AddrSizePair) override
Get call to __kmpc_free_shared.
llvm::Function * emitParallelOutlinedFunction(CodeGenFunction &CGF, const OMPExecutableDirective &D, const VarDecl *ThreadIDVar, OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen) override
Emits inlined function for the specified OpenMP parallel.
void functionFinished(CodeGenFunction &CGF) override
Cleans up references to the objects in finished function.
llvm::Value * getGPUThreadID(CodeGenFunction &CGF)
Get the id of the current thread on the GPU.
void processRequiresDirective(const OMPRequiresDecl *D) override
Perform check on requires decl to ensure that target architecture supports unified addressing.
bool isDelayedVariableLengthDecl(CodeGenFunction &CGF, const VarDecl *VD) const override
Declare generalized virtual functions which need to be defined by all specializations of OpenMPGPURun...
void emitOutlinedFunctionCall(CodeGenFunction &CGF, SourceLocation Loc, llvm::FunctionCallee OutlinedFn, ArrayRef< llvm::Value * > Args={}) const override
Emits call of the outlined function with the provided arguments, translating these arguments to corre...
Address getParameterAddress(CodeGenFunction &CGF, const VarDecl *NativeParam, const VarDecl *TargetParam) const override
Gets the address of the native argument basing on the address of the target-specific parameter.
ExecutionMode
Defines the execution mode.
@ EM_NonSPMD
Non-SPMD execution mode (1 master thread, others are workers).
@ EM_Unknown
Unknown execution mode (orphaned directive).
@ EM_SPMD
SPMD execution mode (all threads are worker threads).
void emitBarrierCall(CodeGenFunction &CGF, SourceLocation Loc, OpenMPDirectiveKind Kind, bool EmitChecks=true, bool ForceSimpleCall=false) override
Emit an implicit/explicit barrier for OpenMP threads.
llvm::Value * getGPUNumThreads(CodeGenFunction &CGF)
Get the maximum number of threads in a block of the GPU.
const VarDecl * translateParameter(const FieldDecl *FD, const VarDecl *NativeParam) const override
Translates the native parameter of outlined function if this is required for target.
std::pair< llvm::Value *, llvm::Value * > getKmpcAllocShared(CodeGenFunction &CGF, const VarDecl *VD) override
Get call to __kmpc_alloc_shared.
bool isGPU() const override
Returns true if the current target is a GPU.
llvm::Value * emitSeverityClause(OpenMPSeverityClauseKind Severity, SourceLocation Loc) override
llvm::Value * emitMessageClause(CodeGenFunction &CGF, const Expr *Message, SourceLocation Loc) override
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) override
Emits code for parallel or serial call of the OutlinedFn with variables captured in a record which ad...
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()) override
Emits call to void __kmpc_push_num_threads(ident_t *loc, kmp_int32global_tid, kmp_int32 num_threads) ...
void adjustTargetSpecificDataForLambdas(CodeGenFunction &CGF, const OMPExecutableDirective &D) const override
Adjust some parameters for the target-based directives, like addresses of the variables captured by r...
virtual Address emitThreadIDAddress(CodeGenFunction &CGF, SourceLocation Loc)
Emits address of the word in a memory where current thread id is stored.
static const Stmt * getSingleCompoundChild(ASTContext &Ctx, const Stmt *Body)
Checks if the Body is the CompoundStmt and returns its child statement iff there is only one that is ...
llvm::Value * emitUpdateLocation(CodeGenFunction &CGF, SourceLocation Loc, unsigned Flags=0, bool EmitLoc=false)
Emits object of ident_t type with info for source location.
virtual void functionFinished(CodeGenFunction &CGF)
Cleans up references to the objects in finished function.
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.
llvm::OpenMPIRBuilder OMPBuilder
An OpenMP-IR-Builder instance.
virtual void emitTargetOutlinedFunctionHelper(const OMPExecutableDirective &D, StringRef ParentName, llvm::Function *&OutlinedFn, llvm::Constant *&OutlinedFnID, bool IsOffloadEntry, const RegionCodeGenTy &CodeGen)
Helper to emit outlined function for 'target' directive.
bool hasRequiresUnifiedSharedMemory() const
Return whether the unified_shared_memory has been specified.
virtual void processRequiresDirective(const OMPRequiresDecl *D)
Perform check on requires decl to ensure that target architecture supports unified addressing.
llvm::Value * getThreadID(CodeGenFunction &CGF, SourceLocation Loc)
Gets thread id value for the current thread.
void computeMinAndMaxThreadsAndTeams(const OMPExecutableDirective &D, CodeGenFunction &CGF, llvm::OpenMPIRBuilder::TargetKernelDefaultAttrs &Attrs)
Helper to determine the min/max number of threads/teams for D.
static unsigned getDefaultFlagsForBarriers(OpenMPDirectiveKind Kind)
Returns default flags for the barriers depending on the directive, for which this barier is going to ...
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 getDefaultDistScheduleAndChunk(CodeGenFunction &CGF, const OMPLoopDirective &S, OpenMPDistScheduleClauseKind &ScheduleKind, llvm::Value *&Chunk) const
Choose default schedule type and chunk value for the dist_schedule clause.
llvm::Type * getIdentTyPointerTy()
Returns pointer to ident_t type.
void emitSingleReductionCombiner(CodeGenFunction &CGF, const Expr *ReductionOp, const Expr *PrivateRef, const DeclRefExpr *LHS, const DeclRefExpr *RHS)
Emits single reduction combiner.
llvm::OpenMPIRBuilder & getOMPBuilder()
virtual void emitCriticalRegion(CodeGenFunction &CGF, StringRef CriticalName, const RegionCodeGenTy &CriticalOpGen, SourceLocation Loc, const Expr *Hint=nullptr)
Emits a critical region.
virtual void emitOutlinedFunctionCall(CodeGenFunction &CGF, SourceLocation Loc, llvm::FunctionCallee OutlinedFn, ArrayRef< llvm::Value * > Args={}) const
Emits call of the outlined function with the provided arguments, translating these arguments to corre...
virtual void emitReduction(CodeGenFunction &CGF, SourceLocation Loc, ArrayRef< const Expr * > Privates, ArrayRef< const Expr * > LHSExprs, ArrayRef< const Expr * > RHSExprs, ArrayRef< const Expr * > ReductionOps, ReductionOptionsTy Options)
Emit a code for reduction clause.
The scope used to remap some variables as private in the OpenMP loop body (or other captured region e...
CodeGenFunction - This class organizes the per-function state that is used while generating LLVM code...
LValue EmitLoadOfReferenceLValue(LValue RefLVal)
Definition CGExpr.cpp:3436
CGCapturedStmtInfo * CapturedStmtInfo
llvm::BasicBlock * createBasicBlock(const Twine &name="", llvm::Function *parent=nullptr, llvm::BasicBlock *before=nullptr)
createBasicBlock - Create an LLVM basic block.
Address EmitLoadOfPointer(Address Ptr, const PointerType *PtrTy, LValueBaseInfo *BaseInfo=nullptr, TBAAAccessInfo *TBAAInfo=nullptr)
Load a pointer with type PtrTy stored at address Ptr.
Definition CGExpr.cpp:3445
LValue MakeNaturalAlignPointeeRawAddrLValue(llvm::Value *V, QualType T)
Same as MakeNaturalAlignPointeeAddrLValue except that the pointer is known to be unsigned.
llvm::AssertingVH< llvm::Instruction > AllocaInsertPt
AllocaInsertPoint - This is an instruction in the entry block before which we prefer to insert alloca...
llvm::DebugLoc SourceLocToDebugLoc(SourceLocation Location)
Converts Location to a DebugLoc, if debug information is enabled.
RawAddress CreateDefaultAlignTempAlloca(llvm::Type *Ty, const Twine &Name="tmp")
CreateDefaultAlignedTempAlloca - This creates an alloca with the default ABI alignment of the given L...
Definition CGExpr.cpp:183
const TargetInfo & getTarget() const
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.
llvm::Value * EvaluateExprAsBool(const Expr *E)
EvaluateExprAsBool - Perform the usual unary conversions on the specified expression and compare the ...
Definition CGExpr.cpp:240
bool HaveInsertPoint() const
HaveInsertPoint - True if an insertion point is defined.
llvm::Value * getTypeSize(QualType Ty)
Returns calculated size of the specified type.
LValue EmitLValueForFieldInitialization(LValue Base, const FieldDecl *Field)
EmitLValueForFieldInitialization - Like EmitLValueForField, except that if the Field is a reference,...
Definition CGExpr.cpp:5963
RawAddress CreateMemTempWithoutCast(QualType T, const Twine &Name="tmp")
CreateMemTemp - Create a temporary memory object of the given type, with appropriate alignmen without...
Definition CGExpr.cpp:232
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...
llvm::CallInst * EmitRuntimeCall(llvm::FunctionCallee callee, const Twine &name="")
llvm::Type * ConvertTypeForMem(QualType T)
CodeGenTypes & getTypes() const
static TypeEvaluationKind getEvaluationKind(QualType T)
getEvaluationKind - Return the TypeEvaluationKind of QualType T.
void EmitBranch(llvm::BasicBlock *Block)
EmitBranch - Emit a branch to the specified basic block from the current insert block,...
Definition CGStmt.cpp:663
RawAddress CreateMemTemp(QualType T, const Twine &Name="tmp", RawAddress *Alloca=nullptr)
CreateMemTemp - Create a temporary memory object of the given type, with appropriate alignmen and cas...
Definition CGExpr.cpp:196
LValue MakeAddrLValue(Address Addr, QualType T, AlignmentSource Source=AlignmentSource::Type)
void FinishFunction(SourceLocation EndLoc=SourceLocation())
FinishFunction - Complete IR generation of the current function.
llvm::Value * LoadCXXThis()
LoadCXXThis - Load the value of 'this'.
Address GetAddrOfLocalVar(const VarDecl *VD)
GetAddrOfLocalVar - Return the address of a local variable.
llvm::LLVMContext & getLLVMContext()
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...
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 EmitBlock(llvm::BasicBlock *BB, bool IsFinished=false)
EmitBlock - Emit the given block.
Definition CGStmt.cpp:643
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
const TargetInfo & getTarget() const
CGOpenMPRuntime & getOpenMPRuntime()
Return a reference to the configured OpenMP runtime.
ASTContext & getContext() const
llvm::LLVMContext & getLLVMContext()
llvm::FunctionType * GetFunctionType(const CGFunctionInfo &Info)
GetFunctionType - Get the LLVM function type for.
Definition CGCall.cpp:1987
const CGFunctionInfo & arrangeBuiltinFunctionDeclaration(QualType resultType, const FunctionArgList &args)
A builtin function is a freestanding function using the default C conventions.
Definition CGCall.cpp:747
unsigned getTargetAddressSpace(QualType T) const
FunctionArgList - Type for representing both the decl and type of parameters to a function.
Definition CGCall.h:377
LValue - This represents an lvalue references.
Definition CGValue.h:183
Address getAddress() const
Definition CGValue.h:373
A basic class for pre|post-action for advanced codegen sequence for OpenMP region.
An abstract representation of an aligned address.
Definition Address.h:42
llvm::Value * getPointer() const
Definition Address.h:66
Class provides a way to call simple version of codegen for OpenMP region, or an advanced with possibl...
void setAction(PrePostActionTy &Action) const
ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition DeclBase.h:1466
void addDecl(Decl *D)
Add the declaration D into this context.
ValueDecl * getDecl()
Definition Expr.h:1344
decl_range decls()
Definition Stmt.h:1689
T * getAttr() const
Definition DeclBase.h:581
bool hasAttrs() const
Definition DeclBase.h:526
attr_iterator attr_end() const
Definition DeclBase.h:550
bool isCanonicalDecl() const
Whether this particular Decl is a canonical one.
Definition DeclBase.h:1001
attr_iterator attr_begin() const
Definition DeclBase.h:547
SourceLocation getLocation() const
Definition DeclBase.h:447
DeclContext * getDeclContext()
Definition DeclBase.h:456
SourceLocation getBeginLoc() const LLVM_READONLY
Definition DeclBase.h:439
AttrVec & getAttrs()
Definition DeclBase.h:532
bool hasAttr() const
Definition DeclBase.h:585
virtual Decl * getCanonicalDecl()
Retrieves the "canonical" declaration of the given declaration.
Definition DeclBase.h:995
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Decl.h:831
This represents one expression.
Definition Expr.h:112
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Definition Expr.cpp:3099
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Definition Expr.cpp:3095
bool isLValue() const
isLValue - True if this expression is an "l-value" according to the rules of the current language.
Definition Expr.h:284
Represents a member of a struct/union/class.
Definition Decl.h:3195
static FieldDecl * Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, const IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable, InClassInitStyle InitStyle)
Definition Decl.cpp:4697
GlobalDecl - represents a global declaration.
Definition GlobalDecl.h:57
static ImplicitParamDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation IdLoc, const IdentifierInfo *Id, QualType T, ImplicitParamKind ParamKind)
Create implicit parameter.
Definition Decl.cpp:5599
static IntegerLiteral * Create(const ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l)
Returns a new integer literal with value 'V' and type 'type'.
Definition Expr.cpp:981
Describes the capture of a variable or of this, or of a C++1y init-capture.
bool isInitCapture(const LambdaCapture *Capture) const
Determine whether one of this lambda's captures is an init-capture.
Definition ExprCXX.cpp:1365
capture_range captures() const
Retrieve this lambda's captures.
Definition ExprCXX.cpp:1378
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition Decl.h:295
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition Decl.h:301
This is a basic class for representing single OpenMP clause.
This represents 'pragma omp requires...' directive.
Definition DeclOpenMP.h:479
clauselist_range clauselists()
Definition DeclOpenMP.h:504
static ParmVarDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, const IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass S, Expr *DefArg)
Definition Decl.cpp:2934
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition TypeBase.h:3392
A (possibly-)qualified type.
Definition TypeBase.h:937
LangAS getAddressSpace() const
Return the address space of this type.
Definition TypeBase.h:8573
QualType getNonReferenceType() const
If Type is a reference type (e.g., const int&), returns the type that the reference refers to ("const...
Definition TypeBase.h:8632
QualType getCanonicalType() const
Definition TypeBase.h:8499
A qualifier set is used to build a set of qualifiers.
Definition TypeBase.h:8387
const Type * strip(QualType type)
Collect any qualifiers on the given type and return an unqualified type.
Definition TypeBase.h:8394
QualType apply(const ASTContext &Context, QualType QT) const
Apply the collected qualifiers to the given type.
Definition Type.cpp:4796
Represents a struct/union/class.
Definition Decl.h:4360
virtual void completeDefinition()
Note that the definition of this type is now complete.
Definition Decl.cpp:5288
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.
Stmt - This represents one statement.
Definition Stmt.h:86
child_range children()
Definition Stmt.cpp:304
void startDefinition()
Starts the definition of this tag declaration.
Definition Decl.cpp:4903
unsigned getNewAlign() const
Return the largest alignment for which a suitably-sized allocation with 'operator new(size_t)' is gua...
Definition TargetInfo.h:767
TargetOptions & getTargetOpts() const
Retrieve the target options.
Definition TargetInfo.h:327
virtual const llvm::omp::GV & getGridValue() const
std::string CPU
If given, the name of the target CPU to generate code for.
The base class of the type hierarchy.
Definition TypeBase.h:1875
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition Type.h:26
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
Definition TypeBase.h:9094
bool isReferenceType() const
Definition TypeBase.h:8708
bool isLValueReferenceType() const
Definition TypeBase.h:8712
bool hasSignedIntegerRepresentation() const
Determine whether this type has an signed integer representation of some sort, e.g....
Definition Type.cpp:2314
bool isVariablyModifiedType() const
Whether this type is a variably-modified type (C99 6.7.5).
Definition TypeBase.h:2864
Expr * getSubExpr() const
Definition Expr.h:2291
Opcode getOpcode() const
Definition Expr.h:2286
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:712
QualType getType() const
Definition Decl.h:723
bool isInitCapture() const
Whether this variable is the implicit variable for a lambda init-capture.
Definition Decl.cpp:5584
Represents a variable declaration or definition.
Definition Decl.h:932
VarDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
Definition Decl.cpp:2236
bool isInitCapture() const
Whether this variable is the implicit variable for a lambda init-capture.
Definition Decl.h:1600
specific_attr_iterator - Iterates over a subrange of an AttrVec, only providing attributes that are o...
@ 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
The JSON file list parser is used to communicate input to InstallAPI.
CanQual< Type > CanQualType
Represents a canonical, potentially-qualified type.
Privates[]
This class represents the 'transparent' clause in the 'pragma omp task' directive.
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ ICIS_NoInit
No in-class initializer.
Definition Specifiers.h:273
bool isOpenMPDistributeDirective(OpenMPDirectiveKind DKind)
Checks if the specified directive is a distribute directive.
@ LCK_ByRef
Capturing by reference.
Definition Lambda.h:37
@ Private
'private' clause, allowed on 'parallel', 'serial', 'loop', 'parallel loop', and 'serial loop' constru...
@ AS_public
Definition Specifiers.h:125
@ CR_OpenMP
bool isOpenMPParallelDirective(OpenMPDirectiveKind DKind)
Checks if the specified directive is a parallel-kind directive.
bool isOpenMPPrivate(OpenMPClauseKind Kind)
Checks if the specified clause is one of private clauses like 'private', 'firstprivate',...
@ SC_None
Definition Specifiers.h:251
OpenMPDistScheduleClauseKind
OpenMP attributes for 'dist_schedule' clause.
bool isOpenMPTargetExecutionDirective(OpenMPDirectiveKind DKind)
Checks if the specified directive is a target code offload directive.
bool isOpenMPTeamsDirective(OpenMPDirectiveKind DKind)
Checks if the specified directive is a teams-kind directive.
OffloadArch StringToOffloadArch(llvm::StringRef S)
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 ...
LangAS
Defines the address space values used by the address space qualifier of QualType.
const char * OffloadArchToString(OffloadArch A)
llvm::omp::Directive OpenMPDirectiveKind
OpenMP directives.
Definition OpenMPKinds.h:25
void getOpenMPCaptureRegions(llvm::SmallVectorImpl< OpenMPDirectiveKind > &CaptureRegions, OpenMPDirectiveKind DKind)
Return the captured regions of an OpenMP directive.
OpenMPNumThreadsClauseModifier
U cast(CodeGen::Address addr)
Definition Address.h:327
@ CXXThis
Parameter for C++ 'this' argument.
Definition Decl.h:1760
@ Other
Other implicit parameter.
Definition Decl.h:1772
OpenMPScheduleClauseKind
OpenMP attributes for 'schedule' clause.
Definition OpenMPKinds.h:31
unsigned long uint64_t