clang 24.0.0git
CGOpenMPRuntime.cpp
Go to the documentation of this file.
1//===----- CGOpenMPRuntime.cpp - Interface to OpenMP 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 class for OpenMP runtime code generation.
10//
11//===----------------------------------------------------------------------===//
12
13#include "CGOpenMPRuntime.h"
14#include "ABIInfoImpl.h"
15#include "CGCXXABI.h"
16#include "CGCleanup.h"
17#include "CGDebugInfo.h"
18#include "CGRecordLayout.h"
19#include "CodeGenFunction.h"
20#include "TargetInfo.h"
21#include "clang/AST/APValue.h"
22#include "clang/AST/Attr.h"
23#include "clang/AST/Decl.h"
32#include "llvm/ADT/ArrayRef.h"
33#include "llvm/ADT/SmallSet.h"
34#include "llvm/ADT/SmallVector.h"
35#include "llvm/ADT/StringExtras.h"
36#include "llvm/Bitcode/BitcodeReader.h"
37#include "llvm/IR/Constants.h"
38#include "llvm/IR/DerivedTypes.h"
39#include "llvm/IR/GlobalValue.h"
40#include "llvm/IR/InstrTypes.h"
41#include "llvm/IR/Value.h"
42#include "llvm/Support/AtomicOrdering.h"
43#include "llvm/Support/VirtualFileSystem.h"
44#include "llvm/Support/raw_ostream.h"
45#include <cassert>
46#include <cstdint>
47#include <numeric>
48#include <optional>
49
50using namespace clang;
51using namespace CodeGen;
52using namespace llvm::omp;
53
54namespace {
55/// Base class for handling code generation inside OpenMP regions.
56class CGOpenMPRegionInfo : public CodeGenFunction::CGCapturedStmtInfo {
57public:
58 /// Kinds of OpenMP regions used in codegen.
59 enum CGOpenMPRegionKind {
60 /// Region with outlined function for standalone 'parallel'
61 /// directive.
62 ParallelOutlinedRegion,
63 /// Region with outlined function for standalone 'task' directive.
64 TaskOutlinedRegion,
65 /// Region for constructs that do not require function outlining,
66 /// like 'for', 'sections', 'atomic' etc. directives.
67 InlinedRegion,
68 /// Region with outlined function for standalone 'target' directive.
69 TargetRegion,
70 };
71
72 CGOpenMPRegionInfo(const CapturedStmt &CS,
73 const CGOpenMPRegionKind RegionKind,
74 const RegionCodeGenTy &CodeGen, OpenMPDirectiveKind Kind,
75 bool HasCancel)
76 : CGCapturedStmtInfo(CS, CR_OpenMP), RegionKind(RegionKind),
77 CodeGen(CodeGen), Kind(Kind), HasCancel(HasCancel) {}
78
79 CGOpenMPRegionInfo(const CGOpenMPRegionKind RegionKind,
80 const RegionCodeGenTy &CodeGen, OpenMPDirectiveKind Kind,
81 bool HasCancel)
82 : CGCapturedStmtInfo(CR_OpenMP), RegionKind(RegionKind), CodeGen(CodeGen),
83 Kind(Kind), HasCancel(HasCancel) {}
84
85 /// Get a variable or parameter for storing global thread id
86 /// inside OpenMP construct.
87 virtual const VarDecl *getThreadIDVariable() const = 0;
88
89 /// Emit the captured statement body.
90 void EmitBody(CodeGenFunction &CGF, const Stmt *S) override;
91
92 /// Get an LValue for the current ThreadID variable.
93 /// \return LValue for thread id variable. This LValue always has type int32*.
94 virtual LValue getThreadIDVariableLValue(CodeGenFunction &CGF);
95
96 virtual void emitUntiedSwitch(CodeGenFunction & /*CGF*/) {}
97
98 CGOpenMPRegionKind getRegionKind() const { return RegionKind; }
99
100 OpenMPDirectiveKind getDirectiveKind() const { return Kind; }
101
102 bool hasCancel() const { return HasCancel; }
103
104 static bool classof(const CGCapturedStmtInfo *Info) {
105 return Info->getKind() == CR_OpenMP;
106 }
107
108 ~CGOpenMPRegionInfo() override = default;
109
110protected:
111 CGOpenMPRegionKind RegionKind;
112 RegionCodeGenTy CodeGen;
114 bool HasCancel;
115};
116
117/// API for captured statement code generation in OpenMP constructs.
118class CGOpenMPOutlinedRegionInfo final : public CGOpenMPRegionInfo {
119public:
120 CGOpenMPOutlinedRegionInfo(const CapturedStmt &CS, const VarDecl *ThreadIDVar,
121 const RegionCodeGenTy &CodeGen,
122 OpenMPDirectiveKind Kind, bool HasCancel,
123 StringRef HelperName)
124 : CGOpenMPRegionInfo(CS, ParallelOutlinedRegion, CodeGen, Kind,
125 HasCancel),
126 ThreadIDVar(ThreadIDVar), HelperName(HelperName) {
127 assert(ThreadIDVar != nullptr && "No ThreadID in OpenMP region.");
128 }
129
130 /// Get a variable or parameter for storing global thread id
131 /// inside OpenMP construct.
132 const VarDecl *getThreadIDVariable() const override { return ThreadIDVar; }
133
134 /// Get the name of the capture helper.
135 StringRef getHelperName() const override { return HelperName; }
136
137 static bool classof(const CGCapturedStmtInfo *Info) {
138 return CGOpenMPRegionInfo::classof(Info) &&
139 cast<CGOpenMPRegionInfo>(Info)->getRegionKind() ==
140 ParallelOutlinedRegion;
141 }
142
143private:
144 /// A variable or parameter storing global thread id for OpenMP
145 /// constructs.
146 const VarDecl *ThreadIDVar;
147 StringRef HelperName;
148};
149
150/// API for captured statement code generation in OpenMP constructs.
151class CGOpenMPTaskOutlinedRegionInfo final : public CGOpenMPRegionInfo {
152public:
153 class UntiedTaskActionTy final : public PrePostActionTy {
154 bool Untied;
155 const VarDecl *PartIDVar;
156 const RegionCodeGenTy UntiedCodeGen;
157 llvm::SwitchInst *UntiedSwitch = nullptr;
158
159 public:
160 UntiedTaskActionTy(bool Tied, const VarDecl *PartIDVar,
161 const RegionCodeGenTy &UntiedCodeGen)
162 : Untied(!Tied), PartIDVar(PartIDVar), UntiedCodeGen(UntiedCodeGen) {}
163 void Enter(CodeGenFunction &CGF) override {
164 if (Untied) {
165 // Emit task switching point.
166 LValue PartIdLVal = CGF.EmitLoadOfPointerLValue(
167 CGF.GetAddrOfLocalVar(PartIDVar),
168 PartIDVar->getType()->castAs<PointerType>());
169 llvm::Value *Res =
170 CGF.EmitLoadOfScalar(PartIdLVal, PartIDVar->getLocation());
171 llvm::BasicBlock *DoneBB = CGF.createBasicBlock(".untied.done.");
172 UntiedSwitch = CGF.Builder.CreateSwitch(Res, DoneBB);
173 CGF.EmitBlock(DoneBB);
175 CGF.EmitBlock(CGF.createBasicBlock(".untied.jmp."));
176 UntiedSwitch->addCase(CGF.Builder.getInt32(0),
177 CGF.Builder.GetInsertBlock());
178 emitUntiedSwitch(CGF);
179 }
180 }
181 void emitUntiedSwitch(CodeGenFunction &CGF) const {
182 if (Untied) {
183 LValue PartIdLVal = CGF.EmitLoadOfPointerLValue(
184 CGF.GetAddrOfLocalVar(PartIDVar),
185 PartIDVar->getType()->castAs<PointerType>());
186 CGF.EmitStoreOfScalar(CGF.Builder.getInt32(UntiedSwitch->getNumCases()),
187 PartIdLVal);
188 UntiedCodeGen(CGF);
189 CodeGenFunction::JumpDest CurPoint =
190 CGF.getJumpDestInCurrentScope(".untied.next.");
192 CGF.EmitBlock(CGF.createBasicBlock(".untied.jmp."));
193 UntiedSwitch->addCase(CGF.Builder.getInt32(UntiedSwitch->getNumCases()),
194 CGF.Builder.GetInsertBlock());
195 CGF.EmitBranchThroughCleanup(CurPoint);
196 CGF.EmitBlock(CurPoint.getBlock());
197 }
198 }
199 unsigned getNumberOfParts() const { return UntiedSwitch->getNumCases(); }
200 };
201 CGOpenMPTaskOutlinedRegionInfo(const CapturedStmt &CS,
202 const VarDecl *ThreadIDVar,
203 const RegionCodeGenTy &CodeGen,
204 OpenMPDirectiveKind Kind, bool HasCancel,
205 const UntiedTaskActionTy &Action)
206 : CGOpenMPRegionInfo(CS, TaskOutlinedRegion, CodeGen, Kind, HasCancel),
207 ThreadIDVar(ThreadIDVar), Action(Action) {
208 assert(ThreadIDVar != nullptr && "No ThreadID in OpenMP region.");
209 }
210
211 /// Get a variable or parameter for storing global thread id
212 /// inside OpenMP construct.
213 const VarDecl *getThreadIDVariable() const override { return ThreadIDVar; }
214
215 /// Get an LValue for the current ThreadID variable.
216 LValue getThreadIDVariableLValue(CodeGenFunction &CGF) override;
217
218 /// Get the name of the capture helper.
219 StringRef getHelperName() const override { return ".omp_outlined."; }
220
221 void emitUntiedSwitch(CodeGenFunction &CGF) override {
222 Action.emitUntiedSwitch(CGF);
223 }
224
225 static bool classof(const CGCapturedStmtInfo *Info) {
226 return CGOpenMPRegionInfo::classof(Info) &&
227 cast<CGOpenMPRegionInfo>(Info)->getRegionKind() ==
228 TaskOutlinedRegion;
229 }
230
231private:
232 /// A variable or parameter storing global thread id for OpenMP
233 /// constructs.
234 const VarDecl *ThreadIDVar;
235 /// Action for emitting code for untied tasks.
236 const UntiedTaskActionTy &Action;
237};
238
239/// API for inlined captured statement code generation in OpenMP
240/// constructs.
241class CGOpenMPInlinedRegionInfo : public CGOpenMPRegionInfo {
242public:
243 CGOpenMPInlinedRegionInfo(CodeGenFunction::CGCapturedStmtInfo *OldCSI,
244 const RegionCodeGenTy &CodeGen,
245 OpenMPDirectiveKind Kind, bool HasCancel)
246 : CGOpenMPRegionInfo(InlinedRegion, CodeGen, Kind, HasCancel),
247 OldCSI(OldCSI),
248 OuterRegionInfo(dyn_cast_or_null<CGOpenMPRegionInfo>(OldCSI)) {}
249
250 // Retrieve the value of the context parameter.
251 llvm::Value *getContextValue() const override {
252 if (OuterRegionInfo)
253 return OuterRegionInfo->getContextValue();
254 llvm_unreachable("No context value for inlined OpenMP region");
255 }
256
257 void setContextValue(llvm::Value *V) override {
258 if (OuterRegionInfo) {
259 OuterRegionInfo->setContextValue(V);
260 return;
261 }
262 llvm_unreachable("No context value for inlined OpenMP region");
263 }
264
265 /// Lookup the captured field decl for a variable.
266 const FieldDecl *lookup(const VarDecl *VD) const override {
267 if (OuterRegionInfo)
268 return OuterRegionInfo->lookup(VD);
269 // If there is no outer outlined region,no need to lookup in a list of
270 // captured variables, we can use the original one.
271 return nullptr;
272 }
273
274 FieldDecl *getThisFieldDecl() const override {
275 if (OuterRegionInfo)
276 return OuterRegionInfo->getThisFieldDecl();
277 return nullptr;
278 }
279
280 /// Get a variable or parameter for storing global thread id
281 /// inside OpenMP construct.
282 const VarDecl *getThreadIDVariable() const override {
283 if (OuterRegionInfo)
284 return OuterRegionInfo->getThreadIDVariable();
285 return nullptr;
286 }
287
288 /// Get an LValue for the current ThreadID variable.
289 LValue getThreadIDVariableLValue(CodeGenFunction &CGF) override {
290 if (OuterRegionInfo)
291 return OuterRegionInfo->getThreadIDVariableLValue(CGF);
292 llvm_unreachable("No LValue for inlined OpenMP construct");
293 }
294
295 /// Get the name of the capture helper.
296 StringRef getHelperName() const override {
297 if (auto *OuterRegionInfo = getOldCSI())
298 return OuterRegionInfo->getHelperName();
299 llvm_unreachable("No helper name for inlined OpenMP construct");
300 }
301
302 void emitUntiedSwitch(CodeGenFunction &CGF) override {
303 if (OuterRegionInfo)
304 OuterRegionInfo->emitUntiedSwitch(CGF);
305 }
306
307 CodeGenFunction::CGCapturedStmtInfo *getOldCSI() const { return OldCSI; }
308
309 static bool classof(const CGCapturedStmtInfo *Info) {
310 return CGOpenMPRegionInfo::classof(Info) &&
311 cast<CGOpenMPRegionInfo>(Info)->getRegionKind() == InlinedRegion;
312 }
313
314 ~CGOpenMPInlinedRegionInfo() override = default;
315
316private:
317 /// CodeGen info about outer OpenMP region.
318 CodeGenFunction::CGCapturedStmtInfo *OldCSI;
319 CGOpenMPRegionInfo *OuterRegionInfo;
320};
321
322/// API for captured statement code generation in OpenMP target
323/// constructs. For this captures, implicit parameters are used instead of the
324/// captured fields. The name of the target region has to be unique in a given
325/// application so it is provided by the client, because only the client has
326/// the information to generate that.
327class CGOpenMPTargetRegionInfo final : public CGOpenMPRegionInfo {
328public:
329 CGOpenMPTargetRegionInfo(const CapturedStmt &CS,
330 const RegionCodeGenTy &CodeGen, StringRef HelperName)
331 : CGOpenMPRegionInfo(CS, TargetRegion, CodeGen, OMPD_target,
332 /*HasCancel=*/false),
333 HelperName(HelperName) {}
334
335 /// This is unused for target regions because each starts executing
336 /// with a single thread.
337 const VarDecl *getThreadIDVariable() const override { return nullptr; }
338
339 /// Get the name of the capture helper.
340 StringRef getHelperName() const override { return HelperName; }
341
342 static bool classof(const CGCapturedStmtInfo *Info) {
343 return CGOpenMPRegionInfo::classof(Info) &&
344 cast<CGOpenMPRegionInfo>(Info)->getRegionKind() == TargetRegion;
345 }
346
347private:
348 StringRef HelperName;
349};
350
351static void EmptyCodeGen(CodeGenFunction &, PrePostActionTy &) {
352 llvm_unreachable("No codegen for expressions");
353}
354/// API for generation of expressions captured in a innermost OpenMP
355/// region.
356class CGOpenMPInnerExprInfo final : public CGOpenMPInlinedRegionInfo {
357public:
358 CGOpenMPInnerExprInfo(CodeGenFunction &CGF, const CapturedStmt &CS)
359 : CGOpenMPInlinedRegionInfo(CGF.CapturedStmtInfo, EmptyCodeGen,
360 OMPD_unknown,
361 /*HasCancel=*/false),
362 PrivScope(CGF) {
363 // Make sure the globals captured in the provided statement are local by
364 // using the privatization logic. We assume the same variable is not
365 // captured more than once.
366 for (const auto &C : CS.captures()) {
367 if (!C.capturesVariable() && !C.capturesVariableByCopy())
368 continue;
369
370 const VarDecl *VD = C.getCapturedVar();
371 if (VD->isLocalVarDeclOrParm())
372 continue;
373
374 DeclRefExpr DRE(CGF.getContext(), const_cast<VarDecl *>(VD),
375 /*RefersToEnclosingVariableOrCapture=*/false,
376 VD->getType().getNonReferenceType(), VK_LValue,
377 C.getLocation());
378 PrivScope.addPrivate(VD, CGF.EmitLValue(&DRE).getAddress());
379 }
380 (void)PrivScope.Privatize();
381 }
382
383 /// Lookup the captured field decl for a variable.
384 const FieldDecl *lookup(const VarDecl *VD) const override {
385 if (const FieldDecl *FD = CGOpenMPInlinedRegionInfo::lookup(VD))
386 return FD;
387 return nullptr;
388 }
389
390 /// Emit the captured statement body.
391 void EmitBody(CodeGenFunction &CGF, const Stmt *S) override {
392 llvm_unreachable("No body for expressions");
393 }
394
395 /// Get a variable or parameter for storing global thread id
396 /// inside OpenMP construct.
397 const VarDecl *getThreadIDVariable() const override {
398 llvm_unreachable("No thread id for expressions");
399 }
400
401 /// Get the name of the capture helper.
402 StringRef getHelperName() const override {
403 llvm_unreachable("No helper name for expressions");
404 }
405
406 static bool classof(const CGCapturedStmtInfo *Info) { return false; }
407
408private:
409 /// Private scope to capture global variables.
410 CodeGenFunction::OMPPrivateScope PrivScope;
411};
412
413/// RAII for emitting code of OpenMP constructs.
414class InlinedOpenMPRegionRAII {
415 CodeGenFunction &CGF;
416 llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
417 FieldDecl *LambdaThisCaptureField = nullptr;
418 const CodeGen::CGBlockInfo *BlockInfo = nullptr;
419 bool NoInheritance = false;
420
421public:
422 /// Constructs region for combined constructs.
423 /// \param CodeGen Code generation sequence for combined directives. Includes
424 /// a list of functions used for code generation of implicitly inlined
425 /// regions.
426 InlinedOpenMPRegionRAII(CodeGenFunction &CGF, const RegionCodeGenTy &CodeGen,
427 OpenMPDirectiveKind Kind, bool HasCancel,
428 bool NoInheritance = true)
429 : CGF(CGF), NoInheritance(NoInheritance) {
430 // Start emission for the construct.
431 CGF.CapturedStmtInfo = new CGOpenMPInlinedRegionInfo(
432 CGF.CapturedStmtInfo, CodeGen, Kind, HasCancel);
433 if (NoInheritance) {
434 std::swap(CGF.LambdaCaptureFields, LambdaCaptureFields);
435 LambdaThisCaptureField = CGF.LambdaThisCaptureField;
436 CGF.LambdaThisCaptureField = nullptr;
437 BlockInfo = CGF.BlockInfo;
438 CGF.BlockInfo = nullptr;
439 }
440 }
441
442 ~InlinedOpenMPRegionRAII() {
443 // Restore original CapturedStmtInfo only if we're done with code emission.
444 auto *OldCSI =
445 cast<CGOpenMPInlinedRegionInfo>(CGF.CapturedStmtInfo)->getOldCSI();
446 delete CGF.CapturedStmtInfo;
447 CGF.CapturedStmtInfo = OldCSI;
448 if (NoInheritance) {
449 std::swap(CGF.LambdaCaptureFields, LambdaCaptureFields);
450 CGF.LambdaThisCaptureField = LambdaThisCaptureField;
451 CGF.BlockInfo = BlockInfo;
452 }
453 }
454};
455
456/// Values for bit flags used in the ident_t to describe the fields.
457/// All enumeric elements are named and described in accordance with the code
458/// from https://github.com/llvm/llvm-project/blob/main/openmp/runtime/src/kmp.h
459enum OpenMPLocationFlags : unsigned {
460 /// Use trampoline for internal microtask.
461 OMP_IDENT_IMD = 0x01,
462 /// Use c-style ident structure.
463 OMP_IDENT_KMPC = 0x02,
464 /// Atomic reduction option for kmpc_reduce.
465 OMP_ATOMIC_REDUCE = 0x10,
466 /// Explicit 'barrier' directive.
467 OMP_IDENT_BARRIER_EXPL = 0x20,
468 /// Implicit barrier in code.
469 OMP_IDENT_BARRIER_IMPL = 0x40,
470 /// Implicit barrier in 'for' directive.
471 OMP_IDENT_BARRIER_IMPL_FOR = 0x40,
472 /// Implicit barrier in 'sections' directive.
473 OMP_IDENT_BARRIER_IMPL_SECTIONS = 0xC0,
474 /// Implicit barrier in 'single' directive.
475 OMP_IDENT_BARRIER_IMPL_SINGLE = 0x140,
476 /// Call of __kmp_for_static_init for static loop.
477 OMP_IDENT_WORK_LOOP = 0x200,
478 /// Call of __kmp_for_static_init for sections.
479 OMP_IDENT_WORK_SECTIONS = 0x400,
480 /// Call of __kmp_for_static_init for distribute.
481 OMP_IDENT_WORK_DISTRIBUTE = 0x800,
482 LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/OMP_IDENT_WORK_DISTRIBUTE)
483};
484
485/// Describes ident structure that describes a source location.
486/// All descriptions are taken from
487/// https://github.com/llvm/llvm-project/blob/main/openmp/runtime/src/kmp.h
488/// Original structure:
489/// typedef struct ident {
490/// kmp_int32 reserved_1; /**< might be used in Fortran;
491/// see above */
492/// kmp_int32 flags; /**< also f.flags; KMP_IDENT_xxx flags;
493/// KMP_IDENT_KMPC identifies this union
494/// member */
495/// kmp_int32 reserved_2; /**< not really used in Fortran any more;
496/// see above */
497///#if USE_ITT_BUILD
498/// /* but currently used for storing
499/// region-specific ITT */
500/// /* contextual information. */
501///#endif /* USE_ITT_BUILD */
502/// kmp_int32 reserved_3; /**< source[4] in Fortran, do not use for
503/// C++ */
504/// char const *psource; /**< String describing the source location.
505/// The string is composed of semi-colon separated
506// fields which describe the source file,
507/// the function and a pair of line numbers that
508/// delimit the construct.
509/// */
510/// } ident_t;
511enum IdentFieldIndex {
512 /// might be used in Fortran
513 IdentField_Reserved_1,
514 /// OMP_IDENT_xxx flags; OMP_IDENT_KMPC identifies this union member.
515 IdentField_Flags,
516 /// Not really used in Fortran any more
517 IdentField_Reserved_2,
518 /// Source[4] in Fortran, do not use for C++
519 IdentField_Reserved_3,
520 /// String describing the source location. The string is composed of
521 /// semi-colon separated fields which describe the source file, the function
522 /// and a pair of line numbers that delimit the construct.
523 IdentField_PSource
524};
525
526/// Schedule types for 'omp for' loops (these enumerators are taken from
527/// the enum sched_type in kmp.h).
528enum OpenMPSchedType {
529 /// Lower bound for default (unordered) versions.
530 OMP_sch_lower = 32,
531 OMP_sch_static_chunked = 33,
532 OMP_sch_static = 34,
533 OMP_sch_dynamic_chunked = 35,
534 OMP_sch_guided_chunked = 36,
535 OMP_sch_runtime = 37,
536 OMP_sch_auto = 38,
537 /// static with chunk adjustment (e.g., simd)
538 OMP_sch_static_balanced_chunked = 45,
539 /// Lower bound for 'ordered' versions.
540 OMP_ord_lower = 64,
541 OMP_ord_static_chunked = 65,
542 OMP_ord_static = 66,
543 OMP_ord_dynamic_chunked = 67,
544 OMP_ord_guided_chunked = 68,
545 OMP_ord_runtime = 69,
546 OMP_ord_auto = 70,
547 OMP_sch_default = OMP_sch_static,
548 /// dist_schedule types
549 OMP_dist_sch_static_chunked = 91,
550 OMP_dist_sch_static = 92,
551 /// Fused distribute+for static schedule (entityId = team*nthreads + tid,
552 /// num_entities = nteams*nthreads). One for_static_init call, no
553 /// surrounding distribute_static_init. Matches
554 /// kmp_sched_distr_static_chunk_sched_static_chunkone in the device RTL
555 /// (openmp/device/include/DeviceTypes.h).
556 OMP_dist_sch_static_chunked_sch_static_chunkone = 93,
557 /// Support for OpenMP 4.5 monotonic and nonmonotonic schedule modifiers.
558 /// Set if the monotonic schedule modifier was present.
559 OMP_sch_modifier_monotonic = (1 << 29),
560 /// Set if the nonmonotonic schedule modifier was present.
561 OMP_sch_modifier_nonmonotonic = (1 << 30),
562};
563
564/// A basic class for pre|post-action for advanced codegen sequence for OpenMP
565/// region.
566class CleanupTy final : public EHScopeStack::Cleanup {
567 PrePostActionTy *Action;
568
569public:
570 explicit CleanupTy(PrePostActionTy *Action) : Action(Action) {}
571 void Emit(CodeGenFunction &CGF, Flags /*flags*/) override {
572 if (!CGF.HaveInsertPoint())
573 return;
574 Action->Exit(CGF);
575 }
576};
577
578} // anonymous namespace
579
582 if (PrePostAction) {
583 CGF.EHStack.pushCleanup<CleanupTy>(NormalAndEHCleanup, PrePostAction);
584 Callback(CodeGen, CGF, *PrePostAction);
585 } else {
586 PrePostActionTy Action;
587 Callback(CodeGen, CGF, Action);
588 }
589}
590
591/// Check if the combiner is a call to UDR combiner and if it is so return the
592/// UDR decl used for reduction.
593static const OMPDeclareReductionDecl *
594getReductionInit(const Expr *ReductionOp) {
595 if (const auto *CE = dyn_cast<CallExpr>(ReductionOp))
596 if (const auto *OVE = dyn_cast<OpaqueValueExpr>(CE->getCallee()))
597 if (const auto *DRE =
598 dyn_cast<DeclRefExpr>(OVE->getSourceExpr()->IgnoreImpCasts()))
599 if (const auto *DRD = dyn_cast<OMPDeclareReductionDecl>(DRE->getDecl()))
600 return DRD;
601 return nullptr;
602}
603
605 const OMPDeclareReductionDecl *DRD,
606 const Expr *InitOp,
607 Address Private, Address Original,
608 QualType Ty) {
609 if (DRD->getInitializer()) {
610 std::pair<llvm::Function *, llvm::Function *> Reduction =
612 const auto *CE = cast<CallExpr>(InitOp);
613 const auto *OVE = cast<OpaqueValueExpr>(CE->getCallee());
614 const Expr *LHS = CE->getArg(/*Arg=*/0)->IgnoreParenImpCasts();
615 const Expr *RHS = CE->getArg(/*Arg=*/1)->IgnoreParenImpCasts();
616 const auto *LHSDRE =
617 cast<DeclRefExpr>(cast<UnaryOperator>(LHS)->getSubExpr());
618 const auto *RHSDRE =
619 cast<DeclRefExpr>(cast<UnaryOperator>(RHS)->getSubExpr());
620 CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
621 PrivateScope.addPrivate(cast<VarDecl>(LHSDRE->getDecl()), Private);
622 PrivateScope.addPrivate(cast<VarDecl>(RHSDRE->getDecl()), Original);
623 (void)PrivateScope.Privatize();
626 CGF.EmitIgnoredExpr(InitOp);
627 } else {
628 llvm::Constant *Init = CGF.CGM.EmitNullConstant(Ty);
629 std::string Name = CGF.CGM.getOpenMPRuntime().getName({"init"});
630 auto *GV = new llvm::GlobalVariable(
631 CGF.CGM.getModule(), Init->getType(), /*isConstant=*/true,
632 llvm::GlobalValue::PrivateLinkage, Init, Name);
633 LValue LV = CGF.MakeNaturalAlignRawAddrLValue(GV, Ty);
634 RValue InitRVal;
635 switch (CGF.getEvaluationKind(Ty)) {
636 case TEK_Scalar:
637 InitRVal = CGF.EmitLoadOfLValue(LV, DRD->getLocation());
638 break;
639 case TEK_Complex:
640 InitRVal =
642 break;
643 case TEK_Aggregate: {
644 OpaqueValueExpr OVE(DRD->getLocation(), Ty, VK_LValue);
645 CodeGenFunction::OpaqueValueMapping OpaqueMap(CGF, &OVE, LV);
646 CGF.EmitAnyExprToMem(&OVE, Private, Ty.getQualifiers(),
647 /*IsInitializer=*/false);
648 return;
649 }
650 }
651 OpaqueValueExpr OVE(DRD->getLocation(), Ty, VK_PRValue);
652 CodeGenFunction::OpaqueValueMapping OpaqueMap(CGF, &OVE, InitRVal);
653 CGF.EmitAnyExprToMem(&OVE, Private, Ty.getQualifiers(),
654 /*IsInitializer=*/false);
655 }
656}
657
658/// Emit initialization of arrays of complex types.
659/// \param DestAddr Address of the array.
660/// \param Type Type of array.
661/// \param Init Initial expression of array.
662/// \param SrcAddr Address of the original array.
664 QualType Type, bool EmitDeclareReductionInit,
665 const Expr *Init,
666 const OMPDeclareReductionDecl *DRD,
667 Address SrcAddr = Address::invalid()) {
668 // Perform element-by-element initialization.
669 QualType ElementTy;
670
671 // Drill down to the base element type on both arrays.
672 const ArrayType *ArrayTy = Type->getAsArrayTypeUnsafe();
673 llvm::Value *NumElements = CGF.emitArrayLength(ArrayTy, ElementTy, DestAddr);
674 if (DRD)
675 SrcAddr = SrcAddr.withElementType(DestAddr.getElementType());
676
677 llvm::Value *SrcBegin = nullptr;
678 if (DRD)
679 SrcBegin = SrcAddr.emitRawPointer(CGF);
680 llvm::Value *DestBegin = DestAddr.emitRawPointer(CGF);
681 // Cast from pointer to array type to pointer to single element.
682 llvm::Value *DestEnd =
683 CGF.Builder.CreateGEP(DestAddr.getElementType(), DestBegin, NumElements);
684 // The basic structure here is a while-do loop.
685 llvm::BasicBlock *BodyBB = CGF.createBasicBlock("omp.arrayinit.body");
686 llvm::BasicBlock *DoneBB = CGF.createBasicBlock("omp.arrayinit.done");
687 llvm::Value *IsEmpty =
688 CGF.Builder.CreateICmpEQ(DestBegin, DestEnd, "omp.arrayinit.isempty");
689 CGF.Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB);
690
691 // Enter the loop body, making that address the current address.
692 llvm::BasicBlock *EntryBB = CGF.Builder.GetInsertBlock();
693 CGF.EmitBlock(BodyBB);
694
695 CharUnits ElementSize = CGF.getContext().getTypeSizeInChars(ElementTy);
696
697 llvm::PHINode *SrcElementPHI = nullptr;
698 Address SrcElementCurrent = Address::invalid();
699 if (DRD) {
700 SrcElementPHI = CGF.Builder.CreatePHI(SrcBegin->getType(), 2,
701 "omp.arraycpy.srcElementPast");
702 SrcElementPHI->addIncoming(SrcBegin, EntryBB);
703 SrcElementCurrent =
704 Address(SrcElementPHI, SrcAddr.getElementType(),
705 SrcAddr.getAlignment().alignmentOfArrayElement(ElementSize));
706 }
707 llvm::PHINode *DestElementPHI = CGF.Builder.CreatePHI(
708 DestBegin->getType(), 2, "omp.arraycpy.destElementPast");
709 DestElementPHI->addIncoming(DestBegin, EntryBB);
710 Address DestElementCurrent =
711 Address(DestElementPHI, DestAddr.getElementType(),
712 DestAddr.getAlignment().alignmentOfArrayElement(ElementSize));
713
714 // Emit copy.
715 {
717 if (EmitDeclareReductionInit) {
718 emitInitWithReductionInitializer(CGF, DRD, Init, DestElementCurrent,
719 SrcElementCurrent, ElementTy);
720 } else
721 CGF.EmitAnyExprToMem(Init, DestElementCurrent, ElementTy.getQualifiers(),
722 /*IsInitializer=*/false);
723 }
724
725 if (DRD) {
726 // Shift the address forward by one element.
727 llvm::Value *SrcElementNext = CGF.Builder.CreateConstGEP1_32(
728 SrcAddr.getElementType(), SrcElementPHI, /*Idx0=*/1,
729 "omp.arraycpy.dest.element");
730 SrcElementPHI->addIncoming(SrcElementNext, CGF.Builder.GetInsertBlock());
731 }
732
733 // Shift the address forward by one element.
734 llvm::Value *DestElementNext = CGF.Builder.CreateConstGEP1_32(
735 DestAddr.getElementType(), DestElementPHI, /*Idx0=*/1,
736 "omp.arraycpy.dest.element");
737 // Check whether we've reached the end.
738 llvm::Value *Done =
739 CGF.Builder.CreateICmpEQ(DestElementNext, DestEnd, "omp.arraycpy.done");
740 CGF.Builder.CreateCondBr(Done, DoneBB, BodyBB);
741 DestElementPHI->addIncoming(DestElementNext, CGF.Builder.GetInsertBlock());
742
743 // Done.
744 CGF.EmitBlock(DoneBB, /*IsFinished=*/true);
745}
746
747LValue ReductionCodeGen::emitSharedLValue(CodeGenFunction &CGF, const Expr *E) {
748 return CGF.EmitOMPSharedLValue(E);
749}
750
751LValue ReductionCodeGen::emitSharedLValueUB(CodeGenFunction &CGF,
752 const Expr *E) {
753 if (const auto *OASE = dyn_cast<ArraySectionExpr>(E))
754 return CGF.EmitArraySectionExpr(OASE, /*IsLowerBound=*/false);
755 return LValue();
756}
757
758void ReductionCodeGen::emitAggregateInitialization(
759 CodeGenFunction &CGF, unsigned N, Address PrivateAddr, Address SharedAddr,
760 const OMPDeclareReductionDecl *DRD) {
761 // Emit VarDecl with copy init for arrays.
762 // Get the address of the original variable captured in current
763 // captured region.
764 const auto *PrivateVD =
765 cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Private)->getDecl());
766 bool EmitDeclareReductionInit =
767 DRD && (DRD->getInitializer() || !PrivateVD->hasInit());
768 EmitOMPAggregateInit(CGF, PrivateAddr, PrivateVD->getType(),
769 EmitDeclareReductionInit,
770 EmitDeclareReductionInit ? ClausesData[N].ReductionOp
771 : PrivateVD->getInit(),
772 DRD, SharedAddr);
773}
774
778 ArrayRef<const Expr *> ReductionOps) {
779 ClausesData.reserve(Shareds.size());
780 SharedAddresses.reserve(Shareds.size());
781 Sizes.reserve(Shareds.size());
782 BaseDecls.reserve(Shareds.size());
783 const auto *IOrig = Origs.begin();
784 const auto *IPriv = Privates.begin();
785 const auto *IRed = ReductionOps.begin();
786 for (const Expr *Ref : Shareds) {
787 ClausesData.emplace_back(Ref, *IOrig, *IPriv, *IRed);
788 std::advance(IOrig, 1);
789 std::advance(IPriv, 1);
790 std::advance(IRed, 1);
791 }
792}
793
795 assert(SharedAddresses.size() == N && OrigAddresses.size() == N &&
796 "Number of generated lvalues must be exactly N.");
797 LValue First = emitSharedLValue(CGF, ClausesData[N].Shared);
798 LValue Second = emitSharedLValueUB(CGF, ClausesData[N].Shared);
799 SharedAddresses.emplace_back(First, Second);
800 if (ClausesData[N].Shared == ClausesData[N].Ref) {
801 OrigAddresses.emplace_back(First, Second);
802 } else {
803 LValue First = emitSharedLValue(CGF, ClausesData[N].Ref);
804 LValue Second = emitSharedLValueUB(CGF, ClausesData[N].Ref);
805 OrigAddresses.emplace_back(First, Second);
806 }
807}
808
810 QualType PrivateType = getPrivateType(N);
811 bool AsArraySection = isa<ArraySectionExpr>(ClausesData[N].Ref);
812 if (!PrivateType->isVariablyModifiedType()) {
813 Sizes.emplace_back(
814 CGF.getTypeSize(OrigAddresses[N].first.getType().getNonReferenceType()),
815 nullptr);
816 return;
817 }
818 llvm::Value *Size;
819 llvm::Value *SizeInChars;
820 auto *ElemType = OrigAddresses[N].first.getAddress().getElementType();
821 auto *ElemSizeOf = llvm::ConstantInt::get(
822 CGF.SizeTy, CGF.CGM.getDataLayout().getTypeAllocSize(ElemType));
823 if (AsArraySection) {
824 SizeInChars =
825 CGF.Builder.CreatePtrDiff(OrigAddresses[N].second.getPointer(CGF),
826 OrigAddresses[N].first.getPointer(CGF));
827 SizeInChars = CGF.Builder.CreateNUWAdd(SizeInChars, ElemSizeOf);
828 } else {
829 SizeInChars =
830 CGF.getTypeSize(OrigAddresses[N].first.getType().getNonReferenceType());
831 }
832 Size = ElemSizeOf->isOne()
833 ? SizeInChars
834 : CGF.Builder.CreateExactUDiv(SizeInChars, ElemSizeOf);
835 Sizes.emplace_back(SizeInChars, Size);
837 CGF,
839 CGF.getContext().getAsVariableArrayType(PrivateType)->getSizeExpr()),
840 RValue::get(Size));
841 CGF.EmitVariablyModifiedType(PrivateType);
842}
843
845 llvm::Value *Size) {
846 QualType PrivateType = getPrivateType(N);
847 if (!PrivateType->isVariablyModifiedType()) {
848 assert(!Size && !Sizes[N].second &&
849 "Size should be nullptr for non-variably modified reduction "
850 "items.");
851 return;
852 }
854 CGF,
856 CGF.getContext().getAsVariableArrayType(PrivateType)->getSizeExpr()),
857 RValue::get(Size));
858 CGF.EmitVariablyModifiedType(PrivateType);
859}
860
862 CodeGenFunction &CGF, unsigned N, Address PrivateAddr, Address SharedAddr,
863 llvm::function_ref<bool(CodeGenFunction &)> DefaultInit) {
864 assert(SharedAddresses.size() > N && "No variable was generated");
865 const auto *PrivateVD =
866 cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Private)->getDecl());
867 const OMPDeclareReductionDecl *DRD =
868 getReductionInit(ClausesData[N].ReductionOp);
869 if (CGF.getContext().getAsArrayType(PrivateVD->getType())) {
870 if (DRD && DRD->getInitializer())
871 (void)DefaultInit(CGF);
872 emitAggregateInitialization(CGF, N, PrivateAddr, SharedAddr, DRD);
873 } else if (DRD && (DRD->getInitializer() || !PrivateVD->hasInit())) {
874 (void)DefaultInit(CGF);
875 QualType SharedType = SharedAddresses[N].first.getType();
876 emitInitWithReductionInitializer(CGF, DRD, ClausesData[N].ReductionOp,
877 PrivateAddr, SharedAddr, SharedType);
878 } else if (!DefaultInit(CGF) && PrivateVD->hasInit() &&
879 !CGF.isTrivialInitializer(PrivateVD->getInit())) {
880 CGF.EmitAnyExprToMem(PrivateVD->getInit(), PrivateAddr,
881 PrivateVD->getType().getQualifiers(),
882 /*IsInitializer=*/false);
883 }
884}
885
887 QualType PrivateType = getPrivateType(N);
888 QualType::DestructionKind DTorKind = PrivateType.isDestructedType();
889 return DTorKind != QualType::DK_none;
890}
891
893 Address PrivateAddr) {
894 QualType PrivateType = getPrivateType(N);
895 QualType::DestructionKind DTorKind = PrivateType.isDestructedType();
896 if (needCleanups(N)) {
897 PrivateAddr =
898 PrivateAddr.withElementType(CGF.ConvertTypeForMem(PrivateType));
899 CGF.pushDestroy(DTorKind, PrivateAddr, PrivateType);
900 }
901}
902
903static LValue loadToBegin(CodeGenFunction &CGF, QualType BaseTy, QualType ElTy,
904 LValue BaseLV) {
905 BaseTy = BaseTy.getNonReferenceType();
906 while ((BaseTy->isPointerType() || BaseTy->isReferenceType()) &&
907 !CGF.getContext().hasSameType(BaseTy, ElTy)) {
908 if (const auto *PtrTy = BaseTy->getAs<PointerType>()) {
909 BaseLV = CGF.EmitLoadOfPointerLValue(BaseLV.getAddress(), PtrTy);
910 } else {
911 LValue RefLVal = CGF.MakeAddrLValue(BaseLV.getAddress(), BaseTy);
912 BaseLV = CGF.EmitLoadOfReferenceLValue(RefLVal);
913 }
914 BaseTy = BaseTy->getPointeeType();
915 }
916 return CGF.MakeAddrLValue(
917 BaseLV.getAddress().withElementType(CGF.ConvertTypeForMem(ElTy)),
918 BaseLV.getType(), BaseLV.getBaseInfo(),
919 CGF.CGM.getTBAAInfoForSubobject(BaseLV, BaseLV.getType()));
920}
921
923 Address OriginalBaseAddress, llvm::Value *Addr) {
925 Address TopTmp = Address::invalid();
926 Address MostTopTmp = Address::invalid();
927 BaseTy = BaseTy.getNonReferenceType();
928 while ((BaseTy->isPointerType() || BaseTy->isReferenceType()) &&
929 !CGF.getContext().hasSameType(BaseTy, ElTy)) {
930 Tmp = CGF.CreateMemTempWithoutCast(BaseTy);
931 if (TopTmp.isValid())
932 CGF.Builder.CreateStore(Tmp.getPointer(), TopTmp);
933 else
934 MostTopTmp = Tmp;
935 TopTmp = Tmp;
936 BaseTy = BaseTy->getPointeeType();
937 }
938
939 if (Tmp.isValid()) {
941 Addr, Tmp.getElementType());
942 CGF.Builder.CreateStore(Addr, Tmp);
943 return MostTopTmp;
944 }
945
947 Addr, OriginalBaseAddress.getType());
948 return OriginalBaseAddress.withPointer(Addr, NotKnownNonNull);
949}
950
951static const VarDecl *getBaseDecl(const Expr *Ref, const DeclRefExpr *&DE) {
952 const VarDecl *OrigVD = nullptr;
953 if (const auto *OASE = dyn_cast<ArraySectionExpr>(Ref)) {
954 const Expr *Base = OASE->getBase()->IgnoreParenImpCasts();
955 while (const auto *TempOASE = dyn_cast<ArraySectionExpr>(Base))
956 Base = TempOASE->getBase()->IgnoreParenImpCasts();
957 while (const auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
958 Base = TempASE->getBase()->IgnoreParenImpCasts();
960 OrigVD = cast<VarDecl>(DE->getDecl());
961 } else if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(Ref)) {
962 const Expr *Base = ASE->getBase()->IgnoreParenImpCasts();
963 while (const auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
964 Base = TempASE->getBase()->IgnoreParenImpCasts();
966 OrigVD = cast<VarDecl>(DE->getDecl());
967 }
968 return OrigVD;
969}
970
972 Address PrivateAddr) {
973 const DeclRefExpr *DE;
974 if (const VarDecl *OrigVD = ::getBaseDecl(ClausesData[N].Ref, DE)) {
975 BaseDecls.emplace_back(OrigVD);
976 LValue OriginalBaseLValue = CGF.EmitLValue(DE);
977 LValue BaseLValue =
978 loadToBegin(CGF, OrigVD->getType(), SharedAddresses[N].first.getType(),
979 OriginalBaseLValue);
980 Address SharedAddr = SharedAddresses[N].first.getAddress();
981 llvm::Value *Adjustment = CGF.Builder.CreatePtrDiff(
982 SharedAddr.getElementType(), BaseLValue.getPointer(CGF),
983 SharedAddr.emitRawPointer(CGF));
984 llvm::Value *PrivatePointer =
986 PrivateAddr.emitRawPointer(CGF), SharedAddr.getType());
987 llvm::Value *Ptr = CGF.Builder.CreateGEP(
988 SharedAddr.getElementType(), PrivatePointer, Adjustment);
989 return castToBase(CGF, OrigVD->getType(),
990 SharedAddresses[N].first.getType(),
991 OriginalBaseLValue.getAddress(), Ptr);
992 }
993 BaseDecls.emplace_back(
994 cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Ref)->getDecl()));
995 return PrivateAddr;
996}
997
999 const OMPDeclareReductionDecl *DRD =
1000 getReductionInit(ClausesData[N].ReductionOp);
1001 return DRD && DRD->getInitializer();
1002}
1003
1004LValue CGOpenMPRegionInfo::getThreadIDVariableLValue(CodeGenFunction &CGF) {
1005 return CGF.EmitLoadOfPointerLValue(
1006 CGF.GetAddrOfLocalVar(getThreadIDVariable()),
1007 getThreadIDVariable()->getType()->castAs<PointerType>());
1008}
1009
1010void CGOpenMPRegionInfo::EmitBody(CodeGenFunction &CGF, const Stmt *S) {
1011 if (!CGF.HaveInsertPoint())
1012 return;
1013 // 1.2.2 OpenMP Language Terminology
1014 // Structured block - An executable statement with a single entry at the
1015 // top and a single exit at the bottom.
1016 // The point of exit cannot be a branch out of the structured block.
1017 // longjmp() and throw() must not violate the entry/exit criteria.
1018 CGF.EHStack.pushTerminate();
1019 if (S)
1021 CodeGen(CGF);
1022 CGF.EHStack.popTerminate();
1023}
1024
1025LValue CGOpenMPTaskOutlinedRegionInfo::getThreadIDVariableLValue(
1026 CodeGenFunction &CGF) {
1027 return CGF.MakeAddrLValue(CGF.GetAddrOfLocalVar(getThreadIDVariable()),
1028 getThreadIDVariable()->getType(),
1030}
1031
1033 QualType FieldTy) {
1034 auto *Field = FieldDecl::Create(
1035 C, DC, SourceLocation(), SourceLocation(), /*Id=*/nullptr, FieldTy,
1036 C.getTrivialTypeSourceInfo(FieldTy, SourceLocation()),
1037 /*BW=*/nullptr, /*Mutable=*/false, /*InitStyle=*/ICIS_NoInit);
1038 Field->setAccess(AS_public);
1039 DC->addDecl(Field);
1040 return Field;
1041}
1042
1044 : CGM(CGM), OMPBuilder(CGM.getModule()) {
1045 KmpCriticalNameTy = llvm::ArrayType::get(CGM.Int32Ty, /*NumElements*/ 8);
1046 llvm::OpenMPIRBuilderConfig Config(
1047 CGM.getLangOpts().OpenMPIsTargetDevice, isGPU(),
1048 CGM.getLangOpts().OpenMPOffloadMandatory,
1049 /*HasRequiresReverseOffload*/ false, /*HasRequiresUnifiedAddress*/ false,
1050 hasRequiresUnifiedSharedMemory(), /*HasRequiresDynamicAllocators*/ false);
1051 Config.setDefaultTargetAS(
1052 CGM.getContext().getTargetInfo().getTargetAddressSpace(LangAS::Default));
1053 Config.setRuntimeCC(CGM.getRuntimeCC());
1054
1055 OMPBuilder.setConfig(Config);
1056 OMPBuilder.initialize();
1057 OMPBuilder.loadOffloadInfoMetadata(*CGM.getFileSystem(),
1058 CGM.getLangOpts().OpenMPIsTargetDevice
1059 ? CGM.getLangOpts().OMPHostIRFile
1060 : StringRef{});
1061
1062 // The user forces the compiler to behave as if omp requires
1063 // unified_shared_memory was given.
1064 if (CGM.getLangOpts().OpenMPForceUSM) {
1066 OMPBuilder.Config.setHasRequiresUnifiedSharedMemory(true);
1067 }
1068}
1069
1071 InternalVars.clear();
1072 // Clean non-target variable declarations possibly used only in debug info.
1073 for (const auto &Data : EmittedNonTargetVariables) {
1074 if (!Data.getValue().pointsToAliveValue())
1075 continue;
1076 auto *GV = dyn_cast<llvm::GlobalVariable>(Data.getValue());
1077 if (!GV)
1078 continue;
1079 if (!GV->isDeclaration() || GV->getNumUses() > 0)
1080 continue;
1081 GV->eraseFromParent();
1082 }
1083}
1084
1086 return OMPBuilder.createPlatformSpecificName(Parts);
1087}
1088
1089static llvm::Function *
1091 const Expr *CombinerInitializer, const VarDecl *In,
1092 const VarDecl *Out, bool IsCombiner) {
1093 // void .omp_combiner.(Ty *in, Ty *out);
1094 ASTContext &C = CGM.getContext();
1095 QualType PtrTy = C.getPointerType(Ty).withRestrict();
1096 auto *OmpOutParm = ImplicitParamDecl::Create(
1097 C, /*DC=*/nullptr, Out->getLocation(),
1098 /*Id=*/nullptr, PtrTy, ImplicitParamKind::Other);
1099 auto *OmpInParm = ImplicitParamDecl::Create(
1100 C, /*DC=*/nullptr, In->getLocation(),
1101 /*Id=*/nullptr, PtrTy, ImplicitParamKind::Other);
1102 FunctionArgList Args{OmpOutParm, OmpInParm};
1103 const CGFunctionInfo &FnInfo =
1104 CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
1105 llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
1106 std::string Name = CGM.getOpenMPRuntime().getName(
1107 {IsCombiner ? "omp_combiner" : "omp_initializer", ""});
1108 auto *Fn = llvm::Function::Create(FnTy, llvm::GlobalValue::InternalLinkage,
1109 Name, &CGM.getModule());
1110 CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FnInfo);
1111 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
1112 Fn->addFnAttr("sample-profile-suffix-elision-policy", "selected");
1113 if (CGM.getCodeGenOpts().OptimizationLevel != 0) {
1114 Fn->removeFnAttr(llvm::Attribute::NoInline);
1115 Fn->removeFnAttr(llvm::Attribute::OptimizeNone);
1116 Fn->addFnAttr(llvm::Attribute::AlwaysInline);
1117 }
1118 CodeGenFunction CGF(CGM);
1119 // Map "T omp_in;" variable to "*omp_in_parm" value in all expressions.
1120 // Map "T omp_out;" variable to "*omp_out_parm" value in all expressions.
1121 CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, FnInfo, Args, In->getLocation(),
1122 Out->getLocation());
1124 Address AddrIn = CGF.GetAddrOfLocalVar(OmpInParm);
1125 Scope.addPrivate(
1126 In, CGF.EmitLoadOfPointerLValue(AddrIn, PtrTy->castAs<PointerType>())
1127 .getAddress());
1128 Address AddrOut = CGF.GetAddrOfLocalVar(OmpOutParm);
1129 Scope.addPrivate(
1130 Out, CGF.EmitLoadOfPointerLValue(AddrOut, PtrTy->castAs<PointerType>())
1131 .getAddress());
1132 (void)Scope.Privatize();
1133 if (!IsCombiner && Out->hasInit() &&
1134 !CGF.isTrivialInitializer(Out->getInit())) {
1135 CGF.EmitAnyExprToMem(Out->getInit(), CGF.GetAddrOfLocalVar(Out),
1136 Out->getType().getQualifiers(),
1137 /*IsInitializer=*/true);
1138 }
1139 if (CombinerInitializer)
1140 CGF.EmitIgnoredExpr(CombinerInitializer);
1141 Scope.ForceCleanup();
1142 CGF.FinishFunction();
1143 return Fn;
1144}
1145
1148 if (UDRMap.count(D) > 0)
1149 return;
1150 llvm::Function *Combiner = emitCombinerOrInitializer(
1151 CGM, D->getType(), D->getCombiner(),
1154 /*IsCombiner=*/true);
1155 llvm::Function *Initializer = nullptr;
1156 if (const Expr *Init = D->getInitializer()) {
1158 CGM, D->getType(),
1160 : nullptr,
1163 /*IsCombiner=*/false);
1164 }
1165 UDRMap.try_emplace(D, Combiner, Initializer);
1166 if (CGF)
1167 FunctionUDRMap[CGF->CurFn].push_back(D);
1168}
1169
1170std::pair<llvm::Function *, llvm::Function *>
1172 auto I = UDRMap.find(D);
1173 if (I != UDRMap.end())
1174 return I->second;
1175 emitUserDefinedReduction(/*CGF=*/nullptr, D);
1176 return UDRMap.lookup(D);
1177}
1178
1179namespace {
1180// Temporary RAII solution to perform a push/pop stack event on the OpenMP IR
1181// Builder if one is present.
1182struct PushAndPopStackRAII {
1183 PushAndPopStackRAII(llvm::OpenMPIRBuilder *OMPBuilder, CodeGenFunction &CGF,
1184 bool HasCancel, llvm::omp::Directive Kind)
1185 : OMPBuilder(OMPBuilder) {
1186 if (!OMPBuilder)
1187 return;
1188
1189 // The following callback is the crucial part of clangs cleanup process.
1190 //
1191 // NOTE:
1192 // Once the OpenMPIRBuilder is used to create parallel regions (and
1193 // similar), the cancellation destination (Dest below) is determined via
1194 // IP. That means if we have variables to finalize we split the block at IP,
1195 // use the new block (=BB) as destination to build a JumpDest (via
1196 // getJumpDestInCurrentScope(BB)) which then is fed to
1197 // EmitBranchThroughCleanup. Furthermore, there will not be the need
1198 // to push & pop an FinalizationInfo object.
1199 // The FiniCB will still be needed but at the point where the
1200 // OpenMPIRBuilder is asked to construct a parallel (or similar) construct.
1201 auto FiniCB = [&CGF](llvm::OpenMPIRBuilder::InsertPointTy IP) {
1202 assert(IP == IP.getNodeParent()->end() &&
1203 "Clang CG should cause non-terminated block!");
1204 CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
1205 CGF.Builder.restoreIP(IP);
1207 CGF.getOMPCancelDestination(OMPD_parallel);
1208 CGF.EmitBranchThroughCleanup(Dest);
1209 return llvm::Error::success();
1210 };
1211
1212 // TODO: Remove this once we emit parallel regions through the
1213 // OpenMPIRBuilder as it can do this setup internally.
1214 llvm::OpenMPIRBuilder::FinalizationInfo FI({FiniCB, Kind, HasCancel});
1215 OMPBuilder->pushFinalizationCB(std::move(FI));
1216 }
1217 ~PushAndPopStackRAII() {
1218 if (OMPBuilder)
1219 OMPBuilder->popFinalizationCB();
1220 }
1221 llvm::OpenMPIRBuilder *OMPBuilder;
1222};
1223} // namespace
1224
1226 CodeGenModule &CGM, const OMPExecutableDirective &D, const CapturedStmt *CS,
1227 const VarDecl *ThreadIDVar, OpenMPDirectiveKind InnermostKind,
1228 const StringRef OutlinedHelperName, const RegionCodeGenTy &CodeGen) {
1229 assert(ThreadIDVar->getType()->isPointerType() &&
1230 "thread id variable must be of type kmp_int32 *");
1231 CodeGenFunction CGF(CGM, true);
1232 bool HasCancel = false;
1233 if (const auto *OPD = dyn_cast<OMPParallelDirective>(&D))
1234 HasCancel = OPD->hasCancel();
1235 else if (const auto *OPD = dyn_cast<OMPTargetParallelDirective>(&D))
1236 HasCancel = OPD->hasCancel();
1237 else if (const auto *OPSD = dyn_cast<OMPParallelSectionsDirective>(&D))
1238 HasCancel = OPSD->hasCancel();
1239 else if (const auto *OPFD = dyn_cast<OMPParallelForDirective>(&D))
1240 HasCancel = OPFD->hasCancel();
1241 else if (const auto *OPFD = dyn_cast<OMPTargetParallelForDirective>(&D))
1242 HasCancel = OPFD->hasCancel();
1243 else if (const auto *OPFD = dyn_cast<OMPDistributeParallelForDirective>(&D))
1244 HasCancel = OPFD->hasCancel();
1245 else if (const auto *OPFD =
1246 dyn_cast<OMPTeamsDistributeParallelForDirective>(&D))
1247 HasCancel = OPFD->hasCancel();
1248 else if (const auto *OPFD =
1249 dyn_cast<OMPTargetTeamsDistributeParallelForDirective>(&D))
1250 HasCancel = OPFD->hasCancel();
1251
1252 // TODO: Temporarily inform the OpenMPIRBuilder, if any, about the new
1253 // parallel region to make cancellation barriers work properly.
1254 llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
1255 PushAndPopStackRAII PSR(&OMPBuilder, CGF, HasCancel, InnermostKind);
1256 CGOpenMPOutlinedRegionInfo CGInfo(*CS, ThreadIDVar, CodeGen, InnermostKind,
1257 HasCancel, OutlinedHelperName);
1258 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
1259 return CGF.GenerateOpenMPCapturedStmtFunction(*CS, D);
1260}
1261
1262std::string CGOpenMPRuntime::getOutlinedHelperName(StringRef Name) const {
1263 std::string Suffix = getName({"omp_outlined"});
1264 return (Name + Suffix).str();
1265}
1266
1268 return getOutlinedHelperName(CGF.CurFn->getName());
1269}
1270
1271std::string CGOpenMPRuntime::getReductionFuncName(StringRef Name) const {
1272 std::string Suffix = getName({"omp", "reduction", "reduction_func"});
1273 return (Name + Suffix).str();
1274}
1275
1278 const VarDecl *ThreadIDVar, OpenMPDirectiveKind InnermostKind,
1279 const RegionCodeGenTy &CodeGen) {
1280 const CapturedStmt *CS = D.getCapturedStmt(OMPD_parallel);
1282 CGM, D, CS, ThreadIDVar, InnermostKind, getOutlinedHelperName(CGF),
1283 CodeGen);
1284}
1285
1288 const VarDecl *ThreadIDVar, OpenMPDirectiveKind InnermostKind,
1289 const RegionCodeGenTy &CodeGen) {
1290 const CapturedStmt *CS = D.getCapturedStmt(OMPD_teams);
1291 llvm::Function *OutlinedFn = emitParallelOrTeamsOutlinedFunction(
1292 CGM, D, CS, ThreadIDVar, InnermostKind, getOutlinedHelperName(CGF),
1293 CodeGen);
1294 // A teams body is called once per team and is not handed back to the runtime
1295 // as a callback, so unlike a parallel body it cannot be re-entered while a
1296 // call to it is live.
1297 OutlinedFn->setDoesNotRecurse();
1298 return OutlinedFn;
1299}
1300
1302 const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
1303 const VarDecl *PartIDVar, const VarDecl *TaskTVar,
1304 OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen,
1305 bool Tied, unsigned &NumberOfParts) {
1306 auto &&UntiedCodeGen = [this, &D, TaskTVar](CodeGenFunction &CGF,
1307 PrePostActionTy &) {
1308 llvm::Value *ThreadID = getThreadID(CGF, D.getBeginLoc());
1309 llvm::Value *UpLoc = emitUpdateLocation(CGF, D.getBeginLoc());
1310 llvm::Value *TaskArgs[] = {
1311 UpLoc, ThreadID,
1312 CGF.EmitLoadOfPointerLValue(CGF.GetAddrOfLocalVar(TaskTVar),
1313 TaskTVar->getType()->castAs<PointerType>())
1314 .getPointer(CGF)};
1315 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
1316 CGM.getModule(), OMPRTL___kmpc_omp_task),
1317 TaskArgs);
1318 };
1319 CGOpenMPTaskOutlinedRegionInfo::UntiedTaskActionTy Action(Tied, PartIDVar,
1320 UntiedCodeGen);
1321 CodeGen.setAction(Action);
1322 assert(!ThreadIDVar->getType()->isPointerType() &&
1323 "thread id variable must be of type kmp_int32 for tasks");
1324 const OpenMPDirectiveKind Region =
1325 isOpenMPTaskLoopDirective(D.getDirectiveKind()) ? OMPD_taskloop
1326 : OMPD_task;
1327 const CapturedStmt *CS = D.getCapturedStmt(Region);
1328 bool HasCancel = false;
1329 if (const auto *TD = dyn_cast<OMPTaskDirective>(&D))
1330 HasCancel = TD->hasCancel();
1331 else if (const auto *TD = dyn_cast<OMPTaskLoopDirective>(&D))
1332 HasCancel = TD->hasCancel();
1333 else if (const auto *TD = dyn_cast<OMPMasterTaskLoopDirective>(&D))
1334 HasCancel = TD->hasCancel();
1335 else if (const auto *TD = dyn_cast<OMPParallelMasterTaskLoopDirective>(&D))
1336 HasCancel = TD->hasCancel();
1337
1338 CodeGenFunction CGF(CGM, true);
1339 CGOpenMPTaskOutlinedRegionInfo CGInfo(*CS, ThreadIDVar, CodeGen,
1340 InnermostKind, HasCancel, Action);
1341 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
1342 llvm::Function *Res = CGF.GenerateCapturedStmtFunction(*CS);
1343 if (!Tied)
1344 NumberOfParts = Action.getNumberOfParts();
1345 return Res;
1346}
1347
1349 bool AtCurrentPoint) {
1350 auto &Elem = OpenMPLocThreadIDMap[CGF.CurFn];
1351 assert(!Elem.ServiceInsertPt && "Insert point is set already.");
1352
1353 llvm::Value *Undef = llvm::UndefValue::get(CGF.Int32Ty);
1354 if (AtCurrentPoint) {
1355 Elem.ServiceInsertPt = new llvm::BitCastInst(Undef, CGF.Int32Ty, "svcpt",
1356 CGF.Builder.GetInsertBlock());
1357 } else {
1358 Elem.ServiceInsertPt = new llvm::BitCastInst(Undef, CGF.Int32Ty, "svcpt");
1359 Elem.ServiceInsertPt->insertAfter(CGF.AllocaInsertPt->getIterator());
1360 }
1361}
1362
1364 auto &Elem = OpenMPLocThreadIDMap[CGF.CurFn];
1365 if (Elem.ServiceInsertPt) {
1366 llvm::Instruction *Ptr = Elem.ServiceInsertPt;
1367 Elem.ServiceInsertPt = nullptr;
1368 Ptr->eraseFromParent();
1369 }
1370}
1371
1373 SourceLocation Loc,
1374 SmallString<128> &Buffer) {
1375 llvm::raw_svector_ostream OS(Buffer);
1376 // Build debug location
1378 OS << ";";
1379 if (auto *DbgInfo = CGF.getDebugInfo())
1380 OS << DbgInfo->remapDIPath(PLoc.getFilename());
1381 else
1382 OS << PLoc.getFilename();
1383 OS << ";";
1384 if (const auto *FD = dyn_cast_or_null<FunctionDecl>(CGF.CurFuncDecl))
1385 OS << FD->getQualifiedNameAsString();
1386 OS << ";" << PLoc.getLine() << ";" << PLoc.getColumn() << ";;";
1387 return OS.str();
1388}
1389
1391 SourceLocation Loc,
1392 unsigned Flags, bool EmitLoc) {
1393 uint32_t SrcLocStrSize;
1394 llvm::Constant *SrcLocStr;
1395 if ((!EmitLoc && CGM.getCodeGenOpts().getDebugInfo() ==
1396 llvm::codegenoptions::NoDebugInfo) ||
1397 Loc.isInvalid()) {
1398 SrcLocStr = OMPBuilder.getOrCreateDefaultSrcLocStr(SrcLocStrSize);
1399 } else {
1400 std::string FunctionName;
1401 std::string FileName;
1402 if (const auto *FD = dyn_cast_or_null<FunctionDecl>(CGF.CurFuncDecl))
1403 FunctionName = FD->getQualifiedNameAsString();
1405 if (auto *DbgInfo = CGF.getDebugInfo())
1406 FileName = DbgInfo->remapDIPath(PLoc.getFilename());
1407 else
1408 FileName = PLoc.getFilename();
1409 unsigned Line = PLoc.getLine();
1410 unsigned Column = PLoc.getColumn();
1411 SrcLocStr = OMPBuilder.getOrCreateSrcLocStr(FunctionName, FileName, Line,
1412 Column, SrcLocStrSize);
1413 }
1414 unsigned Reserved2Flags = getDefaultLocationReserved2Flags();
1415 return OMPBuilder.getOrCreateIdent(
1416 SrcLocStr, SrcLocStrSize, llvm::omp::IdentFlag(Flags), Reserved2Flags);
1417}
1418
1420 SourceLocation Loc) {
1421 assert(CGF.CurFn && "No function in current CodeGenFunction.");
1422 // If the OpenMPIRBuilder is used we need to use it for all thread id calls as
1423 // the clang invariants used below might be broken.
1424 if (CGM.getLangOpts().OpenMPIRBuilder) {
1425 SmallString<128> Buffer;
1426 OMPBuilder.updateToLocation(CGF.Builder);
1427 uint32_t SrcLocStrSize;
1428 auto *SrcLocStr = OMPBuilder.getOrCreateSrcLocStr(
1429 getIdentStringFromSourceLocation(CGF, Loc, Buffer), SrcLocStrSize);
1430 return OMPBuilder.getOrCreateThreadID(
1431 OMPBuilder.getOrCreateIdent(SrcLocStr, SrcLocStrSize));
1432 }
1433
1434 llvm::Value *ThreadID = nullptr;
1435 // Check whether we've already cached a load of the thread id in this
1436 // function.
1437 auto I = OpenMPLocThreadIDMap.find(CGF.CurFn);
1438 if (I != OpenMPLocThreadIDMap.end()) {
1439 ThreadID = I->second.ThreadID;
1440 if (ThreadID != nullptr)
1441 return ThreadID;
1442 }
1443 // If exceptions are enabled, do not use parameter to avoid possible crash.
1444 if (auto *OMPRegionInfo =
1445 dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) {
1446 if (OMPRegionInfo->getThreadIDVariable()) {
1447 // Check if this an outlined function with thread id passed as argument.
1448 LValue LVal = OMPRegionInfo->getThreadIDVariableLValue(CGF);
1449 llvm::BasicBlock *TopBlock = CGF.AllocaInsertPt->getParent();
1450 if (!CGF.EHStack.requiresLandingPad() || !CGF.getLangOpts().Exceptions ||
1451 !CGF.getLangOpts().CXXExceptions ||
1452 CGF.Builder.GetInsertBlock() == TopBlock ||
1453 !isa<llvm::Instruction>(LVal.getPointer(CGF)) ||
1454 cast<llvm::Instruction>(LVal.getPointer(CGF))->getParent() ==
1455 TopBlock ||
1456 cast<llvm::Instruction>(LVal.getPointer(CGF))->getParent() ==
1457 CGF.Builder.GetInsertBlock()) {
1458 ThreadID = CGF.EmitLoadOfScalar(LVal, Loc);
1459 // If value loaded in entry block, cache it and use it everywhere in
1460 // function.
1461 if (CGF.Builder.GetInsertBlock() == TopBlock)
1462 OpenMPLocThreadIDMap[CGF.CurFn].ThreadID = ThreadID;
1463 return ThreadID;
1464 }
1465 }
1466 }
1467
1468 // This is not an outlined function region - need to call __kmpc_int32
1469 // kmpc_global_thread_num(ident_t *loc).
1470 // Generate thread id value and cache this value for use across the
1471 // function.
1472 auto &Elem = OpenMPLocThreadIDMap[CGF.CurFn];
1473 if (!Elem.ServiceInsertPt)
1475 CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
1476 CGF.Builder.SetInsertPoint(Elem.ServiceInsertPt);
1478 llvm::CallInst *Call = CGF.Builder.CreateCall(
1479 OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(),
1480 OMPRTL___kmpc_global_thread_num),
1481 emitUpdateLocation(CGF, Loc));
1482 Call->setCallingConv(CGF.getRuntimeCC());
1483 Elem.ThreadID = Call;
1484 return Call;
1485}
1486
1488 assert(CGF.CurFn && "No function in current CodeGenFunction.");
1489 if (OpenMPLocThreadIDMap.count(CGF.CurFn)) {
1491 OpenMPLocThreadIDMap.erase(CGF.CurFn);
1492 }
1493 if (auto I = FunctionUDRMap.find(CGF.CurFn); I != FunctionUDRMap.end()) {
1494 for (const auto *D : I->second)
1495 UDRMap.erase(D);
1496 FunctionUDRMap.erase(I);
1497 }
1498 if (auto I = FunctionUDMMap.find(CGF.CurFn); I != FunctionUDMMap.end()) {
1499 for (const auto *D : I->second)
1500 UDMMap.erase(D);
1501 FunctionUDMMap.erase(I);
1502 }
1505}
1506
1508 return OMPBuilder.IdentPtr;
1509}
1510
1511static llvm::OffloadEntriesInfoManager::OMPTargetDeviceClauseKind
1513 std::optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
1514 OMPDeclareTargetDeclAttr::getDeviceType(VD);
1515 if (!DevTy)
1516 return llvm::OffloadEntriesInfoManager::OMPTargetDeviceClauseNone;
1517
1518 switch ((int)*DevTy) { // Avoid -Wcovered-switch-default
1519 case OMPDeclareTargetDeclAttr::DT_Host:
1520 return llvm::OffloadEntriesInfoManager::OMPTargetDeviceClauseHost;
1521 break;
1522 case OMPDeclareTargetDeclAttr::DT_NoHost:
1523 return llvm::OffloadEntriesInfoManager::OMPTargetDeviceClauseNoHost;
1524 break;
1525 case OMPDeclareTargetDeclAttr::DT_Any:
1526 return llvm::OffloadEntriesInfoManager::OMPTargetDeviceClauseAny;
1527 break;
1528 default:
1529 return llvm::OffloadEntriesInfoManager::OMPTargetDeviceClauseNone;
1530 break;
1531 }
1532}
1533
1534static llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryKind
1536 std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> MapType =
1537 OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
1538 if (!MapType)
1539 return llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryNone;
1540 switch ((int)*MapType) { // Avoid -Wcovered-switch-default
1541 case OMPDeclareTargetDeclAttr::MapTypeTy::MT_To:
1542 return llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryTo;
1543 break;
1544 case OMPDeclareTargetDeclAttr::MapTypeTy::MT_Enter:
1545 return llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryEnter;
1546 case OMPDeclareTargetDeclAttr::MapTypeTy::MT_Link:
1547 return llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryLink;
1548 break;
1549 case OMPDeclareTargetDeclAttr::MapTypeTy::MT_Local:
1550 // MT_Local variables don't need offload entry (device-local).
1551 llvm_unreachable("MT_Local should not reach convertCaptureClause");
1552 break;
1553 default:
1554 return llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryNone;
1555 break;
1556 }
1557}
1558
1559static llvm::TargetRegionEntryInfo getEntryInfoFromPresumedLoc(
1560 CodeGenModule &CGM, llvm::OpenMPIRBuilder &OMPBuilder,
1561 SourceLocation BeginLoc, llvm::StringRef ParentName = "") {
1562
1563 auto FileInfoCallBack = [&]() {
1565 PresumedLoc PLoc = SM.getPresumedLoc(BeginLoc);
1566
1567 if (!CGM.getFileSystem()->exists(PLoc.getFilename()))
1568 PLoc = SM.getPresumedLoc(BeginLoc, /*UseLineDirectives=*/false);
1569
1570 return std::pair<std::string, uint64_t>(PLoc.getFilename(), PLoc.getLine());
1571 };
1572
1573 return OMPBuilder.getTargetEntryUniqueInfo(FileInfoCallBack,
1574 *CGM.getFileSystem(), ParentName);
1575}
1576
1578 auto AddrOfGlobal = [&VD, this]() { return CGM.GetAddrOfGlobal(VD); };
1579
1580 auto LinkageForVariable = [&VD, this]() {
1581 return CGM.getLLVMLinkageVarDefinition(VD);
1582 };
1583
1584 std::vector<llvm::GlobalVariable *> GeneratedRefs;
1585
1586 llvm::Type *LlvmPtrTy = CGM.getTypes().ConvertTypeForMem(
1587 CGM.getContext().getPointerType(VD->getType()));
1588 llvm::Constant *addr = OMPBuilder.getAddrOfDeclareTargetVar(
1590 VD->hasDefinition(CGM.getContext()) == VarDecl::DeclarationOnly,
1591 VD->isExternallyVisible(),
1593 VD->getCanonicalDecl()->getBeginLoc()),
1594 CGM.getMangledName(VD), GeneratedRefs, CGM.getLangOpts().OpenMPSimd,
1595 CGM.getLangOpts().OMPTargetTriples, LlvmPtrTy, AddrOfGlobal,
1596 LinkageForVariable);
1597
1598 if (!addr)
1599 return ConstantAddress::invalid();
1600 return ConstantAddress(addr, LlvmPtrTy, CGM.getContext().getDeclAlign(VD));
1601}
1602
1603llvm::Constant *
1605 assert(!CGM.getLangOpts().OpenMPUseTLS ||
1606 !CGM.getContext().getTargetInfo().isTLSSupported());
1607 // Lookup the entry, lazily creating it if necessary.
1608 std::string Suffix = getName({"cache", ""});
1609 return OMPBuilder.getOrCreateInternalVariable(
1610 CGM.Int8PtrPtrTy, Twine(CGM.getMangledName(VD)).concat(Suffix).str());
1611}
1612
1614 const VarDecl *VD,
1615 Address VDAddr,
1616 SourceLocation Loc) {
1617 if (CGM.getLangOpts().OpenMPUseTLS &&
1618 CGM.getContext().getTargetInfo().isTLSSupported())
1619 return VDAddr;
1620
1621 llvm::Type *VarTy = VDAddr.getElementType();
1622 llvm::Value *Args[] = {
1623 emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
1624 CGF.Builder.CreatePointerCast(VDAddr.emitRawPointer(CGF), CGM.Int8PtrTy),
1625 CGM.getSize(CGM.GetTargetTypeStoreSize(VarTy)),
1627 return Address(
1628 CGF.EmitRuntimeCall(
1629 OMPBuilder.getOrCreateRuntimeFunction(
1630 CGM.getModule(), OMPRTL___kmpc_threadprivate_cached),
1631 Args),
1632 CGF.Int8Ty, VDAddr.getAlignment());
1633}
1634
1636 CodeGenFunction &CGF, Address VDAddr, llvm::Value *Ctor,
1637 llvm::Value *CopyCtor, llvm::Value *Dtor, SourceLocation Loc) {
1638 // Call kmp_int32 __kmpc_global_thread_num(&loc) to init OpenMP runtime
1639 // library.
1640 llvm::Value *OMPLoc = emitUpdateLocation(CGF, Loc);
1641 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
1642 CGM.getModule(), OMPRTL___kmpc_global_thread_num),
1643 OMPLoc);
1644 // Call __kmpc_threadprivate_register(&loc, &var, ctor, cctor/*NULL*/, dtor)
1645 // to register constructor/destructor for variable.
1646 llvm::Value *Args[] = {
1647 OMPLoc,
1648 CGF.Builder.CreatePointerCast(VDAddr.emitRawPointer(CGF), CGM.VoidPtrTy),
1649 Ctor, CopyCtor, Dtor};
1650 CGF.EmitRuntimeCall(
1651 OMPBuilder.getOrCreateRuntimeFunction(
1652 CGM.getModule(), OMPRTL___kmpc_threadprivate_register),
1653 Args);
1654}
1655
1657 const VarDecl *VD, Address VDAddr, SourceLocation Loc,
1658 bool PerformInit, CodeGenFunction *CGF) {
1659 if (CGM.getLangOpts().OpenMPUseTLS &&
1660 CGM.getContext().getTargetInfo().isTLSSupported())
1661 return nullptr;
1662
1663 VD = VD->getDefinition(CGM.getContext());
1664 if (VD && ThreadPrivateWithDefinition.insert(CGM.getMangledName(VD)).second) {
1665 QualType ASTTy = VD->getType();
1666
1667 llvm::Value *Ctor = nullptr, *CopyCtor = nullptr, *Dtor = nullptr;
1668 const Expr *Init = VD->getAnyInitializer();
1669 if (CGM.getLangOpts().CPlusPlus && PerformInit) {
1670 // Generate function that re-emits the declaration's initializer into the
1671 // threadprivate copy of the variable VD
1672 CodeGenFunction CtorCGF(CGM);
1673 auto *Dst = ImplicitParamDecl::Create(
1674 CGM.getContext(), /*DC=*/nullptr, Loc,
1675 /*Id=*/nullptr, CGM.getContext().VoidPtrTy, ImplicitParamKind::Other);
1676
1677 FunctionArgList Args{Dst};
1678 const auto &FI = CGM.getTypes().arrangeBuiltinFunctionDeclaration(
1679 CGM.getContext().VoidPtrTy, Args);
1680 llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
1681 std::string Name = getName({"__kmpc_global_ctor_", ""});
1682 llvm::Function *Fn =
1683 CGM.CreateGlobalInitOrCleanUpFunction(FTy, Name, FI, Loc);
1684 CtorCGF.StartFunction(GlobalDecl(), CGM.getContext().VoidPtrTy, Fn, FI,
1685 Args, Loc, Loc);
1686 llvm::Value *ArgVal = CtorCGF.EmitLoadOfScalar(
1687 CtorCGF.GetAddrOfLocalVar(Dst), /*Volatile=*/false,
1688 CGM.getContext().VoidPtrTy, Dst->getLocation());
1689 Address Arg(ArgVal, CtorCGF.ConvertTypeForMem(ASTTy),
1690 VDAddr.getAlignment());
1691 CtorCGF.EmitAnyExprToMem(Init, Arg, Init->getType().getQualifiers(),
1692 /*IsInitializer=*/true);
1693 ArgVal = CtorCGF.EmitLoadOfScalar(
1694 CtorCGF.GetAddrOfLocalVar(Dst), /*Volatile=*/false,
1695 CGM.getContext().VoidPtrTy, Dst->getLocation());
1696 CtorCGF.Builder.CreateStore(ArgVal, CtorCGF.ReturnValue);
1697 CtorCGF.FinishFunction();
1698 Ctor = Fn;
1699 }
1701 // Generate function that emits destructor call for the threadprivate copy
1702 // of the variable VD
1703 CodeGenFunction DtorCGF(CGM);
1704 auto *Dst = ImplicitParamDecl::Create(
1705 CGM.getContext(), /*DC=*/nullptr, Loc,
1706 /*Id=*/nullptr, CGM.getContext().VoidPtrTy, ImplicitParamKind::Other);
1707
1708 FunctionArgList Args{Dst};
1709 const auto &FI = CGM.getTypes().arrangeBuiltinFunctionDeclaration(
1710 CGM.getContext().VoidTy, Args);
1711 llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
1712 std::string Name = getName({"__kmpc_global_dtor_", ""});
1713 llvm::Function *Fn =
1714 CGM.CreateGlobalInitOrCleanUpFunction(FTy, Name, FI, Loc);
1715 auto NL = ApplyDebugLocation::CreateEmpty(DtorCGF);
1716 DtorCGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, Fn, FI, Args,
1717 Loc, Loc);
1718 // Create a scope with an artificial location for the body of this function.
1719 auto AL = ApplyDebugLocation::CreateArtificial(DtorCGF);
1720 llvm::Value *ArgVal = DtorCGF.EmitLoadOfScalar(
1721 DtorCGF.GetAddrOfLocalVar(Dst),
1722 /*Volatile=*/false, CGM.getContext().VoidPtrTy, Dst->getLocation());
1723 DtorCGF.emitDestroy(
1724 Address(ArgVal, DtorCGF.Int8Ty, VDAddr.getAlignment()), ASTTy,
1725 DtorCGF.getDestroyer(ASTTy.isDestructedType()),
1726 DtorCGF.needsEHCleanup(ASTTy.isDestructedType()));
1727 DtorCGF.FinishFunction();
1728 Dtor = Fn;
1729 }
1730 // Do not emit init function if it is not required.
1731 if (!Ctor && !Dtor)
1732 return nullptr;
1733
1734 // Copying constructor for the threadprivate variable.
1735 // Must be NULL - reserved by runtime, but currently it requires that this
1736 // parameter is always NULL. Otherwise it fires assertion.
1737 CopyCtor = llvm::Constant::getNullValue(CGM.DefaultPtrTy);
1738 if (Ctor == nullptr) {
1739 Ctor = llvm::Constant::getNullValue(CGM.DefaultPtrTy);
1740 }
1741 if (Dtor == nullptr) {
1742 Dtor = llvm::Constant::getNullValue(CGM.DefaultPtrTy);
1743 }
1744 if (!CGF) {
1745 auto *InitFunctionTy =
1746 llvm::FunctionType::get(CGM.VoidTy, /*isVarArg*/ false);
1747 std::string Name = getName({"__omp_threadprivate_init_", ""});
1748 llvm::Function *InitFunction = CGM.CreateGlobalInitOrCleanUpFunction(
1749 InitFunctionTy, Name, CGM.getTypes().arrangeNullaryFunction());
1750 CodeGenFunction InitCGF(CGM);
1751 FunctionArgList ArgList;
1752 InitCGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, InitFunction,
1753 CGM.getTypes().arrangeNullaryFunction(), ArgList,
1754 Loc, Loc);
1755 emitThreadPrivateVarInit(InitCGF, VDAddr, Ctor, CopyCtor, Dtor, Loc);
1756 InitCGF.FinishFunction();
1757 return InitFunction;
1758 }
1759 emitThreadPrivateVarInit(*CGF, VDAddr, Ctor, CopyCtor, Dtor, Loc);
1760 }
1761 return nullptr;
1762}
1763
1765 llvm::GlobalValue *GV) {
1766 std::optional<OMPDeclareTargetDeclAttr *> ActiveAttr =
1767 OMPDeclareTargetDeclAttr::getActiveAttr(FD);
1768
1769 // We only need to handle active 'indirect' declare target functions.
1770 if (!ActiveAttr || !(*ActiveAttr)->getIndirect())
1771 return;
1772
1773 // Get a mangled name to store the new device global in.
1774 llvm::TargetRegionEntryInfo EntryInfo = getEntryInfoFromPresumedLoc(
1776 SmallString<128> Name;
1777 OMPBuilder.OffloadInfoManager.getTargetRegionEntryFnName(Name, EntryInfo);
1778
1779 // We need to generate a new global to hold the address of the indirectly
1780 // called device function. Doing this allows us to keep the visibility and
1781 // linkage of the associated function unchanged while allowing the runtime to
1782 // access its value.
1783 llvm::GlobalValue *Addr = GV;
1784 if (CGM.getLangOpts().OpenMPIsTargetDevice) {
1785 llvm::PointerType *FnPtrTy = llvm::PointerType::get(
1786 CGM.getLLVMContext(),
1787 CGM.getModule().getDataLayout().getProgramAddressSpace());
1788 Addr = new llvm::GlobalVariable(
1789 CGM.getModule(), FnPtrTy,
1790 /*isConstant=*/true, llvm::GlobalValue::ExternalLinkage, GV, Name,
1791 nullptr, llvm::GlobalValue::NotThreadLocal,
1792 CGM.getModule().getDataLayout().getDefaultGlobalsAddressSpace());
1793 Addr->setVisibility(llvm::GlobalValue::ProtectedVisibility);
1794 }
1795
1796 // Register the indirect Vtable:
1797 // This is similar to OMPTargetGlobalVarEntryIndirect, except that the
1798 // size field refers to the size of memory pointed to, not the size of
1799 // the pointer symbol itself (which is implicitly the size of a pointer).
1800 OMPBuilder.OffloadInfoManager.registerDeviceGlobalVarEntryInfo(
1801 Name, Addr, CGM.GetTargetTypeStoreSize(CGM.VoidPtrTy).getQuantity(),
1802 llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryIndirect,
1803 llvm::GlobalValue::WeakODRLinkage);
1804}
1805
1806void CGOpenMPRuntime::registerVTableOffloadEntry(llvm::GlobalVariable *VTable,
1807 const VarDecl *VD) {
1808 // TODO: add logic to avoid duplicate vtable registrations per
1809 // translation unit; though for external linkage, this should no
1810 // longer be an issue - or at least we can avoid the issue by
1811 // checking for an existing offloading entry. But, perhaps the
1812 // better approach is to defer emission of the vtables and offload
1813 // entries until later (by tracking a list of items that need to be
1814 // emitted).
1815
1816 llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
1817
1818 // Generate a new externally visible global to point to the
1819 // internally visible vtable. Doing this allows us to keep the
1820 // visibility and linkage of the associated vtable unchanged while
1821 // allowing the runtime to access its value. The externally
1822 // visible global var needs to be emitted with a unique mangled
1823 // name that won't conflict with similarly named (internal)
1824 // vtables in other translation units.
1825
1826 // Register vtable with source location of dynamic object in map
1827 // clause.
1828 llvm::TargetRegionEntryInfo EntryInfo = getEntryInfoFromPresumedLoc(
1830 VTable->getName());
1831
1832 llvm::GlobalVariable *Addr = VTable;
1833 SmallString<128> AddrName;
1834 OMPBuilder.OffloadInfoManager.getTargetRegionEntryFnName(AddrName, EntryInfo);
1835 AddrName.append("addr");
1836
1837 if (CGM.getLangOpts().OpenMPIsTargetDevice) {
1838 Addr = new llvm::GlobalVariable(
1839 CGM.getModule(), VTable->getType(),
1840 /*isConstant=*/true, llvm::GlobalValue::ExternalLinkage, VTable,
1841 AddrName,
1842 /*InsertBefore=*/nullptr, llvm::GlobalValue::NotThreadLocal,
1843 CGM.getModule().getDataLayout().getDefaultGlobalsAddressSpace());
1844 Addr->setVisibility(llvm::GlobalValue::ProtectedVisibility);
1845 }
1846 OMPBuilder.OffloadInfoManager.registerDeviceGlobalVarEntryInfo(
1847 AddrName, VTable,
1848 CGM.getDataLayout().getTypeAllocSize(VTable->getInitializer()->getType()),
1849 llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryIndirectVTable,
1850 llvm::GlobalValue::WeakODRLinkage);
1851}
1852
1855 const VarDecl *VD) {
1856 // Register C++ VTable to OpenMP Offload Entry if it's a new
1857 // CXXRecordDecl.
1858 if (CXXRecord && CXXRecord->hasDefinition() && CXXRecord->isDynamicClass() &&
1859 !CGM.getOpenMPRuntime().VTableDeclMap.contains(CXXRecord)) {
1860 auto Res = CGM.getOpenMPRuntime().VTableDeclMap.try_emplace(CXXRecord, VD);
1861 if (Res.second) {
1862 CGM.EmitVTable(CXXRecord);
1863 CodeGenVTables VTables = CGM.getVTables();
1864 llvm::GlobalVariable *VTablesAddr = VTables.GetAddrOfVTable(CXXRecord);
1865 assert(VTablesAddr && "Expected non-null VTable address");
1866 // Must set VTables to weak since we're emitting them in multiple TUs now
1867 if (VTablesAddr->hasExternalLinkage())
1868 VTablesAddr->setLinkage(llvm::GlobalValue::WeakODRLinkage);
1869 CGM.getOpenMPRuntime().registerVTableOffloadEntry(VTablesAddr, VD);
1870 // Emit VTable for all the fields containing dynamic CXXRecord
1871 for (const FieldDecl *Field : CXXRecord->fields()) {
1872 if (CXXRecordDecl *RecordDecl = Field->getType()->getAsCXXRecordDecl())
1874 }
1875 // Emit VTable for all dynamic parent class
1876 for (CXXBaseSpecifier &Base : CXXRecord->bases()) {
1877 if (CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl())
1878 emitAndRegisterVTable(CGM, BaseDecl, VD);
1879 }
1880 }
1881 }
1882}
1883
1885 // Register VTable by scanning through the map clause of OpenMP target region.
1886 // Get CXXRecordDecl and VarDecl from Expr.
1887 auto GetVTableDecl = [](const Expr *E) {
1888 QualType VDTy = E->getType();
1889 CXXRecordDecl *CXXRecord = nullptr;
1890 if (const auto *RefType = VDTy->getAs<LValueReferenceType>())
1891 VDTy = RefType->getPointeeType();
1892 if (VDTy->isPointerType())
1894 else
1895 CXXRecord = VDTy->getAsCXXRecordDecl();
1896
1897 const VarDecl *VD = nullptr;
1898 if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
1899 // Handle BindingDecls by redirecting to their DecompositionDecl.
1900 if (auto *BD = dyn_cast<BindingDecl>(DRE->getDecl()))
1901 VD = cast<VarDecl>(BD->getDecomposedDecl());
1902 else
1903 VD = cast<VarDecl>(DRE->getDecl());
1904 } else if (auto *MRE = dyn_cast<MemberExpr>(E)) {
1905 if (auto *BaseDRE = dyn_cast<DeclRefExpr>(MRE->getBase())) {
1906 if (auto *BaseVD = dyn_cast<VarDecl>(BaseDRE->getDecl()))
1907 VD = BaseVD;
1908 }
1909 }
1910 return std::pair<CXXRecordDecl *, const VarDecl *>(CXXRecord, VD);
1911 };
1912 // Collect VTable from OpenMP map clause.
1913 for (const auto *C : D.getClausesOfKind<OMPMapClause>()) {
1914 for (const auto *E : C->varlist()) {
1915 auto DeclPair = GetVTableDecl(E);
1916 // Ensure VD is not null
1917 if (DeclPair.second)
1918 emitAndRegisterVTable(CGM, DeclPair.first, DeclPair.second);
1919 }
1920 }
1921}
1922
1924 QualType VarType,
1925 StringRef Name) {
1926 std::string Suffix = getName({"artificial", ""});
1927 llvm::Type *VarLVType = CGF.ConvertTypeForMem(VarType);
1928 llvm::GlobalVariable *GAddr = OMPBuilder.getOrCreateInternalVariable(
1929 VarLVType, Twine(Name).concat(Suffix).str());
1930 if (CGM.getLangOpts().OpenMP && CGM.getLangOpts().OpenMPUseTLS &&
1931 CGM.getTarget().isTLSSupported()) {
1932 GAddr->setThreadLocal(/*Val=*/true);
1933 return Address(GAddr, GAddr->getValueType(),
1934 CGM.getContext().getTypeAlignInChars(VarType));
1935 }
1936 std::string CacheSuffix = getName({"cache", ""});
1937 llvm::Value *Args[] = {
1940 CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(GAddr, CGM.VoidPtrTy),
1941 CGF.Builder.CreateIntCast(CGF.getTypeSize(VarType), CGM.SizeTy,
1942 /*isSigned=*/false),
1943 OMPBuilder.getOrCreateInternalVariable(
1944 CGM.VoidPtrPtrTy,
1945 Twine(Name).concat(Suffix).concat(CacheSuffix).str())};
1946 return Address(
1948 CGF.EmitRuntimeCall(
1949 OMPBuilder.getOrCreateRuntimeFunction(
1950 CGM.getModule(), OMPRTL___kmpc_threadprivate_cached),
1951 Args),
1952 CGF.Builder.getPtrTy(0)),
1953 VarLVType, CGM.getContext().getTypeAlignInChars(VarType));
1954}
1955
1957 const RegionCodeGenTy &ThenGen,
1958 const RegionCodeGenTy &ElseGen) {
1959 CodeGenFunction::LexicalScope ConditionScope(CGF, Cond->getSourceRange());
1960
1961 // If the condition constant folds and can be elided, try to avoid emitting
1962 // the condition and the dead arm of the if/else.
1963 bool CondConstant;
1964 if (CGF.ConstantFoldsToSimpleInteger(Cond, CondConstant)) {
1965 if (CondConstant)
1966 ThenGen(CGF);
1967 else
1968 ElseGen(CGF);
1969 return;
1970 }
1971
1972 // Otherwise, the condition did not fold, or we couldn't elide it. Just
1973 // emit the conditional branch.
1974 llvm::BasicBlock *ThenBlock = CGF.createBasicBlock("omp_if.then");
1975 llvm::BasicBlock *ElseBlock = CGF.createBasicBlock("omp_if.else");
1976 llvm::BasicBlock *ContBlock = CGF.createBasicBlock("omp_if.end");
1977 CGF.EmitBranchOnBoolExpr(Cond, ThenBlock, ElseBlock, /*TrueCount=*/0);
1978
1979 // Emit the 'then' code.
1980 CGF.EmitBlock(ThenBlock);
1981 ThenGen(CGF);
1982 CGF.EmitBranch(ContBlock);
1983 // Emit the 'else' code if present.
1984 // There is no need to emit line number for unconditional branch.
1986 CGF.EmitBlock(ElseBlock);
1987 ElseGen(CGF);
1988 // There is no need to emit line number for unconditional branch.
1990 CGF.EmitBranch(ContBlock);
1991 // Emit the continuation block for code after the if.
1992 CGF.EmitBlock(ContBlock, /*IsFinished=*/true);
1993}
1994
1996 CodeGenFunction &CGF, SourceLocation Loc, llvm::Function *OutlinedFn,
1997 ArrayRef<llvm::Value *> CapturedVars, const Expr *IfCond,
1998 llvm::Value *NumThreads, OpenMPNumThreadsClauseModifier NumThreadsModifier,
1999 OpenMPSeverityClauseKind Severity, const Expr *Message) {
2000 if (!CGF.HaveInsertPoint())
2001 return;
2002 llvm::Value *RTLoc = emitUpdateLocation(CGF, Loc);
2003 auto &M = CGM.getModule();
2004 auto &&ThenGen = [&M, OutlinedFn, CapturedVars, RTLoc,
2005 this](CodeGenFunction &CGF, PrePostActionTy &) {
2006 // Build call __kmpc_fork_call(loc, n, microtask, var1, .., varn);
2007 llvm::Value *Args[] = {
2008 RTLoc,
2009 CGF.Builder.getInt32(CapturedVars.size()), // Number of captured vars
2010 OutlinedFn};
2012 RealArgs.append(std::begin(Args), std::end(Args));
2013 RealArgs.append(CapturedVars.begin(), CapturedVars.end());
2014
2015 llvm::FunctionCallee RTLFn =
2016 OMPBuilder.getOrCreateRuntimeFunction(M, OMPRTL___kmpc_fork_call);
2017 CGF.EmitRuntimeCall(RTLFn, RealArgs);
2018 };
2019 auto &&ElseGen = [&M, OutlinedFn, CapturedVars, RTLoc, Loc,
2020 this](CodeGenFunction &CGF, PrePostActionTy &) {
2022 llvm::Value *ThreadID = RT.getThreadID(CGF, Loc);
2023 // Build calls:
2024 // __kmpc_serialized_parallel(&Loc, GTid);
2025 llvm::Value *Args[] = {RTLoc, ThreadID};
2026 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
2027 M, OMPRTL___kmpc_serialized_parallel),
2028 Args);
2029
2030 // OutlinedFn(&GTid, &zero_bound, CapturedStruct);
2031 Address ThreadIDAddr = RT.emitThreadIDAddress(CGF, Loc);
2032 RawAddress ZeroAddrBound =
2034 /*Name=*/".bound.zero.addr");
2035 CGF.Builder.CreateStore(CGF.Builder.getInt32(/*C*/ 0), ZeroAddrBound);
2037 // ThreadId for serialized parallels is 0.
2038 OutlinedFnArgs.push_back(ThreadIDAddr.emitRawPointer(CGF));
2039 OutlinedFnArgs.push_back(ZeroAddrBound.getPointer());
2040 OutlinedFnArgs.append(CapturedVars.begin(), CapturedVars.end());
2041
2042 // Ensure we do not inline the function. This is trivially true for the ones
2043 // passed to __kmpc_fork_call but the ones called in serialized regions
2044 // could be inlined. This is not a perfect but it is closer to the invariant
2045 // we want, namely, every data environment starts with a new function.
2046 // TODO: We should pass the if condition to the runtime function and do the
2047 // handling there. Much cleaner code.
2048 OutlinedFn->removeFnAttr(llvm::Attribute::AlwaysInline);
2049 OutlinedFn->addFnAttr(llvm::Attribute::NoInline);
2050 RT.emitOutlinedFunctionCall(CGF, Loc, OutlinedFn, OutlinedFnArgs);
2051
2052 // __kmpc_end_serialized_parallel(&Loc, GTid);
2053 llvm::Value *EndArgs[] = {RT.emitUpdateLocation(CGF, Loc), ThreadID};
2054 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
2055 M, OMPRTL___kmpc_end_serialized_parallel),
2056 EndArgs);
2057 };
2058 if (IfCond) {
2059 emitIfClause(CGF, IfCond, ThenGen, ElseGen);
2060 } else {
2061 RegionCodeGenTy ThenRCG(ThenGen);
2062 ThenRCG(CGF);
2063 }
2064}
2065
2066// If we're inside an (outlined) parallel region, use the region info's
2067// thread-ID variable (it is passed in a first argument of the outlined function
2068// as "kmp_int32 *gtid"). Otherwise, if we're not inside parallel region, but in
2069// regular serial code region, get thread ID by calling kmp_int32
2070// kmpc_global_thread_num(ident_t *loc), stash this thread ID in a temporary and
2071// return the address of that temp.
2073 SourceLocation Loc) {
2074 if (auto *OMPRegionInfo =
2075 dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo))
2076 if (OMPRegionInfo->getThreadIDVariable())
2077 return OMPRegionInfo->getThreadIDVariableLValue(CGF).getAddress();
2078
2079 llvm::Value *ThreadID = getThreadID(CGF, Loc);
2080 QualType Int32Ty =
2081 CGF.getContext().getIntTypeForBitwidth(/*DestWidth*/ 32, /*Signed*/ true);
2082 Address ThreadIDTemp =
2083 CGF.CreateMemTempWithoutCast(Int32Ty, /*Name*/ ".threadid_temp.");
2084 CGF.EmitStoreOfScalar(ThreadID,
2085 CGF.MakeAddrLValue(ThreadIDTemp, Int32Ty));
2086
2087 return ThreadIDTemp;
2088}
2089
2090llvm::Value *CGOpenMPRuntime::getCriticalRegionLock(StringRef CriticalName) {
2091 std::string Prefix = Twine("gomp_critical_user_", CriticalName).str();
2092 std::string Name = getName({Prefix, "var"});
2093 llvm::GlobalVariable *GV =
2094 OMPBuilder.getOrCreateInternalVariable(KmpCriticalNameTy, Name);
2095 CGM.setDSOLocal(GV);
2096 return GV;
2097}
2098
2099namespace {
2100/// Common pre(post)-action for different OpenMP constructs.
2101class CommonActionTy final : public PrePostActionTy {
2102 llvm::FunctionCallee EnterCallee;
2103 ArrayRef<llvm::Value *> EnterArgs;
2104 llvm::FunctionCallee ExitCallee;
2105 ArrayRef<llvm::Value *> ExitArgs;
2106 bool Conditional;
2107 llvm::BasicBlock *ContBlock = nullptr;
2108
2109public:
2110 CommonActionTy(llvm::FunctionCallee EnterCallee,
2111 ArrayRef<llvm::Value *> EnterArgs,
2112 llvm::FunctionCallee ExitCallee,
2113 ArrayRef<llvm::Value *> ExitArgs, bool Conditional = false)
2114 : EnterCallee(EnterCallee), EnterArgs(EnterArgs), ExitCallee(ExitCallee),
2115 ExitArgs(ExitArgs), Conditional(Conditional) {}
2116 void Enter(CodeGenFunction &CGF) override {
2117 llvm::Value *EnterRes = CGF.EmitRuntimeCall(EnterCallee, EnterArgs);
2118 if (Conditional) {
2119 llvm::Value *CallBool = CGF.Builder.CreateIsNotNull(EnterRes);
2120 auto *ThenBlock = CGF.createBasicBlock("omp_if.then");
2121 ContBlock = CGF.createBasicBlock("omp_if.end");
2122 // Generate the branch (If-stmt)
2123 CGF.Builder.CreateCondBr(CallBool, ThenBlock, ContBlock);
2124 CGF.EmitBlock(ThenBlock);
2125 }
2126 }
2127 void Done(CodeGenFunction &CGF) {
2128 // Emit the rest of blocks/branches
2129 CGF.EmitBranch(ContBlock);
2130 CGF.EmitBlock(ContBlock, true);
2131 }
2132 void Exit(CodeGenFunction &CGF) override {
2133 CGF.EmitRuntimeCall(ExitCallee, ExitArgs);
2134 }
2135};
2136} // anonymous namespace
2137
2139 StringRef CriticalName,
2140 const RegionCodeGenTy &CriticalOpGen,
2141 SourceLocation Loc, const Expr *Hint) {
2142 // __kmpc_critical[_with_hint](ident_t *, gtid, Lock[, hint]);
2143 // CriticalOpGen();
2144 // __kmpc_end_critical(ident_t *, gtid, Lock);
2145 // Prepare arguments and build a call to __kmpc_critical
2146 if (!CGF.HaveInsertPoint())
2147 return;
2148 llvm::FunctionCallee RuntimeFcn = OMPBuilder.getOrCreateRuntimeFunction(
2149 CGM.getModule(),
2150 Hint ? OMPRTL___kmpc_critical_with_hint : OMPRTL___kmpc_critical);
2151 llvm::Value *LockVar = getCriticalRegionLock(CriticalName);
2152 unsigned LockVarArgIdx = 2;
2153 if (cast<llvm::GlobalVariable>(LockVar)->getAddressSpace() !=
2154 RuntimeFcn.getFunctionType()
2155 ->getParamType(LockVarArgIdx)
2156 ->getPointerAddressSpace())
2157 LockVar = CGF.Builder.CreateAddrSpaceCast(
2158 LockVar, RuntimeFcn.getFunctionType()->getParamType(LockVarArgIdx));
2159 llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
2160 LockVar};
2161 llvm::SmallVector<llvm::Value *, 4> EnterArgs(std::begin(Args),
2162 std::end(Args));
2163 if (Hint) {
2164 EnterArgs.push_back(CGF.Builder.CreateIntCast(
2165 CGF.EmitScalarExpr(Hint), CGM.Int32Ty, /*isSigned=*/false));
2166 }
2167 CommonActionTy Action(RuntimeFcn, EnterArgs,
2168 OMPBuilder.getOrCreateRuntimeFunction(
2169 CGM.getModule(), OMPRTL___kmpc_end_critical),
2170 Args);
2171 CriticalOpGen.setAction(Action);
2172 emitInlinedDirective(CGF, OMPD_critical, CriticalOpGen);
2173}
2174
2176 const RegionCodeGenTy &MasterOpGen,
2177 SourceLocation Loc) {
2178 if (!CGF.HaveInsertPoint())
2179 return;
2180 // if(__kmpc_master(ident_t *, gtid)) {
2181 // MasterOpGen();
2182 // __kmpc_end_master(ident_t *, gtid);
2183 // }
2184 // Prepare arguments and build a call to __kmpc_master
2185 llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
2186 CommonActionTy Action(OMPBuilder.getOrCreateRuntimeFunction(
2187 CGM.getModule(), OMPRTL___kmpc_master),
2188 Args,
2189 OMPBuilder.getOrCreateRuntimeFunction(
2190 CGM.getModule(), OMPRTL___kmpc_end_master),
2191 Args,
2192 /*Conditional=*/true);
2193 MasterOpGen.setAction(Action);
2194 emitInlinedDirective(CGF, OMPD_master, MasterOpGen);
2195 Action.Done(CGF);
2196}
2197
2199 const RegionCodeGenTy &MaskedOpGen,
2200 SourceLocation Loc, const Expr *Filter) {
2201 if (!CGF.HaveInsertPoint())
2202 return;
2203 // if(__kmpc_masked(ident_t *, gtid, filter)) {
2204 // MaskedOpGen();
2205 // __kmpc_end_masked(iden_t *, gtid);
2206 // }
2207 // Prepare arguments and build a call to __kmpc_masked
2208 llvm::Value *FilterVal = Filter
2209 ? CGF.EmitScalarExpr(Filter, CGF.Int32Ty)
2210 : llvm::ConstantInt::get(CGM.Int32Ty, /*V=*/0);
2211 llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
2212 FilterVal};
2213 llvm::Value *ArgsEnd[] = {emitUpdateLocation(CGF, Loc),
2214 getThreadID(CGF, Loc)};
2215 CommonActionTy Action(OMPBuilder.getOrCreateRuntimeFunction(
2216 CGM.getModule(), OMPRTL___kmpc_masked),
2217 Args,
2218 OMPBuilder.getOrCreateRuntimeFunction(
2219 CGM.getModule(), OMPRTL___kmpc_end_masked),
2220 ArgsEnd,
2221 /*Conditional=*/true);
2222 MaskedOpGen.setAction(Action);
2223 emitInlinedDirective(CGF, OMPD_masked, MaskedOpGen);
2224 Action.Done(CGF);
2225}
2226
2228 SourceLocation Loc) {
2229 if (!CGF.HaveInsertPoint())
2230 return;
2231 if (CGF.CGM.getLangOpts().OpenMPIRBuilder) {
2232 OMPBuilder.createTaskyield(CGF.Builder);
2233 } else {
2234 // Build call __kmpc_omp_taskyield(loc, thread_id, 0);
2235 llvm::Value *Args[] = {
2236 emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
2237 llvm::ConstantInt::get(CGM.IntTy, /*V=*/0, /*isSigned=*/true)};
2238 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
2239 CGM.getModule(), OMPRTL___kmpc_omp_taskyield),
2240 Args);
2241 }
2242
2243 if (auto *Region = dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo))
2244 Region->emitUntiedSwitch(CGF);
2245}
2246
2248 const RegionCodeGenTy &TaskgroupOpGen,
2249 SourceLocation Loc) {
2250 if (!CGF.HaveInsertPoint())
2251 return;
2252 // __kmpc_taskgroup(ident_t *, gtid);
2253 // TaskgroupOpGen();
2254 // __kmpc_end_taskgroup(ident_t *, gtid);
2255 // Prepare arguments and build a call to __kmpc_taskgroup
2256 llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
2257 CommonActionTy Action(OMPBuilder.getOrCreateRuntimeFunction(
2258 CGM.getModule(), OMPRTL___kmpc_taskgroup),
2259 Args,
2260 OMPBuilder.getOrCreateRuntimeFunction(
2261 CGM.getModule(), OMPRTL___kmpc_end_taskgroup),
2262 Args);
2263 TaskgroupOpGen.setAction(Action);
2264 emitInlinedDirective(CGF, OMPD_taskgroup, TaskgroupOpGen);
2265}
2266
2267/// Given an array of pointers to variables, project the address of a
2268/// given variable.
2270 unsigned Index, const VarDecl *Var) {
2271 // Pull out the pointer to the variable.
2272 Address PtrAddr = CGF.Builder.CreateConstArrayGEP(Array, Index);
2273 llvm::Value *Ptr = CGF.Builder.CreateLoad(PtrAddr);
2274
2275 llvm::Type *ElemTy = CGF.ConvertTypeForMem(Var->getType());
2276 return Address(Ptr, ElemTy, CGF.getContext().getDeclAlign(Var));
2277}
2278
2280 CodeGenModule &CGM, llvm::Type *ArgsElemType,
2281 ArrayRef<const Expr *> CopyprivateVars, ArrayRef<const Expr *> DestExprs,
2282 ArrayRef<const Expr *> SrcExprs, ArrayRef<const Expr *> AssignmentOps,
2283 SourceLocation Loc) {
2284 ASTContext &C = CGM.getContext();
2285 // void copy_func(void *LHSArg, void *RHSArg);
2286
2287 auto *LHSArg =
2288 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
2289 C.VoidPtrTy, ImplicitParamKind::Other);
2290 auto *RHSArg =
2291 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
2292 C.VoidPtrTy, ImplicitParamKind::Other);
2293 FunctionArgList Args{LHSArg, RHSArg};
2294 const auto &CGFI =
2295 CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
2296 std::string Name =
2297 CGM.getOpenMPRuntime().getName({"omp", "copyprivate", "copy_func"});
2298 auto *Fn = llvm::Function::Create(CGM.getTypes().GetFunctionType(CGFI),
2299 llvm::GlobalValue::InternalLinkage, Name,
2300 &CGM.getModule());
2302 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
2303 Fn->addFnAttr("sample-profile-suffix-elision-policy", "selected");
2304 Fn->setDoesNotRecurse();
2305 CodeGenFunction CGF(CGM);
2306 CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, CGFI, Args, Loc, Loc);
2307 // Dest = (void*[n])(LHSArg);
2308 // Src = (void*[n])(RHSArg);
2310 CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(LHSArg)),
2311 CGF.Builder.getPtrTy(0)),
2312 ArgsElemType, CGF.getPointerAlign());
2314 CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(RHSArg)),
2315 CGF.Builder.getPtrTy(0)),
2316 ArgsElemType, CGF.getPointerAlign());
2317 // *(Type0*)Dst[0] = *(Type0*)Src[0];
2318 // *(Type1*)Dst[1] = *(Type1*)Src[1];
2319 // ...
2320 // *(Typen*)Dst[n] = *(Typen*)Src[n];
2321 for (unsigned I = 0, E = AssignmentOps.size(); I < E; ++I) {
2322 const auto *DestVar =
2323 cast<VarDecl>(cast<DeclRefExpr>(DestExprs[I])->getDecl());
2324 Address DestAddr = emitAddrOfVarFromArray(CGF, LHS, I, DestVar);
2325
2326 const auto *SrcVar =
2327 cast<VarDecl>(cast<DeclRefExpr>(SrcExprs[I])->getDecl());
2328 Address SrcAddr = emitAddrOfVarFromArray(CGF, RHS, I, SrcVar);
2329
2330 const auto *VD = cast<DeclRefExpr>(CopyprivateVars[I])->getDecl();
2331 QualType Type = VD->getType();
2332 CGF.EmitOMPCopy(Type, DestAddr, SrcAddr, DestVar, SrcVar, AssignmentOps[I]);
2333 }
2334 CGF.FinishFunction();
2335 return Fn;
2336}
2337
2339 const RegionCodeGenTy &SingleOpGen,
2340 SourceLocation Loc,
2341 ArrayRef<const Expr *> CopyprivateVars,
2342 ArrayRef<const Expr *> SrcExprs,
2343 ArrayRef<const Expr *> DstExprs,
2344 ArrayRef<const Expr *> AssignmentOps) {
2345 if (!CGF.HaveInsertPoint())
2346 return;
2347 assert(CopyprivateVars.size() == SrcExprs.size() &&
2348 CopyprivateVars.size() == DstExprs.size() &&
2349 CopyprivateVars.size() == AssignmentOps.size());
2350 ASTContext &C = CGM.getContext();
2351 // int32 did_it = 0;
2352 // if(__kmpc_single(ident_t *, gtid)) {
2353 // SingleOpGen();
2354 // __kmpc_end_single(ident_t *, gtid);
2355 // did_it = 1;
2356 // }
2357 // call __kmpc_copyprivate(ident_t *, gtid, <buf_size>, <copyprivate list>,
2358 // <copy_func>, did_it);
2359
2360 Address DidIt = Address::invalid();
2361 if (!CopyprivateVars.empty()) {
2362 // int32 did_it = 0;
2363 QualType KmpInt32Ty =
2364 C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1);
2365 DidIt = CGF.CreateMemTempWithoutCast(KmpInt32Ty, ".omp.copyprivate.did_it");
2366 CGF.Builder.CreateStore(CGF.Builder.getInt32(0), DidIt);
2367 }
2368 // Prepare arguments and build a call to __kmpc_single
2369 llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
2370 CommonActionTy Action(OMPBuilder.getOrCreateRuntimeFunction(
2371 CGM.getModule(), OMPRTL___kmpc_single),
2372 Args,
2373 OMPBuilder.getOrCreateRuntimeFunction(
2374 CGM.getModule(), OMPRTL___kmpc_end_single),
2375 Args,
2376 /*Conditional=*/true);
2377 SingleOpGen.setAction(Action);
2378 emitInlinedDirective(CGF, OMPD_single, SingleOpGen);
2379 if (DidIt.isValid()) {
2380 // did_it = 1;
2381 CGF.Builder.CreateStore(CGF.Builder.getInt32(1), DidIt);
2382 }
2383 Action.Done(CGF);
2384 // call __kmpc_copyprivate(ident_t *, gtid, <buf_size>, <copyprivate list>,
2385 // <copy_func>, did_it);
2386 if (DidIt.isValid()) {
2387 llvm::APInt ArraySize(/*unsigned int numBits=*/32, CopyprivateVars.size());
2388 QualType CopyprivateArrayTy = C.getConstantArrayType(
2389 C.VoidPtrTy, ArraySize, nullptr, ArraySizeModifier::Normal,
2390 /*IndexTypeQuals=*/0);
2391 // Create a list of all private variables for copyprivate.
2392 Address CopyprivateList = CGF.CreateMemTempWithoutCast(
2393 CopyprivateArrayTy, ".omp.copyprivate.cpr_list");
2394 for (unsigned I = 0, E = CopyprivateVars.size(); I < E; ++I) {
2395 Address Elem = CGF.Builder.CreateConstArrayGEP(CopyprivateList, I);
2396 CGF.Builder.CreateStore(
2398 CGF.EmitLValue(CopyprivateVars[I]).getPointer(CGF),
2399 CGF.VoidPtrTy),
2400 Elem);
2401 }
2402 // Build function that copies private values from single region to all other
2403 // threads in the corresponding parallel region.
2404 llvm::Value *CpyFn = emitCopyprivateCopyFunction(
2405 CGM, CGF.ConvertTypeForMem(CopyprivateArrayTy), CopyprivateVars,
2406 SrcExprs, DstExprs, AssignmentOps, Loc);
2407 llvm::Value *BufSize = CGF.getTypeSize(CopyprivateArrayTy);
2409 CopyprivateList, CGF.VoidPtrTy, CGF.Int8Ty);
2410 llvm::Value *DidItVal = CGF.Builder.CreateLoad(DidIt);
2411 llvm::Value *Args[] = {
2412 emitUpdateLocation(CGF, Loc), // ident_t *<loc>
2413 getThreadID(CGF, Loc), // i32 <gtid>
2414 BufSize, // size_t <buf_size>
2415 CL.emitRawPointer(CGF), // void *<copyprivate list>
2416 CpyFn, // void (*) (void *, void *) <copy_func>
2417 DidItVal // i32 did_it
2418 };
2419 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
2420 CGM.getModule(), OMPRTL___kmpc_copyprivate),
2421 Args);
2422 }
2423}
2424
2426 const RegionCodeGenTy &OrderedOpGen,
2427 SourceLocation Loc, bool IsThreads) {
2428 if (!CGF.HaveInsertPoint())
2429 return;
2430 // __kmpc_ordered(ident_t *, gtid);
2431 // OrderedOpGen();
2432 // __kmpc_end_ordered(ident_t *, gtid);
2433 // Prepare arguments and build a call to __kmpc_ordered
2434 if (IsThreads) {
2435 llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
2436 CommonActionTy Action(OMPBuilder.getOrCreateRuntimeFunction(
2437 CGM.getModule(), OMPRTL___kmpc_ordered),
2438 Args,
2439 OMPBuilder.getOrCreateRuntimeFunction(
2440 CGM.getModule(), OMPRTL___kmpc_end_ordered),
2441 Args);
2442 OrderedOpGen.setAction(Action);
2443 emitInlinedDirective(CGF, OMPD_ordered_blockassoc, OrderedOpGen);
2444 return;
2445 }
2446 emitInlinedDirective(CGF, OMPD_ordered_blockassoc, OrderedOpGen);
2447}
2448
2450 unsigned Flags;
2451 if (Kind == OMPD_for)
2452 Flags = OMP_IDENT_BARRIER_IMPL_FOR;
2453 else if (Kind == OMPD_sections)
2454 Flags = OMP_IDENT_BARRIER_IMPL_SECTIONS;
2455 else if (Kind == OMPD_single)
2456 Flags = OMP_IDENT_BARRIER_IMPL_SINGLE;
2457 else if (Kind == OMPD_barrier)
2458 Flags = OMP_IDENT_BARRIER_EXPL;
2459 else
2460 Flags = OMP_IDENT_BARRIER_IMPL;
2461 return Flags;
2462}
2463
2465 CodeGenFunction &CGF, const OMPLoopDirective &S,
2466 OpenMPScheduleClauseKind &ScheduleKind, const Expr *&ChunkExpr) const {
2467 // Check if the loop directive is actually a doacross loop directive. In this
2468 // case choose static, 1 schedule.
2469 if (llvm::any_of(
2470 S.getClausesOfKind<OMPOrderedClause>(),
2471 [](const OMPOrderedClause *C) { return C->getNumForLoops(); })) {
2472 ScheduleKind = OMPC_SCHEDULE_static;
2473 // Chunk size is 1 in this case.
2474 llvm::APInt ChunkSize(32, 1);
2475 ChunkExpr = IntegerLiteral::Create(
2476 CGF.getContext(), ChunkSize,
2477 CGF.getContext().getIntTypeForBitwidth(32, /*Signed=*/0),
2478 SourceLocation());
2479 }
2480}
2481
2483 OpenMPDirectiveKind Kind, bool EmitChecks,
2484 bool ForceSimpleCall) {
2485 // Check if we should use the OMPBuilder
2486 auto *OMPRegionInfo =
2487 dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo);
2488 if (CGF.CGM.getLangOpts().OpenMPIRBuilder) {
2489 llvm::OpenMPIRBuilder::InsertPointTy AfterIP =
2490 cantFail(OMPBuilder.createBarrier(CGF.Builder, Kind, ForceSimpleCall,
2491 EmitChecks));
2492 CGF.Builder.restoreIP(AfterIP);
2493 return;
2494 }
2495
2496 if (!CGF.HaveInsertPoint())
2497 return;
2498 // Build call __kmpc_cancel_barrier(loc, thread_id);
2499 // Build call __kmpc_barrier(loc, thread_id);
2500 unsigned Flags = getDefaultFlagsForBarriers(Kind);
2501 // Build call __kmpc_cancel_barrier(loc, thread_id) or __kmpc_barrier(loc,
2502 // thread_id);
2503 llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc, Flags),
2504 getThreadID(CGF, Loc)};
2505 if (OMPRegionInfo) {
2506 if (!ForceSimpleCall && OMPRegionInfo->hasCancel()) {
2507 llvm::Value *Result = CGF.EmitRuntimeCall(
2508 OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(),
2509 OMPRTL___kmpc_cancel_barrier),
2510 Args);
2511 if (EmitChecks) {
2512 // if (__kmpc_cancel_barrier()) {
2513 // exit from construct;
2514 // }
2515 llvm::BasicBlock *ExitBB = CGF.createBasicBlock(".cancel.exit");
2516 llvm::BasicBlock *ContBB = CGF.createBasicBlock(".cancel.continue");
2517 llvm::Value *Cmp = CGF.Builder.CreateIsNotNull(Result);
2518 CGF.Builder.CreateCondBr(Cmp, ExitBB, ContBB);
2519 CGF.EmitBlock(ExitBB);
2520 // exit from construct;
2521 CodeGenFunction::JumpDest CancelDestination =
2522 CGF.getOMPCancelDestination(OMPRegionInfo->getDirectiveKind());
2523 CGF.EmitBranchThroughCleanup(CancelDestination);
2524 CGF.EmitBlock(ContBB, /*IsFinished=*/true);
2525 }
2526 return;
2527 }
2528 }
2529 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
2530 CGM.getModule(), OMPRTL___kmpc_barrier),
2531 Args);
2532}
2533
2535 Expr *ME, bool IsFatal) {
2536 llvm::Value *MVL = ME ? CGF.EmitScalarExpr(ME)
2537 : llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
2538 // Build call void __kmpc_error(ident_t *loc, int severity, const char
2539 // *message)
2540 llvm::Value *Args[] = {
2541 emitUpdateLocation(CGF, Loc, /*Flags=*/0, /*GenLoc=*/true),
2542 llvm::ConstantInt::get(CGM.Int32Ty, IsFatal ? 2 : 1),
2543 CGF.Builder.CreatePointerCast(MVL, CGM.Int8PtrTy)};
2544 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
2545 CGM.getModule(), OMPRTL___kmpc_error),
2546 Args);
2547}
2548
2549/// Map the OpenMP loop schedule to the runtime enumeration.
2550static OpenMPSchedType getRuntimeSchedule(OpenMPScheduleClauseKind ScheduleKind,
2551 bool Chunked, bool Ordered) {
2552 switch (ScheduleKind) {
2553 case OMPC_SCHEDULE_static:
2554 return Chunked ? (Ordered ? OMP_ord_static_chunked : OMP_sch_static_chunked)
2555 : (Ordered ? OMP_ord_static : OMP_sch_static);
2556 case OMPC_SCHEDULE_dynamic:
2557 return Ordered ? OMP_ord_dynamic_chunked : OMP_sch_dynamic_chunked;
2558 case OMPC_SCHEDULE_guided:
2559 return Ordered ? OMP_ord_guided_chunked : OMP_sch_guided_chunked;
2560 case OMPC_SCHEDULE_runtime:
2561 return Ordered ? OMP_ord_runtime : OMP_sch_runtime;
2562 case OMPC_SCHEDULE_auto:
2563 return Ordered ? OMP_ord_auto : OMP_sch_auto;
2565 assert(!Chunked && "chunk was specified but schedule kind not known");
2566 return Ordered ? OMP_ord_static : OMP_sch_static;
2567 }
2568 llvm_unreachable("Unexpected runtime schedule");
2569}
2570
2571/// Map the OpenMP distribute schedule to the runtime enumeration.
2572static OpenMPSchedType
2574 // only static is allowed for dist_schedule
2575 return Chunked ? OMP_dist_sch_static_chunked : OMP_dist_sch_static;
2576}
2577
2579 bool Chunked) const {
2580 OpenMPSchedType Schedule =
2581 getRuntimeSchedule(ScheduleKind, Chunked, /*Ordered=*/false);
2582 return Schedule == OMP_sch_static;
2583}
2584
2586 OpenMPDistScheduleClauseKind ScheduleKind, bool Chunked) const {
2587 OpenMPSchedType Schedule = getRuntimeSchedule(ScheduleKind, Chunked);
2588 return Schedule == OMP_dist_sch_static;
2589}
2590
2592 bool Chunked) const {
2593 OpenMPSchedType Schedule =
2594 getRuntimeSchedule(ScheduleKind, Chunked, /*Ordered=*/false);
2595 return Schedule == OMP_sch_static_chunked;
2596}
2597
2599 OpenMPDistScheduleClauseKind ScheduleKind, bool Chunked) const {
2600 OpenMPSchedType Schedule = getRuntimeSchedule(ScheduleKind, Chunked);
2601 return Schedule == OMP_dist_sch_static_chunked;
2602}
2603
2605 OpenMPSchedType Schedule =
2606 getRuntimeSchedule(ScheduleKind, /*Chunked=*/false, /*Ordered=*/false);
2607 assert(Schedule != OMP_sch_static_chunked && "cannot be chunked here");
2608 return Schedule != OMP_sch_static;
2609}
2610
2611static int addMonoNonMonoModifier(CodeGenModule &CGM, OpenMPSchedType Schedule,
2614 int Modifier = 0;
2615 switch (M1) {
2616 case OMPC_SCHEDULE_MODIFIER_monotonic:
2617 Modifier = OMP_sch_modifier_monotonic;
2618 break;
2619 case OMPC_SCHEDULE_MODIFIER_nonmonotonic:
2620 Modifier = OMP_sch_modifier_nonmonotonic;
2621 break;
2622 case OMPC_SCHEDULE_MODIFIER_simd:
2623 if (Schedule == OMP_sch_static_chunked)
2624 Schedule = OMP_sch_static_balanced_chunked;
2625 break;
2628 break;
2629 }
2630 switch (M2) {
2631 case OMPC_SCHEDULE_MODIFIER_monotonic:
2632 Modifier = OMP_sch_modifier_monotonic;
2633 break;
2634 case OMPC_SCHEDULE_MODIFIER_nonmonotonic:
2635 Modifier = OMP_sch_modifier_nonmonotonic;
2636 break;
2637 case OMPC_SCHEDULE_MODIFIER_simd:
2638 if (Schedule == OMP_sch_static_chunked)
2639 Schedule = OMP_sch_static_balanced_chunked;
2640 break;
2643 break;
2644 }
2645 // OpenMP 5.0, 2.9.2 Worksharing-Loop Construct, Desription.
2646 // If the static schedule kind is specified or if the ordered clause is
2647 // specified, and if the nonmonotonic modifier is not specified, the effect is
2648 // as if the monotonic modifier is specified. Otherwise, unless the monotonic
2649 // modifier is specified, the effect is as if the nonmonotonic modifier is
2650 // specified.
2651 if (CGM.getLangOpts().OpenMP >= 50 && Modifier == 0) {
2652 if (!(Schedule == OMP_sch_static_chunked || Schedule == OMP_sch_static ||
2653 Schedule == OMP_sch_static_balanced_chunked ||
2654 Schedule == OMP_ord_static_chunked || Schedule == OMP_ord_static ||
2655 Schedule == OMP_dist_sch_static_chunked ||
2656 Schedule == OMP_dist_sch_static ||
2657 Schedule == OMP_dist_sch_static_chunked_sch_static_chunkone))
2658 Modifier = OMP_sch_modifier_nonmonotonic;
2659 }
2660 return Schedule | Modifier;
2661}
2662
2665 const OpenMPScheduleTy &ScheduleKind, unsigned IVSize, bool IVSigned,
2666 bool Ordered, const DispatchRTInput &DispatchValues) {
2667 if (!CGF.HaveInsertPoint())
2668 return;
2669 OpenMPSchedType Schedule = getRuntimeSchedule(
2670 ScheduleKind.Schedule, DispatchValues.Chunk != nullptr, Ordered);
2671 assert(Ordered ||
2672 (Schedule != OMP_sch_static && Schedule != OMP_sch_static_chunked &&
2673 Schedule != OMP_ord_static && Schedule != OMP_ord_static_chunked &&
2674 Schedule != OMP_sch_static_balanced_chunked));
2675 // Call __kmpc_dispatch_init(
2676 // ident_t *loc, kmp_int32 tid, kmp_int32 schedule,
2677 // kmp_int[32|64] lower, kmp_int[32|64] upper,
2678 // kmp_int[32|64] stride, kmp_int[32|64] chunk);
2679
2680 // If the Chunk was not specified in the clause - use default value 1.
2681 llvm::Value *Chunk = DispatchValues.Chunk ? DispatchValues.Chunk
2682 : CGF.Builder.getIntN(IVSize, 1);
2683 llvm::Value *Args[] = {
2684 emitUpdateLocation(CGF, Loc),
2685 getThreadID(CGF, Loc),
2686 CGF.Builder.getInt32(addMonoNonMonoModifier(
2687 CGM, Schedule, ScheduleKind.M1, ScheduleKind.M2)), // Schedule type
2688 DispatchValues.LB, // Lower
2689 DispatchValues.UB, // Upper
2690 CGF.Builder.getIntN(IVSize, 1), // Stride
2691 Chunk // Chunk
2692 };
2693 CGF.EmitRuntimeCall(OMPBuilder.createDispatchInitFunction(IVSize, IVSigned),
2694 Args);
2695}
2696
2698 SourceLocation Loc) {
2699 if (!CGF.HaveInsertPoint())
2700 return;
2701 // Call __kmpc_dispatch_deinit(ident_t *loc, kmp_int32 tid);
2702 llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
2703 CGF.EmitRuntimeCall(OMPBuilder.createDispatchDeinitFunction(), Args);
2704}
2705
2707 CodeGenFunction &CGF, llvm::Value *UpdateLocation, llvm::Value *ThreadId,
2708 llvm::FunctionCallee ForStaticInitFunction, OpenMPSchedType Schedule,
2710 const CGOpenMPRuntime::StaticRTInput &Values) {
2711 if (!CGF.HaveInsertPoint())
2712 return;
2713
2714 assert(!Values.Ordered);
2715 assert(Schedule == OMP_sch_static || Schedule == OMP_sch_static_chunked ||
2716 Schedule == OMP_sch_static_balanced_chunked ||
2717 Schedule == OMP_ord_static || Schedule == OMP_ord_static_chunked ||
2718 Schedule == OMP_dist_sch_static ||
2719 Schedule == OMP_dist_sch_static_chunked ||
2720 Schedule == OMP_dist_sch_static_chunked_sch_static_chunkone);
2721
2722 // Call __kmpc_for_static_init(
2723 // ident_t *loc, kmp_int32 tid, kmp_int32 schedtype,
2724 // kmp_int32 *p_lastiter, kmp_int[32|64] *p_lower,
2725 // kmp_int[32|64] *p_upper, kmp_int[32|64] *p_stride,
2726 // kmp_int[32|64] incr, kmp_int[32|64] chunk);
2727 llvm::Value *Chunk = Values.Chunk;
2728 if (Chunk == nullptr) {
2729 assert((Schedule == OMP_sch_static || Schedule == OMP_ord_static ||
2730 Schedule == OMP_dist_sch_static) &&
2731 "expected static non-chunked schedule");
2732 // If the Chunk was not specified in the clause - use default value 1.
2733 Chunk = CGF.Builder.getIntN(Values.IVSize, 1);
2734 } else {
2735 assert((Schedule == OMP_sch_static_chunked ||
2736 Schedule == OMP_sch_static_balanced_chunked ||
2737 Schedule == OMP_ord_static_chunked ||
2738 Schedule == OMP_dist_sch_static_chunked ||
2739 Schedule == OMP_dist_sch_static_chunked_sch_static_chunkone) &&
2740 "expected static chunked schedule");
2741 }
2742 llvm::Value *Args[] = {
2743 UpdateLocation,
2744 ThreadId,
2745 CGF.Builder.getInt32(addMonoNonMonoModifier(CGF.CGM, Schedule, M1,
2746 M2)), // Schedule type
2747 Values.IL.emitRawPointer(CGF), // &isLastIter
2748 Values.LB.emitRawPointer(CGF), // &LB
2749 Values.UB.emitRawPointer(CGF), // &UB
2750 Values.ST.emitRawPointer(CGF), // &Stride
2751 CGF.Builder.getIntN(Values.IVSize, 1), // Incr
2752 Chunk // Chunk
2753 };
2754 CGF.EmitRuntimeCall(ForStaticInitFunction, Args);
2755}
2756
2758 SourceLocation Loc,
2759 OpenMPDirectiveKind DKind,
2760 const OpenMPScheduleTy &ScheduleKind,
2761 const StaticRTInput &Values) {
2762 OpenMPSchedType ScheduleNum =
2763 ScheduleKind.UseFusedDistChunkSchedule
2764 ? OMP_dist_sch_static_chunked_sch_static_chunkone
2765 : getRuntimeSchedule(ScheduleKind.Schedule, Values.Chunk != nullptr,
2766 Values.Ordered);
2767 assert((isOpenMPWorksharingDirective(DKind) || (DKind == OMPD_loop)) &&
2768 "Expected loop-based or sections-based directive.");
2769 llvm::Value *UpdatedLocation = emitUpdateLocation(CGF, Loc,
2771 ? OMP_IDENT_WORK_LOOP
2772 : OMP_IDENT_WORK_SECTIONS);
2773 llvm::Value *ThreadId = getThreadID(CGF, Loc);
2774 llvm::FunctionCallee StaticInitFunction =
2775 OMPBuilder.createForStaticInitFunction(Values.IVSize, Values.IVSigned,
2776 false);
2778 emitForStaticInitCall(CGF, UpdatedLocation, ThreadId, StaticInitFunction,
2779 ScheduleNum, ScheduleKind.M1, ScheduleKind.M2, Values);
2780}
2781
2785 const CGOpenMPRuntime::StaticRTInput &Values) {
2786 OpenMPSchedType ScheduleNum =
2787 getRuntimeSchedule(SchedKind, Values.Chunk != nullptr);
2788 llvm::Value *UpdatedLocation =
2789 emitUpdateLocation(CGF, Loc, OMP_IDENT_WORK_DISTRIBUTE);
2790 llvm::Value *ThreadId = getThreadID(CGF, Loc);
2791 llvm::FunctionCallee StaticInitFunction;
2792 bool isGPUDistribute =
2793 CGM.getLangOpts().OpenMPIsTargetDevice && CGM.getTriple().isGPU();
2794 StaticInitFunction = OMPBuilder.createForStaticInitFunction(
2795 Values.IVSize, Values.IVSigned, isGPUDistribute);
2796
2797 emitForStaticInitCall(CGF, UpdatedLocation, ThreadId, StaticInitFunction,
2798 ScheduleNum, OMPC_SCHEDULE_MODIFIER_unknown,
2800}
2801
2803 SourceLocation Loc,
2804 OpenMPDirectiveKind DKind) {
2805 assert((DKind == OMPD_distribute || DKind == OMPD_for ||
2806 DKind == OMPD_sections) &&
2807 "Expected distribute, for, or sections directive kind");
2808 if (!CGF.HaveInsertPoint())
2809 return;
2810 // Call __kmpc_for_static_fini(ident_t *loc, kmp_int32 tid);
2811 llvm::Value *Args[] = {
2812 emitUpdateLocation(CGF, Loc,
2814 (DKind == OMPD_target_teams_loop)
2815 ? OMP_IDENT_WORK_DISTRIBUTE
2816 : isOpenMPLoopDirective(DKind)
2817 ? OMP_IDENT_WORK_LOOP
2818 : OMP_IDENT_WORK_SECTIONS),
2819 getThreadID(CGF, Loc)};
2821 if (isOpenMPDistributeDirective(DKind) &&
2822 CGM.getLangOpts().OpenMPIsTargetDevice && CGM.getTriple().isGPU())
2823 CGF.EmitRuntimeCall(
2824 OMPBuilder.getOrCreateRuntimeFunction(
2825 CGM.getModule(), OMPRTL___kmpc_distribute_static_fini),
2826 Args);
2827 else
2828 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
2829 CGM.getModule(), OMPRTL___kmpc_for_static_fini),
2830 Args);
2831}
2832
2834 SourceLocation Loc,
2835 unsigned IVSize,
2836 bool IVSigned) {
2837 if (!CGF.HaveInsertPoint())
2838 return;
2839 // Call __kmpc_for_dynamic_fini_(4|8)[u](ident_t *loc, kmp_int32 tid);
2840 llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
2841 CGF.EmitRuntimeCall(OMPBuilder.createDispatchFiniFunction(IVSize, IVSigned),
2842 Args);
2843}
2844
2846 SourceLocation Loc, unsigned IVSize,
2847 bool IVSigned, Address IL,
2848 Address LB, Address UB,
2849 Address ST) {
2850 // Call __kmpc_dispatch_next(
2851 // ident_t *loc, kmp_int32 tid, kmp_int32 *p_lastiter,
2852 // kmp_int[32|64] *p_lower, kmp_int[32|64] *p_upper,
2853 // kmp_int[32|64] *p_stride);
2854 llvm::Value *Args[] = {
2855 emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
2856 IL.emitRawPointer(CGF), // &isLastIter
2857 LB.emitRawPointer(CGF), // &Lower
2858 UB.emitRawPointer(CGF), // &Upper
2859 ST.emitRawPointer(CGF) // &Stride
2860 };
2861 llvm::Value *Call = CGF.EmitRuntimeCall(
2862 OMPBuilder.createDispatchNextFunction(IVSize, IVSigned), Args);
2863 return CGF.EmitScalarConversion(
2864 Call, CGF.getContext().getIntTypeForBitwidth(32, /*Signed=*/1),
2865 CGF.getContext().BoolTy, Loc);
2866}
2867
2869 const Expr *Message,
2870 SourceLocation Loc) {
2871 if (!Message)
2872 return llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
2873 return CGF.EmitScalarExpr(Message);
2874}
2875
2876llvm::Value *
2878 SourceLocation Loc) {
2879 // OpenMP 6.0, 10.4: "If no severity clause is specified then the effect is
2880 // as if sev-level is fatal."
2881 return llvm::ConstantInt::get(CGM.Int32Ty,
2882 Severity == OMPC_SEVERITY_warning ? 1 : 2);
2883}
2884
2886 CodeGenFunction &CGF, llvm::Value *NumThreads, SourceLocation Loc,
2888 SourceLocation SeverityLoc, const Expr *Message,
2889 SourceLocation MessageLoc) {
2890 if (!CGF.HaveInsertPoint())
2891 return;
2893 {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
2894 CGF.Builder.CreateIntCast(NumThreads, CGF.Int32Ty, /*isSigned*/ true)});
2895 // Build call __kmpc_push_num_threads(&loc, global_tid, num_threads)
2896 // or __kmpc_push_num_threads_strict(&loc, global_tid, num_threads, severity,
2897 // messsage) if strict modifier is used.
2898 RuntimeFunction FnID = OMPRTL___kmpc_push_num_threads;
2899 if (Modifier == OMPC_NUMTHREADS_strict) {
2900 FnID = OMPRTL___kmpc_push_num_threads_strict;
2901 Args.push_back(emitSeverityClause(Severity, SeverityLoc));
2902 Args.push_back(emitMessageClause(CGF, Message, MessageLoc));
2903 }
2904 CGF.EmitRuntimeCall(
2905 OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(), FnID), Args);
2906}
2907
2909 ProcBindKind ProcBind,
2910 SourceLocation Loc) {
2911 if (!CGF.HaveInsertPoint())
2912 return;
2913 assert(ProcBind != OMP_PROC_BIND_unknown && "Unsupported proc_bind value.");
2914 // Build call __kmpc_push_proc_bind(&loc, global_tid, proc_bind)
2915 llvm::Value *Args[] = {
2916 emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
2917 llvm::ConstantInt::get(CGM.IntTy, unsigned(ProcBind), /*isSigned=*/true)};
2918 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
2919 CGM.getModule(), OMPRTL___kmpc_push_proc_bind),
2920 Args);
2921}
2922
2924 SourceLocation Loc, llvm::AtomicOrdering AO) {
2925 if (CGF.CGM.getLangOpts().OpenMPIRBuilder) {
2926 OMPBuilder.createFlush(CGF.Builder);
2927 } else {
2928 if (!CGF.HaveInsertPoint())
2929 return;
2930 // Build call void __kmpc_flush(ident_t *loc)
2931 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
2932 CGM.getModule(), OMPRTL___kmpc_flush),
2933 emitUpdateLocation(CGF, Loc));
2934 }
2935}
2936
2937namespace {
2938/// Indexes of fields for type kmp_task_t.
2939enum KmpTaskTFields {
2940 /// List of shared variables.
2941 KmpTaskTShareds,
2942 /// Task routine.
2943 KmpTaskTRoutine,
2944 /// Partition id for the untied tasks.
2945 KmpTaskTPartId,
2946 /// Function with call of destructors for private variables.
2947 Data1,
2948 /// Task priority.
2949 Data2,
2950 /// (Taskloops only) Lower bound.
2951 KmpTaskTLowerBound,
2952 /// (Taskloops only) Upper bound.
2953 KmpTaskTUpperBound,
2954 /// (Taskloops only) Stride.
2955 KmpTaskTStride,
2956 /// (Taskloops only) Is last iteration flag.
2957 KmpTaskTLastIter,
2958 /// (Taskloops only) Reduction data.
2959 KmpTaskTReductions,
2960};
2961} // anonymous namespace
2962
2964 // If we are in simd mode or there are no entries, we don't need to do
2965 // anything.
2966 if (CGM.getLangOpts().OpenMPSimd || OMPBuilder.OffloadInfoManager.empty())
2967 return;
2968
2969 llvm::OpenMPIRBuilder::EmitMetadataErrorReportFunctionTy &&ErrorReportFn =
2970 [this](llvm::OpenMPIRBuilder::EmitMetadataErrorKind Kind,
2971 const llvm::TargetRegionEntryInfo &EntryInfo) -> void {
2972 SourceLocation Loc;
2973 if (Kind != llvm::OpenMPIRBuilder::EMIT_MD_GLOBAL_VAR_LINK_ERROR) {
2974 for (auto I = CGM.getContext().getSourceManager().fileinfo_begin(),
2975 E = CGM.getContext().getSourceManager().fileinfo_end();
2976 I != E; ++I) {
2977 if (I->getFirst().getUniqueID().getDevice() == EntryInfo.DeviceID &&
2978 I->getFirst().getUniqueID().getFile() == EntryInfo.FileID) {
2979 Loc = CGM.getContext().getSourceManager().translateFileLineCol(
2980 I->getFirst(), EntryInfo.Line, 1);
2981 break;
2982 }
2983 }
2984 }
2985 switch (Kind) {
2986 case llvm::OpenMPIRBuilder::EMIT_MD_TARGET_REGION_ERROR: {
2987 CGM.getDiags().Report(Loc,
2988 diag::err_target_region_offloading_entry_incorrect)
2989 << EntryInfo.ParentName;
2990 } break;
2991 case llvm::OpenMPIRBuilder::EMIT_MD_DECLARE_TARGET_ERROR: {
2992 CGM.getDiags().Report(
2993 Loc, diag::err_target_var_offloading_entry_incorrect_with_parent)
2994 << EntryInfo.ParentName;
2995 } break;
2996 case llvm::OpenMPIRBuilder::EMIT_MD_GLOBAL_VAR_LINK_ERROR: {
2997 CGM.getDiags().Report(diag::err_target_var_offloading_entry_incorrect);
2998 } break;
2999 case llvm::OpenMPIRBuilder::EMIT_MD_GLOBAL_VAR_INDIRECT_ERROR: {
3000 unsigned DiagID = CGM.getDiags().getCustomDiagID(
3001 DiagnosticsEngine::Error, "Offloading entry for indirect declare "
3002 "target variable is incorrect: the "
3003 "address is invalid.");
3004 CGM.getDiags().Report(DiagID);
3005 } break;
3006 }
3007 };
3008
3009 OMPBuilder.createOffloadEntriesAndInfoMetadata(ErrorReportFn);
3010}
3011
3013 if (!KmpRoutineEntryPtrTy) {
3014 // Build typedef kmp_int32 (* kmp_routine_entry_t)(kmp_int32, void *); type.
3015 ASTContext &C = CGM.getContext();
3016 QualType KmpRoutineEntryTyArgs[] = {KmpInt32Ty, C.VoidPtrTy};
3018 KmpRoutineEntryPtrQTy = C.getPointerType(
3019 C.getFunctionType(KmpInt32Ty, KmpRoutineEntryTyArgs, EPI));
3020 KmpRoutineEntryPtrTy = CGM.getTypes().ConvertType(KmpRoutineEntryPtrQTy);
3021 }
3022}
3023
3024namespace {
3025struct PrivateHelpersTy {
3026 PrivateHelpersTy(const Expr *OriginalRef, const VarDecl *Original,
3027 const VarDecl *PrivateCopy, const VarDecl *PrivateElemInit)
3028 : OriginalRef(OriginalRef), Original(Original), PrivateCopy(PrivateCopy),
3029 PrivateElemInit(PrivateElemInit) {}
3030 PrivateHelpersTy(const VarDecl *Original) : Original(Original) {}
3031 const Expr *OriginalRef = nullptr;
3032 const VarDecl *Original = nullptr;
3033 const VarDecl *PrivateCopy = nullptr;
3034 const VarDecl *PrivateElemInit = nullptr;
3035 bool isLocalPrivate() const {
3036 return !OriginalRef && !PrivateCopy && !PrivateElemInit;
3037 }
3038};
3039typedef std::pair<CharUnits /*Align*/, PrivateHelpersTy> PrivateDataTy;
3040} // anonymous namespace
3041
3042/// For BindingDecls, returns the DecomposedDecl as the original VarDecl.
3043/// For regular VarDecls, returns the VarDecl itself.
3045 if (const auto *BD = dyn_cast<BindingDecl>(Decl))
3046 return cast<VarDecl>(BD->getDecomposedDecl());
3047 return cast<VarDecl>(Decl);
3048}
3049
3050static bool isAllocatableDecl(const VarDecl *VD) {
3051 const VarDecl *CVD = VD->getCanonicalDecl();
3052 if (!CVD->hasAttr<OMPAllocateDeclAttr>())
3053 return false;
3054 const auto *AA = CVD->getAttr<OMPAllocateDeclAttr>();
3055 // Use the default allocation.
3056 return !(AA->getAllocatorType() == OMPAllocateDeclAttr::OMPDefaultMemAlloc &&
3057 !AA->getAllocator());
3058}
3059
3060static RecordDecl *
3062 if (!Privates.empty()) {
3063 ASTContext &C = CGM.getContext();
3064 // Build struct .kmp_privates_t. {
3065 // /* private vars */
3066 // };
3067 RecordDecl *RD = C.buildImplicitRecord(".kmp_privates.t");
3068 RD->startDefinition();
3069 for (const auto &Pair : Privates) {
3070 const VarDecl *VD = Pair.second.Original;
3071 const VarDecl *PrivateCopy = Pair.second.PrivateCopy;
3072 // For BindingDecls, use PrivateCopy type (binding's actual type).
3073 // For regular variables, use Original type to preserve qualifiers.
3074 // Check OriginalRef to detect BindingDecls since Original may be the
3075 // DecompositionDecl.
3076 bool IsBinding =
3077 Pair.second.OriginalRef &&
3079 cast<DeclRefExpr>(Pair.second.OriginalRef)->getDecl());
3080 QualType Type = IsBinding ? PrivateCopy->getType().getNonReferenceType()
3081 : VD->getType().getNonReferenceType();
3082
3083 // If the private variable is a local variable with lvalue ref type,
3084 // allocate the pointer instead of the pointee type.
3085 if (Pair.second.isLocalPrivate()) {
3086 if (VD->getType()->isLValueReferenceType())
3087 Type = C.getPointerType(Type);
3088 if (isAllocatableDecl(VD))
3089 Type = C.getPointerType(Type);
3090 }
3092 if (VD->hasAttrs()) {
3093 for (specific_attr_iterator<AlignedAttr> I(VD->getAttrs().begin()),
3094 E(VD->getAttrs().end());
3095 I != E; ++I)
3096 FD->addAttr(*I);
3097 }
3098 }
3099 RD->completeDefinition();
3100 return RD;
3101 }
3102 return nullptr;
3103}
3104
3105static RecordDecl *
3107 QualType KmpInt32Ty,
3108 QualType KmpRoutineEntryPointerQTy) {
3109 ASTContext &C = CGM.getContext();
3110 // Build struct kmp_task_t {
3111 // void * shareds;
3112 // kmp_routine_entry_t routine;
3113 // kmp_int32 part_id;
3114 // kmp_cmplrdata_t data1;
3115 // kmp_cmplrdata_t data2;
3116 // For taskloops additional fields:
3117 // kmp_uint64 lb;
3118 // kmp_uint64 ub;
3119 // kmp_int64 st;
3120 // kmp_int32 liter;
3121 // void * reductions;
3122 // };
3123 RecordDecl *UD = C.buildImplicitRecord("kmp_cmplrdata_t", TagTypeKind::Union);
3124 UD->startDefinition();
3125 addFieldToRecordDecl(C, UD, KmpInt32Ty);
3126 addFieldToRecordDecl(C, UD, KmpRoutineEntryPointerQTy);
3127 UD->completeDefinition();
3128 CanQualType KmpCmplrdataTy = C.getCanonicalTagType(UD);
3129 RecordDecl *RD = C.buildImplicitRecord("kmp_task_t");
3130 RD->startDefinition();
3131 addFieldToRecordDecl(C, RD, C.VoidPtrTy);
3132 addFieldToRecordDecl(C, RD, KmpRoutineEntryPointerQTy);
3133 addFieldToRecordDecl(C, RD, KmpInt32Ty);
3134 addFieldToRecordDecl(C, RD, KmpCmplrdataTy);
3135 addFieldToRecordDecl(C, RD, KmpCmplrdataTy);
3136 if (isOpenMPTaskLoopDirective(Kind)) {
3137 QualType KmpUInt64Ty =
3138 CGM.getContext().getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/0);
3139 QualType KmpInt64Ty =
3140 CGM.getContext().getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1);
3141 addFieldToRecordDecl(C, RD, KmpUInt64Ty);
3142 addFieldToRecordDecl(C, RD, KmpUInt64Ty);
3143 addFieldToRecordDecl(C, RD, KmpInt64Ty);
3144 addFieldToRecordDecl(C, RD, KmpInt32Ty);
3145 addFieldToRecordDecl(C, RD, C.VoidPtrTy);
3146 }
3147 RD->completeDefinition();
3148 return RD;
3149}
3150
3151static RecordDecl *
3154 ASTContext &C = CGM.getContext();
3155 // Build struct kmp_task_t_with_privates {
3156 // kmp_task_t task_data;
3157 // .kmp_privates_t. privates;
3158 // };
3159 RecordDecl *RD = C.buildImplicitRecord("kmp_task_t_with_privates");
3160 RD->startDefinition();
3161 addFieldToRecordDecl(C, RD, KmpTaskTQTy);
3162 if (const RecordDecl *PrivateRD = createPrivatesRecordDecl(CGM, Privates))
3163 addFieldToRecordDecl(C, RD, C.getCanonicalTagType(PrivateRD));
3164 RD->completeDefinition();
3165 return RD;
3166}
3167
3168/// Emit a proxy function which accepts kmp_task_t as the second
3169/// argument.
3170/// \code
3171/// kmp_int32 .omp_task_entry.(kmp_int32 gtid, kmp_task_t *tt) {
3172/// TaskFunction(gtid, tt->part_id, &tt->privates, task_privates_map, tt,
3173/// For taskloops:
3174/// tt->task_data.lb, tt->task_data.ub, tt->task_data.st, tt->task_data.liter,
3175/// tt->reductions, tt->shareds);
3176/// return 0;
3177/// }
3178/// \endcode
3179static llvm::Function *
3181 OpenMPDirectiveKind Kind, QualType KmpInt32Ty,
3182 QualType KmpTaskTWithPrivatesPtrQTy,
3183 QualType KmpTaskTWithPrivatesQTy, QualType KmpTaskTQTy,
3184 QualType SharedsPtrTy, llvm::Function *TaskFunction,
3185 llvm::Value *TaskPrivatesMap) {
3186 ASTContext &C = CGM.getContext();
3187 auto *GtidArg =
3188 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
3189 KmpInt32Ty, ImplicitParamKind::Other);
3190 auto *TaskTypeArg = ImplicitParamDecl::Create(
3191 C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
3192 KmpTaskTWithPrivatesPtrQTy.withRestrict(), ImplicitParamKind::Other);
3193 FunctionArgList Args{GtidArg, TaskTypeArg};
3194 const auto &TaskEntryFnInfo =
3195 CGM.getTypes().arrangeBuiltinFunctionDeclaration(KmpInt32Ty, Args);
3196 llvm::FunctionType *TaskEntryTy =
3197 CGM.getTypes().GetFunctionType(TaskEntryFnInfo);
3198 std::string Name = CGM.getOpenMPRuntime().getName({"omp_task_entry", ""});
3199 auto *TaskEntry = llvm::Function::Create(
3200 TaskEntryTy, llvm::GlobalValue::InternalLinkage, Name, &CGM.getModule());
3201 CGM.SetInternalFunctionAttributes(GlobalDecl(), TaskEntry, TaskEntryFnInfo);
3202 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
3203 TaskEntry->addFnAttr("sample-profile-suffix-elision-policy", "selected");
3204 TaskEntry->setDoesNotRecurse();
3205 CodeGenFunction CGF(CGM);
3206 CGF.StartFunction(GlobalDecl(), KmpInt32Ty, TaskEntry, TaskEntryFnInfo, Args,
3207 Loc, Loc);
3208
3209 // TaskFunction(gtid, tt->task_data.part_id, &tt->privates, task_privates_map,
3210 // tt,
3211 // For taskloops:
3212 // tt->task_data.lb, tt->task_data.ub, tt->task_data.st, tt->task_data.liter,
3213 // tt->task_data.shareds);
3214 llvm::Value *GtidParam = CGF.EmitLoadOfScalar(
3215 CGF.GetAddrOfLocalVar(GtidArg), /*Volatile=*/false, KmpInt32Ty, Loc);
3216 LValue TDBase = CGF.EmitLoadOfPointerLValue(
3217 CGF.GetAddrOfLocalVar(TaskTypeArg),
3218 KmpTaskTWithPrivatesPtrQTy->castAs<PointerType>());
3219 const auto *KmpTaskTWithPrivatesQTyRD =
3220 KmpTaskTWithPrivatesQTy->castAsRecordDecl();
3221 LValue Base =
3222 CGF.EmitLValueForField(TDBase, *KmpTaskTWithPrivatesQTyRD->field_begin());
3223 const auto *KmpTaskTQTyRD = KmpTaskTQTy->castAsRecordDecl();
3224 auto PartIdFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTPartId);
3225 LValue PartIdLVal = CGF.EmitLValueForField(Base, *PartIdFI);
3226 llvm::Value *PartidParam = PartIdLVal.getPointer(CGF);
3227
3228 auto SharedsFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTShareds);
3229 LValue SharedsLVal = CGF.EmitLValueForField(Base, *SharedsFI);
3230 llvm::Value *SharedsParam = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
3231 CGF.EmitLoadOfScalar(SharedsLVal, Loc),
3232 CGF.ConvertTypeForMem(SharedsPtrTy));
3233
3234 auto PrivatesFI = std::next(KmpTaskTWithPrivatesQTyRD->field_begin(), 1);
3235 llvm::Value *PrivatesParam;
3236 if (PrivatesFI != KmpTaskTWithPrivatesQTyRD->field_end()) {
3237 LValue PrivatesLVal = CGF.EmitLValueForField(TDBase, *PrivatesFI);
3238 PrivatesParam = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
3239 PrivatesLVal.getPointer(CGF), CGF.VoidPtrTy);
3240 } else {
3241 PrivatesParam = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
3242 }
3243
3244 llvm::Value *CommonArgs[] = {
3245 GtidParam, PartidParam, PrivatesParam, TaskPrivatesMap,
3246 CGF.Builder
3247 .CreatePointerBitCastOrAddrSpaceCast(TDBase.getAddress(),
3248 CGF.VoidPtrTy, CGF.Int8Ty)
3249 .emitRawPointer(CGF)};
3250 SmallVector<llvm::Value *, 16> CallArgs(std::begin(CommonArgs),
3251 std::end(CommonArgs));
3252 if (isOpenMPTaskLoopDirective(Kind)) {
3253 auto LBFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTLowerBound);
3254 LValue LBLVal = CGF.EmitLValueForField(Base, *LBFI);
3255 llvm::Value *LBParam = CGF.EmitLoadOfScalar(LBLVal, Loc);
3256 auto UBFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTUpperBound);
3257 LValue UBLVal = CGF.EmitLValueForField(Base, *UBFI);
3258 llvm::Value *UBParam = CGF.EmitLoadOfScalar(UBLVal, Loc);
3259 auto StFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTStride);
3260 LValue StLVal = CGF.EmitLValueForField(Base, *StFI);
3261 llvm::Value *StParam = CGF.EmitLoadOfScalar(StLVal, Loc);
3262 auto LIFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTLastIter);
3263 LValue LILVal = CGF.EmitLValueForField(Base, *LIFI);
3264 llvm::Value *LIParam = CGF.EmitLoadOfScalar(LILVal, Loc);
3265 auto RFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTReductions);
3266 LValue RLVal = CGF.EmitLValueForField(Base, *RFI);
3267 llvm::Value *RParam = CGF.EmitLoadOfScalar(RLVal, Loc);
3268 CallArgs.push_back(LBParam);
3269 CallArgs.push_back(UBParam);
3270 CallArgs.push_back(StParam);
3271 CallArgs.push_back(LIParam);
3272 CallArgs.push_back(RParam);
3273 }
3274 CallArgs.push_back(SharedsParam);
3275
3276 CGM.getOpenMPRuntime().emitOutlinedFunctionCall(CGF, Loc, TaskFunction,
3277 CallArgs);
3278 CGF.EmitStoreThroughLValue(RValue::get(CGF.Builder.getInt32(/*C=*/0)),
3279 CGF.MakeAddrLValue(CGF.ReturnValue, KmpInt32Ty));
3280 CGF.FinishFunction();
3281 return TaskEntry;
3282}
3283
3285 SourceLocation Loc,
3286 QualType KmpInt32Ty,
3287 QualType KmpTaskTWithPrivatesPtrQTy,
3288 QualType KmpTaskTWithPrivatesQTy) {
3289 ASTContext &C = CGM.getContext();
3290 auto *GtidArg =
3291 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
3292 KmpInt32Ty, ImplicitParamKind::Other);
3293 auto *TaskTypeArg = ImplicitParamDecl::Create(
3294 C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
3295 KmpTaskTWithPrivatesPtrQTy.withRestrict(), ImplicitParamKind::Other);
3296 FunctionArgList Args{GtidArg, TaskTypeArg};
3297 const auto &DestructorFnInfo =
3298 CGM.getTypes().arrangeBuiltinFunctionDeclaration(KmpInt32Ty, Args);
3299 llvm::FunctionType *DestructorFnTy =
3300 CGM.getTypes().GetFunctionType(DestructorFnInfo);
3301 std::string Name =
3302 CGM.getOpenMPRuntime().getName({"omp_task_destructor", ""});
3303 auto *DestructorFn =
3304 llvm::Function::Create(DestructorFnTy, llvm::GlobalValue::InternalLinkage,
3305 Name, &CGM.getModule());
3306 CGM.SetInternalFunctionAttributes(GlobalDecl(), DestructorFn,
3307 DestructorFnInfo);
3308 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
3309 DestructorFn->addFnAttr("sample-profile-suffix-elision-policy", "selected");
3310 DestructorFn->setDoesNotRecurse();
3311 CodeGenFunction CGF(CGM);
3312 CGF.StartFunction(GlobalDecl(), KmpInt32Ty, DestructorFn, DestructorFnInfo,
3313 Args, Loc, Loc);
3314
3315 LValue Base = CGF.EmitLoadOfPointerLValue(
3316 CGF.GetAddrOfLocalVar(TaskTypeArg),
3317 KmpTaskTWithPrivatesPtrQTy->castAs<PointerType>());
3318 const auto *KmpTaskTWithPrivatesQTyRD =
3319 KmpTaskTWithPrivatesQTy->castAsRecordDecl();
3320 auto FI = std::next(KmpTaskTWithPrivatesQTyRD->field_begin());
3321 Base = CGF.EmitLValueForField(Base, *FI);
3322 for (const auto *Field : FI->getType()->castAsRecordDecl()->fields()) {
3323 if (QualType::DestructionKind DtorKind =
3324 Field->getType().isDestructedType()) {
3325 LValue FieldLValue = CGF.EmitLValueForField(Base, Field);
3326 CGF.pushDestroy(DtorKind, FieldLValue.getAddress(), Field->getType());
3327 }
3328 }
3329 CGF.FinishFunction();
3330 return DestructorFn;
3331}
3332
3333/// Emit a privates mapping function for correct handling of private and
3334/// firstprivate variables.
3335/// \code
3336/// void .omp_task_privates_map.(const .privates. *noalias privs, <ty1>
3337/// **noalias priv1,..., <tyn> **noalias privn) {
3338/// *priv1 = &.privates.priv1;
3339/// ...;
3340/// *privn = &.privates.privn;
3341/// }
3342/// \endcode
3343static llvm::Value *
3345 const OMPTaskDataTy &Data, QualType PrivatesQTy,
3347 ASTContext &C = CGM.getContext();
3348 FunctionArgList Args;
3349 auto *TaskPrivatesArg = ImplicitParamDecl::Create(
3350 C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
3351 C.getPointerType(PrivatesQTy).withConst().withRestrict(),
3353 Args.push_back(TaskPrivatesArg);
3354 llvm::SmallDenseMap<CanonicalDeclPtr<const VarDecl>, unsigned> PrivateVarsPos;
3355 // Track BindingDecl positions separately since BindingDecl is not a VarDecl.
3356 llvm::SmallDenseMap<const BindingDecl *, unsigned> BindingDeclPos;
3357 unsigned Counter = 1;
3358 for (const Expr *E : Data.PrivateVars) {
3359 Args.push_back(ImplicitParamDecl::Create(
3360 C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
3361 C.getPointerType(C.getPointerType(E->getType()))
3362 .withConst()
3363 .withRestrict(),
3365 const ValueDecl *VD = cast<DeclRefExpr>(E)->getDecl();
3366 if (const auto *BD = dyn_cast<BindingDecl>(VD))
3367 BindingDeclPos[cast<BindingDecl>(BD->getCanonicalDecl())] = Counter;
3368 else
3369 PrivateVarsPos[cast<VarDecl>(VD)] = Counter;
3370 ++Counter;
3371 }
3372 for (const Expr *E : Data.FirstprivateVars) {
3373 Args.push_back(ImplicitParamDecl::Create(
3374 C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
3375 C.getPointerType(C.getPointerType(E->getType()))
3376 .withConst()
3377 .withRestrict(),
3379 const ValueDecl *VD = cast<DeclRefExpr>(E)->getDecl();
3380 if (const auto *BD = dyn_cast<BindingDecl>(VD))
3381 BindingDeclPos[cast<BindingDecl>(BD->getCanonicalDecl())] = Counter;
3382 else
3383 PrivateVarsPos[cast<VarDecl>(VD)] = Counter;
3384 ++Counter;
3385 }
3386 for (const Expr *E : Data.LastprivateVars) {
3387 Args.push_back(ImplicitParamDecl::Create(
3388 C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
3389 C.getPointerType(C.getPointerType(E->getType()))
3390 .withConst()
3391 .withRestrict(),
3393 const ValueDecl *VD = cast<DeclRefExpr>(E)->getDecl();
3394 if (const auto *BD = dyn_cast<BindingDecl>(VD))
3395 BindingDeclPos[cast<BindingDecl>(BD->getCanonicalDecl())] = Counter;
3396 else
3397 PrivateVarsPos[cast<VarDecl>(VD)] = Counter;
3398 ++Counter;
3399 }
3400 for (const VarDecl *VD : Data.PrivateLocals) {
3402 if (VD->getType()->isLValueReferenceType())
3403 Ty = C.getPointerType(Ty);
3404 if (isAllocatableDecl(VD))
3405 Ty = C.getPointerType(Ty);
3406 Args.push_back(ImplicitParamDecl::Create(
3407 C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
3408 C.getPointerType(C.getPointerType(Ty)).withConst().withRestrict(),
3410 PrivateVarsPos[VD] = Counter;
3411 ++Counter;
3412 }
3413 const auto &TaskPrivatesMapFnInfo =
3414 CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
3415 llvm::FunctionType *TaskPrivatesMapTy =
3416 CGM.getTypes().GetFunctionType(TaskPrivatesMapFnInfo);
3417 std::string Name =
3418 CGM.getOpenMPRuntime().getName({"omp_task_privates_map", ""});
3419 auto *TaskPrivatesMap = llvm::Function::Create(
3420 TaskPrivatesMapTy, llvm::GlobalValue::InternalLinkage, Name,
3421 &CGM.getModule());
3422 CGM.SetInternalFunctionAttributes(GlobalDecl(), TaskPrivatesMap,
3423 TaskPrivatesMapFnInfo);
3424 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
3425 TaskPrivatesMap->addFnAttr("sample-profile-suffix-elision-policy",
3426 "selected");
3427 if (CGM.getCodeGenOpts().OptimizationLevel != 0) {
3428 TaskPrivatesMap->removeFnAttr(llvm::Attribute::NoInline);
3429 TaskPrivatesMap->removeFnAttr(llvm::Attribute::OptimizeNone);
3430 TaskPrivatesMap->addFnAttr(llvm::Attribute::AlwaysInline);
3431 }
3432 CodeGenFunction CGF(CGM);
3433 CGF.StartFunction(GlobalDecl(), C.VoidTy, TaskPrivatesMap,
3434 TaskPrivatesMapFnInfo, Args, Loc, Loc);
3435
3436 // *privi = &.privates.privi;
3437 LValue Base = CGF.EmitLoadOfPointerLValue(
3438 CGF.GetAddrOfLocalVar(TaskPrivatesArg),
3439 TaskPrivatesArg->getType()->castAs<PointerType>());
3440 const auto *PrivatesQTyRD = PrivatesQTy->castAsRecordDecl();
3441 Counter = 0;
3442 for (const FieldDecl *Field : PrivatesQTyRD->fields()) {
3443 LValue FieldLVal = CGF.EmitLValueForField(Base, Field);
3444 // Lookup by the original declaration (BindingDecl or VarDecl).
3445 const ValueDecl *LookupVD;
3446 if (Privates[Counter].second.OriginalRef) {
3447 LookupVD =
3448 cast<DeclRefExpr>(Privates[Counter].second.OriginalRef)->getDecl();
3449 } else {
3450 LookupVD = Privates[Counter].second.Original;
3451 }
3452
3453 // For BindingDecls, the privates record now stores each binding's type
3454 // directly (not the full DecompositionDecl), so FieldLVal is already
3455 // correct.
3456
3457 unsigned Position;
3458 if (const auto *BD = dyn_cast<BindingDecl>(LookupVD)) {
3459 Position =
3460 BindingDeclPos.lookup(cast<BindingDecl>(BD->getCanonicalDecl()));
3461 assert(Position && "binding not in privates mapping");
3462 } else {
3463 Position = PrivateVarsPos[cast<VarDecl>(LookupVD)];
3464 }
3465 const VarDecl *VD = Args[Position];
3466 LValue RefLVal =
3467 CGF.MakeAddrLValue(CGF.GetAddrOfLocalVar(VD), VD->getType());
3468 LValue RefLoadLVal = CGF.EmitLoadOfPointerLValue(
3469 RefLVal.getAddress(), RefLVal.getType()->castAs<PointerType>());
3470 CGF.EmitStoreOfScalar(FieldLVal.getPointer(CGF), RefLoadLVal);
3471 ++Counter;
3472 }
3473 CGF.FinishFunction();
3474 return TaskPrivatesMap;
3475}
3476
3477/// Emit initialization for private variables in task-based directives.
3479 const OMPExecutableDirective &D,
3480 Address KmpTaskSharedsPtr, LValue TDBase,
3481 const RecordDecl *KmpTaskTWithPrivatesQTyRD,
3482 QualType SharedsTy, QualType SharedsPtrTy,
3483 const OMPTaskDataTy &Data,
3484 ArrayRef<PrivateDataTy> Privates, bool ForDup) {
3485 ASTContext &C = CGF.getContext();
3486 auto FI = std::next(KmpTaskTWithPrivatesQTyRD->field_begin());
3487 LValue PrivatesBase = CGF.EmitLValueForField(TDBase, *FI);
3488 OpenMPDirectiveKind Kind = isOpenMPTaskLoopDirective(D.getDirectiveKind())
3489 ? OMPD_taskloop
3490 : OMPD_task;
3491 const CapturedStmt &CS = *D.getCapturedStmt(Kind);
3492 CodeGenFunction::CGCapturedStmtInfo CapturesInfo(CS);
3493 LValue SrcBase;
3494 bool IsTargetTask =
3495 isOpenMPTargetDataManagementDirective(D.getDirectiveKind()) ||
3496 isOpenMPTargetExecutionDirective(D.getDirectiveKind());
3497 // For target-based directives skip 4 firstprivate arrays BasePointersArray,
3498 // PointersArray, SizesArray, and MappersArray. The original variables for
3499 // these arrays are not captured and we get their addresses explicitly.
3500 if ((!IsTargetTask && !Data.FirstprivateVars.empty() && ForDup) ||
3501 (IsTargetTask && KmpTaskSharedsPtr.isValid())) {
3502 SrcBase = CGF.MakeAddrLValue(
3504 KmpTaskSharedsPtr, CGF.ConvertTypeForMem(SharedsPtrTy),
3505 CGF.ConvertTypeForMem(SharedsTy)),
3506 SharedsTy);
3507 }
3508 FI = FI->getType()->castAsRecordDecl()->field_begin();
3509 for (const PrivateDataTy &Pair : Privates) {
3510 // Do not initialize private locals.
3511 if (Pair.second.isLocalPrivate()) {
3512 ++FI;
3513 continue;
3514 }
3515 const VarDecl *VD = Pair.second.PrivateCopy;
3516 const Expr *Init = VD->getAnyInitializer();
3517 if (Init && (!ForDup || (isa<CXXConstructExpr>(Init) &&
3518 !CGF.isTrivialInitializer(Init)))) {
3519 LValue PrivateLValue = CGF.EmitLValueForField(PrivatesBase, *FI);
3520 if (const VarDecl *Elem = Pair.second.PrivateElemInit) {
3521 const VarDecl *OriginalVD = Pair.second.Original;
3522 // Check if the variable is the target-based BasePointersArray,
3523 // PointersArray, SizesArray, or MappersArray.
3524 LValue SharedRefLValue;
3525 QualType Type = PrivateLValue.getType();
3526 const FieldDecl *SharedField = CapturesInfo.lookup(OriginalVD);
3527 if (IsTargetTask && !SharedField) {
3528 assert(isa<ImplicitParamDecl>(OriginalVD) &&
3529 isa<CapturedDecl>(OriginalVD->getDeclContext()) &&
3530 cast<CapturedDecl>(OriginalVD->getDeclContext())
3531 ->getNumParams() == 0 &&
3533 cast<CapturedDecl>(OriginalVD->getDeclContext())
3534 ->getDeclContext()) &&
3535 "Expected artificial target data variable.");
3536 SharedRefLValue =
3537 CGF.MakeAddrLValue(CGF.GetAddrOfLocalVar(OriginalVD), Type);
3538 } else if (ForDup) {
3539 SharedRefLValue = CGF.EmitLValueForField(SrcBase, SharedField);
3540 // For BindingDecls, access the specific binding field within the
3541 // captured DecompositionDecl.
3542 if (Pair.second.OriginalRef) {
3543 if (const auto *DRE =
3544 dyn_cast<DeclRefExpr>(Pair.second.OriginalRef)) {
3545 if (const auto *BD = dyn_cast<BindingDecl>(DRE->getDecl())) {
3546 // Emit the binding subobject (member or array element) with
3547 // the decomposed decl temporarily mapped to the capture.
3548 const VarDecl *DD = cast<VarDecl>(BD->getDecomposedDecl());
3549 auto It = CGF.findLocalDecl(DD);
3550 bool WasMapped = It != CGF.localDeclMapEnd();
3551 Address Saved = WasMapped ? It->second : Address::invalid();
3552 if (WasMapped)
3553 It->second = SharedRefLValue.getAddress();
3554 else
3555 CGF.insertLocalDecl(DD, SharedRefLValue.getAddress());
3556 SharedRefLValue = CGF.EmitLValue(BD->getBinding());
3557 if (WasMapped) {
3558 auto RestoreIt = CGF.findLocalDecl(DD);
3559 RestoreIt->second = Saved;
3560 } else {
3561 CGF.eraseLocalDecl(DD);
3562 }
3563 }
3564 }
3565 }
3566 bool IsBinding =
3567 Pair.second.OriginalRef &&
3569 cast<DeclRefExpr>(Pair.second.OriginalRef)->getDecl());
3570 SharedRefLValue = CGF.MakeAddrLValue(
3571 SharedRefLValue.getAddress().withAlignment(
3572 IsBinding ? C.toCharUnitsFromBits(
3573 C.getTypeAlign(SharedRefLValue.getType()))
3574 : C.getDeclAlign(OriginalVD)),
3575 SharedRefLValue.getType(), LValueBaseInfo(AlignmentSource::Decl),
3576 SharedRefLValue.getTBAAInfo());
3577 } else if (CGF.LambdaCaptureFields.count(
3578 Pair.second.Original->getCanonicalDecl()) > 0 ||
3579 isa_and_nonnull<BlockDecl>(CGF.CurCodeDecl)) {
3580 SharedRefLValue = CGF.EmitLValue(Pair.second.OriginalRef);
3581 } else {
3582 // Processing for implicitly captured variables.
3583 InlinedOpenMPRegionRAII Region(
3584 CGF, [](CodeGenFunction &, PrePostActionTy &) {}, OMPD_unknown,
3585 /*HasCancel=*/false, /*NoInheritance=*/true);
3586 SharedRefLValue = CGF.EmitLValue(Pair.second.OriginalRef);
3587 }
3588 if (Type->isArrayType()) {
3589 // Initialize firstprivate array.
3591 // Perform simple memcpy.
3592 CGF.EmitAggregateAssign(PrivateLValue, SharedRefLValue, Type);
3593 } else {
3594 // Initialize firstprivate array using element-by-element
3595 // initialization.
3597 PrivateLValue.getAddress(), SharedRefLValue.getAddress(), Type,
3598 [&CGF, Elem, Init, &CapturesInfo](Address DestElement,
3599 Address SrcElement) {
3600 // Clean up any temporaries needed by the initialization.
3601 CodeGenFunction::OMPPrivateScope InitScope(CGF);
3602 InitScope.addPrivate(Elem, SrcElement);
3603 (void)InitScope.Privatize();
3604 // Emit initialization for single element.
3605 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(
3606 CGF, &CapturesInfo);
3607 CGF.EmitAnyExprToMem(Init, DestElement,
3608 Init->getType().getQualifiers(),
3609 /*IsInitializer=*/false);
3610 });
3611 }
3612 } else {
3613 CodeGenFunction::OMPPrivateScope InitScope(CGF);
3614 InitScope.addPrivate(Elem, SharedRefLValue.getAddress());
3615 (void)InitScope.Privatize();
3616 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CapturesInfo);
3617 CGF.EmitExprAsInit(Init, VD, PrivateLValue,
3618 /*capturedByInit=*/false);
3619 }
3620 } else {
3621 CGF.EmitExprAsInit(Init, VD, PrivateLValue, /*capturedByInit=*/false);
3622 }
3623 } else if (const VarDecl *OriginalVD = Pair.second.Original) {
3624 // Handle array bindings without initializers (firstprivate only).
3625 // For private clause (PrivateElemInit is nullptr), skip initialization.
3626 // Check if OriginalRef is a BindingDecl with array type.
3627 const BindingDecl *BD = nullptr;
3628 if (Pair.second.OriginalRef) {
3629 if (const auto *DRE = dyn_cast<DeclRefExpr>(Pair.second.OriginalRef)) {
3630 BD = dyn_cast<BindingDecl>(DRE->getDecl());
3631 }
3632 }
3633 if (BD && BD->getType()->isArrayType() && Pair.second.PrivateElemInit) {
3634 LValue PrivateLValue = CGF.EmitLValueForField(PrivatesBase, *FI);
3635 QualType Type = PrivateLValue.getType();
3636 const FieldDecl *SharedField = CapturesInfo.lookup(OriginalVD);
3637
3638 // Lambda to temporarily map DecompositionDecl and emit the binding
3639 // expression.
3640 auto EmitBindingWithTempMap = [&CGF](const BindingDecl *BD,
3641 Address DDAddr) -> LValue {
3642 const VarDecl *DD = cast<VarDecl>(BD->getDecomposedDecl());
3643 auto It = CGF.findLocalDecl(DD);
3644 bool WasMapped = It != CGF.localDeclMapEnd();
3645 Address Saved = WasMapped ? It->second : Address::invalid();
3646 if (WasMapped)
3647 It->second = DDAddr;
3648 else
3649 CGF.insertLocalDecl(DD, DDAddr);
3650
3651 LValue Result = CGF.EmitLValue(BD->getBinding());
3652
3653 // Restore the mapping
3654 if (WasMapped) {
3655 auto RestoreIt = CGF.findLocalDecl(DD);
3656 RestoreIt->second = Saved;
3657 } else {
3658 CGF.eraseLocalDecl(DD);
3659 }
3660
3661 return Result;
3662 };
3663
3664 LValue SharedRefLValue;
3665 if (ForDup) {
3666 SharedRefLValue = CGF.EmitLValueForField(SrcBase, SharedField);
3667 SharedRefLValue =
3668 EmitBindingWithTempMap(BD, SharedRefLValue.getAddress());
3669 SharedRefLValue = CGF.MakeAddrLValue(
3670 SharedRefLValue.getAddress().withAlignment(
3671 C.getDeclAlign(OriginalVD)),
3672 SharedRefLValue.getType(), LValueBaseInfo(AlignmentSource::Decl),
3673 SharedRefLValue.getTBAAInfo());
3674 } else {
3675 // For !ForDup (first task), emit binding from parent scope using
3676 // InlinedOpenMPRegionRAII to access the correct scope
3677 InlinedOpenMPRegionRAII Region(
3678 CGF, [](CodeGenFunction &, PrePostActionTy &) {}, OMPD_unknown,
3679 /*HasCancel=*/false, /*NoInheritance=*/true);
3680
3681 // Get the decomposed decl address from parent scope
3682 const VarDecl *DD = cast<VarDecl>(BD->getDecomposedDecl());
3683 Address DDAddr = CGF.GetAddrOfLocalVar(DD);
3684 SharedRefLValue = EmitBindingWithTempMap(BD, DDAddr);
3685 }
3686 // Perform simple memcpy for array binding
3687 CGF.EmitAggregateAssign(PrivateLValue, SharedRefLValue, Type);
3688 }
3689 }
3690 ++FI;
3691 }
3692}
3693
3694/// Check if duplication function is required for taskloops.
3697 bool InitRequired = false;
3698 for (const PrivateDataTy &Pair : Privates) {
3699 if (Pair.second.isLocalPrivate())
3700 continue;
3701 const VarDecl *VD = Pair.second.PrivateCopy;
3702 const Expr *Init = VD->getAnyInitializer();
3703 InitRequired = InitRequired || (isa_and_nonnull<CXXConstructExpr>(Init) &&
3705 if (InitRequired)
3706 break;
3707 }
3708 return InitRequired;
3709}
3710
3711
3712/// Emit task_dup function (for initialization of
3713/// private/firstprivate/lastprivate vars and last_iter flag)
3714/// \code
3715/// void __task_dup_entry(kmp_task_t *task_dst, const kmp_task_t *task_src, int
3716/// lastpriv) {
3717/// // setup lastprivate flag
3718/// task_dst->last = lastpriv;
3719/// // could be constructor calls here...
3720/// }
3721/// \endcode
3722static llvm::Value *
3724 const OMPExecutableDirective &D,
3725 QualType KmpTaskTWithPrivatesPtrQTy,
3726 const RecordDecl *KmpTaskTWithPrivatesQTyRD,
3727 const RecordDecl *KmpTaskTQTyRD, QualType SharedsTy,
3728 QualType SharedsPtrTy, const OMPTaskDataTy &Data,
3729 ArrayRef<PrivateDataTy> Privates, bool WithLastIter) {
3730 ASTContext &C = CGM.getContext();
3731 auto *DstArg = ImplicitParamDecl::Create(
3732 C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, KmpTaskTWithPrivatesPtrQTy,
3734 auto *SrcArg = ImplicitParamDecl::Create(
3735 C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, KmpTaskTWithPrivatesPtrQTy,
3737 auto *LastprivArg =
3738 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, C.IntTy,
3740 FunctionArgList Args{DstArg, SrcArg, LastprivArg};
3741 const auto &TaskDupFnInfo =
3742 CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
3743 llvm::FunctionType *TaskDupTy = CGM.getTypes().GetFunctionType(TaskDupFnInfo);
3744 std::string Name = CGM.getOpenMPRuntime().getName({"omp_task_dup", ""});
3745 auto *TaskDup = llvm::Function::Create(
3746 TaskDupTy, llvm::GlobalValue::InternalLinkage, Name, &CGM.getModule());
3747 CGM.SetInternalFunctionAttributes(GlobalDecl(), TaskDup, TaskDupFnInfo);
3748 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
3749 TaskDup->addFnAttr("sample-profile-suffix-elision-policy", "selected");
3750 TaskDup->setDoesNotRecurse();
3751 CodeGenFunction CGF(CGM);
3752 CGF.StartFunction(GlobalDecl(), C.VoidTy, TaskDup, TaskDupFnInfo, Args, Loc,
3753 Loc);
3754
3755 LValue TDBase = CGF.EmitLoadOfPointerLValue(
3756 CGF.GetAddrOfLocalVar(DstArg),
3757 KmpTaskTWithPrivatesPtrQTy->castAs<PointerType>());
3758 // task_dst->liter = lastpriv;
3759 if (WithLastIter) {
3760 auto LIFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTLastIter);
3761 LValue Base = CGF.EmitLValueForField(
3762 TDBase, *KmpTaskTWithPrivatesQTyRD->field_begin());
3763 LValue LILVal = CGF.EmitLValueForField(Base, *LIFI);
3764 llvm::Value *Lastpriv = CGF.EmitLoadOfScalar(
3765 CGF.GetAddrOfLocalVar(LastprivArg), /*Volatile=*/false, C.IntTy, Loc);
3766 CGF.EmitStoreOfScalar(Lastpriv, LILVal);
3767 }
3768
3769 // Emit initial values for private copies (if any).
3770 assert(!Privates.empty());
3771 Address KmpTaskSharedsPtr = Address::invalid();
3772 if (!Data.FirstprivateVars.empty()) {
3773 LValue TDBase = CGF.EmitLoadOfPointerLValue(
3774 CGF.GetAddrOfLocalVar(SrcArg),
3775 KmpTaskTWithPrivatesPtrQTy->castAs<PointerType>());
3776 LValue Base = CGF.EmitLValueForField(
3777 TDBase, *KmpTaskTWithPrivatesQTyRD->field_begin());
3778 KmpTaskSharedsPtr = Address(
3780 Base, *std::next(KmpTaskTQTyRD->field_begin(),
3781 KmpTaskTShareds)),
3782 Loc),
3783 CGF.Int8Ty, CGM.getNaturalTypeAlignment(SharedsTy));
3784 }
3785 emitPrivatesInit(CGF, D, KmpTaskSharedsPtr, TDBase, KmpTaskTWithPrivatesQTyRD,
3786 SharedsTy, SharedsPtrTy, Data, Privates, /*ForDup=*/true);
3787 CGF.FinishFunction();
3788 return TaskDup;
3789}
3790
3791/// Checks if destructor function is required to be generated.
3792/// \return true if cleanups are required, false otherwise.
3793static bool
3794checkDestructorsRequired(const RecordDecl *KmpTaskTWithPrivatesQTyRD,
3796 for (const PrivateDataTy &P : Privates) {
3797 if (P.second.isLocalPrivate())
3798 continue;
3799 QualType Ty = P.second.Original->getType().getNonReferenceType();
3800 if (Ty.isDestructedType())
3801 return true;
3802 }
3803 return false;
3804}
3805
3806namespace {
3807/// Loop generator for OpenMP iterator expression.
3808class OMPIteratorGeneratorScope final
3810 CodeGenFunction &CGF;
3811 const OMPIteratorExpr *E = nullptr;
3812 SmallVector<CodeGenFunction::JumpDest, 4> ContDests;
3813 SmallVector<CodeGenFunction::JumpDest, 4> ExitDests;
3814 OMPIteratorGeneratorScope() = delete;
3815 OMPIteratorGeneratorScope(OMPIteratorGeneratorScope &) = delete;
3816
3817public:
3818 OMPIteratorGeneratorScope(CodeGenFunction &CGF, const OMPIteratorExpr *E)
3819 : CodeGenFunction::OMPPrivateScope(CGF), CGF(CGF), E(E) {
3820 if (!E)
3821 return;
3822 SmallVector<llvm::Value *, 4> Uppers;
3823 for (unsigned I = 0, End = E->numOfIterators(); I < End; ++I) {
3824 Uppers.push_back(CGF.EmitScalarExpr(E->getHelper(I).Upper));
3825 const auto *VD = cast<VarDecl>(E->getIteratorDecl(I));
3826 addPrivate(VD, CGF.CreateMemTemp(VD->getType(), VD->getName()));
3827 const OMPIteratorHelperData &HelperData = E->getHelper(I);
3828 addPrivate(
3829 HelperData.CounterVD,
3830 CGF.CreateMemTemp(HelperData.CounterVD->getType(), "counter.addr"));
3831 }
3832 Privatize();
3833
3834 for (unsigned I = 0, End = E->numOfIterators(); I < End; ++I) {
3835 const OMPIteratorHelperData &HelperData = E->getHelper(I);
3836 LValue CLVal =
3837 CGF.MakeAddrLValue(CGF.GetAddrOfLocalVar(HelperData.CounterVD),
3838 HelperData.CounterVD->getType());
3839 // Counter = 0;
3840 CGF.EmitStoreOfScalar(
3841 llvm::ConstantInt::get(CLVal.getAddress().getElementType(), 0),
3842 CLVal);
3843 CodeGenFunction::JumpDest &ContDest =
3844 ContDests.emplace_back(CGF.getJumpDestInCurrentScope("iter.cont"));
3845 CodeGenFunction::JumpDest &ExitDest =
3846 ExitDests.emplace_back(CGF.getJumpDestInCurrentScope("iter.exit"));
3847 // N = <number-of_iterations>;
3848 llvm::Value *N = Uppers[I];
3849 // cont:
3850 // if (Counter < N) goto body; else goto exit;
3851 CGF.EmitBlock(ContDest.getBlock());
3852 auto *CVal =
3853 CGF.EmitLoadOfScalar(CLVal, HelperData.CounterVD->getLocation());
3854 llvm::Value *Cmp =
3855 HelperData.CounterVD->getType()->isSignedIntegerOrEnumerationType()
3856 ? CGF.Builder.CreateICmpSLT(CVal, N)
3857 : CGF.Builder.CreateICmpULT(CVal, N);
3858 llvm::BasicBlock *BodyBB = CGF.createBasicBlock("iter.body");
3859 CGF.Builder.CreateCondBr(Cmp, BodyBB, ExitDest.getBlock());
3860 // body:
3861 CGF.EmitBlock(BodyBB);
3862 // Iteri = Begini + Counter * Stepi;
3863 CGF.EmitIgnoredExpr(HelperData.Update);
3864 }
3865 }
3866 ~OMPIteratorGeneratorScope() {
3867 if (!E)
3868 return;
3869 for (unsigned I = E->numOfIterators(); I > 0; --I) {
3870 // Counter = Counter + 1;
3871 const OMPIteratorHelperData &HelperData = E->getHelper(I - 1);
3872 CGF.EmitIgnoredExpr(HelperData.CounterUpdate);
3873 // goto cont;
3874 CGF.EmitBranchThroughCleanup(ContDests[I - 1]);
3875 // exit:
3876 CGF.EmitBlock(ExitDests[I - 1].getBlock(), /*IsFinished=*/I == 1);
3877 }
3878 }
3879};
3880} // namespace
3881
3882static std::pair<llvm::Value *, llvm::Value *>
3884 const auto *OASE = dyn_cast<OMPArrayShapingExpr>(E);
3885 llvm::Value *Addr;
3886 if (OASE) {
3887 const Expr *Base = OASE->getBase();
3888 Addr = CGF.EmitScalarExpr(Base);
3889 } else {
3890 Addr = CGF.EmitLValue(E).getPointer(CGF);
3891 }
3892 llvm::Value *SizeVal;
3893 QualType Ty = E->getType();
3894 if (OASE) {
3895 SizeVal = CGF.getTypeSize(OASE->getBase()->getType()->getPointeeType());
3896 for (const Expr *SE : OASE->getDimensions()) {
3897 llvm::Value *Sz = CGF.EmitScalarExpr(SE);
3898 Sz = CGF.EmitScalarConversion(
3899 Sz, SE->getType(), CGF.getContext().getSizeType(), SE->getExprLoc());
3900 SizeVal = CGF.Builder.CreateNUWMul(SizeVal, Sz);
3901 }
3902 } else if (const auto *ASE =
3903 dyn_cast<ArraySectionExpr>(E->IgnoreParenImpCasts())) {
3904 LValue UpAddrLVal = CGF.EmitArraySectionExpr(ASE, /*IsLowerBound=*/false);
3905 Address UpAddrAddress = UpAddrLVal.getAddress();
3906 llvm::Value *UpAddr = CGF.Builder.CreateConstGEP1_32(
3907 UpAddrAddress.getElementType(), UpAddrAddress.emitRawPointer(CGF),
3908 /*Idx0=*/1);
3909 SizeVal = CGF.Builder.CreatePtrDiff(UpAddr, Addr, "", /*IsNUW=*/true);
3910 } else {
3911 SizeVal = CGF.getTypeSize(Ty);
3912 }
3913 return std::make_pair(Addr, SizeVal);
3914}
3915
3916/// Builds kmp_depend_info, if it is not built yet, and builds flags type.
3917static void getKmpAffinityType(ASTContext &C, QualType &KmpTaskAffinityInfoTy) {
3918 QualType FlagsTy = C.getIntTypeForBitwidth(32, /*Signed=*/false);
3919 if (KmpTaskAffinityInfoTy.isNull()) {
3920 RecordDecl *KmpAffinityInfoRD =
3921 C.buildImplicitRecord("kmp_task_affinity_info_t");
3922 KmpAffinityInfoRD->startDefinition();
3923 addFieldToRecordDecl(C, KmpAffinityInfoRD, C.getIntPtrType());
3924 addFieldToRecordDecl(C, KmpAffinityInfoRD, C.getSizeType());
3925 addFieldToRecordDecl(C, KmpAffinityInfoRD, FlagsTy);
3926 KmpAffinityInfoRD->completeDefinition();
3927 KmpTaskAffinityInfoTy = C.getCanonicalTagType(KmpAffinityInfoRD);
3928 }
3929}
3930
3933 const OMPExecutableDirective &D,
3934 llvm::Function *TaskFunction, QualType SharedsTy,
3935 Address Shareds, const OMPTaskDataTy &Data) {
3936 ASTContext &C = CGM.getContext();
3938 // Aggregate privates and sort them by the alignment.
3939 const auto *I = Data.PrivateCopies.begin();
3940 for (const Expr *E : Data.PrivateVars) {
3941 const auto *Decl = cast<DeclRefExpr>(E)->getDecl();
3942 const auto *VD = getOriginalVarDecl(Decl);
3943 const auto *CopyVD = cast<VarDecl>(cast<DeclRefExpr>(*I)->getDecl());
3944 Privates.emplace_back(C.getDeclAlign(VD),
3945 PrivateHelpersTy(E, VD, CopyVD,
3946 /*PrivateElemInit=*/nullptr));
3947 ++I;
3948 }
3949 I = Data.FirstprivateCopies.begin();
3950 const auto *IElemInitRef = Data.FirstprivateInits.begin();
3951 for (const Expr *E : Data.FirstprivateVars) {
3952 const auto *Decl = cast<DeclRefExpr>(E)->getDecl();
3953 const auto *VD = getOriginalVarDecl(Decl);
3954 const auto *CopyVD = cast<VarDecl>(cast<DeclRefExpr>(*I)->getDecl());
3955 const auto *InitVD =
3956 cast<VarDecl>(cast<DeclRefExpr>(*IElemInitRef)->getDecl());
3957 Privates.emplace_back(C.getDeclAlign(VD),
3958 PrivateHelpersTy(E, VD, CopyVD, InitVD));
3959 ++I;
3960 ++IElemInitRef;
3961 }
3962 I = Data.LastprivateCopies.begin();
3963 for (const Expr *E : Data.LastprivateVars) {
3964 const auto *Decl = cast<DeclRefExpr>(E)->getDecl();
3965 const auto *VD = getOriginalVarDecl(Decl);
3966 const auto *CopyVD = cast<VarDecl>(cast<DeclRefExpr>(*I)->getDecl());
3967 Privates.emplace_back(C.getDeclAlign(VD),
3968 PrivateHelpersTy(E, VD, CopyVD,
3969 /*PrivateElemInit=*/nullptr));
3970 ++I;
3971 }
3972 for (const VarDecl *VD : Data.PrivateLocals) {
3973 if (isAllocatableDecl(VD))
3974 Privates.emplace_back(CGM.getPointerAlign(), PrivateHelpersTy(VD));
3975 else
3976 Privates.emplace_back(C.getDeclAlign(VD), PrivateHelpersTy(VD));
3977 }
3978 llvm::stable_sort(Privates,
3979 [](const PrivateDataTy &L, const PrivateDataTy &R) {
3980 return L.first > R.first;
3981 });
3982 QualType KmpInt32Ty = C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1);
3983 // Build type kmp_routine_entry_t (if not built yet).
3984 emitKmpRoutineEntryT(KmpInt32Ty);
3985 // Build type kmp_task_t (if not built yet).
3986 if (isOpenMPTaskLoopDirective(D.getDirectiveKind())) {
3987 if (SavedKmpTaskloopTQTy.isNull()) {
3988 SavedKmpTaskloopTQTy = C.getCanonicalTagType(createKmpTaskTRecordDecl(
3989 CGM, D.getDirectiveKind(), KmpInt32Ty, KmpRoutineEntryPtrQTy));
3990 }
3992 } else {
3993 assert((D.getDirectiveKind() == OMPD_task ||
3994 isOpenMPTargetExecutionDirective(D.getDirectiveKind()) ||
3995 isOpenMPTargetDataManagementDirective(D.getDirectiveKind())) &&
3996 "Expected taskloop, task or target directive");
3997 if (SavedKmpTaskTQTy.isNull()) {
3998 SavedKmpTaskTQTy = C.getCanonicalTagType(createKmpTaskTRecordDecl(
3999 CGM, D.getDirectiveKind(), KmpInt32Ty, KmpRoutineEntryPtrQTy));
4000 }
4002 }
4003 const auto *KmpTaskTQTyRD = KmpTaskTQTy->castAsRecordDecl();
4004 // Build particular struct kmp_task_t for the given task.
4005 const RecordDecl *KmpTaskTWithPrivatesQTyRD =
4007 CanQualType KmpTaskTWithPrivatesQTy =
4008 C.getCanonicalTagType(KmpTaskTWithPrivatesQTyRD);
4009 QualType KmpTaskTWithPrivatesPtrQTy =
4010 C.getPointerType(KmpTaskTWithPrivatesQTy);
4011 llvm::Type *KmpTaskTWithPrivatesPtrTy = CGF.Builder.getPtrTy(0);
4012 llvm::Value *KmpTaskTWithPrivatesTySize =
4013 CGF.getTypeSize(KmpTaskTWithPrivatesQTy);
4014 QualType SharedsPtrTy = C.getPointerType(SharedsTy);
4015
4016 // Emit initial values for private copies (if any).
4017 llvm::Value *TaskPrivatesMap = nullptr;
4018 llvm::Type *TaskPrivatesMapTy =
4019 std::next(TaskFunction->arg_begin(), 3)->getType();
4020 if (!Privates.empty()) {
4021 auto FI = std::next(KmpTaskTWithPrivatesQTyRD->field_begin());
4022 TaskPrivatesMap =
4023 emitTaskPrivateMappingFunction(CGM, Loc, Data, FI->getType(), Privates);
4024 TaskPrivatesMap = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
4025 TaskPrivatesMap, TaskPrivatesMapTy);
4026 } else {
4027 TaskPrivatesMap = llvm::ConstantPointerNull::get(
4028 cast<llvm::PointerType>(TaskPrivatesMapTy));
4029 }
4030 // Build a proxy function kmp_int32 .omp_task_entry.(kmp_int32 gtid,
4031 // kmp_task_t *tt);
4032 llvm::Function *TaskEntry = emitProxyTaskFunction(
4033 CGM, Loc, D.getDirectiveKind(), KmpInt32Ty, KmpTaskTWithPrivatesPtrQTy,
4034 KmpTaskTWithPrivatesQTy, KmpTaskTQTy, SharedsPtrTy, TaskFunction,
4035 TaskPrivatesMap);
4036
4037 // Build call kmp_task_t * __kmpc_omp_task_alloc(ident_t *, kmp_int32 gtid,
4038 // kmp_int32 flags, size_t sizeof_kmp_task_t, size_t sizeof_shareds,
4039 // kmp_routine_entry_t *task_entry);
4040 // Task flags. Format is taken from
4041 // https://github.com/llvm/llvm-project/blob/main/openmp/runtime/src/kmp.h,
4042 // description of kmp_tasking_flags struct.
4043 enum {
4044 TiedFlag = 0x1,
4045 FinalFlag = 0x2,
4046 DestructorsFlag = 0x8,
4047 PriorityFlag = 0x20,
4048 DetachableFlag = 0x40,
4049 FreeAgentFlag = 0x80,
4050 TransparentFlag = 0x100,
4051 };
4052 unsigned Flags = Data.Tied ? TiedFlag : 0;
4053 bool NeedsCleanup = false;
4054 if (!Privates.empty()) {
4055 NeedsCleanup =
4056 checkDestructorsRequired(KmpTaskTWithPrivatesQTyRD, Privates);
4057 if (NeedsCleanup)
4058 Flags = Flags | DestructorsFlag;
4059 }
4060 if (const auto *Clause = D.getSingleClause<OMPThreadsetClause>()) {
4061 OpenMPThreadsetKind Kind = Clause->getThreadsetKind();
4062 if (Kind == OMPC_THREADSET_omp_pool)
4063 Flags = Flags | FreeAgentFlag;
4064 }
4065 if (D.getSingleClause<OMPTransparentClause>())
4066 Flags |= TransparentFlag;
4067
4068 if (Data.Priority.getInt())
4069 Flags = Flags | PriorityFlag;
4070 if (D.hasClausesOfKind<OMPDetachClause>())
4071 Flags = Flags | DetachableFlag;
4072 llvm::Value *TaskFlags =
4073 Data.Final.getPointer()
4074 ? CGF.Builder.CreateSelect(Data.Final.getPointer(),
4075 CGF.Builder.getInt32(FinalFlag),
4076 CGF.Builder.getInt32(/*C=*/0))
4077 : CGF.Builder.getInt32(Data.Final.getInt() ? FinalFlag : 0);
4078 TaskFlags = CGF.Builder.CreateOr(TaskFlags, CGF.Builder.getInt32(Flags));
4079 llvm::Value *SharedsSize = CGM.getSize(C.getTypeSizeInChars(SharedsTy));
4081 getThreadID(CGF, Loc), TaskFlags, KmpTaskTWithPrivatesTySize,
4083 TaskEntry, KmpRoutineEntryPtrTy)};
4084 llvm::Value *NewTask;
4085 if (D.hasClausesOfKind<OMPNowaitClause>()) {
4086 // Check if we have any device clause associated with the directive.
4087 const Expr *Device = nullptr;
4088 if (auto *C = D.getSingleClause<OMPDeviceClause>())
4089 Device = C->getDevice();
4090 // Emit device ID if any otherwise use default value.
4091 llvm::Value *DeviceID;
4092 if (Device)
4093 DeviceID = CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(Device),
4094 CGF.Int64Ty, /*isSigned=*/true);
4095 else
4096 DeviceID = CGF.Builder.getInt64(OMP_DEVICEID_UNDEF);
4097 AllocArgs.push_back(DeviceID);
4098 NewTask = CGF.EmitRuntimeCall(
4099 OMPBuilder.getOrCreateRuntimeFunction(
4100 CGM.getModule(), OMPRTL___kmpc_omp_target_task_alloc),
4101 AllocArgs);
4102 } else {
4103 NewTask =
4104 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
4105 CGM.getModule(), OMPRTL___kmpc_omp_task_alloc),
4106 AllocArgs);
4107 }
4108 // Emit detach clause initialization.
4109 // evt = (typeof(evt))__kmpc_task_allow_completion_event(loc, tid,
4110 // task_descriptor);
4111 if (const auto *DC = D.getSingleClause<OMPDetachClause>()) {
4112 const Expr *Evt = DC->getEventHandler()->IgnoreParenImpCasts();
4113 LValue EvtLVal = CGF.EmitLValue(Evt);
4114
4115 // Build kmp_event_t *__kmpc_task_allow_completion_event(ident_t *loc_ref,
4116 // int gtid, kmp_task_t *task);
4117 llvm::Value *Loc = emitUpdateLocation(CGF, DC->getBeginLoc());
4118 llvm::Value *Tid = getThreadID(CGF, DC->getBeginLoc());
4119 Tid = CGF.Builder.CreateIntCast(Tid, CGF.IntTy, /*isSigned=*/false);
4120 llvm::Value *EvtVal = CGF.EmitRuntimeCall(
4121 OMPBuilder.getOrCreateRuntimeFunction(
4122 CGM.getModule(), OMPRTL___kmpc_task_allow_completion_event),
4123 {Loc, Tid, NewTask});
4124 EvtVal = CGF.EmitScalarConversion(EvtVal, C.VoidPtrTy, Evt->getType(),
4125 Evt->getExprLoc());
4126 CGF.EmitStoreOfScalar(EvtVal, EvtLVal);
4127 }
4128 // Process affinity clauses.
4129 if (D.hasClausesOfKind<OMPAffinityClause>()) {
4130 // Process list of affinity data.
4131 ASTContext &C = CGM.getContext();
4132 Address AffinitiesArray = Address::invalid();
4133 // Calculate number of elements to form the array of affinity data.
4134 llvm::Value *NumOfElements = nullptr;
4135 unsigned NumAffinities = 0;
4136 for (const auto *C : D.getClausesOfKind<OMPAffinityClause>()) {
4137 if (const Expr *Modifier = C->getModifier()) {
4138 const auto *IE = cast<OMPIteratorExpr>(Modifier->IgnoreParenImpCasts());
4139 for (unsigned I = 0, E = IE->numOfIterators(); I < E; ++I) {
4140 llvm::Value *Sz = CGF.EmitScalarExpr(IE->getHelper(I).Upper);
4141 Sz = CGF.Builder.CreateIntCast(Sz, CGF.SizeTy, /*isSigned=*/false);
4142 NumOfElements =
4143 NumOfElements ? CGF.Builder.CreateNUWMul(NumOfElements, Sz) : Sz;
4144 }
4145 } else {
4146 NumAffinities += C->varlist_size();
4147 }
4148 }
4150 // Fields ids in kmp_task_affinity_info record.
4151 enum RTLAffinityInfoFieldsTy { BaseAddr, Len, Flags };
4152
4153 QualType KmpTaskAffinityInfoArrayTy;
4154 if (NumOfElements) {
4155 NumOfElements = CGF.Builder.CreateNUWAdd(
4156 llvm::ConstantInt::get(CGF.SizeTy, NumAffinities), NumOfElements);
4157 auto *OVE = new (C) OpaqueValueExpr(
4158 Loc,
4159 C.getIntTypeForBitwidth(C.getTypeSize(C.getSizeType()), /*Signed=*/0),
4160 VK_PRValue);
4161 CodeGenFunction::OpaqueValueMapping OpaqueMap(CGF, OVE,
4162 RValue::get(NumOfElements));
4163 KmpTaskAffinityInfoArrayTy = C.getVariableArrayType(
4165 /*IndexTypeQuals=*/0);
4166 // Properly emit variable-sized array.
4167 auto *PD = ImplicitParamDecl::Create(C, KmpTaskAffinityInfoArrayTy,
4169 CGF.EmitVarDecl(*PD);
4170 AffinitiesArray = CGF.GetAddrOfLocalVar(PD);
4171 NumOfElements = CGF.Builder.CreateIntCast(NumOfElements, CGF.Int32Ty,
4172 /*isSigned=*/false);
4173 } else {
4174 KmpTaskAffinityInfoArrayTy = C.getConstantArrayType(
4176 llvm::APInt(C.getTypeSize(C.getSizeType()), NumAffinities), nullptr,
4177 ArraySizeModifier::Normal, /*IndexTypeQuals=*/0);
4178 AffinitiesArray = CGF.CreateMemTempWithoutCast(KmpTaskAffinityInfoArrayTy,
4179 ".affs.arr.addr");
4180 AffinitiesArray = CGF.Builder.CreateConstArrayGEP(AffinitiesArray, 0);
4181 NumOfElements = llvm::ConstantInt::get(CGM.Int32Ty, NumAffinities,
4182 /*isSigned=*/false);
4183 }
4184
4185 const auto *KmpAffinityInfoRD = KmpTaskAffinityInfoTy->getAsRecordDecl();
4186 // Fill array by elements without iterators.
4187 unsigned Pos = 0;
4188 bool HasIterator = false;
4189 for (const auto *C : D.getClausesOfKind<OMPAffinityClause>()) {
4190 if (C->getModifier()) {
4191 HasIterator = true;
4192 continue;
4193 }
4194 for (const Expr *E : C->varlist()) {
4195 llvm::Value *Addr;
4196 llvm::Value *Size;
4197 std::tie(Addr, Size) = getPointerAndSize(CGF, E);
4198 LValue Base =
4199 CGF.MakeAddrLValue(CGF.Builder.CreateConstGEP(AffinitiesArray, Pos),
4201 // affs[i].base_addr = &<Affinities[i].second>;
4202 LValue BaseAddrLVal = CGF.EmitLValueForField(
4203 Base, *std::next(KmpAffinityInfoRD->field_begin(), BaseAddr));
4204 CGF.EmitStoreOfScalar(CGF.Builder.CreatePtrToInt(Addr, CGF.IntPtrTy),
4205 BaseAddrLVal);
4206 // affs[i].len = sizeof(<Affinities[i].second>);
4207 LValue LenLVal = CGF.EmitLValueForField(
4208 Base, *std::next(KmpAffinityInfoRD->field_begin(), Len));
4209 CGF.EmitStoreOfScalar(Size, LenLVal);
4210 ++Pos;
4211 }
4212 }
4213 LValue PosLVal;
4214 if (HasIterator) {
4215 PosLVal = CGF.MakeAddrLValue(
4216 CGF.CreateMemTempWithoutCast(C.getSizeType(), "affs.counter.addr"),
4217 C.getSizeType());
4218 CGF.EmitStoreOfScalar(llvm::ConstantInt::get(CGF.SizeTy, Pos), PosLVal);
4219 }
4220 // Process elements with iterators.
4221 for (const auto *C : D.getClausesOfKind<OMPAffinityClause>()) {
4222 const Expr *Modifier = C->getModifier();
4223 if (!Modifier)
4224 continue;
4225 OMPIteratorGeneratorScope IteratorScope(
4226 CGF, cast_or_null<OMPIteratorExpr>(Modifier->IgnoreParenImpCasts()));
4227 for (const Expr *E : C->varlist()) {
4228 llvm::Value *Addr;
4229 llvm::Value *Size;
4230 std::tie(Addr, Size) = getPointerAndSize(CGF, E);
4231 llvm::Value *Idx = CGF.EmitLoadOfScalar(PosLVal, E->getExprLoc());
4232 LValue Base =
4233 CGF.MakeAddrLValue(CGF.Builder.CreateGEP(CGF, AffinitiesArray, Idx),
4235 // affs[i].base_addr = &<Affinities[i].second>;
4236 LValue BaseAddrLVal = CGF.EmitLValueForField(
4237 Base, *std::next(KmpAffinityInfoRD->field_begin(), BaseAddr));
4238 CGF.EmitStoreOfScalar(CGF.Builder.CreatePtrToInt(Addr, CGF.IntPtrTy),
4239 BaseAddrLVal);
4240 // affs[i].len = sizeof(<Affinities[i].second>);
4241 LValue LenLVal = CGF.EmitLValueForField(
4242 Base, *std::next(KmpAffinityInfoRD->field_begin(), Len));
4243 CGF.EmitStoreOfScalar(Size, LenLVal);
4244 Idx = CGF.Builder.CreateNUWAdd(
4245 Idx, llvm::ConstantInt::get(Idx->getType(), 1));
4246 CGF.EmitStoreOfScalar(Idx, PosLVal);
4247 }
4248 }
4249 // Call to kmp_int32 __kmpc_omp_reg_task_with_affinity(ident_t *loc_ref,
4250 // kmp_int32 gtid, kmp_task_t *new_task, kmp_int32
4251 // naffins, kmp_task_affinity_info_t *affin_list);
4252 llvm::Value *LocRef = emitUpdateLocation(CGF, Loc);
4253 llvm::Value *GTid = getThreadID(CGF, Loc);
4254 llvm::Value *AffinListPtr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
4255 AffinitiesArray.emitRawPointer(CGF), CGM.VoidPtrTy);
4256 // FIXME: Emit the function and ignore its result for now unless the
4257 // runtime function is properly implemented.
4258 (void)CGF.EmitRuntimeCall(
4259 OMPBuilder.getOrCreateRuntimeFunction(
4260 CGM.getModule(), OMPRTL___kmpc_omp_reg_task_with_affinity),
4261 {LocRef, GTid, NewTask, NumOfElements, AffinListPtr});
4262 }
4263 llvm::Value *NewTaskNewTaskTTy =
4265 NewTask, KmpTaskTWithPrivatesPtrTy);
4266 LValue Base = CGF.MakeNaturalAlignRawAddrLValue(NewTaskNewTaskTTy,
4267 KmpTaskTWithPrivatesQTy);
4268 LValue TDBase =
4269 CGF.EmitLValueForField(Base, *KmpTaskTWithPrivatesQTyRD->field_begin());
4270 // Fill the data in the resulting kmp_task_t record.
4271 // Copy shareds if there are any.
4272 Address KmpTaskSharedsPtr = Address::invalid();
4273 if (!SharedsTy->castAsRecordDecl()->field_empty()) {
4274 KmpTaskSharedsPtr = Address(
4275 CGF.EmitLoadOfScalar(
4277 TDBase,
4278 *std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTShareds)),
4279 Loc),
4280 CGF.Int8Ty, CGM.getNaturalTypeAlignment(SharedsTy));
4281 LValue Dest = CGF.MakeAddrLValue(KmpTaskSharedsPtr, SharedsTy);
4282 LValue Src = CGF.MakeAddrLValue(Shareds, SharedsTy);
4283 CGF.EmitAggregateCopy(Dest, Src, SharedsTy, AggValueSlot::DoesNotOverlap);
4284 }
4285 // Emit initial values for private copies (if any).
4287 if (!Privates.empty()) {
4288 emitPrivatesInit(CGF, D, KmpTaskSharedsPtr, Base, KmpTaskTWithPrivatesQTyRD,
4289 SharedsTy, SharedsPtrTy, Data, Privates,
4290 /*ForDup=*/false);
4291 if (isOpenMPTaskLoopDirective(D.getDirectiveKind()) &&
4292 (!Data.LastprivateVars.empty() || checkInitIsRequired(CGF, Privates))) {
4293 Result.TaskDupFn = emitTaskDupFunction(
4294 CGM, Loc, D, KmpTaskTWithPrivatesPtrQTy, KmpTaskTWithPrivatesQTyRD,
4295 KmpTaskTQTyRD, SharedsTy, SharedsPtrTy, Data, Privates,
4296 /*WithLastIter=*/!Data.LastprivateVars.empty());
4297 }
4298 }
4299 // Fields of union "kmp_cmplrdata_t" for destructors and priority.
4300 enum { Priority = 0, Destructors = 1 };
4301 // Provide pointer to function with destructors for privates.
4302 auto FI = std::next(KmpTaskTQTyRD->field_begin(), Data1);
4303 const auto *KmpCmplrdataUD = (*FI)->getType()->castAsRecordDecl();
4304 assert(KmpCmplrdataUD->isUnion());
4305 if (NeedsCleanup) {
4306 llvm::Value *DestructorFn = emitDestructorsFunction(
4307 CGM, Loc, KmpInt32Ty, KmpTaskTWithPrivatesPtrQTy,
4308 KmpTaskTWithPrivatesQTy);
4309 LValue Data1LV = CGF.EmitLValueForField(TDBase, *FI);
4310 LValue DestructorsLV = CGF.EmitLValueForField(
4311 Data1LV, *std::next(KmpCmplrdataUD->field_begin(), Destructors));
4313 DestructorFn, KmpRoutineEntryPtrTy),
4314 DestructorsLV);
4315 }
4316 // Set priority.
4317 if (Data.Priority.getInt()) {
4318 LValue Data2LV = CGF.EmitLValueForField(
4319 TDBase, *std::next(KmpTaskTQTyRD->field_begin(), Data2));
4320 LValue PriorityLV = CGF.EmitLValueForField(
4321 Data2LV, *std::next(KmpCmplrdataUD->field_begin(), Priority));
4322 CGF.EmitStoreOfScalar(Data.Priority.getPointer(), PriorityLV);
4323 }
4324 Result.NewTask = NewTask;
4325 Result.TaskEntry = TaskEntry;
4326 Result.NewTaskNewTaskTTy = NewTaskNewTaskTTy;
4327 Result.TDBase = TDBase;
4328 Result.KmpTaskTQTyRD = KmpTaskTQTyRD;
4329 return Result;
4330}
4331
4332/// Translates internal dependency kind into the runtime kind.
4334 RTLDependenceKindTy DepKind;
4335 switch (K) {
4336 case OMPC_DEPEND_in:
4337 DepKind = RTLDependenceKindTy::DepIn;
4338 break;
4339 // Out and InOut dependencies must use the same code.
4340 case OMPC_DEPEND_out:
4341 case OMPC_DEPEND_inout:
4342 DepKind = RTLDependenceKindTy::DepInOut;
4343 break;
4344 case OMPC_DEPEND_mutexinoutset:
4345 DepKind = RTLDependenceKindTy::DepMutexInOutSet;
4346 break;
4347 case OMPC_DEPEND_inoutset:
4348 DepKind = RTLDependenceKindTy::DepInOutSet;
4349 break;
4350 case OMPC_DEPEND_outallmemory:
4351 DepKind = RTLDependenceKindTy::DepOmpAllMem;
4352 break;
4353 case OMPC_DEPEND_source:
4354 case OMPC_DEPEND_sink:
4355 case OMPC_DEPEND_depobj:
4356 case OMPC_DEPEND_inoutallmemory:
4358 llvm_unreachable("Unknown task dependence type");
4359 }
4360 return DepKind;
4361}
4362
4363/// Builds kmp_depend_info, if it is not built yet, and builds flags type.
4364static void getDependTypes(ASTContext &C, QualType &KmpDependInfoTy,
4365 QualType &FlagsTy) {
4366 FlagsTy = C.getIntTypeForBitwidth(C.getTypeSize(C.BoolTy), /*Signed=*/false);
4367 if (KmpDependInfoTy.isNull()) {
4368 RecordDecl *KmpDependInfoRD = C.buildImplicitRecord("kmp_depend_info");
4369 KmpDependInfoRD->startDefinition();
4370 addFieldToRecordDecl(C, KmpDependInfoRD, C.getIntPtrType());
4371 addFieldToRecordDecl(C, KmpDependInfoRD, C.getSizeType());
4372 addFieldToRecordDecl(C, KmpDependInfoRD, FlagsTy);
4373 KmpDependInfoRD->completeDefinition();
4374 KmpDependInfoTy = C.getCanonicalTagType(KmpDependInfoRD);
4375 }
4376}
4377
4378std::pair<llvm::Value *, LValue>
4380 SourceLocation Loc) {
4381 ASTContext &C = CGM.getContext();
4382 QualType FlagsTy;
4383 getDependTypes(C, KmpDependInfoTy, FlagsTy);
4384 auto *KmpDependInfoRD = KmpDependInfoTy->castAsRecordDecl();
4385 QualType KmpDependInfoPtrTy = C.getPointerType(KmpDependInfoTy);
4387 DepobjLVal.getAddress().withElementType(
4388 CGF.ConvertTypeForMem(KmpDependInfoPtrTy)),
4389 KmpDependInfoPtrTy->castAs<PointerType>());
4390 Address DepObjAddr = CGF.Builder.CreateGEP(
4391 CGF, Base.getAddress(),
4392 llvm::ConstantInt::get(CGF.IntPtrTy, -1, /*isSigned=*/true));
4393 LValue NumDepsBase = CGF.MakeAddrLValue(
4394 DepObjAddr, KmpDependInfoTy, Base.getBaseInfo(), Base.getTBAAInfo());
4395 // NumDeps = deps[i].base_addr;
4396 LValue BaseAddrLVal = CGF.EmitLValueForField(
4397 NumDepsBase,
4398 *std::next(KmpDependInfoRD->field_begin(),
4399 static_cast<unsigned int>(RTLDependInfoFields::BaseAddr)));
4400 llvm::Value *NumDeps = CGF.EmitLoadOfScalar(BaseAddrLVal, Loc);
4401 return std::make_pair(NumDeps, Base);
4402}
4403
4404static void emitDependData(CodeGenFunction &CGF, QualType &KmpDependInfoTy,
4405 llvm::PointerUnion<unsigned *, LValue *> Pos,
4407 Address DependenciesArray) {
4408 CodeGenModule &CGM = CGF.CGM;
4409 ASTContext &C = CGM.getContext();
4410 QualType FlagsTy;
4411 getDependTypes(C, KmpDependInfoTy, FlagsTy);
4412 auto *KmpDependInfoRD = KmpDependInfoTy->castAsRecordDecl();
4413 llvm::Type *LLVMFlagsTy = CGF.ConvertTypeForMem(FlagsTy);
4414
4415 OMPIteratorGeneratorScope IteratorScope(
4416 CGF, cast_or_null<OMPIteratorExpr>(
4417 Data.IteratorExpr ? Data.IteratorExpr->IgnoreParenImpCasts()
4418 : nullptr));
4419 for (const Expr *E : Data.DepExprs) {
4420 llvm::Value *Addr;
4421 llvm::Value *Size;
4422
4423 // The expression will be a nullptr in the 'omp_all_memory' case.
4424 if (E) {
4425 std::tie(Addr, Size) = getPointerAndSize(CGF, E);
4426 Addr = CGF.Builder.CreatePtrToInt(Addr, CGF.IntPtrTy);
4427 } else {
4428 Addr = llvm::ConstantInt::get(CGF.IntPtrTy, 0);
4429 Size = llvm::ConstantInt::get(CGF.SizeTy, 0);
4430 }
4431 LValue Base;
4432 if (unsigned *P = dyn_cast<unsigned *>(Pos)) {
4433 Base = CGF.MakeAddrLValue(
4434 CGF.Builder.CreateConstGEP(DependenciesArray, *P), KmpDependInfoTy);
4435 } else {
4436 assert(E && "Expected a non-null expression");
4437 LValue &PosLVal = *cast<LValue *>(Pos);
4438 llvm::Value *Idx = CGF.EmitLoadOfScalar(PosLVal, E->getExprLoc());
4439 Base = CGF.MakeAddrLValue(
4440 CGF.Builder.CreateGEP(CGF, DependenciesArray, Idx), KmpDependInfoTy);
4441 }
4442 // deps[i].base_addr = &<Dependencies[i].second>;
4443 LValue BaseAddrLVal = CGF.EmitLValueForField(
4444 Base,
4445 *std::next(KmpDependInfoRD->field_begin(),
4446 static_cast<unsigned int>(RTLDependInfoFields::BaseAddr)));
4447 CGF.EmitStoreOfScalar(Addr, BaseAddrLVal);
4448 // deps[i].len = sizeof(<Dependencies[i].second>);
4449 LValue LenLVal = CGF.EmitLValueForField(
4450 Base, *std::next(KmpDependInfoRD->field_begin(),
4451 static_cast<unsigned int>(RTLDependInfoFields::Len)));
4452 CGF.EmitStoreOfScalar(Size, LenLVal);
4453 // deps[i].flags = <Dependencies[i].first>;
4454 RTLDependenceKindTy DepKind = translateDependencyKind(Data.DepKind);
4455 LValue FlagsLVal = CGF.EmitLValueForField(
4456 Base,
4457 *std::next(KmpDependInfoRD->field_begin(),
4458 static_cast<unsigned int>(RTLDependInfoFields::Flags)));
4460 llvm::ConstantInt::get(LLVMFlagsTy, static_cast<unsigned int>(DepKind)),
4461 FlagsLVal);
4462 if (unsigned *P = dyn_cast<unsigned *>(Pos)) {
4463 ++(*P);
4464 } else {
4465 LValue &PosLVal = *cast<LValue *>(Pos);
4466 llvm::Value *Idx = CGF.EmitLoadOfScalar(PosLVal, E->getExprLoc());
4467 Idx = CGF.Builder.CreateNUWAdd(Idx,
4468 llvm::ConstantInt::get(Idx->getType(), 1));
4469 CGF.EmitStoreOfScalar(Idx, PosLVal);
4470 }
4471 }
4472}
4473
4477 assert(Data.DepKind == OMPC_DEPEND_depobj &&
4478 "Expected depobj dependency kind.");
4480 SmallVector<LValue, 4> SizeLVals;
4481 ASTContext &C = CGF.getContext();
4482 {
4483 OMPIteratorGeneratorScope IteratorScope(
4484 CGF, cast_or_null<OMPIteratorExpr>(
4485 Data.IteratorExpr ? Data.IteratorExpr->IgnoreParenImpCasts()
4486 : nullptr));
4487 for (const Expr *E : Data.DepExprs) {
4488 llvm::Value *NumDeps;
4489 LValue Base;
4490 LValue DepobjLVal = CGF.EmitLValue(E->IgnoreParenImpCasts());
4491 std::tie(NumDeps, Base) =
4492 getDepobjElements(CGF, DepobjLVal, E->getExprLoc());
4493 LValue NumLVal = CGF.MakeAddrLValue(
4494 CGF.CreateMemTempWithoutCast(C.getUIntPtrType(), "depobj.size.addr"),
4495 C.getUIntPtrType());
4496 CGF.Builder.CreateStore(llvm::ConstantInt::get(CGF.IntPtrTy, 0),
4497 NumLVal.getAddress());
4498 llvm::Value *PrevVal = CGF.EmitLoadOfScalar(NumLVal, E->getExprLoc());
4499 llvm::Value *Add = CGF.Builder.CreateNUWAdd(PrevVal, NumDeps);
4500 CGF.EmitStoreOfScalar(Add, NumLVal);
4501 SizeLVals.push_back(NumLVal);
4502 }
4503 }
4504 for (unsigned I = 0, E = SizeLVals.size(); I < E; ++I) {
4505 llvm::Value *Size =
4506 CGF.EmitLoadOfScalar(SizeLVals[I], Data.DepExprs[I]->getExprLoc());
4507 Sizes.push_back(Size);
4508 }
4509 return Sizes;
4510}
4511
4514 LValue PosLVal,
4516 Address DependenciesArray) {
4517 assert(Data.DepKind == OMPC_DEPEND_depobj &&
4518 "Expected depobj dependency kind.");
4519 llvm::Value *ElSize = CGF.getTypeSize(KmpDependInfoTy);
4520 {
4521 OMPIteratorGeneratorScope IteratorScope(
4522 CGF, cast_or_null<OMPIteratorExpr>(
4523 Data.IteratorExpr ? Data.IteratorExpr->IgnoreParenImpCasts()
4524 : nullptr));
4525 for (const Expr *E : Data.DepExprs) {
4526 llvm::Value *NumDeps;
4527 LValue Base;
4528 LValue DepobjLVal = CGF.EmitLValue(E->IgnoreParenImpCasts());
4529 std::tie(NumDeps, Base) =
4530 getDepobjElements(CGF, DepobjLVal, E->getExprLoc());
4531
4532 // memcopy dependency data.
4533 llvm::Value *Size = CGF.Builder.CreateNUWMul(
4534 ElSize,
4535 CGF.Builder.CreateIntCast(NumDeps, CGF.SizeTy, /*isSigned=*/false));
4536 llvm::Value *Pos = CGF.EmitLoadOfScalar(PosLVal, E->getExprLoc());
4537 Address DepAddr = CGF.Builder.CreateGEP(CGF, DependenciesArray, Pos);
4538 CGF.Builder.CreateMemCpy(DepAddr, Base.getAddress(), Size);
4539
4540 // Increase pos.
4541 // pos += size;
4542 llvm::Value *Add = CGF.Builder.CreateNUWAdd(Pos, NumDeps);
4543 CGF.EmitStoreOfScalar(Add, PosLVal);
4544 }
4545 }
4546}
4547
4548std::pair<llvm::Value *, Address> CGOpenMPRuntime::emitDependClause(
4550 SourceLocation Loc) {
4551 if (llvm::all_of(Dependencies, [](const OMPTaskDataTy::DependData &D) {
4552 return D.DepExprs.empty();
4553 }))
4554 return std::make_pair(nullptr, Address::invalid());
4555 // Process list of dependencies.
4556 ASTContext &C = CGM.getContext();
4557 Address DependenciesArray = Address::invalid();
4558 llvm::Value *NumOfElements = nullptr;
4559 unsigned NumDependencies = std::accumulate(
4560 Dependencies.begin(), Dependencies.end(), 0,
4561 [](unsigned V, const OMPTaskDataTy::DependData &D) {
4562 return D.DepKind == OMPC_DEPEND_depobj
4563 ? V
4564 : (V + (D.IteratorExpr ? 0 : D.DepExprs.size()));
4565 });
4566 QualType FlagsTy;
4567 getDependTypes(C, KmpDependInfoTy, FlagsTy);
4568 bool HasDepobjDeps = false;
4569 bool HasRegularWithIterators = false;
4570 llvm::Value *NumOfDepobjElements = llvm::ConstantInt::get(CGF.IntPtrTy, 0);
4571 llvm::Value *NumOfRegularWithIterators =
4572 llvm::ConstantInt::get(CGF.IntPtrTy, 0);
4573 // Calculate number of depobj dependencies and regular deps with the
4574 // iterators.
4575 for (const OMPTaskDataTy::DependData &D : Dependencies) {
4576 if (D.DepKind == OMPC_DEPEND_depobj) {
4579 for (llvm::Value *Size : Sizes) {
4580 NumOfDepobjElements =
4581 CGF.Builder.CreateNUWAdd(NumOfDepobjElements, Size);
4582 }
4583 HasDepobjDeps = true;
4584 continue;
4585 }
4586 // Include number of iterations, if any.
4587
4588 if (const auto *IE = cast_or_null<OMPIteratorExpr>(D.IteratorExpr)) {
4589 llvm::Value *ClauseIteratorSpace =
4590 llvm::ConstantInt::get(CGF.IntPtrTy, 1);
4591 for (unsigned I = 0, E = IE->numOfIterators(); I < E; ++I) {
4592 llvm::Value *Sz = CGF.EmitScalarExpr(IE->getHelper(I).Upper);
4593 Sz = CGF.Builder.CreateIntCast(Sz, CGF.IntPtrTy, /*isSigned=*/false);
4594 ClauseIteratorSpace = CGF.Builder.CreateNUWMul(Sz, ClauseIteratorSpace);
4595 }
4596 llvm::Value *NumClauseDeps = CGF.Builder.CreateNUWMul(
4597 ClauseIteratorSpace,
4598 llvm::ConstantInt::get(CGF.IntPtrTy, D.DepExprs.size()));
4599 NumOfRegularWithIterators =
4600 CGF.Builder.CreateNUWAdd(NumOfRegularWithIterators, NumClauseDeps);
4601 HasRegularWithIterators = true;
4602 continue;
4603 }
4604 }
4605
4606 QualType KmpDependInfoArrayTy;
4607 if (HasDepobjDeps || HasRegularWithIterators) {
4608 NumOfElements = llvm::ConstantInt::get(CGM.IntPtrTy, NumDependencies,
4609 /*isSigned=*/false);
4610 if (HasDepobjDeps) {
4611 NumOfElements =
4612 CGF.Builder.CreateNUWAdd(NumOfDepobjElements, NumOfElements);
4613 }
4614 if (HasRegularWithIterators) {
4615 NumOfElements =
4616 CGF.Builder.CreateNUWAdd(NumOfRegularWithIterators, NumOfElements);
4617 }
4618 auto *OVE = new (C) OpaqueValueExpr(
4619 Loc, C.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/0),
4620 VK_PRValue);
4621 CodeGenFunction::OpaqueValueMapping OpaqueMap(CGF, OVE,
4622 RValue::get(NumOfElements));
4623 KmpDependInfoArrayTy =
4624 C.getVariableArrayType(KmpDependInfoTy, OVE, ArraySizeModifier::Normal,
4625 /*IndexTypeQuals=*/0);
4626 // CGF.EmitVariablyModifiedType(KmpDependInfoArrayTy);
4627 // Properly emit variable-sized array.
4628 auto *PD = ImplicitParamDecl::Create(C, KmpDependInfoArrayTy,
4630 CGF.EmitVarDecl(*PD);
4631 DependenciesArray = CGF.GetAddrOfLocalVar(PD);
4632 NumOfElements = CGF.Builder.CreateIntCast(NumOfElements, CGF.Int32Ty,
4633 /*isSigned=*/false);
4634 } else {
4635 KmpDependInfoArrayTy = C.getConstantArrayType(
4636 KmpDependInfoTy, llvm::APInt(/*numBits=*/64, NumDependencies), nullptr,
4637 ArraySizeModifier::Normal, /*IndexTypeQuals=*/0);
4638 DependenciesArray =
4639 CGF.CreateMemTempWithoutCast(KmpDependInfoArrayTy, ".dep.arr.addr");
4640 DependenciesArray = CGF.Builder.CreateConstArrayGEP(DependenciesArray, 0);
4641 NumOfElements = llvm::ConstantInt::get(CGM.Int32Ty, NumDependencies,
4642 /*isSigned=*/false);
4643 }
4644 unsigned Pos = 0;
4645 for (const OMPTaskDataTy::DependData &Dep : Dependencies) {
4646 if (Dep.DepKind == OMPC_DEPEND_depobj || Dep.IteratorExpr)
4647 continue;
4648 emitDependData(CGF, KmpDependInfoTy, &Pos, Dep, DependenciesArray);
4649 }
4650 // Copy regular dependencies with iterators.
4651 LValue PosLVal = CGF.MakeAddrLValue(
4652 CGF.CreateMemTempWithoutCast(C.getSizeType(), "dep.counter.addr"),
4653 C.getSizeType());
4654 CGF.EmitStoreOfScalar(llvm::ConstantInt::get(CGF.SizeTy, Pos), PosLVal);
4655 for (const OMPTaskDataTy::DependData &Dep : Dependencies) {
4656 if (Dep.DepKind == OMPC_DEPEND_depobj || !Dep.IteratorExpr)
4657 continue;
4658 emitDependData(CGF, KmpDependInfoTy, &PosLVal, Dep, DependenciesArray);
4659 }
4660 // Copy final depobj arrays without iterators.
4661 if (HasDepobjDeps) {
4662 for (const OMPTaskDataTy::DependData &Dep : Dependencies) {
4663 if (Dep.DepKind != OMPC_DEPEND_depobj)
4664 continue;
4665 emitDepobjElements(CGF, KmpDependInfoTy, PosLVal, Dep, DependenciesArray);
4666 }
4667 }
4668 DependenciesArray = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
4669 DependenciesArray, CGF.VoidPtrTy, CGF.Int8Ty);
4670 return std::make_pair(NumOfElements, DependenciesArray);
4671}
4672
4674 CodeGenFunction &CGF, const OMPTaskDataTy::DependData &Dependencies,
4675 SourceLocation Loc) {
4676 if (Dependencies.DepExprs.empty())
4677 return Address::invalid();
4678 // Process list of dependencies.
4679 ASTContext &C = CGM.getContext();
4680 Address DependenciesArray = Address::invalid();
4681 unsigned NumDependencies = Dependencies.DepExprs.size();
4682 QualType FlagsTy;
4683 getDependTypes(C, KmpDependInfoTy, FlagsTy);
4684 auto *KmpDependInfoRD = KmpDependInfoTy->castAsRecordDecl();
4685
4686 llvm::Value *Size;
4687 // Define type kmp_depend_info[<Dependencies.size()>];
4688 // For depobj reserve one extra element to store the number of elements.
4689 // It is required to handle depobj(x) update(in) construct.
4690 // kmp_depend_info[<Dependencies.size()>] deps;
4691 llvm::Value *NumDepsVal;
4692 CharUnits Align = C.getTypeAlignInChars(KmpDependInfoTy);
4693 if (const auto *IE =
4694 cast_or_null<OMPIteratorExpr>(Dependencies.IteratorExpr)) {
4695 NumDepsVal = llvm::ConstantInt::get(CGF.SizeTy, 1);
4696 for (unsigned I = 0, E = IE->numOfIterators(); I < E; ++I) {
4697 llvm::Value *Sz = CGF.EmitScalarExpr(IE->getHelper(I).Upper);
4698 Sz = CGF.Builder.CreateIntCast(Sz, CGF.SizeTy, /*isSigned=*/false);
4699 NumDepsVal = CGF.Builder.CreateNUWMul(NumDepsVal, Sz);
4700 }
4701 Size = CGF.Builder.CreateNUWAdd(llvm::ConstantInt::get(CGF.SizeTy, 1),
4702 NumDepsVal);
4703 CharUnits SizeInBytes =
4704 C.getTypeSizeInChars(KmpDependInfoTy).alignTo(Align);
4705 llvm::Value *RecSize = CGM.getSize(SizeInBytes);
4706 Size = CGF.Builder.CreateNUWMul(Size, RecSize);
4707 NumDepsVal =
4708 CGF.Builder.CreateIntCast(NumDepsVal, CGF.IntPtrTy, /*isSigned=*/false);
4709 } else {
4710 QualType KmpDependInfoArrayTy = C.getConstantArrayType(
4711 KmpDependInfoTy, llvm::APInt(/*numBits=*/64, NumDependencies + 1),
4712 nullptr, ArraySizeModifier::Normal, /*IndexTypeQuals=*/0);
4713 CharUnits Sz = C.getTypeSizeInChars(KmpDependInfoArrayTy);
4714 Size = CGM.getSize(Sz.alignTo(Align));
4715 NumDepsVal = llvm::ConstantInt::get(CGF.IntPtrTy, NumDependencies);
4716 }
4717 // Need to allocate on the dynamic memory.
4718 llvm::Value *ThreadID = getThreadID(CGF, Loc);
4719 // Use default allocator.
4720 llvm::Value *Allocator = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
4721 llvm::Value *Args[] = {ThreadID, Size, Allocator};
4722
4723 llvm::Value *Addr =
4724 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
4725 CGM.getModule(), OMPRTL___kmpc_alloc),
4726 Args, ".dep.arr.addr");
4727 llvm::Type *KmpDependInfoLlvmTy = CGF.ConvertTypeForMem(KmpDependInfoTy);
4729 Addr, CGF.Builder.getPtrTy(0));
4730 DependenciesArray = Address(Addr, KmpDependInfoLlvmTy, Align);
4731 // Write number of elements in the first element of array for depobj.
4732 LValue Base = CGF.MakeAddrLValue(DependenciesArray, KmpDependInfoTy);
4733 // deps[i].base_addr = NumDependencies;
4734 LValue BaseAddrLVal = CGF.EmitLValueForField(
4735 Base,
4736 *std::next(KmpDependInfoRD->field_begin(),
4737 static_cast<unsigned int>(RTLDependInfoFields::BaseAddr)));
4738 CGF.EmitStoreOfScalar(NumDepsVal, BaseAddrLVal);
4739 llvm::PointerUnion<unsigned *, LValue *> Pos;
4740 unsigned Idx = 1;
4741 LValue PosLVal;
4742 if (Dependencies.IteratorExpr) {
4743 PosLVal = CGF.MakeAddrLValue(
4744 CGF.CreateMemTempWithoutCast(C.getSizeType(), "iterator.counter.addr"),
4745 C.getSizeType());
4746 CGF.EmitStoreOfScalar(llvm::ConstantInt::get(CGF.SizeTy, Idx), PosLVal,
4747 /*IsInit=*/true);
4748 Pos = &PosLVal;
4749 } else {
4750 Pos = &Idx;
4751 }
4752 emitDependData(CGF, KmpDependInfoTy, Pos, Dependencies, DependenciesArray);
4753 DependenciesArray = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
4754 CGF.Builder.CreateConstGEP(DependenciesArray, 1), CGF.VoidPtrTy,
4755 CGF.Int8Ty);
4756 return DependenciesArray;
4757}
4758
4760 SourceLocation Loc) {
4761 ASTContext &C = CGM.getContext();
4762 QualType FlagsTy;
4763 getDependTypes(C, KmpDependInfoTy, FlagsTy);
4764 LValue Base = CGF.EmitLoadOfPointerLValue(DepobjLVal.getAddress(),
4765 C.VoidPtrTy.castAs<PointerType>());
4766 QualType KmpDependInfoPtrTy = C.getPointerType(KmpDependInfoTy);
4768 Base.getAddress(), CGF.ConvertTypeForMem(KmpDependInfoPtrTy),
4770 llvm::Value *DepObjAddr = CGF.Builder.CreateGEP(
4771 Addr.getElementType(), Addr.emitRawPointer(CGF),
4772 llvm::ConstantInt::get(CGF.IntPtrTy, -1, /*isSigned=*/true));
4773 DepObjAddr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(DepObjAddr,
4774 CGF.VoidPtrTy);
4775 llvm::Value *ThreadID = getThreadID(CGF, Loc);
4776 // Use default allocator.
4777 llvm::Value *Allocator = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
4778 llvm::Value *Args[] = {ThreadID, DepObjAddr, Allocator};
4779
4780 // _kmpc_free(gtid, addr, nullptr);
4781 (void)CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
4782 CGM.getModule(), OMPRTL___kmpc_free),
4783 Args);
4784}
4785
4787 CodeGenFunction &CGF, LValue DepobjLVal, OpenMPDependClauseKind NewDepKind,
4788 SourceLocation Loc) {
4789 ASTContext &C = CGM.getContext();
4790 QualType FlagsTy;
4791 getDependTypes(C, KmpDependInfoTy, FlagsTy);
4792 auto *KmpDependInfoRD = KmpDependInfoTy->castAsRecordDecl();
4793 llvm::Type *LLVMFlagsTy = CGF.ConvertTypeForMem(FlagsTy);
4794 llvm::Value *NumDeps;
4795 LValue Base;
4796 std::tie(NumDeps, Base) = getDepobjElements(CGF, DepobjLVal, Loc);
4797
4798 Address Begin = Base.getAddress();
4799 // Cast from pointer to array type to pointer to single element.
4800 llvm::Value *End = CGF.Builder.CreateGEP(Begin.getElementType(),
4801 Begin.emitRawPointer(CGF), NumDeps);
4802 // The basic structure here is a while-do loop.
4803 llvm::BasicBlock *BodyBB = CGF.createBasicBlock("omp.body");
4804 llvm::BasicBlock *DoneBB = CGF.createBasicBlock("omp.done");
4805 llvm::BasicBlock *EntryBB = CGF.Builder.GetInsertBlock();
4806 CGF.EmitBlock(BodyBB);
4807 llvm::PHINode *ElementPHI =
4808 CGF.Builder.CreatePHI(Begin.getType(), 2, "omp.elementPast");
4809 ElementPHI->addIncoming(Begin.emitRawPointer(CGF), EntryBB);
4810 Begin = Begin.withPointer(ElementPHI, KnownNonNull);
4811 Base = CGF.MakeAddrLValue(Begin, KmpDependInfoTy, Base.getBaseInfo(),
4812 Base.getTBAAInfo());
4813 // deps[i].flags = NewDepKind;
4814 RTLDependenceKindTy DepKind = translateDependencyKind(NewDepKind);
4815 LValue FlagsLVal = CGF.EmitLValueForField(
4816 Base, *std::next(KmpDependInfoRD->field_begin(),
4817 static_cast<unsigned int>(RTLDependInfoFields::Flags)));
4819 llvm::ConstantInt::get(LLVMFlagsTy, static_cast<unsigned int>(DepKind)),
4820 FlagsLVal);
4821
4822 // Shift the address forward by one element.
4823 llvm::Value *ElementNext =
4824 CGF.Builder.CreateConstGEP(Begin, /*Index=*/1, "omp.elementNext")
4825 .emitRawPointer(CGF);
4826 ElementPHI->addIncoming(ElementNext, CGF.Builder.GetInsertBlock());
4827 llvm::Value *IsEmpty =
4828 CGF.Builder.CreateICmpEQ(ElementNext, End, "omp.isempty");
4829 CGF.Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB);
4830 // Done.
4831 CGF.EmitBlock(DoneBB, /*IsFinished=*/true);
4832}
4833
4835 const OMPExecutableDirective &D,
4836 llvm::Function *TaskFunction,
4837 QualType SharedsTy, Address Shareds,
4838 const Expr *IfCond,
4839 const OMPTaskDataTy &Data) {
4840 if (!CGF.HaveInsertPoint())
4841 return;
4842
4844 emitTaskInit(CGF, Loc, D, TaskFunction, SharedsTy, Shareds, Data);
4845 llvm::Value *NewTask = Result.NewTask;
4846 llvm::Function *TaskEntry = Result.TaskEntry;
4847 llvm::Value *NewTaskNewTaskTTy = Result.NewTaskNewTaskTTy;
4848 LValue TDBase = Result.TDBase;
4849 const RecordDecl *KmpTaskTQTyRD = Result.KmpTaskTQTyRD;
4850 // Process list of dependences.
4851 Address DependenciesArray = Address::invalid();
4852 llvm::Value *NumOfElements;
4853 std::tie(NumOfElements, DependenciesArray) =
4854 emitDependClause(CGF, Data.Dependences, Loc);
4855
4856 // NOTE: routine and part_id fields are initialized by __kmpc_omp_task_alloc()
4857 // libcall.
4858 // Build kmp_int32 __kmpc_omp_task_with_deps(ident_t *, kmp_int32 gtid,
4859 // kmp_task_t *new_task, kmp_int32 ndeps, kmp_depend_info_t *dep_list,
4860 // kmp_int32 ndeps_noalias, kmp_depend_info_t *noalias_dep_list) if dependence
4861 // list is not empty
4862 llvm::Value *ThreadID = getThreadID(CGF, Loc);
4863 llvm::Value *UpLoc = emitUpdateLocation(CGF, Loc);
4864 llvm::Value *TaskArgs[] = { UpLoc, ThreadID, NewTask };
4865 llvm::Value *DepTaskArgs[7];
4866 if (!Data.Dependences.empty()) {
4867 DepTaskArgs[0] = UpLoc;
4868 DepTaskArgs[1] = ThreadID;
4869 DepTaskArgs[2] = NewTask;
4870 DepTaskArgs[3] = NumOfElements;
4871 DepTaskArgs[4] = DependenciesArray.emitRawPointer(CGF);
4872 DepTaskArgs[5] = CGF.Builder.getInt32(0);
4873 DepTaskArgs[6] = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
4874 }
4875 auto &&ThenCodeGen = [this, &Data, TDBase, KmpTaskTQTyRD, &TaskArgs,
4876 &DepTaskArgs](CodeGenFunction &CGF, PrePostActionTy &) {
4877 if (!Data.Tied) {
4878 auto PartIdFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTPartId);
4879 LValue PartIdLVal = CGF.EmitLValueForField(TDBase, *PartIdFI);
4880 CGF.EmitStoreOfScalar(CGF.Builder.getInt32(0), PartIdLVal);
4881 }
4882 if (!Data.Dependences.empty()) {
4883 CGF.EmitRuntimeCall(
4884 OMPBuilder.getOrCreateRuntimeFunction(
4885 CGM.getModule(), OMPRTL___kmpc_omp_task_with_deps),
4886 DepTaskArgs);
4887 } else {
4888 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
4889 CGM.getModule(), OMPRTL___kmpc_omp_task),
4890 TaskArgs);
4891 }
4892 // Check if parent region is untied and build return for untied task;
4893 if (auto *Region =
4894 dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo))
4895 Region->emitUntiedSwitch(CGF);
4896 };
4897
4898 llvm::Value *DepWaitTaskArgs[7];
4899 if (!Data.Dependences.empty()) {
4900 DepWaitTaskArgs[0] = UpLoc;
4901 DepWaitTaskArgs[1] = ThreadID;
4902 DepWaitTaskArgs[2] = NumOfElements;
4903 DepWaitTaskArgs[3] = DependenciesArray.emitRawPointer(CGF);
4904 DepWaitTaskArgs[4] = CGF.Builder.getInt32(0);
4905 DepWaitTaskArgs[5] = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
4906 DepWaitTaskArgs[6] =
4907 llvm::ConstantInt::get(CGF.Int32Ty, Data.HasNowaitClause);
4908 }
4909 auto &M = CGM.getModule();
4910 auto &&ElseCodeGen = [this, &M, &TaskArgs, ThreadID, NewTaskNewTaskTTy,
4911 TaskEntry, &Data, &DepWaitTaskArgs,
4912 Loc](CodeGenFunction &CGF, PrePostActionTy &) {
4913 CodeGenFunction::RunCleanupsScope LocalScope(CGF);
4914 // Build void __kmpc_omp_wait_deps(ident_t *, kmp_int32 gtid,
4915 // kmp_int32 ndeps, kmp_depend_info_t *dep_list, kmp_int32
4916 // ndeps_noalias, kmp_depend_info_t *noalias_dep_list); if dependence info
4917 // is specified.
4918 if (!Data.Dependences.empty())
4919 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
4920 M, OMPRTL___kmpc_omp_taskwait_deps_51),
4921 DepWaitTaskArgs);
4922 // Call proxy_task_entry(gtid, new_task);
4923 auto &&CodeGen = [TaskEntry, ThreadID, NewTaskNewTaskTTy,
4924 Loc](CodeGenFunction &CGF, PrePostActionTy &Action) {
4925 Action.Enter(CGF);
4926 llvm::Value *OutlinedFnArgs[] = {ThreadID, NewTaskNewTaskTTy};
4927 CGF.CGM.getOpenMPRuntime().emitOutlinedFunctionCall(CGF, Loc, TaskEntry,
4928 OutlinedFnArgs);
4929 };
4930
4931 // Build void __kmpc_omp_task_begin_if0(ident_t *, kmp_int32 gtid,
4932 // kmp_task_t *new_task);
4933 // Build void __kmpc_omp_task_complete_if0(ident_t *, kmp_int32 gtid,
4934 // kmp_task_t *new_task);
4936 CommonActionTy Action(OMPBuilder.getOrCreateRuntimeFunction(
4937 M, OMPRTL___kmpc_omp_task_begin_if0),
4938 TaskArgs,
4939 OMPBuilder.getOrCreateRuntimeFunction(
4940 M, OMPRTL___kmpc_omp_task_complete_if0),
4941 TaskArgs);
4942 RCG.setAction(Action);
4943 RCG(CGF);
4944 };
4945
4946 if (IfCond) {
4947 emitIfClause(CGF, IfCond, ThenCodeGen, ElseCodeGen);
4948 } else {
4949 RegionCodeGenTy ThenRCG(ThenCodeGen);
4950 ThenRCG(CGF);
4951 }
4952}
4953
4955 const OMPLoopDirective &D,
4956 llvm::Function *TaskFunction,
4957 QualType SharedsTy, Address Shareds,
4958 const Expr *IfCond,
4959 const OMPTaskDataTy &Data) {
4960 if (!CGF.HaveInsertPoint())
4961 return;
4963 emitTaskInit(CGF, Loc, D, TaskFunction, SharedsTy, Shareds, Data);
4964 // NOTE: routine and part_id fields are initialized by __kmpc_omp_task_alloc()
4965 // libcall.
4966 // Call to void __kmpc_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int
4967 // if_val, kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, int nogroup, int
4968 // sched, kmp_uint64 grainsize, void *task_dup);
4969 llvm::Value *ThreadID = getThreadID(CGF, Loc);
4970 llvm::Value *UpLoc = emitUpdateLocation(CGF, Loc);
4971 llvm::Value *IfVal;
4972 if (IfCond) {
4973 IfVal = CGF.Builder.CreateIntCast(CGF.EvaluateExprAsBool(IfCond), CGF.IntTy,
4974 /*isSigned=*/true);
4975 } else {
4976 IfVal = llvm::ConstantInt::getSigned(CGF.IntTy, /*V=*/1);
4977 }
4978
4979 LValue LBLVal = CGF.EmitLValueForField(
4980 Result.TDBase,
4981 *std::next(Result.KmpTaskTQTyRD->field_begin(), KmpTaskTLowerBound));
4982 const auto *LBVar =
4984 CGF.EmitAnyExprToMem(LBVar->getInit(), LBLVal.getAddress(), LBLVal.getQuals(),
4985 /*IsInitializer=*/true);
4986 LValue UBLVal = CGF.EmitLValueForField(
4987 Result.TDBase,
4988 *std::next(Result.KmpTaskTQTyRD->field_begin(), KmpTaskTUpperBound));
4989 const auto *UBVar =
4991 CGF.EmitAnyExprToMem(UBVar->getInit(), UBLVal.getAddress(), UBLVal.getQuals(),
4992 /*IsInitializer=*/true);
4993 LValue StLVal = CGF.EmitLValueForField(
4994 Result.TDBase,
4995 *std::next(Result.KmpTaskTQTyRD->field_begin(), KmpTaskTStride));
4996 const auto *StVar =
4998 CGF.EmitAnyExprToMem(StVar->getInit(), StLVal.getAddress(), StLVal.getQuals(),
4999 /*IsInitializer=*/true);
5000 // Store reductions address.
5001 LValue RedLVal = CGF.EmitLValueForField(
5002 Result.TDBase,
5003 *std::next(Result.KmpTaskTQTyRD->field_begin(), KmpTaskTReductions));
5004 if (Data.Reductions) {
5005 CGF.EmitStoreOfScalar(Data.Reductions, RedLVal);
5006 } else {
5007 CGF.EmitNullInitialization(RedLVal.getAddress(),
5008 CGF.getContext().VoidPtrTy);
5009 }
5010 enum { NoSchedule = 0, Grainsize = 1, NumTasks = 2 };
5012 UpLoc,
5013 ThreadID,
5014 Result.NewTask,
5015 IfVal,
5016 LBLVal.getPointer(CGF),
5017 UBLVal.getPointer(CGF),
5018 CGF.EmitLoadOfScalar(StLVal, Loc),
5019 llvm::ConstantInt::getSigned(
5020 CGF.IntTy, 1), // Always 1 because taskgroup emitted by the compiler
5021 llvm::ConstantInt::getSigned(
5022 CGF.IntTy, Data.Schedule.getPointer()
5023 ? Data.Schedule.getInt() ? NumTasks : Grainsize
5024 : NoSchedule),
5025 Data.Schedule.getPointer()
5026 ? CGF.Builder.CreateIntCast(Data.Schedule.getPointer(), CGF.Int64Ty,
5027 /*isSigned=*/false)
5028 : llvm::ConstantInt::get(CGF.Int64Ty, /*V=*/0)};
5029 if (Data.HasModifier)
5030 TaskArgs.push_back(llvm::ConstantInt::get(CGF.Int32Ty, 1));
5031
5032 TaskArgs.push_back(Result.TaskDupFn
5034 Result.TaskDupFn, CGF.VoidPtrTy)
5035 : llvm::ConstantPointerNull::get(CGF.VoidPtrTy));
5036 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
5037 CGM.getModule(), Data.HasModifier
5038 ? OMPRTL___kmpc_taskloop_5
5039 : OMPRTL___kmpc_taskloop),
5040 TaskArgs);
5041}
5042
5043/// Emit reduction operation for each element of array (required for
5044/// array sections) LHS op = RHS.
5045/// \param Type Type of array.
5046/// \param LHSVar Variable on the left side of the reduction operation
5047/// (references element of array in original variable).
5048/// \param RHSVar Variable on the right side of the reduction operation
5049/// (references element of array in original variable).
5050/// \param RedOpGen Generator of reduction operation with use of LHSVar and
5051/// RHSVar.
5053 CodeGenFunction &CGF, QualType Type, const VarDecl *LHSVar,
5054 const VarDecl *RHSVar,
5055 const llvm::function_ref<void(CodeGenFunction &CGF, const Expr *,
5056 const Expr *, const Expr *)> &RedOpGen,
5057 const Expr *XExpr = nullptr, const Expr *EExpr = nullptr,
5058 const Expr *UpExpr = nullptr) {
5059 // Perform element-by-element initialization.
5060 QualType ElementTy;
5061 Address LHSAddr = CGF.GetAddrOfLocalVar(LHSVar);
5062 Address RHSAddr = CGF.GetAddrOfLocalVar(RHSVar);
5063
5064 // Drill down to the base element type on both arrays.
5065 const ArrayType *ArrayTy = Type->getAsArrayTypeUnsafe();
5066 llvm::Value *NumElements = CGF.emitArrayLength(ArrayTy, ElementTy, LHSAddr);
5067
5068 llvm::Value *RHSBegin = RHSAddr.emitRawPointer(CGF);
5069 llvm::Value *LHSBegin = LHSAddr.emitRawPointer(CGF);
5070 // Cast from pointer to array type to pointer to single element.
5071 llvm::Value *LHSEnd =
5072 CGF.Builder.CreateGEP(LHSAddr.getElementType(), LHSBegin, NumElements);
5073 // The basic structure here is a while-do loop.
5074 llvm::BasicBlock *BodyBB = CGF.createBasicBlock("omp.arraycpy.body");
5075 llvm::BasicBlock *DoneBB = CGF.createBasicBlock("omp.arraycpy.done");
5076 llvm::Value *IsEmpty =
5077 CGF.Builder.CreateICmpEQ(LHSBegin, LHSEnd, "omp.arraycpy.isempty");
5078 CGF.Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB);
5079
5080 // Enter the loop body, making that address the current address.
5081 llvm::BasicBlock *EntryBB = CGF.Builder.GetInsertBlock();
5082 CGF.EmitBlock(BodyBB);
5083
5084 CharUnits ElementSize = CGF.getContext().getTypeSizeInChars(ElementTy);
5085
5086 llvm::PHINode *RHSElementPHI = CGF.Builder.CreatePHI(
5087 RHSBegin->getType(), 2, "omp.arraycpy.srcElementPast");
5088 RHSElementPHI->addIncoming(RHSBegin, EntryBB);
5089 Address RHSElementCurrent(
5090 RHSElementPHI, RHSAddr.getElementType(),
5091 RHSAddr.getAlignment().alignmentOfArrayElement(ElementSize));
5092
5093 llvm::PHINode *LHSElementPHI = CGF.Builder.CreatePHI(
5094 LHSBegin->getType(), 2, "omp.arraycpy.destElementPast");
5095 LHSElementPHI->addIncoming(LHSBegin, EntryBB);
5096 Address LHSElementCurrent(
5097 LHSElementPHI, LHSAddr.getElementType(),
5098 LHSAddr.getAlignment().alignmentOfArrayElement(ElementSize));
5099
5100 // Emit copy.
5102 Scope.addPrivate(LHSVar, LHSElementCurrent);
5103 Scope.addPrivate(RHSVar, RHSElementCurrent);
5104 Scope.Privatize();
5105 RedOpGen(CGF, XExpr, EExpr, UpExpr);
5106 Scope.ForceCleanup();
5107
5108 // Shift the address forward by one element.
5109 llvm::Value *LHSElementNext = CGF.Builder.CreateConstGEP1_32(
5110 LHSAddr.getElementType(), LHSElementPHI, /*Idx0=*/1,
5111 "omp.arraycpy.dest.element");
5112 llvm::Value *RHSElementNext = CGF.Builder.CreateConstGEP1_32(
5113 RHSAddr.getElementType(), RHSElementPHI, /*Idx0=*/1,
5114 "omp.arraycpy.src.element");
5115 // Check whether we've reached the end.
5116 llvm::Value *Done =
5117 CGF.Builder.CreateICmpEQ(LHSElementNext, LHSEnd, "omp.arraycpy.done");
5118 CGF.Builder.CreateCondBr(Done, DoneBB, BodyBB);
5119 LHSElementPHI->addIncoming(LHSElementNext, CGF.Builder.GetInsertBlock());
5120 RHSElementPHI->addIncoming(RHSElementNext, CGF.Builder.GetInsertBlock());
5121
5122 // Done.
5123 CGF.EmitBlock(DoneBB, /*IsFinished=*/true);
5124}
5125
5126/// Emit reduction combiner. If the combiner is a simple expression emit it as
5127/// is, otherwise consider it as combiner of UDR decl and emit it as a call of
5128/// UDR combiner function.
5130 const Expr *ReductionOp) {
5131 if (const auto *CE = dyn_cast<CallExpr>(ReductionOp))
5132 if (const auto *OVE = dyn_cast<OpaqueValueExpr>(CE->getCallee()))
5133 if (const auto *DRE =
5134 dyn_cast<DeclRefExpr>(OVE->getSourceExpr()->IgnoreImpCasts()))
5135 if (const auto *DRD =
5136 dyn_cast<OMPDeclareReductionDecl>(DRE->getDecl())) {
5137 std::pair<llvm::Function *, llvm::Function *> Reduction =
5141 CGF.EmitIgnoredExpr(ReductionOp);
5142 return;
5143 }
5144 CGF.EmitIgnoredExpr(ReductionOp);
5145}
5146
5148 StringRef ReducerName, SourceLocation Loc, llvm::Type *ArgsElemType,
5150 ArrayRef<const Expr *> RHSExprs, ArrayRef<const Expr *> ReductionOps) {
5151 ASTContext &C = CGM.getContext();
5152
5153 // void reduction_func(void *LHSArg, void *RHSArg);
5154 auto *LHSArg =
5155 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
5156 C.VoidPtrTy, ImplicitParamKind::Other);
5157 auto *RHSArg =
5158 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
5159 C.VoidPtrTy, ImplicitParamKind::Other);
5160 FunctionArgList Args{LHSArg, RHSArg};
5161 const auto &CGFI =
5162 CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
5163 std::string Name = getReductionFuncName(ReducerName);
5164 auto *Fn = llvm::Function::Create(CGM.getTypes().GetFunctionType(CGFI),
5165 llvm::GlobalValue::InternalLinkage, Name,
5166 &CGM.getModule());
5167 CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, CGFI);
5168 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
5169 Fn->addFnAttr("sample-profile-suffix-elision-policy", "selected");
5170 Fn->setDoesNotRecurse();
5171 CodeGenFunction CGF(CGM);
5172 CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, CGFI, Args, Loc, Loc);
5173
5174 // Dst = (void*[n])(LHSArg);
5175 // Src = (void*[n])(RHSArg);
5177 CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(LHSArg)),
5178 CGF.Builder.getPtrTy(0)),
5179 ArgsElemType, CGF.getPointerAlign());
5181 CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(RHSArg)),
5182 CGF.Builder.getPtrTy(0)),
5183 ArgsElemType, CGF.getPointerAlign());
5184
5185 // ...
5186 // *(Type<i>*)lhs[i] = RedOp<i>(*(Type<i>*)lhs[i], *(Type<i>*)rhs[i]);
5187 // ...
5189 const auto *IPriv = Privates.begin();
5190 unsigned Idx = 0;
5191 for (unsigned I = 0, E = ReductionOps.size(); I < E; ++I, ++IPriv, ++Idx) {
5192 const auto *RHSVar =
5193 cast<VarDecl>(cast<DeclRefExpr>(RHSExprs[I])->getDecl());
5194 Scope.addPrivate(RHSVar, emitAddrOfVarFromArray(CGF, RHS, Idx, RHSVar));
5195 const auto *LHSVar =
5196 cast<VarDecl>(cast<DeclRefExpr>(LHSExprs[I])->getDecl());
5197 Scope.addPrivate(LHSVar, emitAddrOfVarFromArray(CGF, LHS, Idx, LHSVar));
5198 QualType PrivTy = (*IPriv)->getType();
5199 if (PrivTy->isVariablyModifiedType()) {
5200 // Get array size and emit VLA type.
5201 ++Idx;
5202 Address Elem = CGF.Builder.CreateConstArrayGEP(LHS, Idx);
5203 llvm::Value *Ptr = CGF.Builder.CreateLoad(Elem);
5204 const VariableArrayType *VLA =
5205 CGF.getContext().getAsVariableArrayType(PrivTy);
5206 const auto *OVE = cast<OpaqueValueExpr>(VLA->getSizeExpr());
5208 CGF, OVE, RValue::get(CGF.Builder.CreatePtrToInt(Ptr, CGF.SizeTy)));
5209 CGF.EmitVariablyModifiedType(PrivTy);
5210 }
5211 }
5212 Scope.Privatize();
5213 IPriv = Privates.begin();
5214 const auto *ILHS = LHSExprs.begin();
5215 const auto *IRHS = RHSExprs.begin();
5216 for (const Expr *E : ReductionOps) {
5217 if ((*IPriv)->getType()->isArrayType()) {
5218 // Emit reduction for array section.
5219 const auto *LHSVar = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
5220 const auto *RHSVar = cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
5222 CGF, (*IPriv)->getType(), LHSVar, RHSVar,
5223 [=](CodeGenFunction &CGF, const Expr *, const Expr *, const Expr *) {
5224 emitReductionCombiner(CGF, E);
5225 });
5226 } else {
5227 // Emit reduction for array subscript or single variable.
5228 emitReductionCombiner(CGF, E);
5229 }
5230 ++IPriv;
5231 ++ILHS;
5232 ++IRHS;
5233 }
5234 Scope.ForceCleanup();
5235 CGF.FinishFunction();
5236 return Fn;
5237}
5238
5240 const Expr *ReductionOp,
5241 const Expr *PrivateRef,
5242 const DeclRefExpr *LHS,
5243 const DeclRefExpr *RHS) {
5244 if (PrivateRef->getType()->isArrayType()) {
5245 // Emit reduction for array section.
5246 const auto *LHSVar = cast<VarDecl>(LHS->getDecl());
5247 const auto *RHSVar = cast<VarDecl>(RHS->getDecl());
5249 CGF, PrivateRef->getType(), LHSVar, RHSVar,
5250 [=](CodeGenFunction &CGF, const Expr *, const Expr *, const Expr *) {
5251 emitReductionCombiner(CGF, ReductionOp);
5252 });
5253 } else {
5254 // Emit reduction for array subscript or single variable.
5255 emitReductionCombiner(CGF, ReductionOp);
5256 }
5257}
5258
5259static std::string generateUniqueName(CodeGenModule &CGM,
5260 llvm::StringRef Prefix, const Expr *Ref);
5261
5263 CodeGenFunction &CGF, SourceLocation Loc, const Expr *Privates,
5264 const Expr *LHSExprs, const Expr *RHSExprs, const Expr *ReductionOps) {
5265
5266 // Create a shared global variable (__shared_reduction_var) to accumulate the
5267 // final result.
5268 //
5269 // Call __kmpc_barrier to synchronize threads before initialization.
5270 //
5271 // The master thread (thread_id == 0) initializes __shared_reduction_var
5272 // with the identity value or initializer.
5273 //
5274 // Call __kmpc_barrier to synchronize before combining.
5275 // For each i:
5276 // - Thread enters critical section.
5277 // - Reads its private value from LHSExprs[i].
5278 // - Updates __shared_reduction_var[i] = RedOp_i(__shared_reduction_var[i],
5279 // Privates[i]).
5280 // - Exits critical section.
5281 //
5282 // Call __kmpc_barrier after combining.
5283 //
5284 // Each thread copies __shared_reduction_var[i] back to RHSExprs[i].
5285 //
5286 // Final __kmpc_barrier to synchronize after broadcasting
5287 QualType PrivateType = Privates->getType();
5288 llvm::Type *LLVMType = CGF.ConvertTypeForMem(PrivateType);
5289
5290 const OMPDeclareReductionDecl *UDR = getReductionInit(ReductionOps);
5291 std::string ReductionVarNameStr;
5292 if (const auto *DRE = dyn_cast<DeclRefExpr>(Privates->IgnoreParenCasts()))
5293 ReductionVarNameStr =
5294 generateUniqueName(CGM, DRE->getDecl()->getNameAsString(), Privates);
5295 else
5296 ReductionVarNameStr = "unnamed_priv_var";
5297
5298 // Create an internal shared variable
5299 std::string SharedName =
5300 CGM.getOpenMPRuntime().getName({"internal_pivate_", ReductionVarNameStr});
5301 llvm::GlobalVariable *SharedVar = OMPBuilder.getOrCreateInternalVariable(
5302 LLVMType, ".omp.reduction." + SharedName);
5303
5304 SharedVar->setAlignment(
5305 llvm::MaybeAlign(CGF.getContext().getTypeAlign(PrivateType) / 8));
5306
5307 Address SharedResult =
5308 CGF.MakeNaturalAlignRawAddrLValue(SharedVar, PrivateType).getAddress();
5309
5310 llvm::Value *ThreadId = getThreadID(CGF, Loc);
5311 llvm::Value *BarrierLoc = emitUpdateLocation(CGF, Loc, OMP_ATOMIC_REDUCE);
5312 llvm::Value *BarrierArgs[] = {BarrierLoc, ThreadId};
5313
5314 llvm::BasicBlock *InitBB = CGF.createBasicBlock("init");
5315 llvm::BasicBlock *InitEndBB = CGF.createBasicBlock("init.end");
5316
5317 llvm::Value *IsWorker = CGF.Builder.CreateICmpEQ(
5318 ThreadId, llvm::ConstantInt::get(ThreadId->getType(), 0));
5319 CGF.Builder.CreateCondBr(IsWorker, InitBB, InitEndBB);
5320
5321 CGF.EmitBlock(InitBB);
5322
5323 auto EmitSharedInit = [&]() {
5324 if (UDR) { // Check if it's a User-Defined Reduction
5325 if (const Expr *UDRInitExpr = UDR->getInitializer()) {
5326 std::pair<llvm::Function *, llvm::Function *> FnPair =
5328 llvm::Function *InitializerFn = FnPair.second;
5329 if (InitializerFn) {
5330 if (const auto *CE =
5331 dyn_cast<CallExpr>(UDRInitExpr->IgnoreParenImpCasts())) {
5332 const auto *OutDRE = cast<DeclRefExpr>(
5333 cast<UnaryOperator>(CE->getArg(0)->IgnoreParenImpCasts())
5334 ->getSubExpr());
5335 const VarDecl *OutVD = cast<VarDecl>(OutDRE->getDecl());
5336
5337 CodeGenFunction::OMPPrivateScope LocalScope(CGF);
5338 LocalScope.addPrivate(OutVD, SharedResult);
5339
5340 (void)LocalScope.Privatize();
5341 if (const auto *OVE = dyn_cast<OpaqueValueExpr>(
5342 CE->getCallee()->IgnoreParenImpCasts())) {
5344 CGF, OVE, RValue::get(InitializerFn));
5345 CGF.EmitIgnoredExpr(CE);
5346 } else {
5347 CGF.EmitAnyExprToMem(UDRInitExpr, SharedResult,
5348 PrivateType.getQualifiers(),
5349 /*IsInitializer=*/true);
5350 }
5351 } else {
5352 CGF.EmitAnyExprToMem(UDRInitExpr, SharedResult,
5353 PrivateType.getQualifiers(),
5354 /*IsInitializer=*/true);
5355 }
5356 } else {
5357 CGF.EmitAnyExprToMem(UDRInitExpr, SharedResult,
5358 PrivateType.getQualifiers(),
5359 /*IsInitializer=*/true);
5360 }
5361 } else {
5362 // EmitNullInitialization handles default construction for C++ classes
5363 // and zeroing for scalars, which is a reasonable default.
5364 CGF.EmitNullInitialization(SharedResult, PrivateType);
5365 }
5366 return; // UDR initialization handled
5367 }
5368 if (const auto *DRE = dyn_cast<DeclRefExpr>(Privates)) {
5369 if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
5370 if (const Expr *InitExpr = VD->getInit()) {
5371 CGF.EmitAnyExprToMem(InitExpr, SharedResult,
5372 PrivateType.getQualifiers(), true);
5373 return;
5374 }
5375 }
5376 }
5377 CGF.EmitNullInitialization(SharedResult, PrivateType);
5378 };
5379 EmitSharedInit();
5380 CGF.Builder.CreateBr(InitEndBB);
5381 CGF.EmitBlock(InitEndBB);
5382
5383 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
5384 CGM.getModule(), OMPRTL___kmpc_barrier),
5385 BarrierArgs);
5386
5387 const Expr *ReductionOp = ReductionOps;
5388 const OMPDeclareReductionDecl *CurrentUDR = getReductionInit(ReductionOp);
5389 LValue SharedLV = CGF.MakeAddrLValue(SharedResult, PrivateType);
5390 LValue LHSLV = CGF.EmitLValue(Privates);
5391
5392 auto EmitCriticalReduction = [&](auto ReductionGen) {
5393 std::string CriticalName = getName({"reduction_critical"});
5394 emitCriticalRegion(CGF, CriticalName, ReductionGen, Loc);
5395 };
5396
5397 if (CurrentUDR) {
5398 // Handle user-defined reduction.
5399 auto ReductionGen = [&](CodeGenFunction &CGF, PrePostActionTy &Action) {
5400 Action.Enter(CGF);
5401 std::pair<llvm::Function *, llvm::Function *> FnPair =
5402 getUserDefinedReduction(CurrentUDR);
5403 if (FnPair.first) {
5404 if (const auto *CE = dyn_cast<CallExpr>(ReductionOp)) {
5405 const auto *OutDRE = cast<DeclRefExpr>(
5406 cast<UnaryOperator>(CE->getArg(0)->IgnoreParenImpCasts())
5407 ->getSubExpr());
5408 const auto *InDRE = cast<DeclRefExpr>(
5409 cast<UnaryOperator>(CE->getArg(1)->IgnoreParenImpCasts())
5410 ->getSubExpr());
5411 CodeGenFunction::OMPPrivateScope LocalScope(CGF);
5412 LocalScope.addPrivate(cast<VarDecl>(OutDRE->getDecl()),
5413 SharedLV.getAddress());
5414 LocalScope.addPrivate(cast<VarDecl>(InDRE->getDecl()),
5415 LHSLV.getAddress());
5416 (void)LocalScope.Privatize();
5417 emitReductionCombiner(CGF, ReductionOp);
5418 }
5419 }
5420 };
5421 EmitCriticalReduction(ReductionGen);
5422 } else {
5423 // Handle built-in reduction operations.
5424#ifndef NDEBUG
5425 const Expr *ReductionClauseExpr = ReductionOp->IgnoreParenCasts();
5426 if (const auto *Cleanup = dyn_cast<ExprWithCleanups>(ReductionClauseExpr))
5427 ReductionClauseExpr = Cleanup->getSubExpr()->IgnoreParenCasts();
5428
5429 const Expr *AssignRHS = nullptr;
5430 if (const auto *BinOp = dyn_cast<BinaryOperator>(ReductionClauseExpr)) {
5431 if (BinOp->getOpcode() == BO_Assign)
5432 AssignRHS = BinOp->getRHS();
5433 } else if (const auto *OpCall =
5434 dyn_cast<CXXOperatorCallExpr>(ReductionClauseExpr)) {
5435 if (OpCall->getOperator() == OO_Equal)
5436 AssignRHS = OpCall->getArg(1);
5437 }
5438
5439 assert(AssignRHS &&
5440 "Private Variable Reduction : Invalid ReductionOp expression");
5441#endif
5442
5443 auto ReductionGen = [&](CodeGenFunction &CGF, PrePostActionTy &Action) {
5444 Action.Enter(CGF);
5445 const auto *OmpOutDRE =
5446 dyn_cast<DeclRefExpr>(LHSExprs->IgnoreParenImpCasts());
5447 const auto *OmpInDRE =
5448 dyn_cast<DeclRefExpr>(RHSExprs->IgnoreParenImpCasts());
5449 assert(
5450 OmpOutDRE && OmpInDRE &&
5451 "Private Variable Reduction : LHSExpr/RHSExpr must be DeclRefExprs");
5452 const VarDecl *OmpOutVD = cast<VarDecl>(OmpOutDRE->getDecl());
5453 const VarDecl *OmpInVD = cast<VarDecl>(OmpInDRE->getDecl());
5454 CodeGenFunction::OMPPrivateScope LocalScope(CGF);
5455 LocalScope.addPrivate(OmpOutVD, SharedLV.getAddress());
5456 LocalScope.addPrivate(OmpInVD, LHSLV.getAddress());
5457 (void)LocalScope.Privatize();
5458 // Emit the actual reduction operation
5459 CGF.EmitIgnoredExpr(ReductionOp);
5460 };
5461 EmitCriticalReduction(ReductionGen);
5462 }
5463
5464 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
5465 CGM.getModule(), OMPRTL___kmpc_barrier),
5466 BarrierArgs);
5467
5468 // Broadcast final result
5469 bool IsAggregate = PrivateType->isAggregateType();
5470 LValue SharedLV1 = CGF.MakeAddrLValue(SharedResult, PrivateType);
5471 llvm::Value *FinalResultVal = nullptr;
5472 Address FinalResultAddr = Address::invalid();
5473
5474 if (IsAggregate)
5475 FinalResultAddr = SharedResult;
5476 else
5477 FinalResultVal = CGF.EmitLoadOfScalar(SharedLV1, Loc);
5478
5479 LValue TargetLHSLV = CGF.EmitLValue(RHSExprs);
5480 if (IsAggregate) {
5481 CGF.EmitAggregateCopy(TargetLHSLV,
5482 CGF.MakeAddrLValue(FinalResultAddr, PrivateType),
5483 PrivateType, AggValueSlot::DoesNotOverlap, false);
5484 } else {
5485 CGF.EmitStoreOfScalar(FinalResultVal, TargetLHSLV);
5486 }
5487 // Final synchronization barrier
5488 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
5489 CGM.getModule(), OMPRTL___kmpc_barrier),
5490 BarrierArgs);
5491
5492 // Combiner with original list item
5493 auto OriginalListCombiner = [&](CodeGenFunction &CGF,
5494 PrePostActionTy &Action) {
5495 Action.Enter(CGF);
5496 emitSingleReductionCombiner(CGF, ReductionOps, Privates,
5497 cast<DeclRefExpr>(LHSExprs),
5498 cast<DeclRefExpr>(RHSExprs));
5499 };
5500 EmitCriticalReduction(OriginalListCombiner);
5501}
5502
5504 ArrayRef<const Expr *> OrgPrivates,
5505 ArrayRef<const Expr *> OrgLHSExprs,
5506 ArrayRef<const Expr *> OrgRHSExprs,
5507 ArrayRef<const Expr *> OrgReductionOps,
5508 ReductionOptionsTy Options) {
5509 if (!CGF.HaveInsertPoint())
5510 return;
5511
5512 bool WithNowait = Options.WithNowait;
5513 bool SimpleReduction = Options.SimpleReduction;
5514
5515 // Next code should be emitted for reduction:
5516 //
5517 // static kmp_critical_name lock = { 0 };
5518 //
5519 // void reduce_func(void *lhs[<n>], void *rhs[<n>]) {
5520 // *(Type0*)lhs[0] = ReductionOperation0(*(Type0*)lhs[0], *(Type0*)rhs[0]);
5521 // ...
5522 // *(Type<n>-1*)lhs[<n>-1] = ReductionOperation<n>-1(*(Type<n>-1*)lhs[<n>-1],
5523 // *(Type<n>-1*)rhs[<n>-1]);
5524 // }
5525 //
5526 // ...
5527 // void *RedList[<n>] = {&<RHSExprs>[0], ..., &<RHSExprs>[<n>-1]};
5528 // switch (__kmpc_reduce{_nowait}(<loc>, <gtid>, <n>, sizeof(RedList),
5529 // RedList, reduce_func, &<lock>)) {
5530 // case 1:
5531 // ...
5532 // <LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]);
5533 // ...
5534 // __kmpc_end_reduce{_nowait}(<loc>, <gtid>, &<lock>);
5535 // break;
5536 // case 2:
5537 // ...
5538 // Atomic(<LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]));
5539 // ...
5540 // [__kmpc_end_reduce(<loc>, <gtid>, &<lock>);]
5541 // break;
5542 // default:;
5543 // }
5544 //
5545 // if SimpleReduction is true, only the next code is generated:
5546 // ...
5547 // <LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]);
5548 // ...
5549
5550 ASTContext &C = CGM.getContext();
5551
5552 if (SimpleReduction) {
5554 const auto *IPriv = OrgPrivates.begin();
5555 const auto *ILHS = OrgLHSExprs.begin();
5556 const auto *IRHS = OrgRHSExprs.begin();
5557 for (const Expr *E : OrgReductionOps) {
5558 emitSingleReductionCombiner(CGF, E, *IPriv, cast<DeclRefExpr>(*ILHS),
5559 cast<DeclRefExpr>(*IRHS));
5560 ++IPriv;
5561 ++ILHS;
5562 ++IRHS;
5563 }
5564 return;
5565 }
5566
5567 // Filter out shared reduction variables based on IsPrivateVarReduction flag.
5568 // Only keep entries where the corresponding variable is not private.
5569 SmallVector<const Expr *> FilteredPrivates, FilteredLHSExprs,
5570 FilteredRHSExprs, FilteredReductionOps;
5571 for (unsigned I : llvm::seq<unsigned>(
5572 std::min(OrgReductionOps.size(), OrgLHSExprs.size()))) {
5573 if (!Options.IsPrivateVarReduction[I]) {
5574 FilteredPrivates.emplace_back(OrgPrivates[I]);
5575 FilteredLHSExprs.emplace_back(OrgLHSExprs[I]);
5576 FilteredRHSExprs.emplace_back(OrgRHSExprs[I]);
5577 FilteredReductionOps.emplace_back(OrgReductionOps[I]);
5578 }
5579 }
5580 // Wrap filtered vectors in ArrayRef for downstream shared reduction
5581 // processing.
5582 ArrayRef<const Expr *> Privates = FilteredPrivates;
5583 ArrayRef<const Expr *> LHSExprs = FilteredLHSExprs;
5584 ArrayRef<const Expr *> RHSExprs = FilteredRHSExprs;
5585 ArrayRef<const Expr *> ReductionOps = FilteredReductionOps;
5586
5587 // 1. Build a list of reduction variables.
5588 // void *RedList[<n>] = {<ReductionVars>[0], ..., <ReductionVars>[<n>-1]};
5589 auto Size = RHSExprs.size();
5590 for (const Expr *E : Privates) {
5591 if (E->getType()->isVariablyModifiedType())
5592 // Reserve place for array size.
5593 ++Size;
5594 }
5595 llvm::APInt ArraySize(/*unsigned int numBits=*/32, Size);
5596 QualType ReductionArrayTy = C.getConstantArrayType(
5597 C.VoidPtrTy, ArraySize, nullptr, ArraySizeModifier::Normal,
5598 /*IndexTypeQuals=*/0);
5599 RawAddress ReductionList =
5600 CGF.CreateMemTemp(ReductionArrayTy, ".omp.reduction.red_list");
5601 const auto *IPriv = Privates.begin();
5602 unsigned Idx = 0;
5603 for (unsigned I = 0, E = RHSExprs.size(); I < E; ++I, ++IPriv, ++Idx) {
5604 Address Elem = CGF.Builder.CreateConstArrayGEP(ReductionList, Idx);
5605 CGF.Builder.CreateStore(
5607 CGF.EmitLValue(RHSExprs[I]).getPointer(CGF), CGF.VoidPtrTy),
5608 Elem);
5609 if ((*IPriv)->getType()->isVariablyModifiedType()) {
5610 // Store array size.
5611 ++Idx;
5612 Elem = CGF.Builder.CreateConstArrayGEP(ReductionList, Idx);
5613 llvm::Value *Size = CGF.Builder.CreateIntCast(
5614 CGF.getVLASize(
5615 CGF.getContext().getAsVariableArrayType((*IPriv)->getType()))
5616 .NumElts,
5617 CGF.SizeTy, /*isSigned=*/false);
5618 CGF.Builder.CreateStore(CGF.Builder.CreateIntToPtr(Size, CGF.VoidPtrTy),
5619 Elem);
5620 }
5621 }
5622
5623 // 2. Emit reduce_func().
5624 llvm::Function *ReductionFn = emitReductionFunction(
5625 CGF.CurFn->getName(), Loc, CGF.ConvertTypeForMem(ReductionArrayTy),
5626 Privates, LHSExprs, RHSExprs, ReductionOps);
5627
5628 // 3. Create static kmp_critical_name lock = { 0 };
5629 std::string Name = getName({"reduction"});
5630 llvm::Value *Lock = getCriticalRegionLock(Name);
5631
5632 // 4. Build res = __kmpc_reduce{_nowait}(<loc>, <gtid>, <n>, sizeof(RedList),
5633 // RedList, reduce_func, &<lock>);
5634 llvm::Value *IdentTLoc = emitUpdateLocation(CGF, Loc, OMP_ATOMIC_REDUCE);
5635 llvm::Value *ThreadId = getThreadID(CGF, Loc);
5636 llvm::Value *ReductionArrayTySize = CGF.getTypeSize(ReductionArrayTy);
5637 llvm::Value *RL = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
5638 ReductionList.getPointer(), CGF.VoidPtrTy);
5639 llvm::Value *Args[] = {
5640 IdentTLoc, // ident_t *<loc>
5641 ThreadId, // i32 <gtid>
5642 CGF.Builder.getInt32(RHSExprs.size()), // i32 <n>
5643 ReductionArrayTySize, // size_type sizeof(RedList)
5644 RL, // void *RedList
5645 ReductionFn, // void (*) (void *, void *) <reduce_func>
5646 Lock // kmp_critical_name *&<lock>
5647 };
5648 llvm::Value *Res = CGF.EmitRuntimeCall(
5649 OMPBuilder.getOrCreateRuntimeFunction(
5650 CGM.getModule(),
5651 WithNowait ? OMPRTL___kmpc_reduce_nowait : OMPRTL___kmpc_reduce),
5652 Args);
5653
5654 // 5. Build switch(res)
5655 llvm::BasicBlock *DefaultBB = CGF.createBasicBlock(".omp.reduction.default");
5656 llvm::SwitchInst *SwInst =
5657 CGF.Builder.CreateSwitch(Res, DefaultBB, /*NumCases=*/2);
5658
5659 // 6. Build case 1:
5660 // ...
5661 // <LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]);
5662 // ...
5663 // __kmpc_end_reduce{_nowait}(<loc>, <gtid>, &<lock>);
5664 // break;
5665 llvm::BasicBlock *Case1BB = CGF.createBasicBlock(".omp.reduction.case1");
5666 SwInst->addCase(CGF.Builder.getInt32(1), Case1BB);
5667 CGF.EmitBlock(Case1BB);
5668
5669 // Add emission of __kmpc_end_reduce{_nowait}(<loc>, <gtid>, &<lock>);
5670 llvm::Value *EndArgs[] = {
5671 IdentTLoc, // ident_t *<loc>
5672 ThreadId, // i32 <gtid>
5673 Lock // kmp_critical_name *&<lock>
5674 };
5675 auto &&CodeGen = [Privates, LHSExprs, RHSExprs, ReductionOps](
5676 CodeGenFunction &CGF, PrePostActionTy &Action) {
5678 const auto *IPriv = Privates.begin();
5679 const auto *ILHS = LHSExprs.begin();
5680 const auto *IRHS = RHSExprs.begin();
5681 for (const Expr *E : ReductionOps) {
5682 RT.emitSingleReductionCombiner(CGF, E, *IPriv, cast<DeclRefExpr>(*ILHS),
5683 cast<DeclRefExpr>(*IRHS));
5684 ++IPriv;
5685 ++ILHS;
5686 ++IRHS;
5687 }
5688 };
5690 CommonActionTy Action(
5691 nullptr, {},
5692 OMPBuilder.getOrCreateRuntimeFunction(
5693 CGM.getModule(), WithNowait ? OMPRTL___kmpc_end_reduce_nowait
5694 : OMPRTL___kmpc_end_reduce),
5695 EndArgs);
5696 RCG.setAction(Action);
5697 RCG(CGF);
5698
5699 CGF.EmitBranch(DefaultBB);
5700
5701 // 7. Build case 2:
5702 // ...
5703 // Atomic(<LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]));
5704 // ...
5705 // break;
5706 llvm::BasicBlock *Case2BB = CGF.createBasicBlock(".omp.reduction.case2");
5707 SwInst->addCase(CGF.Builder.getInt32(2), Case2BB);
5708 CGF.EmitBlock(Case2BB);
5709
5710 auto &&AtomicCodeGen = [Loc, Privates, LHSExprs, RHSExprs, ReductionOps](
5711 CodeGenFunction &CGF, PrePostActionTy &Action) {
5712 const auto *ILHS = LHSExprs.begin();
5713 const auto *IRHS = RHSExprs.begin();
5714 const auto *IPriv = Privates.begin();
5715 for (const Expr *E : ReductionOps) {
5716 const Expr *XExpr = nullptr;
5717 const Expr *EExpr = nullptr;
5718 const Expr *UpExpr = nullptr;
5719 BinaryOperatorKind BO = BO_Comma;
5720 if (const auto *BO = dyn_cast<BinaryOperator>(E)) {
5721 if (BO->getOpcode() == BO_Assign) {
5722 XExpr = BO->getLHS();
5723 UpExpr = BO->getRHS();
5724 }
5725 }
5726 // Try to emit update expression as a simple atomic.
5727 const Expr *RHSExpr = UpExpr;
5728 if (RHSExpr) {
5729 // Analyze RHS part of the whole expression.
5730 if (const auto *ACO = dyn_cast<AbstractConditionalOperator>(
5731 RHSExpr->IgnoreParenImpCasts())) {
5732 // If this is a conditional operator, analyze its condition for
5733 // min/max reduction operator.
5734 RHSExpr = ACO->getCond();
5735 }
5736 if (const auto *BORHS =
5737 dyn_cast<BinaryOperator>(RHSExpr->IgnoreParenImpCasts())) {
5738 EExpr = BORHS->getRHS();
5739 BO = BORHS->getOpcode();
5740 }
5741 }
5742 if (XExpr) {
5743 const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
5744 auto &&AtomicRedGen = [BO, VD,
5745 Loc](CodeGenFunction &CGF, const Expr *XExpr,
5746 const Expr *EExpr, const Expr *UpExpr) {
5747 LValue X = CGF.EmitLValue(XExpr);
5748 RValue E;
5749 if (EExpr)
5750 E = CGF.EmitAnyExpr(EExpr);
5751 CGF.EmitOMPAtomicSimpleUpdateExpr(
5752 X, E, BO, /*IsXLHSInRHSPart=*/true,
5753 llvm::AtomicOrdering::Monotonic, Loc,
5754 [&CGF, UpExpr, VD, Loc](RValue XRValue) {
5755 CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
5756 Address LHSTemp = CGF.CreateMemTemp(VD->getType());
5757 CGF.emitOMPSimpleStore(
5758 CGF.MakeAddrLValue(LHSTemp, VD->getType()), XRValue,
5759 VD->getType().getNonReferenceType(), Loc);
5760 PrivateScope.addPrivate(VD, LHSTemp);
5761 (void)PrivateScope.Privatize();
5762 return CGF.EmitAnyExpr(UpExpr);
5763 });
5764 };
5765 if ((*IPriv)->getType()->isArrayType()) {
5766 // Emit atomic reduction for array section.
5767 const auto *RHSVar =
5768 cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
5769 EmitOMPAggregateReduction(CGF, (*IPriv)->getType(), VD, RHSVar,
5770 AtomicRedGen, XExpr, EExpr, UpExpr);
5771 } else {
5772 // Emit atomic reduction for array subscript or single variable.
5773 AtomicRedGen(CGF, XExpr, EExpr, UpExpr);
5774 }
5775 } else {
5776 // Emit as a critical region.
5777 auto &&CritRedGen = [E, Loc](CodeGenFunction &CGF, const Expr *,
5778 const Expr *, const Expr *) {
5779 CGOpenMPRuntime &RT = CGF.CGM.getOpenMPRuntime();
5780 std::string Name = RT.getName({"atomic_reduction"});
5782 CGF, Name,
5783 [=](CodeGenFunction &CGF, PrePostActionTy &Action) {
5784 Action.Enter(CGF);
5785 emitReductionCombiner(CGF, E);
5786 },
5787 Loc);
5788 };
5789 if ((*IPriv)->getType()->isArrayType()) {
5790 const auto *LHSVar =
5791 cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
5792 const auto *RHSVar =
5793 cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
5794 EmitOMPAggregateReduction(CGF, (*IPriv)->getType(), LHSVar, RHSVar,
5795 CritRedGen);
5796 } else {
5797 CritRedGen(CGF, nullptr, nullptr, nullptr);
5798 }
5799 }
5800 ++ILHS;
5801 ++IRHS;
5802 ++IPriv;
5803 }
5804 };
5805 RegionCodeGenTy AtomicRCG(AtomicCodeGen);
5806 if (!WithNowait) {
5807 // Add emission of __kmpc_end_reduce(<loc>, <gtid>, &<lock>);
5808 llvm::Value *EndArgs[] = {
5809 IdentTLoc, // ident_t *<loc>
5810 ThreadId, // i32 <gtid>
5811 Lock // kmp_critical_name *&<lock>
5812 };
5813 CommonActionTy Action(nullptr, {},
5814 OMPBuilder.getOrCreateRuntimeFunction(
5815 CGM.getModule(), OMPRTL___kmpc_end_reduce),
5816 EndArgs);
5817 AtomicRCG.setAction(Action);
5818 AtomicRCG(CGF);
5819 } else {
5820 AtomicRCG(CGF);
5821 }
5822
5823 CGF.EmitBranch(DefaultBB);
5824 CGF.EmitBlock(DefaultBB, /*IsFinished=*/true);
5825 assert(OrgLHSExprs.size() == OrgPrivates.size() &&
5826 "PrivateVarReduction: Privates size mismatch");
5827 assert(OrgLHSExprs.size() == OrgReductionOps.size() &&
5828 "PrivateVarReduction: ReductionOps size mismatch");
5829 for (unsigned I : llvm::seq<unsigned>(
5830 std::min(OrgReductionOps.size(), OrgLHSExprs.size()))) {
5831 if (Options.IsPrivateVarReduction[I])
5832 emitPrivateReduction(CGF, Loc, OrgPrivates[I], OrgLHSExprs[I],
5833 OrgRHSExprs[I], OrgReductionOps[I]);
5834 }
5835}
5836
5837/// Generates unique name for artificial threadprivate variables.
5838/// Format is: <Prefix> "." <Decl_mangled_name> "_" "<Decl_start_loc_raw_enc>"
5839static std::string generateUniqueName(CodeGenModule &CGM, StringRef Prefix,
5840 const Expr *Ref) {
5841 SmallString<256> Buffer;
5842 llvm::raw_svector_ostream Out(Buffer);
5843 const clang::DeclRefExpr *DE;
5844 const VarDecl *D = ::getBaseDecl(Ref, DE);
5845 if (!D) {
5846 auto *DRE = cast<DeclRefExpr>(Ref);
5847 if (const auto *BD = dyn_cast<BindingDecl>(DRE->getDecl())) {
5848 // For BindingDecls, use the decomposed declaration as the base.
5849 D = cast<VarDecl>(BD->getDecomposedDecl());
5850 } else {
5851 D = cast<VarDecl>(DRE->getDecl());
5852 }
5853 }
5854 D = D->getCanonicalDecl();
5855 std::string Name = CGM.getOpenMPRuntime().getName(
5856 {D->isLocalVarDeclOrParm() ? D->getName() : CGM.getMangledName(D)});
5857 Out << Prefix << Name << "_"
5859 return std::string(Out.str());
5860}
5861
5862/// Emits reduction initializer function:
5863/// \code
5864/// void @.red_init(void* %arg, void* %orig) {
5865/// %0 = bitcast void* %arg to <type>*
5866/// store <type> <init>, <type>* %0
5867/// ret void
5868/// }
5869/// \endcode
5870static llvm::Value *emitReduceInitFunction(CodeGenModule &CGM,
5871 SourceLocation Loc,
5872 ReductionCodeGen &RCG, unsigned N) {
5873 ASTContext &C = CGM.getContext();
5874 QualType VoidPtrTy = C.VoidPtrTy;
5875 VoidPtrTy.addRestrict();
5876 FunctionArgList Args;
5877 auto *Param =
5878 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
5879 VoidPtrTy, ImplicitParamKind::Other);
5880 auto *ParamOrig =
5881 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
5882 VoidPtrTy, ImplicitParamKind::Other);
5883 Args.emplace_back(Param);
5884 Args.emplace_back(ParamOrig);
5885 const auto &FnInfo =
5886 CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
5887 llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
5888 std::string Name = CGM.getOpenMPRuntime().getName({"red_init", ""});
5889 auto *Fn = llvm::Function::Create(FnTy, llvm::GlobalValue::InternalLinkage,
5890 Name, &CGM.getModule());
5891 CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FnInfo);
5892 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
5893 Fn->addFnAttr("sample-profile-suffix-elision-policy", "selected");
5894 Fn->setDoesNotRecurse();
5895 CodeGenFunction CGF(CGM);
5896 CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, FnInfo, Args, Loc, Loc);
5897 QualType PrivateType = RCG.getPrivateType(N);
5898 Address PrivateAddr = CGF.EmitLoadOfPointer(
5899 CGF.GetAddrOfLocalVar(Param).withElementType(CGF.Builder.getPtrTy(0)),
5900 C.getPointerType(PrivateType)->castAs<PointerType>());
5901 llvm::Value *Size = nullptr;
5902 // If the size of the reduction item is non-constant, load it from global
5903 // threadprivate variable.
5904 if (RCG.getSizes(N).second) {
5906 CGF, CGM.getContext().getSizeType(),
5907 generateUniqueName(CGM, "reduction_size", RCG.getRefExpr(N)));
5908 Size = CGF.EmitLoadOfScalar(SizeAddr, /*Volatile=*/false,
5909 CGM.getContext().getSizeType(), Loc);
5910 }
5911 RCG.emitAggregateType(CGF, N, Size);
5912 Address OrigAddr = Address::invalid();
5913 // If initializer uses initializer from declare reduction construct, emit a
5914 // pointer to the address of the original reduction item (reuired by reduction
5915 // initializer)
5916 if (RCG.usesReductionInitializer(N)) {
5917 Address SharedAddr = CGF.GetAddrOfLocalVar(ParamOrig);
5918 OrigAddr = CGF.EmitLoadOfPointer(
5919 SharedAddr,
5920 CGM.getContext().VoidPtrTy.castAs<PointerType>()->getTypePtr());
5921 }
5922 // Emit the initializer:
5923 // %0 = bitcast void* %arg to <type>*
5924 // store <type> <init>, <type>* %0
5925 RCG.emitInitialization(CGF, N, PrivateAddr, OrigAddr,
5926 [](CodeGenFunction &) { return false; });
5927 CGF.FinishFunction();
5928 return Fn;
5929}
5930
5931/// Emits reduction combiner function:
5932/// \code
5933/// void @.red_comb(void* %arg0, void* %arg1) {
5934/// %lhs = bitcast void* %arg0 to <type>*
5935/// %rhs = bitcast void* %arg1 to <type>*
5936/// %2 = <ReductionOp>(<type>* %lhs, <type>* %rhs)
5937/// store <type> %2, <type>* %lhs
5938/// ret void
5939/// }
5940/// \endcode
5941static llvm::Value *emitReduceCombFunction(CodeGenModule &CGM,
5942 SourceLocation Loc,
5943 ReductionCodeGen &RCG, unsigned N,
5944 const Expr *ReductionOp,
5945 const Expr *LHS, const Expr *RHS,
5946 const Expr *PrivateRef) {
5947 ASTContext &C = CGM.getContext();
5948 const auto *LHSVD = cast<VarDecl>(cast<DeclRefExpr>(LHS)->getDecl());
5949 const auto *RHSVD = cast<VarDecl>(cast<DeclRefExpr>(RHS)->getDecl());
5950 FunctionArgList Args;
5951 auto *ParamInOut =
5952 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
5953 C.VoidPtrTy, ImplicitParamKind::Other);
5954 auto *ParamIn =
5955 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
5956 C.VoidPtrTy, ImplicitParamKind::Other);
5957 Args.emplace_back(ParamInOut);
5958 Args.emplace_back(ParamIn);
5959 const auto &FnInfo =
5960 CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
5961 llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
5962 std::string Name = CGM.getOpenMPRuntime().getName({"red_comb", ""});
5963 auto *Fn = llvm::Function::Create(FnTy, llvm::GlobalValue::InternalLinkage,
5964 Name, &CGM.getModule());
5965 CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FnInfo);
5966 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
5967 Fn->addFnAttr("sample-profile-suffix-elision-policy", "selected");
5968 Fn->setDoesNotRecurse();
5969 CodeGenFunction CGF(CGM);
5970 CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, FnInfo, Args, Loc, Loc);
5971 llvm::Value *Size = nullptr;
5972 // If the size of the reduction item is non-constant, load it from global
5973 // threadprivate variable.
5974 if (RCG.getSizes(N).second) {
5976 CGF, CGM.getContext().getSizeType(),
5977 generateUniqueName(CGM, "reduction_size", RCG.getRefExpr(N)));
5978 Size = CGF.EmitLoadOfScalar(SizeAddr, /*Volatile=*/false,
5979 CGM.getContext().getSizeType(), Loc);
5980 }
5981 RCG.emitAggregateType(CGF, N, Size);
5982 // Remap lhs and rhs variables to the addresses of the function arguments.
5983 // %lhs = bitcast void* %arg0 to <type>*
5984 // %rhs = bitcast void* %arg1 to <type>*
5985 CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
5986 PrivateScope.addPrivate(
5987 LHSVD,
5988 // Pull out the pointer to the variable.
5990 CGF.GetAddrOfLocalVar(ParamInOut)
5991 .withElementType(CGF.Builder.getPtrTy(0)),
5992 C.getPointerType(LHSVD->getType())->castAs<PointerType>()));
5993 PrivateScope.addPrivate(
5994 RHSVD,
5995 // Pull out the pointer to the variable.
5998 CGF.Builder.getPtrTy(0)),
5999 C.getPointerType(RHSVD->getType())->castAs<PointerType>()));
6000 PrivateScope.Privatize();
6001 // Emit the combiner body:
6002 // %2 = <ReductionOp>(<type> *%lhs, <type> *%rhs)
6003 // store <type> %2, <type>* %lhs
6005 CGF, ReductionOp, PrivateRef, cast<DeclRefExpr>(LHS),
6006 cast<DeclRefExpr>(RHS));
6007 CGF.FinishFunction();
6008 return Fn;
6009}
6010
6011/// Emits reduction finalizer function:
6012/// \code
6013/// void @.red_fini(void* %arg) {
6014/// %0 = bitcast void* %arg to <type>*
6015/// <destroy>(<type>* %0)
6016/// ret void
6017/// }
6018/// \endcode
6019static llvm::Value *emitReduceFiniFunction(CodeGenModule &CGM,
6020 SourceLocation Loc,
6021 ReductionCodeGen &RCG, unsigned N) {
6022 if (!RCG.needCleanups(N))
6023 return nullptr;
6024 ASTContext &C = CGM.getContext();
6025 FunctionArgList Args;
6026 auto *Param =
6027 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
6028 C.VoidPtrTy, ImplicitParamKind::Other);
6029 Args.emplace_back(Param);
6030 const auto &FnInfo =
6031 CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
6032 llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
6033 std::string Name = CGM.getOpenMPRuntime().getName({"red_fini", ""});
6034 auto *Fn = llvm::Function::Create(FnTy, llvm::GlobalValue::InternalLinkage,
6035 Name, &CGM.getModule());
6036 CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FnInfo);
6037 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
6038 Fn->addFnAttr("sample-profile-suffix-elision-policy", "selected");
6039 Fn->setDoesNotRecurse();
6040 CodeGenFunction CGF(CGM);
6041 CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, FnInfo, Args, Loc, Loc);
6042 Address PrivateAddr = CGF.EmitLoadOfPointer(
6043 CGF.GetAddrOfLocalVar(Param), C.VoidPtrTy.castAs<PointerType>());
6044 llvm::Value *Size = nullptr;
6045 // If the size of the reduction item is non-constant, load it from global
6046 // threadprivate variable.
6047 if (RCG.getSizes(N).second) {
6049 CGF, CGM.getContext().getSizeType(),
6050 generateUniqueName(CGM, "reduction_size", RCG.getRefExpr(N)));
6051 Size = CGF.EmitLoadOfScalar(SizeAddr, /*Volatile=*/false,
6052 CGM.getContext().getSizeType(), Loc);
6053 }
6054 RCG.emitAggregateType(CGF, N, Size);
6055 // Emit the finalizer body:
6056 // <destroy>(<type>* %0)
6057 RCG.emitCleanups(CGF, N, PrivateAddr);
6058 CGF.FinishFunction(Loc);
6059 return Fn;
6060}
6061
6064 ArrayRef<const Expr *> RHSExprs, const OMPTaskDataTy &Data) {
6065 if (!CGF.HaveInsertPoint() || Data.ReductionVars.empty())
6066 return nullptr;
6067
6068 // Build typedef struct:
6069 // kmp_taskred_input {
6070 // void *reduce_shar; // shared reduction item
6071 // void *reduce_orig; // original reduction item used for initialization
6072 // size_t reduce_size; // size of data item
6073 // void *reduce_init; // data initialization routine
6074 // void *reduce_fini; // data finalization routine
6075 // void *reduce_comb; // data combiner routine
6076 // kmp_task_red_flags_t flags; // flags for additional info from compiler
6077 // } kmp_taskred_input_t;
6078 ASTContext &C = CGM.getContext();
6079 RecordDecl *RD = C.buildImplicitRecord("kmp_taskred_input_t");
6080 RD->startDefinition();
6081 const FieldDecl *SharedFD = addFieldToRecordDecl(C, RD, C.VoidPtrTy);
6082 const FieldDecl *OrigFD = addFieldToRecordDecl(C, RD, C.VoidPtrTy);
6083 const FieldDecl *SizeFD = addFieldToRecordDecl(C, RD, C.getSizeType());
6084 const FieldDecl *InitFD = addFieldToRecordDecl(C, RD, C.VoidPtrTy);
6085 const FieldDecl *FiniFD = addFieldToRecordDecl(C, RD, C.VoidPtrTy);
6086 const FieldDecl *CombFD = addFieldToRecordDecl(C, RD, C.VoidPtrTy);
6087 const FieldDecl *FlagsFD = addFieldToRecordDecl(
6088 C, RD, C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/false));
6089 RD->completeDefinition();
6090 CanQualType RDType = C.getCanonicalTagType(RD);
6091 unsigned Size = Data.ReductionVars.size();
6092 llvm::APInt ArraySize(/*numBits=*/64, Size);
6093 QualType ArrayRDType =
6094 C.getConstantArrayType(RDType, ArraySize, nullptr,
6095 ArraySizeModifier::Normal, /*IndexTypeQuals=*/0);
6096 // kmp_task_red_input_t .rd_input.[Size];
6097 RawAddress TaskRedInput = CGF.CreateMemTemp(ArrayRDType, ".rd_input.");
6098 ReductionCodeGen RCG(Data.ReductionVars, Data.ReductionOrigs,
6099 Data.ReductionCopies, Data.ReductionOps);
6100 for (unsigned Cnt = 0; Cnt < Size; ++Cnt) {
6101 // kmp_task_red_input_t &ElemLVal = .rd_input.[Cnt];
6102 llvm::Value *Idxs[] = {llvm::ConstantInt::get(CGM.SizeTy, /*V=*/0),
6103 llvm::ConstantInt::get(CGM.SizeTy, Cnt)};
6104 llvm::Value *GEP = CGF.EmitCheckedInBoundsGEP(
6105 TaskRedInput.getElementType(), TaskRedInput.getPointer(), Idxs,
6106 /*SignedIndices=*/false, /*IsSubtraction=*/false, Loc,
6107 ".rd_input.gep.");
6108 LValue ElemLVal = CGF.MakeNaturalAlignRawAddrLValue(GEP, RDType);
6109 // ElemLVal.reduce_shar = &Shareds[Cnt];
6110 LValue SharedLVal = CGF.EmitLValueForField(ElemLVal, SharedFD);
6111 RCG.emitSharedOrigLValue(CGF, Cnt);
6112 llvm::Value *Shared = RCG.getSharedLValue(Cnt).getPointer(CGF);
6113 CGF.EmitStoreOfScalar(Shared, SharedLVal);
6114 // ElemLVal.reduce_orig = &Origs[Cnt];
6115 LValue OrigLVal = CGF.EmitLValueForField(ElemLVal, OrigFD);
6116 llvm::Value *Orig = RCG.getOrigLValue(Cnt).getPointer(CGF);
6117 CGF.EmitStoreOfScalar(Orig, OrigLVal);
6118 RCG.emitAggregateType(CGF, Cnt);
6119 llvm::Value *SizeValInChars;
6120 llvm::Value *SizeVal;
6121 std::tie(SizeValInChars, SizeVal) = RCG.getSizes(Cnt);
6122 // We use delayed creation/initialization for VLAs and array sections. It is
6123 // required because runtime does not provide the way to pass the sizes of
6124 // VLAs/array sections to initializer/combiner/finalizer functions. Instead
6125 // threadprivate global variables are used to store these values and use
6126 // them in the functions.
6127 bool DelayedCreation = !!SizeVal;
6128 SizeValInChars = CGF.Builder.CreateIntCast(SizeValInChars, CGM.SizeTy,
6129 /*isSigned=*/false);
6130 LValue SizeLVal = CGF.EmitLValueForField(ElemLVal, SizeFD);
6131 CGF.EmitStoreOfScalar(SizeValInChars, SizeLVal);
6132 // ElemLVal.reduce_init = init;
6133 LValue InitLVal = CGF.EmitLValueForField(ElemLVal, InitFD);
6134 llvm::Value *InitAddr = emitReduceInitFunction(CGM, Loc, RCG, Cnt);
6135 CGF.EmitStoreOfScalar(InitAddr, InitLVal);
6136 // ElemLVal.reduce_fini = fini;
6137 LValue FiniLVal = CGF.EmitLValueForField(ElemLVal, FiniFD);
6138 llvm::Value *Fini = emitReduceFiniFunction(CGM, Loc, RCG, Cnt);
6139 llvm::Value *FiniAddr =
6140 Fini ? Fini : llvm::ConstantPointerNull::get(CGM.VoidPtrTy);
6141 CGF.EmitStoreOfScalar(FiniAddr, FiniLVal);
6142 // ElemLVal.reduce_comb = comb;
6143 LValue CombLVal = CGF.EmitLValueForField(ElemLVal, CombFD);
6144 llvm::Value *CombAddr = emitReduceCombFunction(
6145 CGM, Loc, RCG, Cnt, Data.ReductionOps[Cnt], LHSExprs[Cnt],
6146 RHSExprs[Cnt], Data.ReductionCopies[Cnt]);
6147 CGF.EmitStoreOfScalar(CombAddr, CombLVal);
6148 // ElemLVal.flags = 0;
6149 LValue FlagsLVal = CGF.EmitLValueForField(ElemLVal, FlagsFD);
6150 if (DelayedCreation) {
6152 llvm::ConstantInt::get(CGM.Int32Ty, /*V=*/1, /*isSigned=*/true),
6153 FlagsLVal);
6154 } else
6155 CGF.EmitNullInitialization(FlagsLVal.getAddress(), FlagsLVal.getType());
6156 }
6157 if (Data.IsReductionWithTaskMod) {
6158 // Build call void *__kmpc_taskred_modifier_init(ident_t *loc, int gtid, int
6159 // is_ws, int num, void *data);
6160 llvm::Value *IdentTLoc = emitUpdateLocation(CGF, Loc);
6161 llvm::Value *GTid = CGF.Builder.CreateIntCast(getThreadID(CGF, Loc),
6162 CGM.IntTy, /*isSigned=*/true);
6163 llvm::Value *Args[] = {
6164 IdentTLoc, GTid,
6165 llvm::ConstantInt::get(CGM.IntTy, Data.IsWorksharingReduction ? 1 : 0,
6166 /*isSigned=*/true),
6167 llvm::ConstantInt::get(CGM.IntTy, Size, /*isSigned=*/true),
6169 TaskRedInput.getPointer(), CGM.VoidPtrTy)};
6170 return CGF.EmitRuntimeCall(
6171 OMPBuilder.getOrCreateRuntimeFunction(
6172 CGM.getModule(), OMPRTL___kmpc_taskred_modifier_init),
6173 Args);
6174 }
6175 // Build call void *__kmpc_taskred_init(int gtid, int num_data, void *data);
6176 llvm::Value *Args[] = {
6177 CGF.Builder.CreateIntCast(getThreadID(CGF, Loc), CGM.IntTy,
6178 /*isSigned=*/true),
6179 llvm::ConstantInt::get(CGM.IntTy, Size, /*isSigned=*/true),
6181 CGM.VoidPtrTy)};
6182 return CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
6183 CGM.getModule(), OMPRTL___kmpc_taskred_init),
6184 Args);
6185}
6186
6188 SourceLocation Loc,
6189 bool IsWorksharingReduction) {
6190 // Build call void *__kmpc_taskred_modifier_init(ident_t *loc, int gtid, int
6191 // is_ws, int num, void *data);
6192 llvm::Value *IdentTLoc = emitUpdateLocation(CGF, Loc);
6193 llvm::Value *GTid = CGF.Builder.CreateIntCast(getThreadID(CGF, Loc),
6194 CGM.IntTy, /*isSigned=*/true);
6195 llvm::Value *Args[] = {IdentTLoc, GTid,
6196 llvm::ConstantInt::get(CGM.IntTy,
6197 IsWorksharingReduction ? 1 : 0,
6198 /*isSigned=*/true)};
6199 (void)CGF.EmitRuntimeCall(
6200 OMPBuilder.getOrCreateRuntimeFunction(
6201 CGM.getModule(), OMPRTL___kmpc_task_reduction_modifier_fini),
6202 Args);
6203}
6204
6206 SourceLocation Loc,
6207 ReductionCodeGen &RCG,
6208 unsigned N) {
6209 auto Sizes = RCG.getSizes(N);
6210 // Emit threadprivate global variable if the type is non-constant
6211 // (Sizes.second = nullptr).
6212 if (Sizes.second) {
6213 llvm::Value *SizeVal = CGF.Builder.CreateIntCast(Sizes.second, CGM.SizeTy,
6214 /*isSigned=*/false);
6216 CGF, CGM.getContext().getSizeType(),
6217 generateUniqueName(CGM, "reduction_size", RCG.getRefExpr(N)));
6218 CGF.Builder.CreateStore(SizeVal, SizeAddr, /*IsVolatile=*/false);
6219 }
6220}
6221
6223 SourceLocation Loc,
6224 llvm::Value *ReductionsPtr,
6225 LValue SharedLVal) {
6226 // Build call void *__kmpc_task_reduction_get_th_data(int gtid, void *tg, void
6227 // *d);
6228 llvm::Value *Args[] = {CGF.Builder.CreateIntCast(getThreadID(CGF, Loc),
6229 CGM.IntTy,
6230 /*isSigned=*/true),
6231 ReductionsPtr,
6233 SharedLVal.getPointer(CGF), CGM.VoidPtrTy)};
6234 return Address(
6235 CGF.EmitRuntimeCall(
6236 OMPBuilder.getOrCreateRuntimeFunction(
6237 CGM.getModule(), OMPRTL___kmpc_task_reduction_get_th_data),
6238 Args),
6239 CGF.Int8Ty, SharedLVal.getAlignment());
6240}
6241
6243 const OMPTaskDataTy &Data) {
6244 if (!CGF.HaveInsertPoint())
6245 return;
6246
6247 if (CGF.CGM.getLangOpts().OpenMPIRBuilder && Data.Dependences.empty()) {
6248 // TODO: Need to support taskwait with dependences in the OpenMPIRBuilder.
6249 OMPBuilder.createTaskwait(CGF.Builder);
6250 } else {
6251 llvm::Value *ThreadID = getThreadID(CGF, Loc);
6252 llvm::Value *UpLoc = emitUpdateLocation(CGF, Loc);
6253 auto &M = CGM.getModule();
6254 Address DependenciesArray = Address::invalid();
6255 llvm::Value *NumOfElements;
6256 std::tie(NumOfElements, DependenciesArray) =
6257 emitDependClause(CGF, Data.Dependences, Loc);
6258 if (!Data.Dependences.empty()) {
6259 llvm::Value *DepWaitTaskArgs[7];
6260 DepWaitTaskArgs[0] = UpLoc;
6261 DepWaitTaskArgs[1] = ThreadID;
6262 DepWaitTaskArgs[2] = NumOfElements;
6263 DepWaitTaskArgs[3] = DependenciesArray.emitRawPointer(CGF);
6264 DepWaitTaskArgs[4] = CGF.Builder.getInt32(0);
6265 DepWaitTaskArgs[5] = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
6266 DepWaitTaskArgs[6] =
6267 llvm::ConstantInt::get(CGF.Int32Ty, Data.HasNowaitClause);
6268
6269 CodeGenFunction::RunCleanupsScope LocalScope(CGF);
6270
6271 // Build void __kmpc_omp_taskwait_deps_51(ident_t *, kmp_int32 gtid,
6272 // kmp_int32 ndeps, kmp_depend_info_t *dep_list, kmp_int32
6273 // ndeps_noalias, kmp_depend_info_t *noalias_dep_list,
6274 // kmp_int32 has_no_wait); if dependence info is specified.
6275 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
6276 M, OMPRTL___kmpc_omp_taskwait_deps_51),
6277 DepWaitTaskArgs);
6278
6279 } else {
6280
6281 // Build call kmp_int32 __kmpc_omp_taskwait(ident_t *loc, kmp_int32
6282 // global_tid);
6283 llvm::Value *Args[] = {UpLoc, ThreadID};
6284 // Ignore return result until untied tasks are supported.
6285 CGF.EmitRuntimeCall(
6286 OMPBuilder.getOrCreateRuntimeFunction(M, OMPRTL___kmpc_omp_taskwait),
6287 Args);
6288 }
6289 }
6290
6291 if (auto *Region = dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo))
6292 Region->emitUntiedSwitch(CGF);
6293}
6294
6296 OpenMPDirectiveKind InnerKind,
6297 const RegionCodeGenTy &CodeGen,
6298 bool HasCancel) {
6299 if (!CGF.HaveInsertPoint())
6300 return;
6301 InlinedOpenMPRegionRAII Region(CGF, CodeGen, InnerKind, HasCancel,
6302 InnerKind != OMPD_critical &&
6303 InnerKind != OMPD_master &&
6304 InnerKind != OMPD_masked);
6305 CGF.CapturedStmtInfo->EmitBody(CGF, /*S=*/nullptr);
6306}
6307
6308namespace {
6309enum RTCancelKind {
6310 CancelNoreq = 0,
6311 CancelParallel = 1,
6312 CancelLoop = 2,
6313 CancelSections = 3,
6314 CancelTaskgroup = 4
6315};
6316} // anonymous namespace
6317
6318static RTCancelKind getCancellationKind(OpenMPDirectiveKind CancelRegion) {
6319 RTCancelKind CancelKind = CancelNoreq;
6320 if (CancelRegion == OMPD_parallel)
6321 CancelKind = CancelParallel;
6322 else if (CancelRegion == OMPD_for)
6323 CancelKind = CancelLoop;
6324 else if (CancelRegion == OMPD_sections)
6325 CancelKind = CancelSections;
6326 else {
6327 assert(CancelRegion == OMPD_taskgroup);
6328 CancelKind = CancelTaskgroup;
6329 }
6330 return CancelKind;
6331}
6332
6335 OpenMPDirectiveKind CancelRegion) {
6336 if (!CGF.HaveInsertPoint())
6337 return;
6338 // Build call kmp_int32 __kmpc_cancellationpoint(ident_t *loc, kmp_int32
6339 // global_tid, kmp_int32 cncl_kind);
6340 if (auto *OMPRegionInfo =
6341 dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) {
6342 // For 'cancellation point taskgroup', the task region info may not have a
6343 // cancel. This may instead happen in another adjacent task.
6344 if (CancelRegion == OMPD_taskgroup || OMPRegionInfo->hasCancel()) {
6345 llvm::Value *Args[] = {
6346 emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
6347 CGF.Builder.getInt32(getCancellationKind(CancelRegion))};
6348 // Ignore return result until untied tasks are supported.
6349 llvm::Value *Result = CGF.EmitRuntimeCall(
6350 OMPBuilder.getOrCreateRuntimeFunction(
6351 CGM.getModule(), OMPRTL___kmpc_cancellationpoint),
6352 Args);
6353 // if (__kmpc_cancellationpoint()) {
6354 // call i32 @__kmpc_cancel_barrier( // for parallel cancellation only
6355 // exit from construct;
6356 // }
6357 llvm::BasicBlock *ExitBB = CGF.createBasicBlock(".cancel.exit");
6358 llvm::BasicBlock *ContBB = CGF.createBasicBlock(".cancel.continue");
6359 llvm::Value *Cmp = CGF.Builder.CreateIsNotNull(Result);
6360 CGF.Builder.CreateCondBr(Cmp, ExitBB, ContBB);
6361 CGF.EmitBlock(ExitBB);
6362 if (CancelRegion == OMPD_parallel)
6363 emitBarrierCall(CGF, Loc, OMPD_unknown, /*EmitChecks=*/false);
6364 // exit from construct;
6365 CodeGenFunction::JumpDest CancelDest =
6366 CGF.getOMPCancelDestination(OMPRegionInfo->getDirectiveKind());
6367 CGF.EmitBranchThroughCleanup(CancelDest);
6368 CGF.EmitBlock(ContBB, /*IsFinished=*/true);
6369 }
6370 }
6371}
6372
6374 const Expr *IfCond,
6375 OpenMPDirectiveKind CancelRegion) {
6376 if (!CGF.HaveInsertPoint())
6377 return;
6378 // Build call kmp_int32 __kmpc_cancel(ident_t *loc, kmp_int32 global_tid,
6379 // kmp_int32 cncl_kind);
6380 auto &M = CGM.getModule();
6381 if (auto *OMPRegionInfo =
6382 dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) {
6383 auto &&ThenGen = [this, &M, Loc, CancelRegion,
6384 OMPRegionInfo](CodeGenFunction &CGF, PrePostActionTy &) {
6385 CGOpenMPRuntime &RT = CGF.CGM.getOpenMPRuntime();
6386 llvm::Value *Args[] = {
6387 RT.emitUpdateLocation(CGF, Loc), RT.getThreadID(CGF, Loc),
6388 CGF.Builder.getInt32(getCancellationKind(CancelRegion))};
6389 // Ignore return result until untied tasks are supported.
6390 llvm::Value *Result = CGF.EmitRuntimeCall(
6391 OMPBuilder.getOrCreateRuntimeFunction(M, OMPRTL___kmpc_cancel), Args);
6392 // if (__kmpc_cancel()) {
6393 // call i32 @__kmpc_cancel_barrier( // for parallel cancellation only
6394 // exit from construct;
6395 // }
6396 llvm::BasicBlock *ExitBB = CGF.createBasicBlock(".cancel.exit");
6397 llvm::BasicBlock *ContBB = CGF.createBasicBlock(".cancel.continue");
6398 llvm::Value *Cmp = CGF.Builder.CreateIsNotNull(Result);
6399 CGF.Builder.CreateCondBr(Cmp, ExitBB, ContBB);
6400 CGF.EmitBlock(ExitBB);
6401 if (CancelRegion == OMPD_parallel)
6402 RT.emitBarrierCall(CGF, Loc, OMPD_unknown, /*EmitChecks=*/false);
6403 // exit from construct;
6404 CodeGenFunction::JumpDest CancelDest =
6405 CGF.getOMPCancelDestination(OMPRegionInfo->getDirectiveKind());
6406 CGF.EmitBranchThroughCleanup(CancelDest);
6407 CGF.EmitBlock(ContBB, /*IsFinished=*/true);
6408 };
6409 if (IfCond) {
6410 emitIfClause(CGF, IfCond, ThenGen,
6411 [](CodeGenFunction &, PrePostActionTy &) {});
6412 } else {
6413 RegionCodeGenTy ThenRCG(ThenGen);
6414 ThenRCG(CGF);
6415 }
6416 }
6417}
6418
6419namespace {
6420/// Cleanup action for uses_allocators support.
6421class OMPUsesAllocatorsActionTy final : public PrePostActionTy {
6423 const OMPExecutableDirective &D;
6424 bool IsOffloadEntry;
6425
6426public:
6427 OMPUsesAllocatorsActionTy(
6428 ArrayRef<std::pair<const Expr *, const Expr *>> Allocators,
6429 const OMPExecutableDirective &D, bool IsOffloadEntry)
6430 : Allocators(Allocators), D(D), IsOffloadEntry(IsOffloadEntry) {}
6431 void Enter(CodeGenFunction &CGF) override {
6432 if (!CGF.HaveInsertPoint())
6433 return;
6434 for (const auto &AllocatorData : Allocators) {
6436 CGF, AllocatorData.first, AllocatorData.second);
6437 }
6438 // This kernel does not go through the device-side runtime
6439 // init/deinit sequence (that is GPU-only), but the runtime still
6440 // needs a '<kernel>_kernel_environment' global to know how the
6441 // kernel was configured, so emit it directly here.
6442 if (IsOffloadEntry)
6444 }
6445 void Exit(CodeGenFunction &CGF) override {
6446 if (!CGF.HaveInsertPoint())
6447 return;
6448 for (const auto &AllocatorData : Allocators) {
6450 AllocatorData.first);
6451 }
6452 }
6453};
6454} // namespace
6455
6457 CodeGenFunction &CGF) {
6458 llvm::OpenMPIRBuilder::TargetKernelDefaultAttrs Attrs;
6459 Attrs.ExecFlags = llvm::omp::OMPTgtExecModeFlags::OMP_TGT_EXEC_MODE_GENERIC;
6460 computeMinAndMaxThreadsAndTeams(D, CGF, Attrs);
6461 OMPBuilder.emitKernelEnvironment(CGF.Builder, Attrs);
6462}
6463
6465 const OMPExecutableDirective &D, StringRef ParentName,
6466 llvm::Function *&OutlinedFn, llvm::Constant *&OutlinedFnID,
6467 bool IsOffloadEntry, const RegionCodeGenTy &CodeGen) {
6468 assert(!ParentName.empty() && "Invalid target entry parent name!");
6471 for (const auto *C : D.getClausesOfKind<OMPUsesAllocatorsClause>()) {
6472 for (unsigned I = 0, E = C->getNumberOfAllocators(); I < E; ++I) {
6473 const OMPUsesAllocatorsClause::Data D = C->getAllocatorData(I);
6474 if (!D.AllocatorTraits)
6475 continue;
6476 Allocators.emplace_back(D.Allocator, D.AllocatorTraits);
6477 }
6478 }
6479 OMPUsesAllocatorsActionTy UsesAllocatorAction(Allocators, D, IsOffloadEntry);
6480 CodeGen.setAction(UsesAllocatorAction);
6481 emitTargetOutlinedFunctionHelper(D, ParentName, OutlinedFn, OutlinedFnID,
6482 IsOffloadEntry, CodeGen);
6483}
6484
6486 const Expr *Allocator,
6487 const Expr *AllocatorTraits) {
6488 llvm::Value *ThreadId = getThreadID(CGF, Allocator->getExprLoc());
6489 ThreadId = CGF.Builder.CreateIntCast(ThreadId, CGF.IntTy, /*isSigned=*/true);
6490 // Use default memspace handle.
6491 llvm::Value *MemSpaceHandle = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
6492 llvm::Value *NumTraits = llvm::ConstantInt::get(
6494 AllocatorTraits->getType()->getAsArrayTypeUnsafe())
6495 ->getSize()
6496 .getLimitedValue());
6497 LValue AllocatorTraitsLVal = CGF.EmitLValue(AllocatorTraits);
6499 AllocatorTraitsLVal.getAddress(), CGF.VoidPtrPtrTy, CGF.VoidPtrTy);
6500 AllocatorTraitsLVal = CGF.MakeAddrLValue(Addr, CGF.getContext().VoidPtrTy,
6501 AllocatorTraitsLVal.getBaseInfo(),
6502 AllocatorTraitsLVal.getTBAAInfo());
6503 llvm::Value *Traits = Addr.emitRawPointer(CGF);
6504
6505 llvm::Value *AllocatorVal =
6506 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
6507 CGM.getModule(), OMPRTL___kmpc_init_allocator),
6508 {ThreadId, MemSpaceHandle, NumTraits, Traits});
6509 // Store to allocator.
6511 cast<DeclRefExpr>(Allocator->IgnoreParenImpCasts())->getDecl()));
6512 LValue AllocatorLVal = CGF.EmitLValue(Allocator->IgnoreParenImpCasts());
6513 AllocatorVal =
6514 CGF.EmitScalarConversion(AllocatorVal, CGF.getContext().VoidPtrTy,
6515 Allocator->getType(), Allocator->getExprLoc());
6516 CGF.EmitStoreOfScalar(AllocatorVal, AllocatorLVal);
6517}
6518
6520 const Expr *Allocator) {
6521 llvm::Value *ThreadId = getThreadID(CGF, Allocator->getExprLoc());
6522 ThreadId = CGF.Builder.CreateIntCast(ThreadId, CGF.IntTy, /*isSigned=*/true);
6523 LValue AllocatorLVal = CGF.EmitLValue(Allocator->IgnoreParenImpCasts());
6524 llvm::Value *AllocatorVal =
6525 CGF.EmitLoadOfScalar(AllocatorLVal, Allocator->getExprLoc());
6526 AllocatorVal = CGF.EmitScalarConversion(AllocatorVal, Allocator->getType(),
6527 CGF.getContext().VoidPtrTy,
6528 Allocator->getExprLoc());
6529 (void)CGF.EmitRuntimeCall(
6530 OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(),
6531 OMPRTL___kmpc_destroy_allocator),
6532 {ThreadId, AllocatorVal});
6533}
6534
6537 llvm::OpenMPIRBuilder::TargetKernelDefaultAttrs &Attrs) {
6538 assert(Attrs.MaxTeams.size() == 1 && Attrs.MaxThreads.size() == 1 &&
6539 "invalid default attrs structure");
6540 int32_t &MaxTeamsVal = Attrs.MaxTeams.front();
6541 int32_t &MaxThreadsVal = Attrs.MaxThreads.front();
6542
6543 getNumTeamsExprForTargetDirective(CGF, D, Attrs.MinTeams.front(),
6544 MaxTeamsVal);
6545 getNumThreadsExprForTargetDirective(CGF, D, MaxThreadsVal,
6546 /*UpperBoundOnly=*/true);
6547
6548 for (auto *C : D.getClausesOfKind<OMPXAttributeClause>()) {
6549 for (auto *A : C->getAttrs()) {
6550 int32_t AttrMinThreadsVal = 1, AttrMaxThreadsVal = -1;
6551 int32_t AttrMinBlocksVal = 1, AttrMaxBlocksVal = -1;
6552 if (auto *Attr = dyn_cast<CUDALaunchBoundsAttr>(A))
6553 CGM.handleCUDALaunchBoundsAttr(nullptr, Attr, &AttrMaxThreadsVal,
6554 &AttrMinBlocksVal, &AttrMaxBlocksVal);
6555 else if (auto *Attr = dyn_cast<AMDGPUFlatWorkGroupSizeAttr>(A))
6556 CGM.handleAMDGPUFlatWorkGroupSizeAttr(
6557 nullptr, Attr, /*ReqdWGS=*/nullptr, &AttrMinThreadsVal,
6558 &AttrMaxThreadsVal);
6559 else
6560 continue;
6561
6562 Attrs.MinThreads.front() =
6563 std::max(Attrs.MinThreads.front(), AttrMinThreadsVal);
6564 if (AttrMaxThreadsVal > 0)
6565 MaxThreadsVal = MaxThreadsVal > 0
6566 ? std::min(MaxThreadsVal, AttrMaxThreadsVal)
6567 : AttrMaxThreadsVal;
6568 Attrs.MinTeams.front() =
6569 std::max(Attrs.MinTeams.front(), AttrMinBlocksVal);
6570 if (AttrMaxBlocksVal > 0)
6571 MaxTeamsVal = MaxTeamsVal > 0 ? std::min(MaxTeamsVal, AttrMaxBlocksVal)
6572 : AttrMaxBlocksVal;
6573 }
6574 }
6575}
6576
6578 const OMPExecutableDirective &D, StringRef ParentName,
6579 llvm::Function *&OutlinedFn, llvm::Constant *&OutlinedFnID,
6580 bool IsOffloadEntry, const RegionCodeGenTy &CodeGen) {
6581
6582 llvm::TargetRegionEntryInfo EntryInfo =
6583 getEntryInfoFromPresumedLoc(CGM, OMPBuilder, D.getBeginLoc(), ParentName);
6584
6585 CodeGenFunction CGF(CGM, true);
6586 llvm::OpenMPIRBuilder::FunctionGenCallback &&GenerateOutlinedFunction =
6587 [&CGF, &D, &CodeGen, this](StringRef EntryFnName) {
6588 const CapturedStmt &CS = *D.getCapturedStmt(OMPD_target);
6589
6590 CGOpenMPTargetRegionInfo CGInfo(CS, CodeGen, EntryFnName);
6591 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
6592 if (CGM.getLangOpts().OpenMPIsTargetDevice && !isGPU())
6594 return CGF.GenerateOpenMPCapturedStmtFunction(CS, D);
6595 };
6596
6597 cantFail(OMPBuilder.emitTargetRegionFunction(
6598 EntryInfo, GenerateOutlinedFunction, IsOffloadEntry, OutlinedFn,
6599 OutlinedFnID));
6600
6601 if (!OutlinedFn)
6602 return;
6603
6604 // A target body is entered once, from the kernel, and never re-entered by
6605 // the runtime, so it cannot occur in a cycle.
6606 OutlinedFn->setDoesNotRecurse();
6607
6608 CGM.getTargetCodeGenInfo().setTargetAttributes(nullptr, OutlinedFn, CGM);
6609
6610 for (auto *C : D.getClausesOfKind<OMPXAttributeClause>()) {
6611 for (auto *A : C->getAttrs()) {
6612 if (auto *Attr = dyn_cast<AMDGPUWavesPerEUAttr>(A))
6613 CGM.handleAMDGPUWavesPerEUAttr(OutlinedFn, Attr);
6614 }
6615 }
6616 registerVTable(D);
6617}
6618
6619/// Checks if the expression is constant or does not have non-trivial function
6620/// calls.
6621static bool isTrivial(ASTContext &Ctx, const Expr * E) {
6622 // We can skip constant expressions.
6623 // We can skip expressions with trivial calls or simple expressions.
6625 !E->hasNonTrivialCall(Ctx)) &&
6626 !E->HasSideEffects(Ctx, /*IncludePossibleEffects=*/true);
6627}
6628
6630 const Stmt *Body) {
6631 const Stmt *Child = Body->IgnoreContainers();
6632 while (const auto *C = dyn_cast_or_null<CompoundStmt>(Child)) {
6633 Child = nullptr;
6634 for (const Stmt *S : C->body()) {
6635 if (const auto *E = dyn_cast<Expr>(S)) {
6636 if (isTrivial(Ctx, E))
6637 continue;
6638 }
6639 // Some of the statements can be ignored.
6642 continue;
6643 // Analyze declarations.
6644 if (const auto *DS = dyn_cast<DeclStmt>(S)) {
6645 if (llvm::all_of(DS->decls(), [](const Decl *D) {
6646 if (isa<EmptyDecl>(D) || isa<DeclContext>(D) ||
6647 isa<TypeDecl>(D) || isa<PragmaCommentDecl>(D) ||
6648 isa<PragmaDetectMismatchDecl>(D) || isa<UsingDecl>(D) ||
6649 isa<UsingDirectiveDecl>(D) ||
6650 isa<OMPDeclareReductionDecl>(D) ||
6651 isa<OMPThreadPrivateDecl>(D) || isa<OMPAllocateDecl>(D))
6652 return true;
6653 const auto *VD = dyn_cast<VarDecl>(D);
6654 if (!VD)
6655 return false;
6656 return VD->hasGlobalStorage() || !VD->isUsed();
6657 }))
6658 continue;
6659 }
6660 // Found multiple children - cannot get the one child only.
6661 if (Child)
6662 return nullptr;
6663 Child = S;
6664 }
6665 if (Child)
6666 Child = Child->IgnoreContainers();
6667 }
6668 return Child;
6669}
6670
6672 CodeGenFunction &CGF, const OMPExecutableDirective &D, int32_t &MinTeamsVal,
6673 int32_t &MaxTeamsVal) {
6674
6675 OpenMPDirectiveKind DirectiveKind = D.getDirectiveKind();
6676 assert(isOpenMPTargetExecutionDirective(DirectiveKind) &&
6677 "Expected target-based executable directive.");
6678 switch (DirectiveKind) {
6679 case OMPD_target: {
6680 const auto *CS = D.getInnermostCapturedStmt();
6681 const auto *Body =
6682 CS->getCapturedStmt()->IgnoreContainers(/*IgnoreCaptured=*/true);
6683 const Stmt *ChildStmt =
6685 if (const auto *NestedDir =
6686 dyn_cast_or_null<OMPExecutableDirective>(ChildStmt)) {
6687 if (isOpenMPTeamsDirective(NestedDir->getDirectiveKind())) {
6688 if (NestedDir->hasClausesOfKind<OMPNumTeamsClause>()) {
6689 const Expr *NumTeams = NestedDir->getSingleClause<OMPNumTeamsClause>()
6690 ->getNumTeams()
6691 .front();
6692 if (NumTeams->isIntegerConstantExpr(CGF.getContext()))
6693 if (auto Constant =
6694 NumTeams->getIntegerConstantExpr(CGF.getContext()))
6695 MinTeamsVal = MaxTeamsVal = Constant->getExtValue();
6696 return NumTeams;
6697 }
6698 MinTeamsVal = MaxTeamsVal = 0;
6699 return nullptr;
6700 }
6701 MinTeamsVal = MaxTeamsVal = 1;
6702 return nullptr;
6703 }
6704 // A value of -1 is used to check if we need to emit no teams region
6705 MinTeamsVal = MaxTeamsVal = -1;
6706 return nullptr;
6707 }
6708 case OMPD_target_teams_loop:
6709 case OMPD_target_teams:
6710 case OMPD_target_teams_distribute:
6711 case OMPD_target_teams_distribute_simd:
6712 case OMPD_target_teams_distribute_parallel_for:
6713 case OMPD_target_teams_distribute_parallel_for_simd: {
6714 if (D.hasClausesOfKind<OMPNumTeamsClause>()) {
6715 const Expr *NumTeams =
6716 D.getSingleClause<OMPNumTeamsClause>()->getNumTeams().front();
6717 if (NumTeams->isIntegerConstantExpr(CGF.getContext()))
6718 if (auto Constant = NumTeams->getIntegerConstantExpr(CGF.getContext()))
6719 MinTeamsVal = MaxTeamsVal = Constant->getExtValue();
6720 return NumTeams;
6721 }
6722 MinTeamsVal = MaxTeamsVal = 0;
6723 return nullptr;
6724 }
6725 case OMPD_target_parallel:
6726 case OMPD_target_parallel_for:
6727 case OMPD_target_parallel_for_simd:
6728 case OMPD_target_parallel_loop:
6729 case OMPD_target_simd:
6730 MinTeamsVal = MaxTeamsVal = 1;
6731 return nullptr;
6732 case OMPD_parallel:
6733 case OMPD_for:
6734 case OMPD_parallel_for:
6735 case OMPD_parallel_loop:
6736 case OMPD_parallel_master:
6737 case OMPD_parallel_sections:
6738 case OMPD_for_simd:
6739 case OMPD_parallel_for_simd:
6740 case OMPD_cancel:
6741 case OMPD_cancellation_point:
6742 case OMPD_ordered_standalone:
6743 case OMPD_ordered_blockassoc:
6744 case OMPD_threadprivate:
6745 case OMPD_allocate:
6746 case OMPD_task:
6747 case OMPD_simd:
6748 case OMPD_tile:
6749 case OMPD_unroll:
6750 case OMPD_sections:
6751 case OMPD_section:
6752 case OMPD_single:
6753 case OMPD_master:
6754 case OMPD_critical:
6755 case OMPD_taskyield:
6756 case OMPD_barrier:
6757 case OMPD_taskwait:
6758 case OMPD_taskgroup:
6759 case OMPD_atomic:
6760 case OMPD_flush:
6761 case OMPD_depobj:
6762 case OMPD_scan:
6763 case OMPD_teams:
6764 case OMPD_target_data:
6765 case OMPD_target_exit_data:
6766 case OMPD_target_enter_data:
6767 case OMPD_distribute:
6768 case OMPD_distribute_simd:
6769 case OMPD_distribute_parallel_for:
6770 case OMPD_distribute_parallel_for_simd:
6771 case OMPD_teams_distribute:
6772 case OMPD_teams_distribute_simd:
6773 case OMPD_teams_distribute_parallel_for:
6774 case OMPD_teams_distribute_parallel_for_simd:
6775 case OMPD_target_update:
6776 case OMPD_declare_simd:
6777 case OMPD_declare_variant:
6778 case OMPD_begin_declare_variant:
6779 case OMPD_end_declare_variant:
6780 case OMPD_declare_target:
6781 case OMPD_end_declare_target:
6782 case OMPD_declare_reduction:
6783 case OMPD_declare_mapper:
6784 case OMPD_taskloop:
6785 case OMPD_taskloop_simd:
6786 case OMPD_master_taskloop:
6787 case OMPD_master_taskloop_simd:
6788 case OMPD_parallel_master_taskloop:
6789 case OMPD_parallel_master_taskloop_simd:
6790 case OMPD_requires:
6791 case OMPD_metadirective:
6792 case OMPD_unknown:
6793 break;
6794 default:
6795 break;
6796 }
6797 llvm_unreachable("Unexpected directive kind.");
6798}
6799
6801 CodeGenFunction &CGF, const OMPExecutableDirective &D) {
6802 assert(!CGF.getLangOpts().OpenMPIsTargetDevice &&
6803 "Clauses associated with the teams directive expected to be emitted "
6804 "only for the host!");
6805 CGBuilderTy &Bld = CGF.Builder;
6806 int32_t MinNT = -1, MaxNT = -1;
6807 const Expr *NumTeams =
6808 getNumTeamsExprForTargetDirective(CGF, D, MinNT, MaxNT);
6809 if (NumTeams != nullptr) {
6810 OpenMPDirectiveKind DirectiveKind = D.getDirectiveKind();
6811
6812 switch (DirectiveKind) {
6813 case OMPD_target: {
6814 const auto *CS = D.getInnermostCapturedStmt();
6815 CGOpenMPInnerExprInfo CGInfo(CGF, *CS);
6816 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
6817 llvm::Value *NumTeamsVal = CGF.EmitScalarExpr(NumTeams,
6818 /*IgnoreResultAssign*/ true);
6819 return Bld.CreateIntCast(NumTeamsVal, CGF.Int32Ty,
6820 /*isSigned=*/true);
6821 }
6822 case OMPD_target_teams:
6823 case OMPD_target_teams_distribute:
6824 case OMPD_target_teams_distribute_simd:
6825 case OMPD_target_teams_distribute_parallel_for:
6826 case OMPD_target_teams_distribute_parallel_for_simd: {
6827 CodeGenFunction::RunCleanupsScope NumTeamsScope(CGF);
6828 llvm::Value *NumTeamsVal = CGF.EmitScalarExpr(NumTeams,
6829 /*IgnoreResultAssign*/ true);
6830 return Bld.CreateIntCast(NumTeamsVal, CGF.Int32Ty,
6831 /*isSigned=*/true);
6832 }
6833 default:
6834 break;
6835 }
6836 }
6837
6838 assert(MinNT == MaxNT && "Num threads ranges require handling here.");
6839 return llvm::ConstantInt::getSigned(CGF.Int32Ty, MinNT);
6840}
6841
6842/// Merge the thread count upper bound \p Val into \p UpperBound.
6843///
6844/// \p UpperBound is -1 while no thread limiting clause has been seen, 0 once
6845/// one has been seen whose value is not known at compile time, and otherwise
6846/// the smallest constant bound found so far.
6847///
6848/// Thread limiting clauses compose by taking the minimum, so a constant bound
6849/// stays valid whatever the clauses that are not compile time constants
6850/// evaluate to. That makes it correct to replace the 0 marker with \p Val, and
6851/// necessary to keep a clause from raising a smaller bound found earlier.
6852static void mergeThreadCountUpperBound(int32_t &UpperBound, int32_t Val) {
6853 UpperBound = UpperBound > 0 ? std::min(UpperBound, Val) : Val;
6854}
6855
6856/// Check for a num threads constant value (stored in \p DefaultVal), or
6857/// expression (stored in \p E). If the value is conditional (via an if-clause),
6858/// store the condition in \p CondVal. If \p E, and \p CondVal respectively, are
6859/// nullptr, no expression evaluation is perfomed.
6860static void getNumThreads(CodeGenFunction &CGF, const CapturedStmt *CS,
6861 const Expr **E, int32_t &UpperBound,
6862 bool UpperBoundOnly, llvm::Value **CondVal) {
6864 CGF.getContext(), CS->getCapturedStmt());
6865 const auto *Dir = dyn_cast_or_null<OMPExecutableDirective>(Child);
6866 if (!Dir)
6867 return;
6868
6869 if (isOpenMPParallelDirective(Dir->getDirectiveKind())) {
6870 // Handle if clause. If if clause present, the number of threads is
6871 // calculated as <cond> ? (<numthreads> ? <numthreads> : 0 ) : 1.
6872 if (CondVal && Dir->hasClausesOfKind<OMPIfClause>()) {
6873 CGOpenMPInnerExprInfo CGInfo(CGF, *CS);
6874 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
6875 const OMPIfClause *IfClause = nullptr;
6876 for (const auto *C : Dir->getClausesOfKind<OMPIfClause>()) {
6877 if (C->getNameModifier() == OMPD_unknown ||
6878 C->getNameModifier() == OMPD_parallel) {
6879 IfClause = C;
6880 break;
6881 }
6882 }
6883 if (IfClause) {
6884 const Expr *CondExpr = IfClause->getCondition();
6885 bool Result;
6886 if (CondExpr->EvaluateAsBooleanCondition(Result, CGF.getContext())) {
6887 if (!Result) {
6888 UpperBound = 1;
6889 return;
6890 }
6891 } else {
6893 if (const auto *PreInit =
6894 cast_or_null<DeclStmt>(IfClause->getPreInitStmt())) {
6895 for (const auto *I : PreInit->decls()) {
6896 if (!I->hasAttr<OMPCaptureNoInitAttr>()) {
6897 CGF.EmitVarDecl(cast<VarDecl>(*I));
6898 } else {
6901 CGF.EmitAutoVarCleanups(Emission);
6902 }
6903 }
6904 *CondVal = CGF.EvaluateExprAsBool(CondExpr);
6905 }
6906 }
6907 }
6908 }
6909 // Check the value of num_threads clause iff if clause was not specified
6910 // or is not evaluated to false.
6911 if (Dir->hasClausesOfKind<OMPNumThreadsClause>()) {
6912 CGOpenMPInnerExprInfo CGInfo(CGF, *CS);
6913 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
6914 const auto *NumThreadsClause =
6915 Dir->getSingleClause<OMPNumThreadsClause>();
6916 const Expr *NTExpr = NumThreadsClause->getNumThreads().front();
6917 if (NTExpr->isIntegerConstantExpr(CGF.getContext()))
6918 if (auto Constant = NTExpr->getIntegerConstantExpr(CGF.getContext()))
6920 UpperBound, static_cast<int32_t>(Constant->getZExtValue()));
6921 // If we haven't found a upper bound, remember we saw a thread limiting
6922 // clause.
6923 if (UpperBound == -1)
6924 UpperBound = 0;
6925 if (!E)
6926 return;
6927 CodeGenFunction::LexicalScope Scope(CGF, NTExpr->getSourceRange());
6928 if (const auto *PreInit =
6929 cast_or_null<DeclStmt>(NumThreadsClause->getPreInitStmt())) {
6930 for (const auto *I : PreInit->decls()) {
6931 if (!I->hasAttr<OMPCaptureNoInitAttr>()) {
6932 CGF.EmitVarDecl(cast<VarDecl>(*I));
6933 } else {
6936 CGF.EmitAutoVarCleanups(Emission);
6937 }
6938 }
6939 }
6940 *E = NTExpr;
6941 }
6942 return;
6943 }
6944 if (isOpenMPSimdDirective(Dir->getDirectiveKind()))
6945 UpperBound = 1;
6946}
6947
6949 CodeGenFunction &CGF, const OMPExecutableDirective &D, int32_t &UpperBound,
6950 bool UpperBoundOnly, llvm::Value **CondVal, const Expr **ThreadLimitExpr) {
6951 assert((!CGF.getLangOpts().OpenMPIsTargetDevice || UpperBoundOnly) &&
6952 "Clauses associated with the teams directive expected to be emitted "
6953 "only for the host!");
6954 OpenMPDirectiveKind DirectiveKind = D.getDirectiveKind();
6955 assert(isOpenMPTargetExecutionDirective(DirectiveKind) &&
6956 "Expected target-based executable directive.");
6957
6958 const Expr *NT = nullptr;
6959 const Expr **NTPtr = UpperBoundOnly ? nullptr : &NT;
6960
6961 auto CheckForConstExpr = [&](const Expr *E, const Expr **EPtr) {
6962 if (E->isIntegerConstantExpr(CGF.getContext())) {
6963 if (auto Constant = E->getIntegerConstantExpr(CGF.getContext()))
6965 UpperBound, static_cast<int32_t>(Constant->getZExtValue()));
6966 }
6967 // If we haven't found a upper bound, remember we saw a thread limiting
6968 // clause.
6969 if (UpperBound == -1)
6970 UpperBound = 0;
6971 if (EPtr)
6972 *EPtr = E;
6973 };
6974
6975 auto ReturnSequential = [&]() {
6976 UpperBound = 1;
6977 return NT;
6978 };
6979
6980 switch (DirectiveKind) {
6981 case OMPD_target: {
6982 const CapturedStmt *CS = D.getInnermostCapturedStmt();
6983 getNumThreads(CGF, CS, NTPtr, UpperBound, UpperBoundOnly, CondVal);
6985 CGF.getContext(), CS->getCapturedStmt());
6986 // TODO: The standard is not clear how to resolve two thread limit clauses,
6987 // let's pick the teams one if it's present, otherwise the target one.
6988 const auto *ThreadLimitClause = D.getSingleClause<OMPThreadLimitClause>();
6989 if (const auto *Dir = dyn_cast_or_null<OMPExecutableDirective>(Child)) {
6990 if (const auto *TLC = Dir->getSingleClause<OMPThreadLimitClause>()) {
6991 ThreadLimitClause = TLC;
6992 if (ThreadLimitExpr) {
6993 CGOpenMPInnerExprInfo CGInfo(CGF, *CS);
6994 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
6996 CGF,
6997 ThreadLimitClause->getThreadLimit().front()->getSourceRange());
6998 if (const auto *PreInit =
6999 cast_or_null<DeclStmt>(ThreadLimitClause->getPreInitStmt())) {
7000 for (const auto *I : PreInit->decls()) {
7001 if (!I->hasAttr<OMPCaptureNoInitAttr>()) {
7002 CGF.EmitVarDecl(cast<VarDecl>(*I));
7003 } else {
7006 CGF.EmitAutoVarCleanups(Emission);
7007 }
7008 }
7009 }
7010 }
7011 }
7012 }
7013 if (ThreadLimitClause)
7014 CheckForConstExpr(ThreadLimitClause->getThreadLimit().front(),
7015 ThreadLimitExpr);
7016 if (const auto *Dir = dyn_cast_or_null<OMPExecutableDirective>(Child)) {
7017 if (isOpenMPTeamsDirective(Dir->getDirectiveKind()) &&
7018 !isOpenMPDistributeDirective(Dir->getDirectiveKind())) {
7019 CS = Dir->getInnermostCapturedStmt();
7020 // Now that the 'teams' level has been peeled off, the remainder is
7021 // shaped like a 'target teams' region, so pick up the num_threads of
7022 // the directive nested in it the same way the OMPD_target_teams case
7023 // below does. Without this the upper bound of a construct written as
7024 // 'target' / 'teams' / 'distribute parallel for' would stay at the
7025 // default, while every combined spelling of the same construct honors
7026 // the clause. Only the bound is taken here: passing null for the
7027 // expression and the condition keeps this from emitting anything, so
7028 // the value the host passes to the kernel launch is left as it was.
7029 getNumThreads(CGF, CS, /*E=*/nullptr, UpperBound, UpperBoundOnly,
7030 /*CondVal=*/nullptr);
7032 CGF.getContext(), CS->getCapturedStmt());
7033 Dir = dyn_cast_or_null<OMPExecutableDirective>(Child);
7034 }
7035 if (Dir && isOpenMPParallelDirective(Dir->getDirectiveKind())) {
7036 CS = Dir->getInnermostCapturedStmt();
7037 getNumThreads(CGF, CS, NTPtr, UpperBound, UpperBoundOnly, CondVal);
7038 } else if (Dir && isOpenMPSimdDirective(Dir->getDirectiveKind()))
7039 return ReturnSequential();
7040 }
7041 return NT;
7042 }
7043 case OMPD_target_teams: {
7044 if (D.hasClausesOfKind<OMPThreadLimitClause>()) {
7045 CodeGenFunction::RunCleanupsScope ThreadLimitScope(CGF);
7046 const auto *ThreadLimitClause = D.getSingleClause<OMPThreadLimitClause>();
7047 CheckForConstExpr(ThreadLimitClause->getThreadLimit().front(),
7048 ThreadLimitExpr);
7049 }
7050 const CapturedStmt *CS = D.getInnermostCapturedStmt();
7051 getNumThreads(CGF, CS, NTPtr, UpperBound, UpperBoundOnly, CondVal);
7053 CGF.getContext(), CS->getCapturedStmt());
7054 if (const auto *Dir = dyn_cast_or_null<OMPExecutableDirective>(Child)) {
7055 if (Dir->getDirectiveKind() == OMPD_distribute) {
7056 CS = Dir->getInnermostCapturedStmt();
7057 getNumThreads(CGF, CS, NTPtr, UpperBound, UpperBoundOnly, CondVal);
7058 }
7059 }
7060 return NT;
7061 }
7062 case OMPD_target_teams_distribute:
7063 if (D.hasClausesOfKind<OMPThreadLimitClause>()) {
7064 CodeGenFunction::RunCleanupsScope ThreadLimitScope(CGF);
7065 const auto *ThreadLimitClause = D.getSingleClause<OMPThreadLimitClause>();
7066 CheckForConstExpr(ThreadLimitClause->getThreadLimit().front(),
7067 ThreadLimitExpr);
7068 }
7069 getNumThreads(CGF, D.getInnermostCapturedStmt(), NTPtr, UpperBound,
7070 UpperBoundOnly, CondVal);
7071 return NT;
7072 case OMPD_target_teams_loop:
7073 case OMPD_target_parallel_loop:
7074 case OMPD_target_parallel:
7075 case OMPD_target_parallel_for:
7076 case OMPD_target_parallel_for_simd:
7077 case OMPD_target_teams_distribute_parallel_for:
7078 case OMPD_target_teams_distribute_parallel_for_simd: {
7079 if (CondVal && D.hasClausesOfKind<OMPIfClause>()) {
7080 const OMPIfClause *IfClause = nullptr;
7081 for (const auto *C : D.getClausesOfKind<OMPIfClause>()) {
7082 if (C->getNameModifier() == OMPD_unknown ||
7083 C->getNameModifier() == OMPD_parallel) {
7084 IfClause = C;
7085 break;
7086 }
7087 }
7088 if (IfClause) {
7089 const Expr *Cond = IfClause->getCondition();
7090 bool Result;
7091 if (Cond->EvaluateAsBooleanCondition(Result, CGF.getContext())) {
7092 if (!Result)
7093 return ReturnSequential();
7094 } else {
7096 *CondVal = CGF.EvaluateExprAsBool(Cond);
7097 }
7098 }
7099 }
7100 if (D.hasClausesOfKind<OMPThreadLimitClause>()) {
7101 CodeGenFunction::RunCleanupsScope ThreadLimitScope(CGF);
7102 const auto *ThreadLimitClause = D.getSingleClause<OMPThreadLimitClause>();
7103 CheckForConstExpr(ThreadLimitClause->getThreadLimit().front(),
7104 ThreadLimitExpr);
7105 }
7106 if (D.hasClausesOfKind<OMPNumThreadsClause>()) {
7107 CodeGenFunction::RunCleanupsScope NumThreadsScope(CGF);
7108 const auto *NumThreadsClause = D.getSingleClause<OMPNumThreadsClause>();
7109 CheckForConstExpr(NumThreadsClause->getNumThreads().front(), nullptr);
7110 return NumThreadsClause->getNumThreads().front();
7111 }
7112 return NT;
7113 }
7114 case OMPD_target_teams_distribute_simd:
7115 case OMPD_target_simd:
7116 return ReturnSequential();
7117 default:
7118 break;
7119 }
7120 llvm_unreachable("Unsupported directive kind.");
7121}
7122
7124 CodeGenFunction &CGF, const OMPExecutableDirective &D) {
7125 llvm::Value *NumThreadsVal = nullptr;
7126 llvm::Value *CondVal = nullptr;
7127 llvm::Value *ThreadLimitVal = nullptr;
7128 const Expr *ThreadLimitExpr = nullptr;
7129 int32_t UpperBound = -1;
7130
7132 CGF, D, UpperBound, /* UpperBoundOnly */ false, &CondVal,
7133 &ThreadLimitExpr);
7134
7135 // Thread limit expressions are used below, emit them.
7136 if (ThreadLimitExpr) {
7137 ThreadLimitVal =
7138 CGF.EmitScalarExpr(ThreadLimitExpr, /*IgnoreResultAssign=*/true);
7139 ThreadLimitVal = CGF.Builder.CreateIntCast(ThreadLimitVal, CGF.Int32Ty,
7140 /*isSigned=*/false);
7141 }
7142
7143 // Generate the num teams expression.
7144 if (UpperBound == 1) {
7145 NumThreadsVal = CGF.Builder.getInt32(UpperBound);
7146 } else if (NT) {
7147 NumThreadsVal = CGF.EmitScalarExpr(NT, /*IgnoreResultAssign=*/true);
7148 NumThreadsVal = CGF.Builder.CreateIntCast(NumThreadsVal, CGF.Int32Ty,
7149 /*isSigned=*/false);
7150 } else if (ThreadLimitVal) {
7151 // If we do not have a num threads value but a thread limit, replace the
7152 // former with the latter. We know handled the thread limit expression.
7153 NumThreadsVal = ThreadLimitVal;
7154 ThreadLimitVal = nullptr;
7155 } else {
7156 // Default to "0" which means runtime choice.
7157 assert(!ThreadLimitVal && "Default not applicable with thread limit value");
7158 NumThreadsVal = CGF.Builder.getInt32(0);
7159 }
7160
7161 // Handle if clause. If if clause present, the number of threads is
7162 // calculated as <cond> ? (<numthreads> ? <numthreads> : 0 ) : 1.
7163 if (CondVal) {
7165 NumThreadsVal = CGF.Builder.CreateSelect(CondVal, NumThreadsVal,
7166 CGF.Builder.getInt32(1));
7167 }
7168
7169 // If the thread limit and num teams expression were present, take the
7170 // minimum.
7171 if (ThreadLimitVal) {
7172 NumThreadsVal = CGF.Builder.CreateSelect(
7173 CGF.Builder.CreateICmpULT(ThreadLimitVal, NumThreadsVal),
7174 ThreadLimitVal, NumThreadsVal);
7175 }
7176
7177 return NumThreadsVal;
7178}
7179
7180namespace {
7182
7183// Utility to handle information from clauses associated with a given
7184// construct that use mappable expressions (e.g. 'map' clause, 'to' clause).
7185// It provides a convenient interface to obtain the information and generate
7186// code for that information.
7187class MappableExprsHandler {
7188public:
7189 /// Custom comparator for attach-pointer expressions that compares them by
7190 /// complexity (i.e. their component-depth) first, then by the order in which
7191 /// they were computed by collectAttachPtrExprInfo(), if they are semantically
7192 /// different.
7193 struct AttachPtrExprComparator {
7194 const MappableExprsHandler &Handler;
7195 // Cache of previous equality comparison results.
7196 mutable llvm::DenseMap<std::pair<const Expr *, const Expr *>, bool>
7197 CachedEqualityComparisons;
7198
7199 AttachPtrExprComparator(const MappableExprsHandler &H) : Handler(H) {}
7200 AttachPtrExprComparator() = delete;
7201
7202 // Return true iff LHS is "less than" RHS.
7203 bool operator()(const Expr *LHS, const Expr *RHS) const {
7204 if (LHS == RHS)
7205 return false;
7206
7207 // First, compare by complexity (depth)
7208 const auto ItLHS = Handler.AttachPtrComponentDepthMap.find(LHS);
7209 const auto ItRHS = Handler.AttachPtrComponentDepthMap.find(RHS);
7210
7211 std::optional<size_t> DepthLHS =
7212 (ItLHS != Handler.AttachPtrComponentDepthMap.end()) ? ItLHS->second
7213 : std::nullopt;
7214 std::optional<size_t> DepthRHS =
7215 (ItRHS != Handler.AttachPtrComponentDepthMap.end()) ? ItRHS->second
7216 : std::nullopt;
7217
7218 // std::nullopt (no attach pointer) has lowest complexity
7219 if (!DepthLHS.has_value() && !DepthRHS.has_value()) {
7220 // Both have same complexity, now check semantic equality
7221 if (areEqual(LHS, RHS))
7222 return false;
7223 // Different semantically, compare by computation order
7224 return wasComputedBefore(LHS, RHS);
7225 }
7226 if (!DepthLHS.has_value())
7227 return true; // LHS has lower complexity
7228 if (!DepthRHS.has_value())
7229 return false; // RHS has lower complexity
7230
7231 // Both have values, compare by depth (lower depth = lower complexity)
7232 if (DepthLHS.value() != DepthRHS.value())
7233 return DepthLHS.value() < DepthRHS.value();
7234
7235 // Same complexity, now check semantic equality
7236 if (areEqual(LHS, RHS))
7237 return false;
7238 // Different semantically, compare by computation order
7239 return wasComputedBefore(LHS, RHS);
7240 }
7241
7242 public:
7243 /// Return true if \p LHS and \p RHS are semantically equal. Uses pre-cached
7244 /// results, if available, otherwise does a recursive semantic comparison.
7245 bool areEqual(const Expr *LHS, const Expr *RHS) const {
7246 // Check cache first for faster lookup
7247 const auto CachedResultIt = CachedEqualityComparisons.find({LHS, RHS});
7248 if (CachedResultIt != CachedEqualityComparisons.end())
7249 return CachedResultIt->second;
7250
7251 bool ComparisonResult = areSemanticallyEqual(LHS, RHS);
7252
7253 // Cache the result for future lookups (both orders since semantic
7254 // equality is commutative)
7255 CachedEqualityComparisons[{LHS, RHS}] = ComparisonResult;
7256 CachedEqualityComparisons[{RHS, LHS}] = ComparisonResult;
7257 return ComparisonResult;
7258 }
7259
7260 /// Compare the two attach-ptr expressions by their computation order.
7261 /// Returns true iff LHS was computed before RHS by
7262 /// collectAttachPtrExprInfo().
7263 bool wasComputedBefore(const Expr *LHS, const Expr *RHS) const {
7264 const size_t &OrderLHS = Handler.AttachPtrComputationOrderMap.at(LHS);
7265 const size_t &OrderRHS = Handler.AttachPtrComputationOrderMap.at(RHS);
7266
7267 return OrderLHS < OrderRHS;
7268 }
7269
7270 private:
7271 /// Helper function to compare attach-pointer expressions semantically.
7272 /// This function handles various expression types that can be part of an
7273 /// attach-pointer.
7274 /// TODO: Not urgent, but we should ideally return true when comparing
7275 /// `p[10]`, `*(p + 10)`, `*(p + 5 + 5)`, `p[10:1]` etc.
7276 bool areSemanticallyEqual(const Expr *LHS, const Expr *RHS) const {
7277 if (LHS == RHS)
7278 return true;
7279
7280 // If only one is null, they aren't equal
7281 if (!LHS || !RHS)
7282 return false;
7283
7284 ASTContext &Ctx = Handler.CGF.getContext();
7285 // Strip away parentheses and no-op casts to get to the core expression
7286 LHS = LHS->IgnoreParenNoopCasts(Ctx);
7287 RHS = RHS->IgnoreParenNoopCasts(Ctx);
7288
7289 // Direct pointer comparison of the underlying expressions
7290 if (LHS == RHS)
7291 return true;
7292
7293 // Check if the expression classes match
7294 if (LHS->getStmtClass() != RHS->getStmtClass())
7295 return false;
7296
7297 // Handle DeclRefExpr (variable references)
7298 if (const auto *LD = dyn_cast<DeclRefExpr>(LHS)) {
7299 const auto *RD = dyn_cast<DeclRefExpr>(RHS);
7300 if (!RD)
7301 return false;
7302 return LD->getDecl()->getCanonicalDecl() ==
7303 RD->getDecl()->getCanonicalDecl();
7304 }
7305
7306 // Handle ArraySubscriptExpr (array indexing like a[i])
7307 if (const auto *LA = dyn_cast<ArraySubscriptExpr>(LHS)) {
7308 const auto *RA = dyn_cast<ArraySubscriptExpr>(RHS);
7309 if (!RA)
7310 return false;
7311 return areSemanticallyEqual(LA->getBase(), RA->getBase()) &&
7312 areSemanticallyEqual(LA->getIdx(), RA->getIdx());
7313 }
7314
7315 // Handle MemberExpr (member access like s.m or p->m)
7316 if (const auto *LM = dyn_cast<MemberExpr>(LHS)) {
7317 const auto *RM = dyn_cast<MemberExpr>(RHS);
7318 if (!RM)
7319 return false;
7320 if (LM->getMemberDecl()->getCanonicalDecl() !=
7321 RM->getMemberDecl()->getCanonicalDecl())
7322 return false;
7323 return areSemanticallyEqual(LM->getBase(), RM->getBase());
7324 }
7325
7326 // Handle UnaryOperator (unary operations like *p, &x, etc.)
7327 if (const auto *LU = dyn_cast<UnaryOperator>(LHS)) {
7328 const auto *RU = dyn_cast<UnaryOperator>(RHS);
7329 if (!RU)
7330 return false;
7331 if (LU->getOpcode() != RU->getOpcode())
7332 return false;
7333 return areSemanticallyEqual(LU->getSubExpr(), RU->getSubExpr());
7334 }
7335
7336 // Handle BinaryOperator (binary operations like p + offset)
7337 if (const auto *LB = dyn_cast<BinaryOperator>(LHS)) {
7338 const auto *RB = dyn_cast<BinaryOperator>(RHS);
7339 if (!RB)
7340 return false;
7341 if (LB->getOpcode() != RB->getOpcode())
7342 return false;
7343 return areSemanticallyEqual(LB->getLHS(), RB->getLHS()) &&
7344 areSemanticallyEqual(LB->getRHS(), RB->getRHS());
7345 }
7346
7347 // Handle ArraySectionExpr (array sections like a[0:1])
7348 // Attach pointers should not contain array-sections, but currently we
7349 // don't emit an error.
7350 if (const auto *LAS = dyn_cast<ArraySectionExpr>(LHS)) {
7351 const auto *RAS = dyn_cast<ArraySectionExpr>(RHS);
7352 if (!RAS)
7353 return false;
7354 return areSemanticallyEqual(LAS->getBase(), RAS->getBase()) &&
7355 areSemanticallyEqual(LAS->getLowerBound(),
7356 RAS->getLowerBound()) &&
7357 areSemanticallyEqual(LAS->getLength(), RAS->getLength());
7358 }
7359
7360 // Handle CastExpr (explicit casts)
7361 if (const auto *LC = dyn_cast<CastExpr>(LHS)) {
7362 const auto *RC = dyn_cast<CastExpr>(RHS);
7363 if (!RC)
7364 return false;
7365 if (LC->getCastKind() != RC->getCastKind())
7366 return false;
7367 return areSemanticallyEqual(LC->getSubExpr(), RC->getSubExpr());
7368 }
7369
7370 // Handle CXXThisExpr (this pointer)
7371 if (isa<CXXThisExpr>(LHS) && isa<CXXThisExpr>(RHS))
7372 return true;
7373
7374 // Handle IntegerLiteral (integer constants)
7375 if (const auto *LI = dyn_cast<IntegerLiteral>(LHS)) {
7376 const auto *RI = dyn_cast<IntegerLiteral>(RHS);
7377 if (!RI)
7378 return false;
7379 return LI->getValue() == RI->getValue();
7380 }
7381
7382 // Handle CharacterLiteral (character constants)
7383 if (const auto *LC = dyn_cast<CharacterLiteral>(LHS)) {
7384 const auto *RC = dyn_cast<CharacterLiteral>(RHS);
7385 if (!RC)
7386 return false;
7387 return LC->getValue() == RC->getValue();
7388 }
7389
7390 // Handle FloatingLiteral (floating point constants)
7391 if (const auto *LF = dyn_cast<FloatingLiteral>(LHS)) {
7392 const auto *RF = dyn_cast<FloatingLiteral>(RHS);
7393 if (!RF)
7394 return false;
7395 // Use bitwise comparison for floating point literals
7396 return LF->getValue().bitwiseIsEqual(RF->getValue());
7397 }
7398
7399 // Handle StringLiteral (string constants)
7400 if (const auto *LS = dyn_cast<StringLiteral>(LHS)) {
7401 const auto *RS = dyn_cast<StringLiteral>(RHS);
7402 if (!RS)
7403 return false;
7404 return LS->getString() == RS->getString();
7405 }
7406
7407 // Handle CXXNullPtrLiteralExpr (nullptr)
7409 return true;
7410
7411 // Handle CXXBoolLiteralExpr (true/false)
7412 if (const auto *LB = dyn_cast<CXXBoolLiteralExpr>(LHS)) {
7413 const auto *RB = dyn_cast<CXXBoolLiteralExpr>(RHS);
7414 if (!RB)
7415 return false;
7416 return LB->getValue() == RB->getValue();
7417 }
7418
7419 // Fallback for other forms - use the existing comparison method
7420 return Expr::isSameComparisonOperand(LHS, RHS);
7421 }
7422 };
7423
7424 /// Get the offset of the OMP_MAP_MEMBER_OF field.
7425 static unsigned getFlagMemberOffset() {
7426 unsigned Offset = 0;
7427 for (uint64_t Remain =
7428 static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
7429 OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF);
7430 !(Remain & 1); Remain = Remain >> 1)
7431 Offset++;
7432 return Offset;
7433 }
7434
7435 /// Class that holds debugging information for a data mapping to be passed to
7436 /// the runtime library.
7437 class MappingExprInfo {
7438 /// The variable declaration used for the data mapping.
7439 const ValueDecl *MapDecl = nullptr;
7440 /// The original expression used in the map clause, or null if there is
7441 /// none.
7442 const Expr *MapExpr = nullptr;
7443
7444 public:
7445 MappingExprInfo(const ValueDecl *MapDecl, const Expr *MapExpr = nullptr)
7446 : MapDecl(MapDecl), MapExpr(MapExpr) {}
7447
7448 const ValueDecl *getMapDecl() const { return MapDecl; }
7449 const Expr *getMapExpr() const { return MapExpr; }
7450 };
7451
7452 using DeviceInfoTy = llvm::OpenMPIRBuilder::DeviceInfoTy;
7453 using MapBaseValuesArrayTy = llvm::OpenMPIRBuilder::MapValuesArrayTy;
7454 using MapValuesArrayTy = llvm::OpenMPIRBuilder::MapValuesArrayTy;
7455 using MapFlagsArrayTy = llvm::OpenMPIRBuilder::MapFlagsArrayTy;
7456 using MapDimArrayTy = llvm::OpenMPIRBuilder::MapDimArrayTy;
7457 using MapNonContiguousArrayTy =
7458 llvm::OpenMPIRBuilder::MapNonContiguousArrayTy;
7459 using MapExprsArrayTy = SmallVector<MappingExprInfo, 4>;
7460 using MapValueDeclsArrayTy = SmallVector<const ValueDecl *, 4>;
7461 using MapData =
7463 OpenMPMapClauseKind, ArrayRef<OpenMPMapModifierKind>,
7464 bool /*IsImplicit*/, const ValueDecl *, const Expr *>;
7465 using MapDataArrayTy = SmallVector<MapData, 4>;
7466
7467 /// This structure contains combined information generated for mappable
7468 /// clauses, including base pointers, pointers, sizes, map types, user-defined
7469 /// mappers, and non-contiguous information.
7470 struct MapCombinedInfoTy : llvm::OpenMPIRBuilder::MapInfosTy {
7471 MapExprsArrayTy Exprs;
7472 MapValueDeclsArrayTy Mappers;
7473 MapValueDeclsArrayTy DevicePtrDecls;
7474
7475 /// Append arrays in \a CurInfo.
7476 void append(MapCombinedInfoTy &CurInfo) {
7477 Exprs.append(CurInfo.Exprs.begin(), CurInfo.Exprs.end());
7478 DevicePtrDecls.append(CurInfo.DevicePtrDecls.begin(),
7479 CurInfo.DevicePtrDecls.end());
7480 Mappers.append(CurInfo.Mappers.begin(), CurInfo.Mappers.end());
7481 llvm::OpenMPIRBuilder::MapInfosTy::append(CurInfo);
7482 }
7483 };
7484
7485 /// Map between a struct and the its lowest & highest elements which have been
7486 /// mapped.
7487 /// [ValueDecl *] --> {LE(FieldIndex, Pointer),
7488 /// HE(FieldIndex, Pointer)}
7489 struct StructRangeInfoTy {
7490 MapCombinedInfoTy PreliminaryMapData;
7491 std::pair<unsigned /*FieldIndex*/, Address /*Pointer*/> LowestElem = {
7492 0, Address::invalid()};
7493 std::pair<unsigned /*FieldIndex*/, Address /*Pointer*/> HighestElem = {
7494 0, Address::invalid()};
7497 bool IsArraySection = false;
7498 bool HasCompleteRecord = false;
7499 };
7500
7501 /// A struct to store the attach pointer and pointee information, to be used
7502 /// when emitting an attach entry.
7503 struct AttachInfoTy {
7504 Address AttachPtrAddr = Address::invalid();
7505 Address AttachPteeAddr = Address::invalid();
7506 const ValueDecl *AttachPtrDecl = nullptr;
7507 const Expr *AttachMapExpr = nullptr;
7508
7509 bool isValid() const {
7510 return AttachPtrAddr.isValid() && AttachPteeAddr.isValid();
7511 }
7512 };
7513
7514 /// Check if there's any component list where the attach pointer expression
7515 /// matches the given captured variable.
7516 bool hasAttachEntryForCapturedVar(const ValueDecl *VD) const {
7517 for (const auto &AttachEntry : AttachPtrExprMap) {
7518 if (AttachEntry.second) {
7519 // Check if the attach pointer expression is a DeclRefExpr that
7520 // references the captured variable
7521 if (const auto *DRE = dyn_cast<DeclRefExpr>(AttachEntry.second))
7522 if (DRE->getDecl() == VD)
7523 return true;
7524 }
7525 }
7526 return false;
7527 }
7528
7529 /// Get the previously-cached attach pointer for a component list, if-any.
7530 const Expr *getAttachPtrExpr(
7532 const {
7533 const auto It = AttachPtrExprMap.find(Components);
7534 if (It != AttachPtrExprMap.end())
7535 return It->second;
7536
7537 return nullptr;
7538 }
7539
7540private:
7541 /// Kind that defines how a device pointer has to be returned.
7542 struct MapInfo {
7545 ArrayRef<OpenMPMapModifierKind> MapModifiers;
7546 ArrayRef<OpenMPMotionModifierKind> MotionModifiers;
7547 bool ReturnDevicePointer = false;
7548 bool IsImplicit = false;
7549 const ValueDecl *Mapper = nullptr;
7550 const Expr *VarRef = nullptr;
7551 bool ForDeviceAddr = false;
7552 bool HasUdpFbNullify = false;
7553
7554 MapInfo() = default;
7555 MapInfo(
7557 OpenMPMapClauseKind MapType,
7558 ArrayRef<OpenMPMapModifierKind> MapModifiers,
7559 ArrayRef<OpenMPMotionModifierKind> MotionModifiers,
7560 bool ReturnDevicePointer, bool IsImplicit,
7561 const ValueDecl *Mapper = nullptr, const Expr *VarRef = nullptr,
7562 bool ForDeviceAddr = false, bool HasUdpFbNullify = false)
7563 : Components(Components), MapType(MapType), MapModifiers(MapModifiers),
7564 MotionModifiers(MotionModifiers),
7565 ReturnDevicePointer(ReturnDevicePointer), IsImplicit(IsImplicit),
7566 Mapper(Mapper), VarRef(VarRef), ForDeviceAddr(ForDeviceAddr),
7567 HasUdpFbNullify(HasUdpFbNullify) {}
7568 };
7569
7570 /// The target directive from where the mappable clauses were extracted. It
7571 /// is either a executable directive or a user-defined mapper directive.
7572 llvm::PointerUnion<const OMPExecutableDirective *,
7573 const OMPDeclareMapperDecl *>
7574 CurDir;
7575
7576 /// Function the directive is being generated for.
7577 CodeGenFunction &CGF;
7578
7579 /// Set of all first private variables in the current directive.
7580 /// bool data is set to true if the variable is implicitly marked as
7581 /// firstprivate, false otherwise.
7582 llvm::DenseMap<CanonicalDeclPtr<const VarDecl>, bool> FirstPrivateDecls;
7583
7584 /// Set of defaultmap clause kinds that use firstprivate behavior.
7585 llvm::SmallSet<OpenMPDefaultmapClauseKind, 4> DefaultmapFirstprivateKinds;
7586
7587 /// Map between device pointer declarations and their expression components.
7588 /// The key value for declarations in 'this' is null.
7589 llvm::DenseMap<
7590 const ValueDecl *,
7591 SmallVector<OMPClauseMappableExprCommon::MappableExprComponentListRef, 4>>
7592 DevPointersMap;
7593
7594 /// Map between device addr declarations and their expression components.
7595 /// The key value for declarations in 'this' is null.
7596 llvm::DenseMap<
7597 const ValueDecl *,
7598 SmallVector<OMPClauseMappableExprCommon::MappableExprComponentListRef, 4>>
7599 HasDevAddrsMap;
7600
7601 /// Map between lambda declarations and their map type.
7602 llvm::DenseMap<const ValueDecl *, const OMPMapClause *> LambdasMap;
7603
7604 /// Map from component lists to their attach pointer expressions.
7606 const Expr *>
7607 AttachPtrExprMap;
7608
7609 /// Map from attach pointer expressions to their component depth.
7610 /// nullptr key has std::nullopt depth. This can be used to order attach-ptr
7611 /// expressions with increasing/decreasing depth.
7612 /// The component-depth of `nullptr` (i.e. no attach-ptr) is `std::nullopt`.
7613 /// TODO: Not urgent, but we should ideally use the number of pointer
7614 /// dereferences in an expr as an indicator of its complexity, instead of the
7615 /// component-depth. That would be needed for us to treat `p[1]`, `*(p + 10)`,
7616 /// `*(p + 5 + 5)` together.
7617 llvm::DenseMap<const Expr *, std::optional<size_t>>
7618 AttachPtrComponentDepthMap = {{nullptr, std::nullopt}};
7619
7620 /// Map from attach pointer expressions to the order they were computed in, in
7621 /// collectAttachPtrExprInfo().
7622 llvm::DenseMap<const Expr *, size_t> AttachPtrComputationOrderMap = {
7623 {nullptr, 0}};
7624
7625 /// An instance of attach-ptr-expr comparator that can be used throughout the
7626 /// lifetime of this handler.
7627 AttachPtrExprComparator AttachPtrComparator;
7628
7629 llvm::Value *getExprTypeSize(const Expr *E) const {
7630 QualType ExprTy = E->getType().getCanonicalType();
7631
7632 // Calculate the size for array shaping expression.
7633 if (const auto *OAE = dyn_cast<OMPArrayShapingExpr>(E)) {
7634 llvm::Value *Size =
7635 CGF.getTypeSize(OAE->getBase()->getType()->getPointeeType());
7636 for (const Expr *SE : OAE->getDimensions()) {
7637 llvm::Value *Sz = CGF.EmitScalarExpr(SE);
7638 Sz = CGF.EmitScalarConversion(Sz, SE->getType(),
7639 CGF.getContext().getSizeType(),
7640 SE->getExprLoc());
7641 Size = CGF.Builder.CreateNUWMul(Size, Sz);
7642 }
7643 return Size;
7644 }
7645
7646 // Reference types are ignored for mapping purposes.
7647 if (const auto *RefTy = ExprTy->getAs<ReferenceType>())
7648 ExprTy = RefTy->getPointeeType().getCanonicalType();
7649
7650 // Given that an array section is considered a built-in type, we need to
7651 // do the calculation based on the length of the section instead of relying
7652 // on CGF.getTypeSize(E->getType()).
7653 if (const auto *OAE = dyn_cast<ArraySectionExpr>(E)) {
7654 QualType BaseTy = ArraySectionExpr::getBaseOriginalType(
7655 OAE->getBase()->IgnoreParenImpCasts())
7657
7658 // If there is no length associated with the expression and lower bound is
7659 // not specified too, that means we are using the whole length of the
7660 // base.
7661 if (!OAE->getLength() && OAE->getColonLocFirst().isValid() &&
7662 !OAE->getLowerBound())
7663 return CGF.getTypeSize(BaseTy);
7664
7665 llvm::Value *ElemSize;
7666 if (const auto *PTy = BaseTy->getAs<PointerType>()) {
7667 ElemSize = CGF.getTypeSize(PTy->getPointeeType().getCanonicalType());
7668 } else {
7669 const auto *ATy = cast<ArrayType>(BaseTy.getTypePtr());
7670 assert(ATy && "Expecting array type if not a pointer type.");
7671 ElemSize = CGF.getTypeSize(ATy->getElementType().getCanonicalType());
7672 }
7673
7674 // If we don't have a length at this point, that is because we have an
7675 // array section with a single element.
7676 if (!OAE->getLength() && OAE->getColonLocFirst().isInvalid())
7677 return ElemSize;
7678
7679 if (const Expr *LenExpr = OAE->getLength()) {
7680 llvm::Value *LengthVal = CGF.EmitScalarExpr(LenExpr);
7681 LengthVal = CGF.EmitScalarConversion(LengthVal, LenExpr->getType(),
7682 CGF.getContext().getSizeType(),
7683 LenExpr->getExprLoc());
7684 return CGF.Builder.CreateNUWMul(LengthVal, ElemSize);
7685 }
7686 assert(!OAE->getLength() && OAE->getColonLocFirst().isValid() &&
7687 OAE->getLowerBound() && "expected array_section[lb:].");
7688 // Size = sizetype - lb * elemtype;
7689 llvm::Value *LengthVal = CGF.getTypeSize(BaseTy);
7690 llvm::Value *LBVal = CGF.EmitScalarExpr(OAE->getLowerBound());
7691 LBVal = CGF.EmitScalarConversion(LBVal, OAE->getLowerBound()->getType(),
7692 CGF.getContext().getSizeType(),
7693 OAE->getLowerBound()->getExprLoc());
7694 LBVal = CGF.Builder.CreateNUWMul(LBVal, ElemSize);
7695 llvm::Value *Cmp = CGF.Builder.CreateICmpUGT(LengthVal, LBVal);
7696 llvm::Value *TrueVal = CGF.Builder.CreateNUWSub(LengthVal, LBVal);
7697 LengthVal = CGF.Builder.CreateSelect(
7698 Cmp, TrueVal, llvm::ConstantInt::get(CGF.SizeTy, 0));
7699 return LengthVal;
7700 }
7701 return CGF.getTypeSize(ExprTy);
7702 }
7703
7704 /// Return the corresponding bits for a given map clause modifier. Add
7705 /// a flag marking the map as a pointer if requested. Add a flag marking the
7706 /// map as the first one of a series of maps that relate to the same map
7707 /// expression.
7708 OpenMPOffloadMappingFlags getMapTypeBits(
7709 OpenMPMapClauseKind MapType, ArrayRef<OpenMPMapModifierKind> MapModifiers,
7710 ArrayRef<OpenMPMotionModifierKind> MotionModifiers, bool IsImplicit,
7711 bool AddPtrFlag, bool AddIsTargetParamFlag, bool IsNonContiguous) const {
7712 OpenMPOffloadMappingFlags Bits =
7713 IsImplicit ? OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT
7714 : OpenMPOffloadMappingFlags::OMP_MAP_NONE;
7715 switch (MapType) {
7716 case OMPC_MAP_alloc:
7717 case OMPC_MAP_release:
7718 // alloc and release is the default behavior in the runtime library, i.e.
7719 // if we don't pass any bits alloc/release that is what the runtime is
7720 // going to do. Therefore, we don't need to signal anything for these two
7721 // type modifiers.
7722 break;
7723 case OMPC_MAP_to:
7724 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_TO;
7725 break;
7726 case OMPC_MAP_from:
7727 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_FROM;
7728 break;
7729 case OMPC_MAP_tofrom:
7730 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_TO |
7731 OpenMPOffloadMappingFlags::OMP_MAP_FROM;
7732 break;
7733 case OMPC_MAP_delete:
7734 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_DELETE;
7735 break;
7736 case OMPC_MAP_unknown:
7737 llvm_unreachable("Unexpected map type!");
7738 }
7739 if (AddPtrFlag)
7740 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ;
7741 if (AddIsTargetParamFlag)
7742 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM;
7743 if (llvm::is_contained(MapModifiers, OMPC_MAP_MODIFIER_always))
7744 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_ALWAYS;
7745 if (llvm::is_contained(MapModifiers, OMPC_MAP_MODIFIER_close))
7746 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_CLOSE;
7747 if (llvm::is_contained(MapModifiers, OMPC_MAP_MODIFIER_present) ||
7748 llvm::is_contained(MotionModifiers, OMPC_MOTION_MODIFIER_present))
7749 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_PRESENT;
7750 if (llvm::is_contained(MapModifiers, OMPC_MAP_MODIFIER_ompx_hold))
7751 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_OMPX_HOLD;
7752 if (IsNonContiguous)
7753 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_NON_CONTIG;
7754 return Bits;
7755 }
7756
7757 /// Return true if the provided expression is a final array section. A
7758 /// final array section, is one whose length can't be proved to be one.
7759 bool isFinalArraySectionExpression(const Expr *E) const {
7760 const auto *OASE = dyn_cast<ArraySectionExpr>(E);
7761
7762 // It is not an array section and therefore not a unity-size one.
7763 if (!OASE)
7764 return false;
7765
7766 // An array section with no colon always refer to a single element.
7767 if (OASE->getColonLocFirst().isInvalid())
7768 return false;
7769
7770 const Expr *Length = OASE->getLength();
7771
7772 // If we don't have a length we have to check if the array has size 1
7773 // for this dimension. Also, we should always expect a length if the
7774 // base type is pointer.
7775 if (!Length) {
7776 QualType BaseQTy = ArraySectionExpr::getBaseOriginalType(
7777 OASE->getBase()->IgnoreParenImpCasts())
7779 if (const auto *ATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr()))
7780 return ATy->getSExtSize() != 1;
7781 // If we don't have a constant dimension length, we have to consider
7782 // the current section as having any size, so it is not necessarily
7783 // unitary. If it happen to be unity size, that's user fault.
7784 return true;
7785 }
7786
7787 // Check if the length evaluates to 1.
7788 Expr::EvalResult Result;
7789 if (!Length->EvaluateAsInt(Result, CGF.getContext()))
7790 return true; // Can have more that size 1.
7791
7792 llvm::APSInt ConstLength = Result.Val.getInt();
7793 return ConstLength.getSExtValue() != 1;
7794 }
7795
7796 /// Emit an attach entry into \p CombinedInfo, using the information from \p
7797 /// AttachInfo. For example, for a map of form `int *p; ... map(p[1:10])`,
7798 /// an attach entry has the following form:
7799 /// &p, &p[1], sizeof(void*), ATTACH
7800 void emitAttachEntry(CodeGenFunction &CGF, MapCombinedInfoTy &CombinedInfo,
7801 const AttachInfoTy &AttachInfo) const {
7802 assert(AttachInfo.isValid() &&
7803 "Expected valid attach pointer/pointee information!");
7804
7805 // Size is the size of the pointer itself - use pointer size, not BaseDecl
7806 // size
7807 llvm::Value *PointerSize = CGF.Builder.CreateIntCast(
7808 llvm::ConstantInt::get(
7809 CGF.CGM.SizeTy, CGF.getContext()
7811 .getQuantity()),
7812 CGF.Int64Ty, /*isSigned=*/true);
7813
7814 CombinedInfo.Exprs.emplace_back(AttachInfo.AttachPtrDecl,
7815 AttachInfo.AttachMapExpr);
7816 CombinedInfo.BasePointers.push_back(
7817 AttachInfo.AttachPtrAddr.emitRawPointer(CGF));
7818 CombinedInfo.DevicePtrDecls.push_back(nullptr);
7819 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
7820 CombinedInfo.Pointers.push_back(
7821 AttachInfo.AttachPteeAddr.emitRawPointer(CGF));
7822 CombinedInfo.Sizes.push_back(PointerSize);
7823 CombinedInfo.Types.push_back(OpenMPOffloadMappingFlags::OMP_MAP_ATTACH);
7824 // ATTACH entries themselves don't "have" a base attach-ptr.
7825 CombinedInfo.HasAttachPtr.push_back(false);
7826 CombinedInfo.Mappers.push_back(nullptr);
7827 CombinedInfo.NonContigInfo.Dims.push_back(1);
7828 }
7829
7830 /// A helper class to copy structures with overlapped elements, i.e. those
7831 /// which have mappings of both "s" and "s.mem". Consecutive elements that
7832 /// are not explicitly copied have mapping nodes synthesized for them,
7833 /// taking care to avoid generating zero-sized copies.
7834 class CopyOverlappedEntryGaps {
7835 CodeGenFunction &CGF;
7836 MapCombinedInfoTy &CombinedInfo;
7837 OpenMPOffloadMappingFlags Flags = OpenMPOffloadMappingFlags::OMP_MAP_NONE;
7838 const ValueDecl *MapDecl = nullptr;
7839 const Expr *MapExpr = nullptr;
7841 bool IsNonContiguous = false;
7842 uint64_t DimSize = 0;
7843 // These elements track the position as the struct is iterated over
7844 // (in order of increasing element address).
7845 const RecordDecl *LastParent = nullptr;
7846 uint64_t Cursor = 0;
7847 unsigned LastIndex = -1u;
7849
7850 public:
7851 CopyOverlappedEntryGaps(CodeGenFunction &CGF,
7852 MapCombinedInfoTy &CombinedInfo,
7853 OpenMPOffloadMappingFlags Flags,
7854 const ValueDecl *MapDecl, const Expr *MapExpr,
7855 Address BP, Address LB, bool IsNonContiguous,
7856 uint64_t DimSize)
7857 : CGF(CGF), CombinedInfo(CombinedInfo), Flags(Flags), MapDecl(MapDecl),
7858 MapExpr(MapExpr), BP(BP), IsNonContiguous(IsNonContiguous),
7859 DimSize(DimSize), LB(LB) {}
7860
7861 void processField(
7862 const OMPClauseMappableExprCommon::MappableComponent &MC,
7863 const FieldDecl *FD,
7864 llvm::function_ref<LValue(CodeGenFunction &, const MemberExpr *)>
7865 EmitMemberExprBase) {
7866 const RecordDecl *RD = FD->getParent();
7867 const ASTRecordLayout &RL = CGF.getContext().getASTRecordLayout(RD);
7868 uint64_t FieldOffset = RL.getFieldOffset(FD->getFieldIndex());
7869 uint64_t FieldSize =
7871 Address ComponentLB = Address::invalid();
7872
7873 if (FD->getType()->isLValueReferenceType()) {
7874 const auto *ME = cast<MemberExpr>(MC.getAssociatedExpression());
7875 LValue BaseLVal = EmitMemberExprBase(CGF, ME);
7876 ComponentLB =
7877 CGF.EmitLValueForFieldInitialization(BaseLVal, FD).getAddress();
7878 } else {
7879 ComponentLB =
7881 }
7882
7883 if (!LastParent)
7884 LastParent = RD;
7885 if (FD->getParent() == LastParent) {
7886 if (FD->getFieldIndex() != LastIndex + 1)
7887 copyUntilField(FD, ComponentLB);
7888 } else {
7889 LastParent = FD->getParent();
7890 if (((int64_t)FieldOffset - (int64_t)Cursor) > 0)
7891 copyUntilField(FD, ComponentLB);
7892 }
7893 Cursor = FieldOffset + FieldSize;
7894 LastIndex = FD->getFieldIndex();
7895 LB = CGF.Builder.CreateConstGEP(ComponentLB, 1);
7896 }
7897
7898 void copyUntilField(const FieldDecl *FD, Address ComponentLB) {
7899 llvm::Value *ComponentLBPtr = ComponentLB.emitRawPointer(CGF);
7900 llvm::Value *LBPtr = LB.emitRawPointer(CGF);
7901 llvm::Value *Size = CGF.Builder.CreatePtrDiff(ComponentLBPtr, LBPtr);
7902 copySizedChunk(LBPtr, Size);
7903 }
7904
7905 void copyUntilEnd(Address HB) {
7906 if (LastParent) {
7907 const ASTRecordLayout &RL =
7908 CGF.getContext().getASTRecordLayout(LastParent);
7909 if ((uint64_t)CGF.getContext().toBits(RL.getSize()) <= Cursor)
7910 return;
7911 }
7912 llvm::Value *LBPtr = LB.emitRawPointer(CGF);
7913 llvm::Value *Size = CGF.Builder.CreatePtrDiff(
7914 CGF.Builder.CreateConstGEP(HB, 1).emitRawPointer(CGF), LBPtr);
7915 copySizedChunk(LBPtr, Size);
7916 }
7917
7918 void copySizedChunk(llvm::Value *Base, llvm::Value *Size) {
7919 CombinedInfo.Exprs.emplace_back(MapDecl, MapExpr);
7920 CombinedInfo.BasePointers.push_back(BP.emitRawPointer(CGF));
7921 CombinedInfo.DevicePtrDecls.push_back(nullptr);
7922 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
7923 CombinedInfo.Pointers.push_back(Base);
7924 CombinedInfo.Sizes.push_back(
7925 CGF.Builder.CreateIntCast(Size, CGF.Int64Ty, /*isSigned=*/false));
7926 CombinedInfo.Types.push_back(Flags);
7927 CombinedInfo.HasAttachPtr.push_back(false);
7928 CombinedInfo.Mappers.push_back(nullptr);
7929 CombinedInfo.NonContigInfo.Dims.push_back(IsNonContiguous ? DimSize : 1);
7930 }
7931 };
7932
7933 /// Generate the base pointers, section pointers, sizes, map type bits, and
7934 /// user-defined mappers (all included in \a CombinedInfo) for the provided
7935 /// map type, map or motion modifiers, and expression components.
7936 /// \a IsFirstComponent should be set to true if the provided set of
7937 /// components is the first associated with a capture.
7938 void generateInfoForComponentList(
7939 OpenMPMapClauseKind MapType, ArrayRef<OpenMPMapModifierKind> MapModifiers,
7940 ArrayRef<OpenMPMotionModifierKind> MotionModifiers,
7942 MapCombinedInfoTy &CombinedInfo,
7943 MapCombinedInfoTy &StructBaseCombinedInfo,
7944 StructRangeInfoTy &PartialStruct, AttachInfoTy &AttachInfo,
7945 bool IsFirstComponentList, bool IsImplicit,
7946 bool GenerateAllInfoForClauses, const ValueDecl *Mapper = nullptr,
7947 bool ForDeviceAddr = false, const ValueDecl *BaseDecl = nullptr,
7948 const Expr *MapExpr = nullptr,
7949 ArrayRef<OMPClauseMappableExprCommon::MappableExprComponentListRef>
7950 OverlappedElements = {}) const {
7951
7952 // The following summarizes what has to be generated for each map and the
7953 // types below. The generated information is expressed in this order:
7954 // base pointer, section pointer, size, flags
7955 // (to add to the ones that come from the map type and modifier).
7956 // Entries annotated with (+) are only generated for "target" constructs,
7957 // and only if the variable at the beginning of the expression is used in
7958 // the region.
7959 //
7960 // double d;
7961 // int i[100];
7962 // float *p;
7963 // int **a = &i;
7964 //
7965 // struct S1 {
7966 // int i;
7967 // float f[50];
7968 // }
7969 // struct S2 {
7970 // int i;
7971 // float f[50];
7972 // S1 s;
7973 // double *p;
7974 // double *&pref;
7975 // struct S2 *ps;
7976 // int &ref;
7977 // }
7978 // S2 s;
7979 // S2 *ps;
7980 //
7981 // map(d)
7982 // &d, &d, sizeof(double), TARGET_PARAM | TO | FROM
7983 //
7984 // map(i)
7985 // &i, &i, 100*sizeof(int), TARGET_PARAM | TO | FROM
7986 //
7987 // map(i[1:23])
7988 // &i(=&i[0]), &i[1], 23*sizeof(int), TARGET_PARAM | TO | FROM
7989 //
7990 // map(p)
7991 // &p, &p, sizeof(float*), TARGET_PARAM | TO | FROM
7992 //
7993 // map(p[1:24])
7994 // p, &p[1], 24*sizeof(float), TARGET_PARAM | TO | FROM // map pointee
7995 // &p, &p[1], sizeof(void*), ATTACH // attach pointer/pointee, if both
7996 // // are present, and either is new
7997 //
7998 // map(([22])p)
7999 // p, p, 22*sizeof(float), TARGET_PARAM | TO | FROM
8000 // &p, p, sizeof(void*), ATTACH
8001 //
8002 // map((*a)[0:3])
8003 // a, a, 0, TARGET_PARAM | IMPLICIT // (+)
8004 // (*a)[0], &(*a)[0], 3 * sizeof(int), TO | FROM
8005 // &(*a), &(*a)[0], sizeof(void*), ATTACH
8006 // (+) Only on target, if a is used in the region
8007 // Note: Since the attach base-pointer is `*a`, which is not a scalar
8008 // variable, it doesn't determine the clause on `a`. `a` is mapped using
8009 // a zero-length-array-section map by generateDefaultMapInfo, if it is
8010 // referenced in the target region, because it is a pointer.
8011 //
8012 // map(**a)
8013 // a, a, 0, TARGET_PARAM | IMPLICIT // (+)
8014 // &(*a)[0], &(*a)[0], sizeof(int), TO | FROM
8015 // &(*a), &(*a)[0], sizeof(void*), ATTACH
8016 // (+) Only on target, if a is used in the region
8017 //
8018 // map(s)
8019 // FIXME: This needs to also imply map(ref_ptr_ptee: s.ref), since the
8020 // effect is supposed to be same as if the user had a map for every element
8021 // of the struct. We currently do a shallow-map of s.
8022 // &s, &s, sizeof(S2), TARGET_PARAM | TO | FROM
8023 //
8024 // map(s.i)
8025 // &s, &(s.i), sizeof(int), TARGET_PARAM | TO | FROM
8026 //
8027 // map(s.s.f)
8028 // &s, &(s.s.f[0]), 50*sizeof(float), TARGET_PARAM | TO | FROM
8029 //
8030 // map(s.p)
8031 // &s, &(s.p), sizeof(double*), TARGET_PARAM | TO | FROM
8032 //
8033 // map(to: s.p[:22])
8034 // &s, &(s.p), sizeof(double*), TARGET_PARAM | IMPLICIT // (+)
8035 // &(s.p[0]), &(s.p[0]), 22 * sizeof(double*), TO | FROM
8036 // &(s.p), &(s.p[0]), sizeof(void*), ATTACH
8037 //
8038 // map(to: s.ref)
8039 // &s, &(ptr(s.ref)), sizeof(int*), TARGET_PARAM (*)
8040 // &s, &(ptee(s.ref)), sizeof(int), MEMBER_OF(1) | PTR_AND_OBJ | TO (***)
8041 // (*) alloc space for struct members, only this is a target parameter.
8042 // (**) map the pointer (nothing to be mapped in this example) (the compiler
8043 // optimizes this entry out, same in the examples below)
8044 // (***) map the pointee (map: to)
8045 // Note: ptr(s.ref) represents the referring pointer of s.ref
8046 // ptee(s.ref) represents the referenced pointee of s.ref
8047 //
8048 // map(to: s.pref)
8049 // &s, &(ptr(s.pref)), sizeof(double**), TARGET_PARAM
8050 // &s, &(ptee(s.pref)), sizeof(double*), MEMBER_OF(1) | PTR_AND_OBJ | TO
8051 //
8052 // map(to: s.pref[:22])
8053 // &s, &(ptr(s.pref)), sizeof(double**), TARGET_PARAM | IMPLICIT // (+)
8054 // &s, &(ptee(s.pref)), sizeof(double*), MEMBER_OF(1) | PTR_AND_OBJ | TO |
8055 // FROM | IMPLICIT // (+)
8056 // &(ptee(s.pref)[0]), &(ptee(s.pref)[0]), 22 * sizeof(double), TO
8057 // &(ptee(s.pref)), &(ptee(s.pref)[0]), sizeof(void*), ATTACH
8058 //
8059 // map(s.ps)
8060 // &s, &(s.ps), sizeof(S2*), TARGET_PARAM | TO | FROM
8061 //
8062 // map(from: s.ps->s.i)
8063 // &s, &(s.ps), sizeof(S2*), TARGET_PARAM | TO | FROM | IMPLICIT // (+)
8064 // &(s.ps[0]), &(s.ps->s.i), sizeof(int), FROM
8065 // &(s.ps), &(s.ps->s.i), sizeof(void*), ATTACH
8066 //
8067 // map(to: s.ps->ps)
8068 // &s, &(s.ps), sizeof(S2*), TARGET_PARAM | TO | FROM | IMPLICIT // (+)
8069 // &(s.ps[0]), &(s.ps->ps), sizeof(S2*), TO
8070 // &(s.ps), &(s.ps->ps), sizeof(void*), ATTACH
8071 //
8072 // map(s.ps->ps->ps)
8073 // &s, &(s.ps), sizeof(S2*), TARGET_PARAM | TO | FROM | IMPLICIT // (+)
8074 // &(s.ps->ps[0]), &(s.ps->ps->ps), sizeof(S2*), TO
8075 // &(s.ps->ps), &(s.ps->ps->ps), sizeof(void*), ATTACH
8076 //
8077 // map(to: s.ps->ps->s.f[:22])
8078 // &s, &(s.ps), sizeof(S2*), TARGET_PARAM | TO | FROM | IMPLICIT // (+)
8079 // &(s.ps->ps[0]), &(s.ps->ps->s.f[0]), 22*sizeof(float), TO
8080 // &(s.ps->ps), &(s.ps->ps->s.f[0]), sizeof(void*), ATTACH
8081 //
8082 // map(ps)
8083 // &ps, &ps, sizeof(S2*), TARGET_PARAM | TO | FROM
8084 //
8085 // map(ps->i)
8086 // ps, &(ps->i), sizeof(int), TARGET_PARAM | TO | FROM
8087 // &ps, &(ps->i), sizeof(void*), ATTACH
8088 //
8089 // map(ps->s.f)
8090 // ps, &(ps->s.f[0]), 50*sizeof(float), TARGET_PARAM | TO | FROM
8091 // &ps, &(ps->s.f[0]), sizeof(ps), ATTACH
8092 //
8093 // map(from: ps->p)
8094 // ps, &(ps->p), sizeof(double*), TARGET_PARAM | FROM
8095 // &ps, &(ps->p), sizeof(ps), ATTACH
8096 //
8097 // map(to: ps->p[:22])
8098 // ps, &(ps[0]), 0, TARGET_PARAM | IMPLICIT // (+)
8099 // &(ps->p[0]), &(ps->p[0]), 22*sizeof(double), TO
8100 // &(ps->p), &(ps->p[0]), sizeof(void*), ATTACH
8101 //
8102 // map(ps->ps)
8103 // ps, &(ps->ps), sizeof(S2*), TARGET_PARAM | TO | FROM
8104 // &ps, &(ps->ps), sizeof(ps), ATTACH
8105 //
8106 // map(from: ps->ps->s.i)
8107 // ps, &(ps[0]), 0, TARGET_PARAM | IMPLICIT // (+)
8108 // &(ps->ps[0]), &(ps->ps->s.i), sizeof(int), FROM
8109 // &(ps->ps), &(ps->ps->s.i), sizeof(void*), ATTACH
8110 //
8111 // map(from: ps->ps->ps)
8112 // ps, &ps[0], 0, TARGET_PARAM | IMPLICIT // (+)
8113 // &(ps->ps[0]), &(ps->ps->ps), sizeof(S2*), FROM
8114 // &(ps->ps), &(ps->ps->ps), sizeof(void*), ATTACH
8115 //
8116 // map(ps->ps->ps->ps)
8117 // ps, &ps[0], 0, TARGET_PARAM | IMPLICIT // (+)
8118 // &(ps->ps->ps[0]), &(ps->ps->ps->ps), sizeof(S2*), FROM
8119 // &(ps->ps->ps), &(ps->ps->ps->ps), sizeof(void*), ATTACH
8120 //
8121 // map(to: ps->ps->ps->s.f[:22])
8122 // ps, &ps[0], 0, TARGET_PARAM | IMPLICIT // (+)
8123 // &(ps->ps->ps[0]), &(ps->ps->ps->s.f[0]), 22*sizeof(float), TO
8124 // &(ps->ps->ps), &(ps->ps->ps->s.f[0]), sizeof(void*), ATTACH
8125 //
8126 // map(to: s.f[:22]) map(from: s.p[:33])
8127 // On target, and if s is used in the region:
8128 //
8129 // &s, &(s.f[0]), 50*sizeof(float) +
8130 // sizeof(struct S1) +
8131 // sizeof(double*) (**), TARGET_PARAM
8132 // &s, &(s.f[0]), 22*sizeof(float), MEMBER_OF(1) | TO
8133 // &s, &(s.p), sizeof(double*), MEMBER_OF(1) | TO |
8134 // FROM | IMPLICIT
8135 // &(s.p[0]), &(s.p[0]), 33*sizeof(double), FROM
8136 // &(s.p), &(s.p[0]), sizeof(void*), ATTACH
8137 // (**) allocate contiguous space needed to fit all mapped members even if
8138 // we allocate space for members not mapped (in this example,
8139 // s.f[22..49] and s.s are not mapped, yet we must allocate space for
8140 // them as well because they fall between &s.f[0] and &s.p)
8141 //
8142 // On other constructs, and, if s is not used in the region, on target:
8143 // &s, &(s.f[0]), 22*sizeof(float), TO
8144 // &(s.p[0]), &(s.p[0]), 33*sizeof(double), FROM
8145 // &(s.p), &(s.p[0]), sizeof(void*), ATTACH
8146 //
8147 // map(from: s.f[:22]) map(to: ps->p[:33])
8148 // &s, &(s.f[0]), 22*sizeof(float), TARGET_PARAM | FROM
8149 // &ps[0], &ps[0], 0, TARGET_PARAM | IMPLICIT // (+)
8150 // &(ps->p[0]), &(ps->p[0]), 33*sizeof(double), TO
8151 // &(ps->p), &(ps->p[0]), sizeof(void*), ATTACH
8152 //
8153 // map(from: s.f[:22], s.s) map(to: ps->p[:33])
8154 // &s, &(s.f[0]), 50*sizeof(float) +
8155 // sizeof(struct S1), TARGET_PARAM
8156 // &s, &(s.f[0]), 22*sizeof(float), MEMBER_OF(1) | FROM
8157 // &s, &(s.s), sizeof(struct S1), MEMBER_OF(1) | FROM
8158 // ps, &ps[0], 0, TARGET_PARAM | IMPLICIT // (+)
8159 // &(ps->p[0]), &(ps->p[0]), 33*sizeof(double), TO
8160 // &(ps->p), &(ps->p[0]), sizeof(void*), ATTACH
8161 //
8162 // map(p[:100], p)
8163 // &p, &p, sizeof(float*), TARGET_PARAM | TO | FROM
8164 // p, &p[0], 100*sizeof(float), TO | FROM
8165 // &p, &p[0], sizeof(float*), ATTACH
8166
8167 // Track if the map information being generated is the first for a capture.
8168 bool IsCaptureFirstInfo = IsFirstComponentList;
8169 // When the variable is on a declare target link or in a to clause with
8170 // unified memory, a reference is needed to hold the host/device address
8171 // of the variable.
8172 bool RequiresReference = false;
8173
8174 // Scan the components from the base to the complete expression.
8175 auto CI = Components.rbegin();
8176 auto CE = Components.rend();
8177 auto I = CI;
8178
8179 // Track if the map information being generated is the first for a list of
8180 // components.
8181 bool IsExpressionFirstInfo = true;
8182 bool FirstPointerInComplexData = false;
8184 Address FinalLowestElem = Address::invalid();
8185 const Expr *AssocExpr = I->getAssociatedExpression();
8186 const auto *AE = dyn_cast<ArraySubscriptExpr>(AssocExpr);
8187 const auto *OASE = dyn_cast<ArraySectionExpr>(AssocExpr);
8188 const auto *OAShE = dyn_cast<OMPArrayShapingExpr>(AssocExpr);
8189
8190 // Get the pointer-attachment base-pointer for the given list, if any.
8191 const Expr *AttachPtrExpr = getAttachPtrExpr(Components);
8192 auto [AttachPtrAddr, AttachPteeBaseAddr] =
8193 getAttachPtrAddrAndPteeBaseAddr(AttachPtrExpr, CGF);
8194
8195 bool HasAttachPtr = AttachPtrExpr != nullptr;
8196 bool FirstComponentIsForAttachPtr = AssocExpr == AttachPtrExpr;
8197 bool SeenAttachPtr = FirstComponentIsForAttachPtr;
8198
8199 if (FirstComponentIsForAttachPtr) {
8200 // No need to process AttachPtr here. It will be processed at the end
8201 // after we have computed the pointee's address.
8202 ++I;
8203 } else if (isa<MemberExpr>(AssocExpr)) {
8204 // The base is the 'this' pointer. The content of the pointer is going
8205 // to be the base of the field being mapped.
8206 BP = CGF.LoadCXXThisAddress();
8207 } else if ((AE && isa<CXXThisExpr>(AE->getBase()->IgnoreParenImpCasts())) ||
8208 (OASE &&
8209 isa<CXXThisExpr>(OASE->getBase()->IgnoreParenImpCasts()))) {
8210 BP = CGF.EmitOMPSharedLValue(AssocExpr).getAddress();
8211 } else if (OAShE &&
8212 isa<CXXThisExpr>(OAShE->getBase()->IgnoreParenCasts())) {
8213 BP = Address(
8214 CGF.EmitScalarExpr(OAShE->getBase()),
8215 CGF.ConvertTypeForMem(OAShE->getBase()->getType()->getPointeeType()),
8216 CGF.getContext().getTypeAlignInChars(OAShE->getBase()->getType()));
8217 } else {
8218 // The base is the reference to the variable.
8219 // BP = &Var.
8220 BP = CGF.EmitOMPSharedLValue(AssocExpr).getAddress();
8221 if (const auto *VD =
8222 dyn_cast_or_null<VarDecl>(I->getAssociatedDeclaration())) {
8223 if (std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
8224 OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD)) {
8225 if ((*Res == OMPDeclareTargetDeclAttr::MT_Link) ||
8226 ((*Res == OMPDeclareTargetDeclAttr::MT_To ||
8227 *Res == OMPDeclareTargetDeclAttr::MT_Enter) &&
8229 RequiresReference = true;
8231 }
8232 }
8233 }
8234
8235 // If the variable is a pointer and is being dereferenced (i.e. is not
8236 // the last component), the base has to be the pointer itself, not its
8237 // reference. References are ignored for mapping purposes.
8238 QualType Ty =
8239 I->getAssociatedDeclaration()->getType().getNonReferenceType();
8240 if (Ty->isAnyPointerType() && std::next(I) != CE) {
8241 // No need to generate individual map information for the pointer, it
8242 // can be associated with the combined storage if shared memory mode is
8243 // active or the base declaration is not global variable.
8244 const auto *VD = dyn_cast<VarDecl>(I->getAssociatedDeclaration());
8246 !VD || VD->hasLocalStorage() || HasAttachPtr)
8247 BP = CGF.EmitLoadOfPointer(BP, Ty->castAs<PointerType>());
8248 else
8249 FirstPointerInComplexData = true;
8250 ++I;
8251 }
8252 }
8253
8254 // Track whether a component of the list should be marked as MEMBER_OF some
8255 // combined entry (for partial structs). Only the first PTR_AND_OBJ entry
8256 // in a component list should be marked as MEMBER_OF, all subsequent entries
8257 // do not belong to the base struct. E.g.
8258 // struct S2 s;
8259 // s.ps->ps->ps->f[:]
8260 // (1) (2) (3) (4)
8261 // ps(1) is a member pointer, ps(2) is a pointee of ps(1), so it is a
8262 // PTR_AND_OBJ entry; the PTR is ps(1), so MEMBER_OF the base struct. ps(3)
8263 // is the pointee of ps(2) which is not member of struct s, so it should not
8264 // be marked as such (it is still PTR_AND_OBJ).
8265 // The variable is initialized to false so that PTR_AND_OBJ entries which
8266 // are not struct members are not considered (e.g. array of pointers to
8267 // data).
8268 bool ShouldBeMemberOf = false;
8269
8270 // Variable keeping track of whether or not we have encountered a component
8271 // in the component list which is a member expression. Useful when we have a
8272 // pointer or a final array section, in which case it is the previous
8273 // component in the list which tells us whether we have a member expression.
8274 // E.g. X.f[:]
8275 // While processing the final array section "[:]" it is "f" which tells us
8276 // whether we are dealing with a member of a declared struct.
8277 const MemberExpr *EncounteredME = nullptr;
8278
8279 // Track for the total number of dimension. Start from one for the dummy
8280 // dimension.
8281 uint64_t DimSize = 1;
8282
8283 // Detects non-contiguous updates due to strided accesses.
8284 // Sets the 'IsNonContiguous' flag so that the 'MapType' bits are set
8285 // correctly when generating information to be passed to the runtime. The
8286 // flag is set to true if any array section has a stride not equal to 1, or
8287 // if the stride is not a constant expression (conservatively assumed
8288 // non-contiguous).
8289 bool IsNonContiguous =
8290 CombinedInfo.NonContigInfo.IsNonContiguous ||
8291 any_of(Components, [&](const auto &Component) {
8292 const auto *OASE =
8293 dyn_cast<ArraySectionExpr>(Component.getAssociatedExpression());
8294 if (!OASE)
8295 return false;
8296
8297 const Expr *StrideExpr = OASE->getStride();
8298 if (!StrideExpr)
8299 return false;
8300
8301 assert(StrideExpr->getType()->isIntegerType() &&
8302 "Stride expression must be of integer type");
8303
8304 // If stride is not evaluatable as a constant, treat as
8305 // non-contiguous.
8306 const auto Constant =
8307 StrideExpr->getIntegerConstantExpr(CGF.getContext());
8308 if (!Constant)
8309 return true;
8310
8311 // Treat non-unitary strides as non-contiguous.
8312 return !Constant->isOne();
8313 });
8314
8315 bool IsPrevMemberReference = false;
8316
8317 bool IsPartialMapped =
8318 !PartialStruct.PreliminaryMapData.BasePointers.empty();
8319
8320 // We need to check if we will be encountering any MEs. If we do not
8321 // encounter any ME expression it means we will be mapping the whole struct.
8322 // In that case we need to skip adding an entry for the struct to the
8323 // CombinedInfo list and instead add an entry to the StructBaseCombinedInfo
8324 // list only when generating all info for clauses.
8325 bool IsMappingWholeStruct = true;
8326 if (!GenerateAllInfoForClauses) {
8327 IsMappingWholeStruct = false;
8328 } else {
8329 for (auto TempI = I; TempI != CE; ++TempI) {
8330 const MemberExpr *PossibleME =
8331 dyn_cast<MemberExpr>(TempI->getAssociatedExpression());
8332 if (PossibleME) {
8333 IsMappingWholeStruct = false;
8334 break;
8335 }
8336 }
8337 }
8338
8339 bool SeenFirstNonBinOpExprAfterAttachPtr = false;
8340 for (; I != CE; ++I) {
8341 // If we have a valid attach-ptr, we skip processing all components until
8342 // after the attach-ptr.
8343 if (HasAttachPtr && !SeenAttachPtr) {
8344 SeenAttachPtr = I->getAssociatedExpression() == AttachPtrExpr;
8345 continue;
8346 }
8347
8348 // After finding the attach pointer, skip binary-ops, to skip past
8349 // expressions like (p + 10), for a map like map(*(p + 10)), where p is
8350 // the attach-ptr.
8351 if (HasAttachPtr && !SeenFirstNonBinOpExprAfterAttachPtr) {
8352 const auto *BO = dyn_cast<BinaryOperator>(I->getAssociatedExpression());
8353 if (BO)
8354 continue;
8355
8356 // Found the first non-binary-operator component after attach
8357 SeenFirstNonBinOpExprAfterAttachPtr = true;
8358 BP = AttachPteeBaseAddr;
8359 }
8360
8361 // If the current component is member of a struct (parent struct) mark it.
8362 if (!EncounteredME) {
8363 EncounteredME = dyn_cast<MemberExpr>(I->getAssociatedExpression());
8364 // If we encounter a PTR_AND_OBJ entry from now on it should be marked
8365 // as MEMBER_OF the parent struct.
8366 if (EncounteredME) {
8367 ShouldBeMemberOf = true;
8368 // Do not emit as complex pointer if this is actually not array-like
8369 // expression.
8370 if (FirstPointerInComplexData) {
8371 QualType Ty = std::prev(I)
8372 ->getAssociatedDeclaration()
8373 ->getType()
8374 .getNonReferenceType();
8375 BP = CGF.EmitLoadOfPointer(BP, Ty->castAs<PointerType>());
8376 FirstPointerInComplexData = false;
8377 }
8378 }
8379 }
8380
8381 auto Next = std::next(I);
8382
8383 // We need to generate the addresses and sizes if this is the last
8384 // component, if the component is a pointer or if it is an array section
8385 // whose length can't be proved to be one. If this is a pointer, it
8386 // becomes the base address for the following components.
8387
8388 // A final array section, is one whose length can't be proved to be one.
8389 // If the map item is non-contiguous then we don't treat any array section
8390 // as final array section.
8391 bool IsFinalArraySection =
8392 !IsNonContiguous &&
8393 isFinalArraySectionExpression(I->getAssociatedExpression());
8394
8395 // If we have a declaration for the mapping use that, otherwise use
8396 // the base declaration of the map clause.
8397 const ValueDecl *MapDecl = (I->getAssociatedDeclaration())
8398 ? I->getAssociatedDeclaration()
8399 : BaseDecl;
8400 MapExpr = (I->getAssociatedExpression()) ? I->getAssociatedExpression()
8401 : MapExpr;
8402
8403 // Get information on whether the element is a pointer. Have to do a
8404 // special treatment for array sections given that they are built-in
8405 // types.
8406 const auto *OASE =
8407 dyn_cast<ArraySectionExpr>(I->getAssociatedExpression());
8408 const auto *OAShE =
8409 dyn_cast<OMPArrayShapingExpr>(I->getAssociatedExpression());
8410 const auto *UO = dyn_cast<UnaryOperator>(I->getAssociatedExpression());
8411 const auto *BO = dyn_cast<BinaryOperator>(I->getAssociatedExpression());
8412 bool IsPointer =
8413 OAShE ||
8416 ->isAnyPointerType()) ||
8417 I->getAssociatedExpression()->getType()->isAnyPointerType();
8418 bool IsMemberReference = isa<MemberExpr>(I->getAssociatedExpression()) &&
8419 MapDecl &&
8420 MapDecl->getType()->isLValueReferenceType();
8421 bool IsNonDerefPointer = IsPointer &&
8422 !(UO && UO->getOpcode() != UO_Deref) && !BO &&
8423 !IsNonContiguous;
8424
8425 if (OASE)
8426 ++DimSize;
8427
8428 if (Next == CE || IsMemberReference || IsNonDerefPointer ||
8429 IsFinalArraySection) {
8430 // If this is not the last component, we expect the pointer to be
8431 // associated with an array expression or member expression.
8432 assert((Next == CE ||
8433 isa<MemberExpr>(Next->getAssociatedExpression()) ||
8434 isa<ArraySubscriptExpr>(Next->getAssociatedExpression()) ||
8435 isa<ArraySectionExpr>(Next->getAssociatedExpression()) ||
8436 isa<OMPArrayShapingExpr>(Next->getAssociatedExpression()) ||
8437 isa<UnaryOperator>(Next->getAssociatedExpression()) ||
8438 isa<BinaryOperator>(Next->getAssociatedExpression())) &&
8439 "Unexpected expression");
8440
8442 Address LowestElem = Address::invalid();
8443 auto &&EmitMemberExprBase = [](CodeGenFunction &CGF,
8444 const MemberExpr *E) {
8445 const Expr *BaseExpr = E->getBase();
8446 // If this is s.x, emit s as an lvalue. If it is s->x, emit s as a
8447 // scalar.
8448 LValue BaseLV;
8449 if (E->isArrow()) {
8450 LValueBaseInfo BaseInfo;
8451 TBAAAccessInfo TBAAInfo;
8452 Address Addr =
8453 CGF.EmitPointerWithAlignment(BaseExpr, &BaseInfo, &TBAAInfo);
8454 QualType PtrTy = BaseExpr->getType()->getPointeeType();
8455 BaseLV = CGF.MakeAddrLValue(Addr, PtrTy, BaseInfo, TBAAInfo);
8456 } else {
8457 BaseLV = CGF.EmitOMPSharedLValue(BaseExpr);
8458 }
8459 return BaseLV;
8460 };
8461 if (OAShE) {
8462 LowestElem = LB =
8463 Address(CGF.EmitScalarExpr(OAShE->getBase()),
8465 OAShE->getBase()->getType()->getPointeeType()),
8467 OAShE->getBase()->getType()));
8468 } else if (IsMemberReference) {
8469 const auto *ME = cast<MemberExpr>(I->getAssociatedExpression());
8470 LValue BaseLVal = EmitMemberExprBase(CGF, ME);
8471 LowestElem = CGF.EmitLValueForFieldInitialization(
8472 BaseLVal, cast<FieldDecl>(MapDecl))
8473 .getAddress();
8474 LB = CGF.EmitLoadOfReferenceLValue(LowestElem, MapDecl->getType())
8475 .getAddress();
8476 } else {
8477 LowestElem = LB =
8478 CGF.EmitOMPSharedLValue(I->getAssociatedExpression())
8479 .getAddress();
8480 }
8481
8482 // Save the final LowestElem, to use it as the pointee in attach maps,
8483 // if emitted.
8484 if (Next == CE)
8485 FinalLowestElem = LowestElem;
8486
8487 // If this component is a pointer inside the base struct then we don't
8488 // need to create any entry for it - it will be combined with the object
8489 // it is pointing to into a single PTR_AND_OBJ entry.
8490 bool IsMemberPointerOrAddr =
8491 EncounteredME &&
8492 (((IsPointer || ForDeviceAddr) &&
8493 I->getAssociatedExpression() == EncounteredME) ||
8494 (IsPrevMemberReference && !IsPointer) ||
8495 (IsMemberReference && Next != CE &&
8496 !Next->getAssociatedExpression()->getType()->isPointerType()));
8497 if (!OverlappedElements.empty() && Next == CE) {
8498 // Handle base element with the info for overlapped elements.
8499 assert(!PartialStruct.Base.isValid() && "The base element is set.");
8500 assert(!IsPointer &&
8501 "Unexpected base element with the pointer type.");
8502 // Mark the whole struct as the struct that requires allocation on the
8503 // device.
8504 PartialStruct.LowestElem = {0, LowestElem};
8505 CharUnits TypeSize = CGF.getContext().getTypeSizeInChars(
8506 I->getAssociatedExpression()->getType());
8509 LowestElem, CGF.VoidPtrTy, CGF.Int8Ty),
8510 TypeSize.getQuantity() - 1);
8511 PartialStruct.HighestElem = {
8512 std::numeric_limits<decltype(
8513 PartialStruct.HighestElem.first)>::max(),
8514 HB};
8515 PartialStruct.Base = BP;
8516 PartialStruct.LB = LB;
8517 assert(
8518 PartialStruct.PreliminaryMapData.BasePointers.empty() &&
8519 "Overlapped elements must be used only once for the variable.");
8520 std::swap(PartialStruct.PreliminaryMapData, CombinedInfo);
8521 // Emit data for non-overlapped data.
8522 OpenMPOffloadMappingFlags Flags =
8523 OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF |
8524 getMapTypeBits(MapType, MapModifiers, MotionModifiers, IsImplicit,
8525 /*AddPtrFlag=*/false,
8526 /*AddIsTargetParamFlag=*/false, IsNonContiguous);
8527 CopyOverlappedEntryGaps CopyGaps(CGF, CombinedInfo, Flags, MapDecl,
8528 MapExpr, BP, LB, IsNonContiguous,
8529 DimSize);
8530 // Do bitcopy of all non-overlapped structure elements.
8532 Component : OverlappedElements) {
8533 for (const OMPClauseMappableExprCommon::MappableComponent &MC :
8534 Component) {
8535 if (const ValueDecl *VD = MC.getAssociatedDeclaration()) {
8536 if (const auto *FD = dyn_cast<FieldDecl>(VD)) {
8537 CopyGaps.processField(MC, FD, EmitMemberExprBase);
8538 }
8539 }
8540 }
8541 }
8542 CopyGaps.copyUntilEnd(HB);
8543 break;
8544 }
8545 llvm::Value *Size = getExprTypeSize(I->getAssociatedExpression());
8546 // Skip adding an entry in the CurInfo of this combined entry if the
8547 // whole struct is currently being mapped. The struct needs to be added
8548 // in the first position before any data internal to the struct is being
8549 // mapped.
8550 // Skip adding an entry in the CurInfo of this combined entry if the
8551 // PartialStruct.PreliminaryMapData.BasePointers has been mapped.
8552 if ((!IsMemberPointerOrAddr && !IsPartialMapped) ||
8553 (Next == CE && MapType != OMPC_MAP_unknown)) {
8554 if (!IsMappingWholeStruct) {
8555 CombinedInfo.Exprs.emplace_back(MapDecl, MapExpr);
8556 CombinedInfo.BasePointers.push_back(BP.emitRawPointer(CGF));
8557 CombinedInfo.DevicePtrDecls.push_back(nullptr);
8558 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
8559 CombinedInfo.Pointers.push_back(LB.emitRawPointer(CGF));
8560 CombinedInfo.Sizes.push_back(CGF.Builder.CreateIntCast(
8561 Size, CGF.Int64Ty, /*isSigned=*/true));
8562 CombinedInfo.NonContigInfo.Dims.push_back(IsNonContiguous ? DimSize
8563 : 1);
8564 } else {
8565 StructBaseCombinedInfo.Exprs.emplace_back(MapDecl, MapExpr);
8566 StructBaseCombinedInfo.BasePointers.push_back(
8567 BP.emitRawPointer(CGF));
8568 StructBaseCombinedInfo.DevicePtrDecls.push_back(nullptr);
8569 StructBaseCombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
8570 StructBaseCombinedInfo.Pointers.push_back(LB.emitRawPointer(CGF));
8571 StructBaseCombinedInfo.Sizes.push_back(CGF.Builder.CreateIntCast(
8572 Size, CGF.Int64Ty, /*isSigned=*/true));
8573 StructBaseCombinedInfo.NonContigInfo.Dims.push_back(
8574 IsNonContiguous ? DimSize : 1);
8575 }
8576
8577 // If Mapper is valid, the last component inherits the mapper.
8578 bool HasMapper = Mapper && Next == CE;
8579 if (!IsMappingWholeStruct)
8580 CombinedInfo.Mappers.push_back(HasMapper ? Mapper : nullptr);
8581 else
8582 StructBaseCombinedInfo.Mappers.push_back(HasMapper ? Mapper
8583 : nullptr);
8584
8585 // We need to add a pointer flag for each map that comes from the
8586 // same expression except for the first one. We also need to signal
8587 // this map is the first one that relates with the current capture
8588 // (there is a set of entries for each capture).
8589 OpenMPOffloadMappingFlags Flags = getMapTypeBits(
8590 MapType, MapModifiers, MotionModifiers, IsImplicit,
8591 !IsExpressionFirstInfo || RequiresReference ||
8592 FirstPointerInComplexData || IsMemberReference,
8593 IsCaptureFirstInfo && !RequiresReference, IsNonContiguous);
8594
8595 if (!IsExpressionFirstInfo || IsMemberReference) {
8596 // If we have a PTR_AND_OBJ pair where the OBJ is a pointer as well,
8597 // then we reset the TO/FROM/ALWAYS/DELETE/CLOSE flags.
8598 if (IsPointer || (IsMemberReference && Next != CE))
8599 Flags &= ~(OpenMPOffloadMappingFlags::OMP_MAP_TO |
8600 OpenMPOffloadMappingFlags::OMP_MAP_FROM |
8601 OpenMPOffloadMappingFlags::OMP_MAP_ALWAYS |
8602 OpenMPOffloadMappingFlags::OMP_MAP_DELETE |
8603 OpenMPOffloadMappingFlags::OMP_MAP_CLOSE);
8604
8605 if (ShouldBeMemberOf) {
8606 // Set placeholder value MEMBER_OF=FFFF to indicate that the flag
8607 // should be later updated with the correct value of MEMBER_OF.
8608 Flags |= OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF;
8609 // From now on, all subsequent PTR_AND_OBJ entries should not be
8610 // marked as MEMBER_OF.
8611 ShouldBeMemberOf = false;
8612 }
8613 }
8614
8615 if (!IsMappingWholeStruct) {
8616 CombinedInfo.Types.push_back(Flags);
8617 // HasAttachPtr marks pointee entries, which have a base attach-ptr.
8618 CombinedInfo.HasAttachPtr.push_back(HasAttachPtr);
8619 } else {
8620 StructBaseCombinedInfo.Types.push_back(Flags);
8621 StructBaseCombinedInfo.HasAttachPtr.push_back(HasAttachPtr);
8622 }
8623 }
8624
8625 // If we have encountered a member expression so far, keep track of the
8626 // mapped member. If the parent is "*this", then the value declaration
8627 // is nullptr.
8628 if (EncounteredME) {
8629 const auto *FD = cast<FieldDecl>(EncounteredME->getMemberDecl());
8630 unsigned FieldIndex = FD->getFieldIndex();
8631
8632 // Update info about the lowest and highest elements for this struct
8633 if (!PartialStruct.Base.isValid()) {
8634 PartialStruct.LowestElem = {FieldIndex, LowestElem};
8635 if (IsFinalArraySection && OASE) {
8636 Address HB =
8637 CGF.EmitArraySectionExpr(OASE, /*IsLowerBound=*/false)
8638 .getAddress();
8639 PartialStruct.HighestElem = {FieldIndex, HB};
8640 } else {
8641 PartialStruct.HighestElem = {FieldIndex, LowestElem};
8642 }
8643 PartialStruct.Base = BP;
8644 PartialStruct.LB = BP;
8645 } else if (FieldIndex < PartialStruct.LowestElem.first) {
8646 PartialStruct.LowestElem = {FieldIndex, LowestElem};
8647 } else if (FieldIndex > PartialStruct.HighestElem.first) {
8648 if (IsFinalArraySection && OASE) {
8649 Address HB =
8650 CGF.EmitArraySectionExpr(OASE, /*IsLowerBound=*/false)
8651 .getAddress();
8652 PartialStruct.HighestElem = {FieldIndex, HB};
8653 } else {
8654 PartialStruct.HighestElem = {FieldIndex, LowestElem};
8655 }
8656 }
8657 }
8658
8659 // Need to emit combined struct for array sections.
8660 if (IsFinalArraySection || IsNonContiguous)
8661 PartialStruct.IsArraySection = true;
8662
8663 // If we have a final array section, we are done with this expression.
8664 if (IsFinalArraySection)
8665 break;
8666
8667 // The pointer becomes the base for the next element.
8668 if (Next != CE)
8669 BP = IsMemberReference ? LowestElem : LB;
8670 if (!IsPartialMapped)
8671 IsExpressionFirstInfo = false;
8672 IsCaptureFirstInfo = false;
8673 FirstPointerInComplexData = false;
8674 IsPrevMemberReference = IsMemberReference;
8675 } else if (FirstPointerInComplexData) {
8676 QualType Ty = Components.rbegin()
8677 ->getAssociatedDeclaration()
8678 ->getType()
8679 .getNonReferenceType();
8680 BP = CGF.EmitLoadOfPointer(BP, Ty->castAs<PointerType>());
8681 FirstPointerInComplexData = false;
8682 }
8683 }
8684 // If ran into the whole component - allocate the space for the whole
8685 // record.
8686 if (!EncounteredME)
8687 PartialStruct.HasCompleteRecord = true;
8688
8689 // Populate ATTACH information for later processing by emitAttachEntry.
8690 if (shouldEmitAttachEntry(AttachPtrExpr, BaseDecl, CGF, CurDir)) {
8691 AttachInfo.AttachPtrAddr = AttachPtrAddr;
8692 AttachInfo.AttachPteeAddr = FinalLowestElem;
8693 AttachInfo.AttachPtrDecl = BaseDecl;
8694 AttachInfo.AttachMapExpr = MapExpr;
8695 }
8696
8697 if (!IsNonContiguous)
8698 return;
8699
8700 const ASTContext &Context = CGF.getContext();
8701
8702 // For supporting stride in array section, we need to initialize the first
8703 // dimension size as 1, first offset as 0, and first count as 1
8704 MapValuesArrayTy CurOffsets = {llvm::ConstantInt::get(CGF.CGM.Int64Ty, 0)};
8705 MapValuesArrayTy CurCounts;
8706 MapValuesArrayTy CurStrides = {llvm::ConstantInt::get(CGF.CGM.Int64Ty, 1)};
8707 MapValuesArrayTy DimSizes{llvm::ConstantInt::get(CGF.CGM.Int64Ty, 1)};
8708 uint64_t ElementTypeSize;
8709
8710 // Collect Size information for each dimension and get the element size as
8711 // the first Stride. For example, for `int arr[10][10]`, the DimSizes
8712 // should be [10, 10] and the first stride is 4 btyes.
8713 for (const OMPClauseMappableExprCommon::MappableComponent &Component :
8714 Components) {
8715 const Expr *AssocExpr = Component.getAssociatedExpression();
8716 const auto *OASE = dyn_cast<ArraySectionExpr>(AssocExpr);
8717
8718 if (!OASE)
8719 continue;
8720
8721 QualType Ty = ArraySectionExpr::getBaseOriginalType(OASE->getBase());
8722 auto *CAT = Context.getAsConstantArrayType(Ty);
8723 auto *VAT = Context.getAsVariableArrayType(Ty);
8724
8725 // We need all the dimension size except for the last dimension.
8726 assert((VAT || CAT || &Component == &*Components.begin()) &&
8727 "Should be either ConstantArray or VariableArray if not the "
8728 "first Component");
8729
8730 // Get element size if CurCounts is empty.
8731 if (CurCounts.empty()) {
8732 const Type *ElementType = nullptr;
8733 if (CAT)
8734 ElementType = CAT->getElementType().getTypePtr();
8735 else if (VAT)
8736 ElementType = VAT->getElementType().getTypePtr();
8737 else if (&Component == &*Components.begin()) {
8738 // If the base is a raw pointer (e.g. T *data with data[a:b:c]),
8739 // there was no earlier CAT/VAT/array handling to establish
8740 // ElementType. Capture the pointee type now so that subsequent
8741 // components (offset/length/stride) have a concrete element type to
8742 // work with. This makes pointer-backed sections behave consistently
8743 // with CAT/VAT/array bases.
8744 if (const auto *PtrType = Ty->getAs<PointerType>())
8745 ElementType = PtrType->getPointeeType().getTypePtr();
8746 } else {
8747 // Any component after the first should never have a raw pointer type;
8748 // by this point. ElementType must already be known (set above or in
8749 // prior array / CAT / VAT handling).
8750 assert(!Ty->isPointerType() &&
8751 "Non-first components should not be raw pointers");
8752 }
8753
8754 // At this stage, if ElementType was a base pointer and we are in the
8755 // first iteration, it has been computed.
8756 if (ElementType) {
8757 // For the case that having pointer as base, we need to remove one
8758 // level of indirection.
8759 if (&Component != &*Components.begin())
8760 ElementType = ElementType->getPointeeOrArrayElementType();
8761 ElementTypeSize =
8762 Context.getTypeSizeInChars(ElementType).getQuantity();
8763 CurCounts.push_back(
8764 llvm::ConstantInt::get(CGF.Int64Ty, ElementTypeSize));
8765 }
8766 }
8767 // Get dimension value except for the last dimension since we don't need
8768 // it.
8769 if (DimSizes.size() < Components.size() - 1) {
8770 if (CAT)
8771 DimSizes.push_back(
8772 llvm::ConstantInt::get(CGF.Int64Ty, CAT->getZExtSize()));
8773 else if (VAT)
8774 DimSizes.push_back(CGF.Builder.CreateIntCast(
8775 CGF.EmitScalarExpr(VAT->getSizeExpr()), CGF.Int64Ty,
8776 /*IsSigned=*/false));
8777 }
8778 }
8779
8780 // Skip the dummy dimension since we have already have its information.
8781 auto *DI = DimSizes.begin() + 1;
8782 // Product of dimension.
8783 llvm::Value *DimProd =
8784 llvm::ConstantInt::get(CGF.CGM.Int64Ty, ElementTypeSize);
8785
8786 // Collect info for non-contiguous. Notice that offset, count, and stride
8787 // are only meaningful for array-section, so we insert a null for anything
8788 // other than array-section.
8789 // Also, the size of offset, count, and stride are not the same as
8790 // pointers, base_pointers, sizes, or dims. Instead, the size of offset,
8791 // count, and stride are the same as the number of non-contiguous
8792 // declaration in target update to/from clause.
8793 for (const OMPClauseMappableExprCommon::MappableComponent &Component :
8794 Components) {
8795 const Expr *AssocExpr = Component.getAssociatedExpression();
8796
8797 if (const auto *AE = dyn_cast<ArraySubscriptExpr>(AssocExpr)) {
8798 llvm::Value *Offset = CGF.Builder.CreateIntCast(
8799 CGF.EmitScalarExpr(AE->getIdx()), CGF.Int64Ty,
8800 /*isSigned=*/false);
8801 CurOffsets.push_back(Offset);
8802 CurCounts.push_back(llvm::ConstantInt::get(CGF.Int64Ty, /*V=*/1));
8803 CurStrides.push_back(CurStrides.back());
8804 continue;
8805 }
8806
8807 const auto *OASE = dyn_cast<ArraySectionExpr>(AssocExpr);
8808
8809 if (!OASE)
8810 continue;
8811
8812 // Offset
8813 const Expr *OffsetExpr = OASE->getLowerBound();
8814 llvm::Value *Offset = nullptr;
8815 if (!OffsetExpr) {
8816 // If offset is absent, then we just set it to zero.
8817 Offset = llvm::ConstantInt::get(CGF.Int64Ty, 0);
8818 } else {
8819 Offset = CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(OffsetExpr),
8820 CGF.Int64Ty,
8821 /*isSigned=*/false);
8822 }
8823
8824 // Count
8825 const Expr *CountExpr = OASE->getLength();
8826 llvm::Value *Count = nullptr;
8827 if (!CountExpr) {
8828 // In Clang, once a high dimension is an array section, we construct all
8829 // the lower dimension as array section, however, for case like
8830 // arr[0:2][2], Clang construct the inner dimension as an array section
8831 // but it actually is not in an array section form according to spec.
8832 if (!OASE->getColonLocFirst().isValid() &&
8833 !OASE->getColonLocSecond().isValid()) {
8834 Count = llvm::ConstantInt::get(CGF.Int64Ty, 1);
8835 } else {
8836 // OpenMP 5.0, 2.1.5 Array Sections, Description.
8837 // When the length is absent it defaults to ⌈(size −
8838 // lower-bound)/stride⌉, where size is the size of the array
8839 // dimension.
8840 const Expr *StrideExpr = OASE->getStride();
8841 llvm::Value *Stride =
8842 StrideExpr
8843 ? CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(StrideExpr),
8844 CGF.Int64Ty, /*isSigned=*/false)
8845 : nullptr;
8846 if (Stride)
8847 Count = CGF.Builder.CreateUDiv(
8848 CGF.Builder.CreateNUWSub(*DI, Offset), Stride);
8849 else
8850 Count = CGF.Builder.CreateNUWSub(*DI, Offset);
8851 }
8852 } else {
8853 Count = CGF.EmitScalarExpr(CountExpr);
8854 }
8855 Count = CGF.Builder.CreateIntCast(Count, CGF.Int64Ty, /*isSigned=*/false);
8856 CurCounts.push_back(Count);
8857
8858 // Stride_n' = Stride_n * (D_0 * D_1 ... * D_n-1) * Unit size
8859 // Offset_n' = Offset_n * (D_0 * D_1 ... * D_n-1) * Unit size
8860 // Take `int arr[5][5][5]` and `arr[0:2:2][1:2:1][0:2:2]` as an example:
8861 // Offset Count Stride
8862 // D0 0 4 1 (int) <- dummy dimension
8863 // D1 0 2 8 (2 * (1) * 4)
8864 // D2 100 2 20 (1 * (1 * 5) * 4)
8865 // D3 0 2 200 (2 * (1 * 5 * 4) * 4)
8866 const Expr *StrideExpr = OASE->getStride();
8867 llvm::Value *Stride =
8868 StrideExpr
8869 ? CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(StrideExpr),
8870 CGF.Int64Ty, /*isSigned=*/false)
8871 : nullptr;
8872 DimProd = CGF.Builder.CreateNUWMul(DimProd, *(DI - 1));
8873 if (Stride)
8874 CurStrides.push_back(CGF.Builder.CreateNUWMul(DimProd, Stride));
8875 else
8876 CurStrides.push_back(DimProd);
8877
8878 Offset = CGF.Builder.CreateNUWMul(DimProd, Offset);
8879 CurOffsets.push_back(Offset);
8880
8881 if (DI != DimSizes.end())
8882 ++DI;
8883 }
8884
8885 CombinedInfo.NonContigInfo.Offsets.push_back(CurOffsets);
8886 CombinedInfo.NonContigInfo.Counts.push_back(CurCounts);
8887 CombinedInfo.NonContigInfo.Strides.push_back(CurStrides);
8888 }
8889
8890 /// Return the adjusted map modifiers if the declaration a capture refers to
8891 /// appears in a first-private clause. This is expected to be used only with
8892 /// directives that start with 'target'.
8893 OpenMPOffloadMappingFlags
8894 getMapModifiersForPrivateClauses(const CapturedStmt::Capture &Cap) const {
8895 assert(Cap.capturesVariable() && "Expected capture by reference only!");
8896
8897 // A first private variable captured by reference will use only the
8898 // 'private ptr' and 'map to' flag. Return the right flags if the captured
8899 // declaration is known as first-private in this handler.
8900 if (FirstPrivateDecls.count(Cap.getCapturedVar())) {
8901 if (Cap.getCapturedVar()->getType()->isAnyPointerType())
8902 return OpenMPOffloadMappingFlags::OMP_MAP_TO |
8903 OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ;
8904 return OpenMPOffloadMappingFlags::OMP_MAP_PRIVATE |
8905 OpenMPOffloadMappingFlags::OMP_MAP_TO;
8906 }
8907 auto I = LambdasMap.find(Cap.getCapturedVar()->getCanonicalDecl());
8908 if (I != LambdasMap.end())
8909 // for map(to: lambda): using user specified map type.
8910 return getMapTypeBits(
8911 I->getSecond()->getMapType(), I->getSecond()->getMapTypeModifiers(),
8912 /*MotionModifiers=*/{}, I->getSecond()->isImplicit(),
8913 /*AddPtrFlag=*/false,
8914 /*AddIsTargetParamFlag=*/false,
8915 /*isNonContiguous=*/false);
8916 return OpenMPOffloadMappingFlags::OMP_MAP_TO |
8917 OpenMPOffloadMappingFlags::OMP_MAP_FROM;
8918 }
8919
8920 void getPlainLayout(const CXXRecordDecl *RD,
8921 llvm::SmallVectorImpl<const FieldDecl *> &Layout,
8922 bool AsBase) const {
8923 const CGRecordLayout &RL = CGF.getTypes().getCGRecordLayout(RD);
8924
8925 llvm::StructType *St =
8926 AsBase ? RL.getBaseSubobjectLLVMType() : RL.getLLVMType();
8927
8928 unsigned NumElements = St->getNumElements();
8929 llvm::SmallVector<
8930 llvm::PointerUnion<const CXXRecordDecl *, const FieldDecl *>, 4>
8931 RecordLayout(NumElements);
8932
8933 // Fill bases.
8934 for (const auto &I : RD->bases()) {
8935 if (I.isVirtual())
8936 continue;
8937
8938 QualType BaseTy = I.getType();
8939 const auto *Base = BaseTy->getAsCXXRecordDecl();
8940 // Ignore empty bases.
8942 CGF.getContext()
8943 .getASTRecordLayout(Base)
8945 .isZero())
8946 continue;
8947
8948 unsigned FieldIndex = RL.getNonVirtualBaseLLVMFieldNo(Base);
8949 RecordLayout[FieldIndex] = Base;
8950 }
8951 // Fill in virtual bases.
8952 for (const auto &I : RD->vbases()) {
8953 QualType BaseTy = I.getType();
8954 // Ignore empty bases.
8956 continue;
8957
8958 const auto *Base = BaseTy->getAsCXXRecordDecl();
8959 unsigned FieldIndex = RL.getVirtualBaseIndex(Base);
8960 if (RecordLayout[FieldIndex])
8961 continue;
8962 RecordLayout[FieldIndex] = Base;
8963 }
8964 // Fill in all the fields.
8965 assert(!RD->isUnion() && "Unexpected union.");
8966 for (const auto *Field : RD->fields()) {
8967 // Fill in non-bitfields. (Bitfields always use a zero pattern, which we
8968 // will fill in later.)
8969 if (!Field->isBitField() &&
8971 unsigned FieldIndex = RL.getLLVMFieldNo(Field);
8972 RecordLayout[FieldIndex] = Field;
8973 }
8974 }
8975 for (const llvm::PointerUnion<const CXXRecordDecl *, const FieldDecl *>
8976 &Data : RecordLayout) {
8977 if (Data.isNull())
8978 continue;
8979 if (const auto *Base = dyn_cast<const CXXRecordDecl *>(Data))
8980 getPlainLayout(Base, Layout, /*AsBase=*/true);
8981 else
8982 Layout.push_back(cast<const FieldDecl *>(Data));
8983 }
8984 }
8985
8986 /// Returns the address corresponding to \p PointerExpr.
8987 static Address getAttachPtrAddr(const Expr *PointerExpr,
8988 CodeGenFunction &CGF) {
8989 assert(PointerExpr && "Cannot get addr from null attach-ptr expr");
8990 Address AttachPtrAddr = Address::invalid();
8991
8992 if (auto *DRE = dyn_cast<DeclRefExpr>(PointerExpr)) {
8993 // If the pointer is a variable, we can use its address directly.
8994 AttachPtrAddr = CGF.EmitLValue(DRE).getAddress();
8995 } else if (auto *OASE = dyn_cast<ArraySectionExpr>(PointerExpr)) {
8996 AttachPtrAddr =
8997 CGF.EmitArraySectionExpr(OASE, /*IsLowerBound=*/true).getAddress();
8998 } else if (auto *ASE = dyn_cast<ArraySubscriptExpr>(PointerExpr)) {
8999 AttachPtrAddr = CGF.EmitLValue(ASE).getAddress();
9000 } else if (auto *ME = dyn_cast<MemberExpr>(PointerExpr)) {
9001 AttachPtrAddr = CGF.EmitMemberExpr(ME).getAddress();
9002 } else if (auto *UO = dyn_cast<UnaryOperator>(PointerExpr)) {
9003 assert(UO->getOpcode() == UO_Deref &&
9004 "Unexpected unary-operator on attach-ptr-expr");
9005 AttachPtrAddr = CGF.EmitLValue(UO).getAddress();
9006 }
9007 assert(AttachPtrAddr.isValid() &&
9008 "Failed to get address for attach pointer expression");
9009 return AttachPtrAddr;
9010 }
9011
9012 /// Get the address of the attach pointer, and a load from it, to get the
9013 /// pointee base address.
9014 /// \return A pair containing AttachPtrAddr and AttachPteeBaseAddr. The pair
9015 /// contains invalid addresses if \p AttachPtrExpr is null.
9016 static std::pair<Address, Address>
9017 getAttachPtrAddrAndPteeBaseAddr(const Expr *AttachPtrExpr,
9018 CodeGenFunction &CGF) {
9019
9020 if (!AttachPtrExpr)
9021 return {Address::invalid(), Address::invalid()};
9022
9023 Address AttachPtrAddr = getAttachPtrAddr(AttachPtrExpr, CGF);
9024 assert(AttachPtrAddr.isValid() && "Invalid attach pointer addr");
9025
9026 QualType AttachPtrType =
9029
9030 Address AttachPteeBaseAddr = CGF.EmitLoadOfPointer(
9031 AttachPtrAddr, AttachPtrType->castAs<PointerType>());
9032 assert(AttachPteeBaseAddr.isValid() && "Invalid attach pointee base addr");
9033
9034 return {AttachPtrAddr, AttachPteeBaseAddr};
9035 }
9036
9037 /// Returns whether an attach entry should be emitted for a map on
9038 /// \p MapBaseDecl on the directive \p CurDir.
9039 static bool
9040 shouldEmitAttachEntry(const Expr *PointerExpr, const ValueDecl *MapBaseDecl,
9041 CodeGenFunction &CGF,
9042 llvm::PointerUnion<const OMPExecutableDirective *,
9043 const OMPDeclareMapperDecl *>
9044 CurDir) {
9045 if (!PointerExpr)
9046 return false;
9047
9048 // Pointer attachment is needed at map-entering time or for declare
9049 // mappers.
9050 return isa<const OMPDeclareMapperDecl *>(CurDir) ||
9053 ->getDirectiveKind());
9054 }
9055
9056 /// Computes the attach-ptr expr for \p Components, and updates various maps
9057 /// with the information.
9058 /// It internally calls OMPClauseMappableExprCommon::findAttachPtrExpr()
9059 /// with the OpenMPDirectiveKind extracted from \p CurDir.
9060 /// It updates AttachPtrComputationOrderMap, AttachPtrComponentDepthMap, and
9061 /// AttachPtrExprMap.
9062 void collectAttachPtrExprInfo(
9064 llvm::PointerUnion<const OMPExecutableDirective *,
9065 const OMPDeclareMapperDecl *>
9066 CurDir) {
9067
9068 OpenMPDirectiveKind CurDirectiveID =
9070 ? OMPD_declare_mapper
9071 : cast<const OMPExecutableDirective *>(CurDir)->getDirectiveKind();
9072
9073 const auto &[AttachPtrExpr, Depth] =
9075 CurDirectiveID);
9076
9077 AttachPtrComputationOrderMap.try_emplace(
9078 AttachPtrExpr, AttachPtrComputationOrderMap.size());
9079 AttachPtrComponentDepthMap.try_emplace(AttachPtrExpr, Depth);
9080 AttachPtrExprMap.try_emplace(Components, AttachPtrExpr);
9081 }
9082
9083 /// Generate all the base pointers, section pointers, sizes, map types, and
9084 /// mappers for the extracted mappable expressions (all included in \a
9085 /// CombinedInfo). Also, for each item that relates with a device pointer, a
9086 /// pair of the relevant declaration and index where it occurs is appended to
9087 /// the device pointers info array.
9088 void generateAllInfoForClauses(
9089 ArrayRef<const OMPClause *> Clauses, MapCombinedInfoTy &CombinedInfo,
9090 llvm::OpenMPIRBuilder &OMPBuilder,
9091 const llvm::DenseSet<CanonicalDeclPtr<const Decl>> &SkipVarSet =
9092 llvm::DenseSet<CanonicalDeclPtr<const Decl>>()) const {
9093 // We have to process the component lists that relate with the same
9094 // declaration in a single chunk so that we can generate the map flags
9095 // correctly. Therefore, we organize all lists in a map.
9096 enum MapKind { Present, Allocs, Other, Total };
9097 llvm::MapVector<CanonicalDeclPtr<const Decl>,
9098 SmallVector<SmallVector<MapInfo, 8>, 4>>
9099 Info;
9100
9101 // Helper function to fill the information map for the different supported
9102 // clauses.
9103 auto &&InfoGen =
9104 [&Info, &SkipVarSet](
9105 const ValueDecl *D, MapKind Kind,
9107 OpenMPMapClauseKind MapType,
9108 ArrayRef<OpenMPMapModifierKind> MapModifiers,
9109 ArrayRef<OpenMPMotionModifierKind> MotionModifiers,
9110 bool ReturnDevicePointer, bool IsImplicit, const ValueDecl *Mapper,
9111 const Expr *VarRef = nullptr, bool ForDeviceAddr = false) {
9112 if (SkipVarSet.contains(D))
9113 return;
9114 auto It = Info.try_emplace(D, Total).first;
9115 It->second[Kind].emplace_back(
9116 L, MapType, MapModifiers, MotionModifiers, ReturnDevicePointer,
9117 IsImplicit, Mapper, VarRef, ForDeviceAddr);
9118 };
9119
9120 for (const auto *Cl : Clauses) {
9121 const auto *C = dyn_cast<OMPMapClause>(Cl);
9122 if (!C)
9123 continue;
9124 MapKind Kind = Other;
9125 if (llvm::is_contained(C->getMapTypeModifiers(),
9126 OMPC_MAP_MODIFIER_present))
9127 Kind = Present;
9128 else if (C->getMapType() == OMPC_MAP_alloc)
9129 Kind = Allocs;
9130 const auto *EI = C->getVarRefs().begin();
9131 for (const auto L : C->component_lists()) {
9132 const Expr *E = (C->getMapLoc().isValid()) ? *EI : nullptr;
9133 InfoGen(std::get<0>(L), Kind, std::get<1>(L), C->getMapType(),
9134 C->getMapTypeModifiers(), {},
9135 /*ReturnDevicePointer=*/false, C->isImplicit(), std::get<2>(L),
9136 E);
9137 ++EI;
9138 }
9139 }
9140 for (const auto *Cl : Clauses) {
9141 const auto *C = dyn_cast<OMPToClause>(Cl);
9142 if (!C)
9143 continue;
9144 MapKind Kind = Other;
9145 if (llvm::is_contained(C->getMotionModifiers(),
9146 OMPC_MOTION_MODIFIER_present))
9147 Kind = Present;
9148 if (llvm::is_contained(C->getMotionModifiers(),
9149 OMPC_MOTION_MODIFIER_iterator)) {
9150 if (auto *IteratorExpr = dyn_cast<OMPIteratorExpr>(
9151 C->getIteratorModifier()->IgnoreParenImpCasts())) {
9152 const auto *VD = cast<VarDecl>(IteratorExpr->getIteratorDecl(0));
9153 CGF.EmitVarDecl(*VD);
9154 }
9155 }
9156
9157 const auto *EI = C->getVarRefs().begin();
9158 for (const auto L : C->component_lists()) {
9159 InfoGen(std::get<0>(L), Kind, std::get<1>(L), OMPC_MAP_to, {},
9160 C->getMotionModifiers(), /*ReturnDevicePointer=*/false,
9161 C->isImplicit(), std::get<2>(L), *EI);
9162 ++EI;
9163 }
9164 }
9165 for (const auto *Cl : Clauses) {
9166 const auto *C = dyn_cast<OMPFromClause>(Cl);
9167 if (!C)
9168 continue;
9169 MapKind Kind = Other;
9170 if (llvm::is_contained(C->getMotionModifiers(),
9171 OMPC_MOTION_MODIFIER_present))
9172 Kind = Present;
9173 if (llvm::is_contained(C->getMotionModifiers(),
9174 OMPC_MOTION_MODIFIER_iterator)) {
9175 if (auto *IteratorExpr = dyn_cast<OMPIteratorExpr>(
9176 C->getIteratorModifier()->IgnoreParenImpCasts())) {
9177 const auto *VD = cast<VarDecl>(IteratorExpr->getIteratorDecl(0));
9178 CGF.EmitVarDecl(*VD);
9179 }
9180 }
9181
9182 const auto *EI = C->getVarRefs().begin();
9183 for (const auto L : C->component_lists()) {
9184 InfoGen(std::get<0>(L), Kind, std::get<1>(L), OMPC_MAP_from, {},
9185 C->getMotionModifiers(),
9186 /*ReturnDevicePointer=*/false, C->isImplicit(), std::get<2>(L),
9187 *EI);
9188 ++EI;
9189 }
9190 }
9191
9192 // Look at the use_device_ptr and use_device_addr clauses information and
9193 // mark the existing map entries as such. If there is no map information for
9194 // an entry in the use_device_ptr and use_device_addr list, we create one
9195 // with map type 'return_param' and zero size section. It is the user's
9196 // fault if that was not mapped before. If there is no map information, then
9197 // we defer the emission of that entry until all the maps for the same VD
9198 // have been handled.
9199 MapCombinedInfoTy UseDeviceDataCombinedInfo;
9200
9201 auto &&UseDeviceDataCombinedInfoGen =
9202 [&UseDeviceDataCombinedInfo](const ValueDecl *VD, llvm::Value *Ptr,
9203 CodeGenFunction &CGF, bool IsDevAddr,
9204 bool HasUdpFbNullify = false) {
9205 UseDeviceDataCombinedInfo.Exprs.push_back(VD);
9206 UseDeviceDataCombinedInfo.BasePointers.emplace_back(Ptr);
9207 UseDeviceDataCombinedInfo.DevicePtrDecls.emplace_back(VD);
9208 UseDeviceDataCombinedInfo.DevicePointers.emplace_back(
9209 IsDevAddr ? DeviceInfoTy::Address : DeviceInfoTy::Pointer);
9210 // FIXME: For use_device_addr on array-sections, this should
9211 // be the starting address of the section.
9212 // e.g. int *p;
9213 // ... use_device_addr(p[3])
9214 // &p[0], &p[3], /*size=*/0, RETURN_PARAM
9215 UseDeviceDataCombinedInfo.Pointers.push_back(Ptr);
9216 UseDeviceDataCombinedInfo.Sizes.push_back(
9217 llvm::Constant::getNullValue(CGF.Int64Ty));
9218 OpenMPOffloadMappingFlags Flags =
9219 OpenMPOffloadMappingFlags::OMP_MAP_RETURN_PARAM;
9220 if (HasUdpFbNullify)
9221 Flags |= OpenMPOffloadMappingFlags::OMP_MAP_FB_NULLIFY;
9222 UseDeviceDataCombinedInfo.Types.push_back(Flags);
9223 UseDeviceDataCombinedInfo.HasAttachPtr.push_back(false);
9224 UseDeviceDataCombinedInfo.Mappers.push_back(nullptr);
9225 };
9226
9227 auto &&MapInfoGen =
9228 [&UseDeviceDataCombinedInfoGen](
9229 CodeGenFunction &CGF, const Expr *IE, const ValueDecl *VD,
9231 Components,
9232 bool IsDevAddr, bool IEIsAttachPtrForDevAddr = false,
9233 bool HasUdpFbNullify = false) {
9234 // We didn't find any match in our map information - generate a zero
9235 // size array section.
9236 llvm::Value *Ptr;
9237 if (IsDevAddr && !IEIsAttachPtrForDevAddr) {
9238 if (IE->isGLValue())
9239 Ptr = CGF.EmitLValue(IE).getPointer(CGF);
9240 else
9241 Ptr = CGF.EmitScalarExpr(IE);
9242 } else {
9243 Ptr = CGF.EmitLoadOfScalar(CGF.EmitLValue(IE), IE->getExprLoc());
9244 }
9245 bool TreatDevAddrAsDevPtr = IEIsAttachPtrForDevAddr;
9246 // For the purpose of address-translation, treat something like the
9247 // following:
9248 // int *p;
9249 // ... use_device_addr(p[1])
9250 // equivalent to
9251 // ... use_device_ptr(p)
9252 UseDeviceDataCombinedInfoGen(VD, Ptr, CGF, /*IsDevAddr=*/IsDevAddr &&
9253 !TreatDevAddrAsDevPtr,
9254 HasUdpFbNullify);
9255 };
9256
9257 auto &&IsMapInfoExist =
9258 [&Info, this](CodeGenFunction &CGF, const ValueDecl *VD, const Expr *IE,
9259 const Expr *DesiredAttachPtrExpr, bool IsDevAddr,
9260 bool HasUdpFbNullify = false) -> bool {
9261 // We potentially have map information for this declaration already.
9262 // Look for the first set of components that refer to it. If found,
9263 // return true.
9264 // If the first component is a member expression, we have to look into
9265 // 'this', which maps to null in the map of map information. Otherwise
9266 // look directly for the information.
9267 auto It = Info.find(isa<MemberExpr>(IE) ? nullptr : VD);
9268 if (It != Info.end()) {
9269 bool Found = false;
9270 for (auto &Data : It->second) {
9271 MapInfo *CI = nullptr;
9272 // We potentially have multiple maps for the same decl. We need to
9273 // only consider those for which the attach-ptr matches the desired
9274 // attach-ptr.
9275 auto *It = llvm::find_if(Data, [&](const MapInfo &MI) {
9276 if (MI.Components.back().getAssociatedDeclaration() != VD)
9277 return false;
9278
9279 const Expr *MapAttachPtr = getAttachPtrExpr(MI.Components);
9280 bool Match = AttachPtrComparator.areEqual(MapAttachPtr,
9281 DesiredAttachPtrExpr);
9282 return Match;
9283 });
9284
9285 if (It != Data.end())
9286 CI = &*It;
9287
9288 if (CI) {
9289 if (IsDevAddr) {
9290 CI->ForDeviceAddr = true;
9291 CI->ReturnDevicePointer = true;
9292 CI->HasUdpFbNullify = HasUdpFbNullify;
9293 Found = true;
9294 break;
9295 } else {
9296 auto PrevCI = std::next(CI->Components.rbegin());
9297 const auto *VarD = dyn_cast<VarDecl>(VD);
9298 const Expr *AttachPtrExpr = getAttachPtrExpr(CI->Components);
9299 if (CGF.CGM.getOpenMPRuntime().hasRequiresUnifiedSharedMemory() ||
9300 isa<MemberExpr>(IE) ||
9301 !VD->getType().getNonReferenceType()->isPointerType() ||
9302 PrevCI == CI->Components.rend() ||
9303 isa<MemberExpr>(PrevCI->getAssociatedExpression()) || !VarD ||
9304 VarD->hasLocalStorage() ||
9305 (isa_and_nonnull<DeclRefExpr>(AttachPtrExpr) &&
9306 VD == cast<DeclRefExpr>(AttachPtrExpr)->getDecl())) {
9307 CI->ForDeviceAddr = IsDevAddr;
9308 CI->ReturnDevicePointer = true;
9309 CI->HasUdpFbNullify = HasUdpFbNullify;
9310 Found = true;
9311 break;
9312 }
9313 }
9314 }
9315 }
9316 return Found;
9317 }
9318 return false;
9319 };
9320
9321 // Look at the use_device_ptr clause information and mark the existing map
9322 // entries as such. If there is no map information for an entry in the
9323 // use_device_ptr list, we create one with map type 'alloc' and zero size
9324 // section. It is the user fault if that was not mapped before. If there is
9325 // no map information and the pointer is a struct member, then we defer the
9326 // emission of that entry until the whole struct has been processed.
9327 for (const auto *Cl : Clauses) {
9328 const auto *C = dyn_cast<OMPUseDevicePtrClause>(Cl);
9329 if (!C)
9330 continue;
9331 bool HasUdpFbNullify =
9332 C->getFallbackModifier() == OMPC_USE_DEVICE_PTR_FALLBACK_fb_nullify;
9333 for (const auto L : C->component_lists()) {
9335 std::get<1>(L);
9336 assert(!Components.empty() &&
9337 "Not expecting empty list of components!");
9338 const ValueDecl *VD = Components.back().getAssociatedDeclaration();
9340 const Expr *IE = Components.back().getAssociatedExpression();
9341 // For use_device_ptr, we match an existing map clause if its attach-ptr
9342 // is same as the use_device_ptr operand. e.g.
9343 // map expr | use_device_ptr expr | current behavior
9344 // ---------|---------------------|-----------------
9345 // p[1] | p | match
9346 // ps->a | ps | match
9347 // p | p | no match
9348 const Expr *UDPOperandExpr =
9349 Components.front().getAssociatedExpression();
9350 if (IsMapInfoExist(CGF, VD, IE,
9351 /*DesiredAttachPtrExpr=*/UDPOperandExpr,
9352 /*IsDevAddr=*/false, HasUdpFbNullify))
9353 continue;
9354 MapInfoGen(CGF, IE, VD, Components, /*IsDevAddr=*/false,
9355 /*IEIsAttachPtrForDevAddr=*/false, HasUdpFbNullify);
9356 }
9357 }
9358
9359 llvm::SmallDenseSet<CanonicalDeclPtr<const Decl>, 4> Processed;
9360 for (const auto *Cl : Clauses) {
9361 const auto *C = dyn_cast<OMPUseDeviceAddrClause>(Cl);
9362 if (!C)
9363 continue;
9364 for (const auto L : C->component_lists()) {
9366 std::get<1>(L);
9367 assert(!std::get<1>(L).empty() &&
9368 "Not expecting empty list of components!");
9369 const ValueDecl *VD = std::get<1>(L).back().getAssociatedDeclaration();
9370 if (!Processed.insert(VD).second)
9371 continue;
9373 // For use_device_addr, we match an existing map clause if the
9374 // use_device_addr operand's attach-ptr matches the map operand's
9375 // attach-ptr.
9376 // We chould also restrict to only match cases when there is a full
9377 // match between the map/use_device_addr clause exprs, but that may be
9378 // unnecessary.
9379 //
9380 // map expr | use_device_addr expr | current | possible restrictive/
9381 // | | behavior | safer behavior
9382 // ---------|----------------------|-----------|-----------------------
9383 // p | p | match | match
9384 // p[0] | p[0] | match | match
9385 // p[0:1] | p[0] | match | no match
9386 // p[0:1] | p[2:1] | match | no match
9387 // p[1] | p[0] | match | no match
9388 // ps->a | ps->b | match | no match
9389 // p | p[0] | no match | no match
9390 // pp | pp[0][0] | no match | no match
9391 const Expr *UDAAttachPtrExpr = getAttachPtrExpr(Components);
9392 const Expr *IE = std::get<1>(L).back().getAssociatedExpression();
9393 assert((!UDAAttachPtrExpr || UDAAttachPtrExpr == IE) &&
9394 "use_device_addr operand has an attach-ptr, but does not match "
9395 "last component's expr.");
9396 if (IsMapInfoExist(CGF, VD, IE,
9397 /*DesiredAttachPtrExpr=*/UDAAttachPtrExpr,
9398 /*IsDevAddr=*/true))
9399 continue;
9400 MapInfoGen(CGF, IE, VD, Components,
9401 /*IsDevAddr=*/true,
9402 /*IEIsAttachPtrForDevAddr=*/UDAAttachPtrExpr != nullptr);
9403 }
9404 }
9405
9406 for (const auto &Data : Info) {
9407 MapCombinedInfoTy CurInfo;
9408 const Decl *D = Data.first;
9409 const ValueDecl *VD = cast_or_null<ValueDecl>(D);
9410 // Group component lists by their AttachPtrExpr and process them in order
9411 // of increasing complexity (nullptr first, then simple expressions like
9412 // p, then more complex ones like p[0], etc.)
9413 //
9414 // This is similar to how generateInfoForCaptureFromClauseInfo handles
9415 // grouping for target constructs.
9416 SmallVector<std::pair<const Expr *, MapInfo>, 16> AttachPtrMapInfoPairs;
9417
9418 // First, collect all MapData entries with their attach-ptr exprs.
9419 for (const auto &M : Data.second) {
9420 for (const MapInfo &L : M) {
9421 assert(!L.Components.empty() &&
9422 "Not expecting declaration with no component lists.");
9423
9424 const Expr *AttachPtrExpr = getAttachPtrExpr(L.Components);
9425 AttachPtrMapInfoPairs.emplace_back(AttachPtrExpr, L);
9426 }
9427 }
9428
9429 // Next, sort by increasing order of their complexity.
9430 llvm::stable_sort(AttachPtrMapInfoPairs,
9431 [this](const auto &LHS, const auto &RHS) {
9432 return AttachPtrComparator(LHS.first, RHS.first);
9433 });
9434
9435 // And finally, process them all in order, grouping those with
9436 // equivalent attach-ptr exprs together.
9437 auto *It = AttachPtrMapInfoPairs.begin();
9438 while (It != AttachPtrMapInfoPairs.end()) {
9439 const Expr *AttachPtrExpr = It->first;
9440
9441 SmallVector<MapInfo, 8> GroupLists;
9442 while (It != AttachPtrMapInfoPairs.end() &&
9443 (It->first == AttachPtrExpr ||
9444 AttachPtrComparator.areEqual(It->first, AttachPtrExpr))) {
9445 GroupLists.push_back(It->second);
9446 ++It;
9447 }
9448 assert(!GroupLists.empty() && "GroupLists should not be empty");
9449
9450 StructRangeInfoTy PartialStruct;
9451 AttachInfoTy AttachInfo;
9452 MapCombinedInfoTy GroupCurInfo;
9453 // Current group's struct base information:
9454 MapCombinedInfoTy GroupStructBaseCurInfo;
9455 for (const MapInfo &L : GroupLists) {
9456 // Remember the current base pointer index.
9457 unsigned CurrentBasePointersIdx = GroupCurInfo.BasePointers.size();
9458 unsigned StructBasePointersIdx =
9459 GroupStructBaseCurInfo.BasePointers.size();
9460
9461 GroupCurInfo.NonContigInfo.IsNonContiguous =
9462 L.Components.back().isNonContiguous();
9463 generateInfoForComponentList(
9464 L.MapType, L.MapModifiers, L.MotionModifiers, L.Components,
9465 GroupCurInfo, GroupStructBaseCurInfo, PartialStruct, AttachInfo,
9466 /*IsFirstComponentList=*/false, L.IsImplicit,
9467 /*GenerateAllInfoForClauses*/ true, L.Mapper, L.ForDeviceAddr, VD,
9468 L.VarRef, /*OverlappedElements*/ {});
9469
9470 // If this entry relates to a device pointer, set the relevant
9471 // declaration and add the 'return pointer' flag.
9472 if (L.ReturnDevicePointer) {
9473 // Check whether a value was added to either GroupCurInfo or
9474 // GroupStructBaseCurInfo and error if no value was added to either
9475 // of them:
9476 assert((CurrentBasePointersIdx < GroupCurInfo.BasePointers.size() ||
9477 StructBasePointersIdx <
9478 GroupStructBaseCurInfo.BasePointers.size()) &&
9479 "Unexpected number of mapped base pointers.");
9480
9481 // Choose a base pointer index which is always valid:
9482 const ValueDecl *RelevantVD =
9483 L.Components.back().getAssociatedDeclaration();
9484 assert(RelevantVD &&
9485 "No relevant declaration related with device pointer??");
9486
9487 // If GroupStructBaseCurInfo has been updated this iteration then
9488 // work on the first new entry added to it i.e. make sure that when
9489 // multiple values are added to any of the lists, the first value
9490 // added is being modified by the assignments below (not the last
9491 // value added).
9492 auto SetDevicePointerInfo = [&](MapCombinedInfoTy &Info,
9493 unsigned Idx) {
9494 Info.DevicePtrDecls[Idx] = RelevantVD;
9495 Info.DevicePointers[Idx] = L.ForDeviceAddr
9496 ? DeviceInfoTy::Address
9497 : DeviceInfoTy::Pointer;
9498 Info.Types[Idx] |=
9499 OpenMPOffloadMappingFlags::OMP_MAP_RETURN_PARAM;
9500 if (L.HasUdpFbNullify)
9501 Info.Types[Idx] |=
9502 OpenMPOffloadMappingFlags::OMP_MAP_FB_NULLIFY;
9503 };
9504
9505 if (StructBasePointersIdx <
9506 GroupStructBaseCurInfo.BasePointers.size())
9507 SetDevicePointerInfo(GroupStructBaseCurInfo,
9508 StructBasePointersIdx);
9509 else
9510 SetDevicePointerInfo(GroupCurInfo, CurrentBasePointersIdx);
9511 }
9512 }
9513
9514 // Unify entries in one list making sure the struct mapping precedes the
9515 // individual fields:
9516 MapCombinedInfoTy GroupUnionCurInfo;
9517 GroupUnionCurInfo.append(GroupStructBaseCurInfo);
9518 GroupUnionCurInfo.append(GroupCurInfo);
9519
9520 // If there is an entry in PartialStruct it means we have a struct with
9521 // individual members mapped. Emit an extra combined entry.
9522 if (PartialStruct.Base.isValid()) {
9523 // Prepend a synthetic dimension of length 1 to represent the
9524 // aggregated struct object. Using 1 (not 0, as 0 produced an
9525 // incorrect non-contiguous descriptor (DimSize==1), causing the
9526 // non-contiguous motion clause path to be skipped.) is important:
9527 // * It preserves the correct rank so targetDataUpdate() computes
9528 // DimSize == 2 for cases like strided array sections originating
9529 // from user-defined mappers (e.g. test with s.data[0:8:2]).
9530 GroupUnionCurInfo.NonContigInfo.Dims.insert(
9531 GroupUnionCurInfo.NonContigInfo.Dims.begin(), 1);
9532 emitCombinedEntry(
9533 CurInfo, GroupUnionCurInfo.Types, PartialStruct, AttachInfo,
9534 /*IsMapThis=*/!VD, OMPBuilder, VD,
9535 /*OffsetForMemberOfFlag=*/CombinedInfo.BasePointers.size(),
9536 /*NotTargetParams=*/true);
9537 }
9538
9539 // Append this group's results to the overall CurInfo in the correct
9540 // order: combined-entry -> original-field-entries -> attach-entry
9541 CurInfo.append(GroupUnionCurInfo);
9542 if (AttachInfo.isValid())
9543 emitAttachEntry(CGF, CurInfo, AttachInfo);
9544 }
9545
9546 // We need to append the results of this capture to what we already have.
9547 CombinedInfo.append(CurInfo);
9548 }
9549 // Append data for use_device_ptr/addr clauses.
9550 CombinedInfo.append(UseDeviceDataCombinedInfo);
9551 }
9552
9553public:
9554 MappableExprsHandler(const OMPExecutableDirective &Dir, CodeGenFunction &CGF)
9555 : CurDir(&Dir), CGF(CGF), AttachPtrComparator(*this) {
9556 // Extract firstprivate clause information.
9557 for (const auto *C : Dir.getClausesOfKind<OMPFirstprivateClause>())
9558 for (const auto *D : C->varlist()) {
9559 const ValueDecl *VD = cast<DeclRefExpr>(D)->getDecl();
9560 if (const auto *BD = dyn_cast<BindingDecl>(VD))
9561 VD = cast<VarDecl>(BD->getDecomposedDecl());
9562 FirstPrivateDecls.try_emplace(cast<VarDecl>(VD), C->isImplicit());
9563 }
9564 // Extract implicit firstprivates from uses_allocators clauses.
9565 for (const auto *C : Dir.getClausesOfKind<OMPUsesAllocatorsClause>()) {
9566 for (unsigned I = 0, E = C->getNumberOfAllocators(); I < E; ++I) {
9567 OMPUsesAllocatorsClause::Data D = C->getAllocatorData(I);
9568 if (const auto *DRE = dyn_cast_or_null<DeclRefExpr>(D.AllocatorTraits))
9569 FirstPrivateDecls.try_emplace(cast<VarDecl>(DRE->getDecl()),
9570 /*Implicit=*/true);
9571 else if (const auto *VD = dyn_cast<VarDecl>(
9572 cast<DeclRefExpr>(D.Allocator->IgnoreParenImpCasts())
9573 ->getDecl()))
9574 FirstPrivateDecls.try_emplace(VD, /*Implicit=*/true);
9575 }
9576 }
9577 // Extract defaultmap clause information.
9578 for (const auto *C : Dir.getClausesOfKind<OMPDefaultmapClause>())
9579 if (C->getDefaultmapModifier() == OMPC_DEFAULTMAP_MODIFIER_firstprivate)
9580 DefaultmapFirstprivateKinds.insert(C->getDefaultmapKind());
9581 // Extract device pointer clause information.
9582 for (const auto *C : Dir.getClausesOfKind<OMPIsDevicePtrClause>())
9583 for (auto L : C->component_lists())
9584 DevPointersMap[std::get<0>(L)].push_back(std::get<1>(L));
9585 // Extract device addr clause information.
9586 for (const auto *C : Dir.getClausesOfKind<OMPHasDeviceAddrClause>())
9587 for (auto L : C->component_lists())
9588 HasDevAddrsMap[std::get<0>(L)].push_back(std::get<1>(L));
9589 // Extract map information.
9590 for (const auto *C : Dir.getClausesOfKind<OMPMapClause>()) {
9591 if (C->getMapType() != OMPC_MAP_to)
9592 continue;
9593 for (auto L : C->component_lists()) {
9594 const ValueDecl *VD = std::get<0>(L);
9595 const auto *RD = VD ? VD->getType()
9596 .getCanonicalType()
9597 .getNonReferenceType()
9598 ->getAsCXXRecordDecl()
9599 : nullptr;
9600 if (RD && RD->isLambda())
9601 LambdasMap.try_emplace(std::get<0>(L), C);
9602 }
9603 }
9604
9605 auto CollectAttachPtrExprsForClauseComponents = [this](const auto *C) {
9606 for (auto L : C->component_lists()) {
9608 std::get<1>(L);
9609 if (!Components.empty())
9610 collectAttachPtrExprInfo(Components, CurDir);
9611 }
9612 };
9613
9614 // Populate the AttachPtrExprMap for all component lists from map-related
9615 // clauses.
9616 for (const auto *C : Dir.getClausesOfKind<OMPMapClause>())
9617 CollectAttachPtrExprsForClauseComponents(C);
9618 for (const auto *C : Dir.getClausesOfKind<OMPToClause>())
9619 CollectAttachPtrExprsForClauseComponents(C);
9620 for (const auto *C : Dir.getClausesOfKind<OMPFromClause>())
9621 CollectAttachPtrExprsForClauseComponents(C);
9622 for (const auto *C : Dir.getClausesOfKind<OMPUseDevicePtrClause>())
9623 CollectAttachPtrExprsForClauseComponents(C);
9624 for (const auto *C : Dir.getClausesOfKind<OMPUseDeviceAddrClause>())
9625 CollectAttachPtrExprsForClauseComponents(C);
9626 for (const auto *C : Dir.getClausesOfKind<OMPIsDevicePtrClause>())
9627 CollectAttachPtrExprsForClauseComponents(C);
9628 for (const auto *C : Dir.getClausesOfKind<OMPHasDeviceAddrClause>())
9629 CollectAttachPtrExprsForClauseComponents(C);
9630 }
9631
9632 /// Constructor for the declare mapper directive.
9633 MappableExprsHandler(const OMPDeclareMapperDecl &Dir, CodeGenFunction &CGF)
9634 : CurDir(&Dir), CGF(CGF), AttachPtrComparator(*this) {
9635 auto CollectAttachPtrExprsForClauseComponents = [this](const auto *C) {
9636 for (auto L : C->component_lists()) {
9638 std::get<1>(L);
9639 if (!Components.empty())
9640 collectAttachPtrExprInfo(Components, CurDir);
9641 }
9642 };
9643
9644 // Populate the AttachPtrExprMap for all component lists from map-related
9645 // clauses in the declare mapper directive, to enable attach-style mapping
9646 // for mappers.
9647 for (const auto *Cl : Dir.clauses()) {
9648 if (const auto *C = dyn_cast<OMPMapClause>(Cl))
9649 CollectAttachPtrExprsForClauseComponents(C);
9650 else if (const auto *C = dyn_cast<OMPToClause>(Cl))
9651 CollectAttachPtrExprsForClauseComponents(C);
9652 else if (const auto *C = dyn_cast<OMPFromClause>(Cl))
9653 CollectAttachPtrExprsForClauseComponents(C);
9654 }
9655 }
9656
9657 /// Generate code for the combined entry if we have a partially mapped struct
9658 /// and take care of the mapping flags of the arguments corresponding to
9659 /// individual struct members.
9660 /// If a valid \p AttachInfo exists, its pointee addr will be updated to point
9661 /// to the combined-entry's begin address, if emitted.
9662 /// \p PartialStruct contains attach base-pointer information.
9663 /// \returns The index of the combined entry if one was added, std::nullopt
9664 /// otherwise.
9665 void emitCombinedEntry(MapCombinedInfoTy &CombinedInfo,
9666 MapFlagsArrayTy &CurTypes,
9667 const StructRangeInfoTy &PartialStruct,
9668 AttachInfoTy &AttachInfo, bool IsMapThis,
9669 llvm::OpenMPIRBuilder &OMPBuilder, const ValueDecl *VD,
9670 unsigned OffsetForMemberOfFlag,
9671 bool NotTargetParams) const {
9672 if (CurTypes.size() == 1 &&
9673 ((CurTypes.back() & OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF) !=
9674 OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF) &&
9675 !PartialStruct.IsArraySection)
9676 return;
9677 Address LBAddr = PartialStruct.LowestElem.second;
9678 Address HBAddr = PartialStruct.HighestElem.second;
9679 if (PartialStruct.HasCompleteRecord) {
9680 LBAddr = PartialStruct.LB;
9681 HBAddr = PartialStruct.LB;
9682 }
9683 CombinedInfo.Exprs.push_back(VD);
9684 // Base is the base of the struct
9685 CombinedInfo.BasePointers.push_back(PartialStruct.Base.emitRawPointer(CGF));
9686 CombinedInfo.DevicePtrDecls.push_back(nullptr);
9687 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
9688 // Pointer is the address of the lowest element
9689 llvm::Value *LB = LBAddr.emitRawPointer(CGF);
9690 const CXXMethodDecl *MD =
9691 CGF.CurFuncDecl ? dyn_cast<CXXMethodDecl>(CGF.CurFuncDecl) : nullptr;
9692 const CXXRecordDecl *RD = MD ? MD->getParent() : nullptr;
9693 bool HasBaseClass = RD && IsMapThis ? RD->getNumBases() > 0 : false;
9694 // There should not be a mapper for a combined entry.
9695 if (HasBaseClass) {
9696 // OpenMP 5.2 148:21:
9697 // If the target construct is within a class non-static member function,
9698 // and a variable is an accessible data member of the object for which the
9699 // non-static data member function is invoked, the variable is treated as
9700 // if the this[:1] expression had appeared in a map clause with a map-type
9701 // of tofrom.
9702 // Emit this[:1]
9703 CombinedInfo.Pointers.push_back(PartialStruct.Base.emitRawPointer(CGF));
9704 QualType Ty = MD->getFunctionObjectParameterType();
9705 llvm::Value *Size =
9706 CGF.Builder.CreateIntCast(CGF.getTypeSize(Ty), CGF.Int64Ty,
9707 /*isSigned=*/true);
9708 CombinedInfo.Sizes.push_back(Size);
9709 } else {
9710 CombinedInfo.Pointers.push_back(LB);
9711 // Size is (addr of {highest+1} element) - (addr of lowest element)
9712 llvm::Value *HB = HBAddr.emitRawPointer(CGF);
9713 llvm::Value *HAddr = CGF.Builder.CreateConstGEP1_32(
9714 HBAddr.getElementType(), HB, /*Idx0=*/1);
9715 llvm::Value *CLAddr = CGF.Builder.CreatePointerCast(LB, CGF.VoidPtrTy);
9716 llvm::Value *CHAddr = CGF.Builder.CreatePointerCast(HAddr, CGF.VoidPtrTy);
9717 llvm::Value *Diff = CGF.Builder.CreatePtrDiff(CHAddr, CLAddr);
9718 llvm::Value *Size = CGF.Builder.CreateIntCast(Diff, CGF.Int64Ty,
9719 /*isSigned=*/false);
9720 CombinedInfo.Sizes.push_back(Size);
9721 }
9722 CombinedInfo.Mappers.push_back(nullptr);
9723 // Map type is always TARGET_PARAM, if generate info for captures.
9724 CombinedInfo.Types.push_back(
9725 NotTargetParams ? OpenMPOffloadMappingFlags::OMP_MAP_NONE
9726 : !PartialStruct.PreliminaryMapData.BasePointers.empty()
9727 ? OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ
9728 : OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM);
9729 // A combined entry has a base attach-ptr if its constituents do. e.g.:
9730 // map(s2.s1p->x, s2.s1p->y)
9731 // combined entry:
9732 // s2.s1p[0], s2.s1p->x, sizeof(s1p->x..y), ALLOC
9733 // here s2.s1p is the attach-ptr for the combined entry.
9734 // See the inline comments in emitUserDefinedMapper's definition for how
9735 // entries with an attach-ptr are treated.
9736 CombinedInfo.HasAttachPtr.push_back(AttachInfo.isValid());
9737 // If any element has the present modifier, then make sure the runtime
9738 // doesn't attempt to allocate the struct.
9739 if (CurTypes.end() !=
9740 llvm::find_if(CurTypes, [](OpenMPOffloadMappingFlags Type) {
9741 return static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
9742 Type & OpenMPOffloadMappingFlags::OMP_MAP_PRESENT);
9743 }))
9744 CombinedInfo.Types.back() |= OpenMPOffloadMappingFlags::OMP_MAP_PRESENT;
9745 // Remove TARGET_PARAM flag from the first element
9746 (*CurTypes.begin()) &= ~OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM;
9747 // If any element has the ompx_hold modifier, then make sure the runtime
9748 // uses the hold reference count for the struct as a whole so that it won't
9749 // be unmapped by an extra dynamic reference count decrement. Add it to all
9750 // elements as well so the runtime knows which reference count to check
9751 // when determining whether it's time for device-to-host transfers of
9752 // individual elements.
9753 if (CurTypes.end() !=
9754 llvm::find_if(CurTypes, [](OpenMPOffloadMappingFlags Type) {
9755 return static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
9756 Type & OpenMPOffloadMappingFlags::OMP_MAP_OMPX_HOLD);
9757 })) {
9758 CombinedInfo.Types.back() |= OpenMPOffloadMappingFlags::OMP_MAP_OMPX_HOLD;
9759 for (auto &M : CurTypes)
9760 M |= OpenMPOffloadMappingFlags::OMP_MAP_OMPX_HOLD;
9761 }
9762
9763 // All other current entries will be MEMBER_OF the combined entry
9764 // (except for PTR_AND_OBJ entries which do not have a placeholder value
9765 // 0xFFFF in the MEMBER_OF field, or ATTACH entries since they are expected
9766 // to be handled by themselves, after all other maps).
9767 OpenMPOffloadMappingFlags MemberOfFlag = OMPBuilder.getMemberOfFlag(
9768 OffsetForMemberOfFlag + CombinedInfo.BasePointers.size() - 1);
9769 for (auto &M : CurTypes)
9770 OMPBuilder.setCorrectMemberOfFlag(M, MemberOfFlag);
9771
9772 // When we are emitting a combined entry. If there were any pending
9773 // attachments to be done, we do them to the begin address of the combined
9774 // entry. Note that this means only one attachment per combined-entry will
9775 // be done. So, for instance, if we have:
9776 // S *ps;
9777 // ... map(ps->a, ps->b)
9778 // When we are emitting a combined entry. If AttachInfo is valid,
9779 // update the pointee address to point to the begin address of the combined
9780 // entry. This ensures that if we have multiple maps like:
9781 // `map(ps->a, ps->b)`, we still get a single ATTACH entry, like:
9782 //
9783 // &ps[0], &ps->a, sizeof(ps->a to ps->b), ALLOC // combined-entry
9784 // &ps[0], &ps->a, sizeof(ps->a), TO | FROM
9785 // &ps[0], &ps->b, sizeof(ps->b), TO | FROM
9786 // &ps, &ps->a, sizeof(void*), ATTACH // Use combined-entry's LB
9787 if (AttachInfo.isValid())
9788 AttachInfo.AttachPteeAddr = LBAddr;
9789 }
9790
9791 /// Generate all the base pointers, section pointers, sizes, map types, and
9792 /// mappers for the extracted mappable expressions (all included in \a
9793 /// CombinedInfo). Also, for each item that relates with a device pointer, a
9794 /// pair of the relevant declaration and index where it occurs is appended to
9795 /// the device pointers info array.
9796 void generateAllInfo(
9797 MapCombinedInfoTy &CombinedInfo, llvm::OpenMPIRBuilder &OMPBuilder,
9798 const llvm::DenseSet<CanonicalDeclPtr<const Decl>> &SkipVarSet =
9799 llvm::DenseSet<CanonicalDeclPtr<const Decl>>()) const {
9800 assert(isa<const OMPExecutableDirective *>(CurDir) &&
9801 "Expect a executable directive");
9802 const auto *CurExecDir = cast<const OMPExecutableDirective *>(CurDir);
9803 generateAllInfoForClauses(CurExecDir->clauses(), CombinedInfo, OMPBuilder,
9804 SkipVarSet);
9805 }
9806
9807 /// Generate all the base pointers, section pointers, sizes, map types, and
9808 /// mappers for the extracted map clauses of user-defined mapper (all included
9809 /// in \a CombinedInfo).
9810 void generateAllInfoForMapper(MapCombinedInfoTy &CombinedInfo,
9811 llvm::OpenMPIRBuilder &OMPBuilder) const {
9812 assert(isa<const OMPDeclareMapperDecl *>(CurDir) &&
9813 "Expect a declare mapper directive");
9814 const auto *CurMapperDir = cast<const OMPDeclareMapperDecl *>(CurDir);
9815 generateAllInfoForClauses(CurMapperDir->clauses(), CombinedInfo,
9816 OMPBuilder);
9817 }
9818
9819 /// Emit capture info for lambdas for variables captured by reference.
9820 void generateInfoForLambdaCaptures(
9821 const ValueDecl *VD, llvm::Value *Arg, MapCombinedInfoTy &CombinedInfo,
9822 llvm::DenseMap<llvm::Value *, llvm::Value *> &LambdaPointers) const {
9823 QualType VDType = VD->getType().getCanonicalType().getNonReferenceType();
9824 const auto *RD = VDType->getAsCXXRecordDecl();
9825 if (!RD || !RD->isLambda())
9826 return;
9827 Address VDAddr(Arg, CGF.ConvertTypeForMem(VDType),
9828 CGF.getContext().getDeclAlign(VD));
9829 LValue VDLVal = CGF.MakeAddrLValue(VDAddr, VDType);
9830 llvm::DenseMap<const ValueDecl *, FieldDecl *> Captures;
9831 FieldDecl *ThisCapture = nullptr;
9832 RD->getCaptureFields(Captures, ThisCapture);
9833 if (ThisCapture) {
9834 LValue ThisLVal =
9835 CGF.EmitLValueForFieldInitialization(VDLVal, ThisCapture);
9836 LValue ThisLValVal = CGF.EmitLValueForField(VDLVal, ThisCapture);
9837 LambdaPointers.try_emplace(ThisLVal.getPointer(CGF),
9838 VDLVal.getPointer(CGF));
9839 CombinedInfo.Exprs.push_back(VD);
9840 CombinedInfo.BasePointers.push_back(ThisLVal.getPointer(CGF));
9841 CombinedInfo.DevicePtrDecls.push_back(nullptr);
9842 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
9843 CombinedInfo.Pointers.push_back(ThisLValVal.getPointer(CGF));
9844 CombinedInfo.Sizes.push_back(
9845 CGF.Builder.CreateIntCast(CGF.getTypeSize(CGF.getContext().VoidPtrTy),
9846 CGF.Int64Ty, /*isSigned=*/true));
9847 CombinedInfo.Types.push_back(
9848 OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ |
9849 OpenMPOffloadMappingFlags::OMP_MAP_LITERAL |
9850 OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF |
9851 OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT);
9852 CombinedInfo.HasAttachPtr.push_back(false);
9853 CombinedInfo.Mappers.push_back(nullptr);
9854 }
9855 for (const LambdaCapture &LC : RD->captures()) {
9856 if (!LC.capturesVariable())
9857 continue;
9858 const VarDecl *VD = cast<VarDecl>(LC.getCapturedVar());
9859 if (LC.getCaptureKind() != LCK_ByRef && !VD->getType()->isPointerType())
9860 continue;
9861 auto It = Captures.find(VD);
9862 assert(It != Captures.end() && "Found lambda capture without field.");
9863 LValue VarLVal = CGF.EmitLValueForFieldInitialization(VDLVal, It->second);
9864 if (LC.getCaptureKind() == LCK_ByRef) {
9865 LValue VarLValVal = CGF.EmitLValueForField(VDLVal, It->second);
9866 LambdaPointers.try_emplace(VarLVal.getPointer(CGF),
9867 VDLVal.getPointer(CGF));
9868 CombinedInfo.Exprs.push_back(VD);
9869 CombinedInfo.BasePointers.push_back(VarLVal.getPointer(CGF));
9870 CombinedInfo.DevicePtrDecls.push_back(nullptr);
9871 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
9872 CombinedInfo.Pointers.push_back(VarLValVal.getPointer(CGF));
9873 CombinedInfo.Sizes.push_back(CGF.Builder.CreateIntCast(
9874 CGF.getTypeSize(
9876 CGF.Int64Ty, /*isSigned=*/true));
9877 } else {
9878 RValue VarRVal = CGF.EmitLoadOfLValue(VarLVal, RD->getLocation());
9879 LambdaPointers.try_emplace(VarLVal.getPointer(CGF),
9880 VDLVal.getPointer(CGF));
9881 CombinedInfo.Exprs.push_back(VD);
9882 CombinedInfo.BasePointers.push_back(VarLVal.getPointer(CGF));
9883 CombinedInfo.DevicePtrDecls.push_back(nullptr);
9884 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
9885 CombinedInfo.Pointers.push_back(VarRVal.getScalarVal());
9886 CombinedInfo.Sizes.push_back(llvm::ConstantInt::get(CGF.Int64Ty, 0));
9887 }
9888 CombinedInfo.Types.push_back(
9889 OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ |
9890 OpenMPOffloadMappingFlags::OMP_MAP_LITERAL |
9891 OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF |
9892 OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT);
9893 CombinedInfo.HasAttachPtr.push_back(false);
9894 CombinedInfo.Mappers.push_back(nullptr);
9895 }
9896 }
9897
9898 /// Set correct indices for lambdas captures.
9899 void adjustMemberOfForLambdaCaptures(
9900 llvm::OpenMPIRBuilder &OMPBuilder,
9901 const llvm::DenseMap<llvm::Value *, llvm::Value *> &LambdaPointers,
9902 MapBaseValuesArrayTy &BasePointers, MapValuesArrayTy &Pointers,
9903 MapFlagsArrayTy &Types) const {
9904 for (unsigned I = 0, E = Types.size(); I < E; ++I) {
9905 // Set correct member_of idx for all implicit lambda captures.
9906 if (Types[I] != (OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ |
9907 OpenMPOffloadMappingFlags::OMP_MAP_LITERAL |
9908 OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF |
9909 OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT))
9910 continue;
9911 llvm::Value *BasePtr = LambdaPointers.lookup(BasePointers[I]);
9912 assert(BasePtr && "Unable to find base lambda address.");
9913 int TgtIdx = -1;
9914 for (unsigned J = I; J > 0; --J) {
9915 unsigned Idx = J - 1;
9916 if (Pointers[Idx] != BasePtr)
9917 continue;
9918 TgtIdx = Idx;
9919 break;
9920 }
9921 assert(TgtIdx != -1 && "Unable to find parent lambda.");
9922 // All other current entries will be MEMBER_OF the combined entry
9923 // (except for PTR_AND_OBJ entries which do not have a placeholder value
9924 // 0xFFFF in the MEMBER_OF field).
9925 OpenMPOffloadMappingFlags MemberOfFlag =
9926 OMPBuilder.getMemberOfFlag(TgtIdx);
9927 OMPBuilder.setCorrectMemberOfFlag(Types[I], MemberOfFlag);
9928 }
9929 }
9930
9931 /// Populate component lists for non-lambda captured variables from map,
9932 /// is_device_ptr and has_device_addr clause info.
9933 void populateComponentListsForNonLambdaCaptureFromClauses(
9934 const ValueDecl *VD, MapDataArrayTy &DeclComponentLists,
9935 SmallVectorImpl<
9936 SmallVector<OMPClauseMappableExprCommon::MappableComponent, 8>>
9937 &StorageForImplicitlyAddedComponentLists) const {
9938 if (VD && LambdasMap.count(VD))
9939 return;
9940
9941 // For member fields list in is_device_ptr, store it in
9942 // DeclComponentLists for generating components info.
9944 auto It = DevPointersMap.find(VD);
9945 if (It != DevPointersMap.end())
9946 for (const auto &MCL : It->second)
9947 DeclComponentLists.emplace_back(MCL, OMPC_MAP_to, Unknown,
9948 /*IsImpicit = */ true, nullptr,
9949 nullptr);
9950 auto I = HasDevAddrsMap.find(VD);
9951 if (I != HasDevAddrsMap.end())
9952 for (const auto &MCL : I->second)
9953 DeclComponentLists.emplace_back(MCL, OMPC_MAP_tofrom, Unknown,
9954 /*IsImpicit = */ true, nullptr,
9955 nullptr);
9956 assert(isa<const OMPExecutableDirective *>(CurDir) &&
9957 "Expect a executable directive");
9958 const auto *CurExecDir = cast<const OMPExecutableDirective *>(CurDir);
9959 for (const auto *C : CurExecDir->getClausesOfKind<OMPMapClause>()) {
9960 const auto *EI = C->getVarRefs().begin();
9961 for (const auto L : C->decl_component_lists(VD)) {
9962 const ValueDecl *VDecl, *Mapper;
9963 // The Expression is not correct if the mapping is implicit
9964 const Expr *E = (C->getMapLoc().isValid()) ? *EI : nullptr;
9966 std::tie(VDecl, Components, Mapper) = L;
9967 assert(VDecl == VD && "We got information for the wrong declaration??");
9968 assert(!Components.empty() &&
9969 "Not expecting declaration with no component lists.");
9970 DeclComponentLists.emplace_back(Components, C->getMapType(),
9971 C->getMapTypeModifiers(),
9972 C->isImplicit(), Mapper, E);
9973 ++EI;
9974 }
9975 }
9976
9977 // For the target construct, if there's a map with a base-pointer that's
9978 // a member of an implicitly captured struct, of the current class,
9979 // we need to emit an implicit map on the pointer.
9980 if (isOpenMPTargetExecutionDirective(CurExecDir->getDirectiveKind()))
9981 addImplicitMapForAttachPtrBaseIfMemberOfCapturedVD(
9982 VD, DeclComponentLists, StorageForImplicitlyAddedComponentLists);
9983
9984 llvm::stable_sort(DeclComponentLists, [](const MapData &LHS,
9985 const MapData &RHS) {
9986 ArrayRef<OpenMPMapModifierKind> MapModifiers = std::get<2>(LHS);
9987 OpenMPMapClauseKind MapType = std::get<1>(RHS);
9988 bool HasPresent =
9989 llvm::is_contained(MapModifiers, clang::OMPC_MAP_MODIFIER_present);
9990 bool HasAllocs = MapType == OMPC_MAP_alloc;
9991 MapModifiers = std::get<2>(RHS);
9992 MapType = std::get<1>(LHS);
9993 bool HasPresentR =
9994 llvm::is_contained(MapModifiers, clang::OMPC_MAP_MODIFIER_present);
9995 bool HasAllocsR = MapType == OMPC_MAP_alloc;
9996 return (HasPresent && !HasPresentR) || (HasAllocs && !HasAllocsR);
9997 });
9998 }
9999
10000 /// On a target construct, if there's an implicit map on a struct, or that of
10001 /// this[:], and an explicit map with a member of that struct/class as the
10002 /// base-pointer, we need to make sure that base-pointer is implicitly mapped,
10003 /// to make sure we don't map the full struct/class. For example:
10004 ///
10005 /// \code
10006 /// struct S {
10007 /// int dummy[10000];
10008 /// int *p;
10009 /// void f1() {
10010 /// #pragma omp target map(p[0:1])
10011 /// (void)this;
10012 /// }
10013 /// }; S s;
10014 ///
10015 /// void f2() {
10016 /// #pragma omp target map(s.p[0:10])
10017 /// (void)s;
10018 /// }
10019 /// \endcode
10020 ///
10021 /// Only `this-p` and `s.p` should be mapped in the two cases above.
10022 //
10023 // OpenMP 6.0: 7.9.6 map clause, pg 285
10024 // If a list item with an implicitly determined data-mapping attribute does
10025 // not have any corresponding storage in the device data environment prior to
10026 // a task encountering the construct associated with the map clause, and one
10027 // or more contiguous parts of the original storage are either list items or
10028 // base pointers to list items that are explicitly mapped on the construct,
10029 // only those parts of the original storage will have corresponding storage in
10030 // the device data environment as a result of the map clauses on the
10031 // construct.
10032 void addImplicitMapForAttachPtrBaseIfMemberOfCapturedVD(
10033 const ValueDecl *CapturedVD, MapDataArrayTy &DeclComponentLists,
10034 SmallVectorImpl<
10035 SmallVector<OMPClauseMappableExprCommon::MappableComponent, 8>>
10036 &ComponentVectorStorage) const {
10037 bool IsThisCapture = CapturedVD == nullptr;
10038
10039 for (const auto &ComponentsAndAttachPtr : AttachPtrExprMap) {
10041 ComponentsWithAttachPtr = ComponentsAndAttachPtr.first;
10042 const Expr *AttachPtrExpr = ComponentsAndAttachPtr.second;
10043 if (!AttachPtrExpr)
10044 continue;
10045
10046 const auto *ME = dyn_cast<MemberExpr>(AttachPtrExpr);
10047 if (!ME)
10048 continue;
10049
10050 const Expr *Base = ME->getBase()->IgnoreParenImpCasts();
10051
10052 // If we are handling a "this" capture, then we are looking for
10053 // attach-ptrs of form `this->p`, either explicitly or implicitly.
10054 if (IsThisCapture && !ME->isImplicitCXXThis() && !isa<CXXThisExpr>(Base))
10055 continue;
10056
10057 if (!IsThisCapture && (!isa<DeclRefExpr>(Base) ||
10058 cast<DeclRefExpr>(Base)->getDecl() != CapturedVD))
10059 continue;
10060
10061 // For non-this captures, we are looking for attach-ptrs of form
10062 // `s.p`.
10063 // For non-this captures, we are looking for attach-ptrs like `s.p`.
10064 if (!IsThisCapture && (ME->isArrow() || !isa<DeclRefExpr>(Base) ||
10065 cast<DeclRefExpr>(Base)->getDecl() != CapturedVD))
10066 continue;
10067
10068 // Check if we have an existing map on either:
10069 // this[:], s, this->p, or s.p, in which case, we don't need to add
10070 // an implicit one for the attach-ptr s.p/this->p.
10071 bool FoundExistingMap = false;
10072 for (const MapData &ExistingL : DeclComponentLists) {
10074 ExistingComponents = std::get<0>(ExistingL);
10075
10076 if (ExistingComponents.empty())
10077 continue;
10078
10079 // First check if we have a map like map(this->p) or map(s.p).
10080 const auto &FirstComponent = ExistingComponents.front();
10081 const Expr *FirstExpr = FirstComponent.getAssociatedExpression();
10082
10083 if (!FirstExpr)
10084 continue;
10085
10086 // First check if we have a map like map(this->p) or map(s.p).
10087 if (AttachPtrComparator.areEqual(FirstExpr, AttachPtrExpr)) {
10088 FoundExistingMap = true;
10089 break;
10090 }
10091
10092 // Check if we have a map like this[0:1]
10093 if (IsThisCapture) {
10094 if (const auto *OASE = dyn_cast<ArraySectionExpr>(FirstExpr)) {
10095 if (isa<CXXThisExpr>(OASE->getBase()->IgnoreParenImpCasts())) {
10096 FoundExistingMap = true;
10097 break;
10098 }
10099 }
10100 continue;
10101 }
10102
10103 // When the attach-ptr is something like `s.p`, check if
10104 // `s` itself is mapped explicitly.
10105 if (const auto *DRE = dyn_cast<DeclRefExpr>(FirstExpr)) {
10106 if (DRE->getDecl() == CapturedVD) {
10107 FoundExistingMap = true;
10108 break;
10109 }
10110 }
10111 }
10112
10113 if (FoundExistingMap)
10114 continue;
10115
10116 // If no base map is found, we need to create an implicit map for the
10117 // attach-pointer expr.
10118
10119 ComponentVectorStorage.emplace_back();
10120 auto &AttachPtrComponents = ComponentVectorStorage.back();
10121
10123 bool SeenAttachPtrComponent = false;
10124 // For creating a map on the attach-ptr `s.p/this->p`, we copy all
10125 // components from the component-list which has `s.p/this->p`
10126 // as the attach-ptr, starting from the component which matches
10127 // `s.p/this->p`. This way, we'll have component-lists of
10128 // `s.p` -> `s`, and `this->p` -> `this`.
10129 for (size_t i = 0; i < ComponentsWithAttachPtr.size(); ++i) {
10130 const auto &Component = ComponentsWithAttachPtr[i];
10131 const Expr *ComponentExpr = Component.getAssociatedExpression();
10132
10133 if (!SeenAttachPtrComponent && ComponentExpr != AttachPtrExpr)
10134 continue;
10135 SeenAttachPtrComponent = true;
10136
10137 AttachPtrComponents.emplace_back(Component.getAssociatedExpression(),
10138 Component.getAssociatedDeclaration(),
10139 Component.isNonContiguous());
10140 }
10141 assert(!AttachPtrComponents.empty() &&
10142 "Could not populate component-lists for mapping attach-ptr");
10143
10144 DeclComponentLists.emplace_back(
10145 AttachPtrComponents, OMPC_MAP_tofrom, Unknown,
10146 /*IsImplicit=*/true, /*mapper=*/nullptr, AttachPtrExpr);
10147 }
10148 }
10149
10150 /// For a capture that has an associated clause, generate the base pointers,
10151 /// section pointers, sizes, map types, and mappers (all included in
10152 /// \a CurCaptureVarInfo).
10153 void generateInfoForCaptureFromClauseInfo(
10154 const MapDataArrayTy &DeclComponentListsFromClauses,
10155 const CapturedStmt::Capture *Cap, llvm::Value *Arg,
10156 MapCombinedInfoTy &CurCaptureVarInfo, llvm::OpenMPIRBuilder &OMPBuilder,
10157 unsigned OffsetForMemberOfFlag) const {
10158 assert(!Cap->capturesVariableArrayType() &&
10159 "Not expecting to generate map info for a variable array type!");
10160
10161 // We need to know when we generating information for the first component
10162 const ValueDecl *VD = Cap->capturesThis()
10163 ? nullptr
10164 : Cap->getCapturedVar()->getCanonicalDecl();
10165
10166 // for map(to: lambda): skip here, processing it in
10167 // generateDefaultMapInfo
10168 if (LambdasMap.count(VD))
10169 return;
10170
10171 // If this declaration appears in a is_device_ptr clause we just have to
10172 // pass the pointer by value. If it is a reference to a declaration, we just
10173 // pass its value.
10174 if (VD && (DevPointersMap.count(VD) || HasDevAddrsMap.count(VD))) {
10175 CurCaptureVarInfo.Exprs.push_back(VD);
10176 CurCaptureVarInfo.BasePointers.emplace_back(Arg);
10177 CurCaptureVarInfo.DevicePtrDecls.emplace_back(VD);
10178 CurCaptureVarInfo.DevicePointers.emplace_back(DeviceInfoTy::Pointer);
10179 CurCaptureVarInfo.Pointers.push_back(Arg);
10180 CurCaptureVarInfo.Sizes.push_back(CGF.Builder.CreateIntCast(
10181 CGF.getTypeSize(CGF.getContext().VoidPtrTy), CGF.Int64Ty,
10182 /*isSigned=*/true));
10183 CurCaptureVarInfo.Types.push_back(
10184 OpenMPOffloadMappingFlags::OMP_MAP_LITERAL |
10185 OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM);
10186 CurCaptureVarInfo.HasAttachPtr.push_back(false);
10187 CurCaptureVarInfo.Mappers.push_back(nullptr);
10188 return;
10189 }
10190
10191 auto GenerateInfoForComponentLists =
10192 [&](ArrayRef<MapData> DeclComponentListsFromClauses,
10193 bool IsEligibleForTargetParamFlag) {
10194 MapCombinedInfoTy CurInfoForComponentLists;
10195 StructRangeInfoTy PartialStruct;
10196 AttachInfoTy AttachInfo;
10197
10198 if (DeclComponentListsFromClauses.empty())
10199 return;
10200
10201 generateInfoForCaptureFromComponentLists(
10202 VD, DeclComponentListsFromClauses, CurInfoForComponentLists,
10203 PartialStruct, AttachInfo, IsEligibleForTargetParamFlag);
10204
10205 // If there is an entry in PartialStruct it means we have a
10206 // struct with individual members mapped. Emit an extra combined
10207 // entry.
10208 if (PartialStruct.Base.isValid()) {
10209 CurCaptureVarInfo.append(PartialStruct.PreliminaryMapData);
10210 emitCombinedEntry(
10211 CurCaptureVarInfo, CurInfoForComponentLists.Types,
10212 PartialStruct, AttachInfo, Cap->capturesThis(), OMPBuilder,
10213 /*VD=*/nullptr, OffsetForMemberOfFlag,
10214 /*NotTargetParams*/ !IsEligibleForTargetParamFlag);
10215 }
10216
10217 // We do the appends to get the entries in the following order:
10218 // combined-entry -> individual-field-entries -> attach-entry,
10219 CurCaptureVarInfo.append(CurInfoForComponentLists);
10220 if (AttachInfo.isValid())
10221 emitAttachEntry(CGF, CurCaptureVarInfo, AttachInfo);
10222 };
10223
10224 // Group component lists by their AttachPtrExpr and process them in order
10225 // of increasing complexity (nullptr first, then simple expressions like p,
10226 // then more complex ones like p[0], etc.)
10227 //
10228 // This ensure that we:
10229 // * handle maps that can contribute towards setting the kernel argument,
10230 // (e.g. map(ps), or map(ps[0])), before any that cannot (e.g. ps->pt->d).
10231 // * allocate a single contiguous storage for all exprs with the same
10232 // captured var and having the same attach-ptr.
10233 //
10234 // Example: The map clauses below should be handled grouped together based
10235 // on their attachable-base-pointers:
10236 // map-clause | attachable-base-pointer
10237 // --------------------------+------------------------
10238 // map(p, ps) | nullptr
10239 // map(p[0]) | p
10240 // map(p[0]->b, p[0]->c) | p[0]
10241 // map(ps->d, ps->e, ps->pt) | ps
10242 // map(ps->pt->d, ps->pt->e) | ps->pt
10243
10244 // First, collect all MapData entries with their attach-ptr exprs.
10245 SmallVector<std::pair<const Expr *, MapData>, 16> AttachPtrMapDataPairs;
10246
10247 for (const MapData &L : DeclComponentListsFromClauses) {
10249 std::get<0>(L);
10250 const Expr *AttachPtrExpr = getAttachPtrExpr(Components);
10251 AttachPtrMapDataPairs.emplace_back(AttachPtrExpr, L);
10252 }
10253
10254 // Next, sort by increasing order of their complexity.
10255 llvm::stable_sort(AttachPtrMapDataPairs,
10256 [this](const auto &LHS, const auto &RHS) {
10257 return AttachPtrComparator(LHS.first, RHS.first);
10258 });
10259
10260 bool NoDefaultMappingDoneForVD = CurCaptureVarInfo.BasePointers.empty();
10261 bool IsFirstGroup = true;
10262
10263 // And finally, process them all in order, grouping those with
10264 // equivalent attach-ptr exprs together.
10265 auto *It = AttachPtrMapDataPairs.begin();
10266 while (It != AttachPtrMapDataPairs.end()) {
10267 const Expr *AttachPtrExpr = It->first;
10268
10269 MapDataArrayTy GroupLists;
10270 while (It != AttachPtrMapDataPairs.end() &&
10271 (It->first == AttachPtrExpr ||
10272 AttachPtrComparator.areEqual(It->first, AttachPtrExpr))) {
10273 GroupLists.push_back(It->second);
10274 ++It;
10275 }
10276 assert(!GroupLists.empty() && "GroupLists should not be empty");
10277
10278 // Determine if this group of component-lists is eligible for TARGET_PARAM
10279 // flag. Only the first group processed should be eligible, and only if no
10280 // default mapping was done.
10281 bool IsEligibleForTargetParamFlag =
10282 IsFirstGroup && NoDefaultMappingDoneForVD;
10283
10284 GenerateInfoForComponentLists(GroupLists, IsEligibleForTargetParamFlag);
10285 IsFirstGroup = false;
10286 }
10287 }
10288
10289 /// Generate the base pointers, section pointers, sizes, map types, and
10290 /// mappers associated to \a DeclComponentLists for a given capture
10291 /// \a VD (all included in \a CurComponentListInfo).
10292 void generateInfoForCaptureFromComponentLists(
10293 const ValueDecl *VD, ArrayRef<MapData> DeclComponentLists,
10294 MapCombinedInfoTy &CurComponentListInfo, StructRangeInfoTy &PartialStruct,
10295 AttachInfoTy &AttachInfo, bool IsListEligibleForTargetParamFlag) const {
10296 // Find overlapping elements (including the offset from the base element).
10297 llvm::SmallDenseMap<
10298 const MapData *,
10299 llvm::SmallVector<
10301 4>
10302 OverlappedData;
10303 size_t Count = 0;
10304 for (const MapData &L : DeclComponentLists) {
10306 OpenMPMapClauseKind MapType;
10307 ArrayRef<OpenMPMapModifierKind> MapModifiers;
10308 bool IsImplicit;
10309 const ValueDecl *Mapper;
10310 const Expr *VarRef;
10311 std::tie(Components, MapType, MapModifiers, IsImplicit, Mapper, VarRef) =
10312 L;
10313 ++Count;
10314 for (const MapData &L1 : ArrayRef(DeclComponentLists).slice(Count)) {
10316 std::tie(Components1, MapType, MapModifiers, IsImplicit, Mapper,
10317 VarRef) = L1;
10318 auto CI = Components.rbegin();
10319 auto CE = Components.rend();
10320 auto SI = Components1.rbegin();
10321 auto SE = Components1.rend();
10322 for (; CI != CE && SI != SE; ++CI, ++SI) {
10323 if (CI->getAssociatedExpression()->getStmtClass() !=
10324 SI->getAssociatedExpression()->getStmtClass())
10325 break;
10326 // Are we dealing with different variables/fields?
10327 if (CI->getAssociatedDeclaration() != SI->getAssociatedDeclaration())
10328 break;
10329 }
10330 // Found overlapping if, at least for one component, reached the head
10331 // of the components list.
10332 if (CI == CE || SI == SE) {
10333 // Ignore it if it is the same component.
10334 if (CI == CE && SI == SE)
10335 continue;
10336 const auto It = (SI == SE) ? CI : SI;
10337 // If one component is a pointer and another one is a kind of
10338 // dereference of this pointer (array subscript, section, dereference,
10339 // etc.), it is not an overlapping.
10340 // Same, if one component is a base and another component is a
10341 // dereferenced pointer memberexpr with the same base.
10342 if (!isa<MemberExpr>(It->getAssociatedExpression()) ||
10343 (std::prev(It)->getAssociatedDeclaration() &&
10344 std::prev(It)
10345 ->getAssociatedDeclaration()
10346 ->getType()
10347 ->isPointerType()) ||
10348 (It->getAssociatedDeclaration() &&
10349 It->getAssociatedDeclaration()->getType()->isPointerType() &&
10350 std::next(It) != CE && std::next(It) != SE))
10351 continue;
10352 const MapData &BaseData = CI == CE ? L : L1;
10354 SI == SE ? Components : Components1;
10355 OverlappedData[&BaseData].push_back(SubData);
10356 }
10357 }
10358 }
10359 // Sort the overlapped elements for each item.
10360 llvm::SmallVector<const FieldDecl *, 4> Layout;
10361 if (!OverlappedData.empty()) {
10362 const Type *BaseType = VD->getType().getCanonicalType().getTypePtr();
10363 const Type *OrigType = BaseType->getPointeeOrArrayElementType();
10364 while (BaseType != OrigType) {
10365 BaseType = OrigType->getCanonicalTypeInternal().getTypePtr();
10366 OrigType = BaseType->getPointeeOrArrayElementType();
10367 }
10368
10369 if (const auto *CRD = BaseType->getAsCXXRecordDecl())
10370 getPlainLayout(CRD, Layout, /*AsBase=*/false);
10371 else {
10372 const auto *RD = BaseType->getAsRecordDecl();
10373 Layout.append(RD->field_begin(), RD->field_end());
10374 }
10375 }
10376 for (auto &Pair : OverlappedData) {
10377 llvm::stable_sort(
10378 Pair.getSecond(),
10379 [&Layout](
10382 Second) {
10383 auto CI = First.rbegin();
10384 auto CE = First.rend();
10385 auto SI = Second.rbegin();
10386 auto SE = Second.rend();
10387 for (; CI != CE && SI != SE; ++CI, ++SI) {
10388 if (CI->getAssociatedExpression()->getStmtClass() !=
10389 SI->getAssociatedExpression()->getStmtClass())
10390 break;
10391 // Are we dealing with different variables/fields?
10392 if (CI->getAssociatedDeclaration() !=
10393 SI->getAssociatedDeclaration())
10394 break;
10395 }
10396
10397 // Lists contain the same elements.
10398 if (CI == CE && SI == SE)
10399 return false;
10400
10401 // List with less elements is less than list with more elements.
10402 if (CI == CE || SI == SE)
10403 return CI == CE;
10404
10405 const auto *FD1 = cast<FieldDecl>(CI->getAssociatedDeclaration());
10406 const auto *FD2 = cast<FieldDecl>(SI->getAssociatedDeclaration());
10407 if (FD1->getParent() == FD2->getParent())
10408 return FD1->getFieldIndex() < FD2->getFieldIndex();
10409 const auto *It =
10410 llvm::find_if(Layout, [FD1, FD2](const FieldDecl *FD) {
10411 return FD == FD1 || FD == FD2;
10412 });
10413 return *It == FD1;
10414 });
10415 }
10416
10417 // Associated with a capture, because the mapping flags depend on it.
10418 // Go through all of the elements with the overlapped elements.
10419 bool AddTargetParamFlag = IsListEligibleForTargetParamFlag;
10420 MapCombinedInfoTy StructBaseCombinedInfo;
10421 for (const auto &Pair : OverlappedData) {
10422 const MapData &L = *Pair.getFirst();
10424 OpenMPMapClauseKind MapType;
10425 ArrayRef<OpenMPMapModifierKind> MapModifiers;
10426 bool IsImplicit;
10427 const ValueDecl *Mapper;
10428 const Expr *VarRef;
10429 std::tie(Components, MapType, MapModifiers, IsImplicit, Mapper, VarRef) =
10430 L;
10431 ArrayRef<OMPClauseMappableExprCommon::MappableExprComponentListRef>
10432 OverlappedComponents = Pair.getSecond();
10433 generateInfoForComponentList(
10434 MapType, MapModifiers, {}, Components, CurComponentListInfo,
10435 StructBaseCombinedInfo, PartialStruct, AttachInfo, AddTargetParamFlag,
10436 IsImplicit, /*GenerateAllInfoForClauses*/ false, Mapper,
10437 /*ForDeviceAddr=*/false, VD, VarRef, OverlappedComponents);
10438 AddTargetParamFlag = false;
10439 }
10440 // Go through other elements without overlapped elements.
10441 for (const MapData &L : DeclComponentLists) {
10443 OpenMPMapClauseKind MapType;
10444 ArrayRef<OpenMPMapModifierKind> MapModifiers;
10445 bool IsImplicit;
10446 const ValueDecl *Mapper;
10447 const Expr *VarRef;
10448 std::tie(Components, MapType, MapModifiers, IsImplicit, Mapper, VarRef) =
10449 L;
10450 auto It = OverlappedData.find(&L);
10451 if (It == OverlappedData.end())
10452 generateInfoForComponentList(
10453 MapType, MapModifiers, {}, Components, CurComponentListInfo,
10454 StructBaseCombinedInfo, PartialStruct, AttachInfo,
10455 AddTargetParamFlag, IsImplicit, /*GenerateAllInfoForClauses*/ false,
10456 Mapper, /*ForDeviceAddr=*/false, VD, VarRef,
10457 /*OverlappedElements*/ {});
10458 AddTargetParamFlag = false;
10459 }
10460 }
10461
10462 /// Check if a variable should be treated as firstprivate due to explicit
10463 /// firstprivate clause or defaultmap(firstprivate:...).
10464 bool isEffectivelyFirstprivate(const VarDecl *VD, QualType Type) const {
10465 // Check explicit firstprivate clauses (not implicit from defaultmap)
10466 auto I = FirstPrivateDecls.find(VD);
10467 if (I != FirstPrivateDecls.end() && !I->getSecond())
10468 return true; // Explicit firstprivate only
10469
10470 // Check defaultmap(firstprivate:scalar) for scalar types
10471 if (DefaultmapFirstprivateKinds.count(OMPC_DEFAULTMAP_scalar)) {
10472 if (Type->isScalarType())
10473 return true;
10474 }
10475
10476 // Check defaultmap(firstprivate:pointer) for pointer types
10477 if (DefaultmapFirstprivateKinds.count(OMPC_DEFAULTMAP_pointer)) {
10478 if (Type->isAnyPointerType())
10479 return true;
10480 }
10481
10482 // Check defaultmap(firstprivate:aggregate) for aggregate types
10483 if (DefaultmapFirstprivateKinds.count(OMPC_DEFAULTMAP_aggregate)) {
10484 if (Type->isAggregateType())
10485 return true;
10486 }
10487
10488 // Check defaultmap(firstprivate:all) for all types
10489 return DefaultmapFirstprivateKinds.count(OMPC_DEFAULTMAP_all);
10490 }
10491
10492 /// Generate the default map information for a given capture \a CI,
10493 /// record field declaration \a RI and captured value \a CV.
10494 void generateDefaultMapInfo(const CapturedStmt::Capture &CI,
10495 const FieldDecl &RI, llvm::Value *CV,
10496 MapCombinedInfoTy &CombinedInfo) const {
10497 bool IsImplicit = true;
10498 // Do the default mapping.
10499 if (CI.capturesThis()) {
10500 CombinedInfo.Exprs.push_back(nullptr);
10501 CombinedInfo.BasePointers.push_back(CV);
10502 CombinedInfo.DevicePtrDecls.push_back(nullptr);
10503 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
10504 CombinedInfo.Pointers.push_back(CV);
10505 const auto *PtrTy = cast<PointerType>(RI.getType().getTypePtr());
10506 CombinedInfo.Sizes.push_back(
10507 CGF.Builder.CreateIntCast(CGF.getTypeSize(PtrTy->getPointeeType()),
10508 CGF.Int64Ty, /*isSigned=*/true));
10509 // Default map type.
10510 CombinedInfo.Types.push_back(OpenMPOffloadMappingFlags::OMP_MAP_TO |
10511 OpenMPOffloadMappingFlags::OMP_MAP_FROM);
10512 } else if (CI.capturesVariableByCopy()) {
10513 const VarDecl *VD = CI.getCapturedVar();
10514 CombinedInfo.Exprs.push_back(VD->getCanonicalDecl());
10515 CombinedInfo.BasePointers.push_back(CV);
10516 CombinedInfo.DevicePtrDecls.push_back(nullptr);
10517 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
10518 CombinedInfo.Pointers.push_back(CV);
10519 bool IsFirstprivate =
10520 isEffectivelyFirstprivate(VD, RI.getType().getNonReferenceType());
10521
10522 if (!RI.getType()->isAnyPointerType()) {
10523 // We have to signal to the runtime captures passed by value that are
10524 // not pointers.
10525 CombinedInfo.Types.push_back(
10526 OpenMPOffloadMappingFlags::OMP_MAP_LITERAL);
10527 CombinedInfo.Sizes.push_back(CGF.Builder.CreateIntCast(
10528 CGF.getTypeSize(RI.getType()), CGF.Int64Ty, /*isSigned=*/true));
10529 } else if (IsFirstprivate) {
10530 // Firstprivate pointers should be passed by value (as literals)
10531 // without performing a present table lookup at runtime.
10532 CombinedInfo.Types.push_back(
10533 OpenMPOffloadMappingFlags::OMP_MAP_LITERAL);
10534 // Use zero size for pointer literals (just passing the pointer value)
10535 CombinedInfo.Sizes.push_back(llvm::Constant::getNullValue(CGF.Int64Ty));
10536 } else {
10537 // Pointers are implicitly mapped with a zero size and no flags
10538 // (other than first map that is added for all implicit maps).
10539 CombinedInfo.Types.push_back(OpenMPOffloadMappingFlags::OMP_MAP_NONE);
10540 CombinedInfo.Sizes.push_back(llvm::Constant::getNullValue(CGF.Int64Ty));
10541 }
10542 auto I = FirstPrivateDecls.find(VD);
10543 if (I != FirstPrivateDecls.end())
10544 IsImplicit = I->getSecond();
10545 } else {
10546 assert(CI.capturesVariable() && "Expected captured reference.");
10547 const auto *PtrTy = cast<ReferenceType>(RI.getType().getTypePtr());
10548 QualType ElementType = PtrTy->getPointeeType();
10549 const VarDecl *VD = CI.getCapturedVar();
10550 bool IsFirstprivate = isEffectivelyFirstprivate(VD, ElementType);
10551 CombinedInfo.Exprs.push_back(VD->getCanonicalDecl());
10552 CombinedInfo.BasePointers.push_back(CV);
10553 CombinedInfo.DevicePtrDecls.push_back(nullptr);
10554 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
10555
10556 // For firstprivate pointers, pass by value instead of dereferencing
10557 if (IsFirstprivate && ElementType->isAnyPointerType()) {
10558 // Treat as a literal value (pass the pointer value itself)
10559 CombinedInfo.Pointers.push_back(CV);
10560 // Use zero size for pointer literals
10561 CombinedInfo.Sizes.push_back(llvm::Constant::getNullValue(CGF.Int64Ty));
10562 CombinedInfo.Types.push_back(
10563 OpenMPOffloadMappingFlags::OMP_MAP_LITERAL);
10564 } else {
10565 CombinedInfo.Sizes.push_back(CGF.Builder.CreateIntCast(
10566 CGF.getTypeSize(ElementType), CGF.Int64Ty, /*isSigned=*/true));
10567 // The default map type for a scalar/complex type is 'to' because by
10568 // default the value doesn't have to be retrieved. For an aggregate
10569 // type, the default is 'tofrom'.
10570 CombinedInfo.Types.push_back(getMapModifiersForPrivateClauses(CI));
10571 CombinedInfo.Pointers.push_back(CV);
10572 }
10573 auto I = FirstPrivateDecls.find(VD);
10574 if (I != FirstPrivateDecls.end())
10575 IsImplicit = I->getSecond();
10576 }
10577 // Every default map produces a single argument which is a target parameter.
10578 CombinedInfo.Types.back() |=
10579 OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM;
10580
10581 // Add flag stating this is an implicit map.
10582 if (IsImplicit)
10583 CombinedInfo.Types.back() |= OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT;
10584
10585 CombinedInfo.HasAttachPtr.push_back(false);
10586 // No user-defined mapper for default mapping.
10587 CombinedInfo.Mappers.push_back(nullptr);
10588 }
10589};
10590} // anonymous namespace
10591
10592// Try to extract the base declaration from a `this->x` expression if possible.
10594 if (!E)
10595 return nullptr;
10596
10597 if (const auto *OASE = dyn_cast<ArraySectionExpr>(E->IgnoreParenCasts()))
10598 if (const MemberExpr *ME =
10599 dyn_cast<MemberExpr>(OASE->getBase()->IgnoreParenImpCasts()))
10600 return ME->getMemberDecl();
10601 return nullptr;
10602}
10603
10604/// Emit a string constant containing the names of the values mapped to the
10605/// offloading runtime library.
10606static llvm::Constant *
10607emitMappingInformation(CodeGenFunction &CGF, llvm::OpenMPIRBuilder &OMPBuilder,
10608 MappableExprsHandler::MappingExprInfo &MapExprs) {
10609
10610 uint32_t SrcLocStrSize;
10611 if (!MapExprs.getMapDecl() && !MapExprs.getMapExpr())
10612 return OMPBuilder.getOrCreateDefaultSrcLocStr(SrcLocStrSize);
10613
10614 SourceLocation Loc;
10615 if (!MapExprs.getMapDecl() && MapExprs.getMapExpr()) {
10616 if (const ValueDecl *VD = getDeclFromThisExpr(MapExprs.getMapExpr()))
10617 Loc = VD->getLocation();
10618 else
10619 Loc = MapExprs.getMapExpr()->getExprLoc();
10620 } else {
10621 Loc = MapExprs.getMapDecl()->getLocation();
10622 }
10623
10624 std::string ExprName;
10625 if (MapExprs.getMapExpr()) {
10627 llvm::raw_string_ostream OS(ExprName);
10628 MapExprs.getMapExpr()->printPretty(OS, nullptr, P);
10629 } else {
10630 ExprName = MapExprs.getMapDecl()->getNameAsString();
10631 }
10632
10633 std::string FileName;
10635 if (auto *DbgInfo = CGF.getDebugInfo())
10636 FileName = DbgInfo->remapDIPath(PLoc.getFilename());
10637 else
10638 FileName = PLoc.getFilename();
10639 return OMPBuilder.getOrCreateSrcLocStr(FileName, ExprName, PLoc.getLine(),
10640 PLoc.getColumn(), SrcLocStrSize);
10641}
10642/// Emit the arrays used to pass the captures and map information to the
10643/// offloading runtime library. If there is no map or capture information,
10644/// return nullptr by reference.
10646 CodeGenFunction &CGF, MappableExprsHandler::MapCombinedInfoTy &CombinedInfo,
10647 CGOpenMPRuntime::TargetDataInfo &Info, llvm::OpenMPIRBuilder &OMPBuilder,
10648 bool IsNonContiguous = false, bool ForEndCall = false) {
10649 CodeGenModule &CGM = CGF.CGM;
10650
10651 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
10652 InsertPointTy AllocaIP(CGF.AllocaInsertPt->getIterator());
10653 InsertPointTy CodeGenIP(CGF.Builder.GetInsertPoint());
10654
10655 auto DeviceAddrCB = [&](unsigned int I, llvm::Value *NewDecl) {
10656 if (const ValueDecl *DevVD = CombinedInfo.DevicePtrDecls[I]) {
10657 Info.CaptureDeviceAddrMap.try_emplace(DevVD, NewDecl);
10658 }
10659 };
10660
10661 auto CustomMapperCB = [&](unsigned int I) {
10662 llvm::Function *MFunc = nullptr;
10663 if (CombinedInfo.Mappers[I]) {
10664 Info.HasMapper = true;
10666 cast<OMPDeclareMapperDecl>(CombinedInfo.Mappers[I]));
10667 }
10668 return MFunc;
10669 };
10670 cantFail(OMPBuilder.emitOffloadingArraysAndArgs(
10671 AllocaIP, CodeGenIP, Info, Info.RTArgs, CombinedInfo, CustomMapperCB,
10672 IsNonContiguous, ForEndCall, DeviceAddrCB));
10673}
10674
10675/// Check for inner distribute directive.
10676static const OMPExecutableDirective *
10678 const auto *CS = D.getInnermostCapturedStmt();
10679 const auto *Body =
10680 CS->getCapturedStmt()->IgnoreContainers(/*IgnoreCaptured=*/true);
10681 const Stmt *ChildStmt =
10683
10684 if (const auto *NestedDir =
10685 dyn_cast_or_null<OMPExecutableDirective>(ChildStmt)) {
10686 OpenMPDirectiveKind DKind = NestedDir->getDirectiveKind();
10687 switch (D.getDirectiveKind()) {
10688 case OMPD_target:
10689 // For now, treat 'target' with nested 'teams loop' as if it's
10690 // distributed (target teams distribute).
10691 if (isOpenMPDistributeDirective(DKind) || DKind == OMPD_teams_loop)
10692 return NestedDir;
10693 if (DKind == OMPD_teams) {
10694 Body = NestedDir->getInnermostCapturedStmt()->IgnoreContainers(
10695 /*IgnoreCaptured=*/true);
10696 if (!Body)
10697 return nullptr;
10698 ChildStmt = CGOpenMPSIMDRuntime::getSingleCompoundChild(Ctx, Body);
10699 if (const auto *NND =
10700 dyn_cast_or_null<OMPExecutableDirective>(ChildStmt)) {
10701 DKind = NND->getDirectiveKind();
10702 if (isOpenMPDistributeDirective(DKind))
10703 return NND;
10704 }
10705 }
10706 return nullptr;
10707 case OMPD_target_teams:
10708 if (isOpenMPDistributeDirective(DKind))
10709 return NestedDir;
10710 return nullptr;
10711 case OMPD_target_parallel:
10712 case OMPD_target_simd:
10713 case OMPD_target_parallel_for:
10714 case OMPD_target_parallel_for_simd:
10715 return nullptr;
10716 case OMPD_target_teams_distribute:
10717 case OMPD_target_teams_distribute_simd:
10718 case OMPD_target_teams_distribute_parallel_for:
10719 case OMPD_target_teams_distribute_parallel_for_simd:
10720 case OMPD_parallel:
10721 case OMPD_for:
10722 case OMPD_parallel_for:
10723 case OMPD_parallel_master:
10724 case OMPD_parallel_sections:
10725 case OMPD_for_simd:
10726 case OMPD_parallel_for_simd:
10727 case OMPD_cancel:
10728 case OMPD_cancellation_point:
10729 case OMPD_ordered_standalone:
10730 case OMPD_ordered_blockassoc:
10731 case OMPD_threadprivate:
10732 case OMPD_allocate:
10733 case OMPD_task:
10734 case OMPD_simd:
10735 case OMPD_tile:
10736 case OMPD_unroll:
10737 case OMPD_sections:
10738 case OMPD_section:
10739 case OMPD_single:
10740 case OMPD_master:
10741 case OMPD_critical:
10742 case OMPD_taskyield:
10743 case OMPD_barrier:
10744 case OMPD_taskwait:
10745 case OMPD_taskgroup:
10746 case OMPD_atomic:
10747 case OMPD_flush:
10748 case OMPD_depobj:
10749 case OMPD_scan:
10750 case OMPD_teams:
10751 case OMPD_target_data:
10752 case OMPD_target_exit_data:
10753 case OMPD_target_enter_data:
10754 case OMPD_distribute:
10755 case OMPD_distribute_simd:
10756 case OMPD_distribute_parallel_for:
10757 case OMPD_distribute_parallel_for_simd:
10758 case OMPD_teams_distribute:
10759 case OMPD_teams_distribute_simd:
10760 case OMPD_teams_distribute_parallel_for:
10761 case OMPD_teams_distribute_parallel_for_simd:
10762 case OMPD_target_update:
10763 case OMPD_declare_simd:
10764 case OMPD_declare_variant:
10765 case OMPD_begin_declare_variant:
10766 case OMPD_end_declare_variant:
10767 case OMPD_declare_target:
10768 case OMPD_end_declare_target:
10769 case OMPD_declare_reduction:
10770 case OMPD_declare_mapper:
10771 case OMPD_taskloop:
10772 case OMPD_taskloop_simd:
10773 case OMPD_master_taskloop:
10774 case OMPD_master_taskloop_simd:
10775 case OMPD_parallel_master_taskloop:
10776 case OMPD_parallel_master_taskloop_simd:
10777 case OMPD_requires:
10778 case OMPD_metadirective:
10779 case OMPD_unknown:
10780 default:
10781 llvm_unreachable("Unexpected directive.");
10782 }
10783 }
10784
10785 return nullptr;
10786}
10787
10788/// Emit the user-defined mapper function. The code generation follows the
10789/// pattern in the example below.
10790/// \code
10791/// void .omp_mapper.<type_name>.<mapper_id>.(void *rt_mapper_handle,
10792/// void *base, void *begin,
10793/// int64_t size, int64_t type,
10794/// void *name = nullptr) {
10795/// // Allocate space for an array section first.
10796/// if ((size > 1 || (base != begin)) && !maptype.IsDelete)
10797/// __tgt_push_mapper_component(rt_mapper_handle, base, begin,
10798/// size*sizeof(Ty), clearToFromMember(type));
10799/// // Map members.
10800/// for (unsigned i = 0; i < size; i++) {
10801/// N = __tgt_mapper_num_components(rt_mapper_handle);
10802/// // For each component specified by this mapper:
10803/// for (auto c : begin[i]->all_components) {
10804/// // MEMBER_OF grouping: tie this component to the current array element
10805/// // (component N) by adding N<<48. Exceptions:
10806/// // - ATTACH entries are not members of any struct storage range.
10807/// // - Pointee entries (reached via a pointer member) occupy separate
10808/// // storage; their inner MEMBER_OF bits are shifted by N instead.
10809/// if (c.isAttach() || c.isPointee())
10810/// member_type = c.arg_type + (c.hasInnerMemberOf() ? N<<48 : 0);
10811/// else
10812/// member_type = c.arg_type + N<<48;
10813/// // Map-type-modifying bits (ALWAYS, DELETE, CLOSE) from the outer map
10814/// // clause are propagated to each component, except ATTACH entries
10815/// // (ATTACH|ALWAYS is reserved for attach(always), and other modifier
10816/// // bits have no meaning for ATTACH). PRESENT is additionally
10817/// // propagated to components with HasAttachPtr (the pointee data) at
10818/// // OpenMP >= 6.0.
10819/// present_bit = (v60 && c.hasAttachPtr()) ? PRESENT : 0;
10820/// imported_modifier_bits =
10821/// type & (ALWAYS | DELETE | CLOSE | present_bit);
10822/// effective_type = c.isAttach() ? member_type
10823/// : member_type | imported_modifier_bits;
10824/// if (c.hasMapper())
10825/// (*c.Mapper())(rt_mapper_handle, c.arg_base, c.arg_begin, c.arg_size,
10826/// effective_type, c.arg_name);
10827/// else
10828/// __tgt_push_mapper_component(rt_mapper_handle, c.arg_base,
10829/// c.arg_begin, c.arg_size, effective_type,
10830/// c.arg_name);
10831/// }
10832/// }
10833/// // Delete the array section.
10834/// if (size > 1 && maptype.IsDelete)
10835/// __tgt_push_mapper_component(rt_mapper_handle, base, begin,
10836/// size*sizeof(Ty), clearToFromMember(type));
10837/// }
10838/// \endcode
10840 CodeGenFunction *CGF) {
10841 if (UDMMap.count(D) > 0)
10842 return;
10843 ASTContext &C = CGM.getContext();
10844 QualType Ty = D->getType();
10845 auto *MapperVarDecl =
10847 CharUnits ElementSize = C.getTypeSizeInChars(Ty);
10848 llvm::Type *ElemTy = CGM.getTypes().ConvertTypeForMem(Ty);
10849
10850 CodeGenFunction MapperCGF(CGM);
10851 MappableExprsHandler::MapCombinedInfoTy CombinedInfo;
10852 auto PrivatizeAndGenMapInfoCB =
10853 [&](llvm::OpenMPIRBuilder::InsertPointTy CodeGenIP, llvm::Value *PtrPHI,
10854 llvm::Value *BeginArg) -> llvm::OpenMPIRBuilder::MapInfosTy & {
10855 MapperCGF.Builder.restoreIP(CodeGenIP);
10856
10857 // Privatize the declared variable of mapper to be the current array
10858 // element.
10859 Address PtrCurrent(
10860 PtrPHI, ElemTy,
10861 Address(BeginArg, MapperCGF.VoidPtrTy, CGM.getPointerAlign())
10862 .getAlignment()
10863 .alignmentOfArrayElement(ElementSize));
10865 Scope.addPrivate(MapperVarDecl, PtrCurrent);
10866 (void)Scope.Privatize();
10867
10868 // Get map clause information.
10869 MappableExprsHandler MEHandler(*D, MapperCGF);
10870 MEHandler.generateAllInfoForMapper(CombinedInfo, OMPBuilder);
10871
10872 auto FillInfoMap = [&](MappableExprsHandler::MappingExprInfo &MapExpr) {
10873 return emitMappingInformation(MapperCGF, OMPBuilder, MapExpr);
10874 };
10875 if (CGM.getCodeGenOpts().getDebugInfo() !=
10876 llvm::codegenoptions::NoDebugInfo) {
10877 CombinedInfo.Names.resize(CombinedInfo.Exprs.size());
10878 llvm::transform(CombinedInfo.Exprs, CombinedInfo.Names.begin(),
10879 FillInfoMap);
10880 }
10881
10882 return CombinedInfo;
10883 };
10884
10885 auto CustomMapperCB = [&](unsigned I) {
10886 llvm::Function *MapperFunc = nullptr;
10887 if (CombinedInfo.Mappers[I]) {
10888 // Call the corresponding mapper function.
10890 cast<OMPDeclareMapperDecl>(CombinedInfo.Mappers[I]));
10891 assert(MapperFunc && "Expect a valid mapper function is available.");
10892 }
10893 return MapperFunc;
10894 };
10895
10896 SmallString<64> TyStr;
10897 llvm::raw_svector_ostream Out(TyStr);
10898 CGM.getCXXABI().getMangleContext().mangleCanonicalTypeName(Ty, Out);
10899 std::string Name = getName({"omp_mapper", TyStr, D->getName()});
10900
10901 // Propagate the PRESENT modifier to the pointee entries (those with
10902 // HasAttachPtr) only for OpenMP >= 6.0; before 6.0 the present modifier does
10903 // not apply to the pointee (see the OpenMP 6.0 erratum on the present motion
10904 // vs. map-type modifier divergence).
10905 bool PropagatePresentToPointee = CGM.getLangOpts().OpenMP >= 60;
10906 llvm::Function *NewFn = cantFail(OMPBuilder.emitUserDefinedMapper(
10907 PrivatizeAndGenMapInfoCB, ElemTy, Name, CustomMapperCB,
10908 /*PreserveMemberOfFlags=*/false, PropagatePresentToPointee));
10909 UDMMap.try_emplace(D, NewFn);
10910 if (CGF)
10911 FunctionUDMMap[CGF->CurFn].push_back(D);
10912}
10913
10915 const OMPDeclareMapperDecl *D) {
10916 auto I = UDMMap.find(D);
10917 if (I != UDMMap.end())
10918 return I->second;
10920 return UDMMap.lookup(D);
10921}
10922
10925 llvm::function_ref<llvm::Value *(CodeGenFunction &CGF,
10926 const OMPLoopDirective &D)>
10927 SizeEmitter) {
10928 OpenMPDirectiveKind Kind = D.getDirectiveKind();
10929 const OMPExecutableDirective *TD = &D;
10930 // Get nested teams distribute kind directive, if any. For now, treat
10931 // 'target_teams_loop' as if it's really a target_teams_distribute.
10932 if ((!isOpenMPDistributeDirective(Kind) || !isOpenMPTeamsDirective(Kind)) &&
10933 Kind != OMPD_target_teams_loop)
10934 TD = getNestedDistributeDirective(CGM.getContext(), D);
10935 if (!TD)
10936 return llvm::ConstantInt::get(CGF.Int64Ty, 0);
10937
10938 const auto *LD = cast<OMPLoopDirective>(TD);
10939 if (llvm::Value *NumIterations = SizeEmitter(CGF, *LD))
10940 return NumIterations;
10941 return llvm::ConstantInt::get(CGF.Int64Ty, 0);
10942}
10943
10944static void
10945emitTargetCallFallback(CGOpenMPRuntime *OMPRuntime, llvm::Function *OutlinedFn,
10946 const OMPExecutableDirective &D,
10948 bool RequiresOuterTask, const CapturedStmt &CS,
10949 bool OffloadingMandatory, CodeGenFunction &CGF) {
10950 if (OffloadingMandatory) {
10951 CGF.Builder.CreateUnreachable();
10952 } else {
10953 if (RequiresOuterTask) {
10954 CapturedVars.clear();
10955 CGF.GenerateOpenMPCapturedVars(CS, CapturedVars);
10956 }
10957 llvm::SmallVector<llvm::Value *, 16> Args(CapturedVars.begin(),
10958 CapturedVars.end());
10959 Args.push_back(llvm::Constant::getNullValue(CGF.Builder.getPtrTy()));
10960 OMPRuntime->emitOutlinedFunctionCall(CGF, D.getBeginLoc(), OutlinedFn,
10961 Args);
10962 }
10963}
10964
10965static llvm::Value *emitDeviceID(
10966 llvm::PointerIntPair<const Expr *, 2, OpenMPDeviceClauseModifier> Device,
10967 CodeGenFunction &CGF) {
10968 // Emit device ID if any.
10969 llvm::Value *DeviceID;
10970 if (Device.getPointer()) {
10971 assert((Device.getInt() == OMPC_DEVICE_unknown ||
10972 Device.getInt() == OMPC_DEVICE_device_num) &&
10973 "Expected device_num modifier.");
10974 llvm::Value *DevVal = CGF.EmitScalarExpr(Device.getPointer());
10975 DeviceID =
10976 CGF.Builder.CreateIntCast(DevVal, CGF.Int64Ty, /*isSigned=*/true);
10977 } else {
10978 DeviceID = CGF.Builder.getInt64(OMP_DEVICEID_UNDEF);
10979 }
10980 return DeviceID;
10981}
10982
10983static std::pair<llvm::Value *, OMPDynGroupprivateFallbackType>
10985 llvm::Value *DynGP = CGF.Builder.getInt32(0);
10986 auto DynGPFallback = OMPDynGroupprivateFallbackType::Abort;
10987
10988 if (auto *DynGPClause = D.getSingleClause<OMPDynGroupprivateClause>()) {
10989 CodeGenFunction::RunCleanupsScope DynGPScope(CGF);
10990 llvm::Value *DynGPVal =
10991 CGF.EmitScalarExpr(DynGPClause->getSize(), /*IgnoreResultAssign=*/true);
10992 DynGP = CGF.Builder.CreateIntCast(DynGPVal, CGF.Int32Ty,
10993 /*isSigned=*/false);
10994 auto FallbackModifier = DynGPClause->getDynGroupprivateFallbackModifier();
10995 switch (FallbackModifier) {
10996 case OMPC_DYN_GROUPPRIVATE_FALLBACK_abort:
10997 DynGPFallback = OMPDynGroupprivateFallbackType::Abort;
10998 break;
10999 case OMPC_DYN_GROUPPRIVATE_FALLBACK_null:
11000 DynGPFallback = OMPDynGroupprivateFallbackType::Null;
11001 break;
11002 case OMPC_DYN_GROUPPRIVATE_FALLBACK_default_mem:
11004 // This is the default for dyn_groupprivate.
11005 DynGPFallback = OMPDynGroupprivateFallbackType::DefaultMem;
11006 break;
11007 default:
11008 llvm_unreachable("Unknown fallback modifier for OpenMP dyn_groupprivate");
11009 }
11010 } else if (auto *OMPXDynCGClause =
11011 D.getSingleClause<OMPXDynCGroupMemClause>()) {
11012 CodeGenFunction::RunCleanupsScope DynCGMemScope(CGF);
11013 llvm::Value *DynCGMemVal = CGF.EmitScalarExpr(OMPXDynCGClause->getSize(),
11014 /*IgnoreResultAssign=*/true);
11015 DynGP = CGF.Builder.CreateIntCast(DynCGMemVal, CGF.Int32Ty,
11016 /*isSigned=*/false);
11017 }
11018 return {DynGP, DynGPFallback};
11019}
11020
11022 MappableExprsHandler &MEHandler, CodeGenFunction &CGF,
11023 const CapturedStmt &CS, llvm::SmallVectorImpl<llvm::Value *> &CapturedVars,
11024 llvm::OpenMPIRBuilder &OMPBuilder,
11025 llvm::DenseSet<CanonicalDeclPtr<const Decl>> &MappedVarSet,
11026 MappableExprsHandler::MapCombinedInfoTy &CombinedInfo) {
11027
11028 llvm::DenseMap<llvm::Value *, llvm::Value *> LambdaPointers;
11029 auto RI = CS.getCapturedRecordDecl()->field_begin();
11030 auto *CV = CapturedVars.begin();
11032 CE = CS.capture_end();
11033 CI != CE; ++CI, ++RI, ++CV) {
11034 MappableExprsHandler::MapCombinedInfoTy CurInfo;
11035
11036 // VLA sizes are passed to the outlined region by copy and do not have map
11037 // information associated.
11038 if (CI->capturesVariableArrayType()) {
11039 CurInfo.Exprs.push_back(nullptr);
11040 CurInfo.BasePointers.push_back(*CV);
11041 CurInfo.DevicePtrDecls.push_back(nullptr);
11042 CurInfo.DevicePointers.push_back(
11043 MappableExprsHandler::DeviceInfoTy::None);
11044 CurInfo.Pointers.push_back(*CV);
11045 CurInfo.Sizes.push_back(CGF.Builder.CreateIntCast(
11046 CGF.getTypeSize(RI->getType()), CGF.Int64Ty, /*isSigned=*/true));
11047 // Copy to the device as an argument. No need to retrieve it.
11048 CurInfo.Types.push_back(OpenMPOffloadMappingFlags::OMP_MAP_LITERAL |
11049 OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM |
11050 OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT);
11051 CurInfo.HasAttachPtr.push_back(false);
11052 CurInfo.Mappers.push_back(nullptr);
11053 } else {
11054 const ValueDecl *CapturedVD =
11055 CI->capturesThis() ? nullptr
11057 bool HasEntryWithCVAsAttachPtr = false;
11058 if (CapturedVD)
11059 HasEntryWithCVAsAttachPtr =
11060 MEHandler.hasAttachEntryForCapturedVar(CapturedVD);
11061
11062 // Populate component lists for the captured variable from clauses.
11063 MappableExprsHandler::MapDataArrayTy DeclComponentLists;
11066 StorageForImplicitlyAddedComponentLists;
11067 MEHandler.populateComponentListsForNonLambdaCaptureFromClauses(
11068 CapturedVD, DeclComponentLists,
11069 StorageForImplicitlyAddedComponentLists);
11070
11071 // OpenMP 6.0, 15.8, target construct, restrictions:
11072 // * A list item in a map clause that is specified on a target construct
11073 // must have a base variable or base pointer.
11074 //
11075 // Map clauses on a target construct must either have a base pointer, or a
11076 // base-variable. So, if we don't have a base-pointer, that means that it
11077 // must have a base-variable, i.e. we have a map like `map(s)`, `map(s.x)`
11078 // etc. In such cases, we do not need to handle default map generation
11079 // for `s`.
11080 bool HasEntryWithoutAttachPtr =
11081 llvm::any_of(DeclComponentLists, [&](const auto &MapData) {
11083 Components = std::get<0>(MapData);
11084 return !MEHandler.getAttachPtrExpr(Components);
11085 });
11086
11087 // Generate default map info first if there's no direct map with CV as
11088 // the base-variable, or attach pointer.
11089 if (DeclComponentLists.empty() ||
11090 (!HasEntryWithCVAsAttachPtr && !HasEntryWithoutAttachPtr))
11091 MEHandler.generateDefaultMapInfo(*CI, **RI, *CV, CurInfo);
11092
11093 // If we have any information in the map clause, we use it, otherwise we
11094 // just do a default mapping.
11095 MEHandler.generateInfoForCaptureFromClauseInfo(
11096 DeclComponentLists, CI, *CV, CurInfo, OMPBuilder,
11097 /*OffsetForMemberOfFlag=*/CombinedInfo.BasePointers.size());
11098
11099 if (!CI->capturesThis())
11100 MappedVarSet.insert(CI->getCapturedVar());
11101 else
11102 MappedVarSet.insert(nullptr);
11103
11104 // Generate correct mapping for variables captured by reference in
11105 // lambdas.
11106 if (CI->capturesVariable())
11107 MEHandler.generateInfoForLambdaCaptures(CI->getCapturedVar(), *CV,
11108 CurInfo, LambdaPointers);
11109 }
11110 // We expect to have at least an element of information for this capture.
11111 assert(!CurInfo.BasePointers.empty() &&
11112 "Non-existing map pointer for capture!");
11113 assert(CurInfo.BasePointers.size() == CurInfo.Pointers.size() &&
11114 CurInfo.BasePointers.size() == CurInfo.Sizes.size() &&
11115 CurInfo.BasePointers.size() == CurInfo.Types.size() &&
11116 CurInfo.BasePointers.size() == CurInfo.Mappers.size() &&
11117 "Inconsistent map information sizes!");
11118
11119 // We need to append the results of this capture to what we already have.
11120 CombinedInfo.append(CurInfo);
11121 }
11122 // Adjust MEMBER_OF flags for the lambdas captures.
11123 MEHandler.adjustMemberOfForLambdaCaptures(
11124 OMPBuilder, LambdaPointers, CombinedInfo.BasePointers,
11125 CombinedInfo.Pointers, CombinedInfo.Types);
11126}
11127static void
11128genMapInfo(MappableExprsHandler &MEHandler, CodeGenFunction &CGF,
11129 MappableExprsHandler::MapCombinedInfoTy &CombinedInfo,
11130 llvm::OpenMPIRBuilder &OMPBuilder,
11131 const llvm::DenseSet<CanonicalDeclPtr<const Decl>> &SkippedVarSet =
11132 llvm::DenseSet<CanonicalDeclPtr<const Decl>>()) {
11133
11134 CodeGenModule &CGM = CGF.CGM;
11135 // Map any list items in a map clause that were not captures because they
11136 // weren't referenced within the construct.
11137 MEHandler.generateAllInfo(CombinedInfo, OMPBuilder, SkippedVarSet);
11138
11139 auto FillInfoMap = [&](MappableExprsHandler::MappingExprInfo &MapExpr) {
11140 return emitMappingInformation(CGF, OMPBuilder, MapExpr);
11141 };
11142 if (CGM.getCodeGenOpts().getDebugInfo() !=
11143 llvm::codegenoptions::NoDebugInfo) {
11144 CombinedInfo.Names.resize(CombinedInfo.Exprs.size());
11145 llvm::transform(CombinedInfo.Exprs, CombinedInfo.Names.begin(),
11146 FillInfoMap);
11147 }
11148}
11149
11151 const CapturedStmt &CS,
11153 llvm::OpenMPIRBuilder &OMPBuilder,
11154 MappableExprsHandler::MapCombinedInfoTy &CombinedInfo) {
11155 // Get mappable expression information.
11156 MappableExprsHandler MEHandler(D, CGF);
11157 llvm::DenseSet<CanonicalDeclPtr<const Decl>> MappedVarSet;
11158
11159 genMapInfoForCaptures(MEHandler, CGF, CS, CapturedVars, OMPBuilder,
11160 MappedVarSet, CombinedInfo);
11161 genMapInfo(MEHandler, CGF, CombinedInfo, OMPBuilder, MappedVarSet);
11162}
11163
11164template <typename ClauseTy>
11165static void
11167 const OMPExecutableDirective &D,
11169 const auto *C = D.getSingleClause<ClauseTy>();
11170 assert(!C->varlist_empty() &&
11171 "ompx_bare requires explicit num_teams and thread_limit");
11173 for (auto *E : C->varlist()) {
11174 llvm::Value *V = CGF.EmitScalarExpr(E);
11175 Values.push_back(
11176 CGF.Builder.CreateIntCast(V, CGF.Int32Ty, /*isSigned=*/true));
11177 }
11178}
11179
11181 CGOpenMPRuntime *OMPRuntime, llvm::Function *OutlinedFn,
11182 const OMPExecutableDirective &D,
11183 llvm::SmallVectorImpl<llvm::Value *> &CapturedVars, bool RequiresOuterTask,
11184 const CapturedStmt &CS, bool OffloadingMandatory,
11185 llvm::PointerIntPair<const Expr *, 2, OpenMPDeviceClauseModifier> Device,
11186 llvm::Value *OutlinedFnID, CodeGenFunction::OMPTargetDataInfo &InputInfo,
11187 llvm::Value *&MapTypesArray, llvm::Value *&MapNamesArray,
11188 llvm::function_ref<llvm::Value *(CodeGenFunction &CGF,
11189 const OMPLoopDirective &D)>
11190 SizeEmitter,
11191 CodeGenFunction &CGF, CodeGenModule &CGM) {
11192 llvm::OpenMPIRBuilder &OMPBuilder = OMPRuntime->getOMPBuilder();
11193
11194 // Fill up the arrays with all the captured variables.
11195 MappableExprsHandler::MapCombinedInfoTy CombinedInfo;
11197 genMapInfo(D, CGF, CS, CapturedVars, OMPBuilder, CombinedInfo);
11198
11199 // Append a null entry for the implicit dyn_ptr argument.
11200 using OpenMPOffloadMappingFlags = llvm::omp::OpenMPOffloadMappingFlags;
11201 auto *NullPtr = llvm::Constant::getNullValue(CGF.Builder.getPtrTy());
11202 CombinedInfo.BasePointers.push_back(NullPtr);
11203 CombinedInfo.Pointers.push_back(NullPtr);
11204 CombinedInfo.DevicePointers.push_back(
11205 llvm::OpenMPIRBuilder::DeviceInfoTy::None);
11206 CombinedInfo.Sizes.push_back(CGF.Builder.getInt64(0));
11207 CombinedInfo.Types.push_back(OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM |
11208 OpenMPOffloadMappingFlags::OMP_MAP_LITERAL);
11209 CombinedInfo.HasAttachPtr.push_back(false);
11210 if (!CombinedInfo.Names.empty())
11211 CombinedInfo.Names.push_back(NullPtr);
11212 CombinedInfo.Exprs.push_back(nullptr);
11213 CombinedInfo.Mappers.push_back(nullptr);
11214 CombinedInfo.DevicePtrDecls.push_back(nullptr);
11215
11216 emitOffloadingArraysAndArgs(CGF, CombinedInfo, Info, OMPBuilder,
11217 /*IsNonContiguous=*/true, /*ForEndCall=*/false);
11218
11219 InputInfo.NumberOfTargetItems = Info.NumberOfPtrs;
11220 InputInfo.BasePointersArray = Address(Info.RTArgs.BasePointersArray,
11221 CGF.VoidPtrTy, CGM.getPointerAlign());
11222 InputInfo.PointersArray =
11223 Address(Info.RTArgs.PointersArray, CGF.VoidPtrTy, CGM.getPointerAlign());
11224 InputInfo.SizesArray =
11225 Address(Info.RTArgs.SizesArray, CGF.Int64Ty, CGM.getPointerAlign());
11226 InputInfo.MappersArray =
11227 Address(Info.RTArgs.MappersArray, CGF.VoidPtrTy, CGM.getPointerAlign());
11228 MapTypesArray = Info.RTArgs.MapTypesArray;
11229 MapNamesArray = Info.RTArgs.MapNamesArray;
11230
11231 auto &&ThenGen = [&OMPRuntime, OutlinedFn, &D, &CapturedVars,
11232 RequiresOuterTask, &CS, OffloadingMandatory, Device,
11233 OutlinedFnID, &InputInfo, &MapTypesArray, &MapNamesArray,
11234 SizeEmitter](CodeGenFunction &CGF, PrePostActionTy &) {
11235 bool IsReverseOffloading = Device.getInt() == OMPC_DEVICE_ancestor;
11236
11237 if (IsReverseOffloading) {
11238 // Reverse offloading is not supported, so just execute on the host.
11239 // FIXME: This fallback solution is incorrect since it ignores the
11240 // OMP_TARGET_OFFLOAD environment variable. Instead it would be better to
11241 // assert here and ensure SEMA emits an error.
11242 emitTargetCallFallback(OMPRuntime, OutlinedFn, D, CapturedVars,
11243 RequiresOuterTask, CS, OffloadingMandatory, CGF);
11244 return;
11245 }
11246
11247 bool HasNoWait = D.hasClausesOfKind<OMPNowaitClause>();
11248 unsigned NumTargetItems = InputInfo.NumberOfTargetItems;
11249
11250 llvm::Value *BasePointersArray =
11251 InputInfo.BasePointersArray.emitRawPointer(CGF);
11252 llvm::Value *PointersArray = InputInfo.PointersArray.emitRawPointer(CGF);
11253 llvm::Value *SizesArray = InputInfo.SizesArray.emitRawPointer(CGF);
11254 llvm::Value *MappersArray = InputInfo.MappersArray.emitRawPointer(CGF);
11255
11256 auto &&EmitTargetCallFallbackCB =
11257 [&OMPRuntime, OutlinedFn, &D, &CapturedVars, RequiresOuterTask, &CS,
11258 OffloadingMandatory, &CGF](llvm::OpenMPIRBuilder::InsertPointTy IP)
11259 -> llvm::OpenMPIRBuilder::InsertPointTy {
11260 CGF.Builder.restoreIP(IP);
11261 emitTargetCallFallback(OMPRuntime, OutlinedFn, D, CapturedVars,
11262 RequiresOuterTask, CS, OffloadingMandatory, CGF);
11263 return CGF.Builder.saveIP();
11264 };
11265
11266 bool IsBare = D.hasClausesOfKind<OMPXBareClause>();
11269 if (IsBare) {
11272 NumThreads);
11273 } else {
11274 NumTeams.push_back(OMPRuntime->emitNumTeamsForTargetDirective(CGF, D));
11275 NumThreads.push_back(
11276 OMPRuntime->emitNumThreadsForTargetDirective(CGF, D));
11277 }
11278
11279 llvm::Value *DeviceID = emitDeviceID(Device, CGF);
11280 llvm::Value *RTLoc = OMPRuntime->emitUpdateLocation(CGF, D.getBeginLoc());
11281 llvm::Value *NumIterations =
11282 OMPRuntime->emitTargetNumIterationsCall(CGF, D, SizeEmitter);
11283 auto [DynCGroupMem, DynCGroupMemFallback] = emitDynCGroupMem(D, CGF);
11284 llvm::OpenMPIRBuilder::InsertPointTy AllocaIP(
11285 CGF.AllocaInsertPt->getIterator());
11286
11287 llvm::OpenMPIRBuilder::TargetDataRTArgs RTArgs(
11288 BasePointersArray, PointersArray, SizesArray, MapTypesArray,
11289 nullptr /* MapTypesArrayEnd */, MappersArray, MapNamesArray);
11290
11291 llvm::OpenMPIRBuilder::TargetKernelArgs Args(
11292 NumTargetItems, RTArgs, NumIterations, NumTeams, NumThreads,
11293 DynCGroupMem, HasNoWait, /*StrictBlocks=*/IsBare,
11294 /*StrictThreads=*/IsBare, DynCGroupMemFallback);
11295
11296 llvm::OpenMPIRBuilder::InsertPointTy AfterIP =
11297 cantFail(OMPRuntime->getOMPBuilder().emitKernelLaunch(
11298 CGF.Builder, OutlinedFnID, EmitTargetCallFallbackCB, Args, DeviceID,
11299 RTLoc, AllocaIP));
11300 CGF.Builder.restoreIP(AfterIP);
11301 };
11302
11303 if (RequiresOuterTask)
11304 CGF.EmitOMPTargetTaskBasedDirective(D, ThenGen, InputInfo);
11305 else
11306 OMPRuntime->emitInlinedDirective(CGF, D.getDirectiveKind(), ThenGen);
11307}
11308
11309static void
11310emitTargetCallElse(CGOpenMPRuntime *OMPRuntime, llvm::Function *OutlinedFn,
11311 const OMPExecutableDirective &D,
11313 bool RequiresOuterTask, const CapturedStmt &CS,
11314 bool OffloadingMandatory, CodeGenFunction &CGF) {
11315
11316 // Notify that the host version must be executed.
11317 auto &&ElseGen =
11318 [&OMPRuntime, OutlinedFn, &D, &CapturedVars, RequiresOuterTask, &CS,
11319 OffloadingMandatory](CodeGenFunction &CGF, PrePostActionTy &) {
11320 emitTargetCallFallback(OMPRuntime, OutlinedFn, D, CapturedVars,
11321 RequiresOuterTask, CS, OffloadingMandatory, CGF);
11322 };
11323
11324 if (RequiresOuterTask) {
11326 CGF.EmitOMPTargetTaskBasedDirective(D, ElseGen, InputInfo);
11327 } else {
11328 OMPRuntime->emitInlinedDirective(CGF, D.getDirectiveKind(), ElseGen);
11329 }
11330}
11331
11334 llvm::Function *OutlinedFn, llvm::Value *OutlinedFnID, const Expr *IfCond,
11335 llvm::PointerIntPair<const Expr *, 2, OpenMPDeviceClauseModifier> Device,
11336 llvm::function_ref<llvm::Value *(CodeGenFunction &CGF,
11337 const OMPLoopDirective &D)>
11338 SizeEmitter) {
11339 if (!CGF.HaveInsertPoint())
11340 return;
11341
11342 const bool OffloadingMandatory = !CGM.getLangOpts().OpenMPIsTargetDevice &&
11343 CGM.getLangOpts().OpenMPOffloadMandatory;
11344
11345 assert((OffloadingMandatory || OutlinedFn) && "Invalid outlined function!");
11346
11347 const bool RequiresOuterTask =
11348 D.hasClausesOfKind<OMPDependClause>() ||
11349 D.hasClausesOfKind<OMPNowaitClause>() ||
11350 D.hasClausesOfKind<OMPInReductionClause>() ||
11351 (CGM.getLangOpts().OpenMP >= 51 &&
11352 needsTaskBasedThreadLimit(D.getDirectiveKind()) &&
11353 D.hasClausesOfKind<OMPThreadLimitClause>());
11355 const CapturedStmt &CS = *D.getCapturedStmt(OMPD_target);
11356 auto &&ArgsCodegen = [&CS, &CapturedVars](CodeGenFunction &CGF,
11357 PrePostActionTy &) {
11358 CGF.GenerateOpenMPCapturedVars(CS, CapturedVars);
11359 };
11360 emitInlinedDirective(CGF, OMPD_unknown, ArgsCodegen);
11361
11363 llvm::Value *MapTypesArray = nullptr;
11364 llvm::Value *MapNamesArray = nullptr;
11365
11366 auto &&TargetThenGen = [this, OutlinedFn, &D, &CapturedVars,
11367 RequiresOuterTask, &CS, OffloadingMandatory, Device,
11368 OutlinedFnID, &InputInfo, &MapTypesArray,
11369 &MapNamesArray, SizeEmitter](CodeGenFunction &CGF,
11370 PrePostActionTy &) {
11371 emitTargetCallKernelLaunch(this, OutlinedFn, D, CapturedVars,
11372 RequiresOuterTask, CS, OffloadingMandatory,
11373 Device, OutlinedFnID, InputInfo, MapTypesArray,
11374 MapNamesArray, SizeEmitter, CGF, CGM);
11375 };
11376
11377 auto &&TargetElseGen =
11378 [this, OutlinedFn, &D, &CapturedVars, RequiresOuterTask, &CS,
11379 OffloadingMandatory](CodeGenFunction &CGF, PrePostActionTy &) {
11380 emitTargetCallElse(this, OutlinedFn, D, CapturedVars, RequiresOuterTask,
11381 CS, OffloadingMandatory, CGF);
11382 };
11383
11384 // If we have a target function ID it means that we need to support
11385 // offloading, otherwise, just execute on the host. We need to execute on host
11386 // regardless of the conditional in the if clause if, e.g., the user do not
11387 // specify target triples.
11388 if (OutlinedFnID) {
11389 if (IfCond) {
11390 emitIfClause(CGF, IfCond, TargetThenGen, TargetElseGen);
11391 } else {
11392 RegionCodeGenTy ThenRCG(TargetThenGen);
11393 ThenRCG(CGF);
11394 }
11395 } else {
11396 RegionCodeGenTy ElseRCG(TargetElseGen);
11397 ElseRCG(CGF);
11398 }
11399}
11400
11402 StringRef ParentName) {
11403 if (!S)
11404 return;
11405
11406 // Register vtable from device for target data and target directives.
11407 // Add this block here since scanForTargetRegionsFunctions ignores
11408 // target data by checking if S is a executable directive (target).
11409 if (auto *E = dyn_cast<OMPExecutableDirective>(S);
11410 E && isOpenMPTargetDataManagementDirective(E->getDirectiveKind())) {
11411 // Don't need to check if it's device compile
11412 // since scanForTargetRegionsFunctions currently only called
11413 // in device compilation.
11414 registerVTable(*E);
11415 }
11416
11417 // Codegen OMP target directives that offload compute to the device.
11418 bool RequiresDeviceCodegen =
11421 cast<OMPExecutableDirective>(S)->getDirectiveKind());
11422
11423 if (RequiresDeviceCodegen) {
11424 const auto &E = *cast<OMPExecutableDirective>(S);
11425
11426 llvm::TargetRegionEntryInfo EntryInfo = getEntryInfoFromPresumedLoc(
11427 CGM, OMPBuilder, E.getBeginLoc(), ParentName);
11428
11429 // Is this a target region that should not be emitted as an entry point? If
11430 // so just signal we are done with this target region.
11431 if (!OMPBuilder.OffloadInfoManager.hasTargetRegionEntryInfo(EntryInfo))
11432 return;
11433
11434 switch (E.getDirectiveKind()) {
11435 case OMPD_target:
11438 break;
11439 case OMPD_target_parallel:
11441 CGM, ParentName, cast<OMPTargetParallelDirective>(E));
11442 break;
11443 case OMPD_target_teams:
11445 CGM, ParentName, cast<OMPTargetTeamsDirective>(E));
11446 break;
11447 case OMPD_target_teams_distribute:
11450 break;
11451 case OMPD_target_teams_distribute_simd:
11454 break;
11455 case OMPD_target_parallel_for:
11458 break;
11459 case OMPD_target_parallel_for_simd:
11462 break;
11463 case OMPD_target_simd:
11465 CGM, ParentName, cast<OMPTargetSimdDirective>(E));
11466 break;
11467 case OMPD_target_teams_distribute_parallel_for:
11469 CGM, ParentName,
11471 break;
11472 case OMPD_target_teams_distribute_parallel_for_simd:
11475 CGM, ParentName,
11477 break;
11478 case OMPD_target_teams_loop:
11481 break;
11482 case OMPD_target_parallel_loop:
11485 break;
11486 case OMPD_parallel:
11487 case OMPD_for:
11488 case OMPD_parallel_for:
11489 case OMPD_parallel_master:
11490 case OMPD_parallel_sections:
11491 case OMPD_for_simd:
11492 case OMPD_parallel_for_simd:
11493 case OMPD_cancel:
11494 case OMPD_cancellation_point:
11495 case OMPD_ordered_standalone:
11496 case OMPD_ordered_blockassoc:
11497 case OMPD_threadprivate:
11498 case OMPD_allocate:
11499 case OMPD_task:
11500 case OMPD_simd:
11501 case OMPD_tile:
11502 case OMPD_unroll:
11503 case OMPD_sections:
11504 case OMPD_section:
11505 case OMPD_single:
11506 case OMPD_master:
11507 case OMPD_critical:
11508 case OMPD_taskyield:
11509 case OMPD_barrier:
11510 case OMPD_taskwait:
11511 case OMPD_taskgroup:
11512 case OMPD_atomic:
11513 case OMPD_flush:
11514 case OMPD_depobj:
11515 case OMPD_scan:
11516 case OMPD_teams:
11517 case OMPD_target_data:
11518 case OMPD_target_exit_data:
11519 case OMPD_target_enter_data:
11520 case OMPD_distribute:
11521 case OMPD_distribute_simd:
11522 case OMPD_distribute_parallel_for:
11523 case OMPD_distribute_parallel_for_simd:
11524 case OMPD_teams_distribute:
11525 case OMPD_teams_distribute_simd:
11526 case OMPD_teams_distribute_parallel_for:
11527 case OMPD_teams_distribute_parallel_for_simd:
11528 case OMPD_target_update:
11529 case OMPD_declare_simd:
11530 case OMPD_declare_variant:
11531 case OMPD_begin_declare_variant:
11532 case OMPD_end_declare_variant:
11533 case OMPD_declare_target:
11534 case OMPD_end_declare_target:
11535 case OMPD_declare_reduction:
11536 case OMPD_declare_mapper:
11537 case OMPD_taskloop:
11538 case OMPD_taskloop_simd:
11539 case OMPD_master_taskloop:
11540 case OMPD_master_taskloop_simd:
11541 case OMPD_parallel_master_taskloop:
11542 case OMPD_parallel_master_taskloop_simd:
11543 case OMPD_requires:
11544 case OMPD_metadirective:
11545 case OMPD_unknown:
11546 default:
11547 llvm_unreachable("Unknown target directive for OpenMP device codegen.");
11548 }
11549 return;
11550 }
11551
11552 if (const auto *E = dyn_cast<OMPExecutableDirective>(S)) {
11553 if (!E->hasAssociatedStmt() || !E->getAssociatedStmt())
11554 return;
11555
11556 scanForTargetRegionsFunctions(E->getRawStmt(), ParentName);
11557 return;
11558 }
11559
11560 // If this is a lambda function, look into its body.
11561 if (const auto *L = dyn_cast<LambdaExpr>(S))
11562 S = L->getBody();
11563
11564 // Keep looking for target regions recursively.
11565 for (const Stmt *II : S->children())
11566 scanForTargetRegionsFunctions(II, ParentName);
11567}
11568
11569static bool isAssumedToBeNotEmitted(const ValueDecl *VD, bool IsDevice) {
11570 std::optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
11571 OMPDeclareTargetDeclAttr::getDeviceType(VD);
11572 if (!DevTy)
11573 return false;
11574 // Do not emit device_type(nohost) functions for the host.
11575 if (!IsDevice && DevTy == OMPDeclareTargetDeclAttr::DT_NoHost)
11576 return true;
11577 // Do not emit device_type(host) functions for the device.
11578 if (IsDevice && DevTy == OMPDeclareTargetDeclAttr::DT_Host)
11579 return true;
11580 return false;
11581}
11582
11584 // If emitting code for the host, we do not process FD here. Instead we do
11585 // the normal code generation.
11586 if (!CGM.getLangOpts().OpenMPIsTargetDevice) {
11587 if (const auto *FD = dyn_cast<FunctionDecl>(GD.getDecl()))
11589 CGM.getLangOpts().OpenMPIsTargetDevice))
11590 return true;
11591 return false;
11592 }
11593
11594 const ValueDecl *VD = cast<ValueDecl>(GD.getDecl());
11595 // Try to detect target regions in the function.
11596 if (const auto *FD = dyn_cast<FunctionDecl>(VD)) {
11597 StringRef Name = CGM.getMangledName(GD);
11600 CGM.getLangOpts().OpenMPIsTargetDevice))
11601 return true;
11602 }
11603
11604 // Do not emit function if it is not marked as declare target.
11605 return !OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD) &&
11606 AlreadyEmittedTargetDecls.count(VD) == 0;
11607}
11608
11611 CGM.getLangOpts().OpenMPIsTargetDevice))
11612 return true;
11613
11614 if (!CGM.getLangOpts().OpenMPIsTargetDevice)
11615 return false;
11616
11617 // Check if there are Ctors/Dtors in this declaration and look for target
11618 // regions in it. We use the complete variant to produce the kernel name
11619 // mangling.
11620 QualType RDTy = cast<VarDecl>(GD.getDecl())->getType();
11621 if (const auto *RD = RDTy->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) {
11622 for (const CXXConstructorDecl *Ctor : RD->ctors()) {
11623 StringRef ParentName =
11624 CGM.getMangledName(GlobalDecl(Ctor, Ctor_Complete));
11625 scanForTargetRegionsFunctions(Ctor->getBody(), ParentName);
11626 }
11627 if (const CXXDestructorDecl *Dtor = RD->getDestructor()) {
11628 StringRef ParentName =
11629 CGM.getMangledName(GlobalDecl(Dtor, Dtor_Complete));
11630 scanForTargetRegionsFunctions(Dtor->getBody(), ParentName);
11631 }
11632 }
11633
11634 // Do not emit variable if it is not marked as declare target.
11635 std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
11636 OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(
11637 cast<VarDecl>(GD.getDecl()));
11638 if (!Res || *Res == OMPDeclareTargetDeclAttr::MT_Link ||
11639 ((*Res == OMPDeclareTargetDeclAttr::MT_To ||
11640 *Res == OMPDeclareTargetDeclAttr::MT_Enter) &&
11643 return true;
11644 }
11645 return false;
11646}
11647
11649 llvm::Constant *Addr) {
11650 if (CGM.getLangOpts().OMPTargetTriples.empty() &&
11651 !CGM.getLangOpts().OpenMPIsTargetDevice)
11652 return;
11653
11654 std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
11655 OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
11656
11657 // If this is an 'extern' declaration we defer to the canonical definition and
11658 // do not emit an offloading entry.
11659 if (Res && *Res != OMPDeclareTargetDeclAttr::MT_Link &&
11660 VD->hasExternalStorage())
11661 return;
11662
11663 // MT_Local variables use direct access with no host-device mapping.
11664 // No offload entry needed — the device global keeps its own initializer.
11665 if (Res && *Res == OMPDeclareTargetDeclAttr::MT_Local)
11666 return;
11667
11668 if (!Res) {
11669 if (CGM.getLangOpts().OpenMPIsTargetDevice) {
11670 // Register non-target variables being emitted in device code (debug info
11671 // may cause this).
11672 StringRef VarName = CGM.getMangledName(VD);
11673 EmittedNonTargetVariables.try_emplace(VarName, Addr);
11674 }
11675 return;
11676 }
11677
11678 auto AddrOfGlobal = [&VD, this]() { return CGM.GetAddrOfGlobal(VD); };
11679 auto LinkageForVariable = [&VD, this]() {
11680 return CGM.getLLVMLinkageVarDefinition(VD);
11681 };
11682
11683 std::vector<llvm::GlobalVariable *> GeneratedRefs;
11684 OMPBuilder.registerTargetGlobalVariable(
11686 VD->hasDefinition(CGM.getContext()) == VarDecl::DeclarationOnly,
11687 VD->isExternallyVisible(),
11689 VD->getCanonicalDecl()->getBeginLoc()),
11690 CGM.getMangledName(VD), GeneratedRefs, CGM.getLangOpts().OpenMPSimd,
11691 CGM.getLangOpts().OMPTargetTriples, AddrOfGlobal, LinkageForVariable,
11692 CGM.getTypes().ConvertTypeForMem(
11693 CGM.getContext().getPointerType(VD->getType())),
11694 Addr);
11695
11696 for (auto *ref : GeneratedRefs)
11697 CGM.addCompilerUsedGlobal(ref);
11698}
11699
11701 if (isa<FunctionDecl>(GD.getDecl()) ||
11703 return emitTargetFunctions(GD);
11704
11705 return emitTargetGlobalVariable(GD);
11706}
11707
11709 for (const VarDecl *VD : DeferredGlobalVariables) {
11710 std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
11711 OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
11712 if (!Res)
11713 continue;
11714 // MT_Local and MT_To/MT_Enter without USM are always emitted.
11715 if (*Res == OMPDeclareTargetDeclAttr::MT_Local ||
11716 ((*Res == OMPDeclareTargetDeclAttr::MT_To ||
11717 *Res == OMPDeclareTargetDeclAttr::MT_Enter) &&
11719 CGM.EmitGlobal(VD);
11720 } else {
11721 assert((*Res == OMPDeclareTargetDeclAttr::MT_Link ||
11722 ((*Res == OMPDeclareTargetDeclAttr::MT_To ||
11723 *Res == OMPDeclareTargetDeclAttr::MT_Enter ||
11724 *Res == OMPDeclareTargetDeclAttr::MT_Local) &&
11726 "Expected link clause or to clause with unified memory.");
11727 (void)CGM.getOpenMPRuntime().getAddrOfDeclareTargetVar(VD);
11728 }
11729 }
11730}
11731
11733 CodeGenFunction &CGF, const OMPExecutableDirective &D) const {
11734 assert(isOpenMPTargetExecutionDirective(D.getDirectiveKind()) &&
11735 " Expected target-based directive.");
11736}
11737
11739 for (const OMPClause *Clause : D->clauselists()) {
11740 if (Clause->getClauseKind() == OMPC_unified_shared_memory) {
11742 OMPBuilder.Config.setHasRequiresUnifiedSharedMemory(true);
11743 } else if (const auto *AC =
11744 dyn_cast<OMPAtomicDefaultMemOrderClause>(Clause)) {
11745 switch (AC->getAtomicDefaultMemOrderKind()) {
11746 case OMPC_ATOMIC_DEFAULT_MEM_ORDER_acq_rel:
11747 RequiresAtomicOrdering = llvm::AtomicOrdering::AcquireRelease;
11748 break;
11749 case OMPC_ATOMIC_DEFAULT_MEM_ORDER_seq_cst:
11750 RequiresAtomicOrdering = llvm::AtomicOrdering::SequentiallyConsistent;
11751 break;
11752 case OMPC_ATOMIC_DEFAULT_MEM_ORDER_relaxed:
11753 RequiresAtomicOrdering = llvm::AtomicOrdering::Monotonic;
11754 break;
11756 break;
11757 }
11758 }
11759 }
11760}
11761
11762llvm::AtomicOrdering CGOpenMPRuntime::getDefaultMemoryOrdering() const {
11764}
11765
11767 LangAS &AS) {
11768 if (!VD || !VD->hasAttr<OMPAllocateDeclAttr>())
11769 return false;
11770 const auto *A = VD->getAttr<OMPAllocateDeclAttr>();
11771 switch(A->getAllocatorType()) {
11772 case OMPAllocateDeclAttr::OMPNullMemAlloc:
11773 case OMPAllocateDeclAttr::OMPDefaultMemAlloc:
11774 // Not supported, fallback to the default mem space.
11775 case OMPAllocateDeclAttr::OMPLargeCapMemAlloc:
11776 case OMPAllocateDeclAttr::OMPCGroupMemAlloc:
11777 case OMPAllocateDeclAttr::OMPHighBWMemAlloc:
11778 case OMPAllocateDeclAttr::OMPLowLatMemAlloc:
11779 case OMPAllocateDeclAttr::OMPThreadMemAlloc:
11780 case OMPAllocateDeclAttr::OMPConstMemAlloc:
11781 case OMPAllocateDeclAttr::OMPPTeamMemAlloc:
11782 AS = LangAS::Default;
11783 return true;
11784 case OMPAllocateDeclAttr::OMPUserDefinedMemAlloc:
11785 llvm_unreachable("Expected predefined allocator for the variables with the "
11786 "static storage.");
11787 }
11788 return false;
11789}
11790
11794
11796 CodeGenModule &CGM)
11797 : CGM(CGM) {
11798 if (CGM.getLangOpts().OpenMPIsTargetDevice) {
11799 SavedShouldMarkAsGlobal = CGM.getOpenMPRuntime().ShouldMarkAsGlobal;
11800 CGM.getOpenMPRuntime().ShouldMarkAsGlobal = false;
11801 }
11802}
11803
11805 if (CGM.getLangOpts().OpenMPIsTargetDevice)
11806 CGM.getOpenMPRuntime().ShouldMarkAsGlobal = SavedShouldMarkAsGlobal;
11807}
11808
11810 if (!CGM.getLangOpts().OpenMPIsTargetDevice || !ShouldMarkAsGlobal)
11811 return true;
11812
11813 const auto *D = cast<FunctionDecl>(GD.getDecl());
11814 // Do not emit function if it is marked as declare target as it was already
11815 // emitted.
11816 if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(D)) {
11817 if (D->hasBody() && AlreadyEmittedTargetDecls.count(D) == 0) {
11818 if (auto *F = dyn_cast_or_null<llvm::Function>(
11819 CGM.GetGlobalValue(CGM.getMangledName(GD))))
11820 return !F->isDeclaration();
11821 return false;
11822 }
11823 return true;
11824 }
11825
11826 return !AlreadyEmittedTargetDecls.insert(D).second;
11827}
11828
11830 const OMPExecutableDirective &D,
11831 SourceLocation Loc,
11832 llvm::Function *OutlinedFn,
11833 ArrayRef<llvm::Value *> CapturedVars) {
11834 if (!CGF.HaveInsertPoint())
11835 return;
11836
11837 llvm::Value *RTLoc = emitUpdateLocation(CGF, Loc);
11839
11840 // Build call __kmpc_fork_teams(loc, n, microtask, var1, .., varn);
11841 llvm::Value *Args[] = {
11842 RTLoc,
11843 CGF.Builder.getInt32(CapturedVars.size()), // Number of captured vars
11844 OutlinedFn};
11846 RealArgs.append(std::begin(Args), std::end(Args));
11847 RealArgs.append(CapturedVars.begin(), CapturedVars.end());
11848
11849 llvm::FunctionCallee RTLFn = OMPBuilder.getOrCreateRuntimeFunction(
11850 CGM.getModule(), OMPRTL___kmpc_fork_teams);
11851 CGF.EmitRuntimeCall(RTLFn, RealArgs);
11852}
11853
11855 const Expr *NumTeams,
11856 const Expr *ThreadLimit,
11857 SourceLocation Loc) {
11858 if (!CGF.HaveInsertPoint())
11859 return;
11860
11861 llvm::Value *RTLoc = emitUpdateLocation(CGF, Loc);
11862
11863 llvm::Value *NumTeamsVal =
11864 NumTeams
11865 ? CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(NumTeams),
11866 CGF.CGM.Int32Ty, /* isSigned = */ true)
11867 : CGF.Builder.getInt32(0);
11868
11869 llvm::Value *ThreadLimitVal =
11870 ThreadLimit
11871 ? CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(ThreadLimit),
11872 CGF.CGM.Int32Ty, /* isSigned = */ true)
11873 : CGF.Builder.getInt32(0);
11874
11875 // Build call __kmpc_push_num_teamss(&loc, global_tid, num_teams, thread_limit)
11876 llvm::Value *PushNumTeamsArgs[] = {RTLoc, getThreadID(CGF, Loc), NumTeamsVal,
11877 ThreadLimitVal};
11878 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
11879 CGM.getModule(), OMPRTL___kmpc_push_num_teams),
11880 PushNumTeamsArgs);
11881}
11882
11884 const Expr *ThreadLimit,
11885 SourceLocation Loc) {
11886 llvm::Value *RTLoc = emitUpdateLocation(CGF, Loc);
11887 llvm::Value *ThreadLimitVal =
11888 ThreadLimit
11889 ? CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(ThreadLimit),
11890 CGF.CGM.Int32Ty, /* isSigned = */ true)
11891 : CGF.Builder.getInt32(0);
11892
11893 // Build call __kmpc_set_thread_limit(&loc, global_tid, thread_limit)
11894 llvm::Value *ThreadLimitArgs[] = {RTLoc, getThreadID(CGF, Loc),
11895 ThreadLimitVal};
11896 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
11897 CGM.getModule(), OMPRTL___kmpc_set_thread_limit),
11898 ThreadLimitArgs);
11899}
11900
11902 CodeGenFunction &CGF, const OMPExecutableDirective &D, const Expr *IfCond,
11903 const Expr *Device, const RegionCodeGenTy &CodeGen,
11905 if (!CGF.HaveInsertPoint())
11906 return;
11907
11908 // Action used to replace the default codegen action and turn privatization
11909 // off.
11910 PrePostActionTy NoPrivAction;
11911
11912 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
11913
11914 llvm::Value *IfCondVal = nullptr;
11915 if (IfCond)
11916 IfCondVal = CGF.EvaluateExprAsBool(IfCond);
11917
11918 // Emit device ID if any.
11919 llvm::Value *DeviceID = nullptr;
11920 if (Device) {
11921 DeviceID = CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(Device),
11922 CGF.Int64Ty, /*isSigned=*/true);
11923 } else {
11924 DeviceID = CGF.Builder.getInt64(OMP_DEVICEID_UNDEF);
11925 }
11926
11927 // Fill up the arrays with all the mapped variables.
11928 MappableExprsHandler::MapCombinedInfoTy CombinedInfo;
11929 auto GenMapInfoCB =
11930 [&](InsertPointTy CodeGenIP) -> llvm::OpenMPIRBuilder::MapInfosTy & {
11931 CGF.Builder.restoreIP(CodeGenIP);
11932 // Get map clause information.
11933 MappableExprsHandler MEHandler(D, CGF);
11934 MEHandler.generateAllInfo(CombinedInfo, OMPBuilder);
11935
11936 auto FillInfoMap = [&](MappableExprsHandler::MappingExprInfo &MapExpr) {
11937 return emitMappingInformation(CGF, OMPBuilder, MapExpr);
11938 };
11939 if (CGM.getCodeGenOpts().getDebugInfo() !=
11940 llvm::codegenoptions::NoDebugInfo) {
11941 CombinedInfo.Names.resize(CombinedInfo.Exprs.size());
11942 llvm::transform(CombinedInfo.Exprs, CombinedInfo.Names.begin(),
11943 FillInfoMap);
11944 }
11945
11946 return CombinedInfo;
11947 };
11948 using BodyGenTy = llvm::OpenMPIRBuilder::BodyGenTy;
11949 auto BodyCB = [&](InsertPointTy CodeGenIP, BodyGenTy BodyGenType) {
11950 CGF.Builder.restoreIP(CodeGenIP);
11951 switch (BodyGenType) {
11952 case BodyGenTy::Priv:
11953 if (!Info.CaptureDeviceAddrMap.empty())
11954 CodeGen(CGF);
11955 break;
11956 case BodyGenTy::DupNoPriv:
11957 if (!Info.CaptureDeviceAddrMap.empty()) {
11958 CodeGen.setAction(NoPrivAction);
11959 CodeGen(CGF);
11960 }
11961 break;
11962 case BodyGenTy::NoPriv:
11963 if (Info.CaptureDeviceAddrMap.empty()) {
11964 CodeGen.setAction(NoPrivAction);
11965 CodeGen(CGF);
11966 }
11967 break;
11968 }
11969 return InsertPointTy(CGF.Builder.GetInsertPoint());
11970 };
11971
11972 auto DeviceAddrCB = [&](unsigned int I, llvm::Value *NewDecl) {
11973 if (const ValueDecl *DevVD = CombinedInfo.DevicePtrDecls[I]) {
11974 Info.CaptureDeviceAddrMap.try_emplace(DevVD, NewDecl);
11975 }
11976 };
11977
11978 auto CustomMapperCB = [&](unsigned int I) {
11979 llvm::Function *MFunc = nullptr;
11980 if (CombinedInfo.Mappers[I]) {
11981 Info.HasMapper = true;
11983 cast<OMPDeclareMapperDecl>(CombinedInfo.Mappers[I]));
11984 }
11985 return MFunc;
11986 };
11987
11988 // Source location for the ident struct
11989 llvm::Value *RTLoc = emitUpdateLocation(CGF, D.getBeginLoc());
11990
11991 InsertPointTy AllocaIP(CGF.AllocaInsertPt->getIterator());
11992 InsertPointTy CodeGenIP(CGF.Builder.GetInsertPoint());
11993 llvm::OpenMPIRBuilder::LocationDescription OmpLoc(CGF.Builder);
11994 llvm::OpenMPIRBuilder::InsertPointTy AfterIP =
11995 cantFail(OMPBuilder.createTargetData(
11996 OmpLoc, AllocaIP, CodeGenIP, /*DeallocBlocks=*/{}, DeviceID,
11997 IfCondVal, Info, GenMapInfoCB, CustomMapperCB,
11998 /*MapperFunc=*/nullptr, BodyCB, DeviceAddrCB, RTLoc));
11999 CGF.Builder.restoreIP(AfterIP);
12000}
12001
12003 CodeGenFunction &CGF, const OMPExecutableDirective &D, const Expr *IfCond,
12004 const Expr *Device) {
12005 if (!CGF.HaveInsertPoint())
12006 return;
12007
12011 "Expecting either target enter, exit data, or update directives.");
12012
12014 llvm::Value *MapTypesArray = nullptr;
12015 llvm::Value *MapNamesArray = nullptr;
12016 // Generate the code for the opening of the data environment.
12017 auto &&ThenGen = [this, &D, Device, &InputInfo, &MapTypesArray,
12018 &MapNamesArray](CodeGenFunction &CGF, PrePostActionTy &) {
12019 // Emit device ID if any.
12020 llvm::Value *DeviceID = nullptr;
12021 if (Device) {
12022 DeviceID = CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(Device),
12023 CGF.Int64Ty, /*isSigned=*/true);
12024 } else {
12025 DeviceID = CGF.Builder.getInt64(OMP_DEVICEID_UNDEF);
12026 }
12027
12028 // Emit the number of elements in the offloading arrays.
12029 llvm::Constant *PointerNum =
12030 CGF.Builder.getInt32(InputInfo.NumberOfTargetItems);
12031
12032 // Source location for the ident struct
12033 llvm::Value *RTLoc = emitUpdateLocation(CGF, D.getBeginLoc());
12034
12035 SmallVector<llvm::Value *, 13> OffloadingArgs(
12036 {RTLoc, DeviceID, PointerNum,
12037 InputInfo.BasePointersArray.emitRawPointer(CGF),
12038 InputInfo.PointersArray.emitRawPointer(CGF),
12039 InputInfo.SizesArray.emitRawPointer(CGF), MapTypesArray, MapNamesArray,
12040 InputInfo.MappersArray.emitRawPointer(CGF)});
12041
12042 // Select the right runtime function call for each standalone
12043 // directive.
12044 const bool HasNowait = D.hasClausesOfKind<OMPNowaitClause>();
12045 RuntimeFunction RTLFn;
12046 switch (D.getDirectiveKind()) {
12047 case OMPD_target_enter_data:
12048 RTLFn = HasNowait ? OMPRTL___tgt_target_data_begin_nowait_mapper
12049 : OMPRTL___tgt_target_data_begin_mapper;
12050 break;
12051 case OMPD_target_exit_data:
12052 RTLFn = HasNowait ? OMPRTL___tgt_target_data_end_nowait_mapper
12053 : OMPRTL___tgt_target_data_end_mapper;
12054 break;
12055 case OMPD_target_update:
12056 RTLFn = HasNowait ? OMPRTL___tgt_target_data_update_nowait_mapper
12057 : OMPRTL___tgt_target_data_update_mapper;
12058 break;
12059 case OMPD_parallel:
12060 case OMPD_for:
12061 case OMPD_parallel_for:
12062 case OMPD_parallel_master:
12063 case OMPD_parallel_sections:
12064 case OMPD_for_simd:
12065 case OMPD_parallel_for_simd:
12066 case OMPD_cancel:
12067 case OMPD_cancellation_point:
12068 case OMPD_ordered_standalone:
12069 case OMPD_ordered_blockassoc:
12070 case OMPD_threadprivate:
12071 case OMPD_allocate:
12072 case OMPD_task:
12073 case OMPD_simd:
12074 case OMPD_tile:
12075 case OMPD_unroll:
12076 case OMPD_sections:
12077 case OMPD_section:
12078 case OMPD_single:
12079 case OMPD_master:
12080 case OMPD_critical:
12081 case OMPD_taskyield:
12082 case OMPD_barrier:
12083 case OMPD_taskwait:
12084 case OMPD_taskgroup:
12085 case OMPD_atomic:
12086 case OMPD_flush:
12087 case OMPD_depobj:
12088 case OMPD_scan:
12089 case OMPD_teams:
12090 case OMPD_target_data:
12091 case OMPD_distribute:
12092 case OMPD_distribute_simd:
12093 case OMPD_distribute_parallel_for:
12094 case OMPD_distribute_parallel_for_simd:
12095 case OMPD_teams_distribute:
12096 case OMPD_teams_distribute_simd:
12097 case OMPD_teams_distribute_parallel_for:
12098 case OMPD_teams_distribute_parallel_for_simd:
12099 case OMPD_declare_simd:
12100 case OMPD_declare_variant:
12101 case OMPD_begin_declare_variant:
12102 case OMPD_end_declare_variant:
12103 case OMPD_declare_target:
12104 case OMPD_end_declare_target:
12105 case OMPD_declare_reduction:
12106 case OMPD_declare_mapper:
12107 case OMPD_taskloop:
12108 case OMPD_taskloop_simd:
12109 case OMPD_master_taskloop:
12110 case OMPD_master_taskloop_simd:
12111 case OMPD_parallel_master_taskloop:
12112 case OMPD_parallel_master_taskloop_simd:
12113 case OMPD_target:
12114 case OMPD_target_simd:
12115 case OMPD_target_teams_distribute:
12116 case OMPD_target_teams_distribute_simd:
12117 case OMPD_target_teams_distribute_parallel_for:
12118 case OMPD_target_teams_distribute_parallel_for_simd:
12119 case OMPD_target_teams:
12120 case OMPD_target_parallel:
12121 case OMPD_target_parallel_for:
12122 case OMPD_target_parallel_for_simd:
12123 case OMPD_requires:
12124 case OMPD_metadirective:
12125 case OMPD_unknown:
12126 default:
12127 llvm_unreachable("Unexpected standalone target data directive.");
12128 break;
12129 }
12130 if (HasNowait) {
12131 OffloadingArgs.push_back(llvm::Constant::getNullValue(CGF.Int32Ty));
12132 OffloadingArgs.push_back(llvm::Constant::getNullValue(CGF.VoidPtrTy));
12133 OffloadingArgs.push_back(llvm::Constant::getNullValue(CGF.Int32Ty));
12134 OffloadingArgs.push_back(llvm::Constant::getNullValue(CGF.VoidPtrTy));
12135 }
12136 CGF.EmitRuntimeCall(
12137 OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(), RTLFn),
12138 OffloadingArgs);
12139 };
12140
12141 auto &&TargetThenGen = [this, &ThenGen, &D, &InputInfo, &MapTypesArray,
12142 &MapNamesArray](CodeGenFunction &CGF,
12143 PrePostActionTy &) {
12144 // Fill up the arrays with all the mapped variables.
12145 MappableExprsHandler::MapCombinedInfoTy CombinedInfo;
12147 MappableExprsHandler MEHandler(D, CGF);
12148 genMapInfo(MEHandler, CGF, CombinedInfo, OMPBuilder);
12149 emitOffloadingArraysAndArgs(CGF, CombinedInfo, Info, OMPBuilder,
12150 /*IsNonContiguous=*/true, /*ForEndCall=*/false);
12151
12152 bool RequiresOuterTask = D.hasClausesOfKind<OMPDependClause>() ||
12153 D.hasClausesOfKind<OMPNowaitClause>();
12154
12155 InputInfo.NumberOfTargetItems = Info.NumberOfPtrs;
12156 InputInfo.BasePointersArray = Address(Info.RTArgs.BasePointersArray,
12157 CGF.VoidPtrTy, CGM.getPointerAlign());
12158 InputInfo.PointersArray = Address(Info.RTArgs.PointersArray, CGF.VoidPtrTy,
12159 CGM.getPointerAlign());
12160 InputInfo.SizesArray =
12161 Address(Info.RTArgs.SizesArray, CGF.Int64Ty, CGM.getPointerAlign());
12162 InputInfo.MappersArray =
12163 Address(Info.RTArgs.MappersArray, CGF.VoidPtrTy, CGM.getPointerAlign());
12164 MapTypesArray = Info.RTArgs.MapTypesArray;
12165 MapNamesArray = Info.RTArgs.MapNamesArray;
12166 if (RequiresOuterTask)
12167 CGF.EmitOMPTargetTaskBasedDirective(D, ThenGen, InputInfo);
12168 else
12169 emitInlinedDirective(CGF, D.getDirectiveKind(), ThenGen);
12170 };
12171
12172 if (IfCond) {
12173 emitIfClause(CGF, IfCond, TargetThenGen,
12174 [](CodeGenFunction &CGF, PrePostActionTy &) {});
12175 } else {
12176 RegionCodeGenTy ThenRCG(TargetThenGen);
12177 ThenRCG(CGF);
12178 }
12179}
12180
12181static unsigned
12184 // Every vector variant of a SIMD-enabled function has a vector length (VLEN).
12185 // If OpenMP clause "simdlen" is used, the VLEN is the value of the argument
12186 // of that clause. The VLEN value must be power of 2.
12187 // In other case the notion of the function`s "characteristic data type" (CDT)
12188 // is used to compute the vector length.
12189 // CDT is defined in the following order:
12190 // a) For non-void function, the CDT is the return type.
12191 // b) If the function has any non-uniform, non-linear parameters, then the
12192 // CDT is the type of the first such parameter.
12193 // c) If the CDT determined by a) or b) above is struct, union, or class
12194 // type which is pass-by-value (except for the type that maps to the
12195 // built-in complex data type), the characteristic data type is int.
12196 // d) If none of the above three cases is applicable, the CDT is int.
12197 // The VLEN is then determined based on the CDT and the size of vector
12198 // register of that ISA for which current vector version is generated. The
12199 // VLEN is computed using the formula below:
12200 // VLEN = sizeof(vector_register) / sizeof(CDT),
12201 // where vector register size specified in section 3.2.1 Registers and the
12202 // Stack Frame of original AMD64 ABI document.
12203 QualType RetType = FD->getReturnType();
12204 if (RetType.isNull())
12205 return 0;
12206 ASTContext &C = FD->getASTContext();
12207 QualType CDT;
12208 if (!RetType.isNull() && !RetType->isVoidType()) {
12209 CDT = RetType;
12210 } else {
12211 unsigned Offset = 0;
12212 if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
12213 if (ParamAttrs[Offset].Kind ==
12214 llvm::OpenMPIRBuilder::DeclareSimdKindTy::Vector)
12215 CDT = C.getPointerType(C.getCanonicalTagType(MD->getParent()));
12216 ++Offset;
12217 }
12218 if (CDT.isNull()) {
12219 for (unsigned I = 0, E = FD->getNumParams(); I < E; ++I) {
12220 if (ParamAttrs[I + Offset].Kind ==
12221 llvm::OpenMPIRBuilder::DeclareSimdKindTy::Vector) {
12222 CDT = FD->getParamDecl(I)->getType();
12223 break;
12224 }
12225 }
12226 }
12227 }
12228 if (CDT.isNull())
12229 CDT = C.IntTy;
12230 CDT = CDT->getCanonicalTypeUnqualified();
12231 if (CDT->isRecordType() || CDT->isUnionType())
12232 CDT = C.IntTy;
12233 return C.getTypeSize(CDT);
12234}
12235
12236// This are the Functions that are needed to mangle the name of the
12237// vector functions generated by the compiler, according to the rules
12238// defined in the "Vector Function ABI specifications for AArch64",
12239// available at
12240// https://developer.arm.com/products/software-development-tools/hpc/arm-compiler-for-hpc/vector-function-abi.
12241
12242/// Maps To Vector (MTV), as defined in 4.1.1 of the AAVFABI (2021Q1).
12244 llvm::OpenMPIRBuilder::DeclareSimdKindTy Kind) {
12245 QT = QT.getCanonicalType();
12246
12247 if (QT->isVoidType())
12248 return false;
12249
12250 if (Kind == llvm::OpenMPIRBuilder::DeclareSimdKindTy::Uniform)
12251 return false;
12252
12253 if (Kind == llvm::OpenMPIRBuilder::DeclareSimdKindTy::LinearUVal ||
12254 Kind == llvm::OpenMPIRBuilder::DeclareSimdKindTy::LinearRef)
12255 return false;
12256
12257 if ((Kind == llvm::OpenMPIRBuilder::DeclareSimdKindTy::Linear ||
12258 Kind == llvm::OpenMPIRBuilder::DeclareSimdKindTy::LinearVal) &&
12259 !QT->isReferenceType())
12260 return false;
12261
12262 return true;
12263}
12264
12265/// Pass By Value (PBV), as defined in 3.1.2 of the AAVFABI.
12267 QT = QT.getCanonicalType();
12268 unsigned Size = C.getTypeSize(QT);
12269
12270 // Only scalars and complex within 16 bytes wide set PVB to true.
12271 if (Size != 8 && Size != 16 && Size != 32 && Size != 64 && Size != 128)
12272 return false;
12273
12274 if (QT->isFloatingType())
12275 return true;
12276
12277 if (QT->isIntegerType())
12278 return true;
12279
12280 if (QT->isPointerType())
12281 return true;
12282
12283 // TODO: Add support for complex types (section 3.1.2, item 2).
12284
12285 return false;
12286}
12287
12288/// Computes the lane size (LS) of a return type or of an input parameter,
12289/// as defined by `LS(P)` in 3.2.1 of the AAVFABI.
12290/// TODO: Add support for references, section 3.2.1, item 1.
12291static unsigned getAArch64LS(QualType QT,
12292 llvm::OpenMPIRBuilder::DeclareSimdKindTy Kind,
12293 ASTContext &C) {
12294 if (!getAArch64MTV(QT, Kind) && QT.getCanonicalType()->isPointerType()) {
12296 if (getAArch64PBV(PTy, C))
12297 return C.getTypeSize(PTy);
12298 }
12299 if (getAArch64PBV(QT, C))
12300 return C.getTypeSize(QT);
12301
12302 return C.getTypeSize(C.getUIntPtrType());
12303}
12304
12305// Get Narrowest Data Size (NDS) and Widest Data Size (WDS) from the
12306// signature of the scalar function, as defined in 3.2.2 of the
12307// AAVFABI.
12308static std::tuple<unsigned, unsigned, bool>
12311 QualType RetType = FD->getReturnType().getCanonicalType();
12312
12313 ASTContext &C = FD->getASTContext();
12314
12315 bool OutputBecomesInput = false;
12316
12318 if (!RetType->isVoidType()) {
12319 Sizes.push_back(getAArch64LS(
12320 RetType, llvm::OpenMPIRBuilder::DeclareSimdKindTy::Vector, C));
12321 if (!getAArch64PBV(RetType, C) && getAArch64MTV(RetType, {}))
12322 OutputBecomesInput = true;
12323 }
12324 for (unsigned I = 0, E = FD->getNumParams(); I < E; ++I) {
12326 Sizes.push_back(getAArch64LS(QT, ParamAttrs[I].Kind, C));
12327 }
12328
12329 assert(!Sizes.empty() && "Unable to determine NDS and WDS.");
12330 // The LS of a function parameter / return value can only be a power
12331 // of 2, starting from 8 bits, up to 128.
12332 assert(llvm::all_of(Sizes,
12333 [](unsigned Size) {
12334 return Size == 8 || Size == 16 || Size == 32 ||
12335 Size == 64 || Size == 128;
12336 }) &&
12337 "Invalid size");
12338
12339 return std::make_tuple(*llvm::min_element(Sizes), *llvm::max_element(Sizes),
12340 OutputBecomesInput);
12341}
12342
12343static llvm::OpenMPIRBuilder::DeclareSimdBranch
12344convertDeclareSimdBranch(OMPDeclareSimdDeclAttr::BranchStateTy State) {
12345 switch (State) {
12346 case OMPDeclareSimdDeclAttr::BS_Undefined:
12347 return llvm::OpenMPIRBuilder::DeclareSimdBranch::Undefined;
12348 case OMPDeclareSimdDeclAttr::BS_Inbranch:
12349 return llvm::OpenMPIRBuilder::DeclareSimdBranch::Inbranch;
12350 case OMPDeclareSimdDeclAttr::BS_Notinbranch:
12351 return llvm::OpenMPIRBuilder::DeclareSimdBranch::Notinbranch;
12352 }
12353 llvm_unreachable("unexpected declare simd branch state");
12354}
12355
12356// Check the values provided via `simdlen` by the user.
12358 unsigned UserVLEN, unsigned WDS, char ISA) {
12359 // 1. A `simdlen(1)` doesn't produce vector signatures.
12360 if (UserVLEN == 1) {
12361 CGM.getDiags().Report(SLoc, diag::warn_simdlen_1_no_effect);
12362 return false;
12363 }
12364
12365 // 2. Section 3.3.1, item 1: user input must be a power of 2 for Advanced
12366 // SIMD.
12367 if (ISA == 'n' && UserVLEN && !llvm::isPowerOf2_32(UserVLEN)) {
12368 CGM.getDiags().Report(SLoc, diag::warn_simdlen_requires_power_of_2);
12369 return false;
12370 }
12371
12372 // 3. Section 3.4.1: SVE fixed length must obey the architectural limits.
12373 if (ISA == 's' && UserVLEN != 0 &&
12374 ((UserVLEN * WDS > 2048) || (UserVLEN * WDS % 128 != 0))) {
12375 CGM.getDiags().Report(SLoc, diag::warn_simdlen_must_fit_lanes) << WDS;
12376 return false;
12377 }
12378
12379 return true;
12380}
12381
12383 llvm::Function *Fn) {
12384 ASTContext &C = CGM.getContext();
12385 FD = FD->getMostRecentDecl();
12386 while (FD) {
12387 // Map params to their positions in function decl.
12388 llvm::DenseMap<const Decl *, unsigned> ParamPositions;
12389 if (isa<CXXMethodDecl>(FD))
12390 ParamPositions.try_emplace(FD, 0);
12391 unsigned ParamPos = ParamPositions.size();
12392 for (const ParmVarDecl *P : FD->parameters()) {
12393 ParamPositions.try_emplace(P->getCanonicalDecl(), ParamPos);
12394 ++ParamPos;
12395 }
12396 for (const auto *Attr : FD->specific_attrs<OMPDeclareSimdDeclAttr>()) {
12398 ParamPositions.size());
12399 // Mark uniform parameters.
12400 for (const Expr *E : Attr->uniforms()) {
12401 E = E->IgnoreParenImpCasts();
12402 unsigned Pos;
12403 if (isa<CXXThisExpr>(E)) {
12404 Pos = ParamPositions[FD];
12405 } else {
12406 const auto *PVD = cast<ParmVarDecl>(cast<DeclRefExpr>(E)->getDecl())
12407 ->getCanonicalDecl();
12408 auto It = ParamPositions.find(PVD);
12409 assert(It != ParamPositions.end() && "Function parameter not found");
12410 Pos = It->second;
12411 }
12412 ParamAttrs[Pos].Kind =
12413 llvm::OpenMPIRBuilder::DeclareSimdKindTy::Uniform;
12414 }
12415 // Get alignment info.
12416 auto *NI = Attr->alignments_begin();
12417 for (const Expr *E : Attr->aligneds()) {
12418 E = E->IgnoreParenImpCasts();
12419 unsigned Pos;
12420 QualType ParmTy;
12421 if (isa<CXXThisExpr>(E)) {
12422 Pos = ParamPositions[FD];
12423 ParmTy = E->getType();
12424 } else {
12425 const auto *PVD = cast<ParmVarDecl>(cast<DeclRefExpr>(E)->getDecl())
12426 ->getCanonicalDecl();
12427 auto It = ParamPositions.find(PVD);
12428 assert(It != ParamPositions.end() && "Function parameter not found");
12429 Pos = It->second;
12430 ParmTy = PVD->getType();
12431 }
12432 ParamAttrs[Pos].Alignment =
12433 (*NI)
12434 ? (*NI)->EvaluateKnownConstInt(C)
12435 : llvm::APSInt::getUnsigned(
12436 C.toCharUnitsFromBits(C.getOpenMPDefaultSimdAlign(ParmTy))
12437 .getQuantity());
12438 ++NI;
12439 }
12440 // Mark linear parameters.
12441 auto *SI = Attr->steps_begin();
12442 auto *MI = Attr->modifiers_begin();
12443 for (const Expr *E : Attr->linears()) {
12444 E = E->IgnoreParenImpCasts();
12445 unsigned Pos;
12446 bool IsReferenceType = false;
12447 // Rescaling factor needed to compute the linear parameter
12448 // value in the mangled name.
12449 unsigned PtrRescalingFactor = 1;
12450 if (isa<CXXThisExpr>(E)) {
12451 Pos = ParamPositions[FD];
12452 auto *P = cast<PointerType>(E->getType());
12453 PtrRescalingFactor = CGM.getContext()
12454 .getTypeSizeInChars(P->getPointeeType())
12455 .getQuantity();
12456 } else {
12457 const auto *PVD = cast<ParmVarDecl>(cast<DeclRefExpr>(E)->getDecl())
12458 ->getCanonicalDecl();
12459 auto It = ParamPositions.find(PVD);
12460 assert(It != ParamPositions.end() && "Function parameter not found");
12461 Pos = It->second;
12462 if (auto *P = dyn_cast<PointerType>(PVD->getType()))
12463 PtrRescalingFactor = CGM.getContext()
12464 .getTypeSizeInChars(P->getPointeeType())
12465 .getQuantity();
12466 else if (PVD->getType()->isReferenceType()) {
12467 IsReferenceType = true;
12468 PtrRescalingFactor =
12469 CGM.getContext()
12470 .getTypeSizeInChars(PVD->getType().getNonReferenceType())
12471 .getQuantity();
12472 }
12473 }
12474 llvm::OpenMPIRBuilder::DeclareSimdAttrTy &ParamAttr = ParamAttrs[Pos];
12475 if (*MI == OMPC_LINEAR_ref)
12476 ParamAttr.Kind = llvm::OpenMPIRBuilder::DeclareSimdKindTy::LinearRef;
12477 else if (*MI == OMPC_LINEAR_uval)
12478 ParamAttr.Kind = llvm::OpenMPIRBuilder::DeclareSimdKindTy::LinearUVal;
12479 else if (IsReferenceType)
12480 ParamAttr.Kind = llvm::OpenMPIRBuilder::DeclareSimdKindTy::LinearVal;
12481 else
12482 ParamAttr.Kind = llvm::OpenMPIRBuilder::DeclareSimdKindTy::Linear;
12483 // Assuming a stride of 1, for `linear` without modifiers.
12484 ParamAttr.StrideOrArg = llvm::APSInt::getUnsigned(1);
12485 if (*SI) {
12487 if (!(*SI)->EvaluateAsInt(Result, C, Expr::SE_AllowSideEffects)) {
12488 if (const auto *DRE =
12489 cast<DeclRefExpr>((*SI)->IgnoreParenImpCasts())) {
12490 if (const auto *StridePVD =
12491 dyn_cast<ParmVarDecl>(DRE->getDecl())) {
12492 ParamAttr.HasVarStride = true;
12493 auto It = ParamPositions.find(StridePVD->getCanonicalDecl());
12494 assert(It != ParamPositions.end() &&
12495 "Function parameter not found");
12496 ParamAttr.StrideOrArg = llvm::APSInt::getUnsigned(It->second);
12497 }
12498 }
12499 } else {
12500 ParamAttr.StrideOrArg = Result.Val.getInt();
12501 }
12502 }
12503 // If we are using a linear clause on a pointer, we need to
12504 // rescale the value of linear_step with the byte size of the
12505 // pointee type.
12506 if (!ParamAttr.HasVarStride &&
12507 (ParamAttr.Kind ==
12508 llvm::OpenMPIRBuilder::DeclareSimdKindTy::Linear ||
12509 ParamAttr.Kind ==
12510 llvm::OpenMPIRBuilder::DeclareSimdKindTy::LinearRef))
12511 ParamAttr.StrideOrArg = ParamAttr.StrideOrArg * PtrRescalingFactor;
12512 ++SI;
12513 ++MI;
12514 }
12515 llvm::APSInt VLENVal;
12516 SourceLocation ExprLoc;
12517 const Expr *VLENExpr = Attr->getSimdlen();
12518 if (VLENExpr) {
12519 VLENVal = VLENExpr->EvaluateKnownConstInt(C);
12520 ExprLoc = VLENExpr->getExprLoc();
12521 }
12522 llvm::OpenMPIRBuilder::DeclareSimdBranch State =
12523 convertDeclareSimdBranch(Attr->getBranchState());
12524 if (CGM.getTriple().isX86()) {
12525 unsigned NumElts = evaluateCDTSize(FD, ParamAttrs);
12526 assert(NumElts && "Non-zero simdlen/cdtsize expected");
12527 OMPBuilder.emitX86DeclareSimdFunction(Fn, NumElts, VLENVal, ParamAttrs,
12528 State);
12529 } else if (CGM.getTriple().getArch() == llvm::Triple::aarch64) {
12530 unsigned VLEN = VLENVal.getExtValue();
12531 // Get basic data for building the vector signature.
12532 const auto Data = getNDSWDS(FD, ParamAttrs);
12533 const unsigned NDS = std::get<0>(Data);
12534 const unsigned WDS = std::get<1>(Data);
12535 const bool OutputBecomesInput = std::get<2>(Data);
12536 if (CGM.getTarget().hasFeature("sve")) {
12537 if (validateAArch64Simdlen(CGM, ExprLoc, VLEN, WDS, 's'))
12538 OMPBuilder.emitAArch64DeclareSimdFunction(
12539 Fn, VLEN, ParamAttrs, State, 's', NDS, OutputBecomesInput);
12540 } else if (CGM.getTarget().hasFeature("neon")) {
12541 if (validateAArch64Simdlen(CGM, ExprLoc, VLEN, WDS, 'n'))
12542 OMPBuilder.emitAArch64DeclareSimdFunction(
12543 Fn, VLEN, ParamAttrs, State, 'n', NDS, OutputBecomesInput);
12544 }
12545 }
12546 }
12547 FD = FD->getPreviousDecl();
12548 }
12549}
12550
12551namespace {
12552/// Cleanup action for doacross support.
12553class DoacrossCleanupTy final : public EHScopeStack::Cleanup {
12554public:
12555 static const int DoacrossFinArgs = 2;
12556
12557private:
12558 llvm::FunctionCallee RTLFn;
12559 llvm::Value *Args[DoacrossFinArgs];
12560
12561public:
12562 DoacrossCleanupTy(llvm::FunctionCallee RTLFn,
12563 ArrayRef<llvm::Value *> CallArgs)
12564 : RTLFn(RTLFn) {
12565 assert(CallArgs.size() == DoacrossFinArgs);
12566 std::copy(CallArgs.begin(), CallArgs.end(), std::begin(Args));
12567 }
12568 void Emit(CodeGenFunction &CGF, Flags /*flags*/) override {
12569 if (!CGF.HaveInsertPoint())
12570 return;
12571 CGF.EmitRuntimeCall(RTLFn, Args);
12572 }
12573};
12574} // namespace
12575
12577 const OMPLoopDirective &D,
12578 ArrayRef<Expr *> NumIterations) {
12579 if (!CGF.HaveInsertPoint())
12580 return;
12581
12582 ASTContext &C = CGM.getContext();
12583 QualType Int64Ty = C.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/true);
12584 RecordDecl *RD;
12585 if (KmpDimTy.isNull()) {
12586 // Build struct kmp_dim { // loop bounds info casted to kmp_int64
12587 // kmp_int64 lo; // lower
12588 // kmp_int64 up; // upper
12589 // kmp_int64 st; // stride
12590 // };
12591 RD = C.buildImplicitRecord("kmp_dim");
12592 RD->startDefinition();
12593 addFieldToRecordDecl(C, RD, Int64Ty);
12594 addFieldToRecordDecl(C, RD, Int64Ty);
12595 addFieldToRecordDecl(C, RD, Int64Ty);
12596 RD->completeDefinition();
12597 KmpDimTy = C.getCanonicalTagType(RD);
12598 } else {
12599 RD = KmpDimTy->castAsRecordDecl();
12600 }
12601 llvm::APInt Size(/*numBits=*/32, NumIterations.size());
12602 QualType ArrayTy = C.getConstantArrayType(KmpDimTy, Size, nullptr,
12604
12605 Address DimsAddr = CGF.CreateMemTemp(ArrayTy, "dims");
12606 CGF.EmitNullInitialization(DimsAddr, ArrayTy);
12607 enum { LowerFD = 0, UpperFD, StrideFD };
12608 // Fill dims with data.
12609 for (unsigned I = 0, E = NumIterations.size(); I < E; ++I) {
12610 LValue DimsLVal = CGF.MakeAddrLValue(
12611 CGF.Builder.CreateConstArrayGEP(DimsAddr, I), KmpDimTy);
12612 // dims.upper = num_iterations;
12613 LValue UpperLVal = CGF.EmitLValueForField(
12614 DimsLVal, *std::next(RD->field_begin(), UpperFD));
12615 llvm::Value *NumIterVal = CGF.EmitScalarConversion(
12616 CGF.EmitScalarExpr(NumIterations[I]), NumIterations[I]->getType(),
12617 Int64Ty, NumIterations[I]->getExprLoc());
12618 CGF.EmitStoreOfScalar(NumIterVal, UpperLVal);
12619 // dims.stride = 1;
12620 LValue StrideLVal = CGF.EmitLValueForField(
12621 DimsLVal, *std::next(RD->field_begin(), StrideFD));
12622 CGF.EmitStoreOfScalar(llvm::ConstantInt::getSigned(CGM.Int64Ty, /*V=*/1),
12623 StrideLVal);
12624 }
12625
12626 // Build call void __kmpc_doacross_init(ident_t *loc, kmp_int32 gtid,
12627 // kmp_int32 num_dims, struct kmp_dim * dims);
12628 llvm::Value *Args[] = {
12629 emitUpdateLocation(CGF, D.getBeginLoc()),
12630 getThreadID(CGF, D.getBeginLoc()),
12631 llvm::ConstantInt::getSigned(CGM.Int32Ty, NumIterations.size()),
12633 CGF.Builder.CreateConstArrayGEP(DimsAddr, 0).emitRawPointer(CGF),
12634 CGM.VoidPtrTy)};
12635
12636 llvm::FunctionCallee RTLFn = OMPBuilder.getOrCreateRuntimeFunction(
12637 CGM.getModule(), OMPRTL___kmpc_doacross_init);
12638 CGF.EmitRuntimeCall(RTLFn, Args);
12639 llvm::Value *FiniArgs[DoacrossCleanupTy::DoacrossFinArgs] = {
12640 emitUpdateLocation(CGF, D.getEndLoc()), getThreadID(CGF, D.getEndLoc())};
12641 llvm::FunctionCallee FiniRTLFn = OMPBuilder.getOrCreateRuntimeFunction(
12642 CGM.getModule(), OMPRTL___kmpc_doacross_fini);
12643 CGF.EHStack.pushCleanup<DoacrossCleanupTy>(NormalAndEHCleanup, FiniRTLFn,
12644 llvm::ArrayRef(FiniArgs));
12645}
12646
12647template <typename T>
12649 const T *C, llvm::Value *ULoc,
12650 llvm::Value *ThreadID) {
12651 QualType Int64Ty =
12652 CGM.getContext().getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1);
12653 llvm::APInt Size(/*numBits=*/32, C->getNumLoops());
12655 Int64Ty, Size, nullptr, ArraySizeModifier::Normal, 0);
12656 Address CntAddr = CGF.CreateMemTemp(ArrayTy, ".cnt.addr");
12657 for (unsigned I = 0, E = C->getNumLoops(); I < E; ++I) {
12658 const Expr *CounterVal = C->getLoopData(I);
12659 assert(CounterVal);
12660 llvm::Value *CntVal = CGF.EmitScalarConversion(
12661 CGF.EmitScalarExpr(CounterVal), CounterVal->getType(), Int64Ty,
12662 CounterVal->getExprLoc());
12663 CGF.EmitStoreOfScalar(CntVal, CGF.Builder.CreateConstArrayGEP(CntAddr, I),
12664 /*Volatile=*/false, Int64Ty);
12665 }
12666 llvm::Value *Args[] = {
12667 ULoc, ThreadID,
12668 CGF.Builder.CreateConstArrayGEP(CntAddr, 0).emitRawPointer(CGF)};
12669 llvm::FunctionCallee RTLFn;
12670 llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
12671 OMPDoacrossKind<T> ODK;
12672 if (ODK.isSource(C)) {
12673 RTLFn = OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(),
12674 OMPRTL___kmpc_doacross_post);
12675 } else {
12676 assert(ODK.isSink(C) && "Expect sink modifier.");
12677 RTLFn = OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(),
12678 OMPRTL___kmpc_doacross_wait);
12679 }
12680 CGF.EmitRuntimeCall(RTLFn, Args);
12681}
12682
12684 const OMPDependClause *C) {
12686 CGF, CGM, C, emitUpdateLocation(CGF, C->getBeginLoc()),
12687 getThreadID(CGF, C->getBeginLoc()));
12688}
12689
12691 const OMPDoacrossClause *C) {
12693 CGF, CGM, C, emitUpdateLocation(CGF, C->getBeginLoc()),
12694 getThreadID(CGF, C->getBeginLoc()));
12695}
12696
12698 llvm::FunctionCallee Callee,
12699 ArrayRef<llvm::Value *> Args) const {
12700 assert(Loc.isValid() && "Outlined function call location must be valid.");
12702
12703 if (auto *Fn = dyn_cast<llvm::Function>(Callee.getCallee())) {
12704 if (Fn->doesNotThrow()) {
12705 CGF.EmitNounwindRuntimeCall(Fn, Args);
12706 return;
12707 }
12708 }
12709 CGF.EmitRuntimeCall(Callee, Args);
12710}
12711
12713 CodeGenFunction &CGF, SourceLocation Loc, llvm::FunctionCallee OutlinedFn,
12714 ArrayRef<llvm::Value *> Args) const {
12715 emitCall(CGF, Loc, OutlinedFn, Args);
12716}
12717
12719 if (const auto *FD = dyn_cast<FunctionDecl>(D))
12720 if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(FD))
12722}
12723
12725 const VarDecl *NativeParam,
12726 const VarDecl *TargetParam) const {
12727 return CGF.GetAddrOfLocalVar(NativeParam);
12728}
12729
12730/// Return allocator value from expression, or return a null allocator (default
12731/// when no allocator specified).
12732static llvm::Value *getAllocatorVal(CodeGenFunction &CGF,
12733 const Expr *Allocator) {
12734 llvm::Value *AllocVal;
12735 if (Allocator) {
12736 AllocVal = CGF.EmitScalarExpr(Allocator);
12737 // According to the standard, the original allocator type is a enum
12738 // (integer). Convert to pointer type, if required.
12739 AllocVal = CGF.EmitScalarConversion(AllocVal, Allocator->getType(),
12740 CGF.getContext().VoidPtrTy,
12741 Allocator->getExprLoc());
12742 } else {
12743 // If no allocator specified, it defaults to the null allocator.
12744 AllocVal = llvm::Constant::getNullValue(
12746 }
12747 return AllocVal;
12748}
12749
12750/// Return the alignment from an allocate directive if present.
12751static llvm::Value *getAlignmentValue(CodeGenModule &CGM, const VarDecl *VD) {
12752 std::optional<CharUnits> AllocateAlignment = CGM.getOMPAllocateAlignment(VD);
12753
12754 if (!AllocateAlignment)
12755 return nullptr;
12756
12757 return llvm::ConstantInt::get(CGM.SizeTy, AllocateAlignment->getQuantity());
12758}
12759
12761 const VarDecl *VD) {
12762 if (!VD)
12763 return Address::invalid();
12764 Address UntiedAddr = Address::invalid();
12765 Address UntiedRealAddr = Address::invalid();
12766 auto It = FunctionToUntiedTaskStackMap.find(CGF.CurFn);
12767 if (It != FunctionToUntiedTaskStackMap.end()) {
12768 const UntiedLocalVarsAddressesMap &UntiedData =
12769 UntiedLocalVarsStack[It->second];
12770 auto I = UntiedData.find(VD);
12771 if (I != UntiedData.end()) {
12772 UntiedAddr = I->second.first;
12773 UntiedRealAddr = I->second.second;
12774 }
12775 }
12776 const VarDecl *CVD = VD->getCanonicalDecl();
12777 if (CVD->hasAttr<OMPAllocateDeclAttr>()) {
12778 // Use the default allocation.
12779 if (!isAllocatableDecl(VD))
12780 return UntiedAddr;
12781 llvm::Value *Size;
12782 CharUnits Align = CGM.getContext().getDeclAlign(CVD);
12783 if (CVD->getType()->isVariablyModifiedType()) {
12784 Size = CGF.getTypeSize(CVD->getType());
12785 // Align the size: ((size + align - 1) / align) * align
12786 Size = CGF.Builder.CreateNUWAdd(
12787 Size, CGM.getSize(Align - CharUnits::fromQuantity(1)));
12788 Size = CGF.Builder.CreateUDiv(Size, CGM.getSize(Align));
12789 Size = CGF.Builder.CreateNUWMul(Size, CGM.getSize(Align));
12790 } else {
12791 CharUnits Sz = CGM.getContext().getTypeSizeInChars(CVD->getType());
12792 Size = CGM.getSize(Sz.alignTo(Align));
12793 }
12794 llvm::Value *ThreadID = getThreadID(CGF, CVD->getBeginLoc());
12795 const auto *AA = CVD->getAttr<OMPAllocateDeclAttr>();
12796 const Expr *Allocator = AA->getAllocator();
12797 llvm::Value *AllocVal = getAllocatorVal(CGF, Allocator);
12798 llvm::Value *Alignment = getAlignmentValue(CGM, CVD);
12800 Args.push_back(ThreadID);
12801 if (Alignment)
12802 Args.push_back(Alignment);
12803 Args.push_back(Size);
12804 Args.push_back(AllocVal);
12805 llvm::omp::RuntimeFunction FnID =
12806 Alignment ? OMPRTL___kmpc_aligned_alloc : OMPRTL___kmpc_alloc;
12807 llvm::Value *Addr = CGF.EmitRuntimeCall(
12808 OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(), FnID), Args,
12809 getName({CVD->getName(), ".void.addr"}));
12810 llvm::FunctionCallee FiniRTLFn = OMPBuilder.getOrCreateRuntimeFunction(
12811 CGM.getModule(), OMPRTL___kmpc_free);
12812 QualType Ty = CGM.getContext().getPointerType(CVD->getType());
12814 Addr, CGF.ConvertTypeForMem(Ty), getName({CVD->getName(), ".addr"}));
12815 if (UntiedAddr.isValid())
12816 CGF.EmitStoreOfScalar(Addr, UntiedAddr, /*Volatile=*/false, Ty);
12817
12818 // Cleanup action for allocate support.
12819 class OMPAllocateCleanupTy final : public EHScopeStack::Cleanup {
12820 llvm::FunctionCallee RTLFn;
12821 SourceLocation::UIntTy LocEncoding;
12822 Address Addr;
12823 const Expr *AllocExpr;
12824
12825 public:
12826 OMPAllocateCleanupTy(llvm::FunctionCallee RTLFn,
12827 SourceLocation::UIntTy LocEncoding, Address Addr,
12828 const Expr *AllocExpr)
12829 : RTLFn(RTLFn), LocEncoding(LocEncoding), Addr(Addr),
12830 AllocExpr(AllocExpr) {}
12831 void Emit(CodeGenFunction &CGF, Flags /*flags*/) override {
12832 if (!CGF.HaveInsertPoint())
12833 return;
12834 llvm::Value *Args[3];
12835 Args[0] = CGF.CGM.getOpenMPRuntime().getThreadID(
12836 CGF, SourceLocation::getFromRawEncoding(LocEncoding));
12838 Addr.emitRawPointer(CGF), CGF.VoidPtrTy);
12839 llvm::Value *AllocVal = getAllocatorVal(CGF, AllocExpr);
12840 Args[2] = AllocVal;
12841 CGF.EmitRuntimeCall(RTLFn, Args);
12842 }
12843 };
12844 Address VDAddr =
12845 UntiedRealAddr.isValid()
12846 ? UntiedRealAddr
12847 : Address(Addr, CGF.ConvertTypeForMem(CVD->getType()), Align);
12848 CGF.EHStack.pushCleanup<OMPAllocateCleanupTy>(
12849 NormalAndEHCleanup, FiniRTLFn, CVD->getLocation().getRawEncoding(),
12850 VDAddr, Allocator);
12851 if (UntiedRealAddr.isValid())
12852 if (auto *Region =
12853 dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo))
12854 Region->emitUntiedSwitch(CGF);
12855 return VDAddr;
12856 }
12857 return UntiedAddr;
12858}
12859
12861 const VarDecl *VD) const {
12862 auto It = FunctionToUntiedTaskStackMap.find(CGF.CurFn);
12863 if (It == FunctionToUntiedTaskStackMap.end())
12864 return false;
12865 return UntiedLocalVarsStack[It->second].count(VD) > 0;
12866}
12867
12869 CodeGenModule &CGM, const OMPLoopDirective &S)
12870 : CGM(CGM), NeedToPush(S.hasClausesOfKind<OMPNontemporalClause>()) {
12871 assert(CGM.getLangOpts().OpenMP && "Not in OpenMP mode.");
12872 if (!NeedToPush)
12873 return;
12875 CGM.getOpenMPRuntime().NontemporalDeclsStack.emplace_back();
12876 for (const auto *C : S.getClausesOfKind<OMPNontemporalClause>()) {
12877 for (const Stmt *Ref : C->private_refs()) {
12878 const auto *SimpleRefExpr = cast<Expr>(Ref)->IgnoreParenImpCasts();
12879 const ValueDecl *VD;
12880 if (const auto *DRE = dyn_cast<DeclRefExpr>(SimpleRefExpr)) {
12881 VD = DRE->getDecl();
12882 } else {
12883 const auto *ME = cast<MemberExpr>(SimpleRefExpr);
12884 assert((ME->isImplicitCXXThis() ||
12885 isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts())) &&
12886 "Expected member of current class.");
12887 VD = ME->getMemberDecl();
12888 }
12889 DS.insert(VD);
12890 }
12891 }
12892}
12893
12895 if (!NeedToPush)
12896 return;
12897 CGM.getOpenMPRuntime().NontemporalDeclsStack.pop_back();
12898}
12899
12901 CodeGenFunction &CGF,
12902 const llvm::MapVector<CanonicalDeclPtr<const VarDecl>,
12903 std::pair<Address, Address>> &LocalVars)
12904 : CGM(CGF.CGM), NeedToPush(!LocalVars.empty()) {
12905 if (!NeedToPush)
12906 return;
12907 CGM.getOpenMPRuntime().FunctionToUntiedTaskStackMap.try_emplace(
12908 CGF.CurFn, CGM.getOpenMPRuntime().UntiedLocalVarsStack.size());
12909 CGM.getOpenMPRuntime().UntiedLocalVarsStack.push_back(LocalVars);
12910}
12911
12913 if (!NeedToPush)
12914 return;
12915 CGM.getOpenMPRuntime().UntiedLocalVarsStack.pop_back();
12916}
12917
12919 assert(CGM.getLangOpts().OpenMP && "Not in OpenMP mode.");
12920
12921 return llvm::any_of(
12922 CGM.getOpenMPRuntime().NontemporalDeclsStack,
12923 [VD](const NontemporalDeclsSet &Set) { return Set.contains(VD); });
12924}
12925
12926void CGOpenMPRuntime::LastprivateConditionalRAII::tryToDisableInnerAnalysis(
12927 const OMPExecutableDirective &S,
12928 llvm::DenseSet<CanonicalDeclPtr<const Decl>> &NeedToAddForLPCsAsDisabled)
12929 const {
12930 llvm::DenseSet<CanonicalDeclPtr<const Decl>> NeedToCheckForLPCs;
12931 // Vars in target/task regions must be excluded completely.
12932 if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()) ||
12933 isOpenMPTaskingDirective(S.getDirectiveKind())) {
12935 getOpenMPCaptureRegions(CaptureRegions, S.getDirectiveKind());
12936 const CapturedStmt *CS = S.getCapturedStmt(CaptureRegions.front());
12937 for (const CapturedStmt::Capture &Cap : CS->captures()) {
12938 if (Cap.capturesVariable() || Cap.capturesVariableByCopy())
12939 NeedToCheckForLPCs.insert(Cap.getCapturedVar());
12940 }
12941 }
12942 // Exclude vars in private clauses.
12943 for (const auto *C : S.getClausesOfKind<OMPPrivateClause>()) {
12944 for (const Expr *Ref : C->varlist()) {
12945 if (!Ref->getType()->isScalarType())
12946 continue;
12947 const auto *DRE = dyn_cast<DeclRefExpr>(Ref->IgnoreParenImpCasts());
12948 if (!DRE)
12949 continue;
12950 NeedToCheckForLPCs.insert(DRE->getDecl());
12951 }
12952 }
12953 for (const auto *C : S.getClausesOfKind<OMPFirstprivateClause>()) {
12954 for (const Expr *Ref : C->varlist()) {
12955 if (!Ref->getType()->isScalarType())
12956 continue;
12957 const auto *DRE = dyn_cast<DeclRefExpr>(Ref->IgnoreParenImpCasts());
12958 if (!DRE)
12959 continue;
12960 NeedToCheckForLPCs.insert(DRE->getDecl());
12961 }
12962 }
12963 for (const auto *C : S.getClausesOfKind<OMPLastprivateClause>()) {
12964 for (const Expr *Ref : C->varlist()) {
12965 if (!Ref->getType()->isScalarType())
12966 continue;
12967 const auto *DRE = dyn_cast<DeclRefExpr>(Ref->IgnoreParenImpCasts());
12968 if (!DRE)
12969 continue;
12970 NeedToCheckForLPCs.insert(DRE->getDecl());
12971 }
12972 }
12973 for (const auto *C : S.getClausesOfKind<OMPReductionClause>()) {
12974 for (const Expr *Ref : C->varlist()) {
12975 if (!Ref->getType()->isScalarType())
12976 continue;
12977 const auto *DRE = dyn_cast<DeclRefExpr>(Ref->IgnoreParenImpCasts());
12978 if (!DRE)
12979 continue;
12980 NeedToCheckForLPCs.insert(DRE->getDecl());
12981 }
12982 }
12983 for (const auto *C : S.getClausesOfKind<OMPLinearClause>()) {
12984 for (const Expr *Ref : C->varlist()) {
12985 if (!Ref->getType()->isScalarType())
12986 continue;
12987 const auto *DRE = dyn_cast<DeclRefExpr>(Ref->IgnoreParenImpCasts());
12988 if (!DRE)
12989 continue;
12990 NeedToCheckForLPCs.insert(DRE->getDecl());
12991 }
12992 }
12993 for (const Decl *VD : NeedToCheckForLPCs) {
12994 for (const LastprivateConditionalData &Data :
12995 llvm::reverse(CGM.getOpenMPRuntime().LastprivateConditionalStack)) {
12996 if (Data.DeclToUniqueName.count(VD) > 0) {
12997 if (!Data.Disabled)
12998 NeedToAddForLPCsAsDisabled.insert(VD);
12999 break;
13000 }
13001 }
13002 }
13003}
13004
13005CGOpenMPRuntime::LastprivateConditionalRAII::LastprivateConditionalRAII(
13006 CodeGenFunction &CGF, const OMPExecutableDirective &S, LValue IVLVal)
13007 : CGM(CGF.CGM),
13008 Action((CGM.getLangOpts().OpenMP >= 50 &&
13009 llvm::any_of(S.getClausesOfKind<OMPLastprivateClause>(),
13010 [](const OMPLastprivateClause *C) {
13011 return C->getKind() ==
13012 OMPC_LASTPRIVATE_conditional;
13013 }))
13014 ? ActionToDo::PushAsLastprivateConditional
13015 : ActionToDo::DoNotPush) {
13016 assert(CGM.getLangOpts().OpenMP && "Not in OpenMP mode.");
13017 if (CGM.getLangOpts().OpenMP < 50 || Action == ActionToDo::DoNotPush)
13018 return;
13019 assert(Action == ActionToDo::PushAsLastprivateConditional &&
13020 "Expected a push action.");
13022 CGM.getOpenMPRuntime().LastprivateConditionalStack.emplace_back();
13023 for (const auto *C : S.getClausesOfKind<OMPLastprivateClause>()) {
13024 if (C->getKind() != OMPC_LASTPRIVATE_conditional)
13025 continue;
13026
13027 for (const Expr *Ref : C->varlist()) {
13028 Data.DeclToUniqueName.insert(std::make_pair(
13029 cast<DeclRefExpr>(Ref->IgnoreParenImpCasts())->getDecl(),
13030 SmallString<16>(generateUniqueName(CGM, "pl_cond", Ref))));
13031 }
13032 }
13033 Data.IVLVal = IVLVal;
13034 Data.Fn = CGF.CurFn;
13035}
13036
13037CGOpenMPRuntime::LastprivateConditionalRAII::LastprivateConditionalRAII(
13039 : CGM(CGF.CGM), Action(ActionToDo::DoNotPush) {
13040 assert(CGM.getLangOpts().OpenMP && "Not in OpenMP mode.");
13041 if (CGM.getLangOpts().OpenMP < 50)
13042 return;
13043 llvm::DenseSet<CanonicalDeclPtr<const Decl>> NeedToAddForLPCsAsDisabled;
13044 tryToDisableInnerAnalysis(S, NeedToAddForLPCsAsDisabled);
13045 if (!NeedToAddForLPCsAsDisabled.empty()) {
13046 Action = ActionToDo::DisableLastprivateConditional;
13047 LastprivateConditionalData &Data =
13049 for (const Decl *VD : NeedToAddForLPCsAsDisabled)
13050 Data.DeclToUniqueName.try_emplace(VD);
13051 Data.Fn = CGF.CurFn;
13052 Data.Disabled = true;
13053 }
13054}
13055
13056CGOpenMPRuntime::LastprivateConditionalRAII
13058 CodeGenFunction &CGF, const OMPExecutableDirective &S) {
13059 return LastprivateConditionalRAII(CGF, S);
13060}
13061
13063 if (CGM.getLangOpts().OpenMP < 50)
13064 return;
13065 if (Action == ActionToDo::DisableLastprivateConditional) {
13066 assert(CGM.getOpenMPRuntime().LastprivateConditionalStack.back().Disabled &&
13067 "Expected list of disabled private vars.");
13068 CGM.getOpenMPRuntime().LastprivateConditionalStack.pop_back();
13069 }
13070 if (Action == ActionToDo::PushAsLastprivateConditional) {
13071 assert(
13072 !CGM.getOpenMPRuntime().LastprivateConditionalStack.back().Disabled &&
13073 "Expected list of lastprivate conditional vars.");
13074 CGM.getOpenMPRuntime().LastprivateConditionalStack.pop_back();
13075 }
13076}
13077
13079 const VarDecl *VD) {
13080 ASTContext &C = CGM.getContext();
13081 auto I = LastprivateConditionalToTypes.try_emplace(CGF.CurFn).first;
13082 QualType NewType;
13083 const FieldDecl *VDField;
13084 const FieldDecl *FiredField;
13085 LValue BaseLVal;
13086 auto VI = I->getSecond().find(VD);
13087 if (VI == I->getSecond().end()) {
13088 RecordDecl *RD = C.buildImplicitRecord("lasprivate.conditional");
13089 RD->startDefinition();
13090 VDField = addFieldToRecordDecl(C, RD, VD->getType().getNonReferenceType());
13091 FiredField = addFieldToRecordDecl(C, RD, C.CharTy);
13092 RD->completeDefinition();
13093 NewType = C.getCanonicalTagType(RD);
13094 Address Addr = CGF.CreateMemTemp(NewType, C.getDeclAlign(VD), VD->getName());
13095 BaseLVal = CGF.MakeAddrLValue(Addr, NewType, AlignmentSource::Decl);
13096 I->getSecond().try_emplace(VD, NewType, VDField, FiredField, BaseLVal);
13097 } else {
13098 NewType = std::get<0>(VI->getSecond());
13099 VDField = std::get<1>(VI->getSecond());
13100 FiredField = std::get<2>(VI->getSecond());
13101 BaseLVal = std::get<3>(VI->getSecond());
13102 }
13103 LValue FiredLVal =
13104 CGF.EmitLValueForField(BaseLVal, FiredField);
13106 llvm::ConstantInt::getNullValue(CGF.ConvertTypeForMem(C.CharTy)),
13107 FiredLVal);
13108 return CGF.EmitLValueForField(BaseLVal, VDField).getAddress();
13109}
13110
13111namespace {
13112/// Checks if the lastprivate conditional variable is referenced in LHS.
13113class LastprivateConditionalRefChecker final
13114 : public ConstStmtVisitor<LastprivateConditionalRefChecker, bool> {
13116 const Expr *FoundE = nullptr;
13117 const Decl *FoundD = nullptr;
13118 StringRef UniqueDeclName;
13119 LValue IVLVal;
13120 llvm::Function *FoundFn = nullptr;
13121 SourceLocation Loc;
13122
13123public:
13124 bool VisitDeclRefExpr(const DeclRefExpr *E) {
13126 llvm::reverse(LPM)) {
13127 auto It = D.DeclToUniqueName.find(E->getDecl());
13128 if (It == D.DeclToUniqueName.end())
13129 continue;
13130 if (D.Disabled)
13131 return false;
13132 FoundE = E;
13133 FoundD = E->getDecl()->getCanonicalDecl();
13134 UniqueDeclName = It->second;
13135 IVLVal = D.IVLVal;
13136 FoundFn = D.Fn;
13137 break;
13138 }
13139 return FoundE == E;
13140 }
13141 bool VisitMemberExpr(const MemberExpr *E) {
13143 return false;
13145 llvm::reverse(LPM)) {
13146 auto It = D.DeclToUniqueName.find(E->getMemberDecl());
13147 if (It == D.DeclToUniqueName.end())
13148 continue;
13149 if (D.Disabled)
13150 return false;
13151 FoundE = E;
13152 FoundD = E->getMemberDecl()->getCanonicalDecl();
13153 UniqueDeclName = It->second;
13154 IVLVal = D.IVLVal;
13155 FoundFn = D.Fn;
13156 break;
13157 }
13158 return FoundE == E;
13159 }
13160 bool VisitStmt(const Stmt *S) {
13161 for (const Stmt *Child : S->children()) {
13162 if (!Child)
13163 continue;
13164 if (const auto *E = dyn_cast<Expr>(Child))
13165 if (!E->isGLValue())
13166 continue;
13167 if (Visit(Child))
13168 return true;
13169 }
13170 return false;
13171 }
13172 explicit LastprivateConditionalRefChecker(
13173 ArrayRef<CGOpenMPRuntime::LastprivateConditionalData> LPM)
13174 : LPM(LPM) {}
13175 std::tuple<const Expr *, const Decl *, StringRef, LValue, llvm::Function *>
13176 getFoundData() const {
13177 return std::make_tuple(FoundE, FoundD, UniqueDeclName, IVLVal, FoundFn);
13178 }
13179};
13180} // namespace
13181
13183 LValue IVLVal,
13184 StringRef UniqueDeclName,
13185 LValue LVal,
13186 SourceLocation Loc) {
13187 // Last updated loop counter for the lastprivate conditional var.
13188 // int<xx> last_iv = 0;
13189 llvm::Type *LLIVTy = CGF.ConvertTypeForMem(IVLVal.getType());
13190 llvm::Constant *LastIV = OMPBuilder.getOrCreateInternalVariable(
13191 LLIVTy, getName({UniqueDeclName, "iv"}));
13192 cast<llvm::GlobalVariable>(LastIV)->setAlignment(
13193 IVLVal.getAlignment().getAsAlign());
13194 LValue LastIVLVal =
13195 CGF.MakeNaturalAlignRawAddrLValue(LastIV, IVLVal.getType());
13196
13197 // Last value of the lastprivate conditional.
13198 // decltype(priv_a) last_a;
13199 llvm::GlobalVariable *Last = OMPBuilder.getOrCreateInternalVariable(
13200 CGF.ConvertTypeForMem(LVal.getType()), UniqueDeclName);
13201 cast<llvm::GlobalVariable>(Last)->setAlignment(
13202 LVal.getAlignment().getAsAlign());
13203 LValue LastLVal =
13204 CGF.MakeRawAddrLValue(Last, LVal.getType(), LVal.getAlignment());
13205
13206 // Global loop counter. Required to handle inner parallel-for regions.
13207 // iv
13208 llvm::Value *IVVal = CGF.EmitLoadOfScalar(IVLVal, Loc);
13209
13210 // #pragma omp critical(a)
13211 // if (last_iv <= iv) {
13212 // last_iv = iv;
13213 // last_a = priv_a;
13214 // }
13215 auto &&CodeGen = [&LastIVLVal, &IVLVal, IVVal, &LVal, &LastLVal,
13216 Loc](CodeGenFunction &CGF, PrePostActionTy &Action) {
13217 Action.Enter(CGF);
13218 llvm::Value *LastIVVal = CGF.EmitLoadOfScalar(LastIVLVal, Loc);
13219 // (last_iv <= iv) ? Check if the variable is updated and store new
13220 // value in global var.
13221 llvm::Value *CmpRes;
13222 if (IVLVal.getType()->isSignedIntegerType()) {
13223 CmpRes = CGF.Builder.CreateICmpSLE(LastIVVal, IVVal);
13224 } else {
13225 assert(IVLVal.getType()->isUnsignedIntegerType() &&
13226 "Loop iteration variable must be integer.");
13227 CmpRes = CGF.Builder.CreateICmpULE(LastIVVal, IVVal);
13228 }
13229 llvm::BasicBlock *ThenBB = CGF.createBasicBlock("lp_cond_then");
13230 llvm::BasicBlock *ExitBB = CGF.createBasicBlock("lp_cond_exit");
13231 CGF.Builder.CreateCondBr(CmpRes, ThenBB, ExitBB);
13232 // {
13233 CGF.EmitBlock(ThenBB);
13234
13235 // last_iv = iv;
13236 CGF.EmitStoreOfScalar(IVVal, LastIVLVal);
13237
13238 // last_a = priv_a;
13239 switch (CGF.getEvaluationKind(LVal.getType())) {
13240 case TEK_Scalar: {
13241 llvm::Value *PrivVal = CGF.EmitLoadOfScalar(LVal, Loc);
13242 CGF.EmitStoreOfScalar(PrivVal, LastLVal);
13243 break;
13244 }
13245 case TEK_Complex: {
13246 CodeGenFunction::ComplexPairTy PrivVal = CGF.EmitLoadOfComplex(LVal, Loc);
13247 CGF.EmitStoreOfComplex(PrivVal, LastLVal, /*isInit=*/false);
13248 break;
13249 }
13250 case TEK_Aggregate:
13251 llvm_unreachable(
13252 "Aggregates are not supported in lastprivate conditional.");
13253 }
13254 // }
13255 CGF.EmitBranch(ExitBB);
13256 // There is no need to emit line number for unconditional branch.
13258 CGF.EmitBlock(ExitBB, /*IsFinished=*/true);
13259 };
13260
13261 if (CGM.getLangOpts().OpenMPSimd) {
13262 // Do not emit as a critical region as no parallel region could be emitted.
13263 RegionCodeGenTy ThenRCG(CodeGen);
13264 ThenRCG(CGF);
13265 } else {
13266 emitCriticalRegion(CGF, UniqueDeclName, CodeGen, Loc);
13267 }
13268}
13269
13271 const Expr *LHS) {
13272 if (CGF.getLangOpts().OpenMP < 50 || LastprivateConditionalStack.empty())
13273 return;
13274 LastprivateConditionalRefChecker Checker(LastprivateConditionalStack);
13275 if (!Checker.Visit(LHS))
13276 return;
13277 const Expr *FoundE;
13278 const Decl *FoundD;
13279 StringRef UniqueDeclName;
13280 LValue IVLVal;
13281 llvm::Function *FoundFn;
13282 std::tie(FoundE, FoundD, UniqueDeclName, IVLVal, FoundFn) =
13283 Checker.getFoundData();
13284 if (FoundFn != CGF.CurFn) {
13285 // Special codegen for inner parallel regions.
13286 // ((struct.lastprivate.conditional*)&priv_a)->Fired = 1;
13287 auto It = LastprivateConditionalToTypes[FoundFn].find(FoundD);
13288 assert(It != LastprivateConditionalToTypes[FoundFn].end() &&
13289 "Lastprivate conditional is not found in outer region.");
13290 QualType StructTy = std::get<0>(It->getSecond());
13291 const FieldDecl* FiredDecl = std::get<2>(It->getSecond());
13292 LValue PrivLVal = CGF.EmitLValue(FoundE);
13294 PrivLVal.getAddress(),
13295 CGF.ConvertTypeForMem(CGF.getContext().getPointerType(StructTy)),
13296 CGF.ConvertTypeForMem(StructTy));
13297 LValue BaseLVal =
13298 CGF.MakeAddrLValue(StructAddr, StructTy, AlignmentSource::Decl);
13299 LValue FiredLVal = CGF.EmitLValueForField(BaseLVal, FiredDecl);
13300 CGF.EmitAtomicStore(RValue::get(llvm::ConstantInt::get(
13301 CGF.ConvertTypeForMem(FiredDecl->getType()), 1)),
13302 FiredLVal, llvm::AtomicOrdering::Unordered,
13303 /*IsVolatile=*/true, /*isInit=*/false);
13304 return;
13305 }
13306
13307 // Private address of the lastprivate conditional in the current context.
13308 // priv_a
13309 LValue LVal = CGF.EmitLValue(FoundE);
13310 emitLastprivateConditionalUpdate(CGF, IVLVal, UniqueDeclName, LVal,
13311 FoundE->getExprLoc());
13312}
13313
13316 const llvm::DenseSet<CanonicalDeclPtr<const VarDecl>> &IgnoredDecls) {
13317 if (CGF.getLangOpts().OpenMP < 50 || LastprivateConditionalStack.empty())
13318 return;
13319 auto Range = llvm::reverse(LastprivateConditionalStack);
13320 auto It = llvm::find_if(
13321 Range, [](const LastprivateConditionalData &D) { return !D.Disabled; });
13322 if (It == Range.end() || It->Fn != CGF.CurFn)
13323 return;
13324 auto LPCI = LastprivateConditionalToTypes.find(It->Fn);
13325 assert(LPCI != LastprivateConditionalToTypes.end() &&
13326 "Lastprivates must be registered already.");
13328 getOpenMPCaptureRegions(CaptureRegions, D.getDirectiveKind());
13329 const CapturedStmt *CS = D.getCapturedStmt(CaptureRegions.back());
13330 for (const auto &Pair : It->DeclToUniqueName) {
13331 const auto *VD = cast<VarDecl>(Pair.first->getCanonicalDecl());
13332 if (!CS->capturesVariable(VD) || IgnoredDecls.contains(VD))
13333 continue;
13334 auto I = LPCI->getSecond().find(Pair.first);
13335 assert(I != LPCI->getSecond().end() &&
13336 "Lastprivate must be rehistered already.");
13337 // bool Cmp = priv_a.Fired != 0;
13338 LValue BaseLVal = std::get<3>(I->getSecond());
13339 LValue FiredLVal =
13340 CGF.EmitLValueForField(BaseLVal, std::get<2>(I->getSecond()));
13341 llvm::Value *Res = CGF.EmitLoadOfScalar(FiredLVal, D.getBeginLoc());
13342 llvm::Value *Cmp = CGF.Builder.CreateIsNotNull(Res);
13343 llvm::BasicBlock *ThenBB = CGF.createBasicBlock("lpc.then");
13344 llvm::BasicBlock *DoneBB = CGF.createBasicBlock("lpc.done");
13345 // if (Cmp) {
13346 CGF.Builder.CreateCondBr(Cmp, ThenBB, DoneBB);
13347 CGF.EmitBlock(ThenBB);
13348 Address Addr = CGF.GetAddrOfLocalVar(VD);
13349 LValue LVal;
13350 if (VD->getType()->isReferenceType())
13351 LVal = CGF.EmitLoadOfReferenceLValue(Addr, VD->getType(),
13353 else
13354 LVal = CGF.MakeAddrLValue(Addr, VD->getType().getNonReferenceType(),
13356 emitLastprivateConditionalUpdate(CGF, It->IVLVal, Pair.second, LVal,
13357 D.getBeginLoc());
13359 CGF.EmitBlock(DoneBB, /*IsFinal=*/true);
13360 // }
13361 }
13362}
13363
13365 CodeGenFunction &CGF, LValue PrivLVal, const VarDecl *VD,
13366 SourceLocation Loc) {
13367 if (CGF.getLangOpts().OpenMP < 50)
13368 return;
13369 auto It = LastprivateConditionalStack.back().DeclToUniqueName.find(VD);
13370 assert(It != LastprivateConditionalStack.back().DeclToUniqueName.end() &&
13371 "Unknown lastprivate conditional variable.");
13372 StringRef UniqueName = It->second;
13373 llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(UniqueName);
13374 // The variable was not updated in the region - exit.
13375 if (!GV)
13376 return;
13377 LValue LPLVal = CGF.MakeRawAddrLValue(
13378 GV, PrivLVal.getType().getNonReferenceType(), PrivLVal.getAlignment());
13379 llvm::Value *Res = CGF.EmitLoadOfScalar(LPLVal, Loc);
13380 CGF.EmitStoreOfScalar(Res, PrivLVal);
13381}
13382
13385 const VarDecl *ThreadIDVar, OpenMPDirectiveKind InnermostKind,
13386 const RegionCodeGenTy &CodeGen) {
13387 llvm_unreachable("Not supported in SIMD-only mode");
13388}
13389
13392 const VarDecl *ThreadIDVar, OpenMPDirectiveKind InnermostKind,
13393 const RegionCodeGenTy &CodeGen) {
13394 llvm_unreachable("Not supported in SIMD-only mode");
13395}
13396
13398 const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
13399 const VarDecl *PartIDVar, const VarDecl *TaskTVar,
13400 OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen,
13401 bool Tied, unsigned &NumberOfParts) {
13402 llvm_unreachable("Not supported in SIMD-only mode");
13403}
13404
13406 CodeGenFunction &CGF, SourceLocation Loc, llvm::Function *OutlinedFn,
13407 ArrayRef<llvm::Value *> CapturedVars, const Expr *IfCond,
13408 llvm::Value *NumThreads, OpenMPNumThreadsClauseModifier NumThreadsModifier,
13409 OpenMPSeverityClauseKind Severity, const Expr *Message) {
13410 llvm_unreachable("Not supported in SIMD-only mode");
13411}
13412
13414 CodeGenFunction &CGF, StringRef CriticalName,
13415 const RegionCodeGenTy &CriticalOpGen, SourceLocation Loc,
13416 const Expr *Hint) {
13417 llvm_unreachable("Not supported in SIMD-only mode");
13418}
13419
13421 const RegionCodeGenTy &MasterOpGen,
13422 SourceLocation Loc) {
13423 llvm_unreachable("Not supported in SIMD-only mode");
13424}
13425
13427 const RegionCodeGenTy &MasterOpGen,
13428 SourceLocation Loc,
13429 const Expr *Filter) {
13430 llvm_unreachable("Not supported in SIMD-only mode");
13431}
13432
13434 SourceLocation Loc) {
13435 llvm_unreachable("Not supported in SIMD-only mode");
13436}
13437
13439 CodeGenFunction &CGF, const RegionCodeGenTy &TaskgroupOpGen,
13440 SourceLocation Loc) {
13441 llvm_unreachable("Not supported in SIMD-only mode");
13442}
13443
13445 CodeGenFunction &CGF, const RegionCodeGenTy &SingleOpGen,
13446 SourceLocation Loc, ArrayRef<const Expr *> CopyprivateVars,
13448 ArrayRef<const Expr *> AssignmentOps) {
13449 llvm_unreachable("Not supported in SIMD-only mode");
13450}
13451
13453 const RegionCodeGenTy &OrderedOpGen,
13454 SourceLocation Loc,
13455 bool IsThreads) {
13456 llvm_unreachable("Not supported in SIMD-only mode");
13457}
13458
13460 SourceLocation Loc,
13462 bool EmitChecks,
13463 bool ForceSimpleCall) {
13464 llvm_unreachable("Not supported in SIMD-only mode");
13465}
13466
13469 const OpenMPScheduleTy &ScheduleKind, unsigned IVSize, bool IVSigned,
13470 bool Ordered, const DispatchRTInput &DispatchValues) {
13471 llvm_unreachable("Not supported in SIMD-only mode");
13472}
13473
13475 SourceLocation Loc) {
13476 llvm_unreachable("Not supported in SIMD-only mode");
13477}
13478
13481 const OpenMPScheduleTy &ScheduleKind, const StaticRTInput &Values) {
13482 llvm_unreachable("Not supported in SIMD-only mode");
13483}
13484
13487 OpenMPDistScheduleClauseKind SchedKind, const StaticRTInput &Values) {
13488 llvm_unreachable("Not supported in SIMD-only mode");
13489}
13490
13492 SourceLocation Loc,
13493 unsigned IVSize,
13494 bool IVSigned) {
13495 llvm_unreachable("Not supported in SIMD-only mode");
13496}
13497
13499 SourceLocation Loc,
13500 OpenMPDirectiveKind DKind) {
13501 llvm_unreachable("Not supported in SIMD-only mode");
13502}
13503
13505 SourceLocation Loc,
13506 unsigned IVSize, bool IVSigned,
13507 Address IL, Address LB,
13508 Address UB, Address ST) {
13509 llvm_unreachable("Not supported in SIMD-only mode");
13510}
13511
13513 CodeGenFunction &CGF, llvm::Value *NumThreads, SourceLocation Loc,
13515 SourceLocation SeverityLoc, const Expr *Message,
13516 SourceLocation MessageLoc) {
13517 llvm_unreachable("Not supported in SIMD-only mode");
13518}
13519
13521 ProcBindKind ProcBind,
13522 SourceLocation Loc) {
13523 llvm_unreachable("Not supported in SIMD-only mode");
13524}
13525
13527 const VarDecl *VD,
13528 Address VDAddr,
13529 SourceLocation Loc) {
13530 llvm_unreachable("Not supported in SIMD-only mode");
13531}
13532
13534 const VarDecl *VD, Address VDAddr, SourceLocation Loc, bool PerformInit,
13535 CodeGenFunction *CGF) {
13536 llvm_unreachable("Not supported in SIMD-only mode");
13537}
13538
13540 CodeGenFunction &CGF, QualType VarType, StringRef Name) {
13541 llvm_unreachable("Not supported in SIMD-only mode");
13542}
13543
13546 SourceLocation Loc,
13547 llvm::AtomicOrdering AO) {
13548 llvm_unreachable("Not supported in SIMD-only mode");
13549}
13550
13552 const OMPExecutableDirective &D,
13553 llvm::Function *TaskFunction,
13554 QualType SharedsTy, Address Shareds,
13555 const Expr *IfCond,
13556 const OMPTaskDataTy &Data) {
13557 llvm_unreachable("Not supported in SIMD-only mode");
13558}
13559
13562 llvm::Function *TaskFunction, QualType SharedsTy, Address Shareds,
13563 const Expr *IfCond, const OMPTaskDataTy &Data) {
13564 llvm_unreachable("Not supported in SIMD-only mode");
13565}
13566
13570 ArrayRef<const Expr *> ReductionOps, ReductionOptionsTy Options) {
13571 assert(Options.SimpleReduction && "Only simple reduction is expected.");
13572 CGOpenMPRuntime::emitReduction(CGF, Loc, Privates, LHSExprs, RHSExprs,
13573 ReductionOps, Options);
13574}
13575
13578 ArrayRef<const Expr *> RHSExprs, const OMPTaskDataTy &Data) {
13579 llvm_unreachable("Not supported in SIMD-only mode");
13580}
13581
13583 SourceLocation Loc,
13584 bool IsWorksharingReduction) {
13585 llvm_unreachable("Not supported in SIMD-only mode");
13586}
13587
13589 SourceLocation Loc,
13590 ReductionCodeGen &RCG,
13591 unsigned N) {
13592 llvm_unreachable("Not supported in SIMD-only mode");
13593}
13594
13596 SourceLocation Loc,
13597 llvm::Value *ReductionsPtr,
13598 LValue SharedLVal) {
13599 llvm_unreachable("Not supported in SIMD-only mode");
13600}
13601
13603 SourceLocation Loc,
13604 const OMPTaskDataTy &Data) {
13605 llvm_unreachable("Not supported in SIMD-only mode");
13606}
13607
13610 OpenMPDirectiveKind CancelRegion) {
13611 llvm_unreachable("Not supported in SIMD-only mode");
13612}
13613
13615 SourceLocation Loc, const Expr *IfCond,
13616 OpenMPDirectiveKind CancelRegion) {
13617 llvm_unreachable("Not supported in SIMD-only mode");
13618}
13619
13621 const OMPExecutableDirective &D, StringRef ParentName,
13622 llvm::Function *&OutlinedFn, llvm::Constant *&OutlinedFnID,
13623 bool IsOffloadEntry, const RegionCodeGenTy &CodeGen) {
13624 llvm_unreachable("Not supported in SIMD-only mode");
13625}
13626
13629 llvm::Function *OutlinedFn, llvm::Value *OutlinedFnID, const Expr *IfCond,
13630 llvm::PointerIntPair<const Expr *, 2, OpenMPDeviceClauseModifier> Device,
13631 llvm::function_ref<llvm::Value *(CodeGenFunction &CGF,
13632 const OMPLoopDirective &D)>
13633 SizeEmitter) {
13634 llvm_unreachable("Not supported in SIMD-only mode");
13635}
13636
13638 llvm_unreachable("Not supported in SIMD-only mode");
13639}
13640
13642 llvm_unreachable("Not supported in SIMD-only mode");
13643}
13644
13646 return false;
13647}
13648
13650 const OMPExecutableDirective &D,
13651 SourceLocation Loc,
13652 llvm::Function *OutlinedFn,
13653 ArrayRef<llvm::Value *> CapturedVars) {
13654 llvm_unreachable("Not supported in SIMD-only mode");
13655}
13656
13658 const Expr *NumTeams,
13659 const Expr *ThreadLimit,
13660 SourceLocation Loc) {
13661 llvm_unreachable("Not supported in SIMD-only mode");
13662}
13663
13665 CodeGenFunction &CGF, const OMPExecutableDirective &D, const Expr *IfCond,
13666 const Expr *Device, const RegionCodeGenTy &CodeGen,
13668 llvm_unreachable("Not supported in SIMD-only mode");
13669}
13670
13672 CodeGenFunction &CGF, const OMPExecutableDirective &D, const Expr *IfCond,
13673 const Expr *Device) {
13674 llvm_unreachable("Not supported in SIMD-only mode");
13675}
13676
13678 const OMPLoopDirective &D,
13679 ArrayRef<Expr *> NumIterations) {
13680 llvm_unreachable("Not supported in SIMD-only mode");
13681}
13682
13684 const OMPDependClause *C) {
13685 llvm_unreachable("Not supported in SIMD-only mode");
13686}
13687
13689 const OMPDoacrossClause *C) {
13690 llvm_unreachable("Not supported in SIMD-only mode");
13691}
13692
13693const VarDecl *
13695 const VarDecl *NativeParam) const {
13696 llvm_unreachable("Not supported in SIMD-only mode");
13697}
13698
13699Address
13701 const VarDecl *NativeParam,
13702 const VarDecl *TargetParam) const {
13703 llvm_unreachable("Not supported in SIMD-only mode");
13704}
#define V(N, I)
static llvm::Value * emitCopyprivateCopyFunction(CodeGenModule &CGM, llvm::Type *ArgsElemType, ArrayRef< const Expr * > CopyprivateVars, ArrayRef< const Expr * > DestExprs, ArrayRef< const Expr * > SrcExprs, ArrayRef< const Expr * > AssignmentOps, SourceLocation Loc)
static StringRef getIdentStringFromSourceLocation(CodeGenFunction &CGF, SourceLocation Loc, SmallString< 128 > &Buffer)
static void emitOffloadingArraysAndArgs(CodeGenFunction &CGF, MappableExprsHandler::MapCombinedInfoTy &CombinedInfo, CGOpenMPRuntime::TargetDataInfo &Info, llvm::OpenMPIRBuilder &OMPBuilder, bool IsNonContiguous=false, bool ForEndCall=false)
Emit the arrays used to pass the captures and map information to the offloading runtime library.
static RecordDecl * createKmpTaskTWithPrivatesRecordDecl(CodeGenModule &CGM, QualType KmpTaskTQTy, ArrayRef< PrivateDataTy > Privates)
static void emitInitWithReductionInitializer(CodeGenFunction &CGF, const OMPDeclareReductionDecl *DRD, const Expr *InitOp, Address Private, Address Original, QualType Ty)
static Address castToBase(CodeGenFunction &CGF, QualType BaseTy, QualType ElTy, Address OriginalBaseAddress, llvm::Value *Addr)
static void emitPrivatesInit(CodeGenFunction &CGF, const OMPExecutableDirective &D, Address KmpTaskSharedsPtr, LValue TDBase, const RecordDecl *KmpTaskTWithPrivatesQTyRD, QualType SharedsTy, QualType SharedsPtrTy, const OMPTaskDataTy &Data, ArrayRef< PrivateDataTy > Privates, bool ForDup)
Emit initialization for private variables in task-based directives.
static void emitClauseForBareTargetDirective(CodeGenFunction &CGF, const OMPExecutableDirective &D, llvm::SmallVectorImpl< llvm::Value * > &Values)
static llvm::Value * emitDestructorsFunction(CodeGenModule &CGM, SourceLocation Loc, QualType KmpInt32Ty, QualType KmpTaskTWithPrivatesPtrQTy, QualType KmpTaskTWithPrivatesQTy)
static void EmitOMPAggregateReduction(CodeGenFunction &CGF, QualType Type, const VarDecl *LHSVar, const VarDecl *RHSVar, const llvm::function_ref< void(CodeGenFunction &CGF, const Expr *, const Expr *, const Expr *)> &RedOpGen, const Expr *XExpr=nullptr, const Expr *EExpr=nullptr, const Expr *UpExpr=nullptr)
Emit reduction operation for each element of array (required for array sections) LHS op = RHS.
static void emitTargetCallFallback(CGOpenMPRuntime *OMPRuntime, llvm::Function *OutlinedFn, const OMPExecutableDirective &D, llvm::SmallVectorImpl< llvm::Value * > &CapturedVars, bool RequiresOuterTask, const CapturedStmt &CS, bool OffloadingMandatory, CodeGenFunction &CGF)
static llvm::Value * emitReduceInitFunction(CodeGenModule &CGM, SourceLocation Loc, ReductionCodeGen &RCG, unsigned N)
Emits reduction initializer function:
static RTCancelKind getCancellationKind(OpenMPDirectiveKind CancelRegion)
static void emitDependData(CodeGenFunction &CGF, QualType &KmpDependInfoTy, llvm::PointerUnion< unsigned *, LValue * > Pos, const OMPTaskDataTy::DependData &Data, Address DependenciesArray)
static llvm::Value * emitTaskPrivateMappingFunction(CodeGenModule &CGM, SourceLocation Loc, const OMPTaskDataTy &Data, QualType PrivatesQTy, ArrayRef< PrivateDataTy > Privates)
Emit a privates mapping function for correct handling of private and firstprivate variables.
static llvm::Value * emitReduceCombFunction(CodeGenModule &CGM, SourceLocation Loc, ReductionCodeGen &RCG, unsigned N, const Expr *ReductionOp, const Expr *LHS, const Expr *RHS, const Expr *PrivateRef)
Emits reduction combiner function:
static RecordDecl * createPrivatesRecordDecl(CodeGenModule &CGM, ArrayRef< PrivateDataTy > Privates)
static llvm::Value * getAllocatorVal(CodeGenFunction &CGF, const Expr *Allocator)
Return allocator value from expression, or return a null allocator (default when no allocator specifi...
static llvm::Function * emitProxyTaskFunction(CodeGenModule &CGM, SourceLocation Loc, OpenMPDirectiveKind Kind, QualType KmpInt32Ty, QualType KmpTaskTWithPrivatesPtrQTy, QualType KmpTaskTWithPrivatesQTy, QualType KmpTaskTQTy, QualType SharedsPtrTy, llvm::Function *TaskFunction, llvm::Value *TaskPrivatesMap)
Emit a proxy function which accepts kmp_task_t as the second argument.
static bool isAllocatableDecl(const VarDecl *VD)
static llvm::Value * getAlignmentValue(CodeGenModule &CGM, const VarDecl *VD)
Return the alignment from an allocate directive if present.
static void emitTargetCallKernelLaunch(CGOpenMPRuntime *OMPRuntime, llvm::Function *OutlinedFn, const OMPExecutableDirective &D, llvm::SmallVectorImpl< llvm::Value * > &CapturedVars, bool RequiresOuterTask, const CapturedStmt &CS, bool OffloadingMandatory, llvm::PointerIntPair< const Expr *, 2, OpenMPDeviceClauseModifier > Device, llvm::Value *OutlinedFnID, CodeGenFunction::OMPTargetDataInfo &InputInfo, llvm::Value *&MapTypesArray, llvm::Value *&MapNamesArray, llvm::function_ref< llvm::Value *(CodeGenFunction &CGF, const OMPLoopDirective &D)> SizeEmitter, CodeGenFunction &CGF, CodeGenModule &CGM)
static const OMPExecutableDirective * getNestedDistributeDirective(ASTContext &Ctx, const OMPExecutableDirective &D)
Check for inner distribute directive.
static std::pair< llvm::Value *, llvm::Value * > getPointerAndSize(CodeGenFunction &CGF, const Expr *E)
static const VarDecl * getBaseDecl(const Expr *Ref, const DeclRefExpr *&DE)
static bool getAArch64MTV(QualType QT, llvm::OpenMPIRBuilder::DeclareSimdKindTy Kind)
Maps To Vector (MTV), as defined in 4.1.1 of the AAVFABI (2021Q1).
static bool isTrivial(ASTContext &Ctx, const Expr *E)
Checks if the expression is constant or does not have non-trivial function calls.
static OpenMPSchedType getRuntimeSchedule(OpenMPScheduleClauseKind ScheduleKind, bool Chunked, bool Ordered)
Map the OpenMP loop schedule to the runtime enumeration.
static void getNumThreads(CodeGenFunction &CGF, const CapturedStmt *CS, const Expr **E, int32_t &UpperBound, bool UpperBoundOnly, llvm::Value **CondVal)
Check for a num threads constant value (stored in DefaultVal), or expression (stored in E).
static llvm::Value * emitDeviceID(llvm::PointerIntPair< const Expr *, 2, OpenMPDeviceClauseModifier > Device, CodeGenFunction &CGF)
static const OMPDeclareReductionDecl * getReductionInit(const Expr *ReductionOp)
Check if the combiner is a call to UDR combiner and if it is so return the UDR decl used for reductio...
static bool checkInitIsRequired(CodeGenFunction &CGF, ArrayRef< PrivateDataTy > Privates)
Check if duplication function is required for taskloops.
static bool validateAArch64Simdlen(CodeGenModule &CGM, SourceLocation SLoc, unsigned UserVLEN, unsigned WDS, char ISA)
static bool checkDestructorsRequired(const RecordDecl *KmpTaskTWithPrivatesQTyRD, ArrayRef< PrivateDataTy > Privates)
Checks if destructor function is required to be generated.
static llvm::TargetRegionEntryInfo getEntryInfoFromPresumedLoc(CodeGenModule &CGM, llvm::OpenMPIRBuilder &OMPBuilder, SourceLocation BeginLoc, llvm::StringRef ParentName="")
static void genMapInfo(MappableExprsHandler &MEHandler, CodeGenFunction &CGF, MappableExprsHandler::MapCombinedInfoTy &CombinedInfo, llvm::OpenMPIRBuilder &OMPBuilder, const llvm::DenseSet< CanonicalDeclPtr< const Decl > > &SkippedVarSet=llvm::DenseSet< CanonicalDeclPtr< const Decl > >())
static unsigned getAArch64LS(QualType QT, llvm::OpenMPIRBuilder::DeclareSimdKindTy Kind, ASTContext &C)
Computes the lane size (LS) of a return type or of an input parameter, as defined by LS(P) in 3....
static llvm::OpenMPIRBuilder::DeclareSimdBranch convertDeclareSimdBranch(OMPDeclareSimdDeclAttr::BranchStateTy State)
static void emitForStaticInitCall(CodeGenFunction &CGF, llvm::Value *UpdateLocation, llvm::Value *ThreadId, llvm::FunctionCallee ForStaticInitFunction, OpenMPSchedType Schedule, OpenMPScheduleClauseModifier M1, OpenMPScheduleClauseModifier M2, const CGOpenMPRuntime::StaticRTInput &Values)
static LValue loadToBegin(CodeGenFunction &CGF, QualType BaseTy, QualType ElTy, LValue BaseLV)
static void getKmpAffinityType(ASTContext &C, QualType &KmpTaskAffinityInfoTy)
Builds kmp_depend_info, if it is not built yet, and builds flags type.
static llvm::Constant * emitMappingInformation(CodeGenFunction &CGF, llvm::OpenMPIRBuilder &OMPBuilder, MappableExprsHandler::MappingExprInfo &MapExprs)
Emit a string constant containing the names of the values mapped to the offloading runtime library.
static void getDependTypes(ASTContext &C, QualType &KmpDependInfoTy, QualType &FlagsTy)
Builds kmp_depend_info, if it is not built yet, and builds flags type.
static llvm::Value * emitTaskDupFunction(CodeGenModule &CGM, SourceLocation Loc, const OMPExecutableDirective &D, QualType KmpTaskTWithPrivatesPtrQTy, const RecordDecl *KmpTaskTWithPrivatesQTyRD, const RecordDecl *KmpTaskTQTyRD, QualType SharedsTy, QualType SharedsPtrTy, const OMPTaskDataTy &Data, ArrayRef< PrivateDataTy > Privates, bool WithLastIter)
Emit task_dup function (for initialization of private/firstprivate/lastprivate vars and last_iter fla...
static std::pair< llvm::Value *, OMPDynGroupprivateFallbackType > emitDynCGroupMem(const OMPExecutableDirective &D, CodeGenFunction &CGF)
static llvm::OffloadEntriesInfoManager::OMPTargetDeviceClauseKind convertDeviceClause(const VarDecl *VD)
static llvm::Value * emitReduceFiniFunction(CodeGenModule &CGM, SourceLocation Loc, ReductionCodeGen &RCG, unsigned N)
Emits reduction finalizer function:
static void EmitOMPAggregateInit(CodeGenFunction &CGF, Address DestAddr, QualType Type, bool EmitDeclareReductionInit, const Expr *Init, const OMPDeclareReductionDecl *DRD, Address SrcAddr=Address::invalid())
Emit initialization of arrays of complex types.
static bool getAArch64PBV(QualType QT, ASTContext &C)
Pass By Value (PBV), as defined in 3.1.2 of the AAVFABI.
static void EmitDoacrossOrdered(CodeGenFunction &CGF, CodeGenModule &CGM, const T *C, llvm::Value *ULoc, llvm::Value *ThreadID)
static RTLDependenceKindTy translateDependencyKind(OpenMPDependClauseKind K)
Translates internal dependency kind into the runtime kind.
static void emitTargetCallElse(CGOpenMPRuntime *OMPRuntime, llvm::Function *OutlinedFn, const OMPExecutableDirective &D, llvm::SmallVectorImpl< llvm::Value * > &CapturedVars, bool RequiresOuterTask, const CapturedStmt &CS, bool OffloadingMandatory, CodeGenFunction &CGF)
static llvm::Function * emitCombinerOrInitializer(CodeGenModule &CGM, QualType Ty, const Expr *CombinerInitializer, const VarDecl *In, const VarDecl *Out, bool IsCombiner)
static void emitReductionCombiner(CodeGenFunction &CGF, const Expr *ReductionOp)
Emit reduction combiner.
static std::tuple< unsigned, unsigned, bool > getNDSWDS(const FunctionDecl *FD, ArrayRef< llvm::OpenMPIRBuilder::DeclareSimdAttrTy > ParamAttrs)
static std::string generateUniqueName(CodeGenModule &CGM, llvm::StringRef Prefix, const Expr *Ref)
static llvm::Function * emitParallelOrTeamsOutlinedFunction(CodeGenModule &CGM, const OMPExecutableDirective &D, const CapturedStmt *CS, const VarDecl *ThreadIDVar, OpenMPDirectiveKind InnermostKind, const StringRef OutlinedHelperName, const RegionCodeGenTy &CodeGen)
static Address emitAddrOfVarFromArray(CodeGenFunction &CGF, Address Array, unsigned Index, const VarDecl *Var)
Given an array of pointers to variables, project the address of a given variable.
static const VarDecl * getOriginalVarDecl(const ValueDecl *Decl)
For BindingDecls, returns the DecomposedDecl as the original VarDecl.
static void mergeThreadCountUpperBound(int32_t &UpperBound, int32_t Val)
Merge the thread count upper bound Val into UpperBound.
static FieldDecl * addFieldToRecordDecl(ASTContext &C, DeclContext *DC, QualType FieldTy)
static unsigned evaluateCDTSize(const FunctionDecl *FD, ArrayRef< llvm::OpenMPIRBuilder::DeclareSimdAttrTy > ParamAttrs)
static ValueDecl * getDeclFromThisExpr(const Expr *E)
static void genMapInfoForCaptures(MappableExprsHandler &MEHandler, CodeGenFunction &CGF, const CapturedStmt &CS, llvm::SmallVectorImpl< llvm::Value * > &CapturedVars, llvm::OpenMPIRBuilder &OMPBuilder, llvm::DenseSet< CanonicalDeclPtr< const Decl > > &MappedVarSet, MappableExprsHandler::MapCombinedInfoTy &CombinedInfo)
static RecordDecl * createKmpTaskTRecordDecl(CodeGenModule &CGM, OpenMPDirectiveKind Kind, QualType KmpInt32Ty, QualType KmpRoutineEntryPointerQTy)
static int addMonoNonMonoModifier(CodeGenModule &CGM, OpenMPSchedType Schedule, OpenMPScheduleClauseModifier M1, OpenMPScheduleClauseModifier M2)
static mlir::omp::DeclareTargetCaptureClause convertCaptureClause(OMPDeclareTargetDeclAttr::MapTypeTy mapTy)
static bool isAssumedToBeNotEmitted(const ValueDecl *vd, bool isDevice)
Returns true if the declaration should be skipped based on its device_type attribute and the current ...
Expr::Classification Cl
TokenType getType() const
Returns the token's type, e.g.
FormatToken * Next
The next token in the unwrapped line.
Result
Implement __builtin_bit_cast and related operations.
#define X(type, name)
Definition Value.h:97
This file defines OpenMP AST classes for clauses.
Defines some OpenMP-specific enums and functions.
llvm::json::Array Array
Defines the SourceManager interface.
This file defines OpenMP AST classes for executable directives and clauses.
__DEVICE__ int max(int __a, int __b)
This represents clause 'affinity' in the 'pragma omp task'-based directives.
static std::pair< const Expr *, std::optional< size_t > > findAttachPtrExpr(MappableExprComponentListRef Components, OpenMPDirectiveKind CurDirKind)
Find the attach pointer expression from a list of mappable expression components.
static QualType getComponentExprElementType(const Expr *Exp)
Get the type of an element of a ComponentList Expr Exp.
ArrayRef< MappableComponent > MappableExprComponentListRef
This represents implicit clause 'depend' for the 'pragma omp task' directive.
This represents 'detach' clause in the 'pragma omp task' directive.
This represents 'device' clause in the 'pragma omp ...' directive.
This represents the 'doacross' clause for the 'pragma omp ordered' directive.
This represents 'dyn_groupprivate' clause in 'pragma omp target ...' and 'pragma omp teams ....
This is a common base class for loop directives ('omp simd', 'omp for', 'omp for simd' etc....
Expr * getLowerBoundVariable() const
Expr * getUpperBoundVariable() const
Expr * getStrideVariable() const
This represents clause 'map' in the 'pragma omp ...' directives.
This represents clause 'nontemporal' in the 'pragma omp ...' directives.
This represents 'num_teams' clause in the 'pragma omp ...' directive.
This represents 'thread_limit' clause in the 'pragma omp ...' directive.
This represents clause 'uses_allocators' in the 'pragma omp target'-based directives.
This represents 'ompx_attribute' clause in a directive that might generate an outlined function.
This represents 'ompx_bare' clause in the 'pragma omp target teams ...' directive.
This represents 'ompx_dyn_cgroup_mem' clause in the 'pragma omp target ...' directive.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:239
SourceManager & getSourceManager()
Definition ASTContext.h:911
const ConstantArrayType * getAsConstantArrayType(QualType T) const
CharUnits getTypeAlignInChars(QualType T) const
Return the ABI-specified alignment of a (complete) type T, in characters.
const ASTRecordLayout & getASTRecordLayout(const RecordDecl *D) const
Get or compute information about the layout of the specified record (struct/union/class) D,...
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
CanQualType VoidPtrTy
QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize, const Expr *SizeExpr, ArraySizeModifier ASM, unsigned IndexTypeQuals) const
Return the unique reference to the type for a constant array of the specified element type.
const LangOptions & getLangOpts() const
CanQualType BoolTy
QualType getIntTypeForBitwidth(unsigned DestWidth, unsigned Signed) const
getIntTypeForBitwidth - sets integer QualTy according to specified details: bitwidth,...
CharUnits getDeclAlign(const Decl *D, bool ForAlignof=false) const
Return a conservative estimate of the alignment of the specified decl D.
int64_t toBits(CharUnits CharSize) const
Convert a size in characters to a size in bits.
const ArrayType * getAsArrayType(QualType T) const
Type Query functions.
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
static bool hasSameType(QualType T1, QualType T2)
Determine whether the given types T1 and T2 are equivalent.
const VariableArrayType * getAsVariableArrayType(QualType T) const
QualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
unsigned getTypeAlign(QualType T) const
Return the ABI-specified alignment of a (complete) type T, in bits.
CharUnits getSize() const
getSize - Get the record size in characters.
uint64_t getFieldOffset(unsigned FieldNo) const
getFieldOffset - Get the offset of the given field index, in bits.
CharUnits getNonVirtualSize() const
getNonVirtualSize - Get the non-virtual size (in chars) of an object, which is the size of the object...
static QualType getBaseOriginalType(const Expr *Base)
Return original type of the base expression for array section.
Definition Expr.cpp:5439
Represents an array type, per C99 6.7.5.2 - Array Declarators.
Definition TypeBase.h:3820
Attr - This represents one attribute.
Definition Attr.h:46
A binding in a decomposition declaration.
Definition DeclCXX.h:4215
Expr * getBinding() const
Get the expression to which this declaration is bound.
Definition DeclCXX.h:4241
DecompositionDecl * getDecomposedDecl() const
Get the decomposition declaration that this binding represents a decomposition of.
Definition DeclCXX.h:4248
Represents a base class of a C++ class.
Definition DeclCXX.h:146
Represents a C++ constructor within a class.
Definition DeclCXX.h:2642
Represents a C++ destructor within a class.
Definition DeclCXX.h:2907
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Definition DeclCXX.h:2293
QualType getFunctionObjectParameterType() const
Definition DeclCXX.h:2317
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
base_class_range bases()
Definition DeclCXX.h:609
bool isLambda() const
Determine whether this class describes a lambda function object.
Definition DeclCXX.h:1028
void getCaptureFields(llvm::DenseMap< const ValueDecl *, FieldDecl * > &Captures, FieldDecl *&ThisCapture) const
For a closure type, retrieve the mapping from captured variables and this to the non-static data memb...
Definition DeclCXX.cpp:1792
unsigned getNumBases() const
Retrieves the number of base classes of this class.
Definition DeclCXX.h:603
base_class_range vbases()
Definition DeclCXX.h:626
capture_const_range captures() const
Definition DeclCXX.h:1107
ctor_range ctors() const
Definition DeclCXX.h:671
CXXDestructorDecl * getDestructor() const
Returns the destructor decl for this class.
Definition DeclCXX.cpp:2129
CanProxy< U > castAs() const
A wrapper class around a pointer that always points to its canonical declaration.
Describes the capture of either a variable, or 'this', or variable-length array type.
Definition Stmt.h:3962
bool capturesVariableByCopy() const
Determine whether this capture handles a variable by copy.
Definition Stmt.h:3996
VarDecl * getCapturedVar() const
Retrieve the declaration of the variable being captured.
Definition Stmt.cpp:1391
bool capturesVariableArrayType() const
Determine whether this capture handles a variable-length array type.
Definition Stmt.h:4002
bool capturesThis() const
Determine whether this capture handles the C++ 'this' pointer.
Definition Stmt.h:3990
bool capturesVariable() const
Determine whether this capture handles a variable (by reference).
Definition Stmt.h:3993
This captures a statement into a function.
Definition Stmt.h:3949
const Capture * const_capture_iterator
Definition Stmt.h:4083
capture_iterator capture_end() const
Retrieve an iterator pointing past the end of the sequence of captures.
Definition Stmt.h:4100
const RecordDecl * getCapturedRecordDecl() const
Retrieve the record declaration for captured variables.
Definition Stmt.h:4070
Stmt * getCapturedStmt()
Retrieve the statement being captured.
Definition Stmt.h:4053
bool capturesVariable(const VarDecl *Var) const
True if this variable has been captured.
Definition Stmt.cpp:1517
capture_iterator capture_begin()
Retrieve an iterator pointing to the first capture.
Definition Stmt.h:4095
capture_range captures()
Definition Stmt.h:4087
This is an opaque type for sizes expressed in character units.
Definition CharUnits.h:38
bool isZero() const
Test whether the quantity equals zero.
Definition CharUnits.h:101
CharUnits alignTo(CharUnits Align) const
Returns the next integer (mod 2**64) that is greater than or equal to this quantity and is a multiple...
Definition CharUnits.h:171
llvm::Align getAsAlign() const
Returns Quantity as a valid llvm::Align, Beware llvm::Align assumes power of two 8-bit bytes.
Definition CharUnits.h:159
QuantityType getQuantity() const
Get the raw integer representation of this quantity.
Definition CharUnits.h:155
CharUnits alignmentOfArrayElement(CharUnits elementSize) const
Given that this is the alignment of the first element of an array, return the minimum alignment of an...
Definition CharUnits.h:184
static CharUnits fromQuantity(QuantityType Quantity)
Construct a CharUnits quantity from a raw integer type.
Definition CharUnits.h:58
std::string SampleProfileFile
Name of the profile file to use with -fprofile-sample-use.
Like RawAddress, an abstract representation of an aligned address, but the pointer contained in this ...
Definition Address.h:128
static Address invalid()
Definition Address.h:176
llvm::Value * emitRawPointer(CodeGenFunction &CGF) const
Return the pointer contained in this class after authenticating it and adding offset to it if necessa...
Definition Address.h:253
CharUnits getAlignment() const
Definition Address.h:194
llvm::Type * getElementType() const
Return the type of the values stored in this address.
Definition Address.h:209
Address withPointer(llvm::Value *NewPointer, KnownNonNull_t IsKnownNonNull) const
Return address with different pointer, but same element type and alignment.
Definition Address.h:261
Address withElementType(llvm::Type *ElemTy) const
Return address with different element type, but same pointer and alignment.
Definition Address.h:276
bool isValid() const
Definition Address.h:177
llvm::PointerType * getType() const
Return the type of the pointer value.
Definition Address.h:204
static ApplyDebugLocation CreateArtificial(CodeGenFunction &CGF)
Apply TemporaryLocation if it is valid.
static ApplyDebugLocation CreateDefaultArtificial(CodeGenFunction &CGF, SourceLocation TemporaryLocation)
Apply TemporaryLocation if it is valid.
static ApplyDebugLocation CreateEmpty(CodeGenFunction &CGF)
Set the IRBuilder to not attach debug locations.
llvm::StoreInst * CreateStore(llvm::Value *Val, Address Addr, bool IsVolatile=false)
Definition CGBuilder.h:148
Address CreateGEP(CodeGenFunction &CGF, Address Addr, llvm::Value *Index, const llvm::Twine &Name="")
Definition CGBuilder.h:304
Address CreatePointerBitCastOrAddrSpaceCast(Address Addr, llvm::Type *Ty, llvm::Type *ElementTy, const llvm::Twine &Name="")
Definition CGBuilder.h:215
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:253
llvm::LoadInst * CreateLoad(Address Addr, const llvm::Twine &Name="")
Definition CGBuilder.h:120
llvm::CallInst * CreateMemCpy(Address Dest, Address Src, llvm::Value *Size, bool IsVolatile=false)
Definition CGBuilder.h:399
Address CreateConstGEP(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:290
Address CreateAddrSpaceCast(Address Addr, llvm::Type *Ty, llvm::Type *ElementTy, const llvm::Twine &Name="")
Definition CGBuilder.h:201
CGFunctionInfo - Class to encapsulate the information about a function definition.
static LastprivateConditionalRAII disable(CodeGenFunction &CGF, const OMPExecutableDirective &S)
NontemporalDeclsRAII(CodeGenModule &CGM, const OMPLoopDirective &S)
Struct that keeps all the relevant information that should be kept throughout a 'target data' region.
llvm::DenseMap< const ValueDecl *, llvm::Value * > CaptureDeviceAddrMap
Map between the a declaration of a capture and the corresponding new llvm address where the runtime r...
UntiedTaskLocalDeclsRAII(CodeGenFunction &CGF, const llvm::MapVector< CanonicalDeclPtr< const VarDecl >, std::pair< Address, Address > > &LocalVars)
virtual Address emitThreadIDAddress(CodeGenFunction &CGF, SourceLocation Loc)
Emits address of the word in a memory where current thread id is stored.
llvm::StringSet ThreadPrivateWithDefinition
Set of threadprivate variables with the generated initializer.
void emitUpdateDependObjectsClause(CodeGenFunction &CGF, LValue DepobjLVal, OpenMPDependClauseKind NewDepKind, SourceLocation Loc)
Updates the dependency kind in the specified depobj object.
virtual void emitTaskCall(CodeGenFunction &CGF, SourceLocation Loc, const OMPExecutableDirective &D, llvm::Function *TaskFunction, QualType SharedsTy, Address Shareds, const Expr *IfCond, const OMPTaskDataTy &Data)
Emit task region for the task directive.
void createOffloadEntriesAndInfoMetadata()
Creates all the offload entries in the current compilation unit along with the associated metadata.
const Expr * getNumTeamsExprForTargetDirective(CodeGenFunction &CGF, const OMPExecutableDirective &D, int32_t &MinTeamsVal, int32_t &MaxTeamsVal)
Emit the number of teams for a target directive.
virtual Address getAddrOfThreadPrivate(CodeGenFunction &CGF, const VarDecl *VD, Address VDAddr, SourceLocation Loc)
Returns address of the threadprivate variable for the current thread.
void emitDeferredTargetDecls() const
Emit deferred declare target variables marked for deferred emission.
virtual llvm::Value * emitForNext(CodeGenFunction &CGF, SourceLocation Loc, unsigned IVSize, bool IVSigned, Address IL, Address LB, Address UB, Address ST)
Call __kmpc_dispatch_next( ident_t *loc, kmp_int32 tid, kmp_int32 *p_lastiter, kmp_int[32|64] *p_lowe...
bool markAsGlobalTarget(GlobalDecl GD)
Marks the declaration as already emitted for the device code and returns true, if it was marked alrea...
virtual void emitParallelCall(CodeGenFunction &CGF, SourceLocation Loc, llvm::Function *OutlinedFn, ArrayRef< llvm::Value * > CapturedVars, const Expr *IfCond, llvm::Value *NumThreads, OpenMPNumThreadsClauseModifier NumThreadsModifier=OMPC_NUMTHREADS_unknown, OpenMPSeverityClauseKind Severity=OMPC_SEVERITY_fatal, const Expr *Message=nullptr)
Emits code for parallel or serial call of the OutlinedFn with variables captured in a record which ad...
llvm::SmallDenseSet< CanonicalDeclPtr< const Decl > > NontemporalDeclsSet
virtual void emitTargetDataStandAloneCall(CodeGenFunction &CGF, const OMPExecutableDirective &D, const Expr *IfCond, const Expr *Device)
Emit the data mapping/movement code associated with the directive D that should be of the form 'targe...
virtual void emitNumThreadsClause(CodeGenFunction &CGF, llvm::Value *NumThreads, SourceLocation Loc, OpenMPNumThreadsClauseModifier Modifier=OMPC_NUMTHREADS_unknown, OpenMPSeverityClauseKind Severity=OMPC_SEVERITY_fatal, SourceLocation SeverityLoc=SourceLocation(), const Expr *Message=nullptr, SourceLocation MessageLoc=SourceLocation())
Emits call to void __kmpc_push_num_threads(ident_t *loc, kmp_int32global_tid, kmp_int32 num_threads) ...
QualType SavedKmpTaskloopTQTy
Saved kmp_task_t for taskloop-based directive.
virtual void emitSingleRegion(CodeGenFunction &CGF, const RegionCodeGenTy &SingleOpGen, SourceLocation Loc, ArrayRef< const Expr * > CopyprivateVars, ArrayRef< const Expr * > DestExprs, ArrayRef< const Expr * > SrcExprs, ArrayRef< const Expr * > AssignmentOps)
Emits a single region.
virtual bool emitTargetGlobal(GlobalDecl GD)
Emit the global GD if it is meaningful for the target.
void setLocThreadIdInsertPt(CodeGenFunction &CGF, bool AtCurrentPoint=false)
std::string getOutlinedHelperName(StringRef Name) const
Get the function name of an outlined region.
bool HasEmittedDeclareTargetRegion
Flag for keeping track of weather a device routine has been emitted.
llvm::Constant * getOrCreateThreadPrivateCache(const VarDecl *VD)
If the specified mangled name is not in the module, create and return threadprivate cache object.
virtual Address getTaskReductionItem(CodeGenFunction &CGF, SourceLocation Loc, llvm::Value *ReductionsPtr, LValue SharedLVal)
Get the address of void * type of the privatue copy of the reduction item specified by the SharedLVal...
virtual void emitForDispatchDeinit(CodeGenFunction &CGF, SourceLocation Loc)
This is used for non static scheduled types and when the ordered clause is present on the loop constr...
void emitCall(CodeGenFunction &CGF, SourceLocation Loc, llvm::FunctionCallee Callee, ArrayRef< llvm::Value * > Args={}) const
Emits Callee function call with arguments Args with location Loc.
virtual void getDefaultScheduleAndChunk(CodeGenFunction &CGF, const OMPLoopDirective &S, OpenMPScheduleClauseKind &ScheduleKind, const Expr *&ChunkExpr) const
Choose default schedule type and chunk value for the schedule clause.
virtual std::pair< llvm::Function *, llvm::Function * > getUserDefinedReduction(const OMPDeclareReductionDecl *D)
Get combiner/initializer for the specified user-defined reduction, if any.
virtual bool isGPU() const
Returns true if the current target is a GPU.
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 ...
virtual void emitDeclareTargetFunction(const FunctionDecl *FD, llvm::GlobalValue *GV)
Emit code for handling declare target functions in the runtime.
bool HasRequiresUnifiedSharedMemory
Flag for keeping track of weather a requires unified_shared_memory directive is present.
llvm::Value * emitUpdateLocation(CodeGenFunction &CGF, SourceLocation Loc, unsigned Flags=0, bool EmitLoc=false)
Emits object of ident_t type with info for source location.
bool isLocalVarInUntiedTask(CodeGenFunction &CGF, const VarDecl *VD) const
Returns true if the variable is a local variable in untied task.
virtual void emitTeamsCall(CodeGenFunction &CGF, const OMPExecutableDirective &D, SourceLocation Loc, llvm::Function *OutlinedFn, ArrayRef< llvm::Value * > CapturedVars)
Emits code for teams call of the OutlinedFn with variables captured in a record which address is stor...
virtual void emitCancellationPointCall(CodeGenFunction &CGF, SourceLocation Loc, OpenMPDirectiveKind CancelRegion)
Emit code for 'cancellation point' construct.
virtual llvm::Function * emitThreadPrivateVarDefinition(const VarDecl *VD, Address VDAddr, SourceLocation Loc, bool PerformInit, CodeGenFunction *CGF=nullptr)
Emit a code for initialization of threadprivate variable.
virtual ConstantAddress getAddrOfDeclareTargetVar(const VarDecl *VD)
Returns the address of the variable marked as declare target with link clause OR as declare target wi...
llvm::Function * getOrCreateUserDefinedMapperFunc(const OMPDeclareMapperDecl *D)
Get the function for the specified user-defined mapper.
OpenMPLocThreadIDMapTy OpenMPLocThreadIDMap
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.
QualType KmpTaskTQTy
Type typedef struct kmp_task { void * shareds; /‍**< pointer to block of pointers to shared vars ‍/ k...
llvm::OpenMPIRBuilder OMPBuilder
An OpenMP-IR-Builder instance.
virtual void emitDoacrossInit(CodeGenFunction &CGF, const OMPLoopDirective &D, ArrayRef< Expr * > NumIterations)
Emit initialization for doacross loop nesting support.
virtual void adjustTargetSpecificDataForLambdas(CodeGenFunction &CGF, const OMPExecutableDirective &D) const
Adjust some parameters for the target-based directives, like addresses of the variables captured by r...
virtual void emitTargetDataCalls(CodeGenFunction &CGF, const OMPExecutableDirective &D, const Expr *IfCond, const Expr *Device, const RegionCodeGenTy &CodeGen, CGOpenMPRuntime::TargetDataInfo &Info)
Emit the target data mapping code associated with D.
virtual unsigned getDefaultLocationReserved2Flags() const
Returns additional flags that can be stored in reserved_2 field of the default location.
virtual Address getParameterAddress(CodeGenFunction &CGF, const VarDecl *NativeParam, const VarDecl *TargetParam) const
Gets the address of the native argument basing on the address of the target-specific parameter.
void emitUsesAllocatorsFini(CodeGenFunction &CGF, const Expr *Allocator)
Destroys user defined allocators specified in the uses_allocators clause.
QualType KmpTaskAffinityInfoTy
Type typedef struct kmp_task_affinity_info { kmp_intptr_t base_addr; size_t len; struct { bool flag1 ...
void emitPrivateReduction(CodeGenFunction &CGF, SourceLocation Loc, const Expr *Privates, const Expr *LHSExprs, const Expr *RHSExprs, const Expr *ReductionOps)
Emits code for private variable reduction.
llvm::Value * emitNumTeamsForTargetDirective(CodeGenFunction &CGF, const OMPExecutableDirective &D)
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.
void scanForTargetRegionsFunctions(const Stmt *S, StringRef ParentName)
Start scanning from statement S and emit all target regions found along the way.
SmallVector< llvm::Value *, 4 > emitDepobjElementsSizes(CodeGenFunction &CGF, QualType &KmpDependInfoTy, const OMPTaskDataTy::DependData &Data)
virtual llvm::Value * emitMessageClause(CodeGenFunction &CGF, const Expr *Message, SourceLocation Loc)
virtual void emitTaskgroupRegion(CodeGenFunction &CGF, const RegionCodeGenTy &TaskgroupOpGen, SourceLocation Loc)
Emit a taskgroup region.
llvm::DenseMap< llvm::Function *, llvm::DenseMap< CanonicalDeclPtr< const Decl >, std::tuple< QualType, const FieldDecl *, const FieldDecl *, LValue > > > LastprivateConditionalToTypes
Maps local variables marked as lastprivate conditional to their internal types.
virtual bool emitTargetGlobalVariable(GlobalDecl GD)
Emit the global variable if it is a valid device global variable.
virtual void emitNumTeamsClause(CodeGenFunction &CGF, const Expr *NumTeams, const Expr *ThreadLimit, SourceLocation Loc)
Emits call to void __kmpc_push_num_teams(ident_t *loc, kmp_int32global_tid, kmp_int32 num_teams,...
bool hasRequiresUnifiedSharedMemory() const
Return whether the unified_shared_memory has been specified.
virtual Address getAddrOfArtificialThreadPrivate(CodeGenFunction &CGF, QualType VarType, StringRef Name)
Creates artificial threadprivate variable with name Name and type VarType.
void emitUserDefinedMapper(const OMPDeclareMapperDecl *D, CodeGenFunction *CGF=nullptr)
Emit the function for the user defined mapper construct.
bool HasEmittedTargetRegion
Flag for keeping track of weather a target region has been emitted.
void emitDepobjElements(CodeGenFunction &CGF, QualType &KmpDependInfoTy, LValue PosLVal, const OMPTaskDataTy::DependData &Data, Address DependenciesArray)
std::string getReductionFuncName(StringRef Name) const
Get the function name of a reduction function.
virtual void processRequiresDirective(const OMPRequiresDecl *D)
Perform check on requires decl to ensure that target architecture supports unified addressing.
llvm::DenseSet< CanonicalDeclPtr< const Decl > > AlreadyEmittedTargetDecls
List of the emitted declarations.
virtual llvm::Value * emitTaskReductionInit(CodeGenFunction &CGF, SourceLocation Loc, ArrayRef< const Expr * > LHSExprs, ArrayRef< const Expr * > RHSExprs, const OMPTaskDataTy &Data)
Emit a code for initialization of task reduction clause.
llvm::Value * getThreadID(CodeGenFunction &CGF, SourceLocation Loc)
Gets thread id value for the current thread.
virtual void emitLastprivateConditionalFinalUpdate(CodeGenFunction &CGF, LValue PrivLVal, const VarDecl *VD, SourceLocation Loc)
Gets the address of the global copy used for lastprivate conditional update, if any.
llvm::MapVector< CanonicalDeclPtr< const VarDecl >, std::pair< Address, Address > > UntiedLocalVarsAddressesMap
virtual void emitErrorCall(CodeGenFunction &CGF, SourceLocation Loc, Expr *ME, bool IsFatal)
Emit __kmpc_error call for error directive extern void __kmpc_error(ident_t *loc, int severity,...
void clearLocThreadIdInsertPt(CodeGenFunction &CGF)
virtual void emitTaskyieldCall(CodeGenFunction &CGF, SourceLocation Loc)
Emits code for a taskyield directive.
std::string getName(ArrayRef< StringRef > Parts) const
Get the platform-specific name separator.
void computeMinAndMaxThreadsAndTeams(const OMPExecutableDirective &D, CodeGenFunction &CGF, llvm::OpenMPIRBuilder::TargetKernelDefaultAttrs &Attrs)
Helper to determine the min/max number of threads/teams for D.
virtual void emitFlush(CodeGenFunction &CGF, ArrayRef< const Expr * > Vars, SourceLocation Loc, llvm::AtomicOrdering AO)
Emit flush of the variables specified in 'omp flush' directive.
virtual void emitTaskwaitCall(CodeGenFunction &CGF, SourceLocation Loc, const OMPTaskDataTy &Data)
Emit code for 'taskwait' directive.
virtual void emitProcBindClause(CodeGenFunction &CGF, llvm::omp::ProcBindKind ProcBind, SourceLocation Loc)
Emit call to void __kmpc_push_proc_bind(ident_t *loc, kmp_int32global_tid, int proc_bind) to generate...
void emitLastprivateConditionalUpdate(CodeGenFunction &CGF, LValue IVLVal, StringRef UniqueDeclName, LValue LVal, SourceLocation Loc)
Emit update for lastprivate conditional data.
virtual void emitTaskLoopCall(CodeGenFunction &CGF, SourceLocation Loc, const OMPLoopDirective &D, llvm::Function *TaskFunction, QualType SharedsTy, Address Shareds, const Expr *IfCond, const OMPTaskDataTy &Data)
Emit task region for the taskloop directive.
virtual void emitBarrierCall(CodeGenFunction &CGF, SourceLocation Loc, OpenMPDirectiveKind Kind, bool EmitChecks=true, bool ForceSimpleCall=false)
Emit an implicit/explicit barrier for OpenMP threads.
static unsigned getDefaultFlagsForBarriers(OpenMPDirectiveKind Kind)
Returns default flags for the barriers depending on the directive, for which this barier is going to ...
virtual bool emitTargetFunctions(GlobalDecl GD)
Emit the target regions enclosed in GD function definition or the function itself in case it is a val...
TaskResultTy emitTaskInit(CodeGenFunction &CGF, SourceLocation Loc, const OMPExecutableDirective &D, llvm::Function *TaskFunction, QualType SharedsTy, Address Shareds, const OMPTaskDataTy &Data)
Emit task region for the task directive.
llvm::Value * emitTargetNumIterationsCall(CodeGenFunction &CGF, const OMPExecutableDirective &D, llvm::function_ref< llvm::Value *(CodeGenFunction &CGF, const OMPLoopDirective &D)> SizeEmitter)
Return the trip count of loops associated with constructs / 'target teams distribute' and 'teams dist...
llvm::StringMap< llvm::AssertingVH< llvm::GlobalVariable >, llvm::BumpPtrAllocator > InternalVars
An ordered map of auto-generated variables to their unique names.
virtual void emitDistributeStaticInit(CodeGenFunction &CGF, SourceLocation Loc, OpenMPDistScheduleClauseKind SchedKind, const StaticRTInput &Values)
llvm::SmallVector< UntiedLocalVarsAddressesMap, 4 > UntiedLocalVarsStack
virtual void emitForStaticFinish(CodeGenFunction &CGF, SourceLocation Loc, OpenMPDirectiveKind DKind)
Call the appropriate runtime routine to notify that we finished all the work with current loop.
virtual void emitThreadLimitClause(CodeGenFunction &CGF, const Expr *ThreadLimit, SourceLocation Loc)
Emits call to void __kmpc_set_thread_limit(ident_t *loc, kmp_int32global_tid, kmp_int32 thread_limit)...
void emitIfClause(CodeGenFunction &CGF, const Expr *Cond, const RegionCodeGenTy &ThenGen, const RegionCodeGenTy &ElseGen)
Emits code for OpenMP 'if' clause using specified CodeGen function.
Address emitDepobjDependClause(CodeGenFunction &CGF, const OMPTaskDataTy::DependData &Dependencies, SourceLocation Loc)
Emits list of dependecies based on the provided data (array of dependence/expression pairs) for depob...
bool isNontemporalDecl(const ValueDecl *VD) const
Checks if the VD variable is marked as nontemporal declaration in current context.
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.
const Expr * getNumThreadsExprForTargetDirective(CodeGenFunction &CGF, const OMPExecutableDirective &D, int32_t &UpperBound, bool UpperBoundOnly, llvm::Value **CondExpr=nullptr, const Expr **ThreadLimitExpr=nullptr)
Check for a number of threads upper bound constant value (stored in UpperBound), or expression (retur...
virtual void registerVTableOffloadEntry(llvm::GlobalVariable *VTable, const VarDecl *VD)
Register VTable to OpenMP offload entry.
virtual llvm::Value * emitSeverityClause(OpenMPSeverityClauseKind Severity, SourceLocation Loc)
llvm::SmallVector< LastprivateConditionalData, 4 > LastprivateConditionalStack
Stack for list of addresses of declarations in current context marked as lastprivate conditional.
virtual void emitForStaticInit(CodeGenFunction &CGF, SourceLocation Loc, OpenMPDirectiveKind DKind, const OpenMPScheduleTy &ScheduleKind, const StaticRTInput &Values)
Call the appropriate runtime routine to initialize it before start of loop.
virtual void emitDeclareSimdFunction(const FunctionDecl *FD, llvm::Function *Fn)
Marks function Fn with properly mangled versions of vector functions.
llvm::AtomicOrdering getDefaultMemoryOrdering() const
Gets default memory ordering as specified in requires directive.
virtual bool isStaticNonchunked(OpenMPScheduleClauseKind ScheduleKind, bool Chunked) const
Check if the specified ScheduleKind is static non-chunked.
virtual void emitAndRegisterVTable(CodeGenModule &CGM, CXXRecordDecl *CXXRecord, const VarDecl *VD)
Emit and register VTable for the C++ class in OpenMP offload entry.
llvm::Value * getCriticalRegionLock(StringRef CriticalName)
Returns corresponding lock object for the specified critical region name.
virtual void emitCancelCall(CodeGenFunction &CGF, SourceLocation Loc, const Expr *IfCond, OpenMPDirectiveKind CancelRegion)
Emit code for 'cancel' construct.
QualType SavedKmpTaskTQTy
Saved kmp_task_t for task directive.
virtual void emitMasterRegion(CodeGenFunction &CGF, const RegionCodeGenTy &MasterOpGen, SourceLocation Loc)
Emits a master region.
virtual llvm::Function * emitTaskOutlinedFunction(const OMPExecutableDirective &D, const VarDecl *ThreadIDVar, const VarDecl *PartIDVar, const VarDecl *TaskTVar, OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen, bool Tied, unsigned &NumberOfParts)
Emits outlined function for the OpenMP task directive D.
llvm::DenseMap< llvm::Function *, unsigned > FunctionToUntiedTaskStackMap
Maps function to the position of the untied task locals stack.
void emitHostKernelEnvironment(const OMPExecutableDirective &D, CodeGenFunction &CGF)
Emit the '<kernel>_kernel_environment' global for a target region that is compiled for a non-GPU (hos...
void emitDestroyClause(CodeGenFunction &CGF, LValue DepobjLVal, SourceLocation Loc)
Emits the code to destroy the dependency object provided in depobj directive.
virtual void emitTaskReductionFixups(CodeGenFunction &CGF, SourceLocation Loc, ReductionCodeGen &RCG, unsigned N)
Required to resolve existing problems in the runtime.
llvm::ArrayType * KmpCriticalNameTy
Type kmp_critical_name, originally defined as typedef kmp_int32 kmp_critical_name[8];.
virtual void emitDoacrossOrdered(CodeGenFunction &CGF, const OMPDependClause *C)
Emit code for doacross ordered directive with 'depend' clause.
llvm::DenseMap< const OMPDeclareMapperDecl *, llvm::Function * > UDMMap
Map from the user-defined mapper declaration to its corresponding functions.
virtual void checkAndEmitLastprivateConditional(CodeGenFunction &CGF, const Expr *LHS)
Checks if the provided LVal is lastprivate conditional and emits the code to update the value of the ...
std::pair< llvm::Value *, LValue > getDepobjElements(CodeGenFunction &CGF, LValue DepobjLVal, SourceLocation Loc)
Returns the number of the elements and the address of the depobj dependency array.
llvm::SmallDenseSet< const VarDecl * > DeferredGlobalVariables
List of variables that can become declare target implicitly and, thus, must be emitted.
void emitUsesAllocatorsInit(CodeGenFunction &CGF, const Expr *Allocator, const Expr *AllocatorTraits)
Initializes user defined allocators specified in the uses_allocators clauses.
virtual void registerVTable(const OMPExecutableDirective &D)
Emit code for registering vtable by scanning through map clause in OpenMP target region.
llvm::Type * KmpRoutineEntryPtrTy
Type typedef kmp_int32 (* kmp_routine_entry_t)(kmp_int32, void *);.
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 emitTargetOutlinedFunction(const OMPExecutableDirective &D, StringRef ParentName, llvm::Function *&OutlinedFn, llvm::Constant *&OutlinedFnID, bool IsOffloadEntry, const RegionCodeGenTy &CodeGen)
Emit outilined function for 'target' directive.
virtual void emitCriticalRegion(CodeGenFunction &CGF, StringRef CriticalName, const RegionCodeGenTy &CriticalOpGen, SourceLocation Loc, const Expr *Hint=nullptr)
Emits a critical region.
virtual void emitForOrderedIterationEnd(CodeGenFunction &CGF, SourceLocation Loc, unsigned IVSize, bool IVSigned)
Call the appropriate runtime routine to notify that we finished iteration of the ordered loop with th...
virtual void 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...
llvm::Value * emitNumThreadsForTargetDirective(CodeGenFunction &CGF, const OMPExecutableDirective &D)
Emit an expression that denotes the number of threads a target region shall use.
void emitThreadPrivateVarInit(CodeGenFunction &CGF, Address VDAddr, llvm::Value *Ctor, llvm::Value *CopyCtor, llvm::Value *Dtor, SourceLocation Loc)
Emits initialization code for the threadprivate variables.
virtual void emitUserDefinedReduction(CodeGenFunction *CGF, const OMPDeclareReductionDecl *D)
Emit code for the specified user defined reduction construct.
virtual void checkAndEmitSharedLastprivateConditional(CodeGenFunction &CGF, const OMPExecutableDirective &D, const llvm::DenseSet< CanonicalDeclPtr< const VarDecl > > &IgnoredDecls)
Checks if the lastprivate conditional was updated in inner region and writes the value.
QualType KmpDimTy
struct kmp_dim { // loop bounds info casted to kmp_int64 kmp_int64 lo; // lower kmp_int64 up; // uppe...
virtual void emitInlinedDirective(CodeGenFunction &CGF, OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen, bool HasCancel=false)
Emit code for the directive that does not require outlining.
virtual void registerTargetGlobalVariable(const VarDecl *VD, llvm::Constant *Addr)
Checks if the provided global decl GD is a declare target variable and registers it when emitting cod...
virtual void emitFunctionProlog(CodeGenFunction &CGF, const Decl *D)
Emits OpenMP-specific function prolog.
void emitKmpRoutineEntryT(QualType KmpInt32Ty)
Build type kmp_routine_entry_t (if not built yet).
virtual bool isStaticChunked(OpenMPScheduleClauseKind ScheduleKind, bool Chunked) const
Check if the specified ScheduleKind is static chunked.
virtual void emitTargetCall(CodeGenFunction &CGF, const OMPExecutableDirective &D, llvm::Function *OutlinedFn, llvm::Value *OutlinedFnID, const Expr *IfCond, llvm::PointerIntPair< const Expr *, 2, OpenMPDeviceClauseModifier > Device, llvm::function_ref< llvm::Value *(CodeGenFunction &CGF, const OMPLoopDirective &D)> SizeEmitter)
Emit the target offloading code associated with D.
virtual bool hasAllocateAttributeForGlobalVar(const VarDecl *VD, LangAS &AS)
Checks if the variable has associated OMPAllocateDeclAttr attribute with the predefined allocator and...
llvm::AtomicOrdering RequiresAtomicOrdering
Atomic ordering from the omp requires directive.
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.
std::pair< llvm::Value *, Address > emitDependClause(CodeGenFunction &CGF, ArrayRef< OMPTaskDataTy::DependData > Dependencies, SourceLocation Loc)
Emits list of dependecies based on the provided data (array of dependence/expression pairs).
llvm::StringMap< llvm::WeakTrackingVH > EmittedNonTargetVariables
List of the global variables with their addresses that should not be emitted for the target.
virtual bool isDynamic(OpenMPScheduleClauseKind ScheduleKind) const
Check if the specified ScheduleKind is dynamic.
Address emitLastprivateConditionalInit(CodeGenFunction &CGF, const VarDecl *VD)
Create specialized alloca to handle lastprivate conditionals.
virtual void emitOrderedRegion(CodeGenFunction &CGF, const RegionCodeGenTy &OrderedOpGen, SourceLocation Loc, bool IsThreads)
Emit an ordered region.
virtual Address getAddressOfLocalVariable(CodeGenFunction &CGF, const VarDecl *VD)
Gets the OpenMP-specific address of the local variable.
virtual void emitTaskReductionFini(CodeGenFunction &CGF, SourceLocation Loc, bool IsWorksharingReduction)
Emits the following code for reduction clause with task modifier:
virtual void emitMaskedRegion(CodeGenFunction &CGF, const RegionCodeGenTy &MaskedOpGen, SourceLocation Loc, const Expr *Filter=nullptr)
Emits a masked region.
QualType KmpDependInfoTy
Type typedef struct kmp_depend_info { kmp_intptr_t base_addr; size_t len; struct { bool in:1; bool ou...
llvm::Function * emitReductionFunction(StringRef ReducerName, SourceLocation Loc, llvm::Type *ArgsElemType, ArrayRef< const Expr * > Privates, ArrayRef< const Expr * > LHSExprs, ArrayRef< const Expr * > RHSExprs, ArrayRef< const Expr * > ReductionOps)
Emits reduction function.
virtual void emitForDispatchInit(CodeGenFunction &CGF, SourceLocation Loc, const OpenMPScheduleTy &ScheduleKind, unsigned IVSize, bool IVSigned, bool Ordered, const DispatchRTInput &DispatchValues)
Call the appropriate runtime routine to initialize it before start of loop.
Address getTaskReductionItem(CodeGenFunction &CGF, SourceLocation Loc, llvm::Value *ReductionsPtr, LValue SharedLVal) override
Get the address of void * type of the privatue copy of the reduction item specified by the SharedLVal...
void emitCriticalRegion(CodeGenFunction &CGF, StringRef CriticalName, const RegionCodeGenTy &CriticalOpGen, SourceLocation Loc, const Expr *Hint=nullptr) override
Emits a critical region.
void emitDistributeStaticInit(CodeGenFunction &CGF, SourceLocation Loc, OpenMPDistScheduleClauseKind SchedKind, const StaticRTInput &Values) override
void emitForStaticInit(CodeGenFunction &CGF, SourceLocation Loc, OpenMPDirectiveKind DKind, const OpenMPScheduleTy &ScheduleKind, const StaticRTInput &Values) override
Call the appropriate runtime routine to initialize it before start of loop.
bool emitTargetGlobalVariable(GlobalDecl GD) override
Emit the global variable if it is a valid device global variable.
llvm::Value * emitForNext(CodeGenFunction &CGF, SourceLocation Loc, unsigned IVSize, bool IVSigned, Address IL, Address LB, Address UB, Address ST) override
Call __kmpc_dispatch_next( ident_t *loc, kmp_int32 tid, kmp_int32 *p_lastiter, kmp_int[32|64] *p_lowe...
llvm::Function * emitThreadPrivateVarDefinition(const VarDecl *VD, Address VDAddr, SourceLocation Loc, bool PerformInit, CodeGenFunction *CGF=nullptr) override
Emit a code for initialization of threadprivate variable.
void emitTargetDataStandAloneCall(CodeGenFunction &CGF, const OMPExecutableDirective &D, const Expr *IfCond, const Expr *Device) override
Emit the data mapping/movement code associated with the directive D that should be of the form 'targe...
llvm::Function * emitTeamsOutlinedFunction(CodeGenFunction &CGF, const OMPExecutableDirective &D, const VarDecl *ThreadIDVar, OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen) override
Emits outlined function for the specified OpenMP teams directive D.
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 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.
void emitFlush(CodeGenFunction &CGF, ArrayRef< const Expr * > Vars, SourceLocation Loc, llvm::AtomicOrdering AO) override
Emit flush of the variables specified in 'omp flush' directive.
void emitDoacrossOrdered(CodeGenFunction &CGF, const OMPDependClause *C) override
Emit code for doacross ordered directive with 'depend' clause.
void emitTaskyieldCall(CodeGenFunction &CGF, SourceLocation Loc) override
Emits a masked region.
Address getAddrOfArtificialThreadPrivate(CodeGenFunction &CGF, QualType VarType, StringRef Name) override
Creates artificial threadprivate variable with name Name and type VarType.
Address getAddrOfThreadPrivate(CodeGenFunction &CGF, const VarDecl *VD, Address VDAddr, SourceLocation Loc) override
Returns address of the threadprivate variable for the current thread.
void emitSingleRegion(CodeGenFunction &CGF, const RegionCodeGenTy &SingleOpGen, SourceLocation Loc, ArrayRef< const Expr * > CopyprivateVars, ArrayRef< const Expr * > DestExprs, ArrayRef< const Expr * > SrcExprs, ArrayRef< const Expr * > AssignmentOps) override
Emits a single region.
void emitTaskReductionFixups(CodeGenFunction &CGF, SourceLocation Loc, ReductionCodeGen &RCG, unsigned N) override
Required to resolve existing problems in the runtime.
llvm::Function * emitParallelOutlinedFunction(CodeGenFunction &CGF, const OMPExecutableDirective &D, const VarDecl *ThreadIDVar, OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen) override
Emits outlined function for the specified OpenMP parallel directive D.
void emitCancellationPointCall(CodeGenFunction &CGF, SourceLocation Loc, OpenMPDirectiveKind CancelRegion) override
Emit code for 'cancellation point' construct.
void emitBarrierCall(CodeGenFunction &CGF, SourceLocation Loc, OpenMPDirectiveKind Kind, bool EmitChecks=true, bool ForceSimpleCall=false) override
Emit an implicit/explicit barrier for OpenMP threads.
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.
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...
void emitForOrderedIterationEnd(CodeGenFunction &CGF, SourceLocation Loc, unsigned IVSize, bool IVSigned) override
Call the appropriate runtime routine to notify that we finished iteration of the ordered loop with th...
bool emitTargetGlobal(GlobalDecl GD) override
Emit the global GD if it is meaningful for the target.
void emitTaskReductionFini(CodeGenFunction &CGF, SourceLocation Loc, bool IsWorksharingReduction) override
Emits the following code for reduction clause with task modifier:
void emitOrderedRegion(CodeGenFunction &CGF, const RegionCodeGenTy &OrderedOpGen, SourceLocation Loc, bool IsThreads) override
Emit an ordered region.
void emitForStaticFinish(CodeGenFunction &CGF, SourceLocation Loc, OpenMPDirectiveKind DKind) override
Call the appropriate runtime routine to notify that we finished all the work with current loop.
llvm::Value * emitTaskReductionInit(CodeGenFunction &CGF, SourceLocation Loc, ArrayRef< const Expr * > LHSExprs, ArrayRef< const Expr * > RHSExprs, const OMPTaskDataTy &Data) override
Emit a code for initialization of task reduction clause.
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 emitTargetOutlinedFunction(const OMPExecutableDirective &D, StringRef ParentName, llvm::Function *&OutlinedFn, llvm::Constant *&OutlinedFnID, bool IsOffloadEntry, const RegionCodeGenTy &CodeGen) override
Emit outilined function for 'target' directive.
void emitMasterRegion(CodeGenFunction &CGF, const RegionCodeGenTy &MasterOpGen, SourceLocation Loc) override
Emits a master region.
void emitNumTeamsClause(CodeGenFunction &CGF, const Expr *NumTeams, const Expr *ThreadLimit, SourceLocation Loc) override
Emits call to void __kmpc_push_num_teams(ident_t *loc, kmp_int32global_tid, kmp_int32 num_teams,...
void emitForDispatchDeinit(CodeGenFunction &CGF, SourceLocation Loc) override
This is used for non static scheduled types and when the ordered clause is present on the loop constr...
const VarDecl * translateParameter(const FieldDecl *FD, const VarDecl *NativeParam) const override
Translates the native parameter of outlined function if this is required for target.
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 emitMaskedRegion(CodeGenFunction &CGF, const RegionCodeGenTy &MaskedOpGen, SourceLocation Loc, const Expr *Filter=nullptr) override
Emits a masked region.
void emitTaskCall(CodeGenFunction &CGF, SourceLocation Loc, const OMPExecutableDirective &D, llvm::Function *TaskFunction, QualType SharedsTy, Address Shareds, const Expr *IfCond, const OMPTaskDataTy &Data) override
Emit task region for the task directive.
void emitTargetCall(CodeGenFunction &CGF, const OMPExecutableDirective &D, llvm::Function *OutlinedFn, llvm::Value *OutlinedFnID, const Expr *IfCond, llvm::PointerIntPair< const Expr *, 2, OpenMPDeviceClauseModifier > Device, llvm::function_ref< llvm::Value *(CodeGenFunction &CGF, const OMPLoopDirective &D)> SizeEmitter) override
Emit the target offloading code associated with D.
bool emitTargetFunctions(GlobalDecl GD) override
Emit the target regions enclosed in GD function definition or the function itself in case it is a val...
void emitDoacrossInit(CodeGenFunction &CGF, const OMPLoopDirective &D, ArrayRef< Expr * > NumIterations) override
Emit initialization for doacross loop nesting support.
void emitCancelCall(CodeGenFunction &CGF, SourceLocation Loc, const Expr *IfCond, OpenMPDirectiveKind CancelRegion) override
Emit code for 'cancel' construct.
void emitTaskwaitCall(CodeGenFunction &CGF, SourceLocation Loc, const OMPTaskDataTy &Data) override
Emit code for 'taskwait' directive.
void emitTaskgroupRegion(CodeGenFunction &CGF, const RegionCodeGenTy &TaskgroupOpGen, SourceLocation Loc) override
Emit a taskgroup region.
void emitTargetDataCalls(CodeGenFunction &CGF, const OMPExecutableDirective &D, const Expr *IfCond, const Expr *Device, const RegionCodeGenTy &CodeGen, CGOpenMPRuntime::TargetDataInfo &Info) override
Emit the target data mapping code associated with D.
void emitForDispatchInit(CodeGenFunction &CGF, SourceLocation Loc, const OpenMPScheduleTy &ScheduleKind, unsigned IVSize, bool IVSigned, bool Ordered, const DispatchRTInput &DispatchValues) override
This is used for non static scheduled types and when the ordered clause is present on the loop constr...
llvm::Function * emitTaskOutlinedFunction(const OMPExecutableDirective &D, const VarDecl *ThreadIDVar, const VarDecl *PartIDVar, const VarDecl *TaskTVar, OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen, bool Tied, unsigned &NumberOfParts) override
Emits outlined function for the OpenMP task directive D.
void emitTaskLoopCall(CodeGenFunction &CGF, SourceLocation Loc, const OMPLoopDirective &D, llvm::Function *TaskFunction, QualType SharedsTy, Address Shareds, const Expr *IfCond, const OMPTaskDataTy &Data) override
Emit task region for the taskloop directive.
unsigned getNonVirtualBaseLLVMFieldNo(const CXXRecordDecl *RD) const
llvm::StructType * getLLVMType() const
Return the "complete object" LLVM type associated with this record.
llvm::StructType * getBaseSubobjectLLVMType() const
Return the "base subobject" LLVM type associated with this record.
unsigned getLLVMFieldNo(const FieldDecl *FD) const
Return llvm::StructType element number that corresponds to the field FD.
unsigned getVirtualBaseIndex(const CXXRecordDecl *base) const
Return the LLVM field index corresponding to the given virtual base.
API for captured statement code generation.
virtual void EmitBody(CodeGenFunction &CGF, const Stmt *S)
Emit the captured statement body.
virtual const FieldDecl * lookup(const VarDecl *VD) const
Lookup the captured field decl for a variable.
RAII for correct setting/restoring of CapturedStmtInfo.
The scope used to remap some variables as private in the OpenMP loop body (or other captured region e...
bool Privatize()
Privatizes local variables previously registered as private.
bool addPrivate(const ValueDecl *LocalVD, Address Addr)
Registers LocalVD variable as a private with Addr as the address of the corresponding private variabl...
An RAII object to set (and then clear) a mapping for an OpaqueValueExpr.
Enters a new scope for capturing cleanups, all of which will be executed once the scope is exited.
CodeGenFunction - This class organizes the per-function state that is used while generating LLVM code...
LValue EmitLoadOfReferenceLValue(LValue RefLVal)
Definition CGExpr.cpp:3454
void EmitBranchOnBoolExpr(const Expr *Cond, llvm::BasicBlock *TrueBlock, llvm::BasicBlock *FalseBlock, uint64_t TrueCount, Stmt::Likelihood LH=Stmt::LH_None, const Expr *ConditionalOp=nullptr, const VarDecl *ConditionalDecl=nullptr)
EmitBranchOnBoolExpr - Emit a branch on a boolean condition (e.g.
void emitDestroy(Address addr, QualType type, Destroyer *destroyer, bool useEHCleanupForArray)
emitDestroy - Immediately perform the destruction of the given object.
Definition CGDecl.cpp:2484
JumpDest getJumpDestInCurrentScope(llvm::BasicBlock *Target)
The given basic block lies in the current EH scope, but may be a target of a potentially scope-crossi...
static void EmitOMPTargetParallelDeviceFunction(CodeGenModule &CGM, StringRef ParentName, const OMPTargetParallelDirective &S)
void EmitNullInitialization(Address DestPtr, QualType Ty)
EmitNullInitialization - Generate code to set a value of the given type to null, If the type contains...
CGCapturedStmtInfo * CapturedStmtInfo
ComplexPairTy EmitLoadOfComplex(LValue src, SourceLocation loc)
EmitLoadOfComplex - Load a complex number from the specified l-value.
static void EmitOMPTargetDeviceFunction(CodeGenModule &CGM, StringRef ParentName, const OMPTargetDirective &S)
Emit device code for the target directive.
static void EmitOMPTargetTeamsDeviceFunction(CodeGenModule &CGM, StringRef ParentName, const OMPTargetTeamsDirective &S)
Emit device code for the target teams directive.
static void EmitOMPTargetTeamsDistributeDeviceFunction(CodeGenModule &CGM, StringRef ParentName, const OMPTargetTeamsDistributeDirective &S)
Emit device code for the target teams distribute directive.
llvm::Function * GenerateOpenMPCapturedStmtFunctionAggregate(const CapturedStmt &S, const OMPExecutableDirective &D)
llvm::BasicBlock * createBasicBlock(const Twine &name="", llvm::Function *parent=nullptr, llvm::BasicBlock *before=nullptr)
createBasicBlock - Create an LLVM basic block.
const LangOptions & getLangOpts() const
AutoVarEmission EmitAutoVarAlloca(const VarDecl &var)
EmitAutoVarAlloca - Emit the alloca and debug information for a local variable.
Definition CGDecl.cpp:1494
void pushDestroy(QualType::DestructionKind dtorKind, Address addr, QualType type)
pushDestroy - Push the standard destructor for the given type as at least a normal cleanup.
Definition CGDecl.cpp:2367
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:3463
DeclMapTy::iterator localDeclMapEnd()
void EmitBranchThroughCleanup(JumpDest Dest)
EmitBranchThroughCleanup - Emit a branch from the current insert block through the normal cleanup han...
const Decl * CurCodeDecl
CurCodeDecl - This is the inner-most code context, which includes blocks.
Destroyer * getDestroyer(QualType::DestructionKind destructionKind)
Definition CGDecl.cpp:2340
llvm::AssertingVH< llvm::Instruction > AllocaInsertPt
AllocaInsertPoint - This is an instruction in the entry block before which we prefer to insert alloca...
void EmitAggregateAssign(LValue Dest, LValue Src, QualType EltTy)
Emit an aggregate assignment.
JumpDest ReturnBlock
ReturnBlock - Unified return block.
void EmitAggregateCopy(LValue Dest, LValue Src, QualType EltTy, AggValueSlot::Overlap_t MayOverlap, bool isVolatile=false)
EmitAggregateCopy - Emit an aggregate copy.
LValue EmitLValueForField(LValue Base, const FieldDecl *Field, bool IsInBounds=true)
Definition CGExpr.cpp:5982
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:186
void GenerateOpenMPCapturedVars(const CapturedStmt &S, SmallVectorImpl< llvm::Value * > &CapturedVars)
DeclMapTy::iterator findLocalDecl(const Decl *D)
Accessors for LocalDeclMap.
void EmitIgnoredExpr(const Expr *E)
EmitIgnoredExpr - Emit an expression in a context which ignores the result.
Definition CGExpr.cpp:262
RValue EmitLoadOfLValue(LValue V, SourceLocation Loc)
EmitLoadOfLValue - Given an expression that represents a value lvalue, this method emits the address ...
Definition CGExpr.cpp:2559
std::pair< DeclMapTy::iterator, bool > insertLocalDecl(const Decl *D, Address Addr)
LValue EmitArraySectionExpr(const ArraySectionExpr *E, bool IsLowerBound=true)
Definition CGExpr.cpp:5491
LValue EmitOMPSharedLValue(const Expr *E)
Emits the lvalue for the expression with possibly captured variable.
void StartFunction(GlobalDecl GD, QualType RetTy, llvm::Function *Fn, const CGFunctionInfo &FnInfo, const FunctionArgList &Args, SourceLocation Loc=SourceLocation(), SourceLocation StartLoc=SourceLocation())
Emit code for the start of a function.
void EmitOMPCopy(QualType OriginalType, Address DestAddr, Address SrcAddr, const VarDecl *DestVD, const VarDecl *SrcVD, const Expr *Copy)
Emit proper copying of data from one variable to another.
llvm::Value * EvaluateExprAsBool(const Expr *E)
EvaluateExprAsBool - Perform the usual unary conversions on the specified expression and compare the ...
Definition CGExpr.cpp:243
JumpDest getOMPCancelDestination(OpenMPDirectiveKind Kind)
llvm::Value * emitArrayLength(const ArrayType *arrayType, QualType &baseType, Address &addr)
emitArrayLength - Compute the length of an array, even if it's a VLA, and drill down to the base elem...
void EmitOMPAggregateAssign(Address DestAddr, Address SrcAddr, QualType OriginalType, const llvm::function_ref< void(Address, Address)> CopyGen)
Perform element by element copying of arrays with type OriginalType from SrcAddr to DestAddr using co...
bool HaveInsertPoint() const
HaveInsertPoint - True if an insertion point is defined.
llvm::Value * getTypeSize(QualType Ty)
Returns calculated size of the specified type.
LValue MakeRawAddrLValue(llvm::Value *V, QualType T, CharUnits Alignment, AlignmentSource Source=AlignmentSource::Type)
Same as MakeAddrLValue above except that the pointer is known to be unsigned.
LValue EmitLValueForFieldInitialization(LValue Base, const FieldDecl *Field)
EmitLValueForFieldInitialization - Like EmitLValueForField, except that if the Field is a reference,...
Definition CGExpr.cpp:6144
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:235
VlaSizePair getVLASize(const VariableArrayType *vla)
Returns an LLVM value that corresponds to the size, in non-variably-sized elements,...
llvm::CallInst * EmitNounwindRuntimeCall(llvm::FunctionCallee callee, const Twine &name="")
llvm::Value * EmitLoadOfScalar(Address Addr, bool Volatile, QualType Ty, SourceLocation Loc, AlignmentSource Source=AlignmentSource::Type, bool isNontemporal=false)
EmitLoadOfScalar - Load a scalar value from an address, taking care to appropriately convert from the...
void EmitStoreOfComplex(ComplexPairTy V, LValue dest, bool isInit)
EmitStoreOfComplex - Store a complex number into the specified l-value.
const Decl * CurFuncDecl
CurFuncDecl - Holds the Decl for the current outermost non-closure context.
void EmitAutoVarCleanups(const AutoVarEmission &emission)
Definition CGDecl.cpp:2286
void EmitStoreThroughLValue(RValue Src, LValue Dst, bool isInit=false)
EmitStoreThroughLValue - Store the specified rvalue into the specified lvalue, where both are guarant...
Definition CGExpr.cpp:2811
LValue EmitLoadOfPointerLValue(Address Ptr, const PointerType *PtrTy)
Definition CGExpr.cpp:3473
void EmitAnyExprToMem(const Expr *E, Address Location, Qualifiers Quals, bool IsInitializer)
EmitAnyExprToMem - Emits the code necessary to evaluate an arbitrary expression into the given memory...
Definition CGExpr.cpp:313
bool needsEHCleanup(QualType::DestructionKind kind)
Determines whether an EH cleanup is required to destroy a type with the given destruction kind.
llvm::DenseMap< const ValueDecl *, FieldDecl * > LambdaCaptureFields
llvm::CallInst * EmitRuntimeCall(llvm::FunctionCallee callee, const Twine &name="")
llvm::Type * ConvertTypeForMem(QualType T)
static void EmitOMPTargetTeamsDistributeParallelForDeviceFunction(CodeGenModule &CGM, StringRef ParentName, const OMPTargetTeamsDistributeParallelForDirective &S)
static void EmitOMPTargetParallelForSimdDeviceFunction(CodeGenModule &CGM, StringRef ParentName, const OMPTargetParallelForSimdDirective &S)
Emit device code for the target parallel for simd directive.
CodeGenTypes & getTypes() const
static TypeEvaluationKind getEvaluationKind(QualType T)
getEvaluationKind - Return the TypeEvaluationKind of QualType T.
void EmitOMPTargetTaskBasedDirective(const OMPExecutableDirective &S, const RegionCodeGenTy &BodyGen, OMPTargetDataInfo &InputInfo)
Address EmitPointerWithAlignment(const Expr *Addr, LValueBaseInfo *BaseInfo=nullptr, TBAAAccessInfo *TBAAInfo=nullptr, KnownNonNull_t IsKnownNonNull=NotKnownNonNull)
EmitPointerWithAlignment - Given an expression with a pointer type, emit the value and compute our be...
Definition CGExpr.cpp:1625
static void EmitOMPTargetTeamsDistributeParallelForSimdDeviceFunction(CodeGenModule &CGM, StringRef ParentName, const OMPTargetTeamsDistributeParallelForSimdDirective &S)
Emit device code for the target teams distribute parallel for simd directive.
void EmitBranch(llvm::BasicBlock *Block)
EmitBranch - Emit a branch to the specified basic block from the current insert block,...
Definition CGStmt.cpp:675
llvm::Function * GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S, const OMPExecutableDirective &D)
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:199
void EmitVarDecl(const VarDecl &D)
EmitVarDecl - Emit a local variable declaration.
Definition CGDecl.cpp:211
llvm::Value * EmitCheckedInBoundsGEP(llvm::Type *ElemTy, llvm::Value *Ptr, ArrayRef< llvm::Value * > IdxList, bool SignedIndices, bool IsSubtraction, SourceLocation Loc, const Twine &Name="")
Same as IRBuilder::CreateInBoundsGEP, but additionally emits a check to detect undefined behavior whe...
static void EmitOMPTargetParallelGenericLoopDeviceFunction(CodeGenModule &CGM, StringRef ParentName, const OMPTargetParallelGenericLoopDirective &S)
Emit device code for the target parallel loop directive.
llvm::Value * EmitScalarExpr(const Expr *E, bool IgnoreResultAssign=false)
EmitScalarExpr - Emit the computation of the specified expression of LLVM scalar type,...
static bool IsWrappedCXXThis(const Expr *E)
Check if E is a C++ "this" pointer wrapped in value-preserving casts.
Definition CGExpr.cpp:1683
LValue MakeAddrLValue(Address Addr, QualType T, AlignmentSource Source=AlignmentSource::Type)
void FinishFunction(SourceLocation EndLoc=SourceLocation())
FinishFunction - Complete IR generation of the current function.
void EmitAtomicStore(RValue rvalue, LValue lvalue, bool isInit)
static void EmitOMPTargetSimdDeviceFunction(CodeGenModule &CGM, StringRef ParentName, const OMPTargetSimdDirective &S)
Emit device code for the target simd directive.
static void EmitOMPTargetParallelForDeviceFunction(CodeGenModule &CGM, StringRef ParentName, const OMPTargetParallelForDirective &S)
Emit device code for the target parallel for directive.
Address GetAddrOfLocalVar(const VarDecl *VD)
GetAddrOfLocalVar - Return the address of a local variable.
bool ConstantFoldsToSimpleInteger(const Expr *Cond, bool &Result, bool AllowLabels=false)
ConstantFoldsToSimpleInteger - If the specified expression does not fold to a constant,...
static void EmitOMPTargetTeamsGenericLoopDeviceFunction(CodeGenModule &CGM, StringRef ParentName, const OMPTargetTeamsGenericLoopDirective &S)
Emit device code for the target teams loop directive.
LValue EmitMemberExpr(const MemberExpr *E)
Definition CGExpr.cpp:5760
std::pair< llvm::Value *, llvm::Value * > ComplexPairTy
Address ReturnValue
ReturnValue - The temporary alloca to hold the return value.
LValue EmitLValue(const Expr *E, KnownNonNull_t IsKnownNonNull=NotKnownNonNull)
EmitLValue - Emit code to compute a designator that specifies the location of the expression.
Definition CGExpr.cpp:1741
void incrementProfileCounter(const Stmt *S, llvm::Value *StepV=nullptr)
Increment the profiler's counter for the given statement by StepV.
static void EmitOMPTargetTeamsDistributeSimdDeviceFunction(CodeGenModule &CGM, StringRef ParentName, const OMPTargetTeamsDistributeSimdDirective &S)
Emit device code for the target teams distribute simd directive.
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 EmitVariablyModifiedType(QualType Ty)
EmitVLASize - Capture all the sizes for the VLA expressions in the given variably-modified type and s...
bool isTrivialInitializer(const Expr *Init)
Determine whether the given initializer is trivial in the sense that it requires no code to be genera...
Definition CGDecl.cpp:1866
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:655
void EmitExprAsInit(const Expr *init, const ValueDecl *D, LValue lvalue, bool capturedByInit)
EmitExprAsInit - Emits the code necessary to initialize a location in memory with the given initializ...
Definition CGDecl.cpp:2176
LValue MakeNaturalAlignRawAddrLValue(llvm::Value *V, QualType T)
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 IntrusiveRefCntPtr< llvm::vfs::FileSystem > & getFileSystem() const
DiagnosticsEngine & getDiags() const
const LangOptions & getLangOpts() const
CharUnits getNaturalTypeAlignment(QualType T, LValueBaseInfo *BaseInfo=nullptr, TBAAAccessInfo *TBAAInfo=nullptr, bool forPointeeType=false)
const llvm::DataLayout & getDataLayout() const
CGOpenMPRuntime & getOpenMPRuntime()
Return a reference to the configured OpenMP runtime.
TBAAAccessInfo getTBAAInfoForSubobject(LValue Base, QualType AccessType)
getTBAAInfoForSubobject - Get TBAA information for an access with a given base lvalue.
ASTContext & getContext() const
const CodeGenOptions & getCodeGenOpts() const
StringRef getMangledName(GlobalDecl GD)
std::optional< CharUnits > getOMPAllocateAlignment(const VarDecl *VD)
Return the alignment specified in an allocate directive, if present.
Definition CGDecl.cpp:3036
llvm::Constant * EmitNullConstant(QualType T)
Return the result of value-initializing the given type, i.e.
llvm::Type * ConvertType(QualType T)
ConvertType - Convert type T into a llvm::Type.
llvm::FunctionType * GetFunctionType(const CGFunctionInfo &Info)
GetFunctionType - Get the LLVM function type for.
Definition CGCall.cpp:2081
const CGFunctionInfo & arrangeBuiltinFunctionDeclaration(QualType resultType, const FunctionArgList &args)
A builtin function is a freestanding function using the default C conventions.
Definition CGCall.cpp:774
const CGRecordLayout & getCGRecordLayout(const RecordDecl *)
getCGRecordLayout - Return record layout info for the given record decl.
llvm::GlobalVariable * GetAddrOfVTable(const CXXRecordDecl *RD)
GetAddrOfVTable - Get the address of the VTable for the given record decl.
Definition CGVTables.cpp:43
A specialization of Address that requires the address to be an LLVM Constant.
Definition Address.h:296
static ConstantAddress invalid()
Definition Address.h:304
void pushTerminate()
Push a terminate handler on the stack.
void popTerminate()
Pops a terminate handler off the stack.
Definition CGCleanup.h:658
FunctionArgList - Type for representing both the decl and type of parameters to a function.
Definition CGCall.h:378
LValue - This represents an lvalue references.
Definition CGValue.h:183
CharUnits getAlignment() const
Definition CGValue.h:355
llvm::Value * getPointer(CodeGenFunction &CGF) const
const Qualifiers & getQuals() const
Definition CGValue.h:350
Address getAddress() const
Definition CGValue.h:373
LValueBaseInfo getBaseInfo() const
Definition CGValue.h:358
QualType getType() const
Definition CGValue.h:303
TBAAAccessInfo getTBAAInfo() const
Definition CGValue.h:347
A basic class for pre|post-action for advanced codegen sequence for OpenMP region.
virtual void Enter(CodeGenFunction &CGF)
RValue - This trivial value class is used to represent the result of an expression that is evaluated.
Definition CGValue.h:42
static RValue get(llvm::Value *V)
Definition CGValue.h:99
static RValue getComplex(llvm::Value *V1, llvm::Value *V2)
Definition CGValue.h:109
llvm::Value * getScalarVal() const
getScalarVal() - Return the Value* of this scalar value.
Definition CGValue.h:72
An abstract representation of an aligned address.
Definition Address.h:42
llvm::Type * getElementType() const
Return the type of the values stored in this address.
Definition Address.h:77
llvm::Value * getPointer() const
Definition Address.h:66
static RawAddress invalid()
Definition Address.h:61
Class intended to support codegen of all kind of the reduction clauses.
LValue getSharedLValue(unsigned N) const
Returns LValue for the reduction item.
const Expr * getRefExpr(unsigned N) const
Returns the base declaration of the reduction item.
LValue getOrigLValue(unsigned N) const
Returns LValue for the original reduction item.
bool needCleanups(unsigned N)
Returns true if the private copy requires cleanups.
void emitAggregateType(CodeGenFunction &CGF, unsigned N)
Emits the code for the variable-modified type, if required.
const VarDecl * getBaseDecl(unsigned N) const
Returns the base declaration of the reduction item.
QualType getPrivateType(unsigned N) const
Return the type of the private item.
bool usesReductionInitializer(unsigned N) const
Returns true if the initialization of the reduction item uses initializer from declare reduction cons...
void emitSharedOrigLValue(CodeGenFunction &CGF, unsigned N)
Emits lvalue for the shared and original reduction item.
void emitInitialization(CodeGenFunction &CGF, unsigned N, Address PrivateAddr, Address SharedAddr, llvm::function_ref< bool(CodeGenFunction &)> DefaultInit)
Performs initialization of the private copy for the reduction item.
std::pair< llvm::Value *, llvm::Value * > getSizes(unsigned N) const
Returns the size of the reduction item (in chars and total number of elements in the item),...
ReductionCodeGen(ArrayRef< const Expr * > Shareds, ArrayRef< const Expr * > Origs, ArrayRef< const Expr * > Privates, ArrayRef< const Expr * > ReductionOps)
void emitCleanups(CodeGenFunction &CGF, unsigned N, Address PrivateAddr)
Emits cleanup code for the reduction item.
Address adjustPrivateAddress(CodeGenFunction &CGF, unsigned N, Address PrivateAddr)
Adjusts PrivatedAddr for using instead of the original variable address in normal operations.
Class provides a way to call simple version of codegen for OpenMP region, or an advanced with possibl...
void operator()(CodeGenFunction &CGF) const
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.
A reference to a declared variable, function, enum, etc.
Definition Expr.h:1294
ValueDecl * getDecl()
Definition Expr.h:1362
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
T * getAttr() const
Definition DeclBase.h:581
bool hasAttrs() const
Definition DeclBase.h:526
ASTContext & getASTContext() const LLVM_READONLY
Definition DeclBase.cpp:550
void addAttr(Attr *A)
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
Definition DeclBase.h:1104
llvm::iterator_range< specific_attr_iterator< T > > specific_attrs() const
Definition DeclBase.h:567
SourceLocation getLocation() const
Definition DeclBase.h:447
DeclContext * getDeclContext()
Definition DeclBase.h:456
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:832
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
This represents one expression.
Definition Expr.h:113
bool isIntegerConstantExpr(const ASTContext &Ctx) const
bool isGLValue() const
Definition Expr.h:288
Expr * IgnoreParenNoopCasts(const ASTContext &Ctx) LLVM_READONLY
Skip past any parentheses and casts which do not change the value (including ptr->int casts of the sa...
Definition Expr.cpp:3153
@ SE_AllowSideEffects
Allow any unmodeled side effect.
Definition Expr.h:695
@ SE_AllowUndefinedBehavior
Allow UB that we can give a value, but not arbitrary unmodeled side effects.
Definition Expr.h:693
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Definition Expr.cpp:3131
llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx) const
EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded integer.
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Definition Expr.cpp:3126
bool isEvaluatable(const ASTContext &Ctx, SideEffectsKind AllowSideEffects=SE_NoSideEffects) const
isEvaluatable - Call EvaluateAsRValue to see if this expression can be constant folded without side-e...
bool HasSideEffects(const ASTContext &Ctx, bool IncludePossibleEffects=true) const
HasSideEffects - This routine returns true for all those expressions which have any effect other than...
Definition Expr.cpp:3725
std::optional< llvm::APSInt > getIntegerConstantExpr(const ASTContext &Ctx, bool AllowRelaxedEval=false) const
isIntegerConstantExpr - Return the value if this expression is a valid integer constant expression.
bool EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx, bool InConstantContext=false) const
EvaluateAsBooleanCondition - Return true if this is a constant which we can fold and convert to a boo...
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition Expr.cpp:283
static bool isSameComparisonOperand(const Expr *E1, const Expr *E2)
Checks that the two Expr's will refer to the same value as a comparison operand.
Definition Expr.cpp:4366
QualType getType() const
Definition Expr.h:145
bool hasNonTrivialCall(const ASTContext &Ctx) const
Determine whether this expression involves a call to any function that is not trivial.
Definition Expr.cpp:4095
Represents a member of a struct/union/class.
Definition Decl.h:3295
unsigned getFieldIndex() const
Returns the index of this field within its record, as appropriate for passing to ASTRecordLayout::get...
Definition Decl.h:3380
const RecordDecl * getParent() const
Returns the parent of this field declaration, which is the struct in which this field is defined.
Definition Decl.h:3531
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:4770
Represents a function declaration or definition.
Definition Decl.h:2059
const ParmVarDecl * getParamDecl(unsigned i) const
Definition Decl.h:2928
QualType getReturnType() const
Definition Decl.h:2976
ArrayRef< ParmVarDecl * > parameters() const
Definition Decl.h:2905
FunctionDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
Definition Decl.cpp:3794
FunctionDecl * getMostRecentDecl()
Returns the most recent (re)declaration of this declaration.
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
Definition Decl.cpp:3873
FunctionDecl * getPreviousDecl()
Return the previous declaration of this declaration or NULL if this is the first declaration.
GlobalDecl - represents a global declaration.
Definition GlobalDecl.h:60
const Decl * getDecl() const
Definition GlobalDecl.h:115
static ImplicitParamDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation IdLoc, const IdentifierInfo *Id, QualType T, ImplicitParamKind ParamKind)
Create implicit parameter.
Definition Decl.cpp:5678
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:985
An lvalue reference type, per C++11 [dcl.ref].
Definition TypeBase.h:3715
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition Expr.h:3412
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
Definition Expr.h:3495
Expr * getBase() const
Definition Expr.h:3489
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition Decl.h:302
bool isExternallyVisible() const
Definition Decl.h:434
const Stmt * getPreInitStmt() const
Get pre-initialization statement for the clause.
This is a basic class for representing single OpenMP clause.
ArrayRef< OMPClause * > clauses() const
Definition DeclOpenMP.h:91
This represents 'pragma omp declare mapper ...' directive.
Definition DeclOpenMP.h:349
Expr * getMapperVarRef()
Get the variable declared in the mapper.
Definition DeclOpenMP.h:411
This represents 'pragma omp declare reduction ...' directive.
Definition DeclOpenMP.h:239
Expr * getInitializer()
Get initializer expression (if specified) of the declare reduction construct.
Definition DeclOpenMP.h:300
Expr * getInitPriv()
Get Priv variable of the initializer.
Definition DeclOpenMP.h:311
Expr * getCombinerOut()
Get Out variable of the combiner.
Definition DeclOpenMP.h:288
Expr * getCombinerIn()
Get In variable of the combiner.
Definition DeclOpenMP.h:285
Expr * getCombiner()
Get combiner expression of the declare reduction construct.
Definition DeclOpenMP.h:282
Expr * getInitOrig()
Get Orig variable of the initializer.
Definition DeclOpenMP.h:308
OMPDeclareReductionInitKind getInitializerKind() const
Get initializer kind.
Definition DeclOpenMP.h:303
This represents 'if' clause in the 'pragma omp ...' directive.
Expr * getCondition() const
Returns condition.
OMPIteratorHelperData & getHelper(unsigned I)
Fetches helper data for the specified iteration space.
Definition Expr.cpp:5647
unsigned numOfIterators() const
Returns number of iterator definitions.
Definition ExprOpenMP.h:275
This represents 'num_threads' clause in the 'pragma omp ...' directive.
This represents 'pragma omp requires...' directive.
Definition DeclOpenMP.h:479
clauselist_range clauselists()
Definition DeclOpenMP.h:504
This represents 'threadset' clause in the 'pragma omp task ...' directive.
OpaqueValueExpr - An expression referring to an opaque object of a fixed type and value class.
Definition Expr.h:1202
Represents a parameter to a function.
Definition Decl.h:1820
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition TypeBase.h:3403
Represents an unpacked "presumed" location which can be presented to the user.
unsigned getColumn() const
Return the presumed column number of this location.
const char * getFilename() const
Return the presumed filename of this location.
unsigned getLine() const
Return the presumed line number of this location.
A (possibly-)qualified type.
Definition TypeBase.h:938
void addRestrict()
Add the restrict qualifier to this QualType.
Definition TypeBase.h:1188
QualType withRestrict() const
Definition TypeBase.h:1191
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1005
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition TypeBase.h:8446
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
Definition TypeBase.h:8486
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:8631
QualType getCanonicalType() const
Definition TypeBase.h:8498
DestructionKind isDestructedType() const
Returns a nonzero value if objects of this type require non-trivial work to clean up after.
Definition TypeBase.h:1561
Represents a struct/union/class.
Definition Decl.h:4460
field_iterator field_end() const
Definition Decl.h:4666
field_range fields() const
Definition Decl.h:4663
virtual void completeDefinition()
Note that the definition of this type is now complete.
Definition Decl.cpp:5367
bool field_empty() const
Definition Decl.h:4671
field_iterator field_begin() const
Definition Decl.cpp:5351
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.
static SourceLocation getFromRawEncoding(UIntTy Encoding)
Turn a raw encoding of a SourceLocation object into a real SourceLocation.
bool isValid() const
Return true if this is a valid SourceLocation object.
UIntTy getRawEncoding() const
When a SourceLocation itself cannot be used, this returns an (opaque) 32-bit integer encoding for it.
This class handles loading and caching of source files into memory.
PresumedLoc getPresumedLoc(SourceLocation Loc, bool UseLineDirectives=true) const
Returns the "presumed" location of a SourceLocation specifies.
Stmt - This represents one statement.
Definition Stmt.h:85
child_range children()
Definition Stmt.cpp:304
StmtClass getStmtClass() const
Definition Stmt.h:1505
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:343
Stmt * IgnoreContainers(bool IgnoreCaptured=false)
Skip no-op (attributed, compound) container stmts and skip captured stmt at the top,...
Definition Stmt.cpp:210
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Stmt.cpp:355
void startDefinition()
Starts the definition of this tag declaration.
Definition Decl.cpp:4982
bool isUnion() const
Definition Decl.h:4063
The base class of the type hierarchy.
Definition TypeBase.h:1879
bool isVoidType() const
Definition TypeBase.h:9068
const Type * getPointeeOrArrayElementType() const
If this is a pointer type, return the pointee type.
Definition TypeBase.h:9259
bool isSignedIntegerType() const
Return true if this is an integer type that is signed, according to C99 6.2.5p4 [char,...
Definition Type.cpp:2392
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition Type.h:26
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Definition Type.h:41
bool isArrayType() const
Definition TypeBase.h:8782
bool isPointerType() const
Definition TypeBase.h:8683
CanQualType getCanonicalTypeUnqualified() const
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
Definition TypeBase.h:9116
const T * castAs() const
Member-template castAs<specific type>.
Definition TypeBase.h:9366
bool isReferenceType() const
Definition TypeBase.h:8707
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:885
bool isLValueReferenceType() const
Definition TypeBase.h:8711
bool isAggregateType() const
Determines whether the type is a C++ aggregate type or C aggregate or union type.
Definition Type.cpp:2631
RecordDecl * castAsRecordDecl() const
Definition Type.h:48
QualType getCanonicalTypeInternal() const
Definition TypeBase.h:3200
const Type * getBaseElementTypeUnsafe() const
Get the base element type of this type, potentially discarding type qualifiers.
Definition TypeBase.h:9252
bool isVariablyModifiedType() const
Whether this type is a variably-modified type (C99 6.7.5).
Definition TypeBase.h:2881
const ArrayType * getAsArrayTypeUnsafe() const
A variant of getAs<> for array types which silently discards qualifiers from the outermost type.
Definition TypeBase.h:9352
bool isFloatingType() const
Definition Type.cpp:2517
bool isUnsignedIntegerType() const
Return true if this is an integer type that is unsigned, according to C99 6.2.5p6 [which returns true...
Definition Type.cpp:2460
bool isAnyPointerType() const
Definition TypeBase.h:8691
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9299
bool isRecordType() const
Definition TypeBase.h:8810
bool isUnionType() const
Definition Type.cpp:851
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:713
QualType getType() const
Definition Decl.h:724
Represents a variable declaration or definition.
Definition Decl.h:933
VarDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
Definition Decl.cpp:2237
VarDecl * getDefinition(ASTContext &)
Get the real (not just tentative) definition for this declaration.
Definition Decl.cpp:2351
const Expr * getInit() const
Definition Decl.h:1392
bool hasExternalStorage() const
Returns true if a variable has extern or private_extern storage.
Definition Decl.h:1239
@ DeclarationOnly
This declaration is only a declaration.
Definition Decl.h:1319
DefinitionKind hasDefinition(ASTContext &) const
Check whether this variable is defined in this translation unit.
Definition Decl.cpp:2360
bool isLocalVarDeclOrParm() const
Similar to isLocalVarDecl but also includes parameters.
Definition Decl.h:1286
const Expr * getAnyInitializer() const
Get the initializer for this variable, no matter which declaration it is attached to.
Definition Decl.h:1382
Represents a C array with a specified size that is not an integer-constant-expression.
Definition TypeBase.h:4064
Expr * getSizeExpr() const
Definition TypeBase.h:4078
specific_attr_iterator - Iterates over a subrange of an AttrVec, only providing attributes that are o...
Definition SPIR.cpp:35
bool isEmptyFieldForLayout(const ASTContext &Ctx, const FieldDecl *FD)
Return true iff the field is "empty", that is, either a zero-width bit-field or an isEmptyRecordForLa...
bool isEmptyRecordForLayout(const ASTContext &Ctx, QualType T)
Return true iff a structure contains only empty base classes (per isEmptyRecordForLayout) and fields ...
@ 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
ComparisonResult
Indicates the result of a tentative comparison.
@ Address
A pointer to a ValueDecl.
Definition Primitives.h:28
Top level wrappers for InstallAPI frontend operations.
bool isOpenMPWorksharingDirective(OpenMPDirectiveKind DKind)
Checks if the specified directive is a worksharing directive.
CanQual< Type > CanQualType
Represents a canonical, potentially-qualified type.
bool needsTaskBasedThreadLimit(OpenMPDirectiveKind DKind)
Checks if the specified target directive, combined or not, needs task based thread_limit.
@ Match
This is not an overload because the signature exactly matches an existing declaration.
Definition Sema.h:824
@ Ctor_Complete
Complete object ctor.
Definition ABI.h:25
Privates[]
This class represents the 'transparent' clause in the 'pragma omp task' directive.
bool isa(CodeGen::Address addr)
Definition Address.h:330
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
bool isOpenMPTargetDataManagementDirective(OpenMPDirectiveKind DKind)
Checks if the specified directive is a target data offload directive.
static bool classof(const OMPClause *T)
Stmt Stmt * Callback
Definition StmtOpenMP.h:930
@ Conditional
A conditional (?:) operator.
Definition Sema.h:663
@ ICIS_NoInit
No in-class initializer.
Definition Specifiers.h:276
bool isOpenMPDistributeDirective(OpenMPDirectiveKind DKind)
Checks if the specified directive is a distribute directive.
@ LCK_ByRef
Capturing by reference.
Definition Lambda.h:37
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE()
@ Private
'private' clause, allowed on 'parallel', 'serial', 'loop', 'parallel loop', and 'serial loop' constru...
@ Reduction
'reduction' clause, allowed on Parallel, Serial, Loop, and the combined constructs.
@ Present
'present' clause, allowed on Compute and Combined constructs, plus 'data' and 'declare'.
OpenMPScheduleClauseModifier
OpenMP modifiers for 'schedule' clause.
Definition OpenMPKinds.h:39
@ OMPC_SCHEDULE_MODIFIER_last
Definition OpenMPKinds.h:44
@ OMPC_SCHEDULE_MODIFIER_unknown
Definition OpenMPKinds.h:40
@ AS_public
Definition Specifiers.h:128
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
@ CR_OpenMP
bool isOpenMPParallelDirective(OpenMPDirectiveKind DKind)
Checks if the specified directive is a parallel-kind directive.
OpenMPDistScheduleClauseKind
OpenMP attributes for 'dist_schedule' clause.
bool isOpenMPTaskingDirective(OpenMPDirectiveKind Kind)
Checks if the specified directive kind is one of tasking directives - task, taskloop,...
bool isOpenMPTargetExecutionDirective(OpenMPDirectiveKind DKind)
Checks if the specified directive is a target code offload directive.
@ OMPC_DYN_GROUPPRIVATE_FALLBACK_unknown
@ Result
The result type of a method or function.
Definition TypeBase.h:906
bool isOpenMPTeamsDirective(OpenMPDirectiveKind DKind)
Checks if the specified directive is a teams-kind directive.
const FunctionProtoType * T
OpenMPDependClauseKind
OpenMP attributes for 'depend' clause.
Definition OpenMPKinds.h:55
@ OMPC_DEPEND_unknown
Definition OpenMPKinds.h:59
@ Dtor_Complete
Complete object dtor.
Definition ABI.h:36
@ Union
The "union" keyword.
Definition TypeBase.h:6047
bool isOpenMPTargetMapEnteringDirective(OpenMPDirectiveKind DKind)
Checks if the specified directive is a map-entering target directive.
bool isOpenMPLoopDirective(OpenMPDirectiveKind DKind)
Checks if the specified directive is a directive with an associated loop construct.
OpenMPSeverityClauseKind
OpenMP attributes for 'severity' clause.
LangAS
Defines the address space values used by the address space qualifier of QualType.
llvm::omp::Directive OpenMPDirectiveKind
OpenMP directives.
Definition OpenMPKinds.h:25
bool isOpenMPSimdDirective(OpenMPDirectiveKind DKind)
Checks if the specified directive is a simd directive.
@ VK_PRValue
A pr-value expression (in the C++11 taxonomy) produces a temporary value.
Definition Specifiers.h:139
@ VK_LValue
An l-value expression is a reference to an object with independent storage.
Definition Specifiers.h:143
for(const auto &A :T->param_types())
void getOpenMPCaptureRegions(llvm::SmallVectorImpl< OpenMPDirectiveKind > &CaptureRegions, OpenMPDirectiveKind DKind)
Return the captured regions of an OpenMP directive.
OpenMPNumThreadsClauseModifier
@ OMPC_ATOMIC_DEFAULT_MEM_ORDER_unknown
U cast(CodeGen::Address addr)
Definition Address.h:327
@ OMPC_DEVICE_unknown
Definition OpenMPKinds.h:51
OpenMPMapModifierKind
OpenMP modifier kind for 'map' clause.
Definition OpenMPKinds.h:79
@ OMPC_MAP_MODIFIER_unknown
Definition OpenMPKinds.h:80
@ Other
Other implicit parameter.
Definition Decl.h:1775
OpenMPScheduleClauseKind
OpenMP attributes for 'schedule' clause.
Definition OpenMPKinds.h:31
@ OMPC_SCHEDULE_unknown
Definition OpenMPKinds.h:35
bool isOpenMPTaskLoopDirective(OpenMPDirectiveKind DKind)
Checks if the specified directive is a taskloop directive.
OpenMPThreadsetKind
OpenMP modifiers for 'threadset' clause.
OpenMPMapClauseKind
OpenMP mapping kind for 'map' clause.
Definition OpenMPKinds.h:71
@ OMPC_MAP_unknown
Definition OpenMPKinds.h:75
unsigned long uint64_t
Diagnostic wrappers for TextAPI types for error reporting.
Definition Dominators.h:30
int32_t uint32_t
#define false
Definition stdbool.h:26
Data for list of allocators.
Expr * AllocatorTraits
Allocator traits.
struct with the values to be passed to the dispatch runtime function
llvm::Value * Chunk
Chunk size specified using 'schedule' clause (nullptr if chunk was not specified)
Maps the expression for the lastprivate variable to the global copy used to store new value because o...
Struct with the values to be passed to the static runtime function.
bool IVSigned
Sign of the iteration variable.
Address UB
Address of the output variable in which the upper iteration number is returned.
Address IL
Address of the output variable in which the flag of the last iteration is returned.
llvm::Value * Chunk
Value of the chunk for the static_chunked scheduled loop.
unsigned IVSize
Size of the iteration variable in bits.
Address ST
Address of the output variable in which the stride value is returned necessary to generated the stati...
bool Ordered
true if loop is ordered, false otherwise.
Address LB
Address of the output variable in which the lower iteration number is returned.
A jump destination is an abstract label, branching to which may require a jump out through normal cle...
llvm::IntegerType * Int8Ty
i8, i16, i32, and i64
llvm::CallingConv::ID getRuntimeCC() const
SmallVector< const Expr *, 4 > DepExprs
EvalResult is a struct with detailed info about an evaluated expression.
Definition Expr.h:666
Extra information about a function prototype.
Definition TypeBase.h:5501
Expr * CounterUpdate
Updater for the internal counter: ++CounterVD;.
Definition ExprOpenMP.h:121
Scheduling data for loop-based OpenMP directives.
bool UseFusedDistChunkSchedule
Request the fused distr_static_chunk + static_chunkone runtime schedule in for_static_init.
OpenMPScheduleClauseModifier M2
OpenMPScheduleClauseModifier M1
OpenMPScheduleClauseKind Schedule
Describes how types, statements, expressions, and declarations should be printed.