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"
31#include "llvm/ADT/ArrayRef.h"
32#include "llvm/ADT/SmallSet.h"
33#include "llvm/ADT/SmallVector.h"
34#include "llvm/ADT/StringExtras.h"
35#include "llvm/Bitcode/BitcodeReader.h"
36#include "llvm/IR/Constants.h"
37#include "llvm/IR/DerivedTypes.h"
38#include "llvm/IR/GlobalValue.h"
39#include "llvm/IR/InstrTypes.h"
40#include "llvm/IR/Value.h"
41#include "llvm/Support/AtomicOrdering.h"
42#include "llvm/Support/raw_ostream.h"
43#include <cassert>
44#include <cstdint>
45#include <numeric>
46#include <optional>
47
48using namespace clang;
49using namespace CodeGen;
50using namespace llvm::omp;
51
52namespace {
53/// Base class for handling code generation inside OpenMP regions.
54class CGOpenMPRegionInfo : public CodeGenFunction::CGCapturedStmtInfo {
55public:
56 /// Kinds of OpenMP regions used in codegen.
57 enum CGOpenMPRegionKind {
58 /// Region with outlined function for standalone 'parallel'
59 /// directive.
60 ParallelOutlinedRegion,
61 /// Region with outlined function for standalone 'task' directive.
62 TaskOutlinedRegion,
63 /// Region for constructs that do not require function outlining,
64 /// like 'for', 'sections', 'atomic' etc. directives.
65 InlinedRegion,
66 /// Region with outlined function for standalone 'target' directive.
67 TargetRegion,
68 };
69
70 CGOpenMPRegionInfo(const CapturedStmt &CS,
71 const CGOpenMPRegionKind RegionKind,
72 const RegionCodeGenTy &CodeGen, OpenMPDirectiveKind Kind,
73 bool HasCancel)
74 : CGCapturedStmtInfo(CS, CR_OpenMP), RegionKind(RegionKind),
75 CodeGen(CodeGen), Kind(Kind), HasCancel(HasCancel) {}
76
77 CGOpenMPRegionInfo(const CGOpenMPRegionKind RegionKind,
78 const RegionCodeGenTy &CodeGen, OpenMPDirectiveKind Kind,
79 bool HasCancel)
80 : CGCapturedStmtInfo(CR_OpenMP), RegionKind(RegionKind), CodeGen(CodeGen),
81 Kind(Kind), HasCancel(HasCancel) {}
82
83 /// Get a variable or parameter for storing global thread id
84 /// inside OpenMP construct.
85 virtual const VarDecl *getThreadIDVariable() const = 0;
86
87 /// Emit the captured statement body.
88 void EmitBody(CodeGenFunction &CGF, const Stmt *S) override;
89
90 /// Get an LValue for the current ThreadID variable.
91 /// \return LValue for thread id variable. This LValue always has type int32*.
92 virtual LValue getThreadIDVariableLValue(CodeGenFunction &CGF);
93
94 virtual void emitUntiedSwitch(CodeGenFunction & /*CGF*/) {}
95
96 CGOpenMPRegionKind getRegionKind() const { return RegionKind; }
97
98 OpenMPDirectiveKind getDirectiveKind() const { return Kind; }
99
100 bool hasCancel() const { return HasCancel; }
101
102 static bool classof(const CGCapturedStmtInfo *Info) {
103 return Info->getKind() == CR_OpenMP;
104 }
105
106 ~CGOpenMPRegionInfo() override = default;
107
108protected:
109 CGOpenMPRegionKind RegionKind;
110 RegionCodeGenTy CodeGen;
112 bool HasCancel;
113};
114
115/// API for captured statement code generation in OpenMP constructs.
116class CGOpenMPOutlinedRegionInfo final : public CGOpenMPRegionInfo {
117public:
118 CGOpenMPOutlinedRegionInfo(const CapturedStmt &CS, const VarDecl *ThreadIDVar,
119 const RegionCodeGenTy &CodeGen,
120 OpenMPDirectiveKind Kind, bool HasCancel,
121 StringRef HelperName)
122 : CGOpenMPRegionInfo(CS, ParallelOutlinedRegion, CodeGen, Kind,
123 HasCancel),
124 ThreadIDVar(ThreadIDVar), HelperName(HelperName) {
125 assert(ThreadIDVar != nullptr && "No ThreadID in OpenMP region.");
126 }
127
128 /// Get a variable or parameter for storing global thread id
129 /// inside OpenMP construct.
130 const VarDecl *getThreadIDVariable() const override { return ThreadIDVar; }
131
132 /// Get the name of the capture helper.
133 StringRef getHelperName() const override { return HelperName; }
134
135 static bool classof(const CGCapturedStmtInfo *Info) {
136 return CGOpenMPRegionInfo::classof(Info) &&
137 cast<CGOpenMPRegionInfo>(Info)->getRegionKind() ==
138 ParallelOutlinedRegion;
139 }
140
141private:
142 /// A variable or parameter storing global thread id for OpenMP
143 /// constructs.
144 const VarDecl *ThreadIDVar;
145 StringRef HelperName;
146};
147
148/// API for captured statement code generation in OpenMP constructs.
149class CGOpenMPTaskOutlinedRegionInfo final : public CGOpenMPRegionInfo {
150public:
151 class UntiedTaskActionTy final : public PrePostActionTy {
152 bool Untied;
153 const VarDecl *PartIDVar;
154 const RegionCodeGenTy UntiedCodeGen;
155 llvm::SwitchInst *UntiedSwitch = nullptr;
156
157 public:
158 UntiedTaskActionTy(bool Tied, const VarDecl *PartIDVar,
159 const RegionCodeGenTy &UntiedCodeGen)
160 : Untied(!Tied), PartIDVar(PartIDVar), UntiedCodeGen(UntiedCodeGen) {}
161 void Enter(CodeGenFunction &CGF) override {
162 if (Untied) {
163 // Emit task switching point.
164 LValue PartIdLVal = CGF.EmitLoadOfPointerLValue(
165 CGF.GetAddrOfLocalVar(PartIDVar),
166 PartIDVar->getType()->castAs<PointerType>());
167 llvm::Value *Res =
168 CGF.EmitLoadOfScalar(PartIdLVal, PartIDVar->getLocation());
169 llvm::BasicBlock *DoneBB = CGF.createBasicBlock(".untied.done.");
170 UntiedSwitch = CGF.Builder.CreateSwitch(Res, DoneBB);
171 CGF.EmitBlock(DoneBB);
173 CGF.EmitBlock(CGF.createBasicBlock(".untied.jmp."));
174 UntiedSwitch->addCase(CGF.Builder.getInt32(0),
175 CGF.Builder.GetInsertBlock());
176 emitUntiedSwitch(CGF);
177 }
178 }
179 void emitUntiedSwitch(CodeGenFunction &CGF) const {
180 if (Untied) {
181 LValue PartIdLVal = CGF.EmitLoadOfPointerLValue(
182 CGF.GetAddrOfLocalVar(PartIDVar),
183 PartIDVar->getType()->castAs<PointerType>());
184 CGF.EmitStoreOfScalar(CGF.Builder.getInt32(UntiedSwitch->getNumCases()),
185 PartIdLVal);
186 UntiedCodeGen(CGF);
187 CodeGenFunction::JumpDest CurPoint =
188 CGF.getJumpDestInCurrentScope(".untied.next.");
190 CGF.EmitBlock(CGF.createBasicBlock(".untied.jmp."));
191 UntiedSwitch->addCase(CGF.Builder.getInt32(UntiedSwitch->getNumCases()),
192 CGF.Builder.GetInsertBlock());
193 CGF.EmitBranchThroughCleanup(CurPoint);
194 CGF.EmitBlock(CurPoint.getBlock());
195 }
196 }
197 unsigned getNumberOfParts() const { return UntiedSwitch->getNumCases(); }
198 };
199 CGOpenMPTaskOutlinedRegionInfo(const CapturedStmt &CS,
200 const VarDecl *ThreadIDVar,
201 const RegionCodeGenTy &CodeGen,
202 OpenMPDirectiveKind Kind, bool HasCancel,
203 const UntiedTaskActionTy &Action)
204 : CGOpenMPRegionInfo(CS, TaskOutlinedRegion, CodeGen, Kind, HasCancel),
205 ThreadIDVar(ThreadIDVar), Action(Action) {
206 assert(ThreadIDVar != nullptr && "No ThreadID in OpenMP region.");
207 }
208
209 /// Get a variable or parameter for storing global thread id
210 /// inside OpenMP construct.
211 const VarDecl *getThreadIDVariable() const override { return ThreadIDVar; }
212
213 /// Get an LValue for the current ThreadID variable.
214 LValue getThreadIDVariableLValue(CodeGenFunction &CGF) override;
215
216 /// Get the name of the capture helper.
217 StringRef getHelperName() const override { return ".omp_outlined."; }
218
219 void emitUntiedSwitch(CodeGenFunction &CGF) override {
220 Action.emitUntiedSwitch(CGF);
221 }
222
223 static bool classof(const CGCapturedStmtInfo *Info) {
224 return CGOpenMPRegionInfo::classof(Info) &&
225 cast<CGOpenMPRegionInfo>(Info)->getRegionKind() ==
226 TaskOutlinedRegion;
227 }
228
229private:
230 /// A variable or parameter storing global thread id for OpenMP
231 /// constructs.
232 const VarDecl *ThreadIDVar;
233 /// Action for emitting code for untied tasks.
234 const UntiedTaskActionTy &Action;
235};
236
237/// API for inlined captured statement code generation in OpenMP
238/// constructs.
239class CGOpenMPInlinedRegionInfo : public CGOpenMPRegionInfo {
240public:
241 CGOpenMPInlinedRegionInfo(CodeGenFunction::CGCapturedStmtInfo *OldCSI,
242 const RegionCodeGenTy &CodeGen,
243 OpenMPDirectiveKind Kind, bool HasCancel)
244 : CGOpenMPRegionInfo(InlinedRegion, CodeGen, Kind, HasCancel),
245 OldCSI(OldCSI),
246 OuterRegionInfo(dyn_cast_or_null<CGOpenMPRegionInfo>(OldCSI)) {}
247
248 // Retrieve the value of the context parameter.
249 llvm::Value *getContextValue() const override {
250 if (OuterRegionInfo)
251 return OuterRegionInfo->getContextValue();
252 llvm_unreachable("No context value for inlined OpenMP region");
253 }
254
255 void setContextValue(llvm::Value *V) override {
256 if (OuterRegionInfo) {
257 OuterRegionInfo->setContextValue(V);
258 return;
259 }
260 llvm_unreachable("No context value for inlined OpenMP region");
261 }
262
263 /// Lookup the captured field decl for a variable.
264 const FieldDecl *lookup(const VarDecl *VD) const override {
265 if (OuterRegionInfo)
266 return OuterRegionInfo->lookup(VD);
267 // If there is no outer outlined region,no need to lookup in a list of
268 // captured variables, we can use the original one.
269 return nullptr;
270 }
271
272 FieldDecl *getThisFieldDecl() const override {
273 if (OuterRegionInfo)
274 return OuterRegionInfo->getThisFieldDecl();
275 return nullptr;
276 }
277
278 /// Get a variable or parameter for storing global thread id
279 /// inside OpenMP construct.
280 const VarDecl *getThreadIDVariable() const override {
281 if (OuterRegionInfo)
282 return OuterRegionInfo->getThreadIDVariable();
283 return nullptr;
284 }
285
286 /// Get an LValue for the current ThreadID variable.
287 LValue getThreadIDVariableLValue(CodeGenFunction &CGF) override {
288 if (OuterRegionInfo)
289 return OuterRegionInfo->getThreadIDVariableLValue(CGF);
290 llvm_unreachable("No LValue for inlined OpenMP construct");
291 }
292
293 /// Get the name of the capture helper.
294 StringRef getHelperName() const override {
295 if (auto *OuterRegionInfo = getOldCSI())
296 return OuterRegionInfo->getHelperName();
297 llvm_unreachable("No helper name for inlined OpenMP construct");
298 }
299
300 void emitUntiedSwitch(CodeGenFunction &CGF) override {
301 if (OuterRegionInfo)
302 OuterRegionInfo->emitUntiedSwitch(CGF);
303 }
304
305 CodeGenFunction::CGCapturedStmtInfo *getOldCSI() const { return OldCSI; }
306
307 static bool classof(const CGCapturedStmtInfo *Info) {
308 return CGOpenMPRegionInfo::classof(Info) &&
309 cast<CGOpenMPRegionInfo>(Info)->getRegionKind() == InlinedRegion;
310 }
311
312 ~CGOpenMPInlinedRegionInfo() override = default;
313
314private:
315 /// CodeGen info about outer OpenMP region.
316 CodeGenFunction::CGCapturedStmtInfo *OldCSI;
317 CGOpenMPRegionInfo *OuterRegionInfo;
318};
319
320/// API for captured statement code generation in OpenMP target
321/// constructs. For this captures, implicit parameters are used instead of the
322/// captured fields. The name of the target region has to be unique in a given
323/// application so it is provided by the client, because only the client has
324/// the information to generate that.
325class CGOpenMPTargetRegionInfo final : public CGOpenMPRegionInfo {
326public:
327 CGOpenMPTargetRegionInfo(const CapturedStmt &CS,
328 const RegionCodeGenTy &CodeGen, StringRef HelperName)
329 : CGOpenMPRegionInfo(CS, TargetRegion, CodeGen, OMPD_target,
330 /*HasCancel=*/false),
331 HelperName(HelperName) {}
332
333 /// This is unused for target regions because each starts executing
334 /// with a single thread.
335 const VarDecl *getThreadIDVariable() const override { return nullptr; }
336
337 /// Get the name of the capture helper.
338 StringRef getHelperName() const override { return HelperName; }
339
340 static bool classof(const CGCapturedStmtInfo *Info) {
341 return CGOpenMPRegionInfo::classof(Info) &&
342 cast<CGOpenMPRegionInfo>(Info)->getRegionKind() == TargetRegion;
343 }
344
345private:
346 StringRef HelperName;
347};
348
349static void EmptyCodeGen(CodeGenFunction &, PrePostActionTy &) {
350 llvm_unreachable("No codegen for expressions");
351}
352/// API for generation of expressions captured in a innermost OpenMP
353/// region.
354class CGOpenMPInnerExprInfo final : public CGOpenMPInlinedRegionInfo {
355public:
356 CGOpenMPInnerExprInfo(CodeGenFunction &CGF, const CapturedStmt &CS)
357 : CGOpenMPInlinedRegionInfo(CGF.CapturedStmtInfo, EmptyCodeGen,
358 OMPD_unknown,
359 /*HasCancel=*/false),
360 PrivScope(CGF) {
361 // Make sure the globals captured in the provided statement are local by
362 // using the privatization logic. We assume the same variable is not
363 // captured more than once.
364 for (const auto &C : CS.captures()) {
365 if (!C.capturesVariable() && !C.capturesVariableByCopy())
366 continue;
367
368 const VarDecl *VD = C.getCapturedVar();
369 if (VD->isLocalVarDeclOrParm())
370 continue;
371
372 DeclRefExpr DRE(CGF.getContext(), const_cast<VarDecl *>(VD),
373 /*RefersToEnclosingVariableOrCapture=*/false,
374 VD->getType().getNonReferenceType(), VK_LValue,
375 C.getLocation());
376 PrivScope.addPrivate(VD, CGF.EmitLValue(&DRE).getAddress());
377 }
378 (void)PrivScope.Privatize();
379 }
380
381 /// Lookup the captured field decl for a variable.
382 const FieldDecl *lookup(const VarDecl *VD) const override {
383 if (const FieldDecl *FD = CGOpenMPInlinedRegionInfo::lookup(VD))
384 return FD;
385 return nullptr;
386 }
387
388 /// Emit the captured statement body.
389 void EmitBody(CodeGenFunction &CGF, const Stmt *S) override {
390 llvm_unreachable("No body for expressions");
391 }
392
393 /// Get a variable or parameter for storing global thread id
394 /// inside OpenMP construct.
395 const VarDecl *getThreadIDVariable() const override {
396 llvm_unreachable("No thread id for expressions");
397 }
398
399 /// Get the name of the capture helper.
400 StringRef getHelperName() const override {
401 llvm_unreachable("No helper name for expressions");
402 }
403
404 static bool classof(const CGCapturedStmtInfo *Info) { return false; }
405
406private:
407 /// Private scope to capture global variables.
408 CodeGenFunction::OMPPrivateScope PrivScope;
409};
410
411/// RAII for emitting code of OpenMP constructs.
412class InlinedOpenMPRegionRAII {
413 CodeGenFunction &CGF;
414 llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
415 FieldDecl *LambdaThisCaptureField = nullptr;
416 const CodeGen::CGBlockInfo *BlockInfo = nullptr;
417 bool NoInheritance = false;
418
419public:
420 /// Constructs region for combined constructs.
421 /// \param CodeGen Code generation sequence for combined directives. Includes
422 /// a list of functions used for code generation of implicitly inlined
423 /// regions.
424 InlinedOpenMPRegionRAII(CodeGenFunction &CGF, const RegionCodeGenTy &CodeGen,
425 OpenMPDirectiveKind Kind, bool HasCancel,
426 bool NoInheritance = true)
427 : CGF(CGF), NoInheritance(NoInheritance) {
428 // Start emission for the construct.
429 CGF.CapturedStmtInfo = new CGOpenMPInlinedRegionInfo(
430 CGF.CapturedStmtInfo, CodeGen, Kind, HasCancel);
431 if (NoInheritance) {
432 std::swap(CGF.LambdaCaptureFields, LambdaCaptureFields);
433 LambdaThisCaptureField = CGF.LambdaThisCaptureField;
434 CGF.LambdaThisCaptureField = nullptr;
435 BlockInfo = CGF.BlockInfo;
436 CGF.BlockInfo = nullptr;
437 }
438 }
439
440 ~InlinedOpenMPRegionRAII() {
441 // Restore original CapturedStmtInfo only if we're done with code emission.
442 auto *OldCSI =
443 cast<CGOpenMPInlinedRegionInfo>(CGF.CapturedStmtInfo)->getOldCSI();
444 delete CGF.CapturedStmtInfo;
445 CGF.CapturedStmtInfo = OldCSI;
446 if (NoInheritance) {
447 std::swap(CGF.LambdaCaptureFields, LambdaCaptureFields);
448 CGF.LambdaThisCaptureField = LambdaThisCaptureField;
449 CGF.BlockInfo = BlockInfo;
450 }
451 }
452};
453
454/// Values for bit flags used in the ident_t to describe the fields.
455/// All enumeric elements are named and described in accordance with the code
456/// from https://github.com/llvm/llvm-project/blob/main/openmp/runtime/src/kmp.h
457enum OpenMPLocationFlags : unsigned {
458 /// Use trampoline for internal microtask.
459 OMP_IDENT_IMD = 0x01,
460 /// Use c-style ident structure.
461 OMP_IDENT_KMPC = 0x02,
462 /// Atomic reduction option for kmpc_reduce.
463 OMP_ATOMIC_REDUCE = 0x10,
464 /// Explicit 'barrier' directive.
465 OMP_IDENT_BARRIER_EXPL = 0x20,
466 /// Implicit barrier in code.
467 OMP_IDENT_BARRIER_IMPL = 0x40,
468 /// Implicit barrier in 'for' directive.
469 OMP_IDENT_BARRIER_IMPL_FOR = 0x40,
470 /// Implicit barrier in 'sections' directive.
471 OMP_IDENT_BARRIER_IMPL_SECTIONS = 0xC0,
472 /// Implicit barrier in 'single' directive.
473 OMP_IDENT_BARRIER_IMPL_SINGLE = 0x140,
474 /// Call of __kmp_for_static_init for static loop.
475 OMP_IDENT_WORK_LOOP = 0x200,
476 /// Call of __kmp_for_static_init for sections.
477 OMP_IDENT_WORK_SECTIONS = 0x400,
478 /// Call of __kmp_for_static_init for distribute.
479 OMP_IDENT_WORK_DISTRIBUTE = 0x800,
480 LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/OMP_IDENT_WORK_DISTRIBUTE)
481};
482
483/// Describes ident structure that describes a source location.
484/// All descriptions are taken from
485/// https://github.com/llvm/llvm-project/blob/main/openmp/runtime/src/kmp.h
486/// Original structure:
487/// typedef struct ident {
488/// kmp_int32 reserved_1; /**< might be used in Fortran;
489/// see above */
490/// kmp_int32 flags; /**< also f.flags; KMP_IDENT_xxx flags;
491/// KMP_IDENT_KMPC identifies this union
492/// member */
493/// kmp_int32 reserved_2; /**< not really used in Fortran any more;
494/// see above */
495///#if USE_ITT_BUILD
496/// /* but currently used for storing
497/// region-specific ITT */
498/// /* contextual information. */
499///#endif /* USE_ITT_BUILD */
500/// kmp_int32 reserved_3; /**< source[4] in Fortran, do not use for
501/// C++ */
502/// char const *psource; /**< String describing the source location.
503/// The string is composed of semi-colon separated
504// fields which describe the source file,
505/// the function and a pair of line numbers that
506/// delimit the construct.
507/// */
508/// } ident_t;
509enum IdentFieldIndex {
510 /// might be used in Fortran
511 IdentField_Reserved_1,
512 /// OMP_IDENT_xxx flags; OMP_IDENT_KMPC identifies this union member.
513 IdentField_Flags,
514 /// Not really used in Fortran any more
515 IdentField_Reserved_2,
516 /// Source[4] in Fortran, do not use for C++
517 IdentField_Reserved_3,
518 /// String describing the source location. The string is composed of
519 /// semi-colon separated fields which describe the source file, the function
520 /// and a pair of line numbers that delimit the construct.
521 IdentField_PSource
522};
523
524/// Schedule types for 'omp for' loops (these enumerators are taken from
525/// the enum sched_type in kmp.h).
526enum OpenMPSchedType {
527 /// Lower bound for default (unordered) versions.
528 OMP_sch_lower = 32,
529 OMP_sch_static_chunked = 33,
530 OMP_sch_static = 34,
531 OMP_sch_dynamic_chunked = 35,
532 OMP_sch_guided_chunked = 36,
533 OMP_sch_runtime = 37,
534 OMP_sch_auto = 38,
535 /// static with chunk adjustment (e.g., simd)
536 OMP_sch_static_balanced_chunked = 45,
537 /// Lower bound for 'ordered' versions.
538 OMP_ord_lower = 64,
539 OMP_ord_static_chunked = 65,
540 OMP_ord_static = 66,
541 OMP_ord_dynamic_chunked = 67,
542 OMP_ord_guided_chunked = 68,
543 OMP_ord_runtime = 69,
544 OMP_ord_auto = 70,
545 OMP_sch_default = OMP_sch_static,
546 /// dist_schedule types
547 OMP_dist_sch_static_chunked = 91,
548 OMP_dist_sch_static = 92,
549 /// Fused distribute+for static schedule (entityId = team*nthreads + tid,
550 /// num_entities = nteams*nthreads). One for_static_init call, no
551 /// surrounding distribute_static_init. Matches
552 /// kmp_sched_distr_static_chunk_sched_static_chunkone in the device RTL
553 /// (openmp/device/include/DeviceTypes.h).
554 OMP_dist_sch_static_chunked_sch_static_chunkone = 93,
555 /// Support for OpenMP 4.5 monotonic and nonmonotonic schedule modifiers.
556 /// Set if the monotonic schedule modifier was present.
557 OMP_sch_modifier_monotonic = (1 << 29),
558 /// Set if the nonmonotonic schedule modifier was present.
559 OMP_sch_modifier_nonmonotonic = (1 << 30),
560};
561
562/// A basic class for pre|post-action for advanced codegen sequence for OpenMP
563/// region.
564class CleanupTy final : public EHScopeStack::Cleanup {
565 PrePostActionTy *Action;
566
567public:
568 explicit CleanupTy(PrePostActionTy *Action) : Action(Action) {}
569 void Emit(CodeGenFunction &CGF, Flags /*flags*/) override {
570 if (!CGF.HaveInsertPoint())
571 return;
572 Action->Exit(CGF);
573 }
574};
575
576} // anonymous namespace
577
580 if (PrePostAction) {
581 CGF.EHStack.pushCleanup<CleanupTy>(NormalAndEHCleanup, PrePostAction);
582 Callback(CodeGen, CGF, *PrePostAction);
583 } else {
584 PrePostActionTy Action;
585 Callback(CodeGen, CGF, Action);
586 }
587}
588
589/// Check if the combiner is a call to UDR combiner and if it is so return the
590/// UDR decl used for reduction.
591static const OMPDeclareReductionDecl *
592getReductionInit(const Expr *ReductionOp) {
593 if (const auto *CE = dyn_cast<CallExpr>(ReductionOp))
594 if (const auto *OVE = dyn_cast<OpaqueValueExpr>(CE->getCallee()))
595 if (const auto *DRE =
596 dyn_cast<DeclRefExpr>(OVE->getSourceExpr()->IgnoreImpCasts()))
597 if (const auto *DRD = dyn_cast<OMPDeclareReductionDecl>(DRE->getDecl()))
598 return DRD;
599 return nullptr;
600}
601
603 const OMPDeclareReductionDecl *DRD,
604 const Expr *InitOp,
605 Address Private, Address Original,
606 QualType Ty) {
607 if (DRD->getInitializer()) {
608 std::pair<llvm::Function *, llvm::Function *> Reduction =
610 const auto *CE = cast<CallExpr>(InitOp);
611 const auto *OVE = cast<OpaqueValueExpr>(CE->getCallee());
612 const Expr *LHS = CE->getArg(/*Arg=*/0)->IgnoreParenImpCasts();
613 const Expr *RHS = CE->getArg(/*Arg=*/1)->IgnoreParenImpCasts();
614 const auto *LHSDRE =
615 cast<DeclRefExpr>(cast<UnaryOperator>(LHS)->getSubExpr());
616 const auto *RHSDRE =
617 cast<DeclRefExpr>(cast<UnaryOperator>(RHS)->getSubExpr());
618 CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
619 PrivateScope.addPrivate(cast<VarDecl>(LHSDRE->getDecl()), Private);
620 PrivateScope.addPrivate(cast<VarDecl>(RHSDRE->getDecl()), Original);
621 (void)PrivateScope.Privatize();
624 CGF.EmitIgnoredExpr(InitOp);
625 } else {
626 llvm::Constant *Init = CGF.CGM.EmitNullConstant(Ty);
627 std::string Name = CGF.CGM.getOpenMPRuntime().getName({"init"});
628 auto *GV = new llvm::GlobalVariable(
629 CGF.CGM.getModule(), Init->getType(), /*isConstant=*/true,
630 llvm::GlobalValue::PrivateLinkage, Init, Name);
631 LValue LV = CGF.MakeNaturalAlignRawAddrLValue(GV, Ty);
632 RValue InitRVal;
633 switch (CGF.getEvaluationKind(Ty)) {
634 case TEK_Scalar:
635 InitRVal = CGF.EmitLoadOfLValue(LV, DRD->getLocation());
636 break;
637 case TEK_Complex:
638 InitRVal =
640 break;
641 case TEK_Aggregate: {
642 OpaqueValueExpr OVE(DRD->getLocation(), Ty, VK_LValue);
643 CodeGenFunction::OpaqueValueMapping OpaqueMap(CGF, &OVE, LV);
644 CGF.EmitAnyExprToMem(&OVE, Private, Ty.getQualifiers(),
645 /*IsInitializer=*/false);
646 return;
647 }
648 }
649 OpaqueValueExpr OVE(DRD->getLocation(), Ty, VK_PRValue);
650 CodeGenFunction::OpaqueValueMapping OpaqueMap(CGF, &OVE, InitRVal);
651 CGF.EmitAnyExprToMem(&OVE, Private, Ty.getQualifiers(),
652 /*IsInitializer=*/false);
653 }
654}
655
656/// Emit initialization of arrays of complex types.
657/// \param DestAddr Address of the array.
658/// \param Type Type of array.
659/// \param Init Initial expression of array.
660/// \param SrcAddr Address of the original array.
662 QualType Type, bool EmitDeclareReductionInit,
663 const Expr *Init,
664 const OMPDeclareReductionDecl *DRD,
665 Address SrcAddr = Address::invalid()) {
666 // Perform element-by-element initialization.
667 QualType ElementTy;
668
669 // Drill down to the base element type on both arrays.
670 const ArrayType *ArrayTy = Type->getAsArrayTypeUnsafe();
671 llvm::Value *NumElements = CGF.emitArrayLength(ArrayTy, ElementTy, DestAddr);
672 if (DRD)
673 SrcAddr = SrcAddr.withElementType(DestAddr.getElementType());
674
675 llvm::Value *SrcBegin = nullptr;
676 if (DRD)
677 SrcBegin = SrcAddr.emitRawPointer(CGF);
678 llvm::Value *DestBegin = DestAddr.emitRawPointer(CGF);
679 // Cast from pointer to array type to pointer to single element.
680 llvm::Value *DestEnd =
681 CGF.Builder.CreateGEP(DestAddr.getElementType(), DestBegin, NumElements);
682 // The basic structure here is a while-do loop.
683 llvm::BasicBlock *BodyBB = CGF.createBasicBlock("omp.arrayinit.body");
684 llvm::BasicBlock *DoneBB = CGF.createBasicBlock("omp.arrayinit.done");
685 llvm::Value *IsEmpty =
686 CGF.Builder.CreateICmpEQ(DestBegin, DestEnd, "omp.arrayinit.isempty");
687 CGF.Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB);
688
689 // Enter the loop body, making that address the current address.
690 llvm::BasicBlock *EntryBB = CGF.Builder.GetInsertBlock();
691 CGF.EmitBlock(BodyBB);
692
693 CharUnits ElementSize = CGF.getContext().getTypeSizeInChars(ElementTy);
694
695 llvm::PHINode *SrcElementPHI = nullptr;
696 Address SrcElementCurrent = Address::invalid();
697 if (DRD) {
698 SrcElementPHI = CGF.Builder.CreatePHI(SrcBegin->getType(), 2,
699 "omp.arraycpy.srcElementPast");
700 SrcElementPHI->addIncoming(SrcBegin, EntryBB);
701 SrcElementCurrent =
702 Address(SrcElementPHI, SrcAddr.getElementType(),
703 SrcAddr.getAlignment().alignmentOfArrayElement(ElementSize));
704 }
705 llvm::PHINode *DestElementPHI = CGF.Builder.CreatePHI(
706 DestBegin->getType(), 2, "omp.arraycpy.destElementPast");
707 DestElementPHI->addIncoming(DestBegin, EntryBB);
708 Address DestElementCurrent =
709 Address(DestElementPHI, DestAddr.getElementType(),
710 DestAddr.getAlignment().alignmentOfArrayElement(ElementSize));
711
712 // Emit copy.
713 {
715 if (EmitDeclareReductionInit) {
716 emitInitWithReductionInitializer(CGF, DRD, Init, DestElementCurrent,
717 SrcElementCurrent, ElementTy);
718 } else
719 CGF.EmitAnyExprToMem(Init, DestElementCurrent, ElementTy.getQualifiers(),
720 /*IsInitializer=*/false);
721 }
722
723 if (DRD) {
724 // Shift the address forward by one element.
725 llvm::Value *SrcElementNext = CGF.Builder.CreateConstGEP1_32(
726 SrcAddr.getElementType(), SrcElementPHI, /*Idx0=*/1,
727 "omp.arraycpy.dest.element");
728 SrcElementPHI->addIncoming(SrcElementNext, CGF.Builder.GetInsertBlock());
729 }
730
731 // Shift the address forward by one element.
732 llvm::Value *DestElementNext = CGF.Builder.CreateConstGEP1_32(
733 DestAddr.getElementType(), DestElementPHI, /*Idx0=*/1,
734 "omp.arraycpy.dest.element");
735 // Check whether we've reached the end.
736 llvm::Value *Done =
737 CGF.Builder.CreateICmpEQ(DestElementNext, DestEnd, "omp.arraycpy.done");
738 CGF.Builder.CreateCondBr(Done, DoneBB, BodyBB);
739 DestElementPHI->addIncoming(DestElementNext, CGF.Builder.GetInsertBlock());
740
741 // Done.
742 CGF.EmitBlock(DoneBB, /*IsFinished=*/true);
743}
744
745LValue ReductionCodeGen::emitSharedLValue(CodeGenFunction &CGF, const Expr *E) {
746 return CGF.EmitOMPSharedLValue(E);
747}
748
749LValue ReductionCodeGen::emitSharedLValueUB(CodeGenFunction &CGF,
750 const Expr *E) {
751 if (const auto *OASE = dyn_cast<ArraySectionExpr>(E))
752 return CGF.EmitArraySectionExpr(OASE, /*IsLowerBound=*/false);
753 return LValue();
754}
755
756void ReductionCodeGen::emitAggregateInitialization(
757 CodeGenFunction &CGF, unsigned N, Address PrivateAddr, Address SharedAddr,
758 const OMPDeclareReductionDecl *DRD) {
759 // Emit VarDecl with copy init for arrays.
760 // Get the address of the original variable captured in current
761 // captured region.
762 const auto *PrivateVD =
763 cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Private)->getDecl());
764 bool EmitDeclareReductionInit =
765 DRD && (DRD->getInitializer() || !PrivateVD->hasInit());
766 EmitOMPAggregateInit(CGF, PrivateAddr, PrivateVD->getType(),
767 EmitDeclareReductionInit,
768 EmitDeclareReductionInit ? ClausesData[N].ReductionOp
769 : PrivateVD->getInit(),
770 DRD, SharedAddr);
771}
772
776 ArrayRef<const Expr *> ReductionOps) {
777 ClausesData.reserve(Shareds.size());
778 SharedAddresses.reserve(Shareds.size());
779 Sizes.reserve(Shareds.size());
780 BaseDecls.reserve(Shareds.size());
781 const auto *IOrig = Origs.begin();
782 const auto *IPriv = Privates.begin();
783 const auto *IRed = ReductionOps.begin();
784 for (const Expr *Ref : Shareds) {
785 ClausesData.emplace_back(Ref, *IOrig, *IPriv, *IRed);
786 std::advance(IOrig, 1);
787 std::advance(IPriv, 1);
788 std::advance(IRed, 1);
789 }
790}
791
793 assert(SharedAddresses.size() == N && OrigAddresses.size() == N &&
794 "Number of generated lvalues must be exactly N.");
795 LValue First = emitSharedLValue(CGF, ClausesData[N].Shared);
796 LValue Second = emitSharedLValueUB(CGF, ClausesData[N].Shared);
797 SharedAddresses.emplace_back(First, Second);
798 if (ClausesData[N].Shared == ClausesData[N].Ref) {
799 OrigAddresses.emplace_back(First, Second);
800 } else {
801 LValue First = emitSharedLValue(CGF, ClausesData[N].Ref);
802 LValue Second = emitSharedLValueUB(CGF, ClausesData[N].Ref);
803 OrigAddresses.emplace_back(First, Second);
804 }
805}
806
808 QualType PrivateType = getPrivateType(N);
809 bool AsArraySection = isa<ArraySectionExpr>(ClausesData[N].Ref);
810 if (!PrivateType->isVariablyModifiedType()) {
811 Sizes.emplace_back(
812 CGF.getTypeSize(OrigAddresses[N].first.getType().getNonReferenceType()),
813 nullptr);
814 return;
815 }
816 llvm::Value *Size;
817 llvm::Value *SizeInChars;
818 auto *ElemType = OrigAddresses[N].first.getAddress().getElementType();
819 auto *ElemSizeOf = llvm::ConstantExpr::getSizeOf(ElemType);
820 if (AsArraySection) {
821 Size = CGF.Builder.CreatePtrDiff(ElemType,
822 OrigAddresses[N].second.getPointer(CGF),
823 OrigAddresses[N].first.getPointer(CGF));
824 Size = CGF.Builder.CreateZExtOrTrunc(Size, ElemSizeOf->getType());
825 Size = CGF.Builder.CreateNUWAdd(
826 Size, llvm::ConstantInt::get(Size->getType(), /*V=*/1));
827 SizeInChars = CGF.Builder.CreateNUWMul(Size, ElemSizeOf);
828 } else {
829 SizeInChars =
830 CGF.getTypeSize(OrigAddresses[N].first.getType().getNonReferenceType());
831 Size = CGF.Builder.CreateExactUDiv(SizeInChars, ElemSizeOf);
832 }
833 Sizes.emplace_back(SizeInChars, Size);
835 CGF,
837 CGF.getContext().getAsVariableArrayType(PrivateType)->getSizeExpr()),
838 RValue::get(Size));
839 CGF.EmitVariablyModifiedType(PrivateType);
840}
841
843 llvm::Value *Size) {
844 QualType PrivateType = getPrivateType(N);
845 if (!PrivateType->isVariablyModifiedType()) {
846 assert(!Size && !Sizes[N].second &&
847 "Size should be nullptr for non-variably modified reduction "
848 "items.");
849 return;
850 }
852 CGF,
854 CGF.getContext().getAsVariableArrayType(PrivateType)->getSizeExpr()),
855 RValue::get(Size));
856 CGF.EmitVariablyModifiedType(PrivateType);
857}
858
860 CodeGenFunction &CGF, unsigned N, Address PrivateAddr, Address SharedAddr,
861 llvm::function_ref<bool(CodeGenFunction &)> DefaultInit) {
862 assert(SharedAddresses.size() > N && "No variable was generated");
863 const auto *PrivateVD =
864 cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Private)->getDecl());
865 const OMPDeclareReductionDecl *DRD =
866 getReductionInit(ClausesData[N].ReductionOp);
867 if (CGF.getContext().getAsArrayType(PrivateVD->getType())) {
868 if (DRD && DRD->getInitializer())
869 (void)DefaultInit(CGF);
870 emitAggregateInitialization(CGF, N, PrivateAddr, SharedAddr, DRD);
871 } else if (DRD && (DRD->getInitializer() || !PrivateVD->hasInit())) {
872 (void)DefaultInit(CGF);
873 QualType SharedType = SharedAddresses[N].first.getType();
874 emitInitWithReductionInitializer(CGF, DRD, ClausesData[N].ReductionOp,
875 PrivateAddr, SharedAddr, SharedType);
876 } else if (!DefaultInit(CGF) && PrivateVD->hasInit() &&
877 !CGF.isTrivialInitializer(PrivateVD->getInit())) {
878 CGF.EmitAnyExprToMem(PrivateVD->getInit(), PrivateAddr,
879 PrivateVD->getType().getQualifiers(),
880 /*IsInitializer=*/false);
881 }
882}
883
885 QualType PrivateType = getPrivateType(N);
886 QualType::DestructionKind DTorKind = PrivateType.isDestructedType();
887 return DTorKind != QualType::DK_none;
888}
889
891 Address PrivateAddr) {
892 QualType PrivateType = getPrivateType(N);
893 QualType::DestructionKind DTorKind = PrivateType.isDestructedType();
894 if (needCleanups(N)) {
895 PrivateAddr =
896 PrivateAddr.withElementType(CGF.ConvertTypeForMem(PrivateType));
897 CGF.pushDestroy(DTorKind, PrivateAddr, PrivateType);
898 }
899}
900
901static LValue loadToBegin(CodeGenFunction &CGF, QualType BaseTy, QualType ElTy,
902 LValue BaseLV) {
903 BaseTy = BaseTy.getNonReferenceType();
904 while ((BaseTy->isPointerType() || BaseTy->isReferenceType()) &&
905 !CGF.getContext().hasSameType(BaseTy, ElTy)) {
906 if (const auto *PtrTy = BaseTy->getAs<PointerType>()) {
907 BaseLV = CGF.EmitLoadOfPointerLValue(BaseLV.getAddress(), PtrTy);
908 } else {
909 LValue RefLVal = CGF.MakeAddrLValue(BaseLV.getAddress(), BaseTy);
910 BaseLV = CGF.EmitLoadOfReferenceLValue(RefLVal);
911 }
912 BaseTy = BaseTy->getPointeeType();
913 }
914 return CGF.MakeAddrLValue(
915 BaseLV.getAddress().withElementType(CGF.ConvertTypeForMem(ElTy)),
916 BaseLV.getType(), BaseLV.getBaseInfo(),
917 CGF.CGM.getTBAAInfoForSubobject(BaseLV, BaseLV.getType()));
918}
919
921 Address OriginalBaseAddress, llvm::Value *Addr) {
923 Address TopTmp = Address::invalid();
924 Address MostTopTmp = Address::invalid();
925 BaseTy = BaseTy.getNonReferenceType();
926 while ((BaseTy->isPointerType() || BaseTy->isReferenceType()) &&
927 !CGF.getContext().hasSameType(BaseTy, ElTy)) {
928 Tmp = CGF.CreateMemTempWithoutCast(BaseTy);
929 if (TopTmp.isValid())
930 CGF.Builder.CreateStore(Tmp.getPointer(), TopTmp);
931 else
932 MostTopTmp = Tmp;
933 TopTmp = Tmp;
934 BaseTy = BaseTy->getPointeeType();
935 }
936
937 if (Tmp.isValid()) {
939 Addr, Tmp.getElementType());
940 CGF.Builder.CreateStore(Addr, Tmp);
941 return MostTopTmp;
942 }
943
945 Addr, OriginalBaseAddress.getType());
946 return OriginalBaseAddress.withPointer(Addr, NotKnownNonNull);
947}
948
949static const VarDecl *getBaseDecl(const Expr *Ref, const DeclRefExpr *&DE) {
950 const VarDecl *OrigVD = nullptr;
951 if (const auto *OASE = dyn_cast<ArraySectionExpr>(Ref)) {
952 const Expr *Base = OASE->getBase()->IgnoreParenImpCasts();
953 while (const auto *TempOASE = dyn_cast<ArraySectionExpr>(Base))
954 Base = TempOASE->getBase()->IgnoreParenImpCasts();
955 while (const auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
956 Base = TempASE->getBase()->IgnoreParenImpCasts();
958 OrigVD = cast<VarDecl>(DE->getDecl());
959 } else if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(Ref)) {
960 const Expr *Base = ASE->getBase()->IgnoreParenImpCasts();
961 while (const auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
962 Base = TempASE->getBase()->IgnoreParenImpCasts();
964 OrigVD = cast<VarDecl>(DE->getDecl());
965 }
966 return OrigVD;
967}
968
970 Address PrivateAddr) {
971 const DeclRefExpr *DE;
972 if (const VarDecl *OrigVD = ::getBaseDecl(ClausesData[N].Ref, DE)) {
973 BaseDecls.emplace_back(OrigVD);
974 LValue OriginalBaseLValue = CGF.EmitLValue(DE);
975 LValue BaseLValue =
976 loadToBegin(CGF, OrigVD->getType(), SharedAddresses[N].first.getType(),
977 OriginalBaseLValue);
978 Address SharedAddr = SharedAddresses[N].first.getAddress();
979 llvm::Value *Adjustment = CGF.Builder.CreatePtrDiff(
980 SharedAddr.getElementType(), BaseLValue.getPointer(CGF),
981 SharedAddr.emitRawPointer(CGF));
982 llvm::Value *PrivatePointer =
984 PrivateAddr.emitRawPointer(CGF), SharedAddr.getType());
985 llvm::Value *Ptr = CGF.Builder.CreateGEP(
986 SharedAddr.getElementType(), PrivatePointer, Adjustment);
987 return castToBase(CGF, OrigVD->getType(),
988 SharedAddresses[N].first.getType(),
989 OriginalBaseLValue.getAddress(), Ptr);
990 }
991 BaseDecls.emplace_back(
992 cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Ref)->getDecl()));
993 return PrivateAddr;
994}
995
997 const OMPDeclareReductionDecl *DRD =
998 getReductionInit(ClausesData[N].ReductionOp);
999 return DRD && DRD->getInitializer();
1000}
1001
1002LValue CGOpenMPRegionInfo::getThreadIDVariableLValue(CodeGenFunction &CGF) {
1003 return CGF.EmitLoadOfPointerLValue(
1004 CGF.GetAddrOfLocalVar(getThreadIDVariable()),
1005 getThreadIDVariable()->getType()->castAs<PointerType>());
1006}
1007
1008void CGOpenMPRegionInfo::EmitBody(CodeGenFunction &CGF, const Stmt *S) {
1009 if (!CGF.HaveInsertPoint())
1010 return;
1011 // 1.2.2 OpenMP Language Terminology
1012 // Structured block - An executable statement with a single entry at the
1013 // top and a single exit at the bottom.
1014 // The point of exit cannot be a branch out of the structured block.
1015 // longjmp() and throw() must not violate the entry/exit criteria.
1016 CGF.EHStack.pushTerminate();
1017 if (S)
1019 CodeGen(CGF);
1020 CGF.EHStack.popTerminate();
1021}
1022
1023LValue CGOpenMPTaskOutlinedRegionInfo::getThreadIDVariableLValue(
1024 CodeGenFunction &CGF) {
1025 return CGF.MakeAddrLValue(CGF.GetAddrOfLocalVar(getThreadIDVariable()),
1026 getThreadIDVariable()->getType(),
1028}
1029
1031 QualType FieldTy) {
1032 auto *Field = FieldDecl::Create(
1033 C, DC, SourceLocation(), SourceLocation(), /*Id=*/nullptr, FieldTy,
1034 C.getTrivialTypeSourceInfo(FieldTy, SourceLocation()),
1035 /*BW=*/nullptr, /*Mutable=*/false, /*InitStyle=*/ICIS_NoInit);
1036 Field->setAccess(AS_public);
1037 DC->addDecl(Field);
1038 return Field;
1039}
1040
1042 : CGM(CGM), OMPBuilder(CGM.getModule()) {
1043 KmpCriticalNameTy = llvm::ArrayType::get(CGM.Int32Ty, /*NumElements*/ 8);
1044 llvm::OpenMPIRBuilderConfig Config(
1045 CGM.getLangOpts().OpenMPIsTargetDevice, isGPU(),
1046 CGM.getLangOpts().OpenMPOffloadMandatory,
1047 /*HasRequiresReverseOffload*/ false, /*HasRequiresUnifiedAddress*/ false,
1048 hasRequiresUnifiedSharedMemory(), /*HasRequiresDynamicAllocators*/ false);
1049 Config.setDefaultTargetAS(
1050 CGM.getContext().getTargetInfo().getTargetAddressSpace(LangAS::Default));
1051 Config.setRuntimeCC(CGM.getRuntimeCC());
1052
1053 OMPBuilder.setConfig(Config);
1054 OMPBuilder.initialize();
1055 OMPBuilder.loadOffloadInfoMetadata(*CGM.getFileSystem(),
1056 CGM.getLangOpts().OpenMPIsTargetDevice
1057 ? CGM.getLangOpts().OMPHostIRFile
1058 : StringRef{});
1059
1060 // The user forces the compiler to behave as if omp requires
1061 // unified_shared_memory was given.
1062 if (CGM.getLangOpts().OpenMPForceUSM) {
1064 OMPBuilder.Config.setHasRequiresUnifiedSharedMemory(true);
1065 }
1066}
1067
1069 InternalVars.clear();
1070 // Clean non-target variable declarations possibly used only in debug info.
1071 for (const auto &Data : EmittedNonTargetVariables) {
1072 if (!Data.getValue().pointsToAliveValue())
1073 continue;
1074 auto *GV = dyn_cast<llvm::GlobalVariable>(Data.getValue());
1075 if (!GV)
1076 continue;
1077 if (!GV->isDeclaration() || GV->getNumUses() > 0)
1078 continue;
1079 GV->eraseFromParent();
1080 }
1081}
1082
1084 return OMPBuilder.createPlatformSpecificName(Parts);
1085}
1086
1087static llvm::Function *
1089 const Expr *CombinerInitializer, const VarDecl *In,
1090 const VarDecl *Out, bool IsCombiner) {
1091 // void .omp_combiner.(Ty *in, Ty *out);
1092 ASTContext &C = CGM.getContext();
1093 QualType PtrTy = C.getPointerType(Ty).withRestrict();
1094 auto *OmpOutParm = ImplicitParamDecl::Create(
1095 C, /*DC=*/nullptr, Out->getLocation(),
1096 /*Id=*/nullptr, PtrTy, ImplicitParamKind::Other);
1097 auto *OmpInParm = ImplicitParamDecl::Create(
1098 C, /*DC=*/nullptr, In->getLocation(),
1099 /*Id=*/nullptr, PtrTy, ImplicitParamKind::Other);
1100 FunctionArgList Args{OmpOutParm, OmpInParm};
1101 const CGFunctionInfo &FnInfo =
1102 CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
1103 llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
1104 std::string Name = CGM.getOpenMPRuntime().getName(
1105 {IsCombiner ? "omp_combiner" : "omp_initializer", ""});
1106 auto *Fn = llvm::Function::Create(FnTy, llvm::GlobalValue::InternalLinkage,
1107 Name, &CGM.getModule());
1108 CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FnInfo);
1109 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
1110 Fn->addFnAttr("sample-profile-suffix-elision-policy", "selected");
1111 if (CGM.getCodeGenOpts().OptimizationLevel != 0) {
1112 Fn->removeFnAttr(llvm::Attribute::NoInline);
1113 Fn->removeFnAttr(llvm::Attribute::OptimizeNone);
1114 Fn->addFnAttr(llvm::Attribute::AlwaysInline);
1115 }
1116 CodeGenFunction CGF(CGM);
1117 // Map "T omp_in;" variable to "*omp_in_parm" value in all expressions.
1118 // Map "T omp_out;" variable to "*omp_out_parm" value in all expressions.
1119 CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, FnInfo, Args, In->getLocation(),
1120 Out->getLocation());
1122 Address AddrIn = CGF.GetAddrOfLocalVar(OmpInParm);
1123 Scope.addPrivate(
1124 In, CGF.EmitLoadOfPointerLValue(AddrIn, PtrTy->castAs<PointerType>())
1125 .getAddress());
1126 Address AddrOut = CGF.GetAddrOfLocalVar(OmpOutParm);
1127 Scope.addPrivate(
1128 Out, CGF.EmitLoadOfPointerLValue(AddrOut, PtrTy->castAs<PointerType>())
1129 .getAddress());
1130 (void)Scope.Privatize();
1131 if (!IsCombiner && Out->hasInit() &&
1132 !CGF.isTrivialInitializer(Out->getInit())) {
1133 CGF.EmitAnyExprToMem(Out->getInit(), CGF.GetAddrOfLocalVar(Out),
1134 Out->getType().getQualifiers(),
1135 /*IsInitializer=*/true);
1136 }
1137 if (CombinerInitializer)
1138 CGF.EmitIgnoredExpr(CombinerInitializer);
1139 Scope.ForceCleanup();
1140 CGF.FinishFunction();
1141 return Fn;
1142}
1143
1146 if (UDRMap.count(D) > 0)
1147 return;
1148 llvm::Function *Combiner = emitCombinerOrInitializer(
1149 CGM, D->getType(), D->getCombiner(),
1152 /*IsCombiner=*/true);
1153 llvm::Function *Initializer = nullptr;
1154 if (const Expr *Init = D->getInitializer()) {
1156 CGM, D->getType(),
1158 : nullptr,
1161 /*IsCombiner=*/false);
1162 }
1163 UDRMap.try_emplace(D, Combiner, Initializer);
1164 if (CGF)
1165 FunctionUDRMap[CGF->CurFn].push_back(D);
1166}
1167
1168std::pair<llvm::Function *, llvm::Function *>
1170 auto I = UDRMap.find(D);
1171 if (I != UDRMap.end())
1172 return I->second;
1173 emitUserDefinedReduction(/*CGF=*/nullptr, D);
1174 return UDRMap.lookup(D);
1175}
1176
1177namespace {
1178// Temporary RAII solution to perform a push/pop stack event on the OpenMP IR
1179// Builder if one is present.
1180struct PushAndPopStackRAII {
1181 PushAndPopStackRAII(llvm::OpenMPIRBuilder *OMPBuilder, CodeGenFunction &CGF,
1182 bool HasCancel, llvm::omp::Directive Kind)
1183 : OMPBuilder(OMPBuilder) {
1184 if (!OMPBuilder)
1185 return;
1186
1187 // The following callback is the crucial part of clangs cleanup process.
1188 //
1189 // NOTE:
1190 // Once the OpenMPIRBuilder is used to create parallel regions (and
1191 // similar), the cancellation destination (Dest below) is determined via
1192 // IP. That means if we have variables to finalize we split the block at IP,
1193 // use the new block (=BB) as destination to build a JumpDest (via
1194 // getJumpDestInCurrentScope(BB)) which then is fed to
1195 // EmitBranchThroughCleanup. Furthermore, there will not be the need
1196 // to push & pop an FinalizationInfo object.
1197 // The FiniCB will still be needed but at the point where the
1198 // OpenMPIRBuilder is asked to construct a parallel (or similar) construct.
1199 auto FiniCB = [&CGF](llvm::OpenMPIRBuilder::InsertPointTy IP) {
1200 assert(IP.getBlock()->end() == IP.getPoint() &&
1201 "Clang CG should cause non-terminated block!");
1202 CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
1203 CGF.Builder.restoreIP(IP);
1205 CGF.getOMPCancelDestination(OMPD_parallel);
1206 CGF.EmitBranchThroughCleanup(Dest);
1207 return llvm::Error::success();
1208 };
1209
1210 // TODO: Remove this once we emit parallel regions through the
1211 // OpenMPIRBuilder as it can do this setup internally.
1212 llvm::OpenMPIRBuilder::FinalizationInfo FI({FiniCB, Kind, HasCancel});
1213 OMPBuilder->pushFinalizationCB(std::move(FI));
1214 }
1215 ~PushAndPopStackRAII() {
1216 if (OMPBuilder)
1217 OMPBuilder->popFinalizationCB();
1218 }
1219 llvm::OpenMPIRBuilder *OMPBuilder;
1220};
1221} // namespace
1222
1224 CodeGenModule &CGM, const OMPExecutableDirective &D, const CapturedStmt *CS,
1225 const VarDecl *ThreadIDVar, OpenMPDirectiveKind InnermostKind,
1226 const StringRef OutlinedHelperName, const RegionCodeGenTy &CodeGen) {
1227 assert(ThreadIDVar->getType()->isPointerType() &&
1228 "thread id variable must be of type kmp_int32 *");
1229 CodeGenFunction CGF(CGM, true);
1230 bool HasCancel = false;
1231 if (const auto *OPD = dyn_cast<OMPParallelDirective>(&D))
1232 HasCancel = OPD->hasCancel();
1233 else if (const auto *OPD = dyn_cast<OMPTargetParallelDirective>(&D))
1234 HasCancel = OPD->hasCancel();
1235 else if (const auto *OPSD = dyn_cast<OMPParallelSectionsDirective>(&D))
1236 HasCancel = OPSD->hasCancel();
1237 else if (const auto *OPFD = dyn_cast<OMPParallelForDirective>(&D))
1238 HasCancel = OPFD->hasCancel();
1239 else if (const auto *OPFD = dyn_cast<OMPTargetParallelForDirective>(&D))
1240 HasCancel = OPFD->hasCancel();
1241 else if (const auto *OPFD = dyn_cast<OMPDistributeParallelForDirective>(&D))
1242 HasCancel = OPFD->hasCancel();
1243 else if (const auto *OPFD =
1244 dyn_cast<OMPTeamsDistributeParallelForDirective>(&D))
1245 HasCancel = OPFD->hasCancel();
1246 else if (const auto *OPFD =
1247 dyn_cast<OMPTargetTeamsDistributeParallelForDirective>(&D))
1248 HasCancel = OPFD->hasCancel();
1249
1250 // TODO: Temporarily inform the OpenMPIRBuilder, if any, about the new
1251 // parallel region to make cancellation barriers work properly.
1252 llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
1253 PushAndPopStackRAII PSR(&OMPBuilder, CGF, HasCancel, InnermostKind);
1254 CGOpenMPOutlinedRegionInfo CGInfo(*CS, ThreadIDVar, CodeGen, InnermostKind,
1255 HasCancel, OutlinedHelperName);
1256 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
1257 return CGF.GenerateOpenMPCapturedStmtFunction(*CS, D);
1258}
1259
1260std::string CGOpenMPRuntime::getOutlinedHelperName(StringRef Name) const {
1261 std::string Suffix = getName({"omp_outlined"});
1262 return (Name + Suffix).str();
1263}
1264
1266 return getOutlinedHelperName(CGF.CurFn->getName());
1267}
1268
1269std::string CGOpenMPRuntime::getReductionFuncName(StringRef Name) const {
1270 std::string Suffix = getName({"omp", "reduction", "reduction_func"});
1271 return (Name + Suffix).str();
1272}
1273
1276 const VarDecl *ThreadIDVar, OpenMPDirectiveKind InnermostKind,
1277 const RegionCodeGenTy &CodeGen) {
1278 const CapturedStmt *CS = D.getCapturedStmt(OMPD_parallel);
1280 CGM, D, CS, ThreadIDVar, InnermostKind, getOutlinedHelperName(CGF),
1281 CodeGen);
1282}
1283
1286 const VarDecl *ThreadIDVar, OpenMPDirectiveKind InnermostKind,
1287 const RegionCodeGenTy &CodeGen) {
1288 const CapturedStmt *CS = D.getCapturedStmt(OMPD_teams);
1290 CGM, D, CS, ThreadIDVar, InnermostKind, getOutlinedHelperName(CGF),
1291 CodeGen);
1292}
1293
1295 const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
1296 const VarDecl *PartIDVar, const VarDecl *TaskTVar,
1297 OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen,
1298 bool Tied, unsigned &NumberOfParts) {
1299 auto &&UntiedCodeGen = [this, &D, TaskTVar](CodeGenFunction &CGF,
1300 PrePostActionTy &) {
1301 llvm::Value *ThreadID = getThreadID(CGF, D.getBeginLoc());
1302 llvm::Value *UpLoc = emitUpdateLocation(CGF, D.getBeginLoc());
1303 llvm::Value *TaskArgs[] = {
1304 UpLoc, ThreadID,
1305 CGF.EmitLoadOfPointerLValue(CGF.GetAddrOfLocalVar(TaskTVar),
1306 TaskTVar->getType()->castAs<PointerType>())
1307 .getPointer(CGF)};
1308 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
1309 CGM.getModule(), OMPRTL___kmpc_omp_task),
1310 TaskArgs);
1311 };
1312 CGOpenMPTaskOutlinedRegionInfo::UntiedTaskActionTy Action(Tied, PartIDVar,
1313 UntiedCodeGen);
1314 CodeGen.setAction(Action);
1315 assert(!ThreadIDVar->getType()->isPointerType() &&
1316 "thread id variable must be of type kmp_int32 for tasks");
1317 const OpenMPDirectiveKind Region =
1318 isOpenMPTaskLoopDirective(D.getDirectiveKind()) ? OMPD_taskloop
1319 : OMPD_task;
1320 const CapturedStmt *CS = D.getCapturedStmt(Region);
1321 bool HasCancel = false;
1322 if (const auto *TD = dyn_cast<OMPTaskDirective>(&D))
1323 HasCancel = TD->hasCancel();
1324 else if (const auto *TD = dyn_cast<OMPTaskLoopDirective>(&D))
1325 HasCancel = TD->hasCancel();
1326 else if (const auto *TD = dyn_cast<OMPMasterTaskLoopDirective>(&D))
1327 HasCancel = TD->hasCancel();
1328 else if (const auto *TD = dyn_cast<OMPParallelMasterTaskLoopDirective>(&D))
1329 HasCancel = TD->hasCancel();
1330
1331 CodeGenFunction CGF(CGM, true);
1332 CGOpenMPTaskOutlinedRegionInfo CGInfo(*CS, ThreadIDVar, CodeGen,
1333 InnermostKind, HasCancel, Action);
1334 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
1335 llvm::Function *Res = CGF.GenerateCapturedStmtFunction(*CS);
1336 if (!Tied)
1337 NumberOfParts = Action.getNumberOfParts();
1338 return Res;
1339}
1340
1342 bool AtCurrentPoint) {
1343 auto &Elem = OpenMPLocThreadIDMap[CGF.CurFn];
1344 assert(!Elem.ServiceInsertPt && "Insert point is set already.");
1345
1346 llvm::Value *Undef = llvm::UndefValue::get(CGF.Int32Ty);
1347 if (AtCurrentPoint) {
1348 Elem.ServiceInsertPt = new llvm::BitCastInst(Undef, CGF.Int32Ty, "svcpt",
1349 CGF.Builder.GetInsertBlock());
1350 } else {
1351 Elem.ServiceInsertPt = new llvm::BitCastInst(Undef, CGF.Int32Ty, "svcpt");
1352 Elem.ServiceInsertPt->insertAfter(CGF.AllocaInsertPt->getIterator());
1353 }
1354}
1355
1357 auto &Elem = OpenMPLocThreadIDMap[CGF.CurFn];
1358 if (Elem.ServiceInsertPt) {
1359 llvm::Instruction *Ptr = Elem.ServiceInsertPt;
1360 Elem.ServiceInsertPt = nullptr;
1361 Ptr->eraseFromParent();
1362 }
1363}
1364
1366 SourceLocation Loc,
1367 SmallString<128> &Buffer) {
1368 llvm::raw_svector_ostream OS(Buffer);
1369 // Build debug location
1371 OS << ";";
1372 if (auto *DbgInfo = CGF.getDebugInfo())
1373 OS << DbgInfo->remapDIPath(PLoc.getFilename());
1374 else
1375 OS << PLoc.getFilename();
1376 OS << ";";
1377 if (const auto *FD = dyn_cast_or_null<FunctionDecl>(CGF.CurFuncDecl))
1378 OS << FD->getQualifiedNameAsString();
1379 OS << ";" << PLoc.getLine() << ";" << PLoc.getColumn() << ";;";
1380 return OS.str();
1381}
1382
1384 SourceLocation Loc,
1385 unsigned Flags, bool EmitLoc) {
1386 uint32_t SrcLocStrSize;
1387 llvm::Constant *SrcLocStr;
1388 if ((!EmitLoc && CGM.getCodeGenOpts().getDebugInfo() ==
1389 llvm::codegenoptions::NoDebugInfo) ||
1390 Loc.isInvalid()) {
1391 SrcLocStr = OMPBuilder.getOrCreateDefaultSrcLocStr(SrcLocStrSize);
1392 } else {
1393 std::string FunctionName;
1394 std::string FileName;
1395 if (const auto *FD = dyn_cast_or_null<FunctionDecl>(CGF.CurFuncDecl))
1396 FunctionName = FD->getQualifiedNameAsString();
1398 if (auto *DbgInfo = CGF.getDebugInfo())
1399 FileName = DbgInfo->remapDIPath(PLoc.getFilename());
1400 else
1401 FileName = PLoc.getFilename();
1402 unsigned Line = PLoc.getLine();
1403 unsigned Column = PLoc.getColumn();
1404 SrcLocStr = OMPBuilder.getOrCreateSrcLocStr(FunctionName, FileName, Line,
1405 Column, SrcLocStrSize);
1406 }
1407 unsigned Reserved2Flags = getDefaultLocationReserved2Flags();
1408 return OMPBuilder.getOrCreateIdent(
1409 SrcLocStr, SrcLocStrSize, llvm::omp::IdentFlag(Flags), Reserved2Flags);
1410}
1411
1413 SourceLocation Loc) {
1414 assert(CGF.CurFn && "No function in current CodeGenFunction.");
1415 // If the OpenMPIRBuilder is used we need to use it for all thread id calls as
1416 // the clang invariants used below might be broken.
1417 if (CGM.getLangOpts().OpenMPIRBuilder) {
1418 SmallString<128> Buffer;
1419 OMPBuilder.updateToLocation(CGF.Builder.saveIP());
1420 uint32_t SrcLocStrSize;
1421 auto *SrcLocStr = OMPBuilder.getOrCreateSrcLocStr(
1422 getIdentStringFromSourceLocation(CGF, Loc, Buffer), SrcLocStrSize);
1423 return OMPBuilder.getOrCreateThreadID(
1424 OMPBuilder.getOrCreateIdent(SrcLocStr, SrcLocStrSize));
1425 }
1426
1427 llvm::Value *ThreadID = nullptr;
1428 // Check whether we've already cached a load of the thread id in this
1429 // function.
1430 auto I = OpenMPLocThreadIDMap.find(CGF.CurFn);
1431 if (I != OpenMPLocThreadIDMap.end()) {
1432 ThreadID = I->second.ThreadID;
1433 if (ThreadID != nullptr)
1434 return ThreadID;
1435 }
1436 // If exceptions are enabled, do not use parameter to avoid possible crash.
1437 if (auto *OMPRegionInfo =
1438 dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) {
1439 if (OMPRegionInfo->getThreadIDVariable()) {
1440 // Check if this an outlined function with thread id passed as argument.
1441 LValue LVal = OMPRegionInfo->getThreadIDVariableLValue(CGF);
1442 llvm::BasicBlock *TopBlock = CGF.AllocaInsertPt->getParent();
1443 if (!CGF.EHStack.requiresLandingPad() || !CGF.getLangOpts().Exceptions ||
1444 !CGF.getLangOpts().CXXExceptions ||
1445 CGF.Builder.GetInsertBlock() == TopBlock ||
1446 !isa<llvm::Instruction>(LVal.getPointer(CGF)) ||
1447 cast<llvm::Instruction>(LVal.getPointer(CGF))->getParent() ==
1448 TopBlock ||
1449 cast<llvm::Instruction>(LVal.getPointer(CGF))->getParent() ==
1450 CGF.Builder.GetInsertBlock()) {
1451 ThreadID = CGF.EmitLoadOfScalar(LVal, Loc);
1452 // If value loaded in entry block, cache it and use it everywhere in
1453 // function.
1454 if (CGF.Builder.GetInsertBlock() == TopBlock)
1455 OpenMPLocThreadIDMap[CGF.CurFn].ThreadID = ThreadID;
1456 return ThreadID;
1457 }
1458 }
1459 }
1460
1461 // This is not an outlined function region - need to call __kmpc_int32
1462 // kmpc_global_thread_num(ident_t *loc).
1463 // Generate thread id value and cache this value for use across the
1464 // function.
1465 auto &Elem = OpenMPLocThreadIDMap[CGF.CurFn];
1466 if (!Elem.ServiceInsertPt)
1468 CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
1469 CGF.Builder.SetInsertPoint(Elem.ServiceInsertPt);
1471 llvm::CallInst *Call = CGF.Builder.CreateCall(
1472 OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(),
1473 OMPRTL___kmpc_global_thread_num),
1474 emitUpdateLocation(CGF, Loc));
1475 Call->setCallingConv(CGF.getRuntimeCC());
1476 Elem.ThreadID = Call;
1477 return Call;
1478}
1479
1481 assert(CGF.CurFn && "No function in current CodeGenFunction.");
1482 if (OpenMPLocThreadIDMap.count(CGF.CurFn)) {
1484 OpenMPLocThreadIDMap.erase(CGF.CurFn);
1485 }
1486 if (auto I = FunctionUDRMap.find(CGF.CurFn); I != FunctionUDRMap.end()) {
1487 for (const auto *D : I->second)
1488 UDRMap.erase(D);
1489 FunctionUDRMap.erase(I);
1490 }
1491 if (auto I = FunctionUDMMap.find(CGF.CurFn); I != FunctionUDMMap.end()) {
1492 for (const auto *D : I->second)
1493 UDMMap.erase(D);
1494 FunctionUDMMap.erase(I);
1495 }
1498}
1499
1501 return OMPBuilder.IdentPtr;
1502}
1503
1504static llvm::OffloadEntriesInfoManager::OMPTargetDeviceClauseKind
1506 std::optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
1507 OMPDeclareTargetDeclAttr::getDeviceType(VD);
1508 if (!DevTy)
1509 return llvm::OffloadEntriesInfoManager::OMPTargetDeviceClauseNone;
1510
1511 switch ((int)*DevTy) { // Avoid -Wcovered-switch-default
1512 case OMPDeclareTargetDeclAttr::DT_Host:
1513 return llvm::OffloadEntriesInfoManager::OMPTargetDeviceClauseHost;
1514 break;
1515 case OMPDeclareTargetDeclAttr::DT_NoHost:
1516 return llvm::OffloadEntriesInfoManager::OMPTargetDeviceClauseNoHost;
1517 break;
1518 case OMPDeclareTargetDeclAttr::DT_Any:
1519 return llvm::OffloadEntriesInfoManager::OMPTargetDeviceClauseAny;
1520 break;
1521 default:
1522 return llvm::OffloadEntriesInfoManager::OMPTargetDeviceClauseNone;
1523 break;
1524 }
1525}
1526
1527static llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryKind
1529 std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> MapType =
1530 OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
1531 if (!MapType)
1532 return llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryNone;
1533 switch ((int)*MapType) { // Avoid -Wcovered-switch-default
1534 case OMPDeclareTargetDeclAttr::MapTypeTy::MT_To:
1535 return llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryTo;
1536 break;
1537 case OMPDeclareTargetDeclAttr::MapTypeTy::MT_Enter:
1538 return llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryEnter;
1539 case OMPDeclareTargetDeclAttr::MapTypeTy::MT_Link:
1540 return llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryLink;
1541 break;
1542 case OMPDeclareTargetDeclAttr::MapTypeTy::MT_Local:
1543 // MT_Local variables don't need offload entry (device-local).
1544 llvm_unreachable("MT_Local should not reach convertCaptureClause");
1545 break;
1546 default:
1547 return llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryNone;
1548 break;
1549 }
1550}
1551
1552static llvm::TargetRegionEntryInfo getEntryInfoFromPresumedLoc(
1553 CodeGenModule &CGM, llvm::OpenMPIRBuilder &OMPBuilder,
1554 SourceLocation BeginLoc, llvm::StringRef ParentName = "") {
1555
1556 auto FileInfoCallBack = [&]() {
1558 PresumedLoc PLoc = SM.getPresumedLoc(BeginLoc);
1559
1560 if (!CGM.getFileSystem()->exists(PLoc.getFilename()))
1561 PLoc = SM.getPresumedLoc(BeginLoc, /*UseLineDirectives=*/false);
1562
1563 return std::pair<std::string, uint64_t>(PLoc.getFilename(), PLoc.getLine());
1564 };
1565
1566 return OMPBuilder.getTargetEntryUniqueInfo(FileInfoCallBack,
1567 *CGM.getFileSystem(), ParentName);
1568}
1569
1571 auto AddrOfGlobal = [&VD, this]() { return CGM.GetAddrOfGlobal(VD); };
1572
1573 auto LinkageForVariable = [&VD, this]() {
1574 return CGM.getLLVMLinkageVarDefinition(VD);
1575 };
1576
1577 std::vector<llvm::GlobalVariable *> GeneratedRefs;
1578
1579 llvm::Type *LlvmPtrTy = CGM.getTypes().ConvertTypeForMem(
1580 CGM.getContext().getPointerType(VD->getType()));
1581 llvm::Constant *addr = OMPBuilder.getAddrOfDeclareTargetVar(
1583 VD->hasDefinition(CGM.getContext()) == VarDecl::DeclarationOnly,
1584 VD->isExternallyVisible(),
1586 VD->getCanonicalDecl()->getBeginLoc()),
1587 CGM.getMangledName(VD), GeneratedRefs, CGM.getLangOpts().OpenMPSimd,
1588 CGM.getLangOpts().OMPTargetTriples, LlvmPtrTy, AddrOfGlobal,
1589 LinkageForVariable);
1590
1591 if (!addr)
1592 return ConstantAddress::invalid();
1593 return ConstantAddress(addr, LlvmPtrTy, CGM.getContext().getDeclAlign(VD));
1594}
1595
1596llvm::Constant *
1598 assert(!CGM.getLangOpts().OpenMPUseTLS ||
1599 !CGM.getContext().getTargetInfo().isTLSSupported());
1600 // Lookup the entry, lazily creating it if necessary.
1601 std::string Suffix = getName({"cache", ""});
1602 return OMPBuilder.getOrCreateInternalVariable(
1603 CGM.Int8PtrPtrTy, Twine(CGM.getMangledName(VD)).concat(Suffix).str());
1604}
1605
1607 const VarDecl *VD,
1608 Address VDAddr,
1609 SourceLocation Loc) {
1610 if (CGM.getLangOpts().OpenMPUseTLS &&
1611 CGM.getContext().getTargetInfo().isTLSSupported())
1612 return VDAddr;
1613
1614 llvm::Type *VarTy = VDAddr.getElementType();
1615 llvm::Value *Args[] = {
1616 emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
1617 CGF.Builder.CreatePointerCast(VDAddr.emitRawPointer(CGF), CGM.Int8PtrTy),
1618 CGM.getSize(CGM.GetTargetTypeStoreSize(VarTy)),
1620 return Address(
1621 CGF.EmitRuntimeCall(
1622 OMPBuilder.getOrCreateRuntimeFunction(
1623 CGM.getModule(), OMPRTL___kmpc_threadprivate_cached),
1624 Args),
1625 CGF.Int8Ty, VDAddr.getAlignment());
1626}
1627
1629 CodeGenFunction &CGF, Address VDAddr, llvm::Value *Ctor,
1630 llvm::Value *CopyCtor, llvm::Value *Dtor, SourceLocation Loc) {
1631 // Call kmp_int32 __kmpc_global_thread_num(&loc) to init OpenMP runtime
1632 // library.
1633 llvm::Value *OMPLoc = emitUpdateLocation(CGF, Loc);
1634 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
1635 CGM.getModule(), OMPRTL___kmpc_global_thread_num),
1636 OMPLoc);
1637 // Call __kmpc_threadprivate_register(&loc, &var, ctor, cctor/*NULL*/, dtor)
1638 // to register constructor/destructor for variable.
1639 llvm::Value *Args[] = {
1640 OMPLoc,
1641 CGF.Builder.CreatePointerCast(VDAddr.emitRawPointer(CGF), CGM.VoidPtrTy),
1642 Ctor, CopyCtor, Dtor};
1643 CGF.EmitRuntimeCall(
1644 OMPBuilder.getOrCreateRuntimeFunction(
1645 CGM.getModule(), OMPRTL___kmpc_threadprivate_register),
1646 Args);
1647}
1648
1650 const VarDecl *VD, Address VDAddr, SourceLocation Loc,
1651 bool PerformInit, CodeGenFunction *CGF) {
1652 if (CGM.getLangOpts().OpenMPUseTLS &&
1653 CGM.getContext().getTargetInfo().isTLSSupported())
1654 return nullptr;
1655
1656 VD = VD->getDefinition(CGM.getContext());
1657 if (VD && ThreadPrivateWithDefinition.insert(CGM.getMangledName(VD)).second) {
1658 QualType ASTTy = VD->getType();
1659
1660 llvm::Value *Ctor = nullptr, *CopyCtor = nullptr, *Dtor = nullptr;
1661 const Expr *Init = VD->getAnyInitializer();
1662 if (CGM.getLangOpts().CPlusPlus && PerformInit) {
1663 // Generate function that re-emits the declaration's initializer into the
1664 // threadprivate copy of the variable VD
1665 CodeGenFunction CtorCGF(CGM);
1666 auto *Dst = ImplicitParamDecl::Create(
1667 CGM.getContext(), /*DC=*/nullptr, Loc,
1668 /*Id=*/nullptr, CGM.getContext().VoidPtrTy, ImplicitParamKind::Other);
1669
1670 FunctionArgList Args{Dst};
1671 const auto &FI = CGM.getTypes().arrangeBuiltinFunctionDeclaration(
1672 CGM.getContext().VoidPtrTy, Args);
1673 llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
1674 std::string Name = getName({"__kmpc_global_ctor_", ""});
1675 llvm::Function *Fn =
1676 CGM.CreateGlobalInitOrCleanUpFunction(FTy, Name, FI, Loc);
1677 CtorCGF.StartFunction(GlobalDecl(), CGM.getContext().VoidPtrTy, Fn, FI,
1678 Args, Loc, Loc);
1679 llvm::Value *ArgVal = CtorCGF.EmitLoadOfScalar(
1680 CtorCGF.GetAddrOfLocalVar(Dst), /*Volatile=*/false,
1681 CGM.getContext().VoidPtrTy, Dst->getLocation());
1682 Address Arg(ArgVal, CtorCGF.ConvertTypeForMem(ASTTy),
1683 VDAddr.getAlignment());
1684 CtorCGF.EmitAnyExprToMem(Init, Arg, Init->getType().getQualifiers(),
1685 /*IsInitializer=*/true);
1686 ArgVal = CtorCGF.EmitLoadOfScalar(
1687 CtorCGF.GetAddrOfLocalVar(Dst), /*Volatile=*/false,
1688 CGM.getContext().VoidPtrTy, Dst->getLocation());
1689 CtorCGF.Builder.CreateStore(ArgVal, CtorCGF.ReturnValue);
1690 CtorCGF.FinishFunction();
1691 Ctor = Fn;
1692 }
1694 // Generate function that emits destructor call for the threadprivate copy
1695 // of the variable VD
1696 CodeGenFunction DtorCGF(CGM);
1697 auto *Dst = ImplicitParamDecl::Create(
1698 CGM.getContext(), /*DC=*/nullptr, Loc,
1699 /*Id=*/nullptr, CGM.getContext().VoidPtrTy, ImplicitParamKind::Other);
1700
1701 FunctionArgList Args{Dst};
1702 const auto &FI = CGM.getTypes().arrangeBuiltinFunctionDeclaration(
1703 CGM.getContext().VoidTy, Args);
1704 llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
1705 std::string Name = getName({"__kmpc_global_dtor_", ""});
1706 llvm::Function *Fn =
1707 CGM.CreateGlobalInitOrCleanUpFunction(FTy, Name, FI, Loc);
1708 auto NL = ApplyDebugLocation::CreateEmpty(DtorCGF);
1709 DtorCGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, Fn, FI, Args,
1710 Loc, Loc);
1711 // Create a scope with an artificial location for the body of this function.
1712 auto AL = ApplyDebugLocation::CreateArtificial(DtorCGF);
1713 llvm::Value *ArgVal = DtorCGF.EmitLoadOfScalar(
1714 DtorCGF.GetAddrOfLocalVar(Dst),
1715 /*Volatile=*/false, CGM.getContext().VoidPtrTy, Dst->getLocation());
1716 DtorCGF.emitDestroy(
1717 Address(ArgVal, DtorCGF.Int8Ty, VDAddr.getAlignment()), ASTTy,
1718 DtorCGF.getDestroyer(ASTTy.isDestructedType()),
1719 DtorCGF.needsEHCleanup(ASTTy.isDestructedType()));
1720 DtorCGF.FinishFunction();
1721 Dtor = Fn;
1722 }
1723 // Do not emit init function if it is not required.
1724 if (!Ctor && !Dtor)
1725 return nullptr;
1726
1727 // Copying constructor for the threadprivate variable.
1728 // Must be NULL - reserved by runtime, but currently it requires that this
1729 // parameter is always NULL. Otherwise it fires assertion.
1730 CopyCtor = llvm::Constant::getNullValue(CGM.DefaultPtrTy);
1731 if (Ctor == nullptr) {
1732 Ctor = llvm::Constant::getNullValue(CGM.DefaultPtrTy);
1733 }
1734 if (Dtor == nullptr) {
1735 Dtor = llvm::Constant::getNullValue(CGM.DefaultPtrTy);
1736 }
1737 if (!CGF) {
1738 auto *InitFunctionTy =
1739 llvm::FunctionType::get(CGM.VoidTy, /*isVarArg*/ false);
1740 std::string Name = getName({"__omp_threadprivate_init_", ""});
1741 llvm::Function *InitFunction = CGM.CreateGlobalInitOrCleanUpFunction(
1742 InitFunctionTy, Name, CGM.getTypes().arrangeNullaryFunction());
1743 CodeGenFunction InitCGF(CGM);
1744 FunctionArgList ArgList;
1745 InitCGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, InitFunction,
1746 CGM.getTypes().arrangeNullaryFunction(), ArgList,
1747 Loc, Loc);
1748 emitThreadPrivateVarInit(InitCGF, VDAddr, Ctor, CopyCtor, Dtor, Loc);
1749 InitCGF.FinishFunction();
1750 return InitFunction;
1751 }
1752 emitThreadPrivateVarInit(*CGF, VDAddr, Ctor, CopyCtor, Dtor, Loc);
1753 }
1754 return nullptr;
1755}
1756
1758 llvm::GlobalValue *GV) {
1759 std::optional<OMPDeclareTargetDeclAttr *> ActiveAttr =
1760 OMPDeclareTargetDeclAttr::getActiveAttr(FD);
1761
1762 // We only need to handle active 'indirect' declare target functions.
1763 if (!ActiveAttr || !(*ActiveAttr)->getIndirect())
1764 return;
1765
1766 // Get a mangled name to store the new device global in.
1767 llvm::TargetRegionEntryInfo EntryInfo = getEntryInfoFromPresumedLoc(
1769 SmallString<128> Name;
1770 OMPBuilder.OffloadInfoManager.getTargetRegionEntryFnName(Name, EntryInfo);
1771
1772 // We need to generate a new global to hold the address of the indirectly
1773 // called device function. Doing this allows us to keep the visibility and
1774 // linkage of the associated function unchanged while allowing the runtime to
1775 // access its value.
1776 llvm::GlobalValue *Addr = GV;
1777 if (CGM.getLangOpts().OpenMPIsTargetDevice) {
1778 llvm::PointerType *FnPtrTy = llvm::PointerType::get(
1779 CGM.getLLVMContext(),
1780 CGM.getModule().getDataLayout().getProgramAddressSpace());
1781 Addr = new llvm::GlobalVariable(
1782 CGM.getModule(), FnPtrTy,
1783 /*isConstant=*/true, llvm::GlobalValue::ExternalLinkage, GV, Name,
1784 nullptr, llvm::GlobalValue::NotThreadLocal,
1785 CGM.getModule().getDataLayout().getDefaultGlobalsAddressSpace());
1786 Addr->setVisibility(llvm::GlobalValue::ProtectedVisibility);
1787 }
1788
1789 // Register the indirect Vtable:
1790 // This is similar to OMPTargetGlobalVarEntryIndirect, except that the
1791 // size field refers to the size of memory pointed to, not the size of
1792 // the pointer symbol itself (which is implicitly the size of a pointer).
1793 OMPBuilder.OffloadInfoManager.registerDeviceGlobalVarEntryInfo(
1794 Name, Addr, CGM.GetTargetTypeStoreSize(CGM.VoidPtrTy).getQuantity(),
1795 llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryIndirect,
1796 llvm::GlobalValue::WeakODRLinkage);
1797}
1798
1799void CGOpenMPRuntime::registerVTableOffloadEntry(llvm::GlobalVariable *VTable,
1800 const VarDecl *VD) {
1801 // TODO: add logic to avoid duplicate vtable registrations per
1802 // translation unit; though for external linkage, this should no
1803 // longer be an issue - or at least we can avoid the issue by
1804 // checking for an existing offloading entry. But, perhaps the
1805 // better approach is to defer emission of the vtables and offload
1806 // entries until later (by tracking a list of items that need to be
1807 // emitted).
1808
1809 llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
1810
1811 // Generate a new externally visible global to point to the
1812 // internally visible vtable. Doing this allows us to keep the
1813 // visibility and linkage of the associated vtable unchanged while
1814 // allowing the runtime to access its value. The externally
1815 // visible global var needs to be emitted with a unique mangled
1816 // name that won't conflict with similarly named (internal)
1817 // vtables in other translation units.
1818
1819 // Register vtable with source location of dynamic object in map
1820 // clause.
1821 llvm::TargetRegionEntryInfo EntryInfo = getEntryInfoFromPresumedLoc(
1823 VTable->getName());
1824
1825 llvm::GlobalVariable *Addr = VTable;
1826 SmallString<128> AddrName;
1827 OMPBuilder.OffloadInfoManager.getTargetRegionEntryFnName(AddrName, EntryInfo);
1828 AddrName.append("addr");
1829
1830 if (CGM.getLangOpts().OpenMPIsTargetDevice) {
1831 Addr = new llvm::GlobalVariable(
1832 CGM.getModule(), VTable->getType(),
1833 /*isConstant=*/true, llvm::GlobalValue::ExternalLinkage, VTable,
1834 AddrName,
1835 /*InsertBefore=*/nullptr, llvm::GlobalValue::NotThreadLocal,
1836 CGM.getModule().getDataLayout().getDefaultGlobalsAddressSpace());
1837 Addr->setVisibility(llvm::GlobalValue::ProtectedVisibility);
1838 }
1839 OMPBuilder.OffloadInfoManager.registerDeviceGlobalVarEntryInfo(
1840 AddrName, VTable,
1841 CGM.getDataLayout().getTypeAllocSize(VTable->getInitializer()->getType()),
1842 llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryIndirectVTable,
1843 llvm::GlobalValue::WeakODRLinkage);
1844}
1845
1848 const VarDecl *VD) {
1849 // Register C++ VTable to OpenMP Offload Entry if it's a new
1850 // CXXRecordDecl.
1851 if (CXXRecord && CXXRecord->isDynamicClass() &&
1852 !CGM.getOpenMPRuntime().VTableDeclMap.contains(CXXRecord)) {
1853 auto Res = CGM.getOpenMPRuntime().VTableDeclMap.try_emplace(CXXRecord, VD);
1854 if (Res.second) {
1855 CGM.EmitVTable(CXXRecord);
1856 CodeGenVTables VTables = CGM.getVTables();
1857 llvm::GlobalVariable *VTablesAddr = VTables.GetAddrOfVTable(CXXRecord);
1858 assert(VTablesAddr && "Expected non-null VTable address");
1859 // Must set VTables to weak since we're emitting them in multiple TUs now
1860 if (VTablesAddr->hasExternalLinkage())
1861 VTablesAddr->setLinkage(llvm::GlobalValue::WeakODRLinkage);
1862 CGM.getOpenMPRuntime().registerVTableOffloadEntry(VTablesAddr, VD);
1863 // Emit VTable for all the fields containing dynamic CXXRecord
1864 for (const FieldDecl *Field : CXXRecord->fields()) {
1865 if (CXXRecordDecl *RecordDecl = Field->getType()->getAsCXXRecordDecl())
1867 }
1868 // Emit VTable for all dynamic parent class
1869 for (CXXBaseSpecifier &Base : CXXRecord->bases()) {
1870 if (CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl())
1871 emitAndRegisterVTable(CGM, BaseDecl, VD);
1872 }
1873 }
1874 }
1875}
1876
1878 // Register VTable by scanning through the map clause of OpenMP target region.
1879 // Get CXXRecordDecl and VarDecl from Expr.
1880 auto GetVTableDecl = [](const Expr *E) {
1881 QualType VDTy = E->getType();
1882 CXXRecordDecl *CXXRecord = nullptr;
1883 if (const auto *RefType = VDTy->getAs<LValueReferenceType>())
1884 VDTy = RefType->getPointeeType();
1885 if (VDTy->isPointerType())
1887 else
1888 CXXRecord = VDTy->getAsCXXRecordDecl();
1889
1890 const VarDecl *VD = nullptr;
1891 if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
1892 VD = cast<VarDecl>(DRE->getDecl());
1893 } else if (auto *MRE = dyn_cast<MemberExpr>(E)) {
1894 if (auto *BaseDRE = dyn_cast<DeclRefExpr>(MRE->getBase())) {
1895 if (auto *BaseVD = dyn_cast<VarDecl>(BaseDRE->getDecl()))
1896 VD = BaseVD;
1897 }
1898 }
1899 return std::pair<CXXRecordDecl *, const VarDecl *>(CXXRecord, VD);
1900 };
1901 // Collect VTable from OpenMP map clause.
1902 for (const auto *C : D.getClausesOfKind<OMPMapClause>()) {
1903 for (const auto *E : C->varlist()) {
1904 auto DeclPair = GetVTableDecl(E);
1905 // Ensure VD is not null
1906 if (DeclPair.second)
1907 emitAndRegisterVTable(CGM, DeclPair.first, DeclPair.second);
1908 }
1909 }
1910}
1911
1913 QualType VarType,
1914 StringRef Name) {
1915 std::string Suffix = getName({"artificial", ""});
1916 llvm::Type *VarLVType = CGF.ConvertTypeForMem(VarType);
1917 llvm::GlobalVariable *GAddr = OMPBuilder.getOrCreateInternalVariable(
1918 VarLVType, Twine(Name).concat(Suffix).str());
1919 if (CGM.getLangOpts().OpenMP && CGM.getLangOpts().OpenMPUseTLS &&
1920 CGM.getTarget().isTLSSupported()) {
1921 GAddr->setThreadLocal(/*Val=*/true);
1922 return Address(GAddr, GAddr->getValueType(),
1923 CGM.getContext().getTypeAlignInChars(VarType));
1924 }
1925 std::string CacheSuffix = getName({"cache", ""});
1926 llvm::Value *Args[] = {
1929 CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(GAddr, CGM.VoidPtrTy),
1930 CGF.Builder.CreateIntCast(CGF.getTypeSize(VarType), CGM.SizeTy,
1931 /*isSigned=*/false),
1932 OMPBuilder.getOrCreateInternalVariable(
1933 CGM.VoidPtrPtrTy,
1934 Twine(Name).concat(Suffix).concat(CacheSuffix).str())};
1935 return Address(
1937 CGF.EmitRuntimeCall(
1938 OMPBuilder.getOrCreateRuntimeFunction(
1939 CGM.getModule(), OMPRTL___kmpc_threadprivate_cached),
1940 Args),
1941 CGF.Builder.getPtrTy(0)),
1942 VarLVType, CGM.getContext().getTypeAlignInChars(VarType));
1943}
1944
1946 const RegionCodeGenTy &ThenGen,
1947 const RegionCodeGenTy &ElseGen) {
1948 CodeGenFunction::LexicalScope ConditionScope(CGF, Cond->getSourceRange());
1949
1950 // If the condition constant folds and can be elided, try to avoid emitting
1951 // the condition and the dead arm of the if/else.
1952 bool CondConstant;
1953 if (CGF.ConstantFoldsToSimpleInteger(Cond, CondConstant)) {
1954 if (CondConstant)
1955 ThenGen(CGF);
1956 else
1957 ElseGen(CGF);
1958 return;
1959 }
1960
1961 // Otherwise, the condition did not fold, or we couldn't elide it. Just
1962 // emit the conditional branch.
1963 llvm::BasicBlock *ThenBlock = CGF.createBasicBlock("omp_if.then");
1964 llvm::BasicBlock *ElseBlock = CGF.createBasicBlock("omp_if.else");
1965 llvm::BasicBlock *ContBlock = CGF.createBasicBlock("omp_if.end");
1966 CGF.EmitBranchOnBoolExpr(Cond, ThenBlock, ElseBlock, /*TrueCount=*/0);
1967
1968 // Emit the 'then' code.
1969 CGF.EmitBlock(ThenBlock);
1970 ThenGen(CGF);
1971 CGF.EmitBranch(ContBlock);
1972 // Emit the 'else' code if present.
1973 // There is no need to emit line number for unconditional branch.
1975 CGF.EmitBlock(ElseBlock);
1976 ElseGen(CGF);
1977 // There is no need to emit line number for unconditional branch.
1979 CGF.EmitBranch(ContBlock);
1980 // Emit the continuation block for code after the if.
1981 CGF.EmitBlock(ContBlock, /*IsFinished=*/true);
1982}
1983
1985 CodeGenFunction &CGF, SourceLocation Loc, llvm::Function *OutlinedFn,
1986 ArrayRef<llvm::Value *> CapturedVars, const Expr *IfCond,
1987 llvm::Value *NumThreads, OpenMPNumThreadsClauseModifier NumThreadsModifier,
1988 OpenMPSeverityClauseKind Severity, const Expr *Message) {
1989 if (!CGF.HaveInsertPoint())
1990 return;
1991 llvm::Value *RTLoc = emitUpdateLocation(CGF, Loc);
1992 auto &M = CGM.getModule();
1993 auto &&ThenGen = [&M, OutlinedFn, CapturedVars, RTLoc,
1994 this](CodeGenFunction &CGF, PrePostActionTy &) {
1995 // Build call __kmpc_fork_call(loc, n, microtask, var1, .., varn);
1996 llvm::Value *Args[] = {
1997 RTLoc,
1998 CGF.Builder.getInt32(CapturedVars.size()), // Number of captured vars
1999 OutlinedFn};
2001 RealArgs.append(std::begin(Args), std::end(Args));
2002 RealArgs.append(CapturedVars.begin(), CapturedVars.end());
2003
2004 llvm::FunctionCallee RTLFn =
2005 OMPBuilder.getOrCreateRuntimeFunction(M, OMPRTL___kmpc_fork_call);
2006 CGF.EmitRuntimeCall(RTLFn, RealArgs);
2007 };
2008 auto &&ElseGen = [&M, OutlinedFn, CapturedVars, RTLoc, Loc,
2009 this](CodeGenFunction &CGF, PrePostActionTy &) {
2011 llvm::Value *ThreadID = RT.getThreadID(CGF, Loc);
2012 // Build calls:
2013 // __kmpc_serialized_parallel(&Loc, GTid);
2014 llvm::Value *Args[] = {RTLoc, ThreadID};
2015 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
2016 M, OMPRTL___kmpc_serialized_parallel),
2017 Args);
2018
2019 // OutlinedFn(&GTid, &zero_bound, CapturedStruct);
2020 Address ThreadIDAddr = RT.emitThreadIDAddress(CGF, Loc);
2021 RawAddress ZeroAddrBound =
2023 /*Name=*/".bound.zero.addr");
2024 CGF.Builder.CreateStore(CGF.Builder.getInt32(/*C*/ 0), ZeroAddrBound);
2026 // ThreadId for serialized parallels is 0.
2027 OutlinedFnArgs.push_back(ThreadIDAddr.emitRawPointer(CGF));
2028 OutlinedFnArgs.push_back(ZeroAddrBound.getPointer());
2029 OutlinedFnArgs.append(CapturedVars.begin(), CapturedVars.end());
2030
2031 // Ensure we do not inline the function. This is trivially true for the ones
2032 // passed to __kmpc_fork_call but the ones called in serialized regions
2033 // could be inlined. This is not a perfect but it is closer to the invariant
2034 // we want, namely, every data environment starts with a new function.
2035 // TODO: We should pass the if condition to the runtime function and do the
2036 // handling there. Much cleaner code.
2037 OutlinedFn->removeFnAttr(llvm::Attribute::AlwaysInline);
2038 OutlinedFn->addFnAttr(llvm::Attribute::NoInline);
2039 RT.emitOutlinedFunctionCall(CGF, Loc, OutlinedFn, OutlinedFnArgs);
2040
2041 // __kmpc_end_serialized_parallel(&Loc, GTid);
2042 llvm::Value *EndArgs[] = {RT.emitUpdateLocation(CGF, Loc), ThreadID};
2043 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
2044 M, OMPRTL___kmpc_end_serialized_parallel),
2045 EndArgs);
2046 };
2047 if (IfCond) {
2048 emitIfClause(CGF, IfCond, ThenGen, ElseGen);
2049 } else {
2050 RegionCodeGenTy ThenRCG(ThenGen);
2051 ThenRCG(CGF);
2052 }
2053}
2054
2055// If we're inside an (outlined) parallel region, use the region info's
2056// thread-ID variable (it is passed in a first argument of the outlined function
2057// as "kmp_int32 *gtid"). Otherwise, if we're not inside parallel region, but in
2058// regular serial code region, get thread ID by calling kmp_int32
2059// kmpc_global_thread_num(ident_t *loc), stash this thread ID in a temporary and
2060// return the address of that temp.
2062 SourceLocation Loc) {
2063 if (auto *OMPRegionInfo =
2064 dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo))
2065 if (OMPRegionInfo->getThreadIDVariable())
2066 return OMPRegionInfo->getThreadIDVariableLValue(CGF).getAddress();
2067
2068 llvm::Value *ThreadID = getThreadID(CGF, Loc);
2069 QualType Int32Ty =
2070 CGF.getContext().getIntTypeForBitwidth(/*DestWidth*/ 32, /*Signed*/ true);
2071 Address ThreadIDTemp =
2072 CGF.CreateMemTempWithoutCast(Int32Ty, /*Name*/ ".threadid_temp.");
2073 CGF.EmitStoreOfScalar(ThreadID,
2074 CGF.MakeAddrLValue(ThreadIDTemp, Int32Ty));
2075
2076 return ThreadIDTemp;
2077}
2078
2079llvm::Value *CGOpenMPRuntime::getCriticalRegionLock(StringRef CriticalName) {
2080 std::string Prefix = Twine("gomp_critical_user_", CriticalName).str();
2081 std::string Name = getName({Prefix, "var"});
2082 llvm::GlobalVariable *GV =
2083 OMPBuilder.getOrCreateInternalVariable(KmpCriticalNameTy, Name);
2084 CGM.setDSOLocal(GV);
2085 return GV;
2086}
2087
2088namespace {
2089/// Common pre(post)-action for different OpenMP constructs.
2090class CommonActionTy final : public PrePostActionTy {
2091 llvm::FunctionCallee EnterCallee;
2092 ArrayRef<llvm::Value *> EnterArgs;
2093 llvm::FunctionCallee ExitCallee;
2094 ArrayRef<llvm::Value *> ExitArgs;
2095 bool Conditional;
2096 llvm::BasicBlock *ContBlock = nullptr;
2097
2098public:
2099 CommonActionTy(llvm::FunctionCallee EnterCallee,
2100 ArrayRef<llvm::Value *> EnterArgs,
2101 llvm::FunctionCallee ExitCallee,
2102 ArrayRef<llvm::Value *> ExitArgs, bool Conditional = false)
2103 : EnterCallee(EnterCallee), EnterArgs(EnterArgs), ExitCallee(ExitCallee),
2104 ExitArgs(ExitArgs), Conditional(Conditional) {}
2105 void Enter(CodeGenFunction &CGF) override {
2106 llvm::Value *EnterRes = CGF.EmitRuntimeCall(EnterCallee, EnterArgs);
2107 if (Conditional) {
2108 llvm::Value *CallBool = CGF.Builder.CreateIsNotNull(EnterRes);
2109 auto *ThenBlock = CGF.createBasicBlock("omp_if.then");
2110 ContBlock = CGF.createBasicBlock("omp_if.end");
2111 // Generate the branch (If-stmt)
2112 CGF.Builder.CreateCondBr(CallBool, ThenBlock, ContBlock);
2113 CGF.EmitBlock(ThenBlock);
2114 }
2115 }
2116 void Done(CodeGenFunction &CGF) {
2117 // Emit the rest of blocks/branches
2118 CGF.EmitBranch(ContBlock);
2119 CGF.EmitBlock(ContBlock, true);
2120 }
2121 void Exit(CodeGenFunction &CGF) override {
2122 CGF.EmitRuntimeCall(ExitCallee, ExitArgs);
2123 }
2124};
2125} // anonymous namespace
2126
2128 StringRef CriticalName,
2129 const RegionCodeGenTy &CriticalOpGen,
2130 SourceLocation Loc, const Expr *Hint) {
2131 // __kmpc_critical[_with_hint](ident_t *, gtid, Lock[, hint]);
2132 // CriticalOpGen();
2133 // __kmpc_end_critical(ident_t *, gtid, Lock);
2134 // Prepare arguments and build a call to __kmpc_critical
2135 if (!CGF.HaveInsertPoint())
2136 return;
2137 llvm::FunctionCallee RuntimeFcn = OMPBuilder.getOrCreateRuntimeFunction(
2138 CGM.getModule(),
2139 Hint ? OMPRTL___kmpc_critical_with_hint : OMPRTL___kmpc_critical);
2140 llvm::Value *LockVar = getCriticalRegionLock(CriticalName);
2141 unsigned LockVarArgIdx = 2;
2142 if (cast<llvm::GlobalVariable>(LockVar)->getAddressSpace() !=
2143 RuntimeFcn.getFunctionType()
2144 ->getParamType(LockVarArgIdx)
2145 ->getPointerAddressSpace())
2146 LockVar = CGF.Builder.CreateAddrSpaceCast(
2147 LockVar, RuntimeFcn.getFunctionType()->getParamType(LockVarArgIdx));
2148 llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
2149 LockVar};
2150 llvm::SmallVector<llvm::Value *, 4> EnterArgs(std::begin(Args),
2151 std::end(Args));
2152 if (Hint) {
2153 EnterArgs.push_back(CGF.Builder.CreateIntCast(
2154 CGF.EmitScalarExpr(Hint), CGM.Int32Ty, /*isSigned=*/false));
2155 }
2156 CommonActionTy Action(RuntimeFcn, EnterArgs,
2157 OMPBuilder.getOrCreateRuntimeFunction(
2158 CGM.getModule(), OMPRTL___kmpc_end_critical),
2159 Args);
2160 CriticalOpGen.setAction(Action);
2161 emitInlinedDirective(CGF, OMPD_critical, CriticalOpGen);
2162}
2163
2165 const RegionCodeGenTy &MasterOpGen,
2166 SourceLocation Loc) {
2167 if (!CGF.HaveInsertPoint())
2168 return;
2169 // if(__kmpc_master(ident_t *, gtid)) {
2170 // MasterOpGen();
2171 // __kmpc_end_master(ident_t *, gtid);
2172 // }
2173 // Prepare arguments and build a call to __kmpc_master
2174 llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
2175 CommonActionTy Action(OMPBuilder.getOrCreateRuntimeFunction(
2176 CGM.getModule(), OMPRTL___kmpc_master),
2177 Args,
2178 OMPBuilder.getOrCreateRuntimeFunction(
2179 CGM.getModule(), OMPRTL___kmpc_end_master),
2180 Args,
2181 /*Conditional=*/true);
2182 MasterOpGen.setAction(Action);
2183 emitInlinedDirective(CGF, OMPD_master, MasterOpGen);
2184 Action.Done(CGF);
2185}
2186
2188 const RegionCodeGenTy &MaskedOpGen,
2189 SourceLocation Loc, const Expr *Filter) {
2190 if (!CGF.HaveInsertPoint())
2191 return;
2192 // if(__kmpc_masked(ident_t *, gtid, filter)) {
2193 // MaskedOpGen();
2194 // __kmpc_end_masked(iden_t *, gtid);
2195 // }
2196 // Prepare arguments and build a call to __kmpc_masked
2197 llvm::Value *FilterVal = Filter
2198 ? CGF.EmitScalarExpr(Filter, CGF.Int32Ty)
2199 : llvm::ConstantInt::get(CGM.Int32Ty, /*V=*/0);
2200 llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
2201 FilterVal};
2202 llvm::Value *ArgsEnd[] = {emitUpdateLocation(CGF, Loc),
2203 getThreadID(CGF, Loc)};
2204 CommonActionTy Action(OMPBuilder.getOrCreateRuntimeFunction(
2205 CGM.getModule(), OMPRTL___kmpc_masked),
2206 Args,
2207 OMPBuilder.getOrCreateRuntimeFunction(
2208 CGM.getModule(), OMPRTL___kmpc_end_masked),
2209 ArgsEnd,
2210 /*Conditional=*/true);
2211 MaskedOpGen.setAction(Action);
2212 emitInlinedDirective(CGF, OMPD_masked, MaskedOpGen);
2213 Action.Done(CGF);
2214}
2215
2217 SourceLocation Loc) {
2218 if (!CGF.HaveInsertPoint())
2219 return;
2220 if (CGF.CGM.getLangOpts().OpenMPIRBuilder) {
2221 OMPBuilder.createTaskyield(CGF.Builder);
2222 } else {
2223 // Build call __kmpc_omp_taskyield(loc, thread_id, 0);
2224 llvm::Value *Args[] = {
2225 emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
2226 llvm::ConstantInt::get(CGM.IntTy, /*V=*/0, /*isSigned=*/true)};
2227 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
2228 CGM.getModule(), OMPRTL___kmpc_omp_taskyield),
2229 Args);
2230 }
2231
2232 if (auto *Region = dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo))
2233 Region->emitUntiedSwitch(CGF);
2234}
2235
2237 const RegionCodeGenTy &TaskgroupOpGen,
2238 SourceLocation Loc) {
2239 if (!CGF.HaveInsertPoint())
2240 return;
2241 // __kmpc_taskgroup(ident_t *, gtid);
2242 // TaskgroupOpGen();
2243 // __kmpc_end_taskgroup(ident_t *, gtid);
2244 // Prepare arguments and build a call to __kmpc_taskgroup
2245 llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
2246 CommonActionTy Action(OMPBuilder.getOrCreateRuntimeFunction(
2247 CGM.getModule(), OMPRTL___kmpc_taskgroup),
2248 Args,
2249 OMPBuilder.getOrCreateRuntimeFunction(
2250 CGM.getModule(), OMPRTL___kmpc_end_taskgroup),
2251 Args);
2252 TaskgroupOpGen.setAction(Action);
2253 emitInlinedDirective(CGF, OMPD_taskgroup, TaskgroupOpGen);
2254}
2255
2256/// Given an array of pointers to variables, project the address of a
2257/// given variable.
2259 unsigned Index, const VarDecl *Var) {
2260 // Pull out the pointer to the variable.
2261 Address PtrAddr = CGF.Builder.CreateConstArrayGEP(Array, Index);
2262 llvm::Value *Ptr = CGF.Builder.CreateLoad(PtrAddr);
2263
2264 llvm::Type *ElemTy = CGF.ConvertTypeForMem(Var->getType());
2265 return Address(Ptr, ElemTy, CGF.getContext().getDeclAlign(Var));
2266}
2267
2269 CodeGenModule &CGM, llvm::Type *ArgsElemType,
2270 ArrayRef<const Expr *> CopyprivateVars, ArrayRef<const Expr *> DestExprs,
2271 ArrayRef<const Expr *> SrcExprs, ArrayRef<const Expr *> AssignmentOps,
2272 SourceLocation Loc) {
2273 ASTContext &C = CGM.getContext();
2274 // void copy_func(void *LHSArg, void *RHSArg);
2275
2276 auto *LHSArg =
2277 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
2278 C.VoidPtrTy, ImplicitParamKind::Other);
2279 auto *RHSArg =
2280 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
2281 C.VoidPtrTy, ImplicitParamKind::Other);
2282 FunctionArgList Args{LHSArg, RHSArg};
2283 const auto &CGFI =
2284 CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
2285 std::string Name =
2286 CGM.getOpenMPRuntime().getName({"omp", "copyprivate", "copy_func"});
2287 auto *Fn = llvm::Function::Create(CGM.getTypes().GetFunctionType(CGFI),
2288 llvm::GlobalValue::InternalLinkage, Name,
2289 &CGM.getModule());
2291 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
2292 Fn->addFnAttr("sample-profile-suffix-elision-policy", "selected");
2293 Fn->setDoesNotRecurse();
2294 CodeGenFunction CGF(CGM);
2295 CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, CGFI, Args, Loc, Loc);
2296 // Dest = (void*[n])(LHSArg);
2297 // Src = (void*[n])(RHSArg);
2299 CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(LHSArg)),
2300 CGF.Builder.getPtrTy(0)),
2301 ArgsElemType, CGF.getPointerAlign());
2303 CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(RHSArg)),
2304 CGF.Builder.getPtrTy(0)),
2305 ArgsElemType, CGF.getPointerAlign());
2306 // *(Type0*)Dst[0] = *(Type0*)Src[0];
2307 // *(Type1*)Dst[1] = *(Type1*)Src[1];
2308 // ...
2309 // *(Typen*)Dst[n] = *(Typen*)Src[n];
2310 for (unsigned I = 0, E = AssignmentOps.size(); I < E; ++I) {
2311 const auto *DestVar =
2312 cast<VarDecl>(cast<DeclRefExpr>(DestExprs[I])->getDecl());
2313 Address DestAddr = emitAddrOfVarFromArray(CGF, LHS, I, DestVar);
2314
2315 const auto *SrcVar =
2316 cast<VarDecl>(cast<DeclRefExpr>(SrcExprs[I])->getDecl());
2317 Address SrcAddr = emitAddrOfVarFromArray(CGF, RHS, I, SrcVar);
2318
2319 const auto *VD = cast<DeclRefExpr>(CopyprivateVars[I])->getDecl();
2320 QualType Type = VD->getType();
2321 CGF.EmitOMPCopy(Type, DestAddr, SrcAddr, DestVar, SrcVar, AssignmentOps[I]);
2322 }
2323 CGF.FinishFunction();
2324 return Fn;
2325}
2326
2328 const RegionCodeGenTy &SingleOpGen,
2329 SourceLocation Loc,
2330 ArrayRef<const Expr *> CopyprivateVars,
2331 ArrayRef<const Expr *> SrcExprs,
2332 ArrayRef<const Expr *> DstExprs,
2333 ArrayRef<const Expr *> AssignmentOps) {
2334 if (!CGF.HaveInsertPoint())
2335 return;
2336 assert(CopyprivateVars.size() == SrcExprs.size() &&
2337 CopyprivateVars.size() == DstExprs.size() &&
2338 CopyprivateVars.size() == AssignmentOps.size());
2339 ASTContext &C = CGM.getContext();
2340 // int32 did_it = 0;
2341 // if(__kmpc_single(ident_t *, gtid)) {
2342 // SingleOpGen();
2343 // __kmpc_end_single(ident_t *, gtid);
2344 // did_it = 1;
2345 // }
2346 // call __kmpc_copyprivate(ident_t *, gtid, <buf_size>, <copyprivate list>,
2347 // <copy_func>, did_it);
2348
2349 Address DidIt = Address::invalid();
2350 if (!CopyprivateVars.empty()) {
2351 // int32 did_it = 0;
2352 QualType KmpInt32Ty =
2353 C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1);
2354 DidIt = CGF.CreateMemTempWithoutCast(KmpInt32Ty, ".omp.copyprivate.did_it");
2355 CGF.Builder.CreateStore(CGF.Builder.getInt32(0), DidIt);
2356 }
2357 // Prepare arguments and build a call to __kmpc_single
2358 llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
2359 CommonActionTy Action(OMPBuilder.getOrCreateRuntimeFunction(
2360 CGM.getModule(), OMPRTL___kmpc_single),
2361 Args,
2362 OMPBuilder.getOrCreateRuntimeFunction(
2363 CGM.getModule(), OMPRTL___kmpc_end_single),
2364 Args,
2365 /*Conditional=*/true);
2366 SingleOpGen.setAction(Action);
2367 emitInlinedDirective(CGF, OMPD_single, SingleOpGen);
2368 if (DidIt.isValid()) {
2369 // did_it = 1;
2370 CGF.Builder.CreateStore(CGF.Builder.getInt32(1), DidIt);
2371 }
2372 Action.Done(CGF);
2373 // call __kmpc_copyprivate(ident_t *, gtid, <buf_size>, <copyprivate list>,
2374 // <copy_func>, did_it);
2375 if (DidIt.isValid()) {
2376 llvm::APInt ArraySize(/*unsigned int numBits=*/32, CopyprivateVars.size());
2377 QualType CopyprivateArrayTy = C.getConstantArrayType(
2378 C.VoidPtrTy, ArraySize, nullptr, ArraySizeModifier::Normal,
2379 /*IndexTypeQuals=*/0);
2380 // Create a list of all private variables for copyprivate.
2381 Address CopyprivateList = CGF.CreateMemTempWithoutCast(
2382 CopyprivateArrayTy, ".omp.copyprivate.cpr_list");
2383 for (unsigned I = 0, E = CopyprivateVars.size(); I < E; ++I) {
2384 Address Elem = CGF.Builder.CreateConstArrayGEP(CopyprivateList, I);
2385 CGF.Builder.CreateStore(
2387 CGF.EmitLValue(CopyprivateVars[I]).getPointer(CGF),
2388 CGF.VoidPtrTy),
2389 Elem);
2390 }
2391 // Build function that copies private values from single region to all other
2392 // threads in the corresponding parallel region.
2393 llvm::Value *CpyFn = emitCopyprivateCopyFunction(
2394 CGM, CGF.ConvertTypeForMem(CopyprivateArrayTy), CopyprivateVars,
2395 SrcExprs, DstExprs, AssignmentOps, Loc);
2396 llvm::Value *BufSize = CGF.getTypeSize(CopyprivateArrayTy);
2398 CopyprivateList, CGF.VoidPtrTy, CGF.Int8Ty);
2399 llvm::Value *DidItVal = CGF.Builder.CreateLoad(DidIt);
2400 llvm::Value *Args[] = {
2401 emitUpdateLocation(CGF, Loc), // ident_t *<loc>
2402 getThreadID(CGF, Loc), // i32 <gtid>
2403 BufSize, // size_t <buf_size>
2404 CL.emitRawPointer(CGF), // void *<copyprivate list>
2405 CpyFn, // void (*) (void *, void *) <copy_func>
2406 DidItVal // i32 did_it
2407 };
2408 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
2409 CGM.getModule(), OMPRTL___kmpc_copyprivate),
2410 Args);
2411 }
2412}
2413
2415 const RegionCodeGenTy &OrderedOpGen,
2416 SourceLocation Loc, bool IsThreads) {
2417 if (!CGF.HaveInsertPoint())
2418 return;
2419 // __kmpc_ordered(ident_t *, gtid);
2420 // OrderedOpGen();
2421 // __kmpc_end_ordered(ident_t *, gtid);
2422 // Prepare arguments and build a call to __kmpc_ordered
2423 if (IsThreads) {
2424 llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
2425 CommonActionTy Action(OMPBuilder.getOrCreateRuntimeFunction(
2426 CGM.getModule(), OMPRTL___kmpc_ordered),
2427 Args,
2428 OMPBuilder.getOrCreateRuntimeFunction(
2429 CGM.getModule(), OMPRTL___kmpc_end_ordered),
2430 Args);
2431 OrderedOpGen.setAction(Action);
2432 emitInlinedDirective(CGF, OMPD_ordered, OrderedOpGen);
2433 return;
2434 }
2435 emitInlinedDirective(CGF, OMPD_ordered, OrderedOpGen);
2436}
2437
2439 unsigned Flags;
2440 if (Kind == OMPD_for)
2441 Flags = OMP_IDENT_BARRIER_IMPL_FOR;
2442 else if (Kind == OMPD_sections)
2443 Flags = OMP_IDENT_BARRIER_IMPL_SECTIONS;
2444 else if (Kind == OMPD_single)
2445 Flags = OMP_IDENT_BARRIER_IMPL_SINGLE;
2446 else if (Kind == OMPD_barrier)
2447 Flags = OMP_IDENT_BARRIER_EXPL;
2448 else
2449 Flags = OMP_IDENT_BARRIER_IMPL;
2450 return Flags;
2451}
2452
2454 CodeGenFunction &CGF, const OMPLoopDirective &S,
2455 OpenMPScheduleClauseKind &ScheduleKind, const Expr *&ChunkExpr) const {
2456 // Check if the loop directive is actually a doacross loop directive. In this
2457 // case choose static, 1 schedule.
2458 if (llvm::any_of(
2459 S.getClausesOfKind<OMPOrderedClause>(),
2460 [](const OMPOrderedClause *C) { return C->getNumForLoops(); })) {
2461 ScheduleKind = OMPC_SCHEDULE_static;
2462 // Chunk size is 1 in this case.
2463 llvm::APInt ChunkSize(32, 1);
2464 ChunkExpr = IntegerLiteral::Create(
2465 CGF.getContext(), ChunkSize,
2466 CGF.getContext().getIntTypeForBitwidth(32, /*Signed=*/0),
2467 SourceLocation());
2468 }
2469}
2470
2472 OpenMPDirectiveKind Kind, bool EmitChecks,
2473 bool ForceSimpleCall) {
2474 // Check if we should use the OMPBuilder
2475 auto *OMPRegionInfo =
2476 dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo);
2477 if (CGF.CGM.getLangOpts().OpenMPIRBuilder) {
2478 llvm::OpenMPIRBuilder::InsertPointTy AfterIP =
2479 cantFail(OMPBuilder.createBarrier(CGF.Builder, Kind, ForceSimpleCall,
2480 EmitChecks));
2481 CGF.Builder.restoreIP(AfterIP);
2482 return;
2483 }
2484
2485 if (!CGF.HaveInsertPoint())
2486 return;
2487 // Build call __kmpc_cancel_barrier(loc, thread_id);
2488 // Build call __kmpc_barrier(loc, thread_id);
2489 unsigned Flags = getDefaultFlagsForBarriers(Kind);
2490 // Build call __kmpc_cancel_barrier(loc, thread_id) or __kmpc_barrier(loc,
2491 // thread_id);
2492 llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc, Flags),
2493 getThreadID(CGF, Loc)};
2494 if (OMPRegionInfo) {
2495 if (!ForceSimpleCall && OMPRegionInfo->hasCancel()) {
2496 llvm::Value *Result = CGF.EmitRuntimeCall(
2497 OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(),
2498 OMPRTL___kmpc_cancel_barrier),
2499 Args);
2500 if (EmitChecks) {
2501 // if (__kmpc_cancel_barrier()) {
2502 // exit from construct;
2503 // }
2504 llvm::BasicBlock *ExitBB = CGF.createBasicBlock(".cancel.exit");
2505 llvm::BasicBlock *ContBB = CGF.createBasicBlock(".cancel.continue");
2506 llvm::Value *Cmp = CGF.Builder.CreateIsNotNull(Result);
2507 CGF.Builder.CreateCondBr(Cmp, ExitBB, ContBB);
2508 CGF.EmitBlock(ExitBB);
2509 // exit from construct;
2510 CodeGenFunction::JumpDest CancelDestination =
2511 CGF.getOMPCancelDestination(OMPRegionInfo->getDirectiveKind());
2512 CGF.EmitBranchThroughCleanup(CancelDestination);
2513 CGF.EmitBlock(ContBB, /*IsFinished=*/true);
2514 }
2515 return;
2516 }
2517 }
2518 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
2519 CGM.getModule(), OMPRTL___kmpc_barrier),
2520 Args);
2521}
2522
2524 Expr *ME, bool IsFatal) {
2525 llvm::Value *MVL = ME ? CGF.EmitScalarExpr(ME)
2526 : llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
2527 // Build call void __kmpc_error(ident_t *loc, int severity, const char
2528 // *message)
2529 llvm::Value *Args[] = {
2530 emitUpdateLocation(CGF, Loc, /*Flags=*/0, /*GenLoc=*/true),
2531 llvm::ConstantInt::get(CGM.Int32Ty, IsFatal ? 2 : 1),
2532 CGF.Builder.CreatePointerCast(MVL, CGM.Int8PtrTy)};
2533 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
2534 CGM.getModule(), OMPRTL___kmpc_error),
2535 Args);
2536}
2537
2538/// Map the OpenMP loop schedule to the runtime enumeration.
2539static OpenMPSchedType getRuntimeSchedule(OpenMPScheduleClauseKind ScheduleKind,
2540 bool Chunked, bool Ordered) {
2541 switch (ScheduleKind) {
2542 case OMPC_SCHEDULE_static:
2543 return Chunked ? (Ordered ? OMP_ord_static_chunked : OMP_sch_static_chunked)
2544 : (Ordered ? OMP_ord_static : OMP_sch_static);
2545 case OMPC_SCHEDULE_dynamic:
2546 return Ordered ? OMP_ord_dynamic_chunked : OMP_sch_dynamic_chunked;
2547 case OMPC_SCHEDULE_guided:
2548 return Ordered ? OMP_ord_guided_chunked : OMP_sch_guided_chunked;
2549 case OMPC_SCHEDULE_runtime:
2550 return Ordered ? OMP_ord_runtime : OMP_sch_runtime;
2551 case OMPC_SCHEDULE_auto:
2552 return Ordered ? OMP_ord_auto : OMP_sch_auto;
2554 assert(!Chunked && "chunk was specified but schedule kind not known");
2555 return Ordered ? OMP_ord_static : OMP_sch_static;
2556 }
2557 llvm_unreachable("Unexpected runtime schedule");
2558}
2559
2560/// Map the OpenMP distribute schedule to the runtime enumeration.
2561static OpenMPSchedType
2563 // only static is allowed for dist_schedule
2564 return Chunked ? OMP_dist_sch_static_chunked : OMP_dist_sch_static;
2565}
2566
2568 bool Chunked) const {
2569 OpenMPSchedType Schedule =
2570 getRuntimeSchedule(ScheduleKind, Chunked, /*Ordered=*/false);
2571 return Schedule == OMP_sch_static;
2572}
2573
2575 OpenMPDistScheduleClauseKind ScheduleKind, bool Chunked) const {
2576 OpenMPSchedType Schedule = getRuntimeSchedule(ScheduleKind, Chunked);
2577 return Schedule == OMP_dist_sch_static;
2578}
2579
2581 bool Chunked) const {
2582 OpenMPSchedType Schedule =
2583 getRuntimeSchedule(ScheduleKind, Chunked, /*Ordered=*/false);
2584 return Schedule == OMP_sch_static_chunked;
2585}
2586
2588 OpenMPDistScheduleClauseKind ScheduleKind, bool Chunked) const {
2589 OpenMPSchedType Schedule = getRuntimeSchedule(ScheduleKind, Chunked);
2590 return Schedule == OMP_dist_sch_static_chunked;
2591}
2592
2594 OpenMPSchedType Schedule =
2595 getRuntimeSchedule(ScheduleKind, /*Chunked=*/false, /*Ordered=*/false);
2596 assert(Schedule != OMP_sch_static_chunked && "cannot be chunked here");
2597 return Schedule != OMP_sch_static;
2598}
2599
2600static int addMonoNonMonoModifier(CodeGenModule &CGM, OpenMPSchedType Schedule,
2603 int Modifier = 0;
2604 switch (M1) {
2605 case OMPC_SCHEDULE_MODIFIER_monotonic:
2606 Modifier = OMP_sch_modifier_monotonic;
2607 break;
2608 case OMPC_SCHEDULE_MODIFIER_nonmonotonic:
2609 Modifier = OMP_sch_modifier_nonmonotonic;
2610 break;
2611 case OMPC_SCHEDULE_MODIFIER_simd:
2612 if (Schedule == OMP_sch_static_chunked)
2613 Schedule = OMP_sch_static_balanced_chunked;
2614 break;
2617 break;
2618 }
2619 switch (M2) {
2620 case OMPC_SCHEDULE_MODIFIER_monotonic:
2621 Modifier = OMP_sch_modifier_monotonic;
2622 break;
2623 case OMPC_SCHEDULE_MODIFIER_nonmonotonic:
2624 Modifier = OMP_sch_modifier_nonmonotonic;
2625 break;
2626 case OMPC_SCHEDULE_MODIFIER_simd:
2627 if (Schedule == OMP_sch_static_chunked)
2628 Schedule = OMP_sch_static_balanced_chunked;
2629 break;
2632 break;
2633 }
2634 // OpenMP 5.0, 2.9.2 Worksharing-Loop Construct, Desription.
2635 // If the static schedule kind is specified or if the ordered clause is
2636 // specified, and if the nonmonotonic modifier is not specified, the effect is
2637 // as if the monotonic modifier is specified. Otherwise, unless the monotonic
2638 // modifier is specified, the effect is as if the nonmonotonic modifier is
2639 // specified.
2640 if (CGM.getLangOpts().OpenMP >= 50 && Modifier == 0) {
2641 if (!(Schedule == OMP_sch_static_chunked || Schedule == OMP_sch_static ||
2642 Schedule == OMP_sch_static_balanced_chunked ||
2643 Schedule == OMP_ord_static_chunked || Schedule == OMP_ord_static ||
2644 Schedule == OMP_dist_sch_static_chunked ||
2645 Schedule == OMP_dist_sch_static ||
2646 Schedule == OMP_dist_sch_static_chunked_sch_static_chunkone))
2647 Modifier = OMP_sch_modifier_nonmonotonic;
2648 }
2649 return Schedule | Modifier;
2650}
2651
2654 const OpenMPScheduleTy &ScheduleKind, unsigned IVSize, bool IVSigned,
2655 bool Ordered, const DispatchRTInput &DispatchValues) {
2656 if (!CGF.HaveInsertPoint())
2657 return;
2658 OpenMPSchedType Schedule = getRuntimeSchedule(
2659 ScheduleKind.Schedule, DispatchValues.Chunk != nullptr, Ordered);
2660 assert(Ordered ||
2661 (Schedule != OMP_sch_static && Schedule != OMP_sch_static_chunked &&
2662 Schedule != OMP_ord_static && Schedule != OMP_ord_static_chunked &&
2663 Schedule != OMP_sch_static_balanced_chunked));
2664 // Call __kmpc_dispatch_init(
2665 // ident_t *loc, kmp_int32 tid, kmp_int32 schedule,
2666 // kmp_int[32|64] lower, kmp_int[32|64] upper,
2667 // kmp_int[32|64] stride, kmp_int[32|64] chunk);
2668
2669 // If the Chunk was not specified in the clause - use default value 1.
2670 llvm::Value *Chunk = DispatchValues.Chunk ? DispatchValues.Chunk
2671 : CGF.Builder.getIntN(IVSize, 1);
2672 llvm::Value *Args[] = {
2673 emitUpdateLocation(CGF, Loc),
2674 getThreadID(CGF, Loc),
2675 CGF.Builder.getInt32(addMonoNonMonoModifier(
2676 CGM, Schedule, ScheduleKind.M1, ScheduleKind.M2)), // Schedule type
2677 DispatchValues.LB, // Lower
2678 DispatchValues.UB, // Upper
2679 CGF.Builder.getIntN(IVSize, 1), // Stride
2680 Chunk // Chunk
2681 };
2682 CGF.EmitRuntimeCall(OMPBuilder.createDispatchInitFunction(IVSize, IVSigned),
2683 Args);
2684}
2685
2687 SourceLocation Loc) {
2688 if (!CGF.HaveInsertPoint())
2689 return;
2690 // Call __kmpc_dispatch_deinit(ident_t *loc, kmp_int32 tid);
2691 llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
2692 CGF.EmitRuntimeCall(OMPBuilder.createDispatchDeinitFunction(), Args);
2693}
2694
2696 CodeGenFunction &CGF, llvm::Value *UpdateLocation, llvm::Value *ThreadId,
2697 llvm::FunctionCallee ForStaticInitFunction, OpenMPSchedType Schedule,
2699 const CGOpenMPRuntime::StaticRTInput &Values) {
2700 if (!CGF.HaveInsertPoint())
2701 return;
2702
2703 assert(!Values.Ordered);
2704 assert(Schedule == OMP_sch_static || Schedule == OMP_sch_static_chunked ||
2705 Schedule == OMP_sch_static_balanced_chunked ||
2706 Schedule == OMP_ord_static || Schedule == OMP_ord_static_chunked ||
2707 Schedule == OMP_dist_sch_static ||
2708 Schedule == OMP_dist_sch_static_chunked ||
2709 Schedule == OMP_dist_sch_static_chunked_sch_static_chunkone);
2710
2711 // Call __kmpc_for_static_init(
2712 // ident_t *loc, kmp_int32 tid, kmp_int32 schedtype,
2713 // kmp_int32 *p_lastiter, kmp_int[32|64] *p_lower,
2714 // kmp_int[32|64] *p_upper, kmp_int[32|64] *p_stride,
2715 // kmp_int[32|64] incr, kmp_int[32|64] chunk);
2716 llvm::Value *Chunk = Values.Chunk;
2717 if (Chunk == nullptr) {
2718 assert((Schedule == OMP_sch_static || Schedule == OMP_ord_static ||
2719 Schedule == OMP_dist_sch_static) &&
2720 "expected static non-chunked schedule");
2721 // If the Chunk was not specified in the clause - use default value 1.
2722 Chunk = CGF.Builder.getIntN(Values.IVSize, 1);
2723 } else {
2724 assert((Schedule == OMP_sch_static_chunked ||
2725 Schedule == OMP_sch_static_balanced_chunked ||
2726 Schedule == OMP_ord_static_chunked ||
2727 Schedule == OMP_dist_sch_static_chunked ||
2728 Schedule == OMP_dist_sch_static_chunked_sch_static_chunkone) &&
2729 "expected static chunked schedule");
2730 }
2731 llvm::Value *Args[] = {
2732 UpdateLocation,
2733 ThreadId,
2734 CGF.Builder.getInt32(addMonoNonMonoModifier(CGF.CGM, Schedule, M1,
2735 M2)), // Schedule type
2736 Values.IL.emitRawPointer(CGF), // &isLastIter
2737 Values.LB.emitRawPointer(CGF), // &LB
2738 Values.UB.emitRawPointer(CGF), // &UB
2739 Values.ST.emitRawPointer(CGF), // &Stride
2740 CGF.Builder.getIntN(Values.IVSize, 1), // Incr
2741 Chunk // Chunk
2742 };
2743 CGF.EmitRuntimeCall(ForStaticInitFunction, Args);
2744}
2745
2747 SourceLocation Loc,
2748 OpenMPDirectiveKind DKind,
2749 const OpenMPScheduleTy &ScheduleKind,
2750 const StaticRTInput &Values) {
2751 OpenMPSchedType ScheduleNum =
2752 ScheduleKind.UseFusedDistChunkSchedule
2753 ? OMP_dist_sch_static_chunked_sch_static_chunkone
2754 : getRuntimeSchedule(ScheduleKind.Schedule, Values.Chunk != nullptr,
2755 Values.Ordered);
2756 assert((isOpenMPWorksharingDirective(DKind) || (DKind == OMPD_loop)) &&
2757 "Expected loop-based or sections-based directive.");
2758 llvm::Value *UpdatedLocation = emitUpdateLocation(CGF, Loc,
2760 ? OMP_IDENT_WORK_LOOP
2761 : OMP_IDENT_WORK_SECTIONS);
2762 llvm::Value *ThreadId = getThreadID(CGF, Loc);
2763 llvm::FunctionCallee StaticInitFunction =
2764 OMPBuilder.createForStaticInitFunction(Values.IVSize, Values.IVSigned,
2765 false);
2767 emitForStaticInitCall(CGF, UpdatedLocation, ThreadId, StaticInitFunction,
2768 ScheduleNum, ScheduleKind.M1, ScheduleKind.M2, Values);
2769}
2770
2774 const CGOpenMPRuntime::StaticRTInput &Values) {
2775 OpenMPSchedType ScheduleNum =
2776 getRuntimeSchedule(SchedKind, Values.Chunk != nullptr);
2777 llvm::Value *UpdatedLocation =
2778 emitUpdateLocation(CGF, Loc, OMP_IDENT_WORK_DISTRIBUTE);
2779 llvm::Value *ThreadId = getThreadID(CGF, Loc);
2780 llvm::FunctionCallee StaticInitFunction;
2781 bool isGPUDistribute =
2782 CGM.getLangOpts().OpenMPIsTargetDevice && CGM.getTriple().isGPU();
2783 StaticInitFunction = OMPBuilder.createForStaticInitFunction(
2784 Values.IVSize, Values.IVSigned, isGPUDistribute);
2785
2786 emitForStaticInitCall(CGF, UpdatedLocation, ThreadId, StaticInitFunction,
2787 ScheduleNum, OMPC_SCHEDULE_MODIFIER_unknown,
2789}
2790
2792 SourceLocation Loc,
2793 OpenMPDirectiveKind DKind) {
2794 assert((DKind == OMPD_distribute || DKind == OMPD_for ||
2795 DKind == OMPD_sections) &&
2796 "Expected distribute, for, or sections directive kind");
2797 if (!CGF.HaveInsertPoint())
2798 return;
2799 // Call __kmpc_for_static_fini(ident_t *loc, kmp_int32 tid);
2800 llvm::Value *Args[] = {
2801 emitUpdateLocation(CGF, Loc,
2803 (DKind == OMPD_target_teams_loop)
2804 ? OMP_IDENT_WORK_DISTRIBUTE
2805 : isOpenMPLoopDirective(DKind)
2806 ? OMP_IDENT_WORK_LOOP
2807 : OMP_IDENT_WORK_SECTIONS),
2808 getThreadID(CGF, Loc)};
2810 if (isOpenMPDistributeDirective(DKind) &&
2811 CGM.getLangOpts().OpenMPIsTargetDevice && CGM.getTriple().isGPU())
2812 CGF.EmitRuntimeCall(
2813 OMPBuilder.getOrCreateRuntimeFunction(
2814 CGM.getModule(), OMPRTL___kmpc_distribute_static_fini),
2815 Args);
2816 else
2817 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
2818 CGM.getModule(), OMPRTL___kmpc_for_static_fini),
2819 Args);
2820}
2821
2823 SourceLocation Loc,
2824 unsigned IVSize,
2825 bool IVSigned) {
2826 if (!CGF.HaveInsertPoint())
2827 return;
2828 // Call __kmpc_for_dynamic_fini_(4|8)[u](ident_t *loc, kmp_int32 tid);
2829 llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
2830 CGF.EmitRuntimeCall(OMPBuilder.createDispatchFiniFunction(IVSize, IVSigned),
2831 Args);
2832}
2833
2835 SourceLocation Loc, unsigned IVSize,
2836 bool IVSigned, Address IL,
2837 Address LB, Address UB,
2838 Address ST) {
2839 // Call __kmpc_dispatch_next(
2840 // ident_t *loc, kmp_int32 tid, kmp_int32 *p_lastiter,
2841 // kmp_int[32|64] *p_lower, kmp_int[32|64] *p_upper,
2842 // kmp_int[32|64] *p_stride);
2843 llvm::Value *Args[] = {
2844 emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
2845 IL.emitRawPointer(CGF), // &isLastIter
2846 LB.emitRawPointer(CGF), // &Lower
2847 UB.emitRawPointer(CGF), // &Upper
2848 ST.emitRawPointer(CGF) // &Stride
2849 };
2850 llvm::Value *Call = CGF.EmitRuntimeCall(
2851 OMPBuilder.createDispatchNextFunction(IVSize, IVSigned), Args);
2852 return CGF.EmitScalarConversion(
2853 Call, CGF.getContext().getIntTypeForBitwidth(32, /*Signed=*/1),
2854 CGF.getContext().BoolTy, Loc);
2855}
2856
2858 const Expr *Message,
2859 SourceLocation Loc) {
2860 if (!Message)
2861 return llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
2862 return CGF.EmitScalarExpr(Message);
2863}
2864
2865llvm::Value *
2867 SourceLocation Loc) {
2868 // OpenMP 6.0, 10.4: "If no severity clause is specified then the effect is
2869 // as if sev-level is fatal."
2870 return llvm::ConstantInt::get(CGM.Int32Ty,
2871 Severity == OMPC_SEVERITY_warning ? 1 : 2);
2872}
2873
2875 CodeGenFunction &CGF, llvm::Value *NumThreads, SourceLocation Loc,
2877 SourceLocation SeverityLoc, const Expr *Message,
2878 SourceLocation MessageLoc) {
2879 if (!CGF.HaveInsertPoint())
2880 return;
2882 {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
2883 CGF.Builder.CreateIntCast(NumThreads, CGF.Int32Ty, /*isSigned*/ true)});
2884 // Build call __kmpc_push_num_threads(&loc, global_tid, num_threads)
2885 // or __kmpc_push_num_threads_strict(&loc, global_tid, num_threads, severity,
2886 // messsage) if strict modifier is used.
2887 RuntimeFunction FnID = OMPRTL___kmpc_push_num_threads;
2888 if (Modifier == OMPC_NUMTHREADS_strict) {
2889 FnID = OMPRTL___kmpc_push_num_threads_strict;
2890 Args.push_back(emitSeverityClause(Severity, SeverityLoc));
2891 Args.push_back(emitMessageClause(CGF, Message, MessageLoc));
2892 }
2893 CGF.EmitRuntimeCall(
2894 OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(), FnID), Args);
2895}
2896
2898 ProcBindKind ProcBind,
2899 SourceLocation Loc) {
2900 if (!CGF.HaveInsertPoint())
2901 return;
2902 assert(ProcBind != OMP_PROC_BIND_unknown && "Unsupported proc_bind value.");
2903 // Build call __kmpc_push_proc_bind(&loc, global_tid, proc_bind)
2904 llvm::Value *Args[] = {
2905 emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
2906 llvm::ConstantInt::get(CGM.IntTy, unsigned(ProcBind), /*isSigned=*/true)};
2907 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
2908 CGM.getModule(), OMPRTL___kmpc_push_proc_bind),
2909 Args);
2910}
2911
2913 SourceLocation Loc, llvm::AtomicOrdering AO) {
2914 if (CGF.CGM.getLangOpts().OpenMPIRBuilder) {
2915 OMPBuilder.createFlush(CGF.Builder);
2916 } else {
2917 if (!CGF.HaveInsertPoint())
2918 return;
2919 // Build call void __kmpc_flush(ident_t *loc)
2920 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
2921 CGM.getModule(), OMPRTL___kmpc_flush),
2922 emitUpdateLocation(CGF, Loc));
2923 }
2924}
2925
2926namespace {
2927/// Indexes of fields for type kmp_task_t.
2928enum KmpTaskTFields {
2929 /// List of shared variables.
2930 KmpTaskTShareds,
2931 /// Task routine.
2932 KmpTaskTRoutine,
2933 /// Partition id for the untied tasks.
2934 KmpTaskTPartId,
2935 /// Function with call of destructors for private variables.
2936 Data1,
2937 /// Task priority.
2938 Data2,
2939 /// (Taskloops only) Lower bound.
2940 KmpTaskTLowerBound,
2941 /// (Taskloops only) Upper bound.
2942 KmpTaskTUpperBound,
2943 /// (Taskloops only) Stride.
2944 KmpTaskTStride,
2945 /// (Taskloops only) Is last iteration flag.
2946 KmpTaskTLastIter,
2947 /// (Taskloops only) Reduction data.
2948 KmpTaskTReductions,
2949};
2950} // anonymous namespace
2951
2953 // If we are in simd mode or there are no entries, we don't need to do
2954 // anything.
2955 if (CGM.getLangOpts().OpenMPSimd || OMPBuilder.OffloadInfoManager.empty())
2956 return;
2957
2958 llvm::OpenMPIRBuilder::EmitMetadataErrorReportFunctionTy &&ErrorReportFn =
2959 [this](llvm::OpenMPIRBuilder::EmitMetadataErrorKind Kind,
2960 const llvm::TargetRegionEntryInfo &EntryInfo) -> void {
2961 SourceLocation Loc;
2962 if (Kind != llvm::OpenMPIRBuilder::EMIT_MD_GLOBAL_VAR_LINK_ERROR) {
2963 for (auto I = CGM.getContext().getSourceManager().fileinfo_begin(),
2964 E = CGM.getContext().getSourceManager().fileinfo_end();
2965 I != E; ++I) {
2966 if (I->getFirst().getUniqueID().getDevice() == EntryInfo.DeviceID &&
2967 I->getFirst().getUniqueID().getFile() == EntryInfo.FileID) {
2968 Loc = CGM.getContext().getSourceManager().translateFileLineCol(
2969 I->getFirst(), EntryInfo.Line, 1);
2970 break;
2971 }
2972 }
2973 }
2974 switch (Kind) {
2975 case llvm::OpenMPIRBuilder::EMIT_MD_TARGET_REGION_ERROR: {
2976 CGM.getDiags().Report(Loc,
2977 diag::err_target_region_offloading_entry_incorrect)
2978 << EntryInfo.ParentName;
2979 } break;
2980 case llvm::OpenMPIRBuilder::EMIT_MD_DECLARE_TARGET_ERROR: {
2981 CGM.getDiags().Report(
2982 Loc, diag::err_target_var_offloading_entry_incorrect_with_parent)
2983 << EntryInfo.ParentName;
2984 } break;
2985 case llvm::OpenMPIRBuilder::EMIT_MD_GLOBAL_VAR_LINK_ERROR: {
2986 CGM.getDiags().Report(diag::err_target_var_offloading_entry_incorrect);
2987 } break;
2988 case llvm::OpenMPIRBuilder::EMIT_MD_GLOBAL_VAR_INDIRECT_ERROR: {
2989 unsigned DiagID = CGM.getDiags().getCustomDiagID(
2990 DiagnosticsEngine::Error, "Offloading entry for indirect declare "
2991 "target variable is incorrect: the "
2992 "address is invalid.");
2993 CGM.getDiags().Report(DiagID);
2994 } break;
2995 }
2996 };
2997
2998 OMPBuilder.createOffloadEntriesAndInfoMetadata(ErrorReportFn);
2999}
3000
3002 if (!KmpRoutineEntryPtrTy) {
3003 // Build typedef kmp_int32 (* kmp_routine_entry_t)(kmp_int32, void *); type.
3004 ASTContext &C = CGM.getContext();
3005 QualType KmpRoutineEntryTyArgs[] = {KmpInt32Ty, C.VoidPtrTy};
3007 KmpRoutineEntryPtrQTy = C.getPointerType(
3008 C.getFunctionType(KmpInt32Ty, KmpRoutineEntryTyArgs, EPI));
3009 KmpRoutineEntryPtrTy = CGM.getTypes().ConvertType(KmpRoutineEntryPtrQTy);
3010 }
3011}
3012
3013namespace {
3014struct PrivateHelpersTy {
3015 PrivateHelpersTy(const Expr *OriginalRef, const VarDecl *Original,
3016 const VarDecl *PrivateCopy, const VarDecl *PrivateElemInit)
3017 : OriginalRef(OriginalRef), Original(Original), PrivateCopy(PrivateCopy),
3018 PrivateElemInit(PrivateElemInit) {}
3019 PrivateHelpersTy(const VarDecl *Original) : Original(Original) {}
3020 const Expr *OriginalRef = nullptr;
3021 const VarDecl *Original = nullptr;
3022 const VarDecl *PrivateCopy = nullptr;
3023 const VarDecl *PrivateElemInit = nullptr;
3024 bool isLocalPrivate() const {
3025 return !OriginalRef && !PrivateCopy && !PrivateElemInit;
3026 }
3027};
3028typedef std::pair<CharUnits /*Align*/, PrivateHelpersTy> PrivateDataTy;
3029} // anonymous namespace
3030
3031static bool isAllocatableDecl(const VarDecl *VD) {
3032 const VarDecl *CVD = VD->getCanonicalDecl();
3033 if (!CVD->hasAttr<OMPAllocateDeclAttr>())
3034 return false;
3035 const auto *AA = CVD->getAttr<OMPAllocateDeclAttr>();
3036 // Use the default allocation.
3037 return !(AA->getAllocatorType() == OMPAllocateDeclAttr::OMPDefaultMemAlloc &&
3038 !AA->getAllocator());
3039}
3040
3041static RecordDecl *
3043 if (!Privates.empty()) {
3044 ASTContext &C = CGM.getContext();
3045 // Build struct .kmp_privates_t. {
3046 // /* private vars */
3047 // };
3048 RecordDecl *RD = C.buildImplicitRecord(".kmp_privates.t");
3049 RD->startDefinition();
3050 for (const auto &Pair : Privates) {
3051 const VarDecl *VD = Pair.second.Original;
3053 // If the private variable is a local variable with lvalue ref type,
3054 // allocate the pointer instead of the pointee type.
3055 if (Pair.second.isLocalPrivate()) {
3056 if (VD->getType()->isLValueReferenceType())
3057 Type = C.getPointerType(Type);
3058 if (isAllocatableDecl(VD))
3059 Type = C.getPointerType(Type);
3060 }
3062 if (VD->hasAttrs()) {
3063 for (specific_attr_iterator<AlignedAttr> I(VD->getAttrs().begin()),
3064 E(VD->getAttrs().end());
3065 I != E; ++I)
3066 FD->addAttr(*I);
3067 }
3068 }
3069 RD->completeDefinition();
3070 return RD;
3071 }
3072 return nullptr;
3073}
3074
3075static RecordDecl *
3077 QualType KmpInt32Ty,
3078 QualType KmpRoutineEntryPointerQTy) {
3079 ASTContext &C = CGM.getContext();
3080 // Build struct kmp_task_t {
3081 // void * shareds;
3082 // kmp_routine_entry_t routine;
3083 // kmp_int32 part_id;
3084 // kmp_cmplrdata_t data1;
3085 // kmp_cmplrdata_t data2;
3086 // For taskloops additional fields:
3087 // kmp_uint64 lb;
3088 // kmp_uint64 ub;
3089 // kmp_int64 st;
3090 // kmp_int32 liter;
3091 // void * reductions;
3092 // };
3093 RecordDecl *UD = C.buildImplicitRecord("kmp_cmplrdata_t", TagTypeKind::Union);
3094 UD->startDefinition();
3095 addFieldToRecordDecl(C, UD, KmpInt32Ty);
3096 addFieldToRecordDecl(C, UD, KmpRoutineEntryPointerQTy);
3097 UD->completeDefinition();
3098 CanQualType KmpCmplrdataTy = C.getCanonicalTagType(UD);
3099 RecordDecl *RD = C.buildImplicitRecord("kmp_task_t");
3100 RD->startDefinition();
3101 addFieldToRecordDecl(C, RD, C.VoidPtrTy);
3102 addFieldToRecordDecl(C, RD, KmpRoutineEntryPointerQTy);
3103 addFieldToRecordDecl(C, RD, KmpInt32Ty);
3104 addFieldToRecordDecl(C, RD, KmpCmplrdataTy);
3105 addFieldToRecordDecl(C, RD, KmpCmplrdataTy);
3106 if (isOpenMPTaskLoopDirective(Kind)) {
3107 QualType KmpUInt64Ty =
3108 CGM.getContext().getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/0);
3109 QualType KmpInt64Ty =
3110 CGM.getContext().getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1);
3111 addFieldToRecordDecl(C, RD, KmpUInt64Ty);
3112 addFieldToRecordDecl(C, RD, KmpUInt64Ty);
3113 addFieldToRecordDecl(C, RD, KmpInt64Ty);
3114 addFieldToRecordDecl(C, RD, KmpInt32Ty);
3115 addFieldToRecordDecl(C, RD, C.VoidPtrTy);
3116 }
3117 RD->completeDefinition();
3118 return RD;
3119}
3120
3121static RecordDecl *
3124 ASTContext &C = CGM.getContext();
3125 // Build struct kmp_task_t_with_privates {
3126 // kmp_task_t task_data;
3127 // .kmp_privates_t. privates;
3128 // };
3129 RecordDecl *RD = C.buildImplicitRecord("kmp_task_t_with_privates");
3130 RD->startDefinition();
3131 addFieldToRecordDecl(C, RD, KmpTaskTQTy);
3132 if (const RecordDecl *PrivateRD = createPrivatesRecordDecl(CGM, Privates))
3133 addFieldToRecordDecl(C, RD, C.getCanonicalTagType(PrivateRD));
3134 RD->completeDefinition();
3135 return RD;
3136}
3137
3138/// Emit a proxy function which accepts kmp_task_t as the second
3139/// argument.
3140/// \code
3141/// kmp_int32 .omp_task_entry.(kmp_int32 gtid, kmp_task_t *tt) {
3142/// TaskFunction(gtid, tt->part_id, &tt->privates, task_privates_map, tt,
3143/// For taskloops:
3144/// tt->task_data.lb, tt->task_data.ub, tt->task_data.st, tt->task_data.liter,
3145/// tt->reductions, tt->shareds);
3146/// return 0;
3147/// }
3148/// \endcode
3149static llvm::Function *
3151 OpenMPDirectiveKind Kind, QualType KmpInt32Ty,
3152 QualType KmpTaskTWithPrivatesPtrQTy,
3153 QualType KmpTaskTWithPrivatesQTy, QualType KmpTaskTQTy,
3154 QualType SharedsPtrTy, llvm::Function *TaskFunction,
3155 llvm::Value *TaskPrivatesMap) {
3156 ASTContext &C = CGM.getContext();
3157 auto *GtidArg =
3158 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
3159 KmpInt32Ty, ImplicitParamKind::Other);
3160 auto *TaskTypeArg = ImplicitParamDecl::Create(
3161 C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
3162 KmpTaskTWithPrivatesPtrQTy.withRestrict(), ImplicitParamKind::Other);
3163 FunctionArgList Args{GtidArg, TaskTypeArg};
3164 const auto &TaskEntryFnInfo =
3165 CGM.getTypes().arrangeBuiltinFunctionDeclaration(KmpInt32Ty, Args);
3166 llvm::FunctionType *TaskEntryTy =
3167 CGM.getTypes().GetFunctionType(TaskEntryFnInfo);
3168 std::string Name = CGM.getOpenMPRuntime().getName({"omp_task_entry", ""});
3169 auto *TaskEntry = llvm::Function::Create(
3170 TaskEntryTy, llvm::GlobalValue::InternalLinkage, Name, &CGM.getModule());
3171 CGM.SetInternalFunctionAttributes(GlobalDecl(), TaskEntry, TaskEntryFnInfo);
3172 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
3173 TaskEntry->addFnAttr("sample-profile-suffix-elision-policy", "selected");
3174 TaskEntry->setDoesNotRecurse();
3175 CodeGenFunction CGF(CGM);
3176 CGF.StartFunction(GlobalDecl(), KmpInt32Ty, TaskEntry, TaskEntryFnInfo, Args,
3177 Loc, Loc);
3178
3179 // TaskFunction(gtid, tt->task_data.part_id, &tt->privates, task_privates_map,
3180 // tt,
3181 // For taskloops:
3182 // tt->task_data.lb, tt->task_data.ub, tt->task_data.st, tt->task_data.liter,
3183 // tt->task_data.shareds);
3184 llvm::Value *GtidParam = CGF.EmitLoadOfScalar(
3185 CGF.GetAddrOfLocalVar(GtidArg), /*Volatile=*/false, KmpInt32Ty, Loc);
3186 LValue TDBase = CGF.EmitLoadOfPointerLValue(
3187 CGF.GetAddrOfLocalVar(TaskTypeArg),
3188 KmpTaskTWithPrivatesPtrQTy->castAs<PointerType>());
3189 const auto *KmpTaskTWithPrivatesQTyRD =
3190 KmpTaskTWithPrivatesQTy->castAsRecordDecl();
3191 LValue Base =
3192 CGF.EmitLValueForField(TDBase, *KmpTaskTWithPrivatesQTyRD->field_begin());
3193 const auto *KmpTaskTQTyRD = KmpTaskTQTy->castAsRecordDecl();
3194 auto PartIdFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTPartId);
3195 LValue PartIdLVal = CGF.EmitLValueForField(Base, *PartIdFI);
3196 llvm::Value *PartidParam = PartIdLVal.getPointer(CGF);
3197
3198 auto SharedsFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTShareds);
3199 LValue SharedsLVal = CGF.EmitLValueForField(Base, *SharedsFI);
3200 llvm::Value *SharedsParam = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
3201 CGF.EmitLoadOfScalar(SharedsLVal, Loc),
3202 CGF.ConvertTypeForMem(SharedsPtrTy));
3203
3204 auto PrivatesFI = std::next(KmpTaskTWithPrivatesQTyRD->field_begin(), 1);
3205 llvm::Value *PrivatesParam;
3206 if (PrivatesFI != KmpTaskTWithPrivatesQTyRD->field_end()) {
3207 LValue PrivatesLVal = CGF.EmitLValueForField(TDBase, *PrivatesFI);
3208 PrivatesParam = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
3209 PrivatesLVal.getPointer(CGF), CGF.VoidPtrTy);
3210 } else {
3211 PrivatesParam = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
3212 }
3213
3214 llvm::Value *CommonArgs[] = {
3215 GtidParam, PartidParam, PrivatesParam, TaskPrivatesMap,
3216 CGF.Builder
3217 .CreatePointerBitCastOrAddrSpaceCast(TDBase.getAddress(),
3218 CGF.VoidPtrTy, CGF.Int8Ty)
3219 .emitRawPointer(CGF)};
3220 SmallVector<llvm::Value *, 16> CallArgs(std::begin(CommonArgs),
3221 std::end(CommonArgs));
3222 if (isOpenMPTaskLoopDirective(Kind)) {
3223 auto LBFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTLowerBound);
3224 LValue LBLVal = CGF.EmitLValueForField(Base, *LBFI);
3225 llvm::Value *LBParam = CGF.EmitLoadOfScalar(LBLVal, Loc);
3226 auto UBFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTUpperBound);
3227 LValue UBLVal = CGF.EmitLValueForField(Base, *UBFI);
3228 llvm::Value *UBParam = CGF.EmitLoadOfScalar(UBLVal, Loc);
3229 auto StFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTStride);
3230 LValue StLVal = CGF.EmitLValueForField(Base, *StFI);
3231 llvm::Value *StParam = CGF.EmitLoadOfScalar(StLVal, Loc);
3232 auto LIFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTLastIter);
3233 LValue LILVal = CGF.EmitLValueForField(Base, *LIFI);
3234 llvm::Value *LIParam = CGF.EmitLoadOfScalar(LILVal, Loc);
3235 auto RFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTReductions);
3236 LValue RLVal = CGF.EmitLValueForField(Base, *RFI);
3237 llvm::Value *RParam = CGF.EmitLoadOfScalar(RLVal, Loc);
3238 CallArgs.push_back(LBParam);
3239 CallArgs.push_back(UBParam);
3240 CallArgs.push_back(StParam);
3241 CallArgs.push_back(LIParam);
3242 CallArgs.push_back(RParam);
3243 }
3244 CallArgs.push_back(SharedsParam);
3245
3246 CGM.getOpenMPRuntime().emitOutlinedFunctionCall(CGF, Loc, TaskFunction,
3247 CallArgs);
3248 CGF.EmitStoreThroughLValue(RValue::get(CGF.Builder.getInt32(/*C=*/0)),
3249 CGF.MakeAddrLValue(CGF.ReturnValue, KmpInt32Ty));
3250 CGF.FinishFunction();
3251 return TaskEntry;
3252}
3253
3255 SourceLocation Loc,
3256 QualType KmpInt32Ty,
3257 QualType KmpTaskTWithPrivatesPtrQTy,
3258 QualType KmpTaskTWithPrivatesQTy) {
3259 ASTContext &C = CGM.getContext();
3260 auto *GtidArg =
3261 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
3262 KmpInt32Ty, ImplicitParamKind::Other);
3263 auto *TaskTypeArg = ImplicitParamDecl::Create(
3264 C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
3265 KmpTaskTWithPrivatesPtrQTy.withRestrict(), ImplicitParamKind::Other);
3266 FunctionArgList Args{GtidArg, TaskTypeArg};
3267 const auto &DestructorFnInfo =
3268 CGM.getTypes().arrangeBuiltinFunctionDeclaration(KmpInt32Ty, Args);
3269 llvm::FunctionType *DestructorFnTy =
3270 CGM.getTypes().GetFunctionType(DestructorFnInfo);
3271 std::string Name =
3272 CGM.getOpenMPRuntime().getName({"omp_task_destructor", ""});
3273 auto *DestructorFn =
3274 llvm::Function::Create(DestructorFnTy, llvm::GlobalValue::InternalLinkage,
3275 Name, &CGM.getModule());
3276 CGM.SetInternalFunctionAttributes(GlobalDecl(), DestructorFn,
3277 DestructorFnInfo);
3278 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
3279 DestructorFn->addFnAttr("sample-profile-suffix-elision-policy", "selected");
3280 DestructorFn->setDoesNotRecurse();
3281 CodeGenFunction CGF(CGM);
3282 CGF.StartFunction(GlobalDecl(), KmpInt32Ty, DestructorFn, DestructorFnInfo,
3283 Args, Loc, Loc);
3284
3285 LValue Base = CGF.EmitLoadOfPointerLValue(
3286 CGF.GetAddrOfLocalVar(TaskTypeArg),
3287 KmpTaskTWithPrivatesPtrQTy->castAs<PointerType>());
3288 const auto *KmpTaskTWithPrivatesQTyRD =
3289 KmpTaskTWithPrivatesQTy->castAsRecordDecl();
3290 auto FI = std::next(KmpTaskTWithPrivatesQTyRD->field_begin());
3291 Base = CGF.EmitLValueForField(Base, *FI);
3292 for (const auto *Field : FI->getType()->castAsRecordDecl()->fields()) {
3293 if (QualType::DestructionKind DtorKind =
3294 Field->getType().isDestructedType()) {
3295 LValue FieldLValue = CGF.EmitLValueForField(Base, Field);
3296 CGF.pushDestroy(DtorKind, FieldLValue.getAddress(), Field->getType());
3297 }
3298 }
3299 CGF.FinishFunction();
3300 return DestructorFn;
3301}
3302
3303/// Emit a privates mapping function for correct handling of private and
3304/// firstprivate variables.
3305/// \code
3306/// void .omp_task_privates_map.(const .privates. *noalias privs, <ty1>
3307/// **noalias priv1,..., <tyn> **noalias privn) {
3308/// *priv1 = &.privates.priv1;
3309/// ...;
3310/// *privn = &.privates.privn;
3311/// }
3312/// \endcode
3313static llvm::Value *
3315 const OMPTaskDataTy &Data, QualType PrivatesQTy,
3317 ASTContext &C = CGM.getContext();
3318 FunctionArgList Args;
3319 auto *TaskPrivatesArg = ImplicitParamDecl::Create(
3320 C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
3321 C.getPointerType(PrivatesQTy).withConst().withRestrict(),
3323 Args.push_back(TaskPrivatesArg);
3324 llvm::DenseMap<CanonicalDeclPtr<const VarDecl>, unsigned> PrivateVarsPos;
3325 unsigned Counter = 1;
3326 for (const Expr *E : Data.PrivateVars) {
3327 Args.push_back(ImplicitParamDecl::Create(
3328 C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
3329 C.getPointerType(C.getPointerType(E->getType()))
3330 .withConst()
3331 .withRestrict(),
3333 const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
3334 PrivateVarsPos[VD] = Counter;
3335 ++Counter;
3336 }
3337 for (const Expr *E : Data.FirstprivateVars) {
3338 Args.push_back(ImplicitParamDecl::Create(
3339 C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
3340 C.getPointerType(C.getPointerType(E->getType()))
3341 .withConst()
3342 .withRestrict(),
3344 const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
3345 PrivateVarsPos[VD] = Counter;
3346 ++Counter;
3347 }
3348 for (const Expr *E : Data.LastprivateVars) {
3349 Args.push_back(ImplicitParamDecl::Create(
3350 C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
3351 C.getPointerType(C.getPointerType(E->getType()))
3352 .withConst()
3353 .withRestrict(),
3355 const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
3356 PrivateVarsPos[VD] = Counter;
3357 ++Counter;
3358 }
3359 for (const VarDecl *VD : Data.PrivateLocals) {
3361 if (VD->getType()->isLValueReferenceType())
3362 Ty = C.getPointerType(Ty);
3363 if (isAllocatableDecl(VD))
3364 Ty = C.getPointerType(Ty);
3365 Args.push_back(ImplicitParamDecl::Create(
3366 C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
3367 C.getPointerType(C.getPointerType(Ty)).withConst().withRestrict(),
3369 PrivateVarsPos[VD] = Counter;
3370 ++Counter;
3371 }
3372 const auto &TaskPrivatesMapFnInfo =
3373 CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
3374 llvm::FunctionType *TaskPrivatesMapTy =
3375 CGM.getTypes().GetFunctionType(TaskPrivatesMapFnInfo);
3376 std::string Name =
3377 CGM.getOpenMPRuntime().getName({"omp_task_privates_map", ""});
3378 auto *TaskPrivatesMap = llvm::Function::Create(
3379 TaskPrivatesMapTy, llvm::GlobalValue::InternalLinkage, Name,
3380 &CGM.getModule());
3381 CGM.SetInternalFunctionAttributes(GlobalDecl(), TaskPrivatesMap,
3382 TaskPrivatesMapFnInfo);
3383 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
3384 TaskPrivatesMap->addFnAttr("sample-profile-suffix-elision-policy",
3385 "selected");
3386 if (CGM.getCodeGenOpts().OptimizationLevel != 0) {
3387 TaskPrivatesMap->removeFnAttr(llvm::Attribute::NoInline);
3388 TaskPrivatesMap->removeFnAttr(llvm::Attribute::OptimizeNone);
3389 TaskPrivatesMap->addFnAttr(llvm::Attribute::AlwaysInline);
3390 }
3391 CodeGenFunction CGF(CGM);
3392 CGF.StartFunction(GlobalDecl(), C.VoidTy, TaskPrivatesMap,
3393 TaskPrivatesMapFnInfo, Args, Loc, Loc);
3394
3395 // *privi = &.privates.privi;
3396 LValue Base = CGF.EmitLoadOfPointerLValue(
3397 CGF.GetAddrOfLocalVar(TaskPrivatesArg),
3398 TaskPrivatesArg->getType()->castAs<PointerType>());
3399 const auto *PrivatesQTyRD = PrivatesQTy->castAsRecordDecl();
3400 Counter = 0;
3401 for (const FieldDecl *Field : PrivatesQTyRD->fields()) {
3402 LValue FieldLVal = CGF.EmitLValueForField(Base, Field);
3403 const VarDecl *VD = Args[PrivateVarsPos[Privates[Counter].second.Original]];
3404 LValue RefLVal =
3405 CGF.MakeAddrLValue(CGF.GetAddrOfLocalVar(VD), VD->getType());
3406 LValue RefLoadLVal = CGF.EmitLoadOfPointerLValue(
3407 RefLVal.getAddress(), RefLVal.getType()->castAs<PointerType>());
3408 CGF.EmitStoreOfScalar(FieldLVal.getPointer(CGF), RefLoadLVal);
3409 ++Counter;
3410 }
3411 CGF.FinishFunction();
3412 return TaskPrivatesMap;
3413}
3414
3415/// Emit initialization for private variables in task-based directives.
3417 const OMPExecutableDirective &D,
3418 Address KmpTaskSharedsPtr, LValue TDBase,
3419 const RecordDecl *KmpTaskTWithPrivatesQTyRD,
3420 QualType SharedsTy, QualType SharedsPtrTy,
3421 const OMPTaskDataTy &Data,
3422 ArrayRef<PrivateDataTy> Privates, bool ForDup) {
3423 ASTContext &C = CGF.getContext();
3424 auto FI = std::next(KmpTaskTWithPrivatesQTyRD->field_begin());
3425 LValue PrivatesBase = CGF.EmitLValueForField(TDBase, *FI);
3426 OpenMPDirectiveKind Kind = isOpenMPTaskLoopDirective(D.getDirectiveKind())
3427 ? OMPD_taskloop
3428 : OMPD_task;
3429 const CapturedStmt &CS = *D.getCapturedStmt(Kind);
3430 CodeGenFunction::CGCapturedStmtInfo CapturesInfo(CS);
3431 LValue SrcBase;
3432 bool IsTargetTask =
3433 isOpenMPTargetDataManagementDirective(D.getDirectiveKind()) ||
3434 isOpenMPTargetExecutionDirective(D.getDirectiveKind());
3435 // For target-based directives skip 4 firstprivate arrays BasePointersArray,
3436 // PointersArray, SizesArray, and MappersArray. The original variables for
3437 // these arrays are not captured and we get their addresses explicitly.
3438 if ((!IsTargetTask && !Data.FirstprivateVars.empty() && ForDup) ||
3439 (IsTargetTask && KmpTaskSharedsPtr.isValid())) {
3440 SrcBase = CGF.MakeAddrLValue(
3442 KmpTaskSharedsPtr, CGF.ConvertTypeForMem(SharedsPtrTy),
3443 CGF.ConvertTypeForMem(SharedsTy)),
3444 SharedsTy);
3445 }
3446 FI = FI->getType()->castAsRecordDecl()->field_begin();
3447 for (const PrivateDataTy &Pair : Privates) {
3448 // Do not initialize private locals.
3449 if (Pair.second.isLocalPrivate()) {
3450 ++FI;
3451 continue;
3452 }
3453 const VarDecl *VD = Pair.second.PrivateCopy;
3454 const Expr *Init = VD->getAnyInitializer();
3455 if (Init && (!ForDup || (isa<CXXConstructExpr>(Init) &&
3456 !CGF.isTrivialInitializer(Init)))) {
3457 LValue PrivateLValue = CGF.EmitLValueForField(PrivatesBase, *FI);
3458 if (const VarDecl *Elem = Pair.second.PrivateElemInit) {
3459 const VarDecl *OriginalVD = Pair.second.Original;
3460 // Check if the variable is the target-based BasePointersArray,
3461 // PointersArray, SizesArray, or MappersArray.
3462 LValue SharedRefLValue;
3463 QualType Type = PrivateLValue.getType();
3464 const FieldDecl *SharedField = CapturesInfo.lookup(OriginalVD);
3465 if (IsTargetTask && !SharedField) {
3466 assert(isa<ImplicitParamDecl>(OriginalVD) &&
3467 isa<CapturedDecl>(OriginalVD->getDeclContext()) &&
3468 cast<CapturedDecl>(OriginalVD->getDeclContext())
3469 ->getNumParams() == 0 &&
3471 cast<CapturedDecl>(OriginalVD->getDeclContext())
3472 ->getDeclContext()) &&
3473 "Expected artificial target data variable.");
3474 SharedRefLValue =
3475 CGF.MakeAddrLValue(CGF.GetAddrOfLocalVar(OriginalVD), Type);
3476 } else if (ForDup) {
3477 SharedRefLValue = CGF.EmitLValueForField(SrcBase, SharedField);
3478 SharedRefLValue = CGF.MakeAddrLValue(
3479 SharedRefLValue.getAddress().withAlignment(
3480 C.getDeclAlign(OriginalVD)),
3481 SharedRefLValue.getType(), LValueBaseInfo(AlignmentSource::Decl),
3482 SharedRefLValue.getTBAAInfo());
3483 } else if (CGF.LambdaCaptureFields.count(
3484 Pair.second.Original->getCanonicalDecl()) > 0 ||
3485 isa_and_nonnull<BlockDecl>(CGF.CurCodeDecl)) {
3486 SharedRefLValue = CGF.EmitLValue(Pair.second.OriginalRef);
3487 } else {
3488 // Processing for implicitly captured variables.
3489 InlinedOpenMPRegionRAII Region(
3490 CGF, [](CodeGenFunction &, PrePostActionTy &) {}, OMPD_unknown,
3491 /*HasCancel=*/false, /*NoInheritance=*/true);
3492 SharedRefLValue = CGF.EmitLValue(Pair.second.OriginalRef);
3493 }
3494 if (Type->isArrayType()) {
3495 // Initialize firstprivate array.
3497 // Perform simple memcpy.
3498 CGF.EmitAggregateAssign(PrivateLValue, SharedRefLValue, Type);
3499 } else {
3500 // Initialize firstprivate array using element-by-element
3501 // initialization.
3503 PrivateLValue.getAddress(), SharedRefLValue.getAddress(), Type,
3504 [&CGF, Elem, Init, &CapturesInfo](Address DestElement,
3505 Address SrcElement) {
3506 // Clean up any temporaries needed by the initialization.
3507 CodeGenFunction::OMPPrivateScope InitScope(CGF);
3508 InitScope.addPrivate(Elem, SrcElement);
3509 (void)InitScope.Privatize();
3510 // Emit initialization for single element.
3511 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(
3512 CGF, &CapturesInfo);
3513 CGF.EmitAnyExprToMem(Init, DestElement,
3514 Init->getType().getQualifiers(),
3515 /*IsInitializer=*/false);
3516 });
3517 }
3518 } else {
3519 CodeGenFunction::OMPPrivateScope InitScope(CGF);
3520 InitScope.addPrivate(Elem, SharedRefLValue.getAddress());
3521 (void)InitScope.Privatize();
3522 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CapturesInfo);
3523 CGF.EmitExprAsInit(Init, VD, PrivateLValue,
3524 /*capturedByInit=*/false);
3525 }
3526 } else {
3527 CGF.EmitExprAsInit(Init, VD, PrivateLValue, /*capturedByInit=*/false);
3528 }
3529 }
3530 ++FI;
3531 }
3532}
3533
3534/// Check if duplication function is required for taskloops.
3537 bool InitRequired = false;
3538 for (const PrivateDataTy &Pair : Privates) {
3539 if (Pair.second.isLocalPrivate())
3540 continue;
3541 const VarDecl *VD = Pair.second.PrivateCopy;
3542 const Expr *Init = VD->getAnyInitializer();
3543 InitRequired = InitRequired || (isa_and_nonnull<CXXConstructExpr>(Init) &&
3545 if (InitRequired)
3546 break;
3547 }
3548 return InitRequired;
3549}
3550
3551
3552/// Emit task_dup function (for initialization of
3553/// private/firstprivate/lastprivate vars and last_iter flag)
3554/// \code
3555/// void __task_dup_entry(kmp_task_t *task_dst, const kmp_task_t *task_src, int
3556/// lastpriv) {
3557/// // setup lastprivate flag
3558/// task_dst->last = lastpriv;
3559/// // could be constructor calls here...
3560/// }
3561/// \endcode
3562static llvm::Value *
3564 const OMPExecutableDirective &D,
3565 QualType KmpTaskTWithPrivatesPtrQTy,
3566 const RecordDecl *KmpTaskTWithPrivatesQTyRD,
3567 const RecordDecl *KmpTaskTQTyRD, QualType SharedsTy,
3568 QualType SharedsPtrTy, const OMPTaskDataTy &Data,
3569 ArrayRef<PrivateDataTy> Privates, bool WithLastIter) {
3570 ASTContext &C = CGM.getContext();
3571 auto *DstArg = ImplicitParamDecl::Create(
3572 C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, KmpTaskTWithPrivatesPtrQTy,
3574 auto *SrcArg = ImplicitParamDecl::Create(
3575 C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, KmpTaskTWithPrivatesPtrQTy,
3577 auto *LastprivArg =
3578 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, C.IntTy,
3580 FunctionArgList Args{DstArg, SrcArg, LastprivArg};
3581 const auto &TaskDupFnInfo =
3582 CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
3583 llvm::FunctionType *TaskDupTy = CGM.getTypes().GetFunctionType(TaskDupFnInfo);
3584 std::string Name = CGM.getOpenMPRuntime().getName({"omp_task_dup", ""});
3585 auto *TaskDup = llvm::Function::Create(
3586 TaskDupTy, llvm::GlobalValue::InternalLinkage, Name, &CGM.getModule());
3587 CGM.SetInternalFunctionAttributes(GlobalDecl(), TaskDup, TaskDupFnInfo);
3588 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
3589 TaskDup->addFnAttr("sample-profile-suffix-elision-policy", "selected");
3590 TaskDup->setDoesNotRecurse();
3591 CodeGenFunction CGF(CGM);
3592 CGF.StartFunction(GlobalDecl(), C.VoidTy, TaskDup, TaskDupFnInfo, Args, Loc,
3593 Loc);
3594
3595 LValue TDBase = CGF.EmitLoadOfPointerLValue(
3596 CGF.GetAddrOfLocalVar(DstArg),
3597 KmpTaskTWithPrivatesPtrQTy->castAs<PointerType>());
3598 // task_dst->liter = lastpriv;
3599 if (WithLastIter) {
3600 auto LIFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTLastIter);
3601 LValue Base = CGF.EmitLValueForField(
3602 TDBase, *KmpTaskTWithPrivatesQTyRD->field_begin());
3603 LValue LILVal = CGF.EmitLValueForField(Base, *LIFI);
3604 llvm::Value *Lastpriv = CGF.EmitLoadOfScalar(
3605 CGF.GetAddrOfLocalVar(LastprivArg), /*Volatile=*/false, C.IntTy, Loc);
3606 CGF.EmitStoreOfScalar(Lastpriv, LILVal);
3607 }
3608
3609 // Emit initial values for private copies (if any).
3610 assert(!Privates.empty());
3611 Address KmpTaskSharedsPtr = Address::invalid();
3612 if (!Data.FirstprivateVars.empty()) {
3613 LValue TDBase = CGF.EmitLoadOfPointerLValue(
3614 CGF.GetAddrOfLocalVar(SrcArg),
3615 KmpTaskTWithPrivatesPtrQTy->castAs<PointerType>());
3616 LValue Base = CGF.EmitLValueForField(
3617 TDBase, *KmpTaskTWithPrivatesQTyRD->field_begin());
3618 KmpTaskSharedsPtr = Address(
3620 Base, *std::next(KmpTaskTQTyRD->field_begin(),
3621 KmpTaskTShareds)),
3622 Loc),
3623 CGF.Int8Ty, CGM.getNaturalTypeAlignment(SharedsTy));
3624 }
3625 emitPrivatesInit(CGF, D, KmpTaskSharedsPtr, TDBase, KmpTaskTWithPrivatesQTyRD,
3626 SharedsTy, SharedsPtrTy, Data, Privates, /*ForDup=*/true);
3627 CGF.FinishFunction();
3628 return TaskDup;
3629}
3630
3631/// Checks if destructor function is required to be generated.
3632/// \return true if cleanups are required, false otherwise.
3633static bool
3634checkDestructorsRequired(const RecordDecl *KmpTaskTWithPrivatesQTyRD,
3636 for (const PrivateDataTy &P : Privates) {
3637 if (P.second.isLocalPrivate())
3638 continue;
3639 QualType Ty = P.second.Original->getType().getNonReferenceType();
3640 if (Ty.isDestructedType())
3641 return true;
3642 }
3643 return false;
3644}
3645
3646namespace {
3647/// Loop generator for OpenMP iterator expression.
3648class OMPIteratorGeneratorScope final
3650 CodeGenFunction &CGF;
3651 const OMPIteratorExpr *E = nullptr;
3652 SmallVector<CodeGenFunction::JumpDest, 4> ContDests;
3653 SmallVector<CodeGenFunction::JumpDest, 4> ExitDests;
3654 OMPIteratorGeneratorScope() = delete;
3655 OMPIteratorGeneratorScope(OMPIteratorGeneratorScope &) = delete;
3656
3657public:
3658 OMPIteratorGeneratorScope(CodeGenFunction &CGF, const OMPIteratorExpr *E)
3659 : CodeGenFunction::OMPPrivateScope(CGF), CGF(CGF), E(E) {
3660 if (!E)
3661 return;
3662 SmallVector<llvm::Value *, 4> Uppers;
3663 for (unsigned I = 0, End = E->numOfIterators(); I < End; ++I) {
3664 Uppers.push_back(CGF.EmitScalarExpr(E->getHelper(I).Upper));
3665 const auto *VD = cast<VarDecl>(E->getIteratorDecl(I));
3666 addPrivate(VD, CGF.CreateMemTemp(VD->getType(), VD->getName()));
3667 const OMPIteratorHelperData &HelperData = E->getHelper(I);
3668 addPrivate(
3669 HelperData.CounterVD,
3670 CGF.CreateMemTemp(HelperData.CounterVD->getType(), "counter.addr"));
3671 }
3672 Privatize();
3673
3674 for (unsigned I = 0, End = E->numOfIterators(); I < End; ++I) {
3675 const OMPIteratorHelperData &HelperData = E->getHelper(I);
3676 LValue CLVal =
3677 CGF.MakeAddrLValue(CGF.GetAddrOfLocalVar(HelperData.CounterVD),
3678 HelperData.CounterVD->getType());
3679 // Counter = 0;
3680 CGF.EmitStoreOfScalar(
3681 llvm::ConstantInt::get(CLVal.getAddress().getElementType(), 0),
3682 CLVal);
3683 CodeGenFunction::JumpDest &ContDest =
3684 ContDests.emplace_back(CGF.getJumpDestInCurrentScope("iter.cont"));
3685 CodeGenFunction::JumpDest &ExitDest =
3686 ExitDests.emplace_back(CGF.getJumpDestInCurrentScope("iter.exit"));
3687 // N = <number-of_iterations>;
3688 llvm::Value *N = Uppers[I];
3689 // cont:
3690 // if (Counter < N) goto body; else goto exit;
3691 CGF.EmitBlock(ContDest.getBlock());
3692 auto *CVal =
3693 CGF.EmitLoadOfScalar(CLVal, HelperData.CounterVD->getLocation());
3694 llvm::Value *Cmp =
3695 HelperData.CounterVD->getType()->isSignedIntegerOrEnumerationType()
3696 ? CGF.Builder.CreateICmpSLT(CVal, N)
3697 : CGF.Builder.CreateICmpULT(CVal, N);
3698 llvm::BasicBlock *BodyBB = CGF.createBasicBlock("iter.body");
3699 CGF.Builder.CreateCondBr(Cmp, BodyBB, ExitDest.getBlock());
3700 // body:
3701 CGF.EmitBlock(BodyBB);
3702 // Iteri = Begini + Counter * Stepi;
3703 CGF.EmitIgnoredExpr(HelperData.Update);
3704 }
3705 }
3706 ~OMPIteratorGeneratorScope() {
3707 if (!E)
3708 return;
3709 for (unsigned I = E->numOfIterators(); I > 0; --I) {
3710 // Counter = Counter + 1;
3711 const OMPIteratorHelperData &HelperData = E->getHelper(I - 1);
3712 CGF.EmitIgnoredExpr(HelperData.CounterUpdate);
3713 // goto cont;
3714 CGF.EmitBranchThroughCleanup(ContDests[I - 1]);
3715 // exit:
3716 CGF.EmitBlock(ExitDests[I - 1].getBlock(), /*IsFinished=*/I == 1);
3717 }
3718 }
3719};
3720} // namespace
3721
3722static std::pair<llvm::Value *, llvm::Value *>
3724 const auto *OASE = dyn_cast<OMPArrayShapingExpr>(E);
3725 llvm::Value *Addr;
3726 if (OASE) {
3727 const Expr *Base = OASE->getBase();
3728 Addr = CGF.EmitScalarExpr(Base);
3729 } else {
3730 Addr = CGF.EmitLValue(E).getPointer(CGF);
3731 }
3732 llvm::Value *SizeVal;
3733 QualType Ty = E->getType();
3734 if (OASE) {
3735 SizeVal = CGF.getTypeSize(OASE->getBase()->getType()->getPointeeType());
3736 for (const Expr *SE : OASE->getDimensions()) {
3737 llvm::Value *Sz = CGF.EmitScalarExpr(SE);
3738 Sz = CGF.EmitScalarConversion(
3739 Sz, SE->getType(), CGF.getContext().getSizeType(), SE->getExprLoc());
3740 SizeVal = CGF.Builder.CreateNUWMul(SizeVal, Sz);
3741 }
3742 } else if (const auto *ASE =
3743 dyn_cast<ArraySectionExpr>(E->IgnoreParenImpCasts())) {
3744 LValue UpAddrLVal = CGF.EmitArraySectionExpr(ASE, /*IsLowerBound=*/false);
3745 Address UpAddrAddress = UpAddrLVal.getAddress();
3746 llvm::Value *UpAddr = CGF.Builder.CreateConstGEP1_32(
3747 UpAddrAddress.getElementType(), UpAddrAddress.emitRawPointer(CGF),
3748 /*Idx0=*/1);
3749 SizeVal = CGF.Builder.CreatePtrDiff(UpAddr, Addr, "", /*IsNUW=*/true);
3750 } else {
3751 SizeVal = CGF.getTypeSize(Ty);
3752 }
3753 return std::make_pair(Addr, SizeVal);
3754}
3755
3756/// Builds kmp_depend_info, if it is not built yet, and builds flags type.
3757static void getKmpAffinityType(ASTContext &C, QualType &KmpTaskAffinityInfoTy) {
3758 QualType FlagsTy = C.getIntTypeForBitwidth(32, /*Signed=*/false);
3759 if (KmpTaskAffinityInfoTy.isNull()) {
3760 RecordDecl *KmpAffinityInfoRD =
3761 C.buildImplicitRecord("kmp_task_affinity_info_t");
3762 KmpAffinityInfoRD->startDefinition();
3763 addFieldToRecordDecl(C, KmpAffinityInfoRD, C.getIntPtrType());
3764 addFieldToRecordDecl(C, KmpAffinityInfoRD, C.getSizeType());
3765 addFieldToRecordDecl(C, KmpAffinityInfoRD, FlagsTy);
3766 KmpAffinityInfoRD->completeDefinition();
3767 KmpTaskAffinityInfoTy = C.getCanonicalTagType(KmpAffinityInfoRD);
3768 }
3769}
3770
3773 const OMPExecutableDirective &D,
3774 llvm::Function *TaskFunction, QualType SharedsTy,
3775 Address Shareds, const OMPTaskDataTy &Data) {
3776 ASTContext &C = CGM.getContext();
3778 // Aggregate privates and sort them by the alignment.
3779 const auto *I = Data.PrivateCopies.begin();
3780 for (const Expr *E : Data.PrivateVars) {
3781 const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
3782 Privates.emplace_back(
3783 C.getDeclAlign(VD),
3784 PrivateHelpersTy(E, VD, cast<VarDecl>(cast<DeclRefExpr>(*I)->getDecl()),
3785 /*PrivateElemInit=*/nullptr));
3786 ++I;
3787 }
3788 I = Data.FirstprivateCopies.begin();
3789 const auto *IElemInitRef = Data.FirstprivateInits.begin();
3790 for (const Expr *E : Data.FirstprivateVars) {
3791 const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
3792 Privates.emplace_back(
3793 C.getDeclAlign(VD),
3794 PrivateHelpersTy(
3795 E, VD, cast<VarDecl>(cast<DeclRefExpr>(*I)->getDecl()),
3796 cast<VarDecl>(cast<DeclRefExpr>(*IElemInitRef)->getDecl())));
3797 ++I;
3798 ++IElemInitRef;
3799 }
3800 I = Data.LastprivateCopies.begin();
3801 for (const Expr *E : Data.LastprivateVars) {
3802 const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
3803 Privates.emplace_back(
3804 C.getDeclAlign(VD),
3805 PrivateHelpersTy(E, VD, cast<VarDecl>(cast<DeclRefExpr>(*I)->getDecl()),
3806 /*PrivateElemInit=*/nullptr));
3807 ++I;
3808 }
3809 for (const VarDecl *VD : Data.PrivateLocals) {
3810 if (isAllocatableDecl(VD))
3811 Privates.emplace_back(CGM.getPointerAlign(), PrivateHelpersTy(VD));
3812 else
3813 Privates.emplace_back(C.getDeclAlign(VD), PrivateHelpersTy(VD));
3814 }
3815 llvm::stable_sort(Privates,
3816 [](const PrivateDataTy &L, const PrivateDataTy &R) {
3817 return L.first > R.first;
3818 });
3819 QualType KmpInt32Ty = C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1);
3820 // Build type kmp_routine_entry_t (if not built yet).
3821 emitKmpRoutineEntryT(KmpInt32Ty);
3822 // Build type kmp_task_t (if not built yet).
3823 if (isOpenMPTaskLoopDirective(D.getDirectiveKind())) {
3824 if (SavedKmpTaskloopTQTy.isNull()) {
3825 SavedKmpTaskloopTQTy = C.getCanonicalTagType(createKmpTaskTRecordDecl(
3826 CGM, D.getDirectiveKind(), KmpInt32Ty, KmpRoutineEntryPtrQTy));
3827 }
3829 } else {
3830 assert((D.getDirectiveKind() == OMPD_task ||
3831 isOpenMPTargetExecutionDirective(D.getDirectiveKind()) ||
3832 isOpenMPTargetDataManagementDirective(D.getDirectiveKind())) &&
3833 "Expected taskloop, task or target directive");
3834 if (SavedKmpTaskTQTy.isNull()) {
3835 SavedKmpTaskTQTy = C.getCanonicalTagType(createKmpTaskTRecordDecl(
3836 CGM, D.getDirectiveKind(), KmpInt32Ty, KmpRoutineEntryPtrQTy));
3837 }
3839 }
3840 const auto *KmpTaskTQTyRD = KmpTaskTQTy->castAsRecordDecl();
3841 // Build particular struct kmp_task_t for the given task.
3842 const RecordDecl *KmpTaskTWithPrivatesQTyRD =
3844 CanQualType KmpTaskTWithPrivatesQTy =
3845 C.getCanonicalTagType(KmpTaskTWithPrivatesQTyRD);
3846 QualType KmpTaskTWithPrivatesPtrQTy =
3847 C.getPointerType(KmpTaskTWithPrivatesQTy);
3848 llvm::Type *KmpTaskTWithPrivatesPtrTy = CGF.Builder.getPtrTy(0);
3849 llvm::Value *KmpTaskTWithPrivatesTySize =
3850 CGF.getTypeSize(KmpTaskTWithPrivatesQTy);
3851 QualType SharedsPtrTy = C.getPointerType(SharedsTy);
3852
3853 // Emit initial values for private copies (if any).
3854 llvm::Value *TaskPrivatesMap = nullptr;
3855 llvm::Type *TaskPrivatesMapTy =
3856 std::next(TaskFunction->arg_begin(), 3)->getType();
3857 if (!Privates.empty()) {
3858 auto FI = std::next(KmpTaskTWithPrivatesQTyRD->field_begin());
3859 TaskPrivatesMap =
3860 emitTaskPrivateMappingFunction(CGM, Loc, Data, FI->getType(), Privates);
3861 TaskPrivatesMap = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
3862 TaskPrivatesMap, TaskPrivatesMapTy);
3863 } else {
3864 TaskPrivatesMap = llvm::ConstantPointerNull::get(
3865 cast<llvm::PointerType>(TaskPrivatesMapTy));
3866 }
3867 // Build a proxy function kmp_int32 .omp_task_entry.(kmp_int32 gtid,
3868 // kmp_task_t *tt);
3869 llvm::Function *TaskEntry = emitProxyTaskFunction(
3870 CGM, Loc, D.getDirectiveKind(), KmpInt32Ty, KmpTaskTWithPrivatesPtrQTy,
3871 KmpTaskTWithPrivatesQTy, KmpTaskTQTy, SharedsPtrTy, TaskFunction,
3872 TaskPrivatesMap);
3873
3874 // Build call kmp_task_t * __kmpc_omp_task_alloc(ident_t *, kmp_int32 gtid,
3875 // kmp_int32 flags, size_t sizeof_kmp_task_t, size_t sizeof_shareds,
3876 // kmp_routine_entry_t *task_entry);
3877 // Task flags. Format is taken from
3878 // https://github.com/llvm/llvm-project/blob/main/openmp/runtime/src/kmp.h,
3879 // description of kmp_tasking_flags struct.
3880 enum {
3881 TiedFlag = 0x1,
3882 FinalFlag = 0x2,
3883 DestructorsFlag = 0x8,
3884 PriorityFlag = 0x20,
3885 DetachableFlag = 0x40,
3886 FreeAgentFlag = 0x80,
3887 TransparentFlag = 0x100,
3888 };
3889 unsigned Flags = Data.Tied ? TiedFlag : 0;
3890 bool NeedsCleanup = false;
3891 if (!Privates.empty()) {
3892 NeedsCleanup =
3893 checkDestructorsRequired(KmpTaskTWithPrivatesQTyRD, Privates);
3894 if (NeedsCleanup)
3895 Flags = Flags | DestructorsFlag;
3896 }
3897 if (const auto *Clause = D.getSingleClause<OMPThreadsetClause>()) {
3898 OpenMPThreadsetKind Kind = Clause->getThreadsetKind();
3899 if (Kind == OMPC_THREADSET_omp_pool)
3900 Flags = Flags | FreeAgentFlag;
3901 }
3902 if (D.getSingleClause<OMPTransparentClause>())
3903 Flags |= TransparentFlag;
3904
3905 if (Data.Priority.getInt())
3906 Flags = Flags | PriorityFlag;
3907 if (D.hasClausesOfKind<OMPDetachClause>())
3908 Flags = Flags | DetachableFlag;
3909 llvm::Value *TaskFlags =
3910 Data.Final.getPointer()
3911 ? CGF.Builder.CreateSelect(Data.Final.getPointer(),
3912 CGF.Builder.getInt32(FinalFlag),
3913 CGF.Builder.getInt32(/*C=*/0))
3914 : CGF.Builder.getInt32(Data.Final.getInt() ? FinalFlag : 0);
3915 TaskFlags = CGF.Builder.CreateOr(TaskFlags, CGF.Builder.getInt32(Flags));
3916 llvm::Value *SharedsSize = CGM.getSize(C.getTypeSizeInChars(SharedsTy));
3918 getThreadID(CGF, Loc), TaskFlags, KmpTaskTWithPrivatesTySize,
3920 TaskEntry, KmpRoutineEntryPtrTy)};
3921 llvm::Value *NewTask;
3922 if (D.hasClausesOfKind<OMPNowaitClause>()) {
3923 // Check if we have any device clause associated with the directive.
3924 const Expr *Device = nullptr;
3925 if (auto *C = D.getSingleClause<OMPDeviceClause>())
3926 Device = C->getDevice();
3927 // Emit device ID if any otherwise use default value.
3928 llvm::Value *DeviceID;
3929 if (Device)
3930 DeviceID = CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(Device),
3931 CGF.Int64Ty, /*isSigned=*/true);
3932 else
3933 DeviceID = CGF.Builder.getInt64(OMP_DEVICEID_UNDEF);
3934 AllocArgs.push_back(DeviceID);
3935 NewTask = CGF.EmitRuntimeCall(
3936 OMPBuilder.getOrCreateRuntimeFunction(
3937 CGM.getModule(), OMPRTL___kmpc_omp_target_task_alloc),
3938 AllocArgs);
3939 } else {
3940 NewTask =
3941 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
3942 CGM.getModule(), OMPRTL___kmpc_omp_task_alloc),
3943 AllocArgs);
3944 }
3945 // Emit detach clause initialization.
3946 // evt = (typeof(evt))__kmpc_task_allow_completion_event(loc, tid,
3947 // task_descriptor);
3948 if (const auto *DC = D.getSingleClause<OMPDetachClause>()) {
3949 const Expr *Evt = DC->getEventHandler()->IgnoreParenImpCasts();
3950 LValue EvtLVal = CGF.EmitLValue(Evt);
3951
3952 // Build kmp_event_t *__kmpc_task_allow_completion_event(ident_t *loc_ref,
3953 // int gtid, kmp_task_t *task);
3954 llvm::Value *Loc = emitUpdateLocation(CGF, DC->getBeginLoc());
3955 llvm::Value *Tid = getThreadID(CGF, DC->getBeginLoc());
3956 Tid = CGF.Builder.CreateIntCast(Tid, CGF.IntTy, /*isSigned=*/false);
3957 llvm::Value *EvtVal = CGF.EmitRuntimeCall(
3958 OMPBuilder.getOrCreateRuntimeFunction(
3959 CGM.getModule(), OMPRTL___kmpc_task_allow_completion_event),
3960 {Loc, Tid, NewTask});
3961 EvtVal = CGF.EmitScalarConversion(EvtVal, C.VoidPtrTy, Evt->getType(),
3962 Evt->getExprLoc());
3963 CGF.EmitStoreOfScalar(EvtVal, EvtLVal);
3964 }
3965 // Process affinity clauses.
3966 if (D.hasClausesOfKind<OMPAffinityClause>()) {
3967 // Process list of affinity data.
3968 ASTContext &C = CGM.getContext();
3969 Address AffinitiesArray = Address::invalid();
3970 // Calculate number of elements to form the array of affinity data.
3971 llvm::Value *NumOfElements = nullptr;
3972 unsigned NumAffinities = 0;
3973 for (const auto *C : D.getClausesOfKind<OMPAffinityClause>()) {
3974 if (const Expr *Modifier = C->getModifier()) {
3975 const auto *IE = cast<OMPIteratorExpr>(Modifier->IgnoreParenImpCasts());
3976 for (unsigned I = 0, E = IE->numOfIterators(); I < E; ++I) {
3977 llvm::Value *Sz = CGF.EmitScalarExpr(IE->getHelper(I).Upper);
3978 Sz = CGF.Builder.CreateIntCast(Sz, CGF.SizeTy, /*isSigned=*/false);
3979 NumOfElements =
3980 NumOfElements ? CGF.Builder.CreateNUWMul(NumOfElements, Sz) : Sz;
3981 }
3982 } else {
3983 NumAffinities += C->varlist_size();
3984 }
3985 }
3987 // Fields ids in kmp_task_affinity_info record.
3988 enum RTLAffinityInfoFieldsTy { BaseAddr, Len, Flags };
3989
3990 QualType KmpTaskAffinityInfoArrayTy;
3991 if (NumOfElements) {
3992 NumOfElements = CGF.Builder.CreateNUWAdd(
3993 llvm::ConstantInt::get(CGF.SizeTy, NumAffinities), NumOfElements);
3994 auto *OVE = new (C) OpaqueValueExpr(
3995 Loc,
3996 C.getIntTypeForBitwidth(C.getTypeSize(C.getSizeType()), /*Signed=*/0),
3997 VK_PRValue);
3998 CodeGenFunction::OpaqueValueMapping OpaqueMap(CGF, OVE,
3999 RValue::get(NumOfElements));
4000 KmpTaskAffinityInfoArrayTy = C.getVariableArrayType(
4002 /*IndexTypeQuals=*/0);
4003 // Properly emit variable-sized array.
4004 auto *PD = ImplicitParamDecl::Create(C, KmpTaskAffinityInfoArrayTy,
4006 CGF.EmitVarDecl(*PD);
4007 AffinitiesArray = CGF.GetAddrOfLocalVar(PD);
4008 NumOfElements = CGF.Builder.CreateIntCast(NumOfElements, CGF.Int32Ty,
4009 /*isSigned=*/false);
4010 } else {
4011 KmpTaskAffinityInfoArrayTy = C.getConstantArrayType(
4013 llvm::APInt(C.getTypeSize(C.getSizeType()), NumAffinities), nullptr,
4014 ArraySizeModifier::Normal, /*IndexTypeQuals=*/0);
4015 AffinitiesArray = CGF.CreateMemTempWithoutCast(KmpTaskAffinityInfoArrayTy,
4016 ".affs.arr.addr");
4017 AffinitiesArray = CGF.Builder.CreateConstArrayGEP(AffinitiesArray, 0);
4018 NumOfElements = llvm::ConstantInt::get(CGM.Int32Ty, NumAffinities,
4019 /*isSigned=*/false);
4020 }
4021
4022 const auto *KmpAffinityInfoRD = KmpTaskAffinityInfoTy->getAsRecordDecl();
4023 // Fill array by elements without iterators.
4024 unsigned Pos = 0;
4025 bool HasIterator = false;
4026 for (const auto *C : D.getClausesOfKind<OMPAffinityClause>()) {
4027 if (C->getModifier()) {
4028 HasIterator = true;
4029 continue;
4030 }
4031 for (const Expr *E : C->varlist()) {
4032 llvm::Value *Addr;
4033 llvm::Value *Size;
4034 std::tie(Addr, Size) = getPointerAndSize(CGF, E);
4035 LValue Base =
4036 CGF.MakeAddrLValue(CGF.Builder.CreateConstGEP(AffinitiesArray, Pos),
4038 // affs[i].base_addr = &<Affinities[i].second>;
4039 LValue BaseAddrLVal = CGF.EmitLValueForField(
4040 Base, *std::next(KmpAffinityInfoRD->field_begin(), BaseAddr));
4041 CGF.EmitStoreOfScalar(CGF.Builder.CreatePtrToInt(Addr, CGF.IntPtrTy),
4042 BaseAddrLVal);
4043 // affs[i].len = sizeof(<Affinities[i].second>);
4044 LValue LenLVal = CGF.EmitLValueForField(
4045 Base, *std::next(KmpAffinityInfoRD->field_begin(), Len));
4046 CGF.EmitStoreOfScalar(Size, LenLVal);
4047 ++Pos;
4048 }
4049 }
4050 LValue PosLVal;
4051 if (HasIterator) {
4052 PosLVal = CGF.MakeAddrLValue(
4053 CGF.CreateMemTempWithoutCast(C.getSizeType(), "affs.counter.addr"),
4054 C.getSizeType());
4055 CGF.EmitStoreOfScalar(llvm::ConstantInt::get(CGF.SizeTy, Pos), PosLVal);
4056 }
4057 // Process elements with iterators.
4058 for (const auto *C : D.getClausesOfKind<OMPAffinityClause>()) {
4059 const Expr *Modifier = C->getModifier();
4060 if (!Modifier)
4061 continue;
4062 OMPIteratorGeneratorScope IteratorScope(
4063 CGF, cast_or_null<OMPIteratorExpr>(Modifier->IgnoreParenImpCasts()));
4064 for (const Expr *E : C->varlist()) {
4065 llvm::Value *Addr;
4066 llvm::Value *Size;
4067 std::tie(Addr, Size) = getPointerAndSize(CGF, E);
4068 llvm::Value *Idx = CGF.EmitLoadOfScalar(PosLVal, E->getExprLoc());
4069 LValue Base =
4070 CGF.MakeAddrLValue(CGF.Builder.CreateGEP(CGF, AffinitiesArray, Idx),
4072 // affs[i].base_addr = &<Affinities[i].second>;
4073 LValue BaseAddrLVal = CGF.EmitLValueForField(
4074 Base, *std::next(KmpAffinityInfoRD->field_begin(), BaseAddr));
4075 CGF.EmitStoreOfScalar(CGF.Builder.CreatePtrToInt(Addr, CGF.IntPtrTy),
4076 BaseAddrLVal);
4077 // affs[i].len = sizeof(<Affinities[i].second>);
4078 LValue LenLVal = CGF.EmitLValueForField(
4079 Base, *std::next(KmpAffinityInfoRD->field_begin(), Len));
4080 CGF.EmitStoreOfScalar(Size, LenLVal);
4081 Idx = CGF.Builder.CreateNUWAdd(
4082 Idx, llvm::ConstantInt::get(Idx->getType(), 1));
4083 CGF.EmitStoreOfScalar(Idx, PosLVal);
4084 }
4085 }
4086 // Call to kmp_int32 __kmpc_omp_reg_task_with_affinity(ident_t *loc_ref,
4087 // kmp_int32 gtid, kmp_task_t *new_task, kmp_int32
4088 // naffins, kmp_task_affinity_info_t *affin_list);
4089 llvm::Value *LocRef = emitUpdateLocation(CGF, Loc);
4090 llvm::Value *GTid = getThreadID(CGF, Loc);
4091 llvm::Value *AffinListPtr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
4092 AffinitiesArray.emitRawPointer(CGF), CGM.VoidPtrTy);
4093 // FIXME: Emit the function and ignore its result for now unless the
4094 // runtime function is properly implemented.
4095 (void)CGF.EmitRuntimeCall(
4096 OMPBuilder.getOrCreateRuntimeFunction(
4097 CGM.getModule(), OMPRTL___kmpc_omp_reg_task_with_affinity),
4098 {LocRef, GTid, NewTask, NumOfElements, AffinListPtr});
4099 }
4100 llvm::Value *NewTaskNewTaskTTy =
4102 NewTask, KmpTaskTWithPrivatesPtrTy);
4103 LValue Base = CGF.MakeNaturalAlignRawAddrLValue(NewTaskNewTaskTTy,
4104 KmpTaskTWithPrivatesQTy);
4105 LValue TDBase =
4106 CGF.EmitLValueForField(Base, *KmpTaskTWithPrivatesQTyRD->field_begin());
4107 // Fill the data in the resulting kmp_task_t record.
4108 // Copy shareds if there are any.
4109 Address KmpTaskSharedsPtr = Address::invalid();
4110 if (!SharedsTy->castAsRecordDecl()->field_empty()) {
4111 KmpTaskSharedsPtr = Address(
4112 CGF.EmitLoadOfScalar(
4114 TDBase,
4115 *std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTShareds)),
4116 Loc),
4117 CGF.Int8Ty, CGM.getNaturalTypeAlignment(SharedsTy));
4118 LValue Dest = CGF.MakeAddrLValue(KmpTaskSharedsPtr, SharedsTy);
4119 LValue Src = CGF.MakeAddrLValue(Shareds, SharedsTy);
4120 CGF.EmitAggregateCopy(Dest, Src, SharedsTy, AggValueSlot::DoesNotOverlap);
4121 }
4122 // Emit initial values for private copies (if any).
4124 if (!Privates.empty()) {
4125 emitPrivatesInit(CGF, D, KmpTaskSharedsPtr, Base, KmpTaskTWithPrivatesQTyRD,
4126 SharedsTy, SharedsPtrTy, Data, Privates,
4127 /*ForDup=*/false);
4128 if (isOpenMPTaskLoopDirective(D.getDirectiveKind()) &&
4129 (!Data.LastprivateVars.empty() || checkInitIsRequired(CGF, Privates))) {
4130 Result.TaskDupFn = emitTaskDupFunction(
4131 CGM, Loc, D, KmpTaskTWithPrivatesPtrQTy, KmpTaskTWithPrivatesQTyRD,
4132 KmpTaskTQTyRD, SharedsTy, SharedsPtrTy, Data, Privates,
4133 /*WithLastIter=*/!Data.LastprivateVars.empty());
4134 }
4135 }
4136 // Fields of union "kmp_cmplrdata_t" for destructors and priority.
4137 enum { Priority = 0, Destructors = 1 };
4138 // Provide pointer to function with destructors for privates.
4139 auto FI = std::next(KmpTaskTQTyRD->field_begin(), Data1);
4140 const auto *KmpCmplrdataUD = (*FI)->getType()->castAsRecordDecl();
4141 assert(KmpCmplrdataUD->isUnion());
4142 if (NeedsCleanup) {
4143 llvm::Value *DestructorFn = emitDestructorsFunction(
4144 CGM, Loc, KmpInt32Ty, KmpTaskTWithPrivatesPtrQTy,
4145 KmpTaskTWithPrivatesQTy);
4146 LValue Data1LV = CGF.EmitLValueForField(TDBase, *FI);
4147 LValue DestructorsLV = CGF.EmitLValueForField(
4148 Data1LV, *std::next(KmpCmplrdataUD->field_begin(), Destructors));
4150 DestructorFn, KmpRoutineEntryPtrTy),
4151 DestructorsLV);
4152 }
4153 // Set priority.
4154 if (Data.Priority.getInt()) {
4155 LValue Data2LV = CGF.EmitLValueForField(
4156 TDBase, *std::next(KmpTaskTQTyRD->field_begin(), Data2));
4157 LValue PriorityLV = CGF.EmitLValueForField(
4158 Data2LV, *std::next(KmpCmplrdataUD->field_begin(), Priority));
4159 CGF.EmitStoreOfScalar(Data.Priority.getPointer(), PriorityLV);
4160 }
4161 Result.NewTask = NewTask;
4162 Result.TaskEntry = TaskEntry;
4163 Result.NewTaskNewTaskTTy = NewTaskNewTaskTTy;
4164 Result.TDBase = TDBase;
4165 Result.KmpTaskTQTyRD = KmpTaskTQTyRD;
4166 return Result;
4167}
4168
4169/// Translates internal dependency kind into the runtime kind.
4171 RTLDependenceKindTy DepKind;
4172 switch (K) {
4173 case OMPC_DEPEND_in:
4174 DepKind = RTLDependenceKindTy::DepIn;
4175 break;
4176 // Out and InOut dependencies must use the same code.
4177 case OMPC_DEPEND_out:
4178 case OMPC_DEPEND_inout:
4179 DepKind = RTLDependenceKindTy::DepInOut;
4180 break;
4181 case OMPC_DEPEND_mutexinoutset:
4182 DepKind = RTLDependenceKindTy::DepMutexInOutSet;
4183 break;
4184 case OMPC_DEPEND_inoutset:
4185 DepKind = RTLDependenceKindTy::DepInOutSet;
4186 break;
4187 case OMPC_DEPEND_outallmemory:
4188 DepKind = RTLDependenceKindTy::DepOmpAllMem;
4189 break;
4190 case OMPC_DEPEND_source:
4191 case OMPC_DEPEND_sink:
4192 case OMPC_DEPEND_depobj:
4193 case OMPC_DEPEND_inoutallmemory:
4195 llvm_unreachable("Unknown task dependence type");
4196 }
4197 return DepKind;
4198}
4199
4200/// Builds kmp_depend_info, if it is not built yet, and builds flags type.
4201static void getDependTypes(ASTContext &C, QualType &KmpDependInfoTy,
4202 QualType &FlagsTy) {
4203 FlagsTy = C.getIntTypeForBitwidth(C.getTypeSize(C.BoolTy), /*Signed=*/false);
4204 if (KmpDependInfoTy.isNull()) {
4205 RecordDecl *KmpDependInfoRD = C.buildImplicitRecord("kmp_depend_info");
4206 KmpDependInfoRD->startDefinition();
4207 addFieldToRecordDecl(C, KmpDependInfoRD, C.getIntPtrType());
4208 addFieldToRecordDecl(C, KmpDependInfoRD, C.getSizeType());
4209 addFieldToRecordDecl(C, KmpDependInfoRD, FlagsTy);
4210 KmpDependInfoRD->completeDefinition();
4211 KmpDependInfoTy = C.getCanonicalTagType(KmpDependInfoRD);
4212 }
4213}
4214
4215std::pair<llvm::Value *, LValue>
4217 SourceLocation Loc) {
4218 ASTContext &C = CGM.getContext();
4219 QualType FlagsTy;
4220 getDependTypes(C, KmpDependInfoTy, FlagsTy);
4221 auto *KmpDependInfoRD = KmpDependInfoTy->castAsRecordDecl();
4222 QualType KmpDependInfoPtrTy = C.getPointerType(KmpDependInfoTy);
4224 DepobjLVal.getAddress().withElementType(
4225 CGF.ConvertTypeForMem(KmpDependInfoPtrTy)),
4226 KmpDependInfoPtrTy->castAs<PointerType>());
4227 Address DepObjAddr = CGF.Builder.CreateGEP(
4228 CGF, Base.getAddress(),
4229 llvm::ConstantInt::get(CGF.IntPtrTy, -1, /*isSigned=*/true));
4230 LValue NumDepsBase = CGF.MakeAddrLValue(
4231 DepObjAddr, KmpDependInfoTy, Base.getBaseInfo(), Base.getTBAAInfo());
4232 // NumDeps = deps[i].base_addr;
4233 LValue BaseAddrLVal = CGF.EmitLValueForField(
4234 NumDepsBase,
4235 *std::next(KmpDependInfoRD->field_begin(),
4236 static_cast<unsigned int>(RTLDependInfoFields::BaseAddr)));
4237 llvm::Value *NumDeps = CGF.EmitLoadOfScalar(BaseAddrLVal, Loc);
4238 return std::make_pair(NumDeps, Base);
4239}
4240
4241static void emitDependData(CodeGenFunction &CGF, QualType &KmpDependInfoTy,
4242 llvm::PointerUnion<unsigned *, LValue *> Pos,
4244 Address DependenciesArray) {
4245 CodeGenModule &CGM = CGF.CGM;
4246 ASTContext &C = CGM.getContext();
4247 QualType FlagsTy;
4248 getDependTypes(C, KmpDependInfoTy, FlagsTy);
4249 auto *KmpDependInfoRD = KmpDependInfoTy->castAsRecordDecl();
4250 llvm::Type *LLVMFlagsTy = CGF.ConvertTypeForMem(FlagsTy);
4251
4252 OMPIteratorGeneratorScope IteratorScope(
4253 CGF, cast_or_null<OMPIteratorExpr>(
4254 Data.IteratorExpr ? Data.IteratorExpr->IgnoreParenImpCasts()
4255 : nullptr));
4256 for (const Expr *E : Data.DepExprs) {
4257 llvm::Value *Addr;
4258 llvm::Value *Size;
4259
4260 // The expression will be a nullptr in the 'omp_all_memory' case.
4261 if (E) {
4262 std::tie(Addr, Size) = getPointerAndSize(CGF, E);
4263 Addr = CGF.Builder.CreatePtrToInt(Addr, CGF.IntPtrTy);
4264 } else {
4265 Addr = llvm::ConstantInt::get(CGF.IntPtrTy, 0);
4266 Size = llvm::ConstantInt::get(CGF.SizeTy, 0);
4267 }
4268 LValue Base;
4269 if (unsigned *P = dyn_cast<unsigned *>(Pos)) {
4270 Base = CGF.MakeAddrLValue(
4271 CGF.Builder.CreateConstGEP(DependenciesArray, *P), KmpDependInfoTy);
4272 } else {
4273 assert(E && "Expected a non-null expression");
4274 LValue &PosLVal = *cast<LValue *>(Pos);
4275 llvm::Value *Idx = CGF.EmitLoadOfScalar(PosLVal, E->getExprLoc());
4276 Base = CGF.MakeAddrLValue(
4277 CGF.Builder.CreateGEP(CGF, DependenciesArray, Idx), KmpDependInfoTy);
4278 }
4279 // deps[i].base_addr = &<Dependencies[i].second>;
4280 LValue BaseAddrLVal = CGF.EmitLValueForField(
4281 Base,
4282 *std::next(KmpDependInfoRD->field_begin(),
4283 static_cast<unsigned int>(RTLDependInfoFields::BaseAddr)));
4284 CGF.EmitStoreOfScalar(Addr, BaseAddrLVal);
4285 // deps[i].len = sizeof(<Dependencies[i].second>);
4286 LValue LenLVal = CGF.EmitLValueForField(
4287 Base, *std::next(KmpDependInfoRD->field_begin(),
4288 static_cast<unsigned int>(RTLDependInfoFields::Len)));
4289 CGF.EmitStoreOfScalar(Size, LenLVal);
4290 // deps[i].flags = <Dependencies[i].first>;
4291 RTLDependenceKindTy DepKind = translateDependencyKind(Data.DepKind);
4292 LValue FlagsLVal = CGF.EmitLValueForField(
4293 Base,
4294 *std::next(KmpDependInfoRD->field_begin(),
4295 static_cast<unsigned int>(RTLDependInfoFields::Flags)));
4297 llvm::ConstantInt::get(LLVMFlagsTy, static_cast<unsigned int>(DepKind)),
4298 FlagsLVal);
4299 if (unsigned *P = dyn_cast<unsigned *>(Pos)) {
4300 ++(*P);
4301 } else {
4302 LValue &PosLVal = *cast<LValue *>(Pos);
4303 llvm::Value *Idx = CGF.EmitLoadOfScalar(PosLVal, E->getExprLoc());
4304 Idx = CGF.Builder.CreateNUWAdd(Idx,
4305 llvm::ConstantInt::get(Idx->getType(), 1));
4306 CGF.EmitStoreOfScalar(Idx, PosLVal);
4307 }
4308 }
4309}
4310
4314 assert(Data.DepKind == OMPC_DEPEND_depobj &&
4315 "Expected depobj dependency kind.");
4317 SmallVector<LValue, 4> SizeLVals;
4318 ASTContext &C = CGF.getContext();
4319 {
4320 OMPIteratorGeneratorScope IteratorScope(
4321 CGF, cast_or_null<OMPIteratorExpr>(
4322 Data.IteratorExpr ? Data.IteratorExpr->IgnoreParenImpCasts()
4323 : nullptr));
4324 for (const Expr *E : Data.DepExprs) {
4325 llvm::Value *NumDeps;
4326 LValue Base;
4327 LValue DepobjLVal = CGF.EmitLValue(E->IgnoreParenImpCasts());
4328 std::tie(NumDeps, Base) =
4329 getDepobjElements(CGF, DepobjLVal, E->getExprLoc());
4330 LValue NumLVal = CGF.MakeAddrLValue(
4331 CGF.CreateMemTempWithoutCast(C.getUIntPtrType(), "depobj.size.addr"),
4332 C.getUIntPtrType());
4333 CGF.Builder.CreateStore(llvm::ConstantInt::get(CGF.IntPtrTy, 0),
4334 NumLVal.getAddress());
4335 llvm::Value *PrevVal = CGF.EmitLoadOfScalar(NumLVal, E->getExprLoc());
4336 llvm::Value *Add = CGF.Builder.CreateNUWAdd(PrevVal, NumDeps);
4337 CGF.EmitStoreOfScalar(Add, NumLVal);
4338 SizeLVals.push_back(NumLVal);
4339 }
4340 }
4341 for (unsigned I = 0, E = SizeLVals.size(); I < E; ++I) {
4342 llvm::Value *Size =
4343 CGF.EmitLoadOfScalar(SizeLVals[I], Data.DepExprs[I]->getExprLoc());
4344 Sizes.push_back(Size);
4345 }
4346 return Sizes;
4347}
4348
4351 LValue PosLVal,
4353 Address DependenciesArray) {
4354 assert(Data.DepKind == OMPC_DEPEND_depobj &&
4355 "Expected depobj dependency kind.");
4356 llvm::Value *ElSize = CGF.getTypeSize(KmpDependInfoTy);
4357 {
4358 OMPIteratorGeneratorScope IteratorScope(
4359 CGF, cast_or_null<OMPIteratorExpr>(
4360 Data.IteratorExpr ? Data.IteratorExpr->IgnoreParenImpCasts()
4361 : nullptr));
4362 for (const Expr *E : Data.DepExprs) {
4363 llvm::Value *NumDeps;
4364 LValue Base;
4365 LValue DepobjLVal = CGF.EmitLValue(E->IgnoreParenImpCasts());
4366 std::tie(NumDeps, Base) =
4367 getDepobjElements(CGF, DepobjLVal, E->getExprLoc());
4368
4369 // memcopy dependency data.
4370 llvm::Value *Size = CGF.Builder.CreateNUWMul(
4371 ElSize,
4372 CGF.Builder.CreateIntCast(NumDeps, CGF.SizeTy, /*isSigned=*/false));
4373 llvm::Value *Pos = CGF.EmitLoadOfScalar(PosLVal, E->getExprLoc());
4374 Address DepAddr = CGF.Builder.CreateGEP(CGF, DependenciesArray, Pos);
4375 CGF.Builder.CreateMemCpy(DepAddr, Base.getAddress(), Size);
4376
4377 // Increase pos.
4378 // pos += size;
4379 llvm::Value *Add = CGF.Builder.CreateNUWAdd(Pos, NumDeps);
4380 CGF.EmitStoreOfScalar(Add, PosLVal);
4381 }
4382 }
4383}
4384
4385std::pair<llvm::Value *, Address> CGOpenMPRuntime::emitDependClause(
4387 SourceLocation Loc) {
4388 if (llvm::all_of(Dependencies, [](const OMPTaskDataTy::DependData &D) {
4389 return D.DepExprs.empty();
4390 }))
4391 return std::make_pair(nullptr, Address::invalid());
4392 // Process list of dependencies.
4393 ASTContext &C = CGM.getContext();
4394 Address DependenciesArray = Address::invalid();
4395 llvm::Value *NumOfElements = nullptr;
4396 unsigned NumDependencies = std::accumulate(
4397 Dependencies.begin(), Dependencies.end(), 0,
4398 [](unsigned V, const OMPTaskDataTy::DependData &D) {
4399 return D.DepKind == OMPC_DEPEND_depobj
4400 ? V
4401 : (V + (D.IteratorExpr ? 0 : D.DepExprs.size()));
4402 });
4403 QualType FlagsTy;
4404 getDependTypes(C, KmpDependInfoTy, FlagsTy);
4405 bool HasDepobjDeps = false;
4406 bool HasRegularWithIterators = false;
4407 llvm::Value *NumOfDepobjElements = llvm::ConstantInt::get(CGF.IntPtrTy, 0);
4408 llvm::Value *NumOfRegularWithIterators =
4409 llvm::ConstantInt::get(CGF.IntPtrTy, 0);
4410 // Calculate number of depobj dependencies and regular deps with the
4411 // iterators.
4412 for (const OMPTaskDataTy::DependData &D : Dependencies) {
4413 if (D.DepKind == OMPC_DEPEND_depobj) {
4416 for (llvm::Value *Size : Sizes) {
4417 NumOfDepobjElements =
4418 CGF.Builder.CreateNUWAdd(NumOfDepobjElements, Size);
4419 }
4420 HasDepobjDeps = true;
4421 continue;
4422 }
4423 // Include number of iterations, if any.
4424
4425 if (const auto *IE = cast_or_null<OMPIteratorExpr>(D.IteratorExpr)) {
4426 llvm::Value *ClauseIteratorSpace =
4427 llvm::ConstantInt::get(CGF.IntPtrTy, 1);
4428 for (unsigned I = 0, E = IE->numOfIterators(); I < E; ++I) {
4429 llvm::Value *Sz = CGF.EmitScalarExpr(IE->getHelper(I).Upper);
4430 Sz = CGF.Builder.CreateIntCast(Sz, CGF.IntPtrTy, /*isSigned=*/false);
4431 ClauseIteratorSpace = CGF.Builder.CreateNUWMul(Sz, ClauseIteratorSpace);
4432 }
4433 llvm::Value *NumClauseDeps = CGF.Builder.CreateNUWMul(
4434 ClauseIteratorSpace,
4435 llvm::ConstantInt::get(CGF.IntPtrTy, D.DepExprs.size()));
4436 NumOfRegularWithIterators =
4437 CGF.Builder.CreateNUWAdd(NumOfRegularWithIterators, NumClauseDeps);
4438 HasRegularWithIterators = true;
4439 continue;
4440 }
4441 }
4442
4443 QualType KmpDependInfoArrayTy;
4444 if (HasDepobjDeps || HasRegularWithIterators) {
4445 NumOfElements = llvm::ConstantInt::get(CGM.IntPtrTy, NumDependencies,
4446 /*isSigned=*/false);
4447 if (HasDepobjDeps) {
4448 NumOfElements =
4449 CGF.Builder.CreateNUWAdd(NumOfDepobjElements, NumOfElements);
4450 }
4451 if (HasRegularWithIterators) {
4452 NumOfElements =
4453 CGF.Builder.CreateNUWAdd(NumOfRegularWithIterators, NumOfElements);
4454 }
4455 auto *OVE = new (C) OpaqueValueExpr(
4456 Loc, C.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/0),
4457 VK_PRValue);
4458 CodeGenFunction::OpaqueValueMapping OpaqueMap(CGF, OVE,
4459 RValue::get(NumOfElements));
4460 KmpDependInfoArrayTy =
4461 C.getVariableArrayType(KmpDependInfoTy, OVE, ArraySizeModifier::Normal,
4462 /*IndexTypeQuals=*/0);
4463 // CGF.EmitVariablyModifiedType(KmpDependInfoArrayTy);
4464 // Properly emit variable-sized array.
4465 auto *PD = ImplicitParamDecl::Create(C, KmpDependInfoArrayTy,
4467 CGF.EmitVarDecl(*PD);
4468 DependenciesArray = CGF.GetAddrOfLocalVar(PD);
4469 NumOfElements = CGF.Builder.CreateIntCast(NumOfElements, CGF.Int32Ty,
4470 /*isSigned=*/false);
4471 } else {
4472 KmpDependInfoArrayTy = C.getConstantArrayType(
4473 KmpDependInfoTy, llvm::APInt(/*numBits=*/64, NumDependencies), nullptr,
4474 ArraySizeModifier::Normal, /*IndexTypeQuals=*/0);
4475 DependenciesArray =
4476 CGF.CreateMemTempWithoutCast(KmpDependInfoArrayTy, ".dep.arr.addr");
4477 DependenciesArray = CGF.Builder.CreateConstArrayGEP(DependenciesArray, 0);
4478 NumOfElements = llvm::ConstantInt::get(CGM.Int32Ty, NumDependencies,
4479 /*isSigned=*/false);
4480 }
4481 unsigned Pos = 0;
4482 for (const OMPTaskDataTy::DependData &Dep : Dependencies) {
4483 if (Dep.DepKind == OMPC_DEPEND_depobj || Dep.IteratorExpr)
4484 continue;
4485 emitDependData(CGF, KmpDependInfoTy, &Pos, Dep, DependenciesArray);
4486 }
4487 // Copy regular dependencies with iterators.
4488 LValue PosLVal = CGF.MakeAddrLValue(
4489 CGF.CreateMemTempWithoutCast(C.getSizeType(), "dep.counter.addr"),
4490 C.getSizeType());
4491 CGF.EmitStoreOfScalar(llvm::ConstantInt::get(CGF.SizeTy, Pos), PosLVal);
4492 for (const OMPTaskDataTy::DependData &Dep : Dependencies) {
4493 if (Dep.DepKind == OMPC_DEPEND_depobj || !Dep.IteratorExpr)
4494 continue;
4495 emitDependData(CGF, KmpDependInfoTy, &PosLVal, Dep, DependenciesArray);
4496 }
4497 // Copy final depobj arrays without iterators.
4498 if (HasDepobjDeps) {
4499 for (const OMPTaskDataTy::DependData &Dep : Dependencies) {
4500 if (Dep.DepKind != OMPC_DEPEND_depobj)
4501 continue;
4502 emitDepobjElements(CGF, KmpDependInfoTy, PosLVal, Dep, DependenciesArray);
4503 }
4504 }
4505 DependenciesArray = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
4506 DependenciesArray, CGF.VoidPtrTy, CGF.Int8Ty);
4507 return std::make_pair(NumOfElements, DependenciesArray);
4508}
4509
4511 CodeGenFunction &CGF, const OMPTaskDataTy::DependData &Dependencies,
4512 SourceLocation Loc) {
4513 if (Dependencies.DepExprs.empty())
4514 return Address::invalid();
4515 // Process list of dependencies.
4516 ASTContext &C = CGM.getContext();
4517 Address DependenciesArray = Address::invalid();
4518 unsigned NumDependencies = Dependencies.DepExprs.size();
4519 QualType FlagsTy;
4520 getDependTypes(C, KmpDependInfoTy, FlagsTy);
4521 auto *KmpDependInfoRD = KmpDependInfoTy->castAsRecordDecl();
4522
4523 llvm::Value *Size;
4524 // Define type kmp_depend_info[<Dependencies.size()>];
4525 // For depobj reserve one extra element to store the number of elements.
4526 // It is required to handle depobj(x) update(in) construct.
4527 // kmp_depend_info[<Dependencies.size()>] deps;
4528 llvm::Value *NumDepsVal;
4529 CharUnits Align = C.getTypeAlignInChars(KmpDependInfoTy);
4530 if (const auto *IE =
4531 cast_or_null<OMPIteratorExpr>(Dependencies.IteratorExpr)) {
4532 NumDepsVal = llvm::ConstantInt::get(CGF.SizeTy, 1);
4533 for (unsigned I = 0, E = IE->numOfIterators(); I < E; ++I) {
4534 llvm::Value *Sz = CGF.EmitScalarExpr(IE->getHelper(I).Upper);
4535 Sz = CGF.Builder.CreateIntCast(Sz, CGF.SizeTy, /*isSigned=*/false);
4536 NumDepsVal = CGF.Builder.CreateNUWMul(NumDepsVal, Sz);
4537 }
4538 Size = CGF.Builder.CreateNUWAdd(llvm::ConstantInt::get(CGF.SizeTy, 1),
4539 NumDepsVal);
4540 CharUnits SizeInBytes =
4541 C.getTypeSizeInChars(KmpDependInfoTy).alignTo(Align);
4542 llvm::Value *RecSize = CGM.getSize(SizeInBytes);
4543 Size = CGF.Builder.CreateNUWMul(Size, RecSize);
4544 NumDepsVal =
4545 CGF.Builder.CreateIntCast(NumDepsVal, CGF.IntPtrTy, /*isSigned=*/false);
4546 } else {
4547 QualType KmpDependInfoArrayTy = C.getConstantArrayType(
4548 KmpDependInfoTy, llvm::APInt(/*numBits=*/64, NumDependencies + 1),
4549 nullptr, ArraySizeModifier::Normal, /*IndexTypeQuals=*/0);
4550 CharUnits Sz = C.getTypeSizeInChars(KmpDependInfoArrayTy);
4551 Size = CGM.getSize(Sz.alignTo(Align));
4552 NumDepsVal = llvm::ConstantInt::get(CGF.IntPtrTy, NumDependencies);
4553 }
4554 // Need to allocate on the dynamic memory.
4555 llvm::Value *ThreadID = getThreadID(CGF, Loc);
4556 // Use default allocator.
4557 llvm::Value *Allocator = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
4558 llvm::Value *Args[] = {ThreadID, Size, Allocator};
4559
4560 llvm::Value *Addr =
4561 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
4562 CGM.getModule(), OMPRTL___kmpc_alloc),
4563 Args, ".dep.arr.addr");
4564 llvm::Type *KmpDependInfoLlvmTy = CGF.ConvertTypeForMem(KmpDependInfoTy);
4566 Addr, CGF.Builder.getPtrTy(0));
4567 DependenciesArray = Address(Addr, KmpDependInfoLlvmTy, Align);
4568 // Write number of elements in the first element of array for depobj.
4569 LValue Base = CGF.MakeAddrLValue(DependenciesArray, KmpDependInfoTy);
4570 // deps[i].base_addr = NumDependencies;
4571 LValue BaseAddrLVal = CGF.EmitLValueForField(
4572 Base,
4573 *std::next(KmpDependInfoRD->field_begin(),
4574 static_cast<unsigned int>(RTLDependInfoFields::BaseAddr)));
4575 CGF.EmitStoreOfScalar(NumDepsVal, BaseAddrLVal);
4576 llvm::PointerUnion<unsigned *, LValue *> Pos;
4577 unsigned Idx = 1;
4578 LValue PosLVal;
4579 if (Dependencies.IteratorExpr) {
4580 PosLVal = CGF.MakeAddrLValue(
4581 CGF.CreateMemTempWithoutCast(C.getSizeType(), "iterator.counter.addr"),
4582 C.getSizeType());
4583 CGF.EmitStoreOfScalar(llvm::ConstantInt::get(CGF.SizeTy, Idx), PosLVal,
4584 /*IsInit=*/true);
4585 Pos = &PosLVal;
4586 } else {
4587 Pos = &Idx;
4588 }
4589 emitDependData(CGF, KmpDependInfoTy, Pos, Dependencies, DependenciesArray);
4590 DependenciesArray = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
4591 CGF.Builder.CreateConstGEP(DependenciesArray, 1), CGF.VoidPtrTy,
4592 CGF.Int8Ty);
4593 return DependenciesArray;
4594}
4595
4597 SourceLocation Loc) {
4598 ASTContext &C = CGM.getContext();
4599 QualType FlagsTy;
4600 getDependTypes(C, KmpDependInfoTy, FlagsTy);
4601 LValue Base = CGF.EmitLoadOfPointerLValue(DepobjLVal.getAddress(),
4602 C.VoidPtrTy.castAs<PointerType>());
4603 QualType KmpDependInfoPtrTy = C.getPointerType(KmpDependInfoTy);
4605 Base.getAddress(), CGF.ConvertTypeForMem(KmpDependInfoPtrTy),
4607 llvm::Value *DepObjAddr = CGF.Builder.CreateGEP(
4608 Addr.getElementType(), Addr.emitRawPointer(CGF),
4609 llvm::ConstantInt::get(CGF.IntPtrTy, -1, /*isSigned=*/true));
4610 DepObjAddr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(DepObjAddr,
4611 CGF.VoidPtrTy);
4612 llvm::Value *ThreadID = getThreadID(CGF, Loc);
4613 // Use default allocator.
4614 llvm::Value *Allocator = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
4615 llvm::Value *Args[] = {ThreadID, DepObjAddr, Allocator};
4616
4617 // _kmpc_free(gtid, addr, nullptr);
4618 (void)CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
4619 CGM.getModule(), OMPRTL___kmpc_free),
4620 Args);
4621}
4622
4624 CodeGenFunction &CGF, LValue DepobjLVal, OpenMPDependClauseKind NewDepKind,
4625 SourceLocation Loc) {
4626 ASTContext &C = CGM.getContext();
4627 QualType FlagsTy;
4628 getDependTypes(C, KmpDependInfoTy, FlagsTy);
4629 auto *KmpDependInfoRD = KmpDependInfoTy->castAsRecordDecl();
4630 llvm::Type *LLVMFlagsTy = CGF.ConvertTypeForMem(FlagsTy);
4631 llvm::Value *NumDeps;
4632 LValue Base;
4633 std::tie(NumDeps, Base) = getDepobjElements(CGF, DepobjLVal, Loc);
4634
4635 Address Begin = Base.getAddress();
4636 // Cast from pointer to array type to pointer to single element.
4637 llvm::Value *End = CGF.Builder.CreateGEP(Begin.getElementType(),
4638 Begin.emitRawPointer(CGF), NumDeps);
4639 // The basic structure here is a while-do loop.
4640 llvm::BasicBlock *BodyBB = CGF.createBasicBlock("omp.body");
4641 llvm::BasicBlock *DoneBB = CGF.createBasicBlock("omp.done");
4642 llvm::BasicBlock *EntryBB = CGF.Builder.GetInsertBlock();
4643 CGF.EmitBlock(BodyBB);
4644 llvm::PHINode *ElementPHI =
4645 CGF.Builder.CreatePHI(Begin.getType(), 2, "omp.elementPast");
4646 ElementPHI->addIncoming(Begin.emitRawPointer(CGF), EntryBB);
4647 Begin = Begin.withPointer(ElementPHI, KnownNonNull);
4648 Base = CGF.MakeAddrLValue(Begin, KmpDependInfoTy, Base.getBaseInfo(),
4649 Base.getTBAAInfo());
4650 // deps[i].flags = NewDepKind;
4651 RTLDependenceKindTy DepKind = translateDependencyKind(NewDepKind);
4652 LValue FlagsLVal = CGF.EmitLValueForField(
4653 Base, *std::next(KmpDependInfoRD->field_begin(),
4654 static_cast<unsigned int>(RTLDependInfoFields::Flags)));
4656 llvm::ConstantInt::get(LLVMFlagsTy, static_cast<unsigned int>(DepKind)),
4657 FlagsLVal);
4658
4659 // Shift the address forward by one element.
4660 llvm::Value *ElementNext =
4661 CGF.Builder.CreateConstGEP(Begin, /*Index=*/1, "omp.elementNext")
4662 .emitRawPointer(CGF);
4663 ElementPHI->addIncoming(ElementNext, CGF.Builder.GetInsertBlock());
4664 llvm::Value *IsEmpty =
4665 CGF.Builder.CreateICmpEQ(ElementNext, End, "omp.isempty");
4666 CGF.Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB);
4667 // Done.
4668 CGF.EmitBlock(DoneBB, /*IsFinished=*/true);
4669}
4670
4672 const OMPExecutableDirective &D,
4673 llvm::Function *TaskFunction,
4674 QualType SharedsTy, Address Shareds,
4675 const Expr *IfCond,
4676 const OMPTaskDataTy &Data) {
4677 if (!CGF.HaveInsertPoint())
4678 return;
4679
4681 emitTaskInit(CGF, Loc, D, TaskFunction, SharedsTy, Shareds, Data);
4682 llvm::Value *NewTask = Result.NewTask;
4683 llvm::Function *TaskEntry = Result.TaskEntry;
4684 llvm::Value *NewTaskNewTaskTTy = Result.NewTaskNewTaskTTy;
4685 LValue TDBase = Result.TDBase;
4686 const RecordDecl *KmpTaskTQTyRD = Result.KmpTaskTQTyRD;
4687 // Process list of dependences.
4688 Address DependenciesArray = Address::invalid();
4689 llvm::Value *NumOfElements;
4690 std::tie(NumOfElements, DependenciesArray) =
4691 emitDependClause(CGF, Data.Dependences, Loc);
4692
4693 // NOTE: routine and part_id fields are initialized by __kmpc_omp_task_alloc()
4694 // libcall.
4695 // Build kmp_int32 __kmpc_omp_task_with_deps(ident_t *, kmp_int32 gtid,
4696 // kmp_task_t *new_task, kmp_int32 ndeps, kmp_depend_info_t *dep_list,
4697 // kmp_int32 ndeps_noalias, kmp_depend_info_t *noalias_dep_list) if dependence
4698 // list is not empty
4699 llvm::Value *ThreadID = getThreadID(CGF, Loc);
4700 llvm::Value *UpLoc = emitUpdateLocation(CGF, Loc);
4701 llvm::Value *TaskArgs[] = { UpLoc, ThreadID, NewTask };
4702 llvm::Value *DepTaskArgs[7];
4703 if (!Data.Dependences.empty()) {
4704 DepTaskArgs[0] = UpLoc;
4705 DepTaskArgs[1] = ThreadID;
4706 DepTaskArgs[2] = NewTask;
4707 DepTaskArgs[3] = NumOfElements;
4708 DepTaskArgs[4] = DependenciesArray.emitRawPointer(CGF);
4709 DepTaskArgs[5] = CGF.Builder.getInt32(0);
4710 DepTaskArgs[6] = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
4711 }
4712 auto &&ThenCodeGen = [this, &Data, TDBase, KmpTaskTQTyRD, &TaskArgs,
4713 &DepTaskArgs](CodeGenFunction &CGF, PrePostActionTy &) {
4714 if (!Data.Tied) {
4715 auto PartIdFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTPartId);
4716 LValue PartIdLVal = CGF.EmitLValueForField(TDBase, *PartIdFI);
4717 CGF.EmitStoreOfScalar(CGF.Builder.getInt32(0), PartIdLVal);
4718 }
4719 if (!Data.Dependences.empty()) {
4720 CGF.EmitRuntimeCall(
4721 OMPBuilder.getOrCreateRuntimeFunction(
4722 CGM.getModule(), OMPRTL___kmpc_omp_task_with_deps),
4723 DepTaskArgs);
4724 } else {
4725 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
4726 CGM.getModule(), OMPRTL___kmpc_omp_task),
4727 TaskArgs);
4728 }
4729 // Check if parent region is untied and build return for untied task;
4730 if (auto *Region =
4731 dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo))
4732 Region->emitUntiedSwitch(CGF);
4733 };
4734
4735 llvm::Value *DepWaitTaskArgs[7];
4736 if (!Data.Dependences.empty()) {
4737 DepWaitTaskArgs[0] = UpLoc;
4738 DepWaitTaskArgs[1] = ThreadID;
4739 DepWaitTaskArgs[2] = NumOfElements;
4740 DepWaitTaskArgs[3] = DependenciesArray.emitRawPointer(CGF);
4741 DepWaitTaskArgs[4] = CGF.Builder.getInt32(0);
4742 DepWaitTaskArgs[5] = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
4743 DepWaitTaskArgs[6] =
4744 llvm::ConstantInt::get(CGF.Int32Ty, Data.HasNowaitClause);
4745 }
4746 auto &M = CGM.getModule();
4747 auto &&ElseCodeGen = [this, &M, &TaskArgs, ThreadID, NewTaskNewTaskTTy,
4748 TaskEntry, &Data, &DepWaitTaskArgs,
4749 Loc](CodeGenFunction &CGF, PrePostActionTy &) {
4750 CodeGenFunction::RunCleanupsScope LocalScope(CGF);
4751 // Build void __kmpc_omp_wait_deps(ident_t *, kmp_int32 gtid,
4752 // kmp_int32 ndeps, kmp_depend_info_t *dep_list, kmp_int32
4753 // ndeps_noalias, kmp_depend_info_t *noalias_dep_list); if dependence info
4754 // is specified.
4755 if (!Data.Dependences.empty())
4756 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
4757 M, OMPRTL___kmpc_omp_taskwait_deps_51),
4758 DepWaitTaskArgs);
4759 // Call proxy_task_entry(gtid, new_task);
4760 auto &&CodeGen = [TaskEntry, ThreadID, NewTaskNewTaskTTy,
4761 Loc](CodeGenFunction &CGF, PrePostActionTy &Action) {
4762 Action.Enter(CGF);
4763 llvm::Value *OutlinedFnArgs[] = {ThreadID, NewTaskNewTaskTTy};
4764 CGF.CGM.getOpenMPRuntime().emitOutlinedFunctionCall(CGF, Loc, TaskEntry,
4765 OutlinedFnArgs);
4766 };
4767
4768 // Build void __kmpc_omp_task_begin_if0(ident_t *, kmp_int32 gtid,
4769 // kmp_task_t *new_task);
4770 // Build void __kmpc_omp_task_complete_if0(ident_t *, kmp_int32 gtid,
4771 // kmp_task_t *new_task);
4773 CommonActionTy Action(OMPBuilder.getOrCreateRuntimeFunction(
4774 M, OMPRTL___kmpc_omp_task_begin_if0),
4775 TaskArgs,
4776 OMPBuilder.getOrCreateRuntimeFunction(
4777 M, OMPRTL___kmpc_omp_task_complete_if0),
4778 TaskArgs);
4779 RCG.setAction(Action);
4780 RCG(CGF);
4781 };
4782
4783 if (IfCond) {
4784 emitIfClause(CGF, IfCond, ThenCodeGen, ElseCodeGen);
4785 } else {
4786 RegionCodeGenTy ThenRCG(ThenCodeGen);
4787 ThenRCG(CGF);
4788 }
4789}
4790
4792 const OMPLoopDirective &D,
4793 llvm::Function *TaskFunction,
4794 QualType SharedsTy, Address Shareds,
4795 const Expr *IfCond,
4796 const OMPTaskDataTy &Data) {
4797 if (!CGF.HaveInsertPoint())
4798 return;
4800 emitTaskInit(CGF, Loc, D, TaskFunction, SharedsTy, Shareds, Data);
4801 // NOTE: routine and part_id fields are initialized by __kmpc_omp_task_alloc()
4802 // libcall.
4803 // Call to void __kmpc_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int
4804 // if_val, kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, int nogroup, int
4805 // sched, kmp_uint64 grainsize, void *task_dup);
4806 llvm::Value *ThreadID = getThreadID(CGF, Loc);
4807 llvm::Value *UpLoc = emitUpdateLocation(CGF, Loc);
4808 llvm::Value *IfVal;
4809 if (IfCond) {
4810 IfVal = CGF.Builder.CreateIntCast(CGF.EvaluateExprAsBool(IfCond), CGF.IntTy,
4811 /*isSigned=*/true);
4812 } else {
4813 IfVal = llvm::ConstantInt::getSigned(CGF.IntTy, /*V=*/1);
4814 }
4815
4816 LValue LBLVal = CGF.EmitLValueForField(
4817 Result.TDBase,
4818 *std::next(Result.KmpTaskTQTyRD->field_begin(), KmpTaskTLowerBound));
4819 const auto *LBVar =
4820 cast<VarDecl>(cast<DeclRefExpr>(D.getLowerBoundVariable())->getDecl());
4821 CGF.EmitAnyExprToMem(LBVar->getInit(), LBLVal.getAddress(), LBLVal.getQuals(),
4822 /*IsInitializer=*/true);
4823 LValue UBLVal = CGF.EmitLValueForField(
4824 Result.TDBase,
4825 *std::next(Result.KmpTaskTQTyRD->field_begin(), KmpTaskTUpperBound));
4826 const auto *UBVar =
4827 cast<VarDecl>(cast<DeclRefExpr>(D.getUpperBoundVariable())->getDecl());
4828 CGF.EmitAnyExprToMem(UBVar->getInit(), UBLVal.getAddress(), UBLVal.getQuals(),
4829 /*IsInitializer=*/true);
4830 LValue StLVal = CGF.EmitLValueForField(
4831 Result.TDBase,
4832 *std::next(Result.KmpTaskTQTyRD->field_begin(), KmpTaskTStride));
4833 const auto *StVar =
4834 cast<VarDecl>(cast<DeclRefExpr>(D.getStrideVariable())->getDecl());
4835 CGF.EmitAnyExprToMem(StVar->getInit(), StLVal.getAddress(), StLVal.getQuals(),
4836 /*IsInitializer=*/true);
4837 // Store reductions address.
4838 LValue RedLVal = CGF.EmitLValueForField(
4839 Result.TDBase,
4840 *std::next(Result.KmpTaskTQTyRD->field_begin(), KmpTaskTReductions));
4841 if (Data.Reductions) {
4842 CGF.EmitStoreOfScalar(Data.Reductions, RedLVal);
4843 } else {
4844 CGF.EmitNullInitialization(RedLVal.getAddress(),
4845 CGF.getContext().VoidPtrTy);
4846 }
4847 enum { NoSchedule = 0, Grainsize = 1, NumTasks = 2 };
4849 UpLoc,
4850 ThreadID,
4851 Result.NewTask,
4852 IfVal,
4853 LBLVal.getPointer(CGF),
4854 UBLVal.getPointer(CGF),
4855 CGF.EmitLoadOfScalar(StLVal, Loc),
4856 llvm::ConstantInt::getSigned(
4857 CGF.IntTy, 1), // Always 1 because taskgroup emitted by the compiler
4858 llvm::ConstantInt::getSigned(
4859 CGF.IntTy, Data.Schedule.getPointer()
4860 ? Data.Schedule.getInt() ? NumTasks : Grainsize
4861 : NoSchedule),
4862 Data.Schedule.getPointer()
4863 ? CGF.Builder.CreateIntCast(Data.Schedule.getPointer(), CGF.Int64Ty,
4864 /*isSigned=*/false)
4865 : llvm::ConstantInt::get(CGF.Int64Ty, /*V=*/0)};
4866 if (Data.HasModifier)
4867 TaskArgs.push_back(llvm::ConstantInt::get(CGF.Int32Ty, 1));
4868
4869 TaskArgs.push_back(Result.TaskDupFn
4871 Result.TaskDupFn, CGF.VoidPtrTy)
4872 : llvm::ConstantPointerNull::get(CGF.VoidPtrTy));
4873 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
4874 CGM.getModule(), Data.HasModifier
4875 ? OMPRTL___kmpc_taskloop_5
4876 : OMPRTL___kmpc_taskloop),
4877 TaskArgs);
4878}
4879
4880/// Emit reduction operation for each element of array (required for
4881/// array sections) LHS op = RHS.
4882/// \param Type Type of array.
4883/// \param LHSVar Variable on the left side of the reduction operation
4884/// (references element of array in original variable).
4885/// \param RHSVar Variable on the right side of the reduction operation
4886/// (references element of array in original variable).
4887/// \param RedOpGen Generator of reduction operation with use of LHSVar and
4888/// RHSVar.
4890 CodeGenFunction &CGF, QualType Type, const VarDecl *LHSVar,
4891 const VarDecl *RHSVar,
4892 const llvm::function_ref<void(CodeGenFunction &CGF, const Expr *,
4893 const Expr *, const Expr *)> &RedOpGen,
4894 const Expr *XExpr = nullptr, const Expr *EExpr = nullptr,
4895 const Expr *UpExpr = nullptr) {
4896 // Perform element-by-element initialization.
4897 QualType ElementTy;
4898 Address LHSAddr = CGF.GetAddrOfLocalVar(LHSVar);
4899 Address RHSAddr = CGF.GetAddrOfLocalVar(RHSVar);
4900
4901 // Drill down to the base element type on both arrays.
4902 const ArrayType *ArrayTy = Type->getAsArrayTypeUnsafe();
4903 llvm::Value *NumElements = CGF.emitArrayLength(ArrayTy, ElementTy, LHSAddr);
4904
4905 llvm::Value *RHSBegin = RHSAddr.emitRawPointer(CGF);
4906 llvm::Value *LHSBegin = LHSAddr.emitRawPointer(CGF);
4907 // Cast from pointer to array type to pointer to single element.
4908 llvm::Value *LHSEnd =
4909 CGF.Builder.CreateGEP(LHSAddr.getElementType(), LHSBegin, NumElements);
4910 // The basic structure here is a while-do loop.
4911 llvm::BasicBlock *BodyBB = CGF.createBasicBlock("omp.arraycpy.body");
4912 llvm::BasicBlock *DoneBB = CGF.createBasicBlock("omp.arraycpy.done");
4913 llvm::Value *IsEmpty =
4914 CGF.Builder.CreateICmpEQ(LHSBegin, LHSEnd, "omp.arraycpy.isempty");
4915 CGF.Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB);
4916
4917 // Enter the loop body, making that address the current address.
4918 llvm::BasicBlock *EntryBB = CGF.Builder.GetInsertBlock();
4919 CGF.EmitBlock(BodyBB);
4920
4921 CharUnits ElementSize = CGF.getContext().getTypeSizeInChars(ElementTy);
4922
4923 llvm::PHINode *RHSElementPHI = CGF.Builder.CreatePHI(
4924 RHSBegin->getType(), 2, "omp.arraycpy.srcElementPast");
4925 RHSElementPHI->addIncoming(RHSBegin, EntryBB);
4926 Address RHSElementCurrent(
4927 RHSElementPHI, RHSAddr.getElementType(),
4928 RHSAddr.getAlignment().alignmentOfArrayElement(ElementSize));
4929
4930 llvm::PHINode *LHSElementPHI = CGF.Builder.CreatePHI(
4931 LHSBegin->getType(), 2, "omp.arraycpy.destElementPast");
4932 LHSElementPHI->addIncoming(LHSBegin, EntryBB);
4933 Address LHSElementCurrent(
4934 LHSElementPHI, LHSAddr.getElementType(),
4935 LHSAddr.getAlignment().alignmentOfArrayElement(ElementSize));
4936
4937 // Emit copy.
4939 Scope.addPrivate(LHSVar, LHSElementCurrent);
4940 Scope.addPrivate(RHSVar, RHSElementCurrent);
4941 Scope.Privatize();
4942 RedOpGen(CGF, XExpr, EExpr, UpExpr);
4943 Scope.ForceCleanup();
4944
4945 // Shift the address forward by one element.
4946 llvm::Value *LHSElementNext = CGF.Builder.CreateConstGEP1_32(
4947 LHSAddr.getElementType(), LHSElementPHI, /*Idx0=*/1,
4948 "omp.arraycpy.dest.element");
4949 llvm::Value *RHSElementNext = CGF.Builder.CreateConstGEP1_32(
4950 RHSAddr.getElementType(), RHSElementPHI, /*Idx0=*/1,
4951 "omp.arraycpy.src.element");
4952 // Check whether we've reached the end.
4953 llvm::Value *Done =
4954 CGF.Builder.CreateICmpEQ(LHSElementNext, LHSEnd, "omp.arraycpy.done");
4955 CGF.Builder.CreateCondBr(Done, DoneBB, BodyBB);
4956 LHSElementPHI->addIncoming(LHSElementNext, CGF.Builder.GetInsertBlock());
4957 RHSElementPHI->addIncoming(RHSElementNext, CGF.Builder.GetInsertBlock());
4958
4959 // Done.
4960 CGF.EmitBlock(DoneBB, /*IsFinished=*/true);
4961}
4962
4963/// Emit reduction combiner. If the combiner is a simple expression emit it as
4964/// is, otherwise consider it as combiner of UDR decl and emit it as a call of
4965/// UDR combiner function.
4967 const Expr *ReductionOp) {
4968 if (const auto *CE = dyn_cast<CallExpr>(ReductionOp))
4969 if (const auto *OVE = dyn_cast<OpaqueValueExpr>(CE->getCallee()))
4970 if (const auto *DRE =
4971 dyn_cast<DeclRefExpr>(OVE->getSourceExpr()->IgnoreImpCasts()))
4972 if (const auto *DRD =
4973 dyn_cast<OMPDeclareReductionDecl>(DRE->getDecl())) {
4974 std::pair<llvm::Function *, llvm::Function *> Reduction =
4978 CGF.EmitIgnoredExpr(ReductionOp);
4979 return;
4980 }
4981 CGF.EmitIgnoredExpr(ReductionOp);
4982}
4983
4985 StringRef ReducerName, SourceLocation Loc, llvm::Type *ArgsElemType,
4987 ArrayRef<const Expr *> RHSExprs, ArrayRef<const Expr *> ReductionOps) {
4988 ASTContext &C = CGM.getContext();
4989
4990 // void reduction_func(void *LHSArg, void *RHSArg);
4991 auto *LHSArg =
4992 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
4993 C.VoidPtrTy, ImplicitParamKind::Other);
4994 auto *RHSArg =
4995 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
4996 C.VoidPtrTy, ImplicitParamKind::Other);
4997 FunctionArgList Args{LHSArg, RHSArg};
4998 const auto &CGFI =
4999 CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
5000 std::string Name = getReductionFuncName(ReducerName);
5001 auto *Fn = llvm::Function::Create(CGM.getTypes().GetFunctionType(CGFI),
5002 llvm::GlobalValue::InternalLinkage, Name,
5003 &CGM.getModule());
5004 CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, CGFI);
5005 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
5006 Fn->addFnAttr("sample-profile-suffix-elision-policy", "selected");
5007 Fn->setDoesNotRecurse();
5008 CodeGenFunction CGF(CGM);
5009 CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, CGFI, Args, Loc, Loc);
5010
5011 // Dst = (void*[n])(LHSArg);
5012 // Src = (void*[n])(RHSArg);
5014 CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(LHSArg)),
5015 CGF.Builder.getPtrTy(0)),
5016 ArgsElemType, CGF.getPointerAlign());
5018 CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(RHSArg)),
5019 CGF.Builder.getPtrTy(0)),
5020 ArgsElemType, CGF.getPointerAlign());
5021
5022 // ...
5023 // *(Type<i>*)lhs[i] = RedOp<i>(*(Type<i>*)lhs[i], *(Type<i>*)rhs[i]);
5024 // ...
5026 const auto *IPriv = Privates.begin();
5027 unsigned Idx = 0;
5028 for (unsigned I = 0, E = ReductionOps.size(); I < E; ++I, ++IPriv, ++Idx) {
5029 const auto *RHSVar =
5030 cast<VarDecl>(cast<DeclRefExpr>(RHSExprs[I])->getDecl());
5031 Scope.addPrivate(RHSVar, emitAddrOfVarFromArray(CGF, RHS, Idx, RHSVar));
5032 const auto *LHSVar =
5033 cast<VarDecl>(cast<DeclRefExpr>(LHSExprs[I])->getDecl());
5034 Scope.addPrivate(LHSVar, emitAddrOfVarFromArray(CGF, LHS, Idx, LHSVar));
5035 QualType PrivTy = (*IPriv)->getType();
5036 if (PrivTy->isVariablyModifiedType()) {
5037 // Get array size and emit VLA type.
5038 ++Idx;
5039 Address Elem = CGF.Builder.CreateConstArrayGEP(LHS, Idx);
5040 llvm::Value *Ptr = CGF.Builder.CreateLoad(Elem);
5041 const VariableArrayType *VLA =
5042 CGF.getContext().getAsVariableArrayType(PrivTy);
5043 const auto *OVE = cast<OpaqueValueExpr>(VLA->getSizeExpr());
5045 CGF, OVE, RValue::get(CGF.Builder.CreatePtrToInt(Ptr, CGF.SizeTy)));
5046 CGF.EmitVariablyModifiedType(PrivTy);
5047 }
5048 }
5049 Scope.Privatize();
5050 IPriv = Privates.begin();
5051 const auto *ILHS = LHSExprs.begin();
5052 const auto *IRHS = RHSExprs.begin();
5053 for (const Expr *E : ReductionOps) {
5054 if ((*IPriv)->getType()->isArrayType()) {
5055 // Emit reduction for array section.
5056 const auto *LHSVar = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
5057 const auto *RHSVar = cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
5059 CGF, (*IPriv)->getType(), LHSVar, RHSVar,
5060 [=](CodeGenFunction &CGF, const Expr *, const Expr *, const Expr *) {
5061 emitReductionCombiner(CGF, E);
5062 });
5063 } else {
5064 // Emit reduction for array subscript or single variable.
5065 emitReductionCombiner(CGF, E);
5066 }
5067 ++IPriv;
5068 ++ILHS;
5069 ++IRHS;
5070 }
5071 Scope.ForceCleanup();
5072 CGF.FinishFunction();
5073 return Fn;
5074}
5075
5077 const Expr *ReductionOp,
5078 const Expr *PrivateRef,
5079 const DeclRefExpr *LHS,
5080 const DeclRefExpr *RHS) {
5081 if (PrivateRef->getType()->isArrayType()) {
5082 // Emit reduction for array section.
5083 const auto *LHSVar = cast<VarDecl>(LHS->getDecl());
5084 const auto *RHSVar = cast<VarDecl>(RHS->getDecl());
5086 CGF, PrivateRef->getType(), LHSVar, RHSVar,
5087 [=](CodeGenFunction &CGF, const Expr *, const Expr *, const Expr *) {
5088 emitReductionCombiner(CGF, ReductionOp);
5089 });
5090 } else {
5091 // Emit reduction for array subscript or single variable.
5092 emitReductionCombiner(CGF, ReductionOp);
5093 }
5094}
5095
5096static std::string generateUniqueName(CodeGenModule &CGM,
5097 llvm::StringRef Prefix, const Expr *Ref);
5098
5100 CodeGenFunction &CGF, SourceLocation Loc, const Expr *Privates,
5101 const Expr *LHSExprs, const Expr *RHSExprs, const Expr *ReductionOps) {
5102
5103 // Create a shared global variable (__shared_reduction_var) to accumulate the
5104 // final result.
5105 //
5106 // Call __kmpc_barrier to synchronize threads before initialization.
5107 //
5108 // The master thread (thread_id == 0) initializes __shared_reduction_var
5109 // with the identity value or initializer.
5110 //
5111 // Call __kmpc_barrier to synchronize before combining.
5112 // For each i:
5113 // - Thread enters critical section.
5114 // - Reads its private value from LHSExprs[i].
5115 // - Updates __shared_reduction_var[i] = RedOp_i(__shared_reduction_var[i],
5116 // Privates[i]).
5117 // - Exits critical section.
5118 //
5119 // Call __kmpc_barrier after combining.
5120 //
5121 // Each thread copies __shared_reduction_var[i] back to RHSExprs[i].
5122 //
5123 // Final __kmpc_barrier to synchronize after broadcasting
5124 QualType PrivateType = Privates->getType();
5125 llvm::Type *LLVMType = CGF.ConvertTypeForMem(PrivateType);
5126
5127 const OMPDeclareReductionDecl *UDR = getReductionInit(ReductionOps);
5128 std::string ReductionVarNameStr;
5129 if (const auto *DRE = dyn_cast<DeclRefExpr>(Privates->IgnoreParenCasts()))
5130 ReductionVarNameStr =
5131 generateUniqueName(CGM, DRE->getDecl()->getNameAsString(), Privates);
5132 else
5133 ReductionVarNameStr = "unnamed_priv_var";
5134
5135 // Create an internal shared variable
5136 std::string SharedName =
5137 CGM.getOpenMPRuntime().getName({"internal_pivate_", ReductionVarNameStr});
5138 llvm::GlobalVariable *SharedVar = OMPBuilder.getOrCreateInternalVariable(
5139 LLVMType, ".omp.reduction." + SharedName);
5140
5141 SharedVar->setAlignment(
5142 llvm::MaybeAlign(CGF.getContext().getTypeAlign(PrivateType) / 8));
5143
5144 Address SharedResult =
5145 CGF.MakeNaturalAlignRawAddrLValue(SharedVar, PrivateType).getAddress();
5146
5147 llvm::Value *ThreadId = getThreadID(CGF, Loc);
5148 llvm::Value *BarrierLoc = emitUpdateLocation(CGF, Loc, OMP_ATOMIC_REDUCE);
5149 llvm::Value *BarrierArgs[] = {BarrierLoc, ThreadId};
5150
5151 llvm::BasicBlock *InitBB = CGF.createBasicBlock("init");
5152 llvm::BasicBlock *InitEndBB = CGF.createBasicBlock("init.end");
5153
5154 llvm::Value *IsWorker = CGF.Builder.CreateICmpEQ(
5155 ThreadId, llvm::ConstantInt::get(ThreadId->getType(), 0));
5156 CGF.Builder.CreateCondBr(IsWorker, InitBB, InitEndBB);
5157
5158 CGF.EmitBlock(InitBB);
5159
5160 auto EmitSharedInit = [&]() {
5161 if (UDR) { // Check if it's a User-Defined Reduction
5162 if (const Expr *UDRInitExpr = UDR->getInitializer()) {
5163 std::pair<llvm::Function *, llvm::Function *> FnPair =
5165 llvm::Function *InitializerFn = FnPair.second;
5166 if (InitializerFn) {
5167 if (const auto *CE =
5168 dyn_cast<CallExpr>(UDRInitExpr->IgnoreParenImpCasts())) {
5169 const auto *OutDRE = cast<DeclRefExpr>(
5170 cast<UnaryOperator>(CE->getArg(0)->IgnoreParenImpCasts())
5171 ->getSubExpr());
5172 const VarDecl *OutVD = cast<VarDecl>(OutDRE->getDecl());
5173
5174 CodeGenFunction::OMPPrivateScope LocalScope(CGF);
5175 LocalScope.addPrivate(OutVD, SharedResult);
5176
5177 (void)LocalScope.Privatize();
5178 if (const auto *OVE = dyn_cast<OpaqueValueExpr>(
5179 CE->getCallee()->IgnoreParenImpCasts())) {
5181 CGF, OVE, RValue::get(InitializerFn));
5182 CGF.EmitIgnoredExpr(CE);
5183 } else {
5184 CGF.EmitAnyExprToMem(UDRInitExpr, SharedResult,
5185 PrivateType.getQualifiers(),
5186 /*IsInitializer=*/true);
5187 }
5188 } else {
5189 CGF.EmitAnyExprToMem(UDRInitExpr, SharedResult,
5190 PrivateType.getQualifiers(),
5191 /*IsInitializer=*/true);
5192 }
5193 } else {
5194 CGF.EmitAnyExprToMem(UDRInitExpr, SharedResult,
5195 PrivateType.getQualifiers(),
5196 /*IsInitializer=*/true);
5197 }
5198 } else {
5199 // EmitNullInitialization handles default construction for C++ classes
5200 // and zeroing for scalars, which is a reasonable default.
5201 CGF.EmitNullInitialization(SharedResult, PrivateType);
5202 }
5203 return; // UDR initialization handled
5204 }
5205 if (const auto *DRE = dyn_cast<DeclRefExpr>(Privates)) {
5206 if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
5207 if (const Expr *InitExpr = VD->getInit()) {
5208 CGF.EmitAnyExprToMem(InitExpr, SharedResult,
5209 PrivateType.getQualifiers(), true);
5210 return;
5211 }
5212 }
5213 }
5214 CGF.EmitNullInitialization(SharedResult, PrivateType);
5215 };
5216 EmitSharedInit();
5217 CGF.Builder.CreateBr(InitEndBB);
5218 CGF.EmitBlock(InitEndBB);
5219
5220 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
5221 CGM.getModule(), OMPRTL___kmpc_barrier),
5222 BarrierArgs);
5223
5224 const Expr *ReductionOp = ReductionOps;
5225 const OMPDeclareReductionDecl *CurrentUDR = getReductionInit(ReductionOp);
5226 LValue SharedLV = CGF.MakeAddrLValue(SharedResult, PrivateType);
5227 LValue LHSLV = CGF.EmitLValue(Privates);
5228
5229 auto EmitCriticalReduction = [&](auto ReductionGen) {
5230 std::string CriticalName = getName({"reduction_critical"});
5231 emitCriticalRegion(CGF, CriticalName, ReductionGen, Loc);
5232 };
5233
5234 if (CurrentUDR) {
5235 // Handle user-defined reduction.
5236 auto ReductionGen = [&](CodeGenFunction &CGF, PrePostActionTy &Action) {
5237 Action.Enter(CGF);
5238 std::pair<llvm::Function *, llvm::Function *> FnPair =
5239 getUserDefinedReduction(CurrentUDR);
5240 if (FnPair.first) {
5241 if (const auto *CE = dyn_cast<CallExpr>(ReductionOp)) {
5242 const auto *OutDRE = cast<DeclRefExpr>(
5243 cast<UnaryOperator>(CE->getArg(0)->IgnoreParenImpCasts())
5244 ->getSubExpr());
5245 const auto *InDRE = cast<DeclRefExpr>(
5246 cast<UnaryOperator>(CE->getArg(1)->IgnoreParenImpCasts())
5247 ->getSubExpr());
5248 CodeGenFunction::OMPPrivateScope LocalScope(CGF);
5249 LocalScope.addPrivate(cast<VarDecl>(OutDRE->getDecl()),
5250 SharedLV.getAddress());
5251 LocalScope.addPrivate(cast<VarDecl>(InDRE->getDecl()),
5252 LHSLV.getAddress());
5253 (void)LocalScope.Privatize();
5254 emitReductionCombiner(CGF, ReductionOp);
5255 }
5256 }
5257 };
5258 EmitCriticalReduction(ReductionGen);
5259 } else {
5260 // Handle built-in reduction operations.
5261#ifndef NDEBUG
5262 const Expr *ReductionClauseExpr = ReductionOp->IgnoreParenCasts();
5263 if (const auto *Cleanup = dyn_cast<ExprWithCleanups>(ReductionClauseExpr))
5264 ReductionClauseExpr = Cleanup->getSubExpr()->IgnoreParenCasts();
5265
5266 const Expr *AssignRHS = nullptr;
5267 if (const auto *BinOp = dyn_cast<BinaryOperator>(ReductionClauseExpr)) {
5268 if (BinOp->getOpcode() == BO_Assign)
5269 AssignRHS = BinOp->getRHS();
5270 } else if (const auto *OpCall =
5271 dyn_cast<CXXOperatorCallExpr>(ReductionClauseExpr)) {
5272 if (OpCall->getOperator() == OO_Equal)
5273 AssignRHS = OpCall->getArg(1);
5274 }
5275
5276 assert(AssignRHS &&
5277 "Private Variable Reduction : Invalid ReductionOp expression");
5278#endif
5279
5280 auto ReductionGen = [&](CodeGenFunction &CGF, PrePostActionTy &Action) {
5281 Action.Enter(CGF);
5282 const auto *OmpOutDRE =
5283 dyn_cast<DeclRefExpr>(LHSExprs->IgnoreParenImpCasts());
5284 const auto *OmpInDRE =
5285 dyn_cast<DeclRefExpr>(RHSExprs->IgnoreParenImpCasts());
5286 assert(
5287 OmpOutDRE && OmpInDRE &&
5288 "Private Variable Reduction : LHSExpr/RHSExpr must be DeclRefExprs");
5289 const VarDecl *OmpOutVD = cast<VarDecl>(OmpOutDRE->getDecl());
5290 const VarDecl *OmpInVD = cast<VarDecl>(OmpInDRE->getDecl());
5291 CodeGenFunction::OMPPrivateScope LocalScope(CGF);
5292 LocalScope.addPrivate(OmpOutVD, SharedLV.getAddress());
5293 LocalScope.addPrivate(OmpInVD, LHSLV.getAddress());
5294 (void)LocalScope.Privatize();
5295 // Emit the actual reduction operation
5296 CGF.EmitIgnoredExpr(ReductionOp);
5297 };
5298 EmitCriticalReduction(ReductionGen);
5299 }
5300
5301 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
5302 CGM.getModule(), OMPRTL___kmpc_barrier),
5303 BarrierArgs);
5304
5305 // Broadcast final result
5306 bool IsAggregate = PrivateType->isAggregateType();
5307 LValue SharedLV1 = CGF.MakeAddrLValue(SharedResult, PrivateType);
5308 llvm::Value *FinalResultVal = nullptr;
5309 Address FinalResultAddr = Address::invalid();
5310
5311 if (IsAggregate)
5312 FinalResultAddr = SharedResult;
5313 else
5314 FinalResultVal = CGF.EmitLoadOfScalar(SharedLV1, Loc);
5315
5316 LValue TargetLHSLV = CGF.EmitLValue(RHSExprs);
5317 if (IsAggregate) {
5318 CGF.EmitAggregateCopy(TargetLHSLV,
5319 CGF.MakeAddrLValue(FinalResultAddr, PrivateType),
5320 PrivateType, AggValueSlot::DoesNotOverlap, false);
5321 } else {
5322 CGF.EmitStoreOfScalar(FinalResultVal, TargetLHSLV);
5323 }
5324 // Final synchronization barrier
5325 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
5326 CGM.getModule(), OMPRTL___kmpc_barrier),
5327 BarrierArgs);
5328
5329 // Combiner with original list item
5330 auto OriginalListCombiner = [&](CodeGenFunction &CGF,
5331 PrePostActionTy &Action) {
5332 Action.Enter(CGF);
5333 emitSingleReductionCombiner(CGF, ReductionOps, Privates,
5334 cast<DeclRefExpr>(LHSExprs),
5335 cast<DeclRefExpr>(RHSExprs));
5336 };
5337 EmitCriticalReduction(OriginalListCombiner);
5338}
5339
5341 ArrayRef<const Expr *> OrgPrivates,
5342 ArrayRef<const Expr *> OrgLHSExprs,
5343 ArrayRef<const Expr *> OrgRHSExprs,
5344 ArrayRef<const Expr *> OrgReductionOps,
5345 ReductionOptionsTy Options) {
5346 if (!CGF.HaveInsertPoint())
5347 return;
5348
5349 bool WithNowait = Options.WithNowait;
5350 bool SimpleReduction = Options.SimpleReduction;
5351
5352 // Next code should be emitted for reduction:
5353 //
5354 // static kmp_critical_name lock = { 0 };
5355 //
5356 // void reduce_func(void *lhs[<n>], void *rhs[<n>]) {
5357 // *(Type0*)lhs[0] = ReductionOperation0(*(Type0*)lhs[0], *(Type0*)rhs[0]);
5358 // ...
5359 // *(Type<n>-1*)lhs[<n>-1] = ReductionOperation<n>-1(*(Type<n>-1*)lhs[<n>-1],
5360 // *(Type<n>-1*)rhs[<n>-1]);
5361 // }
5362 //
5363 // ...
5364 // void *RedList[<n>] = {&<RHSExprs>[0], ..., &<RHSExprs>[<n>-1]};
5365 // switch (__kmpc_reduce{_nowait}(<loc>, <gtid>, <n>, sizeof(RedList),
5366 // RedList, reduce_func, &<lock>)) {
5367 // case 1:
5368 // ...
5369 // <LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]);
5370 // ...
5371 // __kmpc_end_reduce{_nowait}(<loc>, <gtid>, &<lock>);
5372 // break;
5373 // case 2:
5374 // ...
5375 // Atomic(<LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]));
5376 // ...
5377 // [__kmpc_end_reduce(<loc>, <gtid>, &<lock>);]
5378 // break;
5379 // default:;
5380 // }
5381 //
5382 // if SimpleReduction is true, only the next code is generated:
5383 // ...
5384 // <LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]);
5385 // ...
5386
5387 ASTContext &C = CGM.getContext();
5388
5389 if (SimpleReduction) {
5391 const auto *IPriv = OrgPrivates.begin();
5392 const auto *ILHS = OrgLHSExprs.begin();
5393 const auto *IRHS = OrgRHSExprs.begin();
5394 for (const Expr *E : OrgReductionOps) {
5395 emitSingleReductionCombiner(CGF, E, *IPriv, cast<DeclRefExpr>(*ILHS),
5396 cast<DeclRefExpr>(*IRHS));
5397 ++IPriv;
5398 ++ILHS;
5399 ++IRHS;
5400 }
5401 return;
5402 }
5403
5404 // Filter out shared reduction variables based on IsPrivateVarReduction flag.
5405 // Only keep entries where the corresponding variable is not private.
5406 SmallVector<const Expr *> FilteredPrivates, FilteredLHSExprs,
5407 FilteredRHSExprs, FilteredReductionOps;
5408 for (unsigned I : llvm::seq<unsigned>(
5409 std::min(OrgReductionOps.size(), OrgLHSExprs.size()))) {
5410 if (!Options.IsPrivateVarReduction[I]) {
5411 FilteredPrivates.emplace_back(OrgPrivates[I]);
5412 FilteredLHSExprs.emplace_back(OrgLHSExprs[I]);
5413 FilteredRHSExprs.emplace_back(OrgRHSExprs[I]);
5414 FilteredReductionOps.emplace_back(OrgReductionOps[I]);
5415 }
5416 }
5417 // Wrap filtered vectors in ArrayRef for downstream shared reduction
5418 // processing.
5419 ArrayRef<const Expr *> Privates = FilteredPrivates;
5420 ArrayRef<const Expr *> LHSExprs = FilteredLHSExprs;
5421 ArrayRef<const Expr *> RHSExprs = FilteredRHSExprs;
5422 ArrayRef<const Expr *> ReductionOps = FilteredReductionOps;
5423
5424 // 1. Build a list of reduction variables.
5425 // void *RedList[<n>] = {<ReductionVars>[0], ..., <ReductionVars>[<n>-1]};
5426 auto Size = RHSExprs.size();
5427 for (const Expr *E : Privates) {
5428 if (E->getType()->isVariablyModifiedType())
5429 // Reserve place for array size.
5430 ++Size;
5431 }
5432 llvm::APInt ArraySize(/*unsigned int numBits=*/32, Size);
5433 QualType ReductionArrayTy = C.getConstantArrayType(
5434 C.VoidPtrTy, ArraySize, nullptr, ArraySizeModifier::Normal,
5435 /*IndexTypeQuals=*/0);
5436 RawAddress ReductionList =
5437 CGF.CreateMemTemp(ReductionArrayTy, ".omp.reduction.red_list");
5438 const auto *IPriv = Privates.begin();
5439 unsigned Idx = 0;
5440 for (unsigned I = 0, E = RHSExprs.size(); I < E; ++I, ++IPriv, ++Idx) {
5441 Address Elem = CGF.Builder.CreateConstArrayGEP(ReductionList, Idx);
5442 CGF.Builder.CreateStore(
5444 CGF.EmitLValue(RHSExprs[I]).getPointer(CGF), CGF.VoidPtrTy),
5445 Elem);
5446 if ((*IPriv)->getType()->isVariablyModifiedType()) {
5447 // Store array size.
5448 ++Idx;
5449 Elem = CGF.Builder.CreateConstArrayGEP(ReductionList, Idx);
5450 llvm::Value *Size = CGF.Builder.CreateIntCast(
5451 CGF.getVLASize(
5452 CGF.getContext().getAsVariableArrayType((*IPriv)->getType()))
5453 .NumElts,
5454 CGF.SizeTy, /*isSigned=*/false);
5455 CGF.Builder.CreateStore(CGF.Builder.CreateIntToPtr(Size, CGF.VoidPtrTy),
5456 Elem);
5457 }
5458 }
5459
5460 // 2. Emit reduce_func().
5461 llvm::Function *ReductionFn = emitReductionFunction(
5462 CGF.CurFn->getName(), Loc, CGF.ConvertTypeForMem(ReductionArrayTy),
5463 Privates, LHSExprs, RHSExprs, ReductionOps);
5464
5465 // 3. Create static kmp_critical_name lock = { 0 };
5466 std::string Name = getName({"reduction"});
5467 llvm::Value *Lock = getCriticalRegionLock(Name);
5468
5469 // 4. Build res = __kmpc_reduce{_nowait}(<loc>, <gtid>, <n>, sizeof(RedList),
5470 // RedList, reduce_func, &<lock>);
5471 llvm::Value *IdentTLoc = emitUpdateLocation(CGF, Loc, OMP_ATOMIC_REDUCE);
5472 llvm::Value *ThreadId = getThreadID(CGF, Loc);
5473 llvm::Value *ReductionArrayTySize = CGF.getTypeSize(ReductionArrayTy);
5474 llvm::Value *RL = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
5475 ReductionList.getPointer(), CGF.VoidPtrTy);
5476 llvm::Value *Args[] = {
5477 IdentTLoc, // ident_t *<loc>
5478 ThreadId, // i32 <gtid>
5479 CGF.Builder.getInt32(RHSExprs.size()), // i32 <n>
5480 ReductionArrayTySize, // size_type sizeof(RedList)
5481 RL, // void *RedList
5482 ReductionFn, // void (*) (void *, void *) <reduce_func>
5483 Lock // kmp_critical_name *&<lock>
5484 };
5485 llvm::Value *Res = CGF.EmitRuntimeCall(
5486 OMPBuilder.getOrCreateRuntimeFunction(
5487 CGM.getModule(),
5488 WithNowait ? OMPRTL___kmpc_reduce_nowait : OMPRTL___kmpc_reduce),
5489 Args);
5490
5491 // 5. Build switch(res)
5492 llvm::BasicBlock *DefaultBB = CGF.createBasicBlock(".omp.reduction.default");
5493 llvm::SwitchInst *SwInst =
5494 CGF.Builder.CreateSwitch(Res, DefaultBB, /*NumCases=*/2);
5495
5496 // 6. Build case 1:
5497 // ...
5498 // <LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]);
5499 // ...
5500 // __kmpc_end_reduce{_nowait}(<loc>, <gtid>, &<lock>);
5501 // break;
5502 llvm::BasicBlock *Case1BB = CGF.createBasicBlock(".omp.reduction.case1");
5503 SwInst->addCase(CGF.Builder.getInt32(1), Case1BB);
5504 CGF.EmitBlock(Case1BB);
5505
5506 // Add emission of __kmpc_end_reduce{_nowait}(<loc>, <gtid>, &<lock>);
5507 llvm::Value *EndArgs[] = {
5508 IdentTLoc, // ident_t *<loc>
5509 ThreadId, // i32 <gtid>
5510 Lock // kmp_critical_name *&<lock>
5511 };
5512 auto &&CodeGen = [Privates, LHSExprs, RHSExprs, ReductionOps](
5513 CodeGenFunction &CGF, PrePostActionTy &Action) {
5515 const auto *IPriv = Privates.begin();
5516 const auto *ILHS = LHSExprs.begin();
5517 const auto *IRHS = RHSExprs.begin();
5518 for (const Expr *E : ReductionOps) {
5519 RT.emitSingleReductionCombiner(CGF, E, *IPriv, cast<DeclRefExpr>(*ILHS),
5520 cast<DeclRefExpr>(*IRHS));
5521 ++IPriv;
5522 ++ILHS;
5523 ++IRHS;
5524 }
5525 };
5527 CommonActionTy Action(
5528 nullptr, {},
5529 OMPBuilder.getOrCreateRuntimeFunction(
5530 CGM.getModule(), WithNowait ? OMPRTL___kmpc_end_reduce_nowait
5531 : OMPRTL___kmpc_end_reduce),
5532 EndArgs);
5533 RCG.setAction(Action);
5534 RCG(CGF);
5535
5536 CGF.EmitBranch(DefaultBB);
5537
5538 // 7. Build case 2:
5539 // ...
5540 // Atomic(<LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]));
5541 // ...
5542 // break;
5543 llvm::BasicBlock *Case2BB = CGF.createBasicBlock(".omp.reduction.case2");
5544 SwInst->addCase(CGF.Builder.getInt32(2), Case2BB);
5545 CGF.EmitBlock(Case2BB);
5546
5547 auto &&AtomicCodeGen = [Loc, Privates, LHSExprs, RHSExprs, ReductionOps](
5548 CodeGenFunction &CGF, PrePostActionTy &Action) {
5549 const auto *ILHS = LHSExprs.begin();
5550 const auto *IRHS = RHSExprs.begin();
5551 const auto *IPriv = Privates.begin();
5552 for (const Expr *E : ReductionOps) {
5553 const Expr *XExpr = nullptr;
5554 const Expr *EExpr = nullptr;
5555 const Expr *UpExpr = nullptr;
5556 BinaryOperatorKind BO = BO_Comma;
5557 if (const auto *BO = dyn_cast<BinaryOperator>(E)) {
5558 if (BO->getOpcode() == BO_Assign) {
5559 XExpr = BO->getLHS();
5560 UpExpr = BO->getRHS();
5561 }
5562 }
5563 // Try to emit update expression as a simple atomic.
5564 const Expr *RHSExpr = UpExpr;
5565 if (RHSExpr) {
5566 // Analyze RHS part of the whole expression.
5567 if (const auto *ACO = dyn_cast<AbstractConditionalOperator>(
5568 RHSExpr->IgnoreParenImpCasts())) {
5569 // If this is a conditional operator, analyze its condition for
5570 // min/max reduction operator.
5571 RHSExpr = ACO->getCond();
5572 }
5573 if (const auto *BORHS =
5574 dyn_cast<BinaryOperator>(RHSExpr->IgnoreParenImpCasts())) {
5575 EExpr = BORHS->getRHS();
5576 BO = BORHS->getOpcode();
5577 }
5578 }
5579 if (XExpr) {
5580 const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
5581 auto &&AtomicRedGen = [BO, VD,
5582 Loc](CodeGenFunction &CGF, const Expr *XExpr,
5583 const Expr *EExpr, const Expr *UpExpr) {
5584 LValue X = CGF.EmitLValue(XExpr);
5585 RValue E;
5586 if (EExpr)
5587 E = CGF.EmitAnyExpr(EExpr);
5588 CGF.EmitOMPAtomicSimpleUpdateExpr(
5589 X, E, BO, /*IsXLHSInRHSPart=*/true,
5590 llvm::AtomicOrdering::Monotonic, Loc,
5591 [&CGF, UpExpr, VD, Loc](RValue XRValue) {
5592 CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
5593 Address LHSTemp = CGF.CreateMemTemp(VD->getType());
5594 CGF.emitOMPSimpleStore(
5595 CGF.MakeAddrLValue(LHSTemp, VD->getType()), XRValue,
5596 VD->getType().getNonReferenceType(), Loc);
5597 PrivateScope.addPrivate(VD, LHSTemp);
5598 (void)PrivateScope.Privatize();
5599 return CGF.EmitAnyExpr(UpExpr);
5600 });
5601 };
5602 if ((*IPriv)->getType()->isArrayType()) {
5603 // Emit atomic reduction for array section.
5604 const auto *RHSVar =
5605 cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
5606 EmitOMPAggregateReduction(CGF, (*IPriv)->getType(), VD, RHSVar,
5607 AtomicRedGen, XExpr, EExpr, UpExpr);
5608 } else {
5609 // Emit atomic reduction for array subscript or single variable.
5610 AtomicRedGen(CGF, XExpr, EExpr, UpExpr);
5611 }
5612 } else {
5613 // Emit as a critical region.
5614 auto &&CritRedGen = [E, Loc](CodeGenFunction &CGF, const Expr *,
5615 const Expr *, const Expr *) {
5616 CGOpenMPRuntime &RT = CGF.CGM.getOpenMPRuntime();
5617 std::string Name = RT.getName({"atomic_reduction"});
5619 CGF, Name,
5620 [=](CodeGenFunction &CGF, PrePostActionTy &Action) {
5621 Action.Enter(CGF);
5622 emitReductionCombiner(CGF, E);
5623 },
5624 Loc);
5625 };
5626 if ((*IPriv)->getType()->isArrayType()) {
5627 const auto *LHSVar =
5628 cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
5629 const auto *RHSVar =
5630 cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
5631 EmitOMPAggregateReduction(CGF, (*IPriv)->getType(), LHSVar, RHSVar,
5632 CritRedGen);
5633 } else {
5634 CritRedGen(CGF, nullptr, nullptr, nullptr);
5635 }
5636 }
5637 ++ILHS;
5638 ++IRHS;
5639 ++IPriv;
5640 }
5641 };
5642 RegionCodeGenTy AtomicRCG(AtomicCodeGen);
5643 if (!WithNowait) {
5644 // Add emission of __kmpc_end_reduce(<loc>, <gtid>, &<lock>);
5645 llvm::Value *EndArgs[] = {
5646 IdentTLoc, // ident_t *<loc>
5647 ThreadId, // i32 <gtid>
5648 Lock // kmp_critical_name *&<lock>
5649 };
5650 CommonActionTy Action(nullptr, {},
5651 OMPBuilder.getOrCreateRuntimeFunction(
5652 CGM.getModule(), OMPRTL___kmpc_end_reduce),
5653 EndArgs);
5654 AtomicRCG.setAction(Action);
5655 AtomicRCG(CGF);
5656 } else {
5657 AtomicRCG(CGF);
5658 }
5659
5660 CGF.EmitBranch(DefaultBB);
5661 CGF.EmitBlock(DefaultBB, /*IsFinished=*/true);
5662 assert(OrgLHSExprs.size() == OrgPrivates.size() &&
5663 "PrivateVarReduction: Privates size mismatch");
5664 assert(OrgLHSExprs.size() == OrgReductionOps.size() &&
5665 "PrivateVarReduction: ReductionOps size mismatch");
5666 for (unsigned I : llvm::seq<unsigned>(
5667 std::min(OrgReductionOps.size(), OrgLHSExprs.size()))) {
5668 if (Options.IsPrivateVarReduction[I])
5669 emitPrivateReduction(CGF, Loc, OrgPrivates[I], OrgLHSExprs[I],
5670 OrgRHSExprs[I], OrgReductionOps[I]);
5671 }
5672}
5673
5674/// Generates unique name for artificial threadprivate variables.
5675/// Format is: <Prefix> "." <Decl_mangled_name> "_" "<Decl_start_loc_raw_enc>"
5676static std::string generateUniqueName(CodeGenModule &CGM, StringRef Prefix,
5677 const Expr *Ref) {
5678 SmallString<256> Buffer;
5679 llvm::raw_svector_ostream Out(Buffer);
5680 const clang::DeclRefExpr *DE;
5681 const VarDecl *D = ::getBaseDecl(Ref, DE);
5682 if (!D)
5683 D = cast<VarDecl>(cast<DeclRefExpr>(Ref)->getDecl());
5684 D = D->getCanonicalDecl();
5685 std::string Name = CGM.getOpenMPRuntime().getName(
5686 {D->isLocalVarDeclOrParm() ? D->getName() : CGM.getMangledName(D)});
5687 Out << Prefix << Name << "_"
5689 return std::string(Out.str());
5690}
5691
5692/// Emits reduction initializer function:
5693/// \code
5694/// void @.red_init(void* %arg, void* %orig) {
5695/// %0 = bitcast void* %arg to <type>*
5696/// store <type> <init>, <type>* %0
5697/// ret void
5698/// }
5699/// \endcode
5700static llvm::Value *emitReduceInitFunction(CodeGenModule &CGM,
5701 SourceLocation Loc,
5702 ReductionCodeGen &RCG, unsigned N) {
5703 ASTContext &C = CGM.getContext();
5704 QualType VoidPtrTy = C.VoidPtrTy;
5705 VoidPtrTy.addRestrict();
5706 FunctionArgList Args;
5707 auto *Param =
5708 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
5709 VoidPtrTy, ImplicitParamKind::Other);
5710 auto *ParamOrig =
5711 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
5712 VoidPtrTy, ImplicitParamKind::Other);
5713 Args.emplace_back(Param);
5714 Args.emplace_back(ParamOrig);
5715 const auto &FnInfo =
5716 CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
5717 llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
5718 std::string Name = CGM.getOpenMPRuntime().getName({"red_init", ""});
5719 auto *Fn = llvm::Function::Create(FnTy, llvm::GlobalValue::InternalLinkage,
5720 Name, &CGM.getModule());
5721 CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FnInfo);
5722 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
5723 Fn->addFnAttr("sample-profile-suffix-elision-policy", "selected");
5724 Fn->setDoesNotRecurse();
5725 CodeGenFunction CGF(CGM);
5726 CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, FnInfo, Args, Loc, Loc);
5727 QualType PrivateType = RCG.getPrivateType(N);
5728 Address PrivateAddr = CGF.EmitLoadOfPointer(
5729 CGF.GetAddrOfLocalVar(Param).withElementType(CGF.Builder.getPtrTy(0)),
5730 C.getPointerType(PrivateType)->castAs<PointerType>());
5731 llvm::Value *Size = nullptr;
5732 // If the size of the reduction item is non-constant, load it from global
5733 // threadprivate variable.
5734 if (RCG.getSizes(N).second) {
5736 CGF, CGM.getContext().getSizeType(),
5737 generateUniqueName(CGM, "reduction_size", RCG.getRefExpr(N)));
5738 Size = CGF.EmitLoadOfScalar(SizeAddr, /*Volatile=*/false,
5739 CGM.getContext().getSizeType(), Loc);
5740 }
5741 RCG.emitAggregateType(CGF, N, Size);
5742 Address OrigAddr = Address::invalid();
5743 // If initializer uses initializer from declare reduction construct, emit a
5744 // pointer to the address of the original reduction item (reuired by reduction
5745 // initializer)
5746 if (RCG.usesReductionInitializer(N)) {
5747 Address SharedAddr = CGF.GetAddrOfLocalVar(ParamOrig);
5748 OrigAddr = CGF.EmitLoadOfPointer(
5749 SharedAddr,
5750 CGM.getContext().VoidPtrTy.castAs<PointerType>()->getTypePtr());
5751 }
5752 // Emit the initializer:
5753 // %0 = bitcast void* %arg to <type>*
5754 // store <type> <init>, <type>* %0
5755 RCG.emitInitialization(CGF, N, PrivateAddr, OrigAddr,
5756 [](CodeGenFunction &) { return false; });
5757 CGF.FinishFunction();
5758 return Fn;
5759}
5760
5761/// Emits reduction combiner function:
5762/// \code
5763/// void @.red_comb(void* %arg0, void* %arg1) {
5764/// %lhs = bitcast void* %arg0 to <type>*
5765/// %rhs = bitcast void* %arg1 to <type>*
5766/// %2 = <ReductionOp>(<type>* %lhs, <type>* %rhs)
5767/// store <type> %2, <type>* %lhs
5768/// ret void
5769/// }
5770/// \endcode
5771static llvm::Value *emitReduceCombFunction(CodeGenModule &CGM,
5772 SourceLocation Loc,
5773 ReductionCodeGen &RCG, unsigned N,
5774 const Expr *ReductionOp,
5775 const Expr *LHS, const Expr *RHS,
5776 const Expr *PrivateRef) {
5777 ASTContext &C = CGM.getContext();
5778 const auto *LHSVD = cast<VarDecl>(cast<DeclRefExpr>(LHS)->getDecl());
5779 const auto *RHSVD = cast<VarDecl>(cast<DeclRefExpr>(RHS)->getDecl());
5780 FunctionArgList Args;
5781 auto *ParamInOut =
5782 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
5783 C.VoidPtrTy, ImplicitParamKind::Other);
5784 auto *ParamIn =
5785 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
5786 C.VoidPtrTy, ImplicitParamKind::Other);
5787 Args.emplace_back(ParamInOut);
5788 Args.emplace_back(ParamIn);
5789 const auto &FnInfo =
5790 CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
5791 llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
5792 std::string Name = CGM.getOpenMPRuntime().getName({"red_comb", ""});
5793 auto *Fn = llvm::Function::Create(FnTy, llvm::GlobalValue::InternalLinkage,
5794 Name, &CGM.getModule());
5795 CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FnInfo);
5796 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
5797 Fn->addFnAttr("sample-profile-suffix-elision-policy", "selected");
5798 Fn->setDoesNotRecurse();
5799 CodeGenFunction CGF(CGM);
5800 CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, FnInfo, Args, Loc, Loc);
5801 llvm::Value *Size = nullptr;
5802 // If the size of the reduction item is non-constant, load it from global
5803 // threadprivate variable.
5804 if (RCG.getSizes(N).second) {
5806 CGF, CGM.getContext().getSizeType(),
5807 generateUniqueName(CGM, "reduction_size", RCG.getRefExpr(N)));
5808 Size = CGF.EmitLoadOfScalar(SizeAddr, /*Volatile=*/false,
5809 CGM.getContext().getSizeType(), Loc);
5810 }
5811 RCG.emitAggregateType(CGF, N, Size);
5812 // Remap lhs and rhs variables to the addresses of the function arguments.
5813 // %lhs = bitcast void* %arg0 to <type>*
5814 // %rhs = bitcast void* %arg1 to <type>*
5815 CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
5816 PrivateScope.addPrivate(
5817 LHSVD,
5818 // Pull out the pointer to the variable.
5820 CGF.GetAddrOfLocalVar(ParamInOut)
5821 .withElementType(CGF.Builder.getPtrTy(0)),
5822 C.getPointerType(LHSVD->getType())->castAs<PointerType>()));
5823 PrivateScope.addPrivate(
5824 RHSVD,
5825 // Pull out the pointer to the variable.
5828 CGF.Builder.getPtrTy(0)),
5829 C.getPointerType(RHSVD->getType())->castAs<PointerType>()));
5830 PrivateScope.Privatize();
5831 // Emit the combiner body:
5832 // %2 = <ReductionOp>(<type> *%lhs, <type> *%rhs)
5833 // store <type> %2, <type>* %lhs
5835 CGF, ReductionOp, PrivateRef, cast<DeclRefExpr>(LHS),
5836 cast<DeclRefExpr>(RHS));
5837 CGF.FinishFunction();
5838 return Fn;
5839}
5840
5841/// Emits reduction finalizer function:
5842/// \code
5843/// void @.red_fini(void* %arg) {
5844/// %0 = bitcast void* %arg to <type>*
5845/// <destroy>(<type>* %0)
5846/// ret void
5847/// }
5848/// \endcode
5849static llvm::Value *emitReduceFiniFunction(CodeGenModule &CGM,
5850 SourceLocation Loc,
5851 ReductionCodeGen &RCG, unsigned N) {
5852 if (!RCG.needCleanups(N))
5853 return nullptr;
5854 ASTContext &C = CGM.getContext();
5855 FunctionArgList Args;
5856 auto *Param =
5857 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
5858 C.VoidPtrTy, ImplicitParamKind::Other);
5859 Args.emplace_back(Param);
5860 const auto &FnInfo =
5861 CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
5862 llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
5863 std::string Name = CGM.getOpenMPRuntime().getName({"red_fini", ""});
5864 auto *Fn = llvm::Function::Create(FnTy, llvm::GlobalValue::InternalLinkage,
5865 Name, &CGM.getModule());
5866 CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FnInfo);
5867 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
5868 Fn->addFnAttr("sample-profile-suffix-elision-policy", "selected");
5869 Fn->setDoesNotRecurse();
5870 CodeGenFunction CGF(CGM);
5871 CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, FnInfo, Args, Loc, Loc);
5872 Address PrivateAddr = CGF.EmitLoadOfPointer(
5873 CGF.GetAddrOfLocalVar(Param), C.VoidPtrTy.castAs<PointerType>());
5874 llvm::Value *Size = nullptr;
5875 // If the size of the reduction item is non-constant, load it from global
5876 // threadprivate variable.
5877 if (RCG.getSizes(N).second) {
5879 CGF, CGM.getContext().getSizeType(),
5880 generateUniqueName(CGM, "reduction_size", RCG.getRefExpr(N)));
5881 Size = CGF.EmitLoadOfScalar(SizeAddr, /*Volatile=*/false,
5882 CGM.getContext().getSizeType(), Loc);
5883 }
5884 RCG.emitAggregateType(CGF, N, Size);
5885 // Emit the finalizer body:
5886 // <destroy>(<type>* %0)
5887 RCG.emitCleanups(CGF, N, PrivateAddr);
5888 CGF.FinishFunction(Loc);
5889 return Fn;
5890}
5891
5894 ArrayRef<const Expr *> RHSExprs, const OMPTaskDataTy &Data) {
5895 if (!CGF.HaveInsertPoint() || Data.ReductionVars.empty())
5896 return nullptr;
5897
5898 // Build typedef struct:
5899 // kmp_taskred_input {
5900 // void *reduce_shar; // shared reduction item
5901 // void *reduce_orig; // original reduction item used for initialization
5902 // size_t reduce_size; // size of data item
5903 // void *reduce_init; // data initialization routine
5904 // void *reduce_fini; // data finalization routine
5905 // void *reduce_comb; // data combiner routine
5906 // kmp_task_red_flags_t flags; // flags for additional info from compiler
5907 // } kmp_taskred_input_t;
5908 ASTContext &C = CGM.getContext();
5909 RecordDecl *RD = C.buildImplicitRecord("kmp_taskred_input_t");
5910 RD->startDefinition();
5911 const FieldDecl *SharedFD = addFieldToRecordDecl(C, RD, C.VoidPtrTy);
5912 const FieldDecl *OrigFD = addFieldToRecordDecl(C, RD, C.VoidPtrTy);
5913 const FieldDecl *SizeFD = addFieldToRecordDecl(C, RD, C.getSizeType());
5914 const FieldDecl *InitFD = addFieldToRecordDecl(C, RD, C.VoidPtrTy);
5915 const FieldDecl *FiniFD = addFieldToRecordDecl(C, RD, C.VoidPtrTy);
5916 const FieldDecl *CombFD = addFieldToRecordDecl(C, RD, C.VoidPtrTy);
5917 const FieldDecl *FlagsFD = addFieldToRecordDecl(
5918 C, RD, C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/false));
5919 RD->completeDefinition();
5920 CanQualType RDType = C.getCanonicalTagType(RD);
5921 unsigned Size = Data.ReductionVars.size();
5922 llvm::APInt ArraySize(/*numBits=*/64, Size);
5923 QualType ArrayRDType =
5924 C.getConstantArrayType(RDType, ArraySize, nullptr,
5925 ArraySizeModifier::Normal, /*IndexTypeQuals=*/0);
5926 // kmp_task_red_input_t .rd_input.[Size];
5927 RawAddress TaskRedInput = CGF.CreateMemTemp(ArrayRDType, ".rd_input.");
5928 ReductionCodeGen RCG(Data.ReductionVars, Data.ReductionOrigs,
5929 Data.ReductionCopies, Data.ReductionOps);
5930 for (unsigned Cnt = 0; Cnt < Size; ++Cnt) {
5931 // kmp_task_red_input_t &ElemLVal = .rd_input.[Cnt];
5932 llvm::Value *Idxs[] = {llvm::ConstantInt::get(CGM.SizeTy, /*V=*/0),
5933 llvm::ConstantInt::get(CGM.SizeTy, Cnt)};
5934 llvm::Value *GEP = CGF.EmitCheckedInBoundsGEP(
5935 TaskRedInput.getElementType(), TaskRedInput.getPointer(), Idxs,
5936 /*SignedIndices=*/false, /*IsSubtraction=*/false, Loc,
5937 ".rd_input.gep.");
5938 LValue ElemLVal = CGF.MakeNaturalAlignRawAddrLValue(GEP, RDType);
5939 // ElemLVal.reduce_shar = &Shareds[Cnt];
5940 LValue SharedLVal = CGF.EmitLValueForField(ElemLVal, SharedFD);
5941 RCG.emitSharedOrigLValue(CGF, Cnt);
5942 llvm::Value *Shared = RCG.getSharedLValue(Cnt).getPointer(CGF);
5943 CGF.EmitStoreOfScalar(Shared, SharedLVal);
5944 // ElemLVal.reduce_orig = &Origs[Cnt];
5945 LValue OrigLVal = CGF.EmitLValueForField(ElemLVal, OrigFD);
5946 llvm::Value *Orig = RCG.getOrigLValue(Cnt).getPointer(CGF);
5947 CGF.EmitStoreOfScalar(Orig, OrigLVal);
5948 RCG.emitAggregateType(CGF, Cnt);
5949 llvm::Value *SizeValInChars;
5950 llvm::Value *SizeVal;
5951 std::tie(SizeValInChars, SizeVal) = RCG.getSizes(Cnt);
5952 // We use delayed creation/initialization for VLAs and array sections. It is
5953 // required because runtime does not provide the way to pass the sizes of
5954 // VLAs/array sections to initializer/combiner/finalizer functions. Instead
5955 // threadprivate global variables are used to store these values and use
5956 // them in the functions.
5957 bool DelayedCreation = !!SizeVal;
5958 SizeValInChars = CGF.Builder.CreateIntCast(SizeValInChars, CGM.SizeTy,
5959 /*isSigned=*/false);
5960 LValue SizeLVal = CGF.EmitLValueForField(ElemLVal, SizeFD);
5961 CGF.EmitStoreOfScalar(SizeValInChars, SizeLVal);
5962 // ElemLVal.reduce_init = init;
5963 LValue InitLVal = CGF.EmitLValueForField(ElemLVal, InitFD);
5964 llvm::Value *InitAddr = emitReduceInitFunction(CGM, Loc, RCG, Cnt);
5965 CGF.EmitStoreOfScalar(InitAddr, InitLVal);
5966 // ElemLVal.reduce_fini = fini;
5967 LValue FiniLVal = CGF.EmitLValueForField(ElemLVal, FiniFD);
5968 llvm::Value *Fini = emitReduceFiniFunction(CGM, Loc, RCG, Cnt);
5969 llvm::Value *FiniAddr =
5970 Fini ? Fini : llvm::ConstantPointerNull::get(CGM.VoidPtrTy);
5971 CGF.EmitStoreOfScalar(FiniAddr, FiniLVal);
5972 // ElemLVal.reduce_comb = comb;
5973 LValue CombLVal = CGF.EmitLValueForField(ElemLVal, CombFD);
5974 llvm::Value *CombAddr = emitReduceCombFunction(
5975 CGM, Loc, RCG, Cnt, Data.ReductionOps[Cnt], LHSExprs[Cnt],
5976 RHSExprs[Cnt], Data.ReductionCopies[Cnt]);
5977 CGF.EmitStoreOfScalar(CombAddr, CombLVal);
5978 // ElemLVal.flags = 0;
5979 LValue FlagsLVal = CGF.EmitLValueForField(ElemLVal, FlagsFD);
5980 if (DelayedCreation) {
5982 llvm::ConstantInt::get(CGM.Int32Ty, /*V=*/1, /*isSigned=*/true),
5983 FlagsLVal);
5984 } else
5985 CGF.EmitNullInitialization(FlagsLVal.getAddress(), FlagsLVal.getType());
5986 }
5987 if (Data.IsReductionWithTaskMod) {
5988 // Build call void *__kmpc_taskred_modifier_init(ident_t *loc, int gtid, int
5989 // is_ws, int num, void *data);
5990 llvm::Value *IdentTLoc = emitUpdateLocation(CGF, Loc);
5991 llvm::Value *GTid = CGF.Builder.CreateIntCast(getThreadID(CGF, Loc),
5992 CGM.IntTy, /*isSigned=*/true);
5993 llvm::Value *Args[] = {
5994 IdentTLoc, GTid,
5995 llvm::ConstantInt::get(CGM.IntTy, Data.IsWorksharingReduction ? 1 : 0,
5996 /*isSigned=*/true),
5997 llvm::ConstantInt::get(CGM.IntTy, Size, /*isSigned=*/true),
5999 TaskRedInput.getPointer(), CGM.VoidPtrTy)};
6000 return CGF.EmitRuntimeCall(
6001 OMPBuilder.getOrCreateRuntimeFunction(
6002 CGM.getModule(), OMPRTL___kmpc_taskred_modifier_init),
6003 Args);
6004 }
6005 // Build call void *__kmpc_taskred_init(int gtid, int num_data, void *data);
6006 llvm::Value *Args[] = {
6007 CGF.Builder.CreateIntCast(getThreadID(CGF, Loc), CGM.IntTy,
6008 /*isSigned=*/true),
6009 llvm::ConstantInt::get(CGM.IntTy, Size, /*isSigned=*/true),
6011 CGM.VoidPtrTy)};
6012 return CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
6013 CGM.getModule(), OMPRTL___kmpc_taskred_init),
6014 Args);
6015}
6016
6018 SourceLocation Loc,
6019 bool IsWorksharingReduction) {
6020 // Build call void *__kmpc_taskred_modifier_init(ident_t *loc, int gtid, int
6021 // is_ws, int num, void *data);
6022 llvm::Value *IdentTLoc = emitUpdateLocation(CGF, Loc);
6023 llvm::Value *GTid = CGF.Builder.CreateIntCast(getThreadID(CGF, Loc),
6024 CGM.IntTy, /*isSigned=*/true);
6025 llvm::Value *Args[] = {IdentTLoc, GTid,
6026 llvm::ConstantInt::get(CGM.IntTy,
6027 IsWorksharingReduction ? 1 : 0,
6028 /*isSigned=*/true)};
6029 (void)CGF.EmitRuntimeCall(
6030 OMPBuilder.getOrCreateRuntimeFunction(
6031 CGM.getModule(), OMPRTL___kmpc_task_reduction_modifier_fini),
6032 Args);
6033}
6034
6036 SourceLocation Loc,
6037 ReductionCodeGen &RCG,
6038 unsigned N) {
6039 auto Sizes = RCG.getSizes(N);
6040 // Emit threadprivate global variable if the type is non-constant
6041 // (Sizes.second = nullptr).
6042 if (Sizes.second) {
6043 llvm::Value *SizeVal = CGF.Builder.CreateIntCast(Sizes.second, CGM.SizeTy,
6044 /*isSigned=*/false);
6046 CGF, CGM.getContext().getSizeType(),
6047 generateUniqueName(CGM, "reduction_size", RCG.getRefExpr(N)));
6048 CGF.Builder.CreateStore(SizeVal, SizeAddr, /*IsVolatile=*/false);
6049 }
6050}
6051
6053 SourceLocation Loc,
6054 llvm::Value *ReductionsPtr,
6055 LValue SharedLVal) {
6056 // Build call void *__kmpc_task_reduction_get_th_data(int gtid, void *tg, void
6057 // *d);
6058 llvm::Value *Args[] = {CGF.Builder.CreateIntCast(getThreadID(CGF, Loc),
6059 CGM.IntTy,
6060 /*isSigned=*/true),
6061 ReductionsPtr,
6063 SharedLVal.getPointer(CGF), CGM.VoidPtrTy)};
6064 return Address(
6065 CGF.EmitRuntimeCall(
6066 OMPBuilder.getOrCreateRuntimeFunction(
6067 CGM.getModule(), OMPRTL___kmpc_task_reduction_get_th_data),
6068 Args),
6069 CGF.Int8Ty, SharedLVal.getAlignment());
6070}
6071
6073 const OMPTaskDataTy &Data) {
6074 if (!CGF.HaveInsertPoint())
6075 return;
6076
6077 if (CGF.CGM.getLangOpts().OpenMPIRBuilder && Data.Dependences.empty()) {
6078 // TODO: Need to support taskwait with dependences in the OpenMPIRBuilder.
6079 OMPBuilder.createTaskwait(CGF.Builder);
6080 } else {
6081 llvm::Value *ThreadID = getThreadID(CGF, Loc);
6082 llvm::Value *UpLoc = emitUpdateLocation(CGF, Loc);
6083 auto &M = CGM.getModule();
6084 Address DependenciesArray = Address::invalid();
6085 llvm::Value *NumOfElements;
6086 std::tie(NumOfElements, DependenciesArray) =
6087 emitDependClause(CGF, Data.Dependences, Loc);
6088 if (!Data.Dependences.empty()) {
6089 llvm::Value *DepWaitTaskArgs[7];
6090 DepWaitTaskArgs[0] = UpLoc;
6091 DepWaitTaskArgs[1] = ThreadID;
6092 DepWaitTaskArgs[2] = NumOfElements;
6093 DepWaitTaskArgs[3] = DependenciesArray.emitRawPointer(CGF);
6094 DepWaitTaskArgs[4] = CGF.Builder.getInt32(0);
6095 DepWaitTaskArgs[5] = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
6096 DepWaitTaskArgs[6] =
6097 llvm::ConstantInt::get(CGF.Int32Ty, Data.HasNowaitClause);
6098
6099 CodeGenFunction::RunCleanupsScope LocalScope(CGF);
6100
6101 // Build void __kmpc_omp_taskwait_deps_51(ident_t *, kmp_int32 gtid,
6102 // kmp_int32 ndeps, kmp_depend_info_t *dep_list, kmp_int32
6103 // ndeps_noalias, kmp_depend_info_t *noalias_dep_list,
6104 // kmp_int32 has_no_wait); if dependence info is specified.
6105 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
6106 M, OMPRTL___kmpc_omp_taskwait_deps_51),
6107 DepWaitTaskArgs);
6108
6109 } else {
6110
6111 // Build call kmp_int32 __kmpc_omp_taskwait(ident_t *loc, kmp_int32
6112 // global_tid);
6113 llvm::Value *Args[] = {UpLoc, ThreadID};
6114 // Ignore return result until untied tasks are supported.
6115 CGF.EmitRuntimeCall(
6116 OMPBuilder.getOrCreateRuntimeFunction(M, OMPRTL___kmpc_omp_taskwait),
6117 Args);
6118 }
6119 }
6120
6121 if (auto *Region = dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo))
6122 Region->emitUntiedSwitch(CGF);
6123}
6124
6126 OpenMPDirectiveKind InnerKind,
6127 const RegionCodeGenTy &CodeGen,
6128 bool HasCancel) {
6129 if (!CGF.HaveInsertPoint())
6130 return;
6131 InlinedOpenMPRegionRAII Region(CGF, CodeGen, InnerKind, HasCancel,
6132 InnerKind != OMPD_critical &&
6133 InnerKind != OMPD_master &&
6134 InnerKind != OMPD_masked);
6135 CGF.CapturedStmtInfo->EmitBody(CGF, /*S=*/nullptr);
6136}
6137
6138namespace {
6139enum RTCancelKind {
6140 CancelNoreq = 0,
6141 CancelParallel = 1,
6142 CancelLoop = 2,
6143 CancelSections = 3,
6144 CancelTaskgroup = 4
6145};
6146} // anonymous namespace
6147
6148static RTCancelKind getCancellationKind(OpenMPDirectiveKind CancelRegion) {
6149 RTCancelKind CancelKind = CancelNoreq;
6150 if (CancelRegion == OMPD_parallel)
6151 CancelKind = CancelParallel;
6152 else if (CancelRegion == OMPD_for)
6153 CancelKind = CancelLoop;
6154 else if (CancelRegion == OMPD_sections)
6155 CancelKind = CancelSections;
6156 else {
6157 assert(CancelRegion == OMPD_taskgroup);
6158 CancelKind = CancelTaskgroup;
6159 }
6160 return CancelKind;
6161}
6162
6165 OpenMPDirectiveKind CancelRegion) {
6166 if (!CGF.HaveInsertPoint())
6167 return;
6168 // Build call kmp_int32 __kmpc_cancellationpoint(ident_t *loc, kmp_int32
6169 // global_tid, kmp_int32 cncl_kind);
6170 if (auto *OMPRegionInfo =
6171 dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) {
6172 // For 'cancellation point taskgroup', the task region info may not have a
6173 // cancel. This may instead happen in another adjacent task.
6174 if (CancelRegion == OMPD_taskgroup || OMPRegionInfo->hasCancel()) {
6175 llvm::Value *Args[] = {
6176 emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
6177 CGF.Builder.getInt32(getCancellationKind(CancelRegion))};
6178 // Ignore return result until untied tasks are supported.
6179 llvm::Value *Result = CGF.EmitRuntimeCall(
6180 OMPBuilder.getOrCreateRuntimeFunction(
6181 CGM.getModule(), OMPRTL___kmpc_cancellationpoint),
6182 Args);
6183 // if (__kmpc_cancellationpoint()) {
6184 // call i32 @__kmpc_cancel_barrier( // for parallel cancellation only
6185 // exit from construct;
6186 // }
6187 llvm::BasicBlock *ExitBB = CGF.createBasicBlock(".cancel.exit");
6188 llvm::BasicBlock *ContBB = CGF.createBasicBlock(".cancel.continue");
6189 llvm::Value *Cmp = CGF.Builder.CreateIsNotNull(Result);
6190 CGF.Builder.CreateCondBr(Cmp, ExitBB, ContBB);
6191 CGF.EmitBlock(ExitBB);
6192 if (CancelRegion == OMPD_parallel)
6193 emitBarrierCall(CGF, Loc, OMPD_unknown, /*EmitChecks=*/false);
6194 // exit from construct;
6195 CodeGenFunction::JumpDest CancelDest =
6196 CGF.getOMPCancelDestination(OMPRegionInfo->getDirectiveKind());
6197 CGF.EmitBranchThroughCleanup(CancelDest);
6198 CGF.EmitBlock(ContBB, /*IsFinished=*/true);
6199 }
6200 }
6201}
6202
6204 const Expr *IfCond,
6205 OpenMPDirectiveKind CancelRegion) {
6206 if (!CGF.HaveInsertPoint())
6207 return;
6208 // Build call kmp_int32 __kmpc_cancel(ident_t *loc, kmp_int32 global_tid,
6209 // kmp_int32 cncl_kind);
6210 auto &M = CGM.getModule();
6211 if (auto *OMPRegionInfo =
6212 dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) {
6213 auto &&ThenGen = [this, &M, Loc, CancelRegion,
6214 OMPRegionInfo](CodeGenFunction &CGF, PrePostActionTy &) {
6215 CGOpenMPRuntime &RT = CGF.CGM.getOpenMPRuntime();
6216 llvm::Value *Args[] = {
6217 RT.emitUpdateLocation(CGF, Loc), RT.getThreadID(CGF, Loc),
6218 CGF.Builder.getInt32(getCancellationKind(CancelRegion))};
6219 // Ignore return result until untied tasks are supported.
6220 llvm::Value *Result = CGF.EmitRuntimeCall(
6221 OMPBuilder.getOrCreateRuntimeFunction(M, OMPRTL___kmpc_cancel), Args);
6222 // if (__kmpc_cancel()) {
6223 // call i32 @__kmpc_cancel_barrier( // for parallel cancellation only
6224 // exit from construct;
6225 // }
6226 llvm::BasicBlock *ExitBB = CGF.createBasicBlock(".cancel.exit");
6227 llvm::BasicBlock *ContBB = CGF.createBasicBlock(".cancel.continue");
6228 llvm::Value *Cmp = CGF.Builder.CreateIsNotNull(Result);
6229 CGF.Builder.CreateCondBr(Cmp, ExitBB, ContBB);
6230 CGF.EmitBlock(ExitBB);
6231 if (CancelRegion == OMPD_parallel)
6232 RT.emitBarrierCall(CGF, Loc, OMPD_unknown, /*EmitChecks=*/false);
6233 // exit from construct;
6234 CodeGenFunction::JumpDest CancelDest =
6235 CGF.getOMPCancelDestination(OMPRegionInfo->getDirectiveKind());
6236 CGF.EmitBranchThroughCleanup(CancelDest);
6237 CGF.EmitBlock(ContBB, /*IsFinished=*/true);
6238 };
6239 if (IfCond) {
6240 emitIfClause(CGF, IfCond, ThenGen,
6241 [](CodeGenFunction &, PrePostActionTy &) {});
6242 } else {
6243 RegionCodeGenTy ThenRCG(ThenGen);
6244 ThenRCG(CGF);
6245 }
6246 }
6247}
6248
6249namespace {
6250/// Cleanup action for uses_allocators support.
6251class OMPUsesAllocatorsActionTy final : public PrePostActionTy {
6253
6254public:
6255 OMPUsesAllocatorsActionTy(
6256 ArrayRef<std::pair<const Expr *, const Expr *>> Allocators)
6257 : Allocators(Allocators) {}
6258 void Enter(CodeGenFunction &CGF) override {
6259 if (!CGF.HaveInsertPoint())
6260 return;
6261 for (const auto &AllocatorData : Allocators) {
6263 CGF, AllocatorData.first, AllocatorData.second);
6264 }
6265 }
6266 void Exit(CodeGenFunction &CGF) override {
6267 if (!CGF.HaveInsertPoint())
6268 return;
6269 for (const auto &AllocatorData : Allocators) {
6271 AllocatorData.first);
6272 }
6273 }
6274};
6275} // namespace
6276
6278 const OMPExecutableDirective &D, StringRef ParentName,
6279 llvm::Function *&OutlinedFn, llvm::Constant *&OutlinedFnID,
6280 bool IsOffloadEntry, const RegionCodeGenTy &CodeGen) {
6281 assert(!ParentName.empty() && "Invalid target entry parent name!");
6284 for (const auto *C : D.getClausesOfKind<OMPUsesAllocatorsClause>()) {
6285 for (unsigned I = 0, E = C->getNumberOfAllocators(); I < E; ++I) {
6286 const OMPUsesAllocatorsClause::Data D = C->getAllocatorData(I);
6287 if (!D.AllocatorTraits)
6288 continue;
6289 Allocators.emplace_back(D.Allocator, D.AllocatorTraits);
6290 }
6291 }
6292 OMPUsesAllocatorsActionTy UsesAllocatorAction(Allocators);
6293 CodeGen.setAction(UsesAllocatorAction);
6294 emitTargetOutlinedFunctionHelper(D, ParentName, OutlinedFn, OutlinedFnID,
6295 IsOffloadEntry, CodeGen);
6296}
6297
6299 const Expr *Allocator,
6300 const Expr *AllocatorTraits) {
6301 llvm::Value *ThreadId = getThreadID(CGF, Allocator->getExprLoc());
6302 ThreadId = CGF.Builder.CreateIntCast(ThreadId, CGF.IntTy, /*isSigned=*/true);
6303 // Use default memspace handle.
6304 llvm::Value *MemSpaceHandle = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
6305 llvm::Value *NumTraits = llvm::ConstantInt::get(
6307 AllocatorTraits->getType()->getAsArrayTypeUnsafe())
6308 ->getSize()
6309 .getLimitedValue());
6310 LValue AllocatorTraitsLVal = CGF.EmitLValue(AllocatorTraits);
6312 AllocatorTraitsLVal.getAddress(), CGF.VoidPtrPtrTy, CGF.VoidPtrTy);
6313 AllocatorTraitsLVal = CGF.MakeAddrLValue(Addr, CGF.getContext().VoidPtrTy,
6314 AllocatorTraitsLVal.getBaseInfo(),
6315 AllocatorTraitsLVal.getTBAAInfo());
6316 llvm::Value *Traits = Addr.emitRawPointer(CGF);
6317
6318 llvm::Value *AllocatorVal =
6319 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
6320 CGM.getModule(), OMPRTL___kmpc_init_allocator),
6321 {ThreadId, MemSpaceHandle, NumTraits, Traits});
6322 // Store to allocator.
6324 cast<DeclRefExpr>(Allocator->IgnoreParenImpCasts())->getDecl()));
6325 LValue AllocatorLVal = CGF.EmitLValue(Allocator->IgnoreParenImpCasts());
6326 AllocatorVal =
6327 CGF.EmitScalarConversion(AllocatorVal, CGF.getContext().VoidPtrTy,
6328 Allocator->getType(), Allocator->getExprLoc());
6329 CGF.EmitStoreOfScalar(AllocatorVal, AllocatorLVal);
6330}
6331
6333 const Expr *Allocator) {
6334 llvm::Value *ThreadId = getThreadID(CGF, Allocator->getExprLoc());
6335 ThreadId = CGF.Builder.CreateIntCast(ThreadId, CGF.IntTy, /*isSigned=*/true);
6336 LValue AllocatorLVal = CGF.EmitLValue(Allocator->IgnoreParenImpCasts());
6337 llvm::Value *AllocatorVal =
6338 CGF.EmitLoadOfScalar(AllocatorLVal, Allocator->getExprLoc());
6339 AllocatorVal = CGF.EmitScalarConversion(AllocatorVal, Allocator->getType(),
6340 CGF.getContext().VoidPtrTy,
6341 Allocator->getExprLoc());
6342 (void)CGF.EmitRuntimeCall(
6343 OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(),
6344 OMPRTL___kmpc_destroy_allocator),
6345 {ThreadId, AllocatorVal});
6346}
6347
6350 llvm::OpenMPIRBuilder::TargetKernelDefaultAttrs &Attrs) {
6351 assert(Attrs.MaxTeams.size() == 1 && Attrs.MaxThreads.size() == 1 &&
6352 "invalid default attrs structure");
6353 int32_t &MaxTeamsVal = Attrs.MaxTeams.front();
6354 int32_t &MaxThreadsVal = Attrs.MaxThreads.front();
6355
6356 getNumTeamsExprForTargetDirective(CGF, D, Attrs.MinTeams, MaxTeamsVal);
6357 getNumThreadsExprForTargetDirective(CGF, D, MaxThreadsVal,
6358 /*UpperBoundOnly=*/true);
6359
6360 for (auto *C : D.getClausesOfKind<OMPXAttributeClause>()) {
6361 for (auto *A : C->getAttrs()) {
6362 int32_t AttrMinThreadsVal = 1, AttrMaxThreadsVal = -1;
6363 int32_t AttrMinBlocksVal = 1, AttrMaxBlocksVal = -1;
6364 if (auto *Attr = dyn_cast<CUDALaunchBoundsAttr>(A))
6365 CGM.handleCUDALaunchBoundsAttr(nullptr, Attr, &AttrMaxThreadsVal,
6366 &AttrMinBlocksVal, &AttrMaxBlocksVal);
6367 else if (auto *Attr = dyn_cast<AMDGPUFlatWorkGroupSizeAttr>(A))
6368 CGM.handleAMDGPUFlatWorkGroupSizeAttr(
6369 nullptr, Attr, /*ReqdWGS=*/nullptr, &AttrMinThreadsVal,
6370 &AttrMaxThreadsVal);
6371 else
6372 continue;
6373
6374 Attrs.MinThreads = std::max(Attrs.MinThreads, AttrMinThreadsVal);
6375 if (AttrMaxThreadsVal > 0)
6376 MaxThreadsVal = MaxThreadsVal > 0
6377 ? std::min(MaxThreadsVal, AttrMaxThreadsVal)
6378 : AttrMaxThreadsVal;
6379 Attrs.MinTeams = std::max(Attrs.MinTeams, AttrMinBlocksVal);
6380 if (AttrMaxBlocksVal > 0)
6381 MaxTeamsVal = MaxTeamsVal > 0 ? std::min(MaxTeamsVal, AttrMaxBlocksVal)
6382 : AttrMaxBlocksVal;
6383 }
6384 }
6385}
6386
6388 const OMPExecutableDirective &D, StringRef ParentName,
6389 llvm::Function *&OutlinedFn, llvm::Constant *&OutlinedFnID,
6390 bool IsOffloadEntry, const RegionCodeGenTy &CodeGen) {
6391
6392 llvm::TargetRegionEntryInfo EntryInfo =
6393 getEntryInfoFromPresumedLoc(CGM, OMPBuilder, D.getBeginLoc(), ParentName);
6394
6395 CodeGenFunction CGF(CGM, true);
6396 llvm::OpenMPIRBuilder::FunctionGenCallback &&GenerateOutlinedFunction =
6397 [&CGF, &D, &CodeGen, this](StringRef EntryFnName) {
6398 const CapturedStmt &CS = *D.getCapturedStmt(OMPD_target);
6399
6400 CGOpenMPTargetRegionInfo CGInfo(CS, CodeGen, EntryFnName);
6401 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
6402 if (CGM.getLangOpts().OpenMPIsTargetDevice && !isGPU())
6404 return CGF.GenerateOpenMPCapturedStmtFunction(CS, D);
6405 };
6406
6407 cantFail(OMPBuilder.emitTargetRegionFunction(
6408 EntryInfo, GenerateOutlinedFunction, IsOffloadEntry, OutlinedFn,
6409 OutlinedFnID));
6410
6411 if (!OutlinedFn)
6412 return;
6413
6414 CGM.getTargetCodeGenInfo().setTargetAttributes(nullptr, OutlinedFn, CGM);
6415
6416 for (auto *C : D.getClausesOfKind<OMPXAttributeClause>()) {
6417 for (auto *A : C->getAttrs()) {
6418 if (auto *Attr = dyn_cast<AMDGPUWavesPerEUAttr>(A))
6419 CGM.handleAMDGPUWavesPerEUAttr(OutlinedFn, Attr);
6420 }
6421 }
6422 registerVTable(D);
6423}
6424
6425/// Checks if the expression is constant or does not have non-trivial function
6426/// calls.
6427static bool isTrivial(ASTContext &Ctx, const Expr * E) {
6428 // We can skip constant expressions.
6429 // We can skip expressions with trivial calls or simple expressions.
6431 !E->hasNonTrivialCall(Ctx)) &&
6432 !E->HasSideEffects(Ctx, /*IncludePossibleEffects=*/true);
6433}
6434
6436 const Stmt *Body) {
6437 const Stmt *Child = Body->IgnoreContainers();
6438 while (const auto *C = dyn_cast_or_null<CompoundStmt>(Child)) {
6439 Child = nullptr;
6440 for (const Stmt *S : C->body()) {
6441 if (const auto *E = dyn_cast<Expr>(S)) {
6442 if (isTrivial(Ctx, E))
6443 continue;
6444 }
6445 // Some of the statements can be ignored.
6448 continue;
6449 // Analyze declarations.
6450 if (const auto *DS = dyn_cast<DeclStmt>(S)) {
6451 if (llvm::all_of(DS->decls(), [](const Decl *D) {
6452 if (isa<EmptyDecl>(D) || isa<DeclContext>(D) ||
6453 isa<TypeDecl>(D) || isa<PragmaCommentDecl>(D) ||
6454 isa<PragmaDetectMismatchDecl>(D) || isa<UsingDecl>(D) ||
6455 isa<UsingDirectiveDecl>(D) ||
6456 isa<OMPDeclareReductionDecl>(D) ||
6457 isa<OMPThreadPrivateDecl>(D) || isa<OMPAllocateDecl>(D))
6458 return true;
6459 const auto *VD = dyn_cast<VarDecl>(D);
6460 if (!VD)
6461 return false;
6462 return VD->hasGlobalStorage() || !VD->isUsed();
6463 }))
6464 continue;
6465 }
6466 // Found multiple children - cannot get the one child only.
6467 if (Child)
6468 return nullptr;
6469 Child = S;
6470 }
6471 if (Child)
6472 Child = Child->IgnoreContainers();
6473 }
6474 return Child;
6475}
6476
6478 CodeGenFunction &CGF, const OMPExecutableDirective &D, int32_t &MinTeamsVal,
6479 int32_t &MaxTeamsVal) {
6480
6481 OpenMPDirectiveKind DirectiveKind = D.getDirectiveKind();
6482 assert(isOpenMPTargetExecutionDirective(DirectiveKind) &&
6483 "Expected target-based executable directive.");
6484 switch (DirectiveKind) {
6485 case OMPD_target: {
6486 const auto *CS = D.getInnermostCapturedStmt();
6487 const auto *Body =
6488 CS->getCapturedStmt()->IgnoreContainers(/*IgnoreCaptured=*/true);
6489 const Stmt *ChildStmt =
6491 if (const auto *NestedDir =
6492 dyn_cast_or_null<OMPExecutableDirective>(ChildStmt)) {
6493 if (isOpenMPTeamsDirective(NestedDir->getDirectiveKind())) {
6494 if (NestedDir->hasClausesOfKind<OMPNumTeamsClause>()) {
6495 const Expr *NumTeams = NestedDir->getSingleClause<OMPNumTeamsClause>()
6496 ->getNumTeams()
6497 .front();
6498 if (NumTeams->isIntegerConstantExpr(CGF.getContext()))
6499 if (auto Constant =
6500 NumTeams->getIntegerConstantExpr(CGF.getContext()))
6501 MinTeamsVal = MaxTeamsVal = Constant->getExtValue();
6502 return NumTeams;
6503 }
6504 MinTeamsVal = MaxTeamsVal = 0;
6505 return nullptr;
6506 }
6507 MinTeamsVal = MaxTeamsVal = 1;
6508 return nullptr;
6509 }
6510 // A value of -1 is used to check if we need to emit no teams region
6511 MinTeamsVal = MaxTeamsVal = -1;
6512 return nullptr;
6513 }
6514 case OMPD_target_teams_loop:
6515 case OMPD_target_teams:
6516 case OMPD_target_teams_distribute:
6517 case OMPD_target_teams_distribute_simd:
6518 case OMPD_target_teams_distribute_parallel_for:
6519 case OMPD_target_teams_distribute_parallel_for_simd: {
6520 if (D.hasClausesOfKind<OMPNumTeamsClause>()) {
6521 const Expr *NumTeams =
6522 D.getSingleClause<OMPNumTeamsClause>()->getNumTeams().front();
6523 if (NumTeams->isIntegerConstantExpr(CGF.getContext()))
6524 if (auto Constant = NumTeams->getIntegerConstantExpr(CGF.getContext()))
6525 MinTeamsVal = MaxTeamsVal = Constant->getExtValue();
6526 return NumTeams;
6527 }
6528 MinTeamsVal = MaxTeamsVal = 0;
6529 return nullptr;
6530 }
6531 case OMPD_target_parallel:
6532 case OMPD_target_parallel_for:
6533 case OMPD_target_parallel_for_simd:
6534 case OMPD_target_parallel_loop:
6535 case OMPD_target_simd:
6536 MinTeamsVal = MaxTeamsVal = 1;
6537 return nullptr;
6538 case OMPD_parallel:
6539 case OMPD_for:
6540 case OMPD_parallel_for:
6541 case OMPD_parallel_loop:
6542 case OMPD_parallel_master:
6543 case OMPD_parallel_sections:
6544 case OMPD_for_simd:
6545 case OMPD_parallel_for_simd:
6546 case OMPD_cancel:
6547 case OMPD_cancellation_point:
6548 case OMPD_ordered:
6549 case OMPD_threadprivate:
6550 case OMPD_allocate:
6551 case OMPD_task:
6552 case OMPD_simd:
6553 case OMPD_tile:
6554 case OMPD_unroll:
6555 case OMPD_sections:
6556 case OMPD_section:
6557 case OMPD_single:
6558 case OMPD_master:
6559 case OMPD_critical:
6560 case OMPD_taskyield:
6561 case OMPD_barrier:
6562 case OMPD_taskwait:
6563 case OMPD_taskgroup:
6564 case OMPD_atomic:
6565 case OMPD_flush:
6566 case OMPD_depobj:
6567 case OMPD_scan:
6568 case OMPD_teams:
6569 case OMPD_target_data:
6570 case OMPD_target_exit_data:
6571 case OMPD_target_enter_data:
6572 case OMPD_distribute:
6573 case OMPD_distribute_simd:
6574 case OMPD_distribute_parallel_for:
6575 case OMPD_distribute_parallel_for_simd:
6576 case OMPD_teams_distribute:
6577 case OMPD_teams_distribute_simd:
6578 case OMPD_teams_distribute_parallel_for:
6579 case OMPD_teams_distribute_parallel_for_simd:
6580 case OMPD_target_update:
6581 case OMPD_declare_simd:
6582 case OMPD_declare_variant:
6583 case OMPD_begin_declare_variant:
6584 case OMPD_end_declare_variant:
6585 case OMPD_declare_target:
6586 case OMPD_end_declare_target:
6587 case OMPD_declare_reduction:
6588 case OMPD_declare_mapper:
6589 case OMPD_taskloop:
6590 case OMPD_taskloop_simd:
6591 case OMPD_master_taskloop:
6592 case OMPD_master_taskloop_simd:
6593 case OMPD_parallel_master_taskloop:
6594 case OMPD_parallel_master_taskloop_simd:
6595 case OMPD_requires:
6596 case OMPD_metadirective:
6597 case OMPD_unknown:
6598 break;
6599 default:
6600 break;
6601 }
6602 llvm_unreachable("Unexpected directive kind.");
6603}
6604
6606 CodeGenFunction &CGF, const OMPExecutableDirective &D) {
6607 assert(!CGF.getLangOpts().OpenMPIsTargetDevice &&
6608 "Clauses associated with the teams directive expected to be emitted "
6609 "only for the host!");
6610 CGBuilderTy &Bld = CGF.Builder;
6611 int32_t MinNT = -1, MaxNT = -1;
6612 const Expr *NumTeams =
6613 getNumTeamsExprForTargetDirective(CGF, D, MinNT, MaxNT);
6614 if (NumTeams != nullptr) {
6615 OpenMPDirectiveKind DirectiveKind = D.getDirectiveKind();
6616
6617 switch (DirectiveKind) {
6618 case OMPD_target: {
6619 const auto *CS = D.getInnermostCapturedStmt();
6620 CGOpenMPInnerExprInfo CGInfo(CGF, *CS);
6621 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
6622 llvm::Value *NumTeamsVal = CGF.EmitScalarExpr(NumTeams,
6623 /*IgnoreResultAssign*/ true);
6624 return Bld.CreateIntCast(NumTeamsVal, CGF.Int32Ty,
6625 /*isSigned=*/true);
6626 }
6627 case OMPD_target_teams:
6628 case OMPD_target_teams_distribute:
6629 case OMPD_target_teams_distribute_simd:
6630 case OMPD_target_teams_distribute_parallel_for:
6631 case OMPD_target_teams_distribute_parallel_for_simd: {
6632 CodeGenFunction::RunCleanupsScope NumTeamsScope(CGF);
6633 llvm::Value *NumTeamsVal = CGF.EmitScalarExpr(NumTeams,
6634 /*IgnoreResultAssign*/ true);
6635 return Bld.CreateIntCast(NumTeamsVal, CGF.Int32Ty,
6636 /*isSigned=*/true);
6637 }
6638 default:
6639 break;
6640 }
6641 }
6642
6643 assert(MinNT == MaxNT && "Num threads ranges require handling here.");
6644 return llvm::ConstantInt::getSigned(CGF.Int32Ty, MinNT);
6645}
6646
6647/// Check for a num threads constant value (stored in \p DefaultVal), or
6648/// expression (stored in \p E). If the value is conditional (via an if-clause),
6649/// store the condition in \p CondVal. If \p E, and \p CondVal respectively, are
6650/// nullptr, no expression evaluation is perfomed.
6651static void getNumThreads(CodeGenFunction &CGF, const CapturedStmt *CS,
6652 const Expr **E, int32_t &UpperBound,
6653 bool UpperBoundOnly, llvm::Value **CondVal) {
6655 CGF.getContext(), CS->getCapturedStmt());
6656 const auto *Dir = dyn_cast_or_null<OMPExecutableDirective>(Child);
6657 if (!Dir)
6658 return;
6659
6660 if (isOpenMPParallelDirective(Dir->getDirectiveKind())) {
6661 // Handle if clause. If if clause present, the number of threads is
6662 // calculated as <cond> ? (<numthreads> ? <numthreads> : 0 ) : 1.
6663 if (CondVal && Dir->hasClausesOfKind<OMPIfClause>()) {
6664 CGOpenMPInnerExprInfo CGInfo(CGF, *CS);
6665 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
6666 const OMPIfClause *IfClause = nullptr;
6667 for (const auto *C : Dir->getClausesOfKind<OMPIfClause>()) {
6668 if (C->getNameModifier() == OMPD_unknown ||
6669 C->getNameModifier() == OMPD_parallel) {
6670 IfClause = C;
6671 break;
6672 }
6673 }
6674 if (IfClause) {
6675 const Expr *CondExpr = IfClause->getCondition();
6676 bool Result;
6677 if (CondExpr->EvaluateAsBooleanCondition(Result, CGF.getContext())) {
6678 if (!Result) {
6679 UpperBound = 1;
6680 return;
6681 }
6682 } else {
6684 if (const auto *PreInit =
6685 cast_or_null<DeclStmt>(IfClause->getPreInitStmt())) {
6686 for (const auto *I : PreInit->decls()) {
6687 if (!I->hasAttr<OMPCaptureNoInitAttr>()) {
6688 CGF.EmitVarDecl(cast<VarDecl>(*I));
6689 } else {
6692 CGF.EmitAutoVarCleanups(Emission);
6693 }
6694 }
6695 *CondVal = CGF.EvaluateExprAsBool(CondExpr);
6696 }
6697 }
6698 }
6699 }
6700 // Check the value of num_threads clause iff if clause was not specified
6701 // or is not evaluated to false.
6702 if (Dir->hasClausesOfKind<OMPNumThreadsClause>()) {
6703 CGOpenMPInnerExprInfo CGInfo(CGF, *CS);
6704 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
6705 const auto *NumThreadsClause =
6706 Dir->getSingleClause<OMPNumThreadsClause>();
6707 const Expr *NTExpr = NumThreadsClause->getNumThreads();
6708 if (NTExpr->isIntegerConstantExpr(CGF.getContext()))
6709 if (auto Constant = NTExpr->getIntegerConstantExpr(CGF.getContext()))
6710 UpperBound =
6711 UpperBound
6712 ? Constant->getZExtValue()
6713 : std::min(UpperBound,
6714 static_cast<int32_t>(Constant->getZExtValue()));
6715 // If we haven't found a upper bound, remember we saw a thread limiting
6716 // clause.
6717 if (UpperBound == -1)
6718 UpperBound = 0;
6719 if (!E)
6720 return;
6721 CodeGenFunction::LexicalScope Scope(CGF, NTExpr->getSourceRange());
6722 if (const auto *PreInit =
6723 cast_or_null<DeclStmt>(NumThreadsClause->getPreInitStmt())) {
6724 for (const auto *I : PreInit->decls()) {
6725 if (!I->hasAttr<OMPCaptureNoInitAttr>()) {
6726 CGF.EmitVarDecl(cast<VarDecl>(*I));
6727 } else {
6730 CGF.EmitAutoVarCleanups(Emission);
6731 }
6732 }
6733 }
6734 *E = NTExpr;
6735 }
6736 return;
6737 }
6738 if (isOpenMPSimdDirective(Dir->getDirectiveKind()))
6739 UpperBound = 1;
6740}
6741
6743 CodeGenFunction &CGF, const OMPExecutableDirective &D, int32_t &UpperBound,
6744 bool UpperBoundOnly, llvm::Value **CondVal, const Expr **ThreadLimitExpr) {
6745 assert((!CGF.getLangOpts().OpenMPIsTargetDevice || UpperBoundOnly) &&
6746 "Clauses associated with the teams directive expected to be emitted "
6747 "only for the host!");
6748 OpenMPDirectiveKind DirectiveKind = D.getDirectiveKind();
6749 assert(isOpenMPTargetExecutionDirective(DirectiveKind) &&
6750 "Expected target-based executable directive.");
6751
6752 const Expr *NT = nullptr;
6753 const Expr **NTPtr = UpperBoundOnly ? nullptr : &NT;
6754
6755 auto CheckForConstExpr = [&](const Expr *E, const Expr **EPtr) {
6756 if (E->isIntegerConstantExpr(CGF.getContext())) {
6757 if (auto Constant = E->getIntegerConstantExpr(CGF.getContext()))
6758 UpperBound = UpperBound ? Constant->getZExtValue()
6759 : std::min(UpperBound,
6760 int32_t(Constant->getZExtValue()));
6761 }
6762 // If we haven't found a upper bound, remember we saw a thread limiting
6763 // clause.
6764 if (UpperBound == -1)
6765 UpperBound = 0;
6766 if (EPtr)
6767 *EPtr = E;
6768 };
6769
6770 auto ReturnSequential = [&]() {
6771 UpperBound = 1;
6772 return NT;
6773 };
6774
6775 switch (DirectiveKind) {
6776 case OMPD_target: {
6777 const CapturedStmt *CS = D.getInnermostCapturedStmt();
6778 getNumThreads(CGF, CS, NTPtr, UpperBound, UpperBoundOnly, CondVal);
6780 CGF.getContext(), CS->getCapturedStmt());
6781 // TODO: The standard is not clear how to resolve two thread limit clauses,
6782 // let's pick the teams one if it's present, otherwise the target one.
6783 const auto *ThreadLimitClause = D.getSingleClause<OMPThreadLimitClause>();
6784 if (const auto *Dir = dyn_cast_or_null<OMPExecutableDirective>(Child)) {
6785 if (const auto *TLC = Dir->getSingleClause<OMPThreadLimitClause>()) {
6786 ThreadLimitClause = TLC;
6787 if (ThreadLimitExpr) {
6788 CGOpenMPInnerExprInfo CGInfo(CGF, *CS);
6789 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
6791 CGF,
6792 ThreadLimitClause->getThreadLimit().front()->getSourceRange());
6793 if (const auto *PreInit =
6794 cast_or_null<DeclStmt>(ThreadLimitClause->getPreInitStmt())) {
6795 for (const auto *I : PreInit->decls()) {
6796 if (!I->hasAttr<OMPCaptureNoInitAttr>()) {
6797 CGF.EmitVarDecl(cast<VarDecl>(*I));
6798 } else {
6801 CGF.EmitAutoVarCleanups(Emission);
6802 }
6803 }
6804 }
6805 }
6806 }
6807 }
6808 if (ThreadLimitClause)
6809 CheckForConstExpr(ThreadLimitClause->getThreadLimit().front(),
6810 ThreadLimitExpr);
6811 if (const auto *Dir = dyn_cast_or_null<OMPExecutableDirective>(Child)) {
6812 if (isOpenMPTeamsDirective(Dir->getDirectiveKind()) &&
6813 !isOpenMPDistributeDirective(Dir->getDirectiveKind())) {
6814 CS = Dir->getInnermostCapturedStmt();
6816 CGF.getContext(), CS->getCapturedStmt());
6817 Dir = dyn_cast_or_null<OMPExecutableDirective>(Child);
6818 }
6819 if (Dir && isOpenMPParallelDirective(Dir->getDirectiveKind())) {
6820 CS = Dir->getInnermostCapturedStmt();
6821 getNumThreads(CGF, CS, NTPtr, UpperBound, UpperBoundOnly, CondVal);
6822 } else if (Dir && isOpenMPSimdDirective(Dir->getDirectiveKind()))
6823 return ReturnSequential();
6824 }
6825 return NT;
6826 }
6827 case OMPD_target_teams: {
6828 if (D.hasClausesOfKind<OMPThreadLimitClause>()) {
6829 CodeGenFunction::RunCleanupsScope ThreadLimitScope(CGF);
6830 const auto *ThreadLimitClause = D.getSingleClause<OMPThreadLimitClause>();
6831 CheckForConstExpr(ThreadLimitClause->getThreadLimit().front(),
6832 ThreadLimitExpr);
6833 }
6834 const CapturedStmt *CS = D.getInnermostCapturedStmt();
6835 getNumThreads(CGF, CS, NTPtr, UpperBound, UpperBoundOnly, CondVal);
6837 CGF.getContext(), CS->getCapturedStmt());
6838 if (const auto *Dir = dyn_cast_or_null<OMPExecutableDirective>(Child)) {
6839 if (Dir->getDirectiveKind() == OMPD_distribute) {
6840 CS = Dir->getInnermostCapturedStmt();
6841 getNumThreads(CGF, CS, NTPtr, UpperBound, UpperBoundOnly, CondVal);
6842 }
6843 }
6844 return NT;
6845 }
6846 case OMPD_target_teams_distribute:
6847 if (D.hasClausesOfKind<OMPThreadLimitClause>()) {
6848 CodeGenFunction::RunCleanupsScope ThreadLimitScope(CGF);
6849 const auto *ThreadLimitClause = D.getSingleClause<OMPThreadLimitClause>();
6850 CheckForConstExpr(ThreadLimitClause->getThreadLimit().front(),
6851 ThreadLimitExpr);
6852 }
6853 getNumThreads(CGF, D.getInnermostCapturedStmt(), NTPtr, UpperBound,
6854 UpperBoundOnly, CondVal);
6855 return NT;
6856 case OMPD_target_teams_loop:
6857 case OMPD_target_parallel_loop:
6858 case OMPD_target_parallel:
6859 case OMPD_target_parallel_for:
6860 case OMPD_target_parallel_for_simd:
6861 case OMPD_target_teams_distribute_parallel_for:
6862 case OMPD_target_teams_distribute_parallel_for_simd: {
6863 if (CondVal && D.hasClausesOfKind<OMPIfClause>()) {
6864 const OMPIfClause *IfClause = nullptr;
6865 for (const auto *C : D.getClausesOfKind<OMPIfClause>()) {
6866 if (C->getNameModifier() == OMPD_unknown ||
6867 C->getNameModifier() == OMPD_parallel) {
6868 IfClause = C;
6869 break;
6870 }
6871 }
6872 if (IfClause) {
6873 const Expr *Cond = IfClause->getCondition();
6874 bool Result;
6875 if (Cond->EvaluateAsBooleanCondition(Result, CGF.getContext())) {
6876 if (!Result)
6877 return ReturnSequential();
6878 } else {
6880 *CondVal = CGF.EvaluateExprAsBool(Cond);
6881 }
6882 }
6883 }
6884 if (D.hasClausesOfKind<OMPThreadLimitClause>()) {
6885 CodeGenFunction::RunCleanupsScope ThreadLimitScope(CGF);
6886 const auto *ThreadLimitClause = D.getSingleClause<OMPThreadLimitClause>();
6887 CheckForConstExpr(ThreadLimitClause->getThreadLimit().front(),
6888 ThreadLimitExpr);
6889 }
6890 if (D.hasClausesOfKind<OMPNumThreadsClause>()) {
6891 CodeGenFunction::RunCleanupsScope NumThreadsScope(CGF);
6892 const auto *NumThreadsClause = D.getSingleClause<OMPNumThreadsClause>();
6893 CheckForConstExpr(NumThreadsClause->getNumThreads(), nullptr);
6894 return NumThreadsClause->getNumThreads();
6895 }
6896 return NT;
6897 }
6898 case OMPD_target_teams_distribute_simd:
6899 case OMPD_target_simd:
6900 return ReturnSequential();
6901 default:
6902 break;
6903 }
6904 llvm_unreachable("Unsupported directive kind.");
6905}
6906
6908 CodeGenFunction &CGF, const OMPExecutableDirective &D) {
6909 llvm::Value *NumThreadsVal = nullptr;
6910 llvm::Value *CondVal = nullptr;
6911 llvm::Value *ThreadLimitVal = nullptr;
6912 const Expr *ThreadLimitExpr = nullptr;
6913 int32_t UpperBound = -1;
6914
6916 CGF, D, UpperBound, /* UpperBoundOnly */ false, &CondVal,
6917 &ThreadLimitExpr);
6918
6919 // Thread limit expressions are used below, emit them.
6920 if (ThreadLimitExpr) {
6921 ThreadLimitVal =
6922 CGF.EmitScalarExpr(ThreadLimitExpr, /*IgnoreResultAssign=*/true);
6923 ThreadLimitVal = CGF.Builder.CreateIntCast(ThreadLimitVal, CGF.Int32Ty,
6924 /*isSigned=*/false);
6925 }
6926
6927 // Generate the num teams expression.
6928 if (UpperBound == 1) {
6929 NumThreadsVal = CGF.Builder.getInt32(UpperBound);
6930 } else if (NT) {
6931 NumThreadsVal = CGF.EmitScalarExpr(NT, /*IgnoreResultAssign=*/true);
6932 NumThreadsVal = CGF.Builder.CreateIntCast(NumThreadsVal, CGF.Int32Ty,
6933 /*isSigned=*/false);
6934 } else if (ThreadLimitVal) {
6935 // If we do not have a num threads value but a thread limit, replace the
6936 // former with the latter. We know handled the thread limit expression.
6937 NumThreadsVal = ThreadLimitVal;
6938 ThreadLimitVal = nullptr;
6939 } else {
6940 // Default to "0" which means runtime choice.
6941 assert(!ThreadLimitVal && "Default not applicable with thread limit value");
6942 NumThreadsVal = CGF.Builder.getInt32(0);
6943 }
6944
6945 // Handle if clause. If if clause present, the number of threads is
6946 // calculated as <cond> ? (<numthreads> ? <numthreads> : 0 ) : 1.
6947 if (CondVal) {
6949 NumThreadsVal = CGF.Builder.CreateSelect(CondVal, NumThreadsVal,
6950 CGF.Builder.getInt32(1));
6951 }
6952
6953 // If the thread limit and num teams expression were present, take the
6954 // minimum.
6955 if (ThreadLimitVal) {
6956 NumThreadsVal = CGF.Builder.CreateSelect(
6957 CGF.Builder.CreateICmpULT(ThreadLimitVal, NumThreadsVal),
6958 ThreadLimitVal, NumThreadsVal);
6959 }
6960
6961 return NumThreadsVal;
6962}
6963
6964namespace {
6966
6967// Utility to handle information from clauses associated with a given
6968// construct that use mappable expressions (e.g. 'map' clause, 'to' clause).
6969// It provides a convenient interface to obtain the information and generate
6970// code for that information.
6971class MappableExprsHandler {
6972public:
6973 /// Custom comparator for attach-pointer expressions that compares them by
6974 /// complexity (i.e. their component-depth) first, then by the order in which
6975 /// they were computed by collectAttachPtrExprInfo(), if they are semantically
6976 /// different.
6977 struct AttachPtrExprComparator {
6978 const MappableExprsHandler &Handler;
6979 // Cache of previous equality comparison results.
6980 mutable llvm::DenseMap<std::pair<const Expr *, const Expr *>, bool>
6981 CachedEqualityComparisons;
6982
6983 AttachPtrExprComparator(const MappableExprsHandler &H) : Handler(H) {}
6984 AttachPtrExprComparator() = delete;
6985
6986 // Return true iff LHS is "less than" RHS.
6987 bool operator()(const Expr *LHS, const Expr *RHS) const {
6988 if (LHS == RHS)
6989 return false;
6990
6991 // First, compare by complexity (depth)
6992 const auto ItLHS = Handler.AttachPtrComponentDepthMap.find(LHS);
6993 const auto ItRHS = Handler.AttachPtrComponentDepthMap.find(RHS);
6994
6995 std::optional<size_t> DepthLHS =
6996 (ItLHS != Handler.AttachPtrComponentDepthMap.end()) ? ItLHS->second
6997 : std::nullopt;
6998 std::optional<size_t> DepthRHS =
6999 (ItRHS != Handler.AttachPtrComponentDepthMap.end()) ? ItRHS->second
7000 : std::nullopt;
7001
7002 // std::nullopt (no attach pointer) has lowest complexity
7003 if (!DepthLHS.has_value() && !DepthRHS.has_value()) {
7004 // Both have same complexity, now check semantic equality
7005 if (areEqual(LHS, RHS))
7006 return false;
7007 // Different semantically, compare by computation order
7008 return wasComputedBefore(LHS, RHS);
7009 }
7010 if (!DepthLHS.has_value())
7011 return true; // LHS has lower complexity
7012 if (!DepthRHS.has_value())
7013 return false; // RHS has lower complexity
7014
7015 // Both have values, compare by depth (lower depth = lower complexity)
7016 if (DepthLHS.value() != DepthRHS.value())
7017 return DepthLHS.value() < DepthRHS.value();
7018
7019 // Same complexity, now check semantic equality
7020 if (areEqual(LHS, RHS))
7021 return false;
7022 // Different semantically, compare by computation order
7023 return wasComputedBefore(LHS, RHS);
7024 }
7025
7026 public:
7027 /// Return true if \p LHS and \p RHS are semantically equal. Uses pre-cached
7028 /// results, if available, otherwise does a recursive semantic comparison.
7029 bool areEqual(const Expr *LHS, const Expr *RHS) const {
7030 // Check cache first for faster lookup
7031 const auto CachedResultIt = CachedEqualityComparisons.find({LHS, RHS});
7032 if (CachedResultIt != CachedEqualityComparisons.end())
7033 return CachedResultIt->second;
7034
7035 bool ComparisonResult = areSemanticallyEqual(LHS, RHS);
7036
7037 // Cache the result for future lookups (both orders since semantic
7038 // equality is commutative)
7039 CachedEqualityComparisons[{LHS, RHS}] = ComparisonResult;
7040 CachedEqualityComparisons[{RHS, LHS}] = ComparisonResult;
7041 return ComparisonResult;
7042 }
7043
7044 /// Compare the two attach-ptr expressions by their computation order.
7045 /// Returns true iff LHS was computed before RHS by
7046 /// collectAttachPtrExprInfo().
7047 bool wasComputedBefore(const Expr *LHS, const Expr *RHS) const {
7048 const size_t &OrderLHS = Handler.AttachPtrComputationOrderMap.at(LHS);
7049 const size_t &OrderRHS = Handler.AttachPtrComputationOrderMap.at(RHS);
7050
7051 return OrderLHS < OrderRHS;
7052 }
7053
7054 private:
7055 /// Helper function to compare attach-pointer expressions semantically.
7056 /// This function handles various expression types that can be part of an
7057 /// attach-pointer.
7058 /// TODO: Not urgent, but we should ideally return true when comparing
7059 /// `p[10]`, `*(p + 10)`, `*(p + 5 + 5)`, `p[10:1]` etc.
7060 bool areSemanticallyEqual(const Expr *LHS, const Expr *RHS) const {
7061 if (LHS == RHS)
7062 return true;
7063
7064 // If only one is null, they aren't equal
7065 if (!LHS || !RHS)
7066 return false;
7067
7068 ASTContext &Ctx = Handler.CGF.getContext();
7069 // Strip away parentheses and no-op casts to get to the core expression
7070 LHS = LHS->IgnoreParenNoopCasts(Ctx);
7071 RHS = RHS->IgnoreParenNoopCasts(Ctx);
7072
7073 // Direct pointer comparison of the underlying expressions
7074 if (LHS == RHS)
7075 return true;
7076
7077 // Check if the expression classes match
7078 if (LHS->getStmtClass() != RHS->getStmtClass())
7079 return false;
7080
7081 // Handle DeclRefExpr (variable references)
7082 if (const auto *LD = dyn_cast<DeclRefExpr>(LHS)) {
7083 const auto *RD = dyn_cast<DeclRefExpr>(RHS);
7084 if (!RD)
7085 return false;
7086 return LD->getDecl()->getCanonicalDecl() ==
7087 RD->getDecl()->getCanonicalDecl();
7088 }
7089
7090 // Handle ArraySubscriptExpr (array indexing like a[i])
7091 if (const auto *LA = dyn_cast<ArraySubscriptExpr>(LHS)) {
7092 const auto *RA = dyn_cast<ArraySubscriptExpr>(RHS);
7093 if (!RA)
7094 return false;
7095 return areSemanticallyEqual(LA->getBase(), RA->getBase()) &&
7096 areSemanticallyEqual(LA->getIdx(), RA->getIdx());
7097 }
7098
7099 // Handle MemberExpr (member access like s.m or p->m)
7100 if (const auto *LM = dyn_cast<MemberExpr>(LHS)) {
7101 const auto *RM = dyn_cast<MemberExpr>(RHS);
7102 if (!RM)
7103 return false;
7104 if (LM->getMemberDecl()->getCanonicalDecl() !=
7105 RM->getMemberDecl()->getCanonicalDecl())
7106 return false;
7107 return areSemanticallyEqual(LM->getBase(), RM->getBase());
7108 }
7109
7110 // Handle UnaryOperator (unary operations like *p, &x, etc.)
7111 if (const auto *LU = dyn_cast<UnaryOperator>(LHS)) {
7112 const auto *RU = dyn_cast<UnaryOperator>(RHS);
7113 if (!RU)
7114 return false;
7115 if (LU->getOpcode() != RU->getOpcode())
7116 return false;
7117 return areSemanticallyEqual(LU->getSubExpr(), RU->getSubExpr());
7118 }
7119
7120 // Handle BinaryOperator (binary operations like p + offset)
7121 if (const auto *LB = dyn_cast<BinaryOperator>(LHS)) {
7122 const auto *RB = dyn_cast<BinaryOperator>(RHS);
7123 if (!RB)
7124 return false;
7125 if (LB->getOpcode() != RB->getOpcode())
7126 return false;
7127 return areSemanticallyEqual(LB->getLHS(), RB->getLHS()) &&
7128 areSemanticallyEqual(LB->getRHS(), RB->getRHS());
7129 }
7130
7131 // Handle ArraySectionExpr (array sections like a[0:1])
7132 // Attach pointers should not contain array-sections, but currently we
7133 // don't emit an error.
7134 if (const auto *LAS = dyn_cast<ArraySectionExpr>(LHS)) {
7135 const auto *RAS = dyn_cast<ArraySectionExpr>(RHS);
7136 if (!RAS)
7137 return false;
7138 return areSemanticallyEqual(LAS->getBase(), RAS->getBase()) &&
7139 areSemanticallyEqual(LAS->getLowerBound(),
7140 RAS->getLowerBound()) &&
7141 areSemanticallyEqual(LAS->getLength(), RAS->getLength());
7142 }
7143
7144 // Handle CastExpr (explicit casts)
7145 if (const auto *LC = dyn_cast<CastExpr>(LHS)) {
7146 const auto *RC = dyn_cast<CastExpr>(RHS);
7147 if (!RC)
7148 return false;
7149 if (LC->getCastKind() != RC->getCastKind())
7150 return false;
7151 return areSemanticallyEqual(LC->getSubExpr(), RC->getSubExpr());
7152 }
7153
7154 // Handle CXXThisExpr (this pointer)
7155 if (isa<CXXThisExpr>(LHS) && isa<CXXThisExpr>(RHS))
7156 return true;
7157
7158 // Handle IntegerLiteral (integer constants)
7159 if (const auto *LI = dyn_cast<IntegerLiteral>(LHS)) {
7160 const auto *RI = dyn_cast<IntegerLiteral>(RHS);
7161 if (!RI)
7162 return false;
7163 return LI->getValue() == RI->getValue();
7164 }
7165
7166 // Handle CharacterLiteral (character constants)
7167 if (const auto *LC = dyn_cast<CharacterLiteral>(LHS)) {
7168 const auto *RC = dyn_cast<CharacterLiteral>(RHS);
7169 if (!RC)
7170 return false;
7171 return LC->getValue() == RC->getValue();
7172 }
7173
7174 // Handle FloatingLiteral (floating point constants)
7175 if (const auto *LF = dyn_cast<FloatingLiteral>(LHS)) {
7176 const auto *RF = dyn_cast<FloatingLiteral>(RHS);
7177 if (!RF)
7178 return false;
7179 // Use bitwise comparison for floating point literals
7180 return LF->getValue().bitwiseIsEqual(RF->getValue());
7181 }
7182
7183 // Handle StringLiteral (string constants)
7184 if (const auto *LS = dyn_cast<StringLiteral>(LHS)) {
7185 const auto *RS = dyn_cast<StringLiteral>(RHS);
7186 if (!RS)
7187 return false;
7188 return LS->getString() == RS->getString();
7189 }
7190
7191 // Handle CXXNullPtrLiteralExpr (nullptr)
7193 return true;
7194
7195 // Handle CXXBoolLiteralExpr (true/false)
7196 if (const auto *LB = dyn_cast<CXXBoolLiteralExpr>(LHS)) {
7197 const auto *RB = dyn_cast<CXXBoolLiteralExpr>(RHS);
7198 if (!RB)
7199 return false;
7200 return LB->getValue() == RB->getValue();
7201 }
7202
7203 // Fallback for other forms - use the existing comparison method
7204 return Expr::isSameComparisonOperand(LHS, RHS);
7205 }
7206 };
7207
7208 /// Get the offset of the OMP_MAP_MEMBER_OF field.
7209 static unsigned getFlagMemberOffset() {
7210 unsigned Offset = 0;
7211 for (uint64_t Remain =
7212 static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
7213 OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF);
7214 !(Remain & 1); Remain = Remain >> 1)
7215 Offset++;
7216 return Offset;
7217 }
7218
7219 /// Class that holds debugging information for a data mapping to be passed to
7220 /// the runtime library.
7221 class MappingExprInfo {
7222 /// The variable declaration used for the data mapping.
7223 const ValueDecl *MapDecl = nullptr;
7224 /// The original expression used in the map clause, or null if there is
7225 /// none.
7226 const Expr *MapExpr = nullptr;
7227
7228 public:
7229 MappingExprInfo(const ValueDecl *MapDecl, const Expr *MapExpr = nullptr)
7230 : MapDecl(MapDecl), MapExpr(MapExpr) {}
7231
7232 const ValueDecl *getMapDecl() const { return MapDecl; }
7233 const Expr *getMapExpr() const { return MapExpr; }
7234 };
7235
7236 using DeviceInfoTy = llvm::OpenMPIRBuilder::DeviceInfoTy;
7237 using MapBaseValuesArrayTy = llvm::OpenMPIRBuilder::MapValuesArrayTy;
7238 using MapValuesArrayTy = llvm::OpenMPIRBuilder::MapValuesArrayTy;
7239 using MapFlagsArrayTy = llvm::OpenMPIRBuilder::MapFlagsArrayTy;
7240 using MapDimArrayTy = llvm::OpenMPIRBuilder::MapDimArrayTy;
7241 using MapNonContiguousArrayTy =
7242 llvm::OpenMPIRBuilder::MapNonContiguousArrayTy;
7243 using MapExprsArrayTy = SmallVector<MappingExprInfo, 4>;
7244 using MapValueDeclsArrayTy = SmallVector<const ValueDecl *, 4>;
7245 using MapData =
7247 OpenMPMapClauseKind, ArrayRef<OpenMPMapModifierKind>,
7248 bool /*IsImplicit*/, const ValueDecl *, const Expr *>;
7249 using MapDataArrayTy = SmallVector<MapData, 4>;
7250
7251 /// This structure contains combined information generated for mappable
7252 /// clauses, including base pointers, pointers, sizes, map types, user-defined
7253 /// mappers, and non-contiguous information.
7254 struct MapCombinedInfoTy : llvm::OpenMPIRBuilder::MapInfosTy {
7255 MapExprsArrayTy Exprs;
7256 MapValueDeclsArrayTy Mappers;
7257 MapValueDeclsArrayTy DevicePtrDecls;
7258
7259 /// Append arrays in \a CurInfo.
7260 void append(MapCombinedInfoTy &CurInfo) {
7261 Exprs.append(CurInfo.Exprs.begin(), CurInfo.Exprs.end());
7262 DevicePtrDecls.append(CurInfo.DevicePtrDecls.begin(),
7263 CurInfo.DevicePtrDecls.end());
7264 Mappers.append(CurInfo.Mappers.begin(), CurInfo.Mappers.end());
7265 llvm::OpenMPIRBuilder::MapInfosTy::append(CurInfo);
7266 }
7267 };
7268
7269 /// Map between a struct and the its lowest & highest elements which have been
7270 /// mapped.
7271 /// [ValueDecl *] --> {LE(FieldIndex, Pointer),
7272 /// HE(FieldIndex, Pointer)}
7273 struct StructRangeInfoTy {
7274 MapCombinedInfoTy PreliminaryMapData;
7275 std::pair<unsigned /*FieldIndex*/, Address /*Pointer*/> LowestElem = {
7276 0, Address::invalid()};
7277 std::pair<unsigned /*FieldIndex*/, Address /*Pointer*/> HighestElem = {
7278 0, Address::invalid()};
7281 bool IsArraySection = false;
7282 bool HasCompleteRecord = false;
7283 };
7284
7285 /// A struct to store the attach pointer and pointee information, to be used
7286 /// when emitting an attach entry.
7287 struct AttachInfoTy {
7288 Address AttachPtrAddr = Address::invalid();
7289 Address AttachPteeAddr = Address::invalid();
7290 const ValueDecl *AttachPtrDecl = nullptr;
7291 const Expr *AttachMapExpr = nullptr;
7292
7293 bool isValid() const {
7294 return AttachPtrAddr.isValid() && AttachPteeAddr.isValid();
7295 }
7296 };
7297
7298 /// Check if there's any component list where the attach pointer expression
7299 /// matches the given captured variable.
7300 bool hasAttachEntryForCapturedVar(const ValueDecl *VD) const {
7301 for (const auto &AttachEntry : AttachPtrExprMap) {
7302 if (AttachEntry.second) {
7303 // Check if the attach pointer expression is a DeclRefExpr that
7304 // references the captured variable
7305 if (const auto *DRE = dyn_cast<DeclRefExpr>(AttachEntry.second))
7306 if (DRE->getDecl() == VD)
7307 return true;
7308 }
7309 }
7310 return false;
7311 }
7312
7313 /// Get the previously-cached attach pointer for a component list, if-any.
7314 const Expr *getAttachPtrExpr(
7316 const {
7317 const auto It = AttachPtrExprMap.find(Components);
7318 if (It != AttachPtrExprMap.end())
7319 return It->second;
7320
7321 return nullptr;
7322 }
7323
7324private:
7325 /// Kind that defines how a device pointer has to be returned.
7326 struct MapInfo {
7329 ArrayRef<OpenMPMapModifierKind> MapModifiers;
7330 ArrayRef<OpenMPMotionModifierKind> MotionModifiers;
7331 bool ReturnDevicePointer = false;
7332 bool IsImplicit = false;
7333 const ValueDecl *Mapper = nullptr;
7334 const Expr *VarRef = nullptr;
7335 bool ForDeviceAddr = false;
7336 bool HasUdpFbNullify = false;
7337
7338 MapInfo() = default;
7339 MapInfo(
7341 OpenMPMapClauseKind MapType,
7342 ArrayRef<OpenMPMapModifierKind> MapModifiers,
7343 ArrayRef<OpenMPMotionModifierKind> MotionModifiers,
7344 bool ReturnDevicePointer, bool IsImplicit,
7345 const ValueDecl *Mapper = nullptr, const Expr *VarRef = nullptr,
7346 bool ForDeviceAddr = false, bool HasUdpFbNullify = false)
7347 : Components(Components), MapType(MapType), MapModifiers(MapModifiers),
7348 MotionModifiers(MotionModifiers),
7349 ReturnDevicePointer(ReturnDevicePointer), IsImplicit(IsImplicit),
7350 Mapper(Mapper), VarRef(VarRef), ForDeviceAddr(ForDeviceAddr),
7351 HasUdpFbNullify(HasUdpFbNullify) {}
7352 };
7353
7354 /// The target directive from where the mappable clauses were extracted. It
7355 /// is either a executable directive or a user-defined mapper directive.
7356 llvm::PointerUnion<const OMPExecutableDirective *,
7357 const OMPDeclareMapperDecl *>
7358 CurDir;
7359
7360 /// Function the directive is being generated for.
7361 CodeGenFunction &CGF;
7362
7363 /// Set of all first private variables in the current directive.
7364 /// bool data is set to true if the variable is implicitly marked as
7365 /// firstprivate, false otherwise.
7366 llvm::DenseMap<CanonicalDeclPtr<const VarDecl>, bool> FirstPrivateDecls;
7367
7368 /// Set of defaultmap clause kinds that use firstprivate behavior.
7369 llvm::SmallSet<OpenMPDefaultmapClauseKind, 4> DefaultmapFirstprivateKinds;
7370
7371 /// Map between device pointer declarations and their expression components.
7372 /// The key value for declarations in 'this' is null.
7373 llvm::DenseMap<
7374 const ValueDecl *,
7375 SmallVector<OMPClauseMappableExprCommon::MappableExprComponentListRef, 4>>
7376 DevPointersMap;
7377
7378 /// Map between device addr declarations and their expression components.
7379 /// The key value for declarations in 'this' is null.
7380 llvm::DenseMap<
7381 const ValueDecl *,
7382 SmallVector<OMPClauseMappableExprCommon::MappableExprComponentListRef, 4>>
7383 HasDevAddrsMap;
7384
7385 /// Map between lambda declarations and their map type.
7386 llvm::DenseMap<const ValueDecl *, const OMPMapClause *> LambdasMap;
7387
7388 /// Map from component lists to their attach pointer expressions.
7390 const Expr *>
7391 AttachPtrExprMap;
7392
7393 /// Map from attach pointer expressions to their component depth.
7394 /// nullptr key has std::nullopt depth. This can be used to order attach-ptr
7395 /// expressions with increasing/decreasing depth.
7396 /// The component-depth of `nullptr` (i.e. no attach-ptr) is `std::nullopt`.
7397 /// TODO: Not urgent, but we should ideally use the number of pointer
7398 /// dereferences in an expr as an indicator of its complexity, instead of the
7399 /// component-depth. That would be needed for us to treat `p[1]`, `*(p + 10)`,
7400 /// `*(p + 5 + 5)` together.
7401 llvm::DenseMap<const Expr *, std::optional<size_t>>
7402 AttachPtrComponentDepthMap = {{nullptr, std::nullopt}};
7403
7404 /// Map from attach pointer expressions to the order they were computed in, in
7405 /// collectAttachPtrExprInfo().
7406 llvm::DenseMap<const Expr *, size_t> AttachPtrComputationOrderMap = {
7407 {nullptr, 0}};
7408
7409 /// An instance of attach-ptr-expr comparator that can be used throughout the
7410 /// lifetime of this handler.
7411 AttachPtrExprComparator AttachPtrComparator;
7412
7413 llvm::Value *getExprTypeSize(const Expr *E) const {
7414 QualType ExprTy = E->getType().getCanonicalType();
7415
7416 // Calculate the size for array shaping expression.
7417 if (const auto *OAE = dyn_cast<OMPArrayShapingExpr>(E)) {
7418 llvm::Value *Size =
7419 CGF.getTypeSize(OAE->getBase()->getType()->getPointeeType());
7420 for (const Expr *SE : OAE->getDimensions()) {
7421 llvm::Value *Sz = CGF.EmitScalarExpr(SE);
7422 Sz = CGF.EmitScalarConversion(Sz, SE->getType(),
7423 CGF.getContext().getSizeType(),
7424 SE->getExprLoc());
7425 Size = CGF.Builder.CreateNUWMul(Size, Sz);
7426 }
7427 return Size;
7428 }
7429
7430 // Reference types are ignored for mapping purposes.
7431 if (const auto *RefTy = ExprTy->getAs<ReferenceType>())
7432 ExprTy = RefTy->getPointeeType().getCanonicalType();
7433
7434 // Given that an array section is considered a built-in type, we need to
7435 // do the calculation based on the length of the section instead of relying
7436 // on CGF.getTypeSize(E->getType()).
7437 if (const auto *OAE = dyn_cast<ArraySectionExpr>(E)) {
7438 QualType BaseTy = ArraySectionExpr::getBaseOriginalType(
7439 OAE->getBase()->IgnoreParenImpCasts())
7441
7442 // If there is no length associated with the expression and lower bound is
7443 // not specified too, that means we are using the whole length of the
7444 // base.
7445 if (!OAE->getLength() && OAE->getColonLocFirst().isValid() &&
7446 !OAE->getLowerBound())
7447 return CGF.getTypeSize(BaseTy);
7448
7449 llvm::Value *ElemSize;
7450 if (const auto *PTy = BaseTy->getAs<PointerType>()) {
7451 ElemSize = CGF.getTypeSize(PTy->getPointeeType().getCanonicalType());
7452 } else {
7453 const auto *ATy = cast<ArrayType>(BaseTy.getTypePtr());
7454 assert(ATy && "Expecting array type if not a pointer type.");
7455 ElemSize = CGF.getTypeSize(ATy->getElementType().getCanonicalType());
7456 }
7457
7458 // If we don't have a length at this point, that is because we have an
7459 // array section with a single element.
7460 if (!OAE->getLength() && OAE->getColonLocFirst().isInvalid())
7461 return ElemSize;
7462
7463 if (const Expr *LenExpr = OAE->getLength()) {
7464 llvm::Value *LengthVal = CGF.EmitScalarExpr(LenExpr);
7465 LengthVal = CGF.EmitScalarConversion(LengthVal, LenExpr->getType(),
7466 CGF.getContext().getSizeType(),
7467 LenExpr->getExprLoc());
7468 return CGF.Builder.CreateNUWMul(LengthVal, ElemSize);
7469 }
7470 assert(!OAE->getLength() && OAE->getColonLocFirst().isValid() &&
7471 OAE->getLowerBound() && "expected array_section[lb:].");
7472 // Size = sizetype - lb * elemtype;
7473 llvm::Value *LengthVal = CGF.getTypeSize(BaseTy);
7474 llvm::Value *LBVal = CGF.EmitScalarExpr(OAE->getLowerBound());
7475 LBVal = CGF.EmitScalarConversion(LBVal, OAE->getLowerBound()->getType(),
7476 CGF.getContext().getSizeType(),
7477 OAE->getLowerBound()->getExprLoc());
7478 LBVal = CGF.Builder.CreateNUWMul(LBVal, ElemSize);
7479 llvm::Value *Cmp = CGF.Builder.CreateICmpUGT(LengthVal, LBVal);
7480 llvm::Value *TrueVal = CGF.Builder.CreateNUWSub(LengthVal, LBVal);
7481 LengthVal = CGF.Builder.CreateSelect(
7482 Cmp, TrueVal, llvm::ConstantInt::get(CGF.SizeTy, 0));
7483 return LengthVal;
7484 }
7485 return CGF.getTypeSize(ExprTy);
7486 }
7487
7488 /// Return the corresponding bits for a given map clause modifier. Add
7489 /// a flag marking the map as a pointer if requested. Add a flag marking the
7490 /// map as the first one of a series of maps that relate to the same map
7491 /// expression.
7492 OpenMPOffloadMappingFlags getMapTypeBits(
7493 OpenMPMapClauseKind MapType, ArrayRef<OpenMPMapModifierKind> MapModifiers,
7494 ArrayRef<OpenMPMotionModifierKind> MotionModifiers, bool IsImplicit,
7495 bool AddPtrFlag, bool AddIsTargetParamFlag, bool IsNonContiguous) const {
7496 OpenMPOffloadMappingFlags Bits =
7497 IsImplicit ? OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT
7498 : OpenMPOffloadMappingFlags::OMP_MAP_NONE;
7499 switch (MapType) {
7500 case OMPC_MAP_alloc:
7501 case OMPC_MAP_release:
7502 // alloc and release is the default behavior in the runtime library, i.e.
7503 // if we don't pass any bits alloc/release that is what the runtime is
7504 // going to do. Therefore, we don't need to signal anything for these two
7505 // type modifiers.
7506 break;
7507 case OMPC_MAP_to:
7508 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_TO;
7509 break;
7510 case OMPC_MAP_from:
7511 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_FROM;
7512 break;
7513 case OMPC_MAP_tofrom:
7514 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_TO |
7515 OpenMPOffloadMappingFlags::OMP_MAP_FROM;
7516 break;
7517 case OMPC_MAP_delete:
7518 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_DELETE;
7519 break;
7520 case OMPC_MAP_unknown:
7521 llvm_unreachable("Unexpected map type!");
7522 }
7523 if (AddPtrFlag)
7524 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ;
7525 if (AddIsTargetParamFlag)
7526 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM;
7527 if (llvm::is_contained(MapModifiers, OMPC_MAP_MODIFIER_always))
7528 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_ALWAYS;
7529 if (llvm::is_contained(MapModifiers, OMPC_MAP_MODIFIER_close))
7530 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_CLOSE;
7531 if (llvm::is_contained(MapModifiers, OMPC_MAP_MODIFIER_present) ||
7532 llvm::is_contained(MotionModifiers, OMPC_MOTION_MODIFIER_present))
7533 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_PRESENT;
7534 if (llvm::is_contained(MapModifiers, OMPC_MAP_MODIFIER_ompx_hold))
7535 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_OMPX_HOLD;
7536 if (IsNonContiguous)
7537 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_NON_CONTIG;
7538 return Bits;
7539 }
7540
7541 /// Return true if the provided expression is a final array section. A
7542 /// final array section, is one whose length can't be proved to be one.
7543 bool isFinalArraySectionExpression(const Expr *E) const {
7544 const auto *OASE = dyn_cast<ArraySectionExpr>(E);
7545
7546 // It is not an array section and therefore not a unity-size one.
7547 if (!OASE)
7548 return false;
7549
7550 // An array section with no colon always refer to a single element.
7551 if (OASE->getColonLocFirst().isInvalid())
7552 return false;
7553
7554 const Expr *Length = OASE->getLength();
7555
7556 // If we don't have a length we have to check if the array has size 1
7557 // for this dimension. Also, we should always expect a length if the
7558 // base type is pointer.
7559 if (!Length) {
7560 QualType BaseQTy = ArraySectionExpr::getBaseOriginalType(
7561 OASE->getBase()->IgnoreParenImpCasts())
7563 if (const auto *ATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr()))
7564 return ATy->getSExtSize() != 1;
7565 // If we don't have a constant dimension length, we have to consider
7566 // the current section as having any size, so it is not necessarily
7567 // unitary. If it happen to be unity size, that's user fault.
7568 return true;
7569 }
7570
7571 // Check if the length evaluates to 1.
7572 Expr::EvalResult Result;
7573 if (!Length->EvaluateAsInt(Result, CGF.getContext()))
7574 return true; // Can have more that size 1.
7575
7576 llvm::APSInt ConstLength = Result.Val.getInt();
7577 return ConstLength.getSExtValue() != 1;
7578 }
7579
7580 /// Emit an attach entry into \p CombinedInfo, using the information from \p
7581 /// AttachInfo. For example, for a map of form `int *p; ... map(p[1:10])`,
7582 /// an attach entry has the following form:
7583 /// &p, &p[1], sizeof(void*), ATTACH
7584 void emitAttachEntry(CodeGenFunction &CGF, MapCombinedInfoTy &CombinedInfo,
7585 const AttachInfoTy &AttachInfo) const {
7586 assert(AttachInfo.isValid() &&
7587 "Expected valid attach pointer/pointee information!");
7588
7589 // Size is the size of the pointer itself - use pointer size, not BaseDecl
7590 // size
7591 llvm::Value *PointerSize = CGF.Builder.CreateIntCast(
7592 llvm::ConstantInt::get(
7593 CGF.CGM.SizeTy, CGF.getContext()
7595 .getQuantity()),
7596 CGF.Int64Ty, /*isSigned=*/true);
7597
7598 CombinedInfo.Exprs.emplace_back(AttachInfo.AttachPtrDecl,
7599 AttachInfo.AttachMapExpr);
7600 CombinedInfo.BasePointers.push_back(
7601 AttachInfo.AttachPtrAddr.emitRawPointer(CGF));
7602 CombinedInfo.DevicePtrDecls.push_back(nullptr);
7603 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
7604 CombinedInfo.Pointers.push_back(
7605 AttachInfo.AttachPteeAddr.emitRawPointer(CGF));
7606 CombinedInfo.Sizes.push_back(PointerSize);
7607 CombinedInfo.Types.push_back(OpenMPOffloadMappingFlags::OMP_MAP_ATTACH);
7608 // ATTACH entries themselves don't "have" a base attach-ptr.
7609 CombinedInfo.HasAttachPtr.push_back(false);
7610 CombinedInfo.Mappers.push_back(nullptr);
7611 CombinedInfo.NonContigInfo.Dims.push_back(1);
7612 }
7613
7614 /// A helper class to copy structures with overlapped elements, i.e. those
7615 /// which have mappings of both "s" and "s.mem". Consecutive elements that
7616 /// are not explicitly copied have mapping nodes synthesized for them,
7617 /// taking care to avoid generating zero-sized copies.
7618 class CopyOverlappedEntryGaps {
7619 CodeGenFunction &CGF;
7620 MapCombinedInfoTy &CombinedInfo;
7621 OpenMPOffloadMappingFlags Flags = OpenMPOffloadMappingFlags::OMP_MAP_NONE;
7622 const ValueDecl *MapDecl = nullptr;
7623 const Expr *MapExpr = nullptr;
7625 bool IsNonContiguous = false;
7626 uint64_t DimSize = 0;
7627 // These elements track the position as the struct is iterated over
7628 // (in order of increasing element address).
7629 const RecordDecl *LastParent = nullptr;
7630 uint64_t Cursor = 0;
7631 unsigned LastIndex = -1u;
7633
7634 public:
7635 CopyOverlappedEntryGaps(CodeGenFunction &CGF,
7636 MapCombinedInfoTy &CombinedInfo,
7637 OpenMPOffloadMappingFlags Flags,
7638 const ValueDecl *MapDecl, const Expr *MapExpr,
7639 Address BP, Address LB, bool IsNonContiguous,
7640 uint64_t DimSize)
7641 : CGF(CGF), CombinedInfo(CombinedInfo), Flags(Flags), MapDecl(MapDecl),
7642 MapExpr(MapExpr), BP(BP), IsNonContiguous(IsNonContiguous),
7643 DimSize(DimSize), LB(LB) {}
7644
7645 void processField(
7646 const OMPClauseMappableExprCommon::MappableComponent &MC,
7647 const FieldDecl *FD,
7648 llvm::function_ref<LValue(CodeGenFunction &, const MemberExpr *)>
7649 EmitMemberExprBase) {
7650 const RecordDecl *RD = FD->getParent();
7651 const ASTRecordLayout &RL = CGF.getContext().getASTRecordLayout(RD);
7652 uint64_t FieldOffset = RL.getFieldOffset(FD->getFieldIndex());
7653 uint64_t FieldSize =
7655 Address ComponentLB = Address::invalid();
7656
7657 if (FD->getType()->isLValueReferenceType()) {
7658 const auto *ME = cast<MemberExpr>(MC.getAssociatedExpression());
7659 LValue BaseLVal = EmitMemberExprBase(CGF, ME);
7660 ComponentLB =
7661 CGF.EmitLValueForFieldInitialization(BaseLVal, FD).getAddress();
7662 } else {
7663 ComponentLB =
7665 }
7666
7667 if (!LastParent)
7668 LastParent = RD;
7669 if (FD->getParent() == LastParent) {
7670 if (FD->getFieldIndex() != LastIndex + 1)
7671 copyUntilField(FD, ComponentLB);
7672 } else {
7673 LastParent = FD->getParent();
7674 if (((int64_t)FieldOffset - (int64_t)Cursor) > 0)
7675 copyUntilField(FD, ComponentLB);
7676 }
7677 Cursor = FieldOffset + FieldSize;
7678 LastIndex = FD->getFieldIndex();
7679 LB = CGF.Builder.CreateConstGEP(ComponentLB, 1);
7680 }
7681
7682 void copyUntilField(const FieldDecl *FD, Address ComponentLB) {
7683 llvm::Value *ComponentLBPtr = ComponentLB.emitRawPointer(CGF);
7684 llvm::Value *LBPtr = LB.emitRawPointer(CGF);
7685 llvm::Value *Size = CGF.Builder.CreatePtrDiff(ComponentLBPtr, LBPtr);
7686 copySizedChunk(LBPtr, Size);
7687 }
7688
7689 void copyUntilEnd(Address HB) {
7690 if (LastParent) {
7691 const ASTRecordLayout &RL =
7692 CGF.getContext().getASTRecordLayout(LastParent);
7693 if ((uint64_t)CGF.getContext().toBits(RL.getSize()) <= Cursor)
7694 return;
7695 }
7696 llvm::Value *LBPtr = LB.emitRawPointer(CGF);
7697 llvm::Value *Size = CGF.Builder.CreatePtrDiff(
7698 CGF.Builder.CreateConstGEP(HB, 1).emitRawPointer(CGF), LBPtr);
7699 copySizedChunk(LBPtr, Size);
7700 }
7701
7702 void copySizedChunk(llvm::Value *Base, llvm::Value *Size) {
7703 CombinedInfo.Exprs.emplace_back(MapDecl, MapExpr);
7704 CombinedInfo.BasePointers.push_back(BP.emitRawPointer(CGF));
7705 CombinedInfo.DevicePtrDecls.push_back(nullptr);
7706 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
7707 CombinedInfo.Pointers.push_back(Base);
7708 CombinedInfo.Sizes.push_back(
7709 CGF.Builder.CreateIntCast(Size, CGF.Int64Ty, /*isSigned=*/false));
7710 CombinedInfo.Types.push_back(Flags);
7711 CombinedInfo.HasAttachPtr.push_back(false);
7712 CombinedInfo.Mappers.push_back(nullptr);
7713 CombinedInfo.NonContigInfo.Dims.push_back(IsNonContiguous ? DimSize : 1);
7714 }
7715 };
7716
7717 /// Generate the base pointers, section pointers, sizes, map type bits, and
7718 /// user-defined mappers (all included in \a CombinedInfo) for the provided
7719 /// map type, map or motion modifiers, and expression components.
7720 /// \a IsFirstComponent should be set to true if the provided set of
7721 /// components is the first associated with a capture.
7722 void generateInfoForComponentList(
7723 OpenMPMapClauseKind MapType, ArrayRef<OpenMPMapModifierKind> MapModifiers,
7724 ArrayRef<OpenMPMotionModifierKind> MotionModifiers,
7726 MapCombinedInfoTy &CombinedInfo,
7727 MapCombinedInfoTy &StructBaseCombinedInfo,
7728 StructRangeInfoTy &PartialStruct, AttachInfoTy &AttachInfo,
7729 bool IsFirstComponentList, bool IsImplicit,
7730 bool GenerateAllInfoForClauses, const ValueDecl *Mapper = nullptr,
7731 bool ForDeviceAddr = false, const ValueDecl *BaseDecl = nullptr,
7732 const Expr *MapExpr = nullptr,
7733 ArrayRef<OMPClauseMappableExprCommon::MappableExprComponentListRef>
7734 OverlappedElements = {}) const {
7735
7736 // The following summarizes what has to be generated for each map and the
7737 // types below. The generated information is expressed in this order:
7738 // base pointer, section pointer, size, flags
7739 // (to add to the ones that come from the map type and modifier).
7740 // Entries annotated with (+) are only generated for "target" constructs,
7741 // and only if the variable at the beginning of the expression is used in
7742 // the region.
7743 //
7744 // double d;
7745 // int i[100];
7746 // float *p;
7747 // int **a = &i;
7748 //
7749 // struct S1 {
7750 // int i;
7751 // float f[50];
7752 // }
7753 // struct S2 {
7754 // int i;
7755 // float f[50];
7756 // S1 s;
7757 // double *p;
7758 // double *&pref;
7759 // struct S2 *ps;
7760 // int &ref;
7761 // }
7762 // S2 s;
7763 // S2 *ps;
7764 //
7765 // map(d)
7766 // &d, &d, sizeof(double), TARGET_PARAM | TO | FROM
7767 //
7768 // map(i)
7769 // &i, &i, 100*sizeof(int), TARGET_PARAM | TO | FROM
7770 //
7771 // map(i[1:23])
7772 // &i(=&i[0]), &i[1], 23*sizeof(int), TARGET_PARAM | TO | FROM
7773 //
7774 // map(p)
7775 // &p, &p, sizeof(float*), TARGET_PARAM | TO | FROM
7776 //
7777 // map(p[1:24])
7778 // p, &p[1], 24*sizeof(float), TARGET_PARAM | TO | FROM // map pointee
7779 // &p, &p[1], sizeof(void*), ATTACH // attach pointer/pointee, if both
7780 // // are present, and either is new
7781 //
7782 // map(([22])p)
7783 // p, p, 22*sizeof(float), TARGET_PARAM | TO | FROM
7784 // &p, p, sizeof(void*), ATTACH
7785 //
7786 // map((*a)[0:3])
7787 // a, a, 0, TARGET_PARAM | IMPLICIT // (+)
7788 // (*a)[0], &(*a)[0], 3 * sizeof(int), TO | FROM
7789 // &(*a), &(*a)[0], sizeof(void*), ATTACH
7790 // (+) Only on target, if a is used in the region
7791 // Note: Since the attach base-pointer is `*a`, which is not a scalar
7792 // variable, it doesn't determine the clause on `a`. `a` is mapped using
7793 // a zero-length-array-section map by generateDefaultMapInfo, if it is
7794 // referenced in the target region, because it is a pointer.
7795 //
7796 // map(**a)
7797 // a, a, 0, TARGET_PARAM | IMPLICIT // (+)
7798 // &(*a)[0], &(*a)[0], sizeof(int), TO | FROM
7799 // &(*a), &(*a)[0], sizeof(void*), ATTACH
7800 // (+) Only on target, if a is used in the region
7801 //
7802 // map(s)
7803 // FIXME: This needs to also imply map(ref_ptr_ptee: s.ref), since the
7804 // effect is supposed to be same as if the user had a map for every element
7805 // of the struct. We currently do a shallow-map of s.
7806 // &s, &s, sizeof(S2), TARGET_PARAM | TO | FROM
7807 //
7808 // map(s.i)
7809 // &s, &(s.i), sizeof(int), TARGET_PARAM | TO | FROM
7810 //
7811 // map(s.s.f)
7812 // &s, &(s.s.f[0]), 50*sizeof(float), TARGET_PARAM | TO | FROM
7813 //
7814 // map(s.p)
7815 // &s, &(s.p), sizeof(double*), TARGET_PARAM | TO | FROM
7816 //
7817 // map(to: s.p[:22])
7818 // &s, &(s.p), sizeof(double*), TARGET_PARAM | IMPLICIT // (+)
7819 // &(s.p[0]), &(s.p[0]), 22 * sizeof(double*), TO | FROM
7820 // &(s.p), &(s.p[0]), sizeof(void*), ATTACH
7821 //
7822 // map(to: s.ref)
7823 // &s, &(ptr(s.ref)), sizeof(int*), TARGET_PARAM (*)
7824 // &s, &(ptee(s.ref)), sizeof(int), MEMBER_OF(1) | PTR_AND_OBJ | TO (***)
7825 // (*) alloc space for struct members, only this is a target parameter.
7826 // (**) map the pointer (nothing to be mapped in this example) (the compiler
7827 // optimizes this entry out, same in the examples below)
7828 // (***) map the pointee (map: to)
7829 // Note: ptr(s.ref) represents the referring pointer of s.ref
7830 // ptee(s.ref) represents the referenced pointee of s.ref
7831 //
7832 // map(to: s.pref)
7833 // &s, &(ptr(s.pref)), sizeof(double**), TARGET_PARAM
7834 // &s, &(ptee(s.pref)), sizeof(double*), MEMBER_OF(1) | PTR_AND_OBJ | TO
7835 //
7836 // map(to: s.pref[:22])
7837 // &s, &(ptr(s.pref)), sizeof(double**), TARGET_PARAM | IMPLICIT // (+)
7838 // &s, &(ptee(s.pref)), sizeof(double*), MEMBER_OF(1) | PTR_AND_OBJ | TO |
7839 // FROM | IMPLICIT // (+)
7840 // &(ptee(s.pref)[0]), &(ptee(s.pref)[0]), 22 * sizeof(double), TO
7841 // &(ptee(s.pref)), &(ptee(s.pref)[0]), sizeof(void*), ATTACH
7842 //
7843 // map(s.ps)
7844 // &s, &(s.ps), sizeof(S2*), TARGET_PARAM | TO | FROM
7845 //
7846 // map(from: s.ps->s.i)
7847 // &s, &(s.ps), sizeof(S2*), TARGET_PARAM | TO | FROM | IMPLICIT // (+)
7848 // &(s.ps[0]), &(s.ps->s.i), sizeof(int), FROM
7849 // &(s.ps), &(s.ps->s.i), sizeof(void*), ATTACH
7850 //
7851 // map(to: s.ps->ps)
7852 // &s, &(s.ps), sizeof(S2*), TARGET_PARAM | TO | FROM | IMPLICIT // (+)
7853 // &(s.ps[0]), &(s.ps->ps), sizeof(S2*), TO
7854 // &(s.ps), &(s.ps->ps), sizeof(void*), ATTACH
7855 //
7856 // map(s.ps->ps->ps)
7857 // &s, &(s.ps), sizeof(S2*), TARGET_PARAM | TO | FROM | IMPLICIT // (+)
7858 // &(s.ps->ps[0]), &(s.ps->ps->ps), sizeof(S2*), TO
7859 // &(s.ps->ps), &(s.ps->ps->ps), sizeof(void*), ATTACH
7860 //
7861 // map(to: s.ps->ps->s.f[:22])
7862 // &s, &(s.ps), sizeof(S2*), TARGET_PARAM | TO | FROM | IMPLICIT // (+)
7863 // &(s.ps->ps[0]), &(s.ps->ps->s.f[0]), 22*sizeof(float), TO
7864 // &(s.ps->ps), &(s.ps->ps->s.f[0]), sizeof(void*), ATTACH
7865 //
7866 // map(ps)
7867 // &ps, &ps, sizeof(S2*), TARGET_PARAM | TO | FROM
7868 //
7869 // map(ps->i)
7870 // ps, &(ps->i), sizeof(int), TARGET_PARAM | TO | FROM
7871 // &ps, &(ps->i), sizeof(void*), ATTACH
7872 //
7873 // map(ps->s.f)
7874 // ps, &(ps->s.f[0]), 50*sizeof(float), TARGET_PARAM | TO | FROM
7875 // &ps, &(ps->s.f[0]), sizeof(ps), ATTACH
7876 //
7877 // map(from: ps->p)
7878 // ps, &(ps->p), sizeof(double*), TARGET_PARAM | FROM
7879 // &ps, &(ps->p), sizeof(ps), ATTACH
7880 //
7881 // map(to: ps->p[:22])
7882 // ps, &(ps[0]), 0, TARGET_PARAM | IMPLICIT // (+)
7883 // &(ps->p[0]), &(ps->p[0]), 22*sizeof(double), TO
7884 // &(ps->p), &(ps->p[0]), sizeof(void*), ATTACH
7885 //
7886 // map(ps->ps)
7887 // ps, &(ps->ps), sizeof(S2*), TARGET_PARAM | TO | FROM
7888 // &ps, &(ps->ps), sizeof(ps), ATTACH
7889 //
7890 // map(from: ps->ps->s.i)
7891 // ps, &(ps[0]), 0, TARGET_PARAM | IMPLICIT // (+)
7892 // &(ps->ps[0]), &(ps->ps->s.i), sizeof(int), FROM
7893 // &(ps->ps), &(ps->ps->s.i), sizeof(void*), ATTACH
7894 //
7895 // map(from: ps->ps->ps)
7896 // ps, &ps[0], 0, TARGET_PARAM | IMPLICIT // (+)
7897 // &(ps->ps[0]), &(ps->ps->ps), sizeof(S2*), FROM
7898 // &(ps->ps), &(ps->ps->ps), sizeof(void*), ATTACH
7899 //
7900 // map(ps->ps->ps->ps)
7901 // ps, &ps[0], 0, TARGET_PARAM | IMPLICIT // (+)
7902 // &(ps->ps->ps[0]), &(ps->ps->ps->ps), sizeof(S2*), FROM
7903 // &(ps->ps->ps), &(ps->ps->ps->ps), sizeof(void*), ATTACH
7904 //
7905 // map(to: ps->ps->ps->s.f[:22])
7906 // ps, &ps[0], 0, TARGET_PARAM | IMPLICIT // (+)
7907 // &(ps->ps->ps[0]), &(ps->ps->ps->s.f[0]), 22*sizeof(float), TO
7908 // &(ps->ps->ps), &(ps->ps->ps->s.f[0]), sizeof(void*), ATTACH
7909 //
7910 // map(to: s.f[:22]) map(from: s.p[:33])
7911 // On target, and if s is used in the region:
7912 //
7913 // &s, &(s.f[0]), 50*sizeof(float) +
7914 // sizeof(struct S1) +
7915 // sizeof(double*) (**), TARGET_PARAM
7916 // &s, &(s.f[0]), 22*sizeof(float), MEMBER_OF(1) | TO
7917 // &s, &(s.p), sizeof(double*), MEMBER_OF(1) | TO |
7918 // FROM | IMPLICIT
7919 // &(s.p[0]), &(s.p[0]), 33*sizeof(double), FROM
7920 // &(s.p), &(s.p[0]), sizeof(void*), ATTACH
7921 // (**) allocate contiguous space needed to fit all mapped members even if
7922 // we allocate space for members not mapped (in this example,
7923 // s.f[22..49] and s.s are not mapped, yet we must allocate space for
7924 // them as well because they fall between &s.f[0] and &s.p)
7925 //
7926 // On other constructs, and, if s is not used in the region, on target:
7927 // &s, &(s.f[0]), 22*sizeof(float), TO
7928 // &(s.p[0]), &(s.p[0]), 33*sizeof(double), FROM
7929 // &(s.p), &(s.p[0]), sizeof(void*), ATTACH
7930 //
7931 // map(from: s.f[:22]) map(to: ps->p[:33])
7932 // &s, &(s.f[0]), 22*sizeof(float), TARGET_PARAM | FROM
7933 // &ps[0], &ps[0], 0, TARGET_PARAM | IMPLICIT // (+)
7934 // &(ps->p[0]), &(ps->p[0]), 33*sizeof(double), TO
7935 // &(ps->p), &(ps->p[0]), sizeof(void*), ATTACH
7936 //
7937 // map(from: s.f[:22], s.s) map(to: ps->p[:33])
7938 // &s, &(s.f[0]), 50*sizeof(float) +
7939 // sizeof(struct S1), TARGET_PARAM
7940 // &s, &(s.f[0]), 22*sizeof(float), MEMBER_OF(1) | FROM
7941 // &s, &(s.s), sizeof(struct S1), MEMBER_OF(1) | FROM
7942 // ps, &ps[0], 0, TARGET_PARAM | IMPLICIT // (+)
7943 // &(ps->p[0]), &(ps->p[0]), 33*sizeof(double), TO
7944 // &(ps->p), &(ps->p[0]), sizeof(void*), ATTACH
7945 //
7946 // map(p[:100], p)
7947 // &p, &p, sizeof(float*), TARGET_PARAM | TO | FROM
7948 // p, &p[0], 100*sizeof(float), TO | FROM
7949 // &p, &p[0], sizeof(float*), ATTACH
7950
7951 // Track if the map information being generated is the first for a capture.
7952 bool IsCaptureFirstInfo = IsFirstComponentList;
7953 // When the variable is on a declare target link or in a to clause with
7954 // unified memory, a reference is needed to hold the host/device address
7955 // of the variable.
7956 bool RequiresReference = false;
7957
7958 // Scan the components from the base to the complete expression.
7959 auto CI = Components.rbegin();
7960 auto CE = Components.rend();
7961 auto I = CI;
7962
7963 // Track if the map information being generated is the first for a list of
7964 // components.
7965 bool IsExpressionFirstInfo = true;
7966 bool FirstPointerInComplexData = false;
7968 Address FinalLowestElem = Address::invalid();
7969 const Expr *AssocExpr = I->getAssociatedExpression();
7970 const auto *AE = dyn_cast<ArraySubscriptExpr>(AssocExpr);
7971 const auto *OASE = dyn_cast<ArraySectionExpr>(AssocExpr);
7972 const auto *OAShE = dyn_cast<OMPArrayShapingExpr>(AssocExpr);
7973
7974 // Get the pointer-attachment base-pointer for the given list, if any.
7975 const Expr *AttachPtrExpr = getAttachPtrExpr(Components);
7976 auto [AttachPtrAddr, AttachPteeBaseAddr] =
7977 getAttachPtrAddrAndPteeBaseAddr(AttachPtrExpr, CGF);
7978
7979 bool HasAttachPtr = AttachPtrExpr != nullptr;
7980 bool FirstComponentIsForAttachPtr = AssocExpr == AttachPtrExpr;
7981 bool SeenAttachPtr = FirstComponentIsForAttachPtr;
7982
7983 if (FirstComponentIsForAttachPtr) {
7984 // No need to process AttachPtr here. It will be processed at the end
7985 // after we have computed the pointee's address.
7986 ++I;
7987 } else if (isa<MemberExpr>(AssocExpr)) {
7988 // The base is the 'this' pointer. The content of the pointer is going
7989 // to be the base of the field being mapped.
7990 BP = CGF.LoadCXXThisAddress();
7991 } else if ((AE && isa<CXXThisExpr>(AE->getBase()->IgnoreParenImpCasts())) ||
7992 (OASE &&
7993 isa<CXXThisExpr>(OASE->getBase()->IgnoreParenImpCasts()))) {
7994 BP = CGF.EmitOMPSharedLValue(AssocExpr).getAddress();
7995 } else if (OAShE &&
7996 isa<CXXThisExpr>(OAShE->getBase()->IgnoreParenCasts())) {
7997 BP = Address(
7998 CGF.EmitScalarExpr(OAShE->getBase()),
7999 CGF.ConvertTypeForMem(OAShE->getBase()->getType()->getPointeeType()),
8000 CGF.getContext().getTypeAlignInChars(OAShE->getBase()->getType()));
8001 } else {
8002 // The base is the reference to the variable.
8003 // BP = &Var.
8004 BP = CGF.EmitOMPSharedLValue(AssocExpr).getAddress();
8005 if (const auto *VD =
8006 dyn_cast_or_null<VarDecl>(I->getAssociatedDeclaration())) {
8007 if (std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
8008 OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD)) {
8009 if ((*Res == OMPDeclareTargetDeclAttr::MT_Link) ||
8010 ((*Res == OMPDeclareTargetDeclAttr::MT_To ||
8011 *Res == OMPDeclareTargetDeclAttr::MT_Enter) &&
8013 RequiresReference = true;
8015 }
8016 }
8017 }
8018
8019 // If the variable is a pointer and is being dereferenced (i.e. is not
8020 // the last component), the base has to be the pointer itself, not its
8021 // reference. References are ignored for mapping purposes.
8022 QualType Ty =
8023 I->getAssociatedDeclaration()->getType().getNonReferenceType();
8024 if (Ty->isAnyPointerType() && std::next(I) != CE) {
8025 // No need to generate individual map information for the pointer, it
8026 // can be associated with the combined storage if shared memory mode is
8027 // active or the base declaration is not global variable.
8028 const auto *VD = dyn_cast<VarDecl>(I->getAssociatedDeclaration());
8030 !VD || VD->hasLocalStorage() || HasAttachPtr)
8031 BP = CGF.EmitLoadOfPointer(BP, Ty->castAs<PointerType>());
8032 else
8033 FirstPointerInComplexData = true;
8034 ++I;
8035 }
8036 }
8037
8038 // Track whether a component of the list should be marked as MEMBER_OF some
8039 // combined entry (for partial structs). Only the first PTR_AND_OBJ entry
8040 // in a component list should be marked as MEMBER_OF, all subsequent entries
8041 // do not belong to the base struct. E.g.
8042 // struct S2 s;
8043 // s.ps->ps->ps->f[:]
8044 // (1) (2) (3) (4)
8045 // ps(1) is a member pointer, ps(2) is a pointee of ps(1), so it is a
8046 // PTR_AND_OBJ entry; the PTR is ps(1), so MEMBER_OF the base struct. ps(3)
8047 // is the pointee of ps(2) which is not member of struct s, so it should not
8048 // be marked as such (it is still PTR_AND_OBJ).
8049 // The variable is initialized to false so that PTR_AND_OBJ entries which
8050 // are not struct members are not considered (e.g. array of pointers to
8051 // data).
8052 bool ShouldBeMemberOf = false;
8053
8054 // Variable keeping track of whether or not we have encountered a component
8055 // in the component list which is a member expression. Useful when we have a
8056 // pointer or a final array section, in which case it is the previous
8057 // component in the list which tells us whether we have a member expression.
8058 // E.g. X.f[:]
8059 // While processing the final array section "[:]" it is "f" which tells us
8060 // whether we are dealing with a member of a declared struct.
8061 const MemberExpr *EncounteredME = nullptr;
8062
8063 // Track for the total number of dimension. Start from one for the dummy
8064 // dimension.
8065 uint64_t DimSize = 1;
8066
8067 // Detects non-contiguous updates due to strided accesses.
8068 // Sets the 'IsNonContiguous' flag so that the 'MapType' bits are set
8069 // correctly when generating information to be passed to the runtime. The
8070 // flag is set to true if any array section has a stride not equal to 1, or
8071 // if the stride is not a constant expression (conservatively assumed
8072 // non-contiguous).
8073 bool IsNonContiguous =
8074 CombinedInfo.NonContigInfo.IsNonContiguous ||
8075 any_of(Components, [&](const auto &Component) {
8076 const auto *OASE =
8077 dyn_cast<ArraySectionExpr>(Component.getAssociatedExpression());
8078 if (!OASE)
8079 return false;
8080
8081 const Expr *StrideExpr = OASE->getStride();
8082 if (!StrideExpr)
8083 return false;
8084
8085 assert(StrideExpr->getType()->isIntegerType() &&
8086 "Stride expression must be of integer type");
8087
8088 // If stride is not evaluatable as a constant, treat as
8089 // non-contiguous.
8090 const auto Constant =
8091 StrideExpr->getIntegerConstantExpr(CGF.getContext());
8092 if (!Constant)
8093 return true;
8094
8095 // Treat non-unitary strides as non-contiguous.
8096 return !Constant->isOne();
8097 });
8098
8099 bool IsPrevMemberReference = false;
8100
8101 bool IsPartialMapped =
8102 !PartialStruct.PreliminaryMapData.BasePointers.empty();
8103
8104 // We need to check if we will be encountering any MEs. If we do not
8105 // encounter any ME expression it means we will be mapping the whole struct.
8106 // In that case we need to skip adding an entry for the struct to the
8107 // CombinedInfo list and instead add an entry to the StructBaseCombinedInfo
8108 // list only when generating all info for clauses.
8109 bool IsMappingWholeStruct = true;
8110 if (!GenerateAllInfoForClauses) {
8111 IsMappingWholeStruct = false;
8112 } else {
8113 for (auto TempI = I; TempI != CE; ++TempI) {
8114 const MemberExpr *PossibleME =
8115 dyn_cast<MemberExpr>(TempI->getAssociatedExpression());
8116 if (PossibleME) {
8117 IsMappingWholeStruct = false;
8118 break;
8119 }
8120 }
8121 }
8122
8123 bool SeenFirstNonBinOpExprAfterAttachPtr = false;
8124 for (; I != CE; ++I) {
8125 // If we have a valid attach-ptr, we skip processing all components until
8126 // after the attach-ptr.
8127 if (HasAttachPtr && !SeenAttachPtr) {
8128 SeenAttachPtr = I->getAssociatedExpression() == AttachPtrExpr;
8129 continue;
8130 }
8131
8132 // After finding the attach pointer, skip binary-ops, to skip past
8133 // expressions like (p + 10), for a map like map(*(p + 10)), where p is
8134 // the attach-ptr.
8135 if (HasAttachPtr && !SeenFirstNonBinOpExprAfterAttachPtr) {
8136 const auto *BO = dyn_cast<BinaryOperator>(I->getAssociatedExpression());
8137 if (BO)
8138 continue;
8139
8140 // Found the first non-binary-operator component after attach
8141 SeenFirstNonBinOpExprAfterAttachPtr = true;
8142 BP = AttachPteeBaseAddr;
8143 }
8144
8145 // If the current component is member of a struct (parent struct) mark it.
8146 if (!EncounteredME) {
8147 EncounteredME = dyn_cast<MemberExpr>(I->getAssociatedExpression());
8148 // If we encounter a PTR_AND_OBJ entry from now on it should be marked
8149 // as MEMBER_OF the parent struct.
8150 if (EncounteredME) {
8151 ShouldBeMemberOf = true;
8152 // Do not emit as complex pointer if this is actually not array-like
8153 // expression.
8154 if (FirstPointerInComplexData) {
8155 QualType Ty = std::prev(I)
8156 ->getAssociatedDeclaration()
8157 ->getType()
8158 .getNonReferenceType();
8159 BP = CGF.EmitLoadOfPointer(BP, Ty->castAs<PointerType>());
8160 FirstPointerInComplexData = false;
8161 }
8162 }
8163 }
8164
8165 auto Next = std::next(I);
8166
8167 // We need to generate the addresses and sizes if this is the last
8168 // component, if the component is a pointer or if it is an array section
8169 // whose length can't be proved to be one. If this is a pointer, it
8170 // becomes the base address for the following components.
8171
8172 // A final array section, is one whose length can't be proved to be one.
8173 // If the map item is non-contiguous then we don't treat any array section
8174 // as final array section.
8175 bool IsFinalArraySection =
8176 !IsNonContiguous &&
8177 isFinalArraySectionExpression(I->getAssociatedExpression());
8178
8179 // If we have a declaration for the mapping use that, otherwise use
8180 // the base declaration of the map clause.
8181 const ValueDecl *MapDecl = (I->getAssociatedDeclaration())
8182 ? I->getAssociatedDeclaration()
8183 : BaseDecl;
8184 MapExpr = (I->getAssociatedExpression()) ? I->getAssociatedExpression()
8185 : MapExpr;
8186
8187 // Get information on whether the element is a pointer. Have to do a
8188 // special treatment for array sections given that they are built-in
8189 // types.
8190 const auto *OASE =
8191 dyn_cast<ArraySectionExpr>(I->getAssociatedExpression());
8192 const auto *OAShE =
8193 dyn_cast<OMPArrayShapingExpr>(I->getAssociatedExpression());
8194 const auto *UO = dyn_cast<UnaryOperator>(I->getAssociatedExpression());
8195 const auto *BO = dyn_cast<BinaryOperator>(I->getAssociatedExpression());
8196 bool IsPointer =
8197 OAShE ||
8200 ->isAnyPointerType()) ||
8201 I->getAssociatedExpression()->getType()->isAnyPointerType();
8202 bool IsMemberReference = isa<MemberExpr>(I->getAssociatedExpression()) &&
8203 MapDecl &&
8204 MapDecl->getType()->isLValueReferenceType();
8205 bool IsNonDerefPointer = IsPointer &&
8206 !(UO && UO->getOpcode() != UO_Deref) && !BO &&
8207 !IsNonContiguous;
8208
8209 if (OASE)
8210 ++DimSize;
8211
8212 if (Next == CE || IsMemberReference || IsNonDerefPointer ||
8213 IsFinalArraySection) {
8214 // If this is not the last component, we expect the pointer to be
8215 // associated with an array expression or member expression.
8216 assert((Next == CE ||
8217 isa<MemberExpr>(Next->getAssociatedExpression()) ||
8218 isa<ArraySubscriptExpr>(Next->getAssociatedExpression()) ||
8219 isa<ArraySectionExpr>(Next->getAssociatedExpression()) ||
8220 isa<OMPArrayShapingExpr>(Next->getAssociatedExpression()) ||
8221 isa<UnaryOperator>(Next->getAssociatedExpression()) ||
8222 isa<BinaryOperator>(Next->getAssociatedExpression())) &&
8223 "Unexpected expression");
8224
8226 Address LowestElem = Address::invalid();
8227 auto &&EmitMemberExprBase = [](CodeGenFunction &CGF,
8228 const MemberExpr *E) {
8229 const Expr *BaseExpr = E->getBase();
8230 // If this is s.x, emit s as an lvalue. If it is s->x, emit s as a
8231 // scalar.
8232 LValue BaseLV;
8233 if (E->isArrow()) {
8234 LValueBaseInfo BaseInfo;
8235 TBAAAccessInfo TBAAInfo;
8236 Address Addr =
8237 CGF.EmitPointerWithAlignment(BaseExpr, &BaseInfo, &TBAAInfo);
8238 QualType PtrTy = BaseExpr->getType()->getPointeeType();
8239 BaseLV = CGF.MakeAddrLValue(Addr, PtrTy, BaseInfo, TBAAInfo);
8240 } else {
8241 BaseLV = CGF.EmitOMPSharedLValue(BaseExpr);
8242 }
8243 return BaseLV;
8244 };
8245 if (OAShE) {
8246 LowestElem = LB =
8247 Address(CGF.EmitScalarExpr(OAShE->getBase()),
8249 OAShE->getBase()->getType()->getPointeeType()),
8251 OAShE->getBase()->getType()));
8252 } else if (IsMemberReference) {
8253 const auto *ME = cast<MemberExpr>(I->getAssociatedExpression());
8254 LValue BaseLVal = EmitMemberExprBase(CGF, ME);
8255 LowestElem = CGF.EmitLValueForFieldInitialization(
8256 BaseLVal, cast<FieldDecl>(MapDecl))
8257 .getAddress();
8258 LB = CGF.EmitLoadOfReferenceLValue(LowestElem, MapDecl->getType())
8259 .getAddress();
8260 } else {
8261 LowestElem = LB =
8262 CGF.EmitOMPSharedLValue(I->getAssociatedExpression())
8263 .getAddress();
8264 }
8265
8266 // Save the final LowestElem, to use it as the pointee in attach maps,
8267 // if emitted.
8268 if (Next == CE)
8269 FinalLowestElem = LowestElem;
8270
8271 // If this component is a pointer inside the base struct then we don't
8272 // need to create any entry for it - it will be combined with the object
8273 // it is pointing to into a single PTR_AND_OBJ entry.
8274 bool IsMemberPointerOrAddr =
8275 EncounteredME &&
8276 (((IsPointer || ForDeviceAddr) &&
8277 I->getAssociatedExpression() == EncounteredME) ||
8278 (IsPrevMemberReference && !IsPointer) ||
8279 (IsMemberReference && Next != CE &&
8280 !Next->getAssociatedExpression()->getType()->isPointerType()));
8281 if (!OverlappedElements.empty() && Next == CE) {
8282 // Handle base element with the info for overlapped elements.
8283 assert(!PartialStruct.Base.isValid() && "The base element is set.");
8284 assert(!IsPointer &&
8285 "Unexpected base element with the pointer type.");
8286 // Mark the whole struct as the struct that requires allocation on the
8287 // device.
8288 PartialStruct.LowestElem = {0, LowestElem};
8289 CharUnits TypeSize = CGF.getContext().getTypeSizeInChars(
8290 I->getAssociatedExpression()->getType());
8293 LowestElem, CGF.VoidPtrTy, CGF.Int8Ty),
8294 TypeSize.getQuantity() - 1);
8295 PartialStruct.HighestElem = {
8296 std::numeric_limits<decltype(
8297 PartialStruct.HighestElem.first)>::max(),
8298 HB};
8299 PartialStruct.Base = BP;
8300 PartialStruct.LB = LB;
8301 assert(
8302 PartialStruct.PreliminaryMapData.BasePointers.empty() &&
8303 "Overlapped elements must be used only once for the variable.");
8304 std::swap(PartialStruct.PreliminaryMapData, CombinedInfo);
8305 // Emit data for non-overlapped data.
8306 OpenMPOffloadMappingFlags Flags =
8307 OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF |
8308 getMapTypeBits(MapType, MapModifiers, MotionModifiers, IsImplicit,
8309 /*AddPtrFlag=*/false,
8310 /*AddIsTargetParamFlag=*/false, IsNonContiguous);
8311 CopyOverlappedEntryGaps CopyGaps(CGF, CombinedInfo, Flags, MapDecl,
8312 MapExpr, BP, LB, IsNonContiguous,
8313 DimSize);
8314 // Do bitcopy of all non-overlapped structure elements.
8316 Component : OverlappedElements) {
8317 for (const OMPClauseMappableExprCommon::MappableComponent &MC :
8318 Component) {
8319 if (const ValueDecl *VD = MC.getAssociatedDeclaration()) {
8320 if (const auto *FD = dyn_cast<FieldDecl>(VD)) {
8321 CopyGaps.processField(MC, FD, EmitMemberExprBase);
8322 }
8323 }
8324 }
8325 }
8326 CopyGaps.copyUntilEnd(HB);
8327 break;
8328 }
8329 llvm::Value *Size = getExprTypeSize(I->getAssociatedExpression());
8330 // Skip adding an entry in the CurInfo of this combined entry if the
8331 // whole struct is currently being mapped. The struct needs to be added
8332 // in the first position before any data internal to the struct is being
8333 // mapped.
8334 // Skip adding an entry in the CurInfo of this combined entry if the
8335 // PartialStruct.PreliminaryMapData.BasePointers has been mapped.
8336 if ((!IsMemberPointerOrAddr && !IsPartialMapped) ||
8337 (Next == CE && MapType != OMPC_MAP_unknown)) {
8338 if (!IsMappingWholeStruct) {
8339 CombinedInfo.Exprs.emplace_back(MapDecl, MapExpr);
8340 CombinedInfo.BasePointers.push_back(BP.emitRawPointer(CGF));
8341 CombinedInfo.DevicePtrDecls.push_back(nullptr);
8342 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
8343 CombinedInfo.Pointers.push_back(LB.emitRawPointer(CGF));
8344 CombinedInfo.Sizes.push_back(CGF.Builder.CreateIntCast(
8345 Size, CGF.Int64Ty, /*isSigned=*/true));
8346 CombinedInfo.NonContigInfo.Dims.push_back(IsNonContiguous ? DimSize
8347 : 1);
8348 } else {
8349 StructBaseCombinedInfo.Exprs.emplace_back(MapDecl, MapExpr);
8350 StructBaseCombinedInfo.BasePointers.push_back(
8351 BP.emitRawPointer(CGF));
8352 StructBaseCombinedInfo.DevicePtrDecls.push_back(nullptr);
8353 StructBaseCombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
8354 StructBaseCombinedInfo.Pointers.push_back(LB.emitRawPointer(CGF));
8355 StructBaseCombinedInfo.Sizes.push_back(CGF.Builder.CreateIntCast(
8356 Size, CGF.Int64Ty, /*isSigned=*/true));
8357 StructBaseCombinedInfo.NonContigInfo.Dims.push_back(
8358 IsNonContiguous ? DimSize : 1);
8359 }
8360
8361 // If Mapper is valid, the last component inherits the mapper.
8362 bool HasMapper = Mapper && Next == CE;
8363 if (!IsMappingWholeStruct)
8364 CombinedInfo.Mappers.push_back(HasMapper ? Mapper : nullptr);
8365 else
8366 StructBaseCombinedInfo.Mappers.push_back(HasMapper ? Mapper
8367 : nullptr);
8368
8369 // We need to add a pointer flag for each map that comes from the
8370 // same expression except for the first one. We also need to signal
8371 // this map is the first one that relates with the current capture
8372 // (there is a set of entries for each capture).
8373 OpenMPOffloadMappingFlags Flags = getMapTypeBits(
8374 MapType, MapModifiers, MotionModifiers, IsImplicit,
8375 !IsExpressionFirstInfo || RequiresReference ||
8376 FirstPointerInComplexData || IsMemberReference,
8377 IsCaptureFirstInfo && !RequiresReference, IsNonContiguous);
8378
8379 if (!IsExpressionFirstInfo || IsMemberReference) {
8380 // If we have a PTR_AND_OBJ pair where the OBJ is a pointer as well,
8381 // then we reset the TO/FROM/ALWAYS/DELETE/CLOSE flags.
8382 if (IsPointer || (IsMemberReference && Next != CE))
8383 Flags &= ~(OpenMPOffloadMappingFlags::OMP_MAP_TO |
8384 OpenMPOffloadMappingFlags::OMP_MAP_FROM |
8385 OpenMPOffloadMappingFlags::OMP_MAP_ALWAYS |
8386 OpenMPOffloadMappingFlags::OMP_MAP_DELETE |
8387 OpenMPOffloadMappingFlags::OMP_MAP_CLOSE);
8388
8389 if (ShouldBeMemberOf) {
8390 // Set placeholder value MEMBER_OF=FFFF to indicate that the flag
8391 // should be later updated with the correct value of MEMBER_OF.
8392 Flags |= OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF;
8393 // From now on, all subsequent PTR_AND_OBJ entries should not be
8394 // marked as MEMBER_OF.
8395 ShouldBeMemberOf = false;
8396 }
8397 }
8398
8399 if (!IsMappingWholeStruct) {
8400 CombinedInfo.Types.push_back(Flags);
8401 // HasAttachPtr marks pointee entries, which have a base attach-ptr.
8402 CombinedInfo.HasAttachPtr.push_back(HasAttachPtr);
8403 } else {
8404 StructBaseCombinedInfo.Types.push_back(Flags);
8405 StructBaseCombinedInfo.HasAttachPtr.push_back(HasAttachPtr);
8406 }
8407 }
8408
8409 // If we have encountered a member expression so far, keep track of the
8410 // mapped member. If the parent is "*this", then the value declaration
8411 // is nullptr.
8412 if (EncounteredME) {
8413 const auto *FD = cast<FieldDecl>(EncounteredME->getMemberDecl());
8414 unsigned FieldIndex = FD->getFieldIndex();
8415
8416 // Update info about the lowest and highest elements for this struct
8417 if (!PartialStruct.Base.isValid()) {
8418 PartialStruct.LowestElem = {FieldIndex, LowestElem};
8419 if (IsFinalArraySection && OASE) {
8420 Address HB =
8421 CGF.EmitArraySectionExpr(OASE, /*IsLowerBound=*/false)
8422 .getAddress();
8423 PartialStruct.HighestElem = {FieldIndex, HB};
8424 } else {
8425 PartialStruct.HighestElem = {FieldIndex, LowestElem};
8426 }
8427 PartialStruct.Base = BP;
8428 PartialStruct.LB = BP;
8429 } else if (FieldIndex < PartialStruct.LowestElem.first) {
8430 PartialStruct.LowestElem = {FieldIndex, LowestElem};
8431 } else if (FieldIndex > PartialStruct.HighestElem.first) {
8432 if (IsFinalArraySection && OASE) {
8433 Address HB =
8434 CGF.EmitArraySectionExpr(OASE, /*IsLowerBound=*/false)
8435 .getAddress();
8436 PartialStruct.HighestElem = {FieldIndex, HB};
8437 } else {
8438 PartialStruct.HighestElem = {FieldIndex, LowestElem};
8439 }
8440 }
8441 }
8442
8443 // Need to emit combined struct for array sections.
8444 if (IsFinalArraySection || IsNonContiguous)
8445 PartialStruct.IsArraySection = true;
8446
8447 // If we have a final array section, we are done with this expression.
8448 if (IsFinalArraySection)
8449 break;
8450
8451 // The pointer becomes the base for the next element.
8452 if (Next != CE)
8453 BP = IsMemberReference ? LowestElem : LB;
8454 if (!IsPartialMapped)
8455 IsExpressionFirstInfo = false;
8456 IsCaptureFirstInfo = false;
8457 FirstPointerInComplexData = false;
8458 IsPrevMemberReference = IsMemberReference;
8459 } else if (FirstPointerInComplexData) {
8460 QualType Ty = Components.rbegin()
8461 ->getAssociatedDeclaration()
8462 ->getType()
8463 .getNonReferenceType();
8464 BP = CGF.EmitLoadOfPointer(BP, Ty->castAs<PointerType>());
8465 FirstPointerInComplexData = false;
8466 }
8467 }
8468 // If ran into the whole component - allocate the space for the whole
8469 // record.
8470 if (!EncounteredME)
8471 PartialStruct.HasCompleteRecord = true;
8472
8473 // Populate ATTACH information for later processing by emitAttachEntry.
8474 if (shouldEmitAttachEntry(AttachPtrExpr, BaseDecl, CGF, CurDir)) {
8475 AttachInfo.AttachPtrAddr = AttachPtrAddr;
8476 AttachInfo.AttachPteeAddr = FinalLowestElem;
8477 AttachInfo.AttachPtrDecl = BaseDecl;
8478 AttachInfo.AttachMapExpr = MapExpr;
8479 }
8480
8481 if (!IsNonContiguous)
8482 return;
8483
8484 const ASTContext &Context = CGF.getContext();
8485
8486 // For supporting stride in array section, we need to initialize the first
8487 // dimension size as 1, first offset as 0, and first count as 1
8488 MapValuesArrayTy CurOffsets = {llvm::ConstantInt::get(CGF.CGM.Int64Ty, 0)};
8489 MapValuesArrayTy CurCounts;
8490 MapValuesArrayTy CurStrides = {llvm::ConstantInt::get(CGF.CGM.Int64Ty, 1)};
8491 MapValuesArrayTy DimSizes{llvm::ConstantInt::get(CGF.CGM.Int64Ty, 1)};
8492 uint64_t ElementTypeSize;
8493
8494 // Collect Size information for each dimension and get the element size as
8495 // the first Stride. For example, for `int arr[10][10]`, the DimSizes
8496 // should be [10, 10] and the first stride is 4 btyes.
8497 for (const OMPClauseMappableExprCommon::MappableComponent &Component :
8498 Components) {
8499 const Expr *AssocExpr = Component.getAssociatedExpression();
8500 const auto *OASE = dyn_cast<ArraySectionExpr>(AssocExpr);
8501
8502 if (!OASE)
8503 continue;
8504
8505 QualType Ty = ArraySectionExpr::getBaseOriginalType(OASE->getBase());
8506 auto *CAT = Context.getAsConstantArrayType(Ty);
8507 auto *VAT = Context.getAsVariableArrayType(Ty);
8508
8509 // We need all the dimension size except for the last dimension.
8510 assert((VAT || CAT || &Component == &*Components.begin()) &&
8511 "Should be either ConstantArray or VariableArray if not the "
8512 "first Component");
8513
8514 // Get element size if CurCounts is empty.
8515 if (CurCounts.empty()) {
8516 const Type *ElementType = nullptr;
8517 if (CAT)
8518 ElementType = CAT->getElementType().getTypePtr();
8519 else if (VAT)
8520 ElementType = VAT->getElementType().getTypePtr();
8521 else if (&Component == &*Components.begin()) {
8522 // If the base is a raw pointer (e.g. T *data with data[a:b:c]),
8523 // there was no earlier CAT/VAT/array handling to establish
8524 // ElementType. Capture the pointee type now so that subsequent
8525 // components (offset/length/stride) have a concrete element type to
8526 // work with. This makes pointer-backed sections behave consistently
8527 // with CAT/VAT/array bases.
8528 if (const auto *PtrType = Ty->getAs<PointerType>())
8529 ElementType = PtrType->getPointeeType().getTypePtr();
8530 } else {
8531 // Any component after the first should never have a raw pointer type;
8532 // by this point. ElementType must already be known (set above or in
8533 // prior array / CAT / VAT handling).
8534 assert(!Ty->isPointerType() &&
8535 "Non-first components should not be raw pointers");
8536 }
8537
8538 // At this stage, if ElementType was a base pointer and we are in the
8539 // first iteration, it has been computed.
8540 if (ElementType) {
8541 // For the case that having pointer as base, we need to remove one
8542 // level of indirection.
8543 if (&Component != &*Components.begin())
8544 ElementType = ElementType->getPointeeOrArrayElementType();
8545 ElementTypeSize =
8546 Context.getTypeSizeInChars(ElementType).getQuantity();
8547 CurCounts.push_back(
8548 llvm::ConstantInt::get(CGF.Int64Ty, ElementTypeSize));
8549 }
8550 }
8551 // Get dimension value except for the last dimension since we don't need
8552 // it.
8553 if (DimSizes.size() < Components.size() - 1) {
8554 if (CAT)
8555 DimSizes.push_back(
8556 llvm::ConstantInt::get(CGF.Int64Ty, CAT->getZExtSize()));
8557 else if (VAT)
8558 DimSizes.push_back(CGF.Builder.CreateIntCast(
8559 CGF.EmitScalarExpr(VAT->getSizeExpr()), CGF.Int64Ty,
8560 /*IsSigned=*/false));
8561 }
8562 }
8563
8564 // Skip the dummy dimension since we have already have its information.
8565 auto *DI = DimSizes.begin() + 1;
8566 // Product of dimension.
8567 llvm::Value *DimProd =
8568 llvm::ConstantInt::get(CGF.CGM.Int64Ty, ElementTypeSize);
8569
8570 // Collect info for non-contiguous. Notice that offset, count, and stride
8571 // are only meaningful for array-section, so we insert a null for anything
8572 // other than array-section.
8573 // Also, the size of offset, count, and stride are not the same as
8574 // pointers, base_pointers, sizes, or dims. Instead, the size of offset,
8575 // count, and stride are the same as the number of non-contiguous
8576 // declaration in target update to/from clause.
8577 for (const OMPClauseMappableExprCommon::MappableComponent &Component :
8578 Components) {
8579 const Expr *AssocExpr = Component.getAssociatedExpression();
8580
8581 if (const auto *AE = dyn_cast<ArraySubscriptExpr>(AssocExpr)) {
8582 llvm::Value *Offset = CGF.Builder.CreateIntCast(
8583 CGF.EmitScalarExpr(AE->getIdx()), CGF.Int64Ty,
8584 /*isSigned=*/false);
8585 CurOffsets.push_back(Offset);
8586 CurCounts.push_back(llvm::ConstantInt::get(CGF.Int64Ty, /*V=*/1));
8587 CurStrides.push_back(CurStrides.back());
8588 continue;
8589 }
8590
8591 const auto *OASE = dyn_cast<ArraySectionExpr>(AssocExpr);
8592
8593 if (!OASE)
8594 continue;
8595
8596 // Offset
8597 const Expr *OffsetExpr = OASE->getLowerBound();
8598 llvm::Value *Offset = nullptr;
8599 if (!OffsetExpr) {
8600 // If offset is absent, then we just set it to zero.
8601 Offset = llvm::ConstantInt::get(CGF.Int64Ty, 0);
8602 } else {
8603 Offset = CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(OffsetExpr),
8604 CGF.Int64Ty,
8605 /*isSigned=*/false);
8606 }
8607
8608 // Count
8609 const Expr *CountExpr = OASE->getLength();
8610 llvm::Value *Count = nullptr;
8611 if (!CountExpr) {
8612 // In Clang, once a high dimension is an array section, we construct all
8613 // the lower dimension as array section, however, for case like
8614 // arr[0:2][2], Clang construct the inner dimension as an array section
8615 // but it actually is not in an array section form according to spec.
8616 if (!OASE->getColonLocFirst().isValid() &&
8617 !OASE->getColonLocSecond().isValid()) {
8618 Count = llvm::ConstantInt::get(CGF.Int64Ty, 1);
8619 } else {
8620 // OpenMP 5.0, 2.1.5 Array Sections, Description.
8621 // When the length is absent it defaults to ⌈(size −
8622 // lower-bound)/stride⌉, where size is the size of the array
8623 // dimension.
8624 const Expr *StrideExpr = OASE->getStride();
8625 llvm::Value *Stride =
8626 StrideExpr
8627 ? CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(StrideExpr),
8628 CGF.Int64Ty, /*isSigned=*/false)
8629 : nullptr;
8630 if (Stride)
8631 Count = CGF.Builder.CreateUDiv(
8632 CGF.Builder.CreateNUWSub(*DI, Offset), Stride);
8633 else
8634 Count = CGF.Builder.CreateNUWSub(*DI, Offset);
8635 }
8636 } else {
8637 Count = CGF.EmitScalarExpr(CountExpr);
8638 }
8639 Count = CGF.Builder.CreateIntCast(Count, CGF.Int64Ty, /*isSigned=*/false);
8640 CurCounts.push_back(Count);
8641
8642 // Stride_n' = Stride_n * (D_0 * D_1 ... * D_n-1) * Unit size
8643 // Offset_n' = Offset_n * (D_0 * D_1 ... * D_n-1) * Unit size
8644 // Take `int arr[5][5][5]` and `arr[0:2:2][1:2:1][0:2:2]` as an example:
8645 // Offset Count Stride
8646 // D0 0 4 1 (int) <- dummy dimension
8647 // D1 0 2 8 (2 * (1) * 4)
8648 // D2 100 2 20 (1 * (1 * 5) * 4)
8649 // D3 0 2 200 (2 * (1 * 5 * 4) * 4)
8650 const Expr *StrideExpr = OASE->getStride();
8651 llvm::Value *Stride =
8652 StrideExpr
8653 ? CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(StrideExpr),
8654 CGF.Int64Ty, /*isSigned=*/false)
8655 : nullptr;
8656 DimProd = CGF.Builder.CreateNUWMul(DimProd, *(DI - 1));
8657 if (Stride)
8658 CurStrides.push_back(CGF.Builder.CreateNUWMul(DimProd, Stride));
8659 else
8660 CurStrides.push_back(DimProd);
8661
8662 Offset = CGF.Builder.CreateNUWMul(DimProd, Offset);
8663 CurOffsets.push_back(Offset);
8664
8665 if (DI != DimSizes.end())
8666 ++DI;
8667 }
8668
8669 CombinedInfo.NonContigInfo.Offsets.push_back(CurOffsets);
8670 CombinedInfo.NonContigInfo.Counts.push_back(CurCounts);
8671 CombinedInfo.NonContigInfo.Strides.push_back(CurStrides);
8672 }
8673
8674 /// Return the adjusted map modifiers if the declaration a capture refers to
8675 /// appears in a first-private clause. This is expected to be used only with
8676 /// directives that start with 'target'.
8677 OpenMPOffloadMappingFlags
8678 getMapModifiersForPrivateClauses(const CapturedStmt::Capture &Cap) const {
8679 assert(Cap.capturesVariable() && "Expected capture by reference only!");
8680
8681 // A first private variable captured by reference will use only the
8682 // 'private ptr' and 'map to' flag. Return the right flags if the captured
8683 // declaration is known as first-private in this handler.
8684 if (FirstPrivateDecls.count(Cap.getCapturedVar())) {
8685 if (Cap.getCapturedVar()->getType()->isAnyPointerType())
8686 return OpenMPOffloadMappingFlags::OMP_MAP_TO |
8687 OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ;
8688 return OpenMPOffloadMappingFlags::OMP_MAP_PRIVATE |
8689 OpenMPOffloadMappingFlags::OMP_MAP_TO;
8690 }
8691 auto I = LambdasMap.find(Cap.getCapturedVar()->getCanonicalDecl());
8692 if (I != LambdasMap.end())
8693 // for map(to: lambda): using user specified map type.
8694 return getMapTypeBits(
8695 I->getSecond()->getMapType(), I->getSecond()->getMapTypeModifiers(),
8696 /*MotionModifiers=*/{}, I->getSecond()->isImplicit(),
8697 /*AddPtrFlag=*/false,
8698 /*AddIsTargetParamFlag=*/false,
8699 /*isNonContiguous=*/false);
8700 return OpenMPOffloadMappingFlags::OMP_MAP_TO |
8701 OpenMPOffloadMappingFlags::OMP_MAP_FROM;
8702 }
8703
8704 void getPlainLayout(const CXXRecordDecl *RD,
8705 llvm::SmallVectorImpl<const FieldDecl *> &Layout,
8706 bool AsBase) const {
8707 const CGRecordLayout &RL = CGF.getTypes().getCGRecordLayout(RD);
8708
8709 llvm::StructType *St =
8710 AsBase ? RL.getBaseSubobjectLLVMType() : RL.getLLVMType();
8711
8712 unsigned NumElements = St->getNumElements();
8713 llvm::SmallVector<
8714 llvm::PointerUnion<const CXXRecordDecl *, const FieldDecl *>, 4>
8715 RecordLayout(NumElements);
8716
8717 // Fill bases.
8718 for (const auto &I : RD->bases()) {
8719 if (I.isVirtual())
8720 continue;
8721
8722 QualType BaseTy = I.getType();
8723 const auto *Base = BaseTy->getAsCXXRecordDecl();
8724 // Ignore empty bases.
8725 if (isEmptyRecordForLayout(CGF.getContext(), BaseTy) ||
8726 CGF.getContext()
8727 .getASTRecordLayout(Base)
8729 .isZero())
8730 continue;
8731
8732 unsigned FieldIndex = RL.getNonVirtualBaseLLVMFieldNo(Base);
8733 RecordLayout[FieldIndex] = Base;
8734 }
8735 // Fill in virtual bases.
8736 for (const auto &I : RD->vbases()) {
8737 QualType BaseTy = I.getType();
8738 // Ignore empty bases.
8739 if (isEmptyRecordForLayout(CGF.getContext(), BaseTy))
8740 continue;
8741
8742 const auto *Base = BaseTy->getAsCXXRecordDecl();
8743 unsigned FieldIndex = RL.getVirtualBaseIndex(Base);
8744 if (RecordLayout[FieldIndex])
8745 continue;
8746 RecordLayout[FieldIndex] = Base;
8747 }
8748 // Fill in all the fields.
8749 assert(!RD->isUnion() && "Unexpected union.");
8750 for (const auto *Field : RD->fields()) {
8751 // Fill in non-bitfields. (Bitfields always use a zero pattern, which we
8752 // will fill in later.)
8753 if (!Field->isBitField() &&
8754 !isEmptyFieldForLayout(CGF.getContext(), Field)) {
8755 unsigned FieldIndex = RL.getLLVMFieldNo(Field);
8756 RecordLayout[FieldIndex] = Field;
8757 }
8758 }
8759 for (const llvm::PointerUnion<const CXXRecordDecl *, const FieldDecl *>
8760 &Data : RecordLayout) {
8761 if (Data.isNull())
8762 continue;
8763 if (const auto *Base = dyn_cast<const CXXRecordDecl *>(Data))
8764 getPlainLayout(Base, Layout, /*AsBase=*/true);
8765 else
8766 Layout.push_back(cast<const FieldDecl *>(Data));
8767 }
8768 }
8769
8770 /// Returns the address corresponding to \p PointerExpr.
8771 static Address getAttachPtrAddr(const Expr *PointerExpr,
8772 CodeGenFunction &CGF) {
8773 assert(PointerExpr && "Cannot get addr from null attach-ptr expr");
8774 Address AttachPtrAddr = Address::invalid();
8775
8776 if (auto *DRE = dyn_cast<DeclRefExpr>(PointerExpr)) {
8777 // If the pointer is a variable, we can use its address directly.
8778 AttachPtrAddr = CGF.EmitLValue(DRE).getAddress();
8779 } else if (auto *OASE = dyn_cast<ArraySectionExpr>(PointerExpr)) {
8780 AttachPtrAddr =
8781 CGF.EmitArraySectionExpr(OASE, /*IsLowerBound=*/true).getAddress();
8782 } else if (auto *ASE = dyn_cast<ArraySubscriptExpr>(PointerExpr)) {
8783 AttachPtrAddr = CGF.EmitLValue(ASE).getAddress();
8784 } else if (auto *ME = dyn_cast<MemberExpr>(PointerExpr)) {
8785 AttachPtrAddr = CGF.EmitMemberExpr(ME).getAddress();
8786 } else if (auto *UO = dyn_cast<UnaryOperator>(PointerExpr)) {
8787 assert(UO->getOpcode() == UO_Deref &&
8788 "Unexpected unary-operator on attach-ptr-expr");
8789 AttachPtrAddr = CGF.EmitLValue(UO).getAddress();
8790 }
8791 assert(AttachPtrAddr.isValid() &&
8792 "Failed to get address for attach pointer expression");
8793 return AttachPtrAddr;
8794 }
8795
8796 /// Get the address of the attach pointer, and a load from it, to get the
8797 /// pointee base address.
8798 /// \return A pair containing AttachPtrAddr and AttachPteeBaseAddr. The pair
8799 /// contains invalid addresses if \p AttachPtrExpr is null.
8800 static std::pair<Address, Address>
8801 getAttachPtrAddrAndPteeBaseAddr(const Expr *AttachPtrExpr,
8802 CodeGenFunction &CGF) {
8803
8804 if (!AttachPtrExpr)
8805 return {Address::invalid(), Address::invalid()};
8806
8807 Address AttachPtrAddr = getAttachPtrAddr(AttachPtrExpr, CGF);
8808 assert(AttachPtrAddr.isValid() && "Invalid attach pointer addr");
8809
8810 QualType AttachPtrType =
8813
8814 Address AttachPteeBaseAddr = CGF.EmitLoadOfPointer(
8815 AttachPtrAddr, AttachPtrType->castAs<PointerType>());
8816 assert(AttachPteeBaseAddr.isValid() && "Invalid attach pointee base addr");
8817
8818 return {AttachPtrAddr, AttachPteeBaseAddr};
8819 }
8820
8821 /// Returns whether an attach entry should be emitted for a map on
8822 /// \p MapBaseDecl on the directive \p CurDir.
8823 static bool
8824 shouldEmitAttachEntry(const Expr *PointerExpr, const ValueDecl *MapBaseDecl,
8825 CodeGenFunction &CGF,
8826 llvm::PointerUnion<const OMPExecutableDirective *,
8827 const OMPDeclareMapperDecl *>
8828 CurDir) {
8829 if (!PointerExpr)
8830 return false;
8831
8832 // Pointer attachment is needed at map-entering time or for declare
8833 // mappers.
8834 return isa<const OMPDeclareMapperDecl *>(CurDir) ||
8837 ->getDirectiveKind());
8838 }
8839
8840 /// Computes the attach-ptr expr for \p Components, and updates various maps
8841 /// with the information.
8842 /// It internally calls OMPClauseMappableExprCommon::findAttachPtrExpr()
8843 /// with the OpenMPDirectiveKind extracted from \p CurDir.
8844 /// It updates AttachPtrComputationOrderMap, AttachPtrComponentDepthMap, and
8845 /// AttachPtrExprMap.
8846 void collectAttachPtrExprInfo(
8848 llvm::PointerUnion<const OMPExecutableDirective *,
8849 const OMPDeclareMapperDecl *>
8850 CurDir) {
8851
8852 OpenMPDirectiveKind CurDirectiveID =
8854 ? OMPD_declare_mapper
8855 : cast<const OMPExecutableDirective *>(CurDir)->getDirectiveKind();
8856
8857 const auto &[AttachPtrExpr, Depth] =
8859 CurDirectiveID);
8860
8861 AttachPtrComputationOrderMap.try_emplace(
8862 AttachPtrExpr, AttachPtrComputationOrderMap.size());
8863 AttachPtrComponentDepthMap.try_emplace(AttachPtrExpr, Depth);
8864 AttachPtrExprMap.try_emplace(Components, AttachPtrExpr);
8865 }
8866
8867 /// Generate all the base pointers, section pointers, sizes, map types, and
8868 /// mappers for the extracted mappable expressions (all included in \a
8869 /// CombinedInfo). Also, for each item that relates with a device pointer, a
8870 /// pair of the relevant declaration and index where it occurs is appended to
8871 /// the device pointers info array.
8872 void generateAllInfoForClauses(
8873 ArrayRef<const OMPClause *> Clauses, MapCombinedInfoTy &CombinedInfo,
8874 llvm::OpenMPIRBuilder &OMPBuilder,
8875 const llvm::DenseSet<CanonicalDeclPtr<const Decl>> &SkipVarSet =
8876 llvm::DenseSet<CanonicalDeclPtr<const Decl>>()) const {
8877 // We have to process the component lists that relate with the same
8878 // declaration in a single chunk so that we can generate the map flags
8879 // correctly. Therefore, we organize all lists in a map.
8880 enum MapKind { Present, Allocs, Other, Total };
8881 llvm::MapVector<CanonicalDeclPtr<const Decl>,
8882 SmallVector<SmallVector<MapInfo, 8>, 4>>
8883 Info;
8884
8885 // Helper function to fill the information map for the different supported
8886 // clauses.
8887 auto &&InfoGen =
8888 [&Info, &SkipVarSet](
8889 const ValueDecl *D, MapKind Kind,
8891 OpenMPMapClauseKind MapType,
8892 ArrayRef<OpenMPMapModifierKind> MapModifiers,
8893 ArrayRef<OpenMPMotionModifierKind> MotionModifiers,
8894 bool ReturnDevicePointer, bool IsImplicit, const ValueDecl *Mapper,
8895 const Expr *VarRef = nullptr, bool ForDeviceAddr = false) {
8896 if (SkipVarSet.contains(D))
8897 return;
8898 auto It = Info.try_emplace(D, Total).first;
8899 It->second[Kind].emplace_back(
8900 L, MapType, MapModifiers, MotionModifiers, ReturnDevicePointer,
8901 IsImplicit, Mapper, VarRef, ForDeviceAddr);
8902 };
8903
8904 for (const auto *Cl : Clauses) {
8905 const auto *C = dyn_cast<OMPMapClause>(Cl);
8906 if (!C)
8907 continue;
8908 MapKind Kind = Other;
8909 if (llvm::is_contained(C->getMapTypeModifiers(),
8910 OMPC_MAP_MODIFIER_present))
8911 Kind = Present;
8912 else if (C->getMapType() == OMPC_MAP_alloc)
8913 Kind = Allocs;
8914 const auto *EI = C->getVarRefs().begin();
8915 for (const auto L : C->component_lists()) {
8916 const Expr *E = (C->getMapLoc().isValid()) ? *EI : nullptr;
8917 InfoGen(std::get<0>(L), Kind, std::get<1>(L), C->getMapType(),
8918 C->getMapTypeModifiers(), {},
8919 /*ReturnDevicePointer=*/false, C->isImplicit(), std::get<2>(L),
8920 E);
8921 ++EI;
8922 }
8923 }
8924 for (const auto *Cl : Clauses) {
8925 const auto *C = dyn_cast<OMPToClause>(Cl);
8926 if (!C)
8927 continue;
8928 MapKind Kind = Other;
8929 if (llvm::is_contained(C->getMotionModifiers(),
8930 OMPC_MOTION_MODIFIER_present))
8931 Kind = Present;
8932 if (llvm::is_contained(C->getMotionModifiers(),
8933 OMPC_MOTION_MODIFIER_iterator)) {
8934 if (auto *IteratorExpr = dyn_cast<OMPIteratorExpr>(
8935 C->getIteratorModifier()->IgnoreParenImpCasts())) {
8936 const auto *VD = cast<VarDecl>(IteratorExpr->getIteratorDecl(0));
8937 CGF.EmitVarDecl(*VD);
8938 }
8939 }
8940
8941 const auto *EI = C->getVarRefs().begin();
8942 for (const auto L : C->component_lists()) {
8943 InfoGen(std::get<0>(L), Kind, std::get<1>(L), OMPC_MAP_to, {},
8944 C->getMotionModifiers(), /*ReturnDevicePointer=*/false,
8945 C->isImplicit(), std::get<2>(L), *EI);
8946 ++EI;
8947 }
8948 }
8949 for (const auto *Cl : Clauses) {
8950 const auto *C = dyn_cast<OMPFromClause>(Cl);
8951 if (!C)
8952 continue;
8953 MapKind Kind = Other;
8954 if (llvm::is_contained(C->getMotionModifiers(),
8955 OMPC_MOTION_MODIFIER_present))
8956 Kind = Present;
8957 if (llvm::is_contained(C->getMotionModifiers(),
8958 OMPC_MOTION_MODIFIER_iterator)) {
8959 if (auto *IteratorExpr = dyn_cast<OMPIteratorExpr>(
8960 C->getIteratorModifier()->IgnoreParenImpCasts())) {
8961 const auto *VD = cast<VarDecl>(IteratorExpr->getIteratorDecl(0));
8962 CGF.EmitVarDecl(*VD);
8963 }
8964 }
8965
8966 const auto *EI = C->getVarRefs().begin();
8967 for (const auto L : C->component_lists()) {
8968 InfoGen(std::get<0>(L), Kind, std::get<1>(L), OMPC_MAP_from, {},
8969 C->getMotionModifiers(),
8970 /*ReturnDevicePointer=*/false, C->isImplicit(), std::get<2>(L),
8971 *EI);
8972 ++EI;
8973 }
8974 }
8975
8976 // Look at the use_device_ptr and use_device_addr clauses information and
8977 // mark the existing map entries as such. If there is no map information for
8978 // an entry in the use_device_ptr and use_device_addr list, we create one
8979 // with map type 'return_param' and zero size section. It is the user's
8980 // fault if that was not mapped before. If there is no map information, then
8981 // we defer the emission of that entry until all the maps for the same VD
8982 // have been handled.
8983 MapCombinedInfoTy UseDeviceDataCombinedInfo;
8984
8985 auto &&UseDeviceDataCombinedInfoGen =
8986 [&UseDeviceDataCombinedInfo](const ValueDecl *VD, llvm::Value *Ptr,
8987 CodeGenFunction &CGF, bool IsDevAddr,
8988 bool HasUdpFbNullify = false) {
8989 UseDeviceDataCombinedInfo.Exprs.push_back(VD);
8990 UseDeviceDataCombinedInfo.BasePointers.emplace_back(Ptr);
8991 UseDeviceDataCombinedInfo.DevicePtrDecls.emplace_back(VD);
8992 UseDeviceDataCombinedInfo.DevicePointers.emplace_back(
8993 IsDevAddr ? DeviceInfoTy::Address : DeviceInfoTy::Pointer);
8994 // FIXME: For use_device_addr on array-sections, this should
8995 // be the starting address of the section.
8996 // e.g. int *p;
8997 // ... use_device_addr(p[3])
8998 // &p[0], &p[3], /*size=*/0, RETURN_PARAM
8999 UseDeviceDataCombinedInfo.Pointers.push_back(Ptr);
9000 UseDeviceDataCombinedInfo.Sizes.push_back(
9001 llvm::Constant::getNullValue(CGF.Int64Ty));
9002 OpenMPOffloadMappingFlags Flags =
9003 OpenMPOffloadMappingFlags::OMP_MAP_RETURN_PARAM;
9004 if (HasUdpFbNullify)
9005 Flags |= OpenMPOffloadMappingFlags::OMP_MAP_FB_NULLIFY;
9006 UseDeviceDataCombinedInfo.Types.push_back(Flags);
9007 UseDeviceDataCombinedInfo.HasAttachPtr.push_back(false);
9008 UseDeviceDataCombinedInfo.Mappers.push_back(nullptr);
9009 };
9010
9011 auto &&MapInfoGen =
9012 [&UseDeviceDataCombinedInfoGen](
9013 CodeGenFunction &CGF, const Expr *IE, const ValueDecl *VD,
9015 Components,
9016 bool IsDevAddr, bool IEIsAttachPtrForDevAddr = false,
9017 bool HasUdpFbNullify = false) {
9018 // We didn't find any match in our map information - generate a zero
9019 // size array section.
9020 llvm::Value *Ptr;
9021 if (IsDevAddr && !IEIsAttachPtrForDevAddr) {
9022 if (IE->isGLValue())
9023 Ptr = CGF.EmitLValue(IE).getPointer(CGF);
9024 else
9025 Ptr = CGF.EmitScalarExpr(IE);
9026 } else {
9027 Ptr = CGF.EmitLoadOfScalar(CGF.EmitLValue(IE), IE->getExprLoc());
9028 }
9029 bool TreatDevAddrAsDevPtr = IEIsAttachPtrForDevAddr;
9030 // For the purpose of address-translation, treat something like the
9031 // following:
9032 // int *p;
9033 // ... use_device_addr(p[1])
9034 // equivalent to
9035 // ... use_device_ptr(p)
9036 UseDeviceDataCombinedInfoGen(VD, Ptr, CGF, /*IsDevAddr=*/IsDevAddr &&
9037 !TreatDevAddrAsDevPtr,
9038 HasUdpFbNullify);
9039 };
9040
9041 auto &&IsMapInfoExist =
9042 [&Info, this](CodeGenFunction &CGF, const ValueDecl *VD, const Expr *IE,
9043 const Expr *DesiredAttachPtrExpr, bool IsDevAddr,
9044 bool HasUdpFbNullify = false) -> bool {
9045 // We potentially have map information for this declaration already.
9046 // Look for the first set of components that refer to it. If found,
9047 // return true.
9048 // If the first component is a member expression, we have to look into
9049 // 'this', which maps to null in the map of map information. Otherwise
9050 // look directly for the information.
9051 auto It = Info.find(isa<MemberExpr>(IE) ? nullptr : VD);
9052 if (It != Info.end()) {
9053 bool Found = false;
9054 for (auto &Data : It->second) {
9055 MapInfo *CI = nullptr;
9056 // We potentially have multiple maps for the same decl. We need to
9057 // only consider those for which the attach-ptr matches the desired
9058 // attach-ptr.
9059 auto *It = llvm::find_if(Data, [&](const MapInfo &MI) {
9060 if (MI.Components.back().getAssociatedDeclaration() != VD)
9061 return false;
9062
9063 const Expr *MapAttachPtr = getAttachPtrExpr(MI.Components);
9064 bool Match = AttachPtrComparator.areEqual(MapAttachPtr,
9065 DesiredAttachPtrExpr);
9066 return Match;
9067 });
9068
9069 if (It != Data.end())
9070 CI = &*It;
9071
9072 if (CI) {
9073 if (IsDevAddr) {
9074 CI->ForDeviceAddr = true;
9075 CI->ReturnDevicePointer = true;
9076 CI->HasUdpFbNullify = HasUdpFbNullify;
9077 Found = true;
9078 break;
9079 } else {
9080 auto PrevCI = std::next(CI->Components.rbegin());
9081 const auto *VarD = dyn_cast<VarDecl>(VD);
9082 const Expr *AttachPtrExpr = getAttachPtrExpr(CI->Components);
9083 if (CGF.CGM.getOpenMPRuntime().hasRequiresUnifiedSharedMemory() ||
9084 isa<MemberExpr>(IE) ||
9085 !VD->getType().getNonReferenceType()->isPointerType() ||
9086 PrevCI == CI->Components.rend() ||
9087 isa<MemberExpr>(PrevCI->getAssociatedExpression()) || !VarD ||
9088 VarD->hasLocalStorage() ||
9089 (isa_and_nonnull<DeclRefExpr>(AttachPtrExpr) &&
9090 VD == cast<DeclRefExpr>(AttachPtrExpr)->getDecl())) {
9091 CI->ForDeviceAddr = IsDevAddr;
9092 CI->ReturnDevicePointer = true;
9093 CI->HasUdpFbNullify = HasUdpFbNullify;
9094 Found = true;
9095 break;
9096 }
9097 }
9098 }
9099 }
9100 return Found;
9101 }
9102 return false;
9103 };
9104
9105 // Look at the use_device_ptr clause information and mark the existing map
9106 // entries as such. If there is no map information for an entry in the
9107 // use_device_ptr list, we create one with map type 'alloc' and zero size
9108 // section. It is the user fault if that was not mapped before. If there is
9109 // no map information and the pointer is a struct member, then we defer the
9110 // emission of that entry until the whole struct has been processed.
9111 for (const auto *Cl : Clauses) {
9112 const auto *C = dyn_cast<OMPUseDevicePtrClause>(Cl);
9113 if (!C)
9114 continue;
9115 bool HasUdpFbNullify =
9116 C->getFallbackModifier() == OMPC_USE_DEVICE_PTR_FALLBACK_fb_nullify;
9117 for (const auto L : C->component_lists()) {
9119 std::get<1>(L);
9120 assert(!Components.empty() &&
9121 "Not expecting empty list of components!");
9122 const ValueDecl *VD = Components.back().getAssociatedDeclaration();
9124 const Expr *IE = Components.back().getAssociatedExpression();
9125 // For use_device_ptr, we match an existing map clause if its attach-ptr
9126 // is same as the use_device_ptr operand. e.g.
9127 // map expr | use_device_ptr expr | current behavior
9128 // ---------|---------------------|-----------------
9129 // p[1] | p | match
9130 // ps->a | ps | match
9131 // p | p | no match
9132 const Expr *UDPOperandExpr =
9133 Components.front().getAssociatedExpression();
9134 if (IsMapInfoExist(CGF, VD, IE,
9135 /*DesiredAttachPtrExpr=*/UDPOperandExpr,
9136 /*IsDevAddr=*/false, HasUdpFbNullify))
9137 continue;
9138 MapInfoGen(CGF, IE, VD, Components, /*IsDevAddr=*/false,
9139 /*IEIsAttachPtrForDevAddr=*/false, HasUdpFbNullify);
9140 }
9141 }
9142
9143 llvm::SmallDenseSet<CanonicalDeclPtr<const Decl>, 4> Processed;
9144 for (const auto *Cl : Clauses) {
9145 const auto *C = dyn_cast<OMPUseDeviceAddrClause>(Cl);
9146 if (!C)
9147 continue;
9148 for (const auto L : C->component_lists()) {
9150 std::get<1>(L);
9151 assert(!std::get<1>(L).empty() &&
9152 "Not expecting empty list of components!");
9153 const ValueDecl *VD = std::get<1>(L).back().getAssociatedDeclaration();
9154 if (!Processed.insert(VD).second)
9155 continue;
9157 // For use_device_addr, we match an existing map clause if the
9158 // use_device_addr operand's attach-ptr matches the map operand's
9159 // attach-ptr.
9160 // We chould also restrict to only match cases when there is a full
9161 // match between the map/use_device_addr clause exprs, but that may be
9162 // unnecessary.
9163 //
9164 // map expr | use_device_addr expr | current | possible restrictive/
9165 // | | behavior | safer behavior
9166 // ---------|----------------------|-----------|-----------------------
9167 // p | p | match | match
9168 // p[0] | p[0] | match | match
9169 // p[0:1] | p[0] | match | no match
9170 // p[0:1] | p[2:1] | match | no match
9171 // p[1] | p[0] | match | no match
9172 // ps->a | ps->b | match | no match
9173 // p | p[0] | no match | no match
9174 // pp | pp[0][0] | no match | no match
9175 const Expr *UDAAttachPtrExpr = getAttachPtrExpr(Components);
9176 const Expr *IE = std::get<1>(L).back().getAssociatedExpression();
9177 assert((!UDAAttachPtrExpr || UDAAttachPtrExpr == IE) &&
9178 "use_device_addr operand has an attach-ptr, but does not match "
9179 "last component's expr.");
9180 if (IsMapInfoExist(CGF, VD, IE,
9181 /*DesiredAttachPtrExpr=*/UDAAttachPtrExpr,
9182 /*IsDevAddr=*/true))
9183 continue;
9184 MapInfoGen(CGF, IE, VD, Components,
9185 /*IsDevAddr=*/true,
9186 /*IEIsAttachPtrForDevAddr=*/UDAAttachPtrExpr != nullptr);
9187 }
9188 }
9189
9190 for (const auto &Data : Info) {
9191 MapCombinedInfoTy CurInfo;
9192 const Decl *D = Data.first;
9193 const ValueDecl *VD = cast_or_null<ValueDecl>(D);
9194 // Group component lists by their AttachPtrExpr and process them in order
9195 // of increasing complexity (nullptr first, then simple expressions like
9196 // p, then more complex ones like p[0], etc.)
9197 //
9198 // This is similar to how generateInfoForCaptureFromClauseInfo handles
9199 // grouping for target constructs.
9200 SmallVector<std::pair<const Expr *, MapInfo>, 16> AttachPtrMapInfoPairs;
9201
9202 // First, collect all MapData entries with their attach-ptr exprs.
9203 for (const auto &M : Data.second) {
9204 for (const MapInfo &L : M) {
9205 assert(!L.Components.empty() &&
9206 "Not expecting declaration with no component lists.");
9207
9208 const Expr *AttachPtrExpr = getAttachPtrExpr(L.Components);
9209 AttachPtrMapInfoPairs.emplace_back(AttachPtrExpr, L);
9210 }
9211 }
9212
9213 // Next, sort by increasing order of their complexity.
9214 llvm::stable_sort(AttachPtrMapInfoPairs,
9215 [this](const auto &LHS, const auto &RHS) {
9216 return AttachPtrComparator(LHS.first, RHS.first);
9217 });
9218
9219 // And finally, process them all in order, grouping those with
9220 // equivalent attach-ptr exprs together.
9221 auto *It = AttachPtrMapInfoPairs.begin();
9222 while (It != AttachPtrMapInfoPairs.end()) {
9223 const Expr *AttachPtrExpr = It->first;
9224
9225 SmallVector<MapInfo, 8> GroupLists;
9226 while (It != AttachPtrMapInfoPairs.end() &&
9227 (It->first == AttachPtrExpr ||
9228 AttachPtrComparator.areEqual(It->first, AttachPtrExpr))) {
9229 GroupLists.push_back(It->second);
9230 ++It;
9231 }
9232 assert(!GroupLists.empty() && "GroupLists should not be empty");
9233
9234 StructRangeInfoTy PartialStruct;
9235 AttachInfoTy AttachInfo;
9236 MapCombinedInfoTy GroupCurInfo;
9237 // Current group's struct base information:
9238 MapCombinedInfoTy GroupStructBaseCurInfo;
9239 for (const MapInfo &L : GroupLists) {
9240 // Remember the current base pointer index.
9241 unsigned CurrentBasePointersIdx = GroupCurInfo.BasePointers.size();
9242 unsigned StructBasePointersIdx =
9243 GroupStructBaseCurInfo.BasePointers.size();
9244
9245 GroupCurInfo.NonContigInfo.IsNonContiguous =
9246 L.Components.back().isNonContiguous();
9247 generateInfoForComponentList(
9248 L.MapType, L.MapModifiers, L.MotionModifiers, L.Components,
9249 GroupCurInfo, GroupStructBaseCurInfo, PartialStruct, AttachInfo,
9250 /*IsFirstComponentList=*/false, L.IsImplicit,
9251 /*GenerateAllInfoForClauses*/ true, L.Mapper, L.ForDeviceAddr, VD,
9252 L.VarRef, /*OverlappedElements*/ {});
9253
9254 // If this entry relates to a device pointer, set the relevant
9255 // declaration and add the 'return pointer' flag.
9256 if (L.ReturnDevicePointer) {
9257 // Check whether a value was added to either GroupCurInfo or
9258 // GroupStructBaseCurInfo and error if no value was added to either
9259 // of them:
9260 assert((CurrentBasePointersIdx < GroupCurInfo.BasePointers.size() ||
9261 StructBasePointersIdx <
9262 GroupStructBaseCurInfo.BasePointers.size()) &&
9263 "Unexpected number of mapped base pointers.");
9264
9265 // Choose a base pointer index which is always valid:
9266 const ValueDecl *RelevantVD =
9267 L.Components.back().getAssociatedDeclaration();
9268 assert(RelevantVD &&
9269 "No relevant declaration related with device pointer??");
9270
9271 // If GroupStructBaseCurInfo has been updated this iteration then
9272 // work on the first new entry added to it i.e. make sure that when
9273 // multiple values are added to any of the lists, the first value
9274 // added is being modified by the assignments below (not the last
9275 // value added).
9276 auto SetDevicePointerInfo = [&](MapCombinedInfoTy &Info,
9277 unsigned Idx) {
9278 Info.DevicePtrDecls[Idx] = RelevantVD;
9279 Info.DevicePointers[Idx] = L.ForDeviceAddr
9280 ? DeviceInfoTy::Address
9281 : DeviceInfoTy::Pointer;
9282 Info.Types[Idx] |=
9283 OpenMPOffloadMappingFlags::OMP_MAP_RETURN_PARAM;
9284 if (L.HasUdpFbNullify)
9285 Info.Types[Idx] |=
9286 OpenMPOffloadMappingFlags::OMP_MAP_FB_NULLIFY;
9287 };
9288
9289 if (StructBasePointersIdx <
9290 GroupStructBaseCurInfo.BasePointers.size())
9291 SetDevicePointerInfo(GroupStructBaseCurInfo,
9292 StructBasePointersIdx);
9293 else
9294 SetDevicePointerInfo(GroupCurInfo, CurrentBasePointersIdx);
9295 }
9296 }
9297
9298 // Unify entries in one list making sure the struct mapping precedes the
9299 // individual fields:
9300 MapCombinedInfoTy GroupUnionCurInfo;
9301 GroupUnionCurInfo.append(GroupStructBaseCurInfo);
9302 GroupUnionCurInfo.append(GroupCurInfo);
9303
9304 // If there is an entry in PartialStruct it means we have a struct with
9305 // individual members mapped. Emit an extra combined entry.
9306 if (PartialStruct.Base.isValid()) {
9307 // Prepend a synthetic dimension of length 1 to represent the
9308 // aggregated struct object. Using 1 (not 0, as 0 produced an
9309 // incorrect non-contiguous descriptor (DimSize==1), causing the
9310 // non-contiguous motion clause path to be skipped.) is important:
9311 // * It preserves the correct rank so targetDataUpdate() computes
9312 // DimSize == 2 for cases like strided array sections originating
9313 // from user-defined mappers (e.g. test with s.data[0:8:2]).
9314 GroupUnionCurInfo.NonContigInfo.Dims.insert(
9315 GroupUnionCurInfo.NonContigInfo.Dims.begin(), 1);
9316 emitCombinedEntry(
9317 CurInfo, GroupUnionCurInfo.Types, PartialStruct, AttachInfo,
9318 /*IsMapThis=*/!VD, OMPBuilder, VD,
9319 /*OffsetForMemberOfFlag=*/CombinedInfo.BasePointers.size(),
9320 /*NotTargetParams=*/true);
9321 }
9322
9323 // Append this group's results to the overall CurInfo in the correct
9324 // order: combined-entry -> original-field-entries -> attach-entry
9325 CurInfo.append(GroupUnionCurInfo);
9326 if (AttachInfo.isValid())
9327 emitAttachEntry(CGF, CurInfo, AttachInfo);
9328 }
9329
9330 // We need to append the results of this capture to what we already have.
9331 CombinedInfo.append(CurInfo);
9332 }
9333 // Append data for use_device_ptr/addr clauses.
9334 CombinedInfo.append(UseDeviceDataCombinedInfo);
9335 }
9336
9337public:
9338 MappableExprsHandler(const OMPExecutableDirective &Dir, CodeGenFunction &CGF)
9339 : CurDir(&Dir), CGF(CGF), AttachPtrComparator(*this) {
9340 // Extract firstprivate clause information.
9341 for (const auto *C : Dir.getClausesOfKind<OMPFirstprivateClause>())
9342 for (const auto *D : C->varlist())
9343 FirstPrivateDecls.try_emplace(
9344 cast<VarDecl>(cast<DeclRefExpr>(D)->getDecl()), C->isImplicit());
9345 // Extract implicit firstprivates from uses_allocators clauses.
9346 for (const auto *C : Dir.getClausesOfKind<OMPUsesAllocatorsClause>()) {
9347 for (unsigned I = 0, E = C->getNumberOfAllocators(); I < E; ++I) {
9348 OMPUsesAllocatorsClause::Data D = C->getAllocatorData(I);
9349 if (const auto *DRE = dyn_cast_or_null<DeclRefExpr>(D.AllocatorTraits))
9350 FirstPrivateDecls.try_emplace(cast<VarDecl>(DRE->getDecl()),
9351 /*Implicit=*/true);
9352 else if (const auto *VD = dyn_cast<VarDecl>(
9353 cast<DeclRefExpr>(D.Allocator->IgnoreParenImpCasts())
9354 ->getDecl()))
9355 FirstPrivateDecls.try_emplace(VD, /*Implicit=*/true);
9356 }
9357 }
9358 // Extract defaultmap clause information.
9359 for (const auto *C : Dir.getClausesOfKind<OMPDefaultmapClause>())
9360 if (C->getDefaultmapModifier() == OMPC_DEFAULTMAP_MODIFIER_firstprivate)
9361 DefaultmapFirstprivateKinds.insert(C->getDefaultmapKind());
9362 // Extract device pointer clause information.
9363 for (const auto *C : Dir.getClausesOfKind<OMPIsDevicePtrClause>())
9364 for (auto L : C->component_lists())
9365 DevPointersMap[std::get<0>(L)].push_back(std::get<1>(L));
9366 // Extract device addr clause information.
9367 for (const auto *C : Dir.getClausesOfKind<OMPHasDeviceAddrClause>())
9368 for (auto L : C->component_lists())
9369 HasDevAddrsMap[std::get<0>(L)].push_back(std::get<1>(L));
9370 // Extract map information.
9371 for (const auto *C : Dir.getClausesOfKind<OMPMapClause>()) {
9372 if (C->getMapType() != OMPC_MAP_to)
9373 continue;
9374 for (auto L : C->component_lists()) {
9375 const ValueDecl *VD = std::get<0>(L);
9376 const auto *RD = VD ? VD->getType()
9377 .getCanonicalType()
9378 .getNonReferenceType()
9379 ->getAsCXXRecordDecl()
9380 : nullptr;
9381 if (RD && RD->isLambda())
9382 LambdasMap.try_emplace(std::get<0>(L), C);
9383 }
9384 }
9385
9386 auto CollectAttachPtrExprsForClauseComponents = [this](const auto *C) {
9387 for (auto L : C->component_lists()) {
9389 std::get<1>(L);
9390 if (!Components.empty())
9391 collectAttachPtrExprInfo(Components, CurDir);
9392 }
9393 };
9394
9395 // Populate the AttachPtrExprMap for all component lists from map-related
9396 // clauses.
9397 for (const auto *C : Dir.getClausesOfKind<OMPMapClause>())
9398 CollectAttachPtrExprsForClauseComponents(C);
9399 for (const auto *C : Dir.getClausesOfKind<OMPToClause>())
9400 CollectAttachPtrExprsForClauseComponents(C);
9401 for (const auto *C : Dir.getClausesOfKind<OMPFromClause>())
9402 CollectAttachPtrExprsForClauseComponents(C);
9403 for (const auto *C : Dir.getClausesOfKind<OMPUseDevicePtrClause>())
9404 CollectAttachPtrExprsForClauseComponents(C);
9405 for (const auto *C : Dir.getClausesOfKind<OMPUseDeviceAddrClause>())
9406 CollectAttachPtrExprsForClauseComponents(C);
9407 for (const auto *C : Dir.getClausesOfKind<OMPIsDevicePtrClause>())
9408 CollectAttachPtrExprsForClauseComponents(C);
9409 for (const auto *C : Dir.getClausesOfKind<OMPHasDeviceAddrClause>())
9410 CollectAttachPtrExprsForClauseComponents(C);
9411 }
9412
9413 /// Constructor for the declare mapper directive.
9414 MappableExprsHandler(const OMPDeclareMapperDecl &Dir, CodeGenFunction &CGF)
9415 : CurDir(&Dir), CGF(CGF), AttachPtrComparator(*this) {
9416 auto CollectAttachPtrExprsForClauseComponents = [this](const auto *C) {
9417 for (auto L : C->component_lists()) {
9419 std::get<1>(L);
9420 if (!Components.empty())
9421 collectAttachPtrExprInfo(Components, CurDir);
9422 }
9423 };
9424
9425 // Populate the AttachPtrExprMap for all component lists from map-related
9426 // clauses in the declare mapper directive, to enable attach-style mapping
9427 // for mappers.
9428 for (const auto *Cl : Dir.clauses()) {
9429 if (const auto *C = dyn_cast<OMPMapClause>(Cl))
9430 CollectAttachPtrExprsForClauseComponents(C);
9431 else if (const auto *C = dyn_cast<OMPToClause>(Cl))
9432 CollectAttachPtrExprsForClauseComponents(C);
9433 else if (const auto *C = dyn_cast<OMPFromClause>(Cl))
9434 CollectAttachPtrExprsForClauseComponents(C);
9435 }
9436 }
9437
9438 /// Generate code for the combined entry if we have a partially mapped struct
9439 /// and take care of the mapping flags of the arguments corresponding to
9440 /// individual struct members.
9441 /// If a valid \p AttachInfo exists, its pointee addr will be updated to point
9442 /// to the combined-entry's begin address, if emitted.
9443 /// \p PartialStruct contains attach base-pointer information.
9444 /// \returns The index of the combined entry if one was added, std::nullopt
9445 /// otherwise.
9446 void emitCombinedEntry(MapCombinedInfoTy &CombinedInfo,
9447 MapFlagsArrayTy &CurTypes,
9448 const StructRangeInfoTy &PartialStruct,
9449 AttachInfoTy &AttachInfo, bool IsMapThis,
9450 llvm::OpenMPIRBuilder &OMPBuilder, const ValueDecl *VD,
9451 unsigned OffsetForMemberOfFlag,
9452 bool NotTargetParams) const {
9453 if (CurTypes.size() == 1 &&
9454 ((CurTypes.back() & OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF) !=
9455 OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF) &&
9456 !PartialStruct.IsArraySection)
9457 return;
9458 Address LBAddr = PartialStruct.LowestElem.second;
9459 Address HBAddr = PartialStruct.HighestElem.second;
9460 if (PartialStruct.HasCompleteRecord) {
9461 LBAddr = PartialStruct.LB;
9462 HBAddr = PartialStruct.LB;
9463 }
9464 CombinedInfo.Exprs.push_back(VD);
9465 // Base is the base of the struct
9466 CombinedInfo.BasePointers.push_back(PartialStruct.Base.emitRawPointer(CGF));
9467 CombinedInfo.DevicePtrDecls.push_back(nullptr);
9468 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
9469 // Pointer is the address of the lowest element
9470 llvm::Value *LB = LBAddr.emitRawPointer(CGF);
9471 const CXXMethodDecl *MD =
9472 CGF.CurFuncDecl ? dyn_cast<CXXMethodDecl>(CGF.CurFuncDecl) : nullptr;
9473 const CXXRecordDecl *RD = MD ? MD->getParent() : nullptr;
9474 bool HasBaseClass = RD && IsMapThis ? RD->getNumBases() > 0 : false;
9475 // There should not be a mapper for a combined entry.
9476 if (HasBaseClass) {
9477 // OpenMP 5.2 148:21:
9478 // If the target construct is within a class non-static member function,
9479 // and a variable is an accessible data member of the object for which the
9480 // non-static data member function is invoked, the variable is treated as
9481 // if the this[:1] expression had appeared in a map clause with a map-type
9482 // of tofrom.
9483 // Emit this[:1]
9484 CombinedInfo.Pointers.push_back(PartialStruct.Base.emitRawPointer(CGF));
9485 QualType Ty = MD->getFunctionObjectParameterType();
9486 llvm::Value *Size =
9487 CGF.Builder.CreateIntCast(CGF.getTypeSize(Ty), CGF.Int64Ty,
9488 /*isSigned=*/true);
9489 CombinedInfo.Sizes.push_back(Size);
9490 } else {
9491 CombinedInfo.Pointers.push_back(LB);
9492 // Size is (addr of {highest+1} element) - (addr of lowest element)
9493 llvm::Value *HB = HBAddr.emitRawPointer(CGF);
9494 llvm::Value *HAddr = CGF.Builder.CreateConstGEP1_32(
9495 HBAddr.getElementType(), HB, /*Idx0=*/1);
9496 llvm::Value *CLAddr = CGF.Builder.CreatePointerCast(LB, CGF.VoidPtrTy);
9497 llvm::Value *CHAddr = CGF.Builder.CreatePointerCast(HAddr, CGF.VoidPtrTy);
9498 llvm::Value *Diff = CGF.Builder.CreatePtrDiff(CHAddr, CLAddr);
9499 llvm::Value *Size = CGF.Builder.CreateIntCast(Diff, CGF.Int64Ty,
9500 /*isSigned=*/false);
9501 CombinedInfo.Sizes.push_back(Size);
9502 }
9503 CombinedInfo.Mappers.push_back(nullptr);
9504 // Map type is always TARGET_PARAM, if generate info for captures.
9505 CombinedInfo.Types.push_back(
9506 NotTargetParams ? OpenMPOffloadMappingFlags::OMP_MAP_NONE
9507 : !PartialStruct.PreliminaryMapData.BasePointers.empty()
9508 ? OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ
9509 : OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM);
9510 // A combined entry has a base attach-ptr if its constituents do. e.g.:
9511 // map(s2.s1p->x, s2.s1p->y)
9512 // combined entry:
9513 // s2.s1p[0], s2.s1p->x, sizeof(s1p->x..y), ALLOC
9514 // here s2.s1p is the attach-ptr for the combined entry.
9515 // See the inline comments in emitUserDefinedMapper's definition for how
9516 // entries with an attach-ptr are treated.
9517 CombinedInfo.HasAttachPtr.push_back(AttachInfo.isValid());
9518 // If any element has the present modifier, then make sure the runtime
9519 // doesn't attempt to allocate the struct.
9520 if (CurTypes.end() !=
9521 llvm::find_if(CurTypes, [](OpenMPOffloadMappingFlags Type) {
9522 return static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
9523 Type & OpenMPOffloadMappingFlags::OMP_MAP_PRESENT);
9524 }))
9525 CombinedInfo.Types.back() |= OpenMPOffloadMappingFlags::OMP_MAP_PRESENT;
9526 // Remove TARGET_PARAM flag from the first element
9527 (*CurTypes.begin()) &= ~OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM;
9528 // If any element has the ompx_hold modifier, then make sure the runtime
9529 // uses the hold reference count for the struct as a whole so that it won't
9530 // be unmapped by an extra dynamic reference count decrement. Add it to all
9531 // elements as well so the runtime knows which reference count to check
9532 // when determining whether it's time for device-to-host transfers of
9533 // individual elements.
9534 if (CurTypes.end() !=
9535 llvm::find_if(CurTypes, [](OpenMPOffloadMappingFlags Type) {
9536 return static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
9537 Type & OpenMPOffloadMappingFlags::OMP_MAP_OMPX_HOLD);
9538 })) {
9539 CombinedInfo.Types.back() |= OpenMPOffloadMappingFlags::OMP_MAP_OMPX_HOLD;
9540 for (auto &M : CurTypes)
9541 M |= OpenMPOffloadMappingFlags::OMP_MAP_OMPX_HOLD;
9542 }
9543
9544 // All other current entries will be MEMBER_OF the combined entry
9545 // (except for PTR_AND_OBJ entries which do not have a placeholder value
9546 // 0xFFFF in the MEMBER_OF field, or ATTACH entries since they are expected
9547 // to be handled by themselves, after all other maps).
9548 OpenMPOffloadMappingFlags MemberOfFlag = OMPBuilder.getMemberOfFlag(
9549 OffsetForMemberOfFlag + CombinedInfo.BasePointers.size() - 1);
9550 for (auto &M : CurTypes)
9551 OMPBuilder.setCorrectMemberOfFlag(M, MemberOfFlag);
9552
9553 // When we are emitting a combined entry. If there were any pending
9554 // attachments to be done, we do them to the begin address of the combined
9555 // entry. Note that this means only one attachment per combined-entry will
9556 // be done. So, for instance, if we have:
9557 // S *ps;
9558 // ... map(ps->a, ps->b)
9559 // When we are emitting a combined entry. If AttachInfo is valid,
9560 // update the pointee address to point to the begin address of the combined
9561 // entry. This ensures that if we have multiple maps like:
9562 // `map(ps->a, ps->b)`, we still get a single ATTACH entry, like:
9563 //
9564 // &ps[0], &ps->a, sizeof(ps->a to ps->b), ALLOC // combined-entry
9565 // &ps[0], &ps->a, sizeof(ps->a), TO | FROM
9566 // &ps[0], &ps->b, sizeof(ps->b), TO | FROM
9567 // &ps, &ps->a, sizeof(void*), ATTACH // Use combined-entry's LB
9568 if (AttachInfo.isValid())
9569 AttachInfo.AttachPteeAddr = LBAddr;
9570 }
9571
9572 /// Generate all the base pointers, section pointers, sizes, map types, and
9573 /// mappers for the extracted mappable expressions (all included in \a
9574 /// CombinedInfo). Also, for each item that relates with a device pointer, a
9575 /// pair of the relevant declaration and index where it occurs is appended to
9576 /// the device pointers info array.
9577 void generateAllInfo(
9578 MapCombinedInfoTy &CombinedInfo, llvm::OpenMPIRBuilder &OMPBuilder,
9579 const llvm::DenseSet<CanonicalDeclPtr<const Decl>> &SkipVarSet =
9580 llvm::DenseSet<CanonicalDeclPtr<const Decl>>()) const {
9581 assert(isa<const OMPExecutableDirective *>(CurDir) &&
9582 "Expect a executable directive");
9583 const auto *CurExecDir = cast<const OMPExecutableDirective *>(CurDir);
9584 generateAllInfoForClauses(CurExecDir->clauses(), CombinedInfo, OMPBuilder,
9585 SkipVarSet);
9586 }
9587
9588 /// Generate all the base pointers, section pointers, sizes, map types, and
9589 /// mappers for the extracted map clauses of user-defined mapper (all included
9590 /// in \a CombinedInfo).
9591 void generateAllInfoForMapper(MapCombinedInfoTy &CombinedInfo,
9592 llvm::OpenMPIRBuilder &OMPBuilder) const {
9593 assert(isa<const OMPDeclareMapperDecl *>(CurDir) &&
9594 "Expect a declare mapper directive");
9595 const auto *CurMapperDir = cast<const OMPDeclareMapperDecl *>(CurDir);
9596 generateAllInfoForClauses(CurMapperDir->clauses(), CombinedInfo,
9597 OMPBuilder);
9598 }
9599
9600 /// Emit capture info for lambdas for variables captured by reference.
9601 void generateInfoForLambdaCaptures(
9602 const ValueDecl *VD, llvm::Value *Arg, MapCombinedInfoTy &CombinedInfo,
9603 llvm::DenseMap<llvm::Value *, llvm::Value *> &LambdaPointers) const {
9604 QualType VDType = VD->getType().getCanonicalType().getNonReferenceType();
9605 const auto *RD = VDType->getAsCXXRecordDecl();
9606 if (!RD || !RD->isLambda())
9607 return;
9608 Address VDAddr(Arg, CGF.ConvertTypeForMem(VDType),
9609 CGF.getContext().getDeclAlign(VD));
9610 LValue VDLVal = CGF.MakeAddrLValue(VDAddr, VDType);
9611 llvm::DenseMap<const ValueDecl *, FieldDecl *> Captures;
9612 FieldDecl *ThisCapture = nullptr;
9613 RD->getCaptureFields(Captures, ThisCapture);
9614 if (ThisCapture) {
9615 LValue ThisLVal =
9616 CGF.EmitLValueForFieldInitialization(VDLVal, ThisCapture);
9617 LValue ThisLValVal = CGF.EmitLValueForField(VDLVal, ThisCapture);
9618 LambdaPointers.try_emplace(ThisLVal.getPointer(CGF),
9619 VDLVal.getPointer(CGF));
9620 CombinedInfo.Exprs.push_back(VD);
9621 CombinedInfo.BasePointers.push_back(ThisLVal.getPointer(CGF));
9622 CombinedInfo.DevicePtrDecls.push_back(nullptr);
9623 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
9624 CombinedInfo.Pointers.push_back(ThisLValVal.getPointer(CGF));
9625 CombinedInfo.Sizes.push_back(
9626 CGF.Builder.CreateIntCast(CGF.getTypeSize(CGF.getContext().VoidPtrTy),
9627 CGF.Int64Ty, /*isSigned=*/true));
9628 CombinedInfo.Types.push_back(
9629 OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ |
9630 OpenMPOffloadMappingFlags::OMP_MAP_LITERAL |
9631 OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF |
9632 OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT);
9633 CombinedInfo.HasAttachPtr.push_back(false);
9634 CombinedInfo.Mappers.push_back(nullptr);
9635 }
9636 for (const LambdaCapture &LC : RD->captures()) {
9637 if (!LC.capturesVariable())
9638 continue;
9639 const VarDecl *VD = cast<VarDecl>(LC.getCapturedVar());
9640 if (LC.getCaptureKind() != LCK_ByRef && !VD->getType()->isPointerType())
9641 continue;
9642 auto It = Captures.find(VD);
9643 assert(It != Captures.end() && "Found lambda capture without field.");
9644 LValue VarLVal = CGF.EmitLValueForFieldInitialization(VDLVal, It->second);
9645 if (LC.getCaptureKind() == LCK_ByRef) {
9646 LValue VarLValVal = CGF.EmitLValueForField(VDLVal, It->second);
9647 LambdaPointers.try_emplace(VarLVal.getPointer(CGF),
9648 VDLVal.getPointer(CGF));
9649 CombinedInfo.Exprs.push_back(VD);
9650 CombinedInfo.BasePointers.push_back(VarLVal.getPointer(CGF));
9651 CombinedInfo.DevicePtrDecls.push_back(nullptr);
9652 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
9653 CombinedInfo.Pointers.push_back(VarLValVal.getPointer(CGF));
9654 CombinedInfo.Sizes.push_back(CGF.Builder.CreateIntCast(
9655 CGF.getTypeSize(
9657 CGF.Int64Ty, /*isSigned=*/true));
9658 } else {
9659 RValue VarRVal = CGF.EmitLoadOfLValue(VarLVal, RD->getLocation());
9660 LambdaPointers.try_emplace(VarLVal.getPointer(CGF),
9661 VDLVal.getPointer(CGF));
9662 CombinedInfo.Exprs.push_back(VD);
9663 CombinedInfo.BasePointers.push_back(VarLVal.getPointer(CGF));
9664 CombinedInfo.DevicePtrDecls.push_back(nullptr);
9665 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
9666 CombinedInfo.Pointers.push_back(VarRVal.getScalarVal());
9667 CombinedInfo.Sizes.push_back(llvm::ConstantInt::get(CGF.Int64Ty, 0));
9668 }
9669 CombinedInfo.Types.push_back(
9670 OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ |
9671 OpenMPOffloadMappingFlags::OMP_MAP_LITERAL |
9672 OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF |
9673 OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT);
9674 CombinedInfo.HasAttachPtr.push_back(false);
9675 CombinedInfo.Mappers.push_back(nullptr);
9676 }
9677 }
9678
9679 /// Set correct indices for lambdas captures.
9680 void adjustMemberOfForLambdaCaptures(
9681 llvm::OpenMPIRBuilder &OMPBuilder,
9682 const llvm::DenseMap<llvm::Value *, llvm::Value *> &LambdaPointers,
9683 MapBaseValuesArrayTy &BasePointers, MapValuesArrayTy &Pointers,
9684 MapFlagsArrayTy &Types) const {
9685 for (unsigned I = 0, E = Types.size(); I < E; ++I) {
9686 // Set correct member_of idx for all implicit lambda captures.
9687 if (Types[I] != (OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ |
9688 OpenMPOffloadMappingFlags::OMP_MAP_LITERAL |
9689 OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF |
9690 OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT))
9691 continue;
9692 llvm::Value *BasePtr = LambdaPointers.lookup(BasePointers[I]);
9693 assert(BasePtr && "Unable to find base lambda address.");
9694 int TgtIdx = -1;
9695 for (unsigned J = I; J > 0; --J) {
9696 unsigned Idx = J - 1;
9697 if (Pointers[Idx] != BasePtr)
9698 continue;
9699 TgtIdx = Idx;
9700 break;
9701 }
9702 assert(TgtIdx != -1 && "Unable to find parent lambda.");
9703 // All other current entries will be MEMBER_OF the combined entry
9704 // (except for PTR_AND_OBJ entries which do not have a placeholder value
9705 // 0xFFFF in the MEMBER_OF field).
9706 OpenMPOffloadMappingFlags MemberOfFlag =
9707 OMPBuilder.getMemberOfFlag(TgtIdx);
9708 OMPBuilder.setCorrectMemberOfFlag(Types[I], MemberOfFlag);
9709 }
9710 }
9711
9712 /// Populate component lists for non-lambda captured variables from map,
9713 /// is_device_ptr and has_device_addr clause info.
9714 void populateComponentListsForNonLambdaCaptureFromClauses(
9715 const ValueDecl *VD, MapDataArrayTy &DeclComponentLists,
9716 SmallVectorImpl<
9717 SmallVector<OMPClauseMappableExprCommon::MappableComponent, 8>>
9718 &StorageForImplicitlyAddedComponentLists) const {
9719 if (VD && LambdasMap.count(VD))
9720 return;
9721
9722 // For member fields list in is_device_ptr, store it in
9723 // DeclComponentLists for generating components info.
9725 auto It = DevPointersMap.find(VD);
9726 if (It != DevPointersMap.end())
9727 for (const auto &MCL : It->second)
9728 DeclComponentLists.emplace_back(MCL, OMPC_MAP_to, Unknown,
9729 /*IsImpicit = */ true, nullptr,
9730 nullptr);
9731 auto I = HasDevAddrsMap.find(VD);
9732 if (I != HasDevAddrsMap.end())
9733 for (const auto &MCL : I->second)
9734 DeclComponentLists.emplace_back(MCL, OMPC_MAP_tofrom, Unknown,
9735 /*IsImpicit = */ true, nullptr,
9736 nullptr);
9737 assert(isa<const OMPExecutableDirective *>(CurDir) &&
9738 "Expect a executable directive");
9739 const auto *CurExecDir = cast<const OMPExecutableDirective *>(CurDir);
9740 for (const auto *C : CurExecDir->getClausesOfKind<OMPMapClause>()) {
9741 const auto *EI = C->getVarRefs().begin();
9742 for (const auto L : C->decl_component_lists(VD)) {
9743 const ValueDecl *VDecl, *Mapper;
9744 // The Expression is not correct if the mapping is implicit
9745 const Expr *E = (C->getMapLoc().isValid()) ? *EI : nullptr;
9747 std::tie(VDecl, Components, Mapper) = L;
9748 assert(VDecl == VD && "We got information for the wrong declaration??");
9749 assert(!Components.empty() &&
9750 "Not expecting declaration with no component lists.");
9751 DeclComponentLists.emplace_back(Components, C->getMapType(),
9752 C->getMapTypeModifiers(),
9753 C->isImplicit(), Mapper, E);
9754 ++EI;
9755 }
9756 }
9757
9758 // For the target construct, if there's a map with a base-pointer that's
9759 // a member of an implicitly captured struct, of the current class,
9760 // we need to emit an implicit map on the pointer.
9761 if (isOpenMPTargetExecutionDirective(CurExecDir->getDirectiveKind()))
9762 addImplicitMapForAttachPtrBaseIfMemberOfCapturedVD(
9763 VD, DeclComponentLists, StorageForImplicitlyAddedComponentLists);
9764
9765 llvm::stable_sort(DeclComponentLists, [](const MapData &LHS,
9766 const MapData &RHS) {
9767 ArrayRef<OpenMPMapModifierKind> MapModifiers = std::get<2>(LHS);
9768 OpenMPMapClauseKind MapType = std::get<1>(RHS);
9769 bool HasPresent =
9770 llvm::is_contained(MapModifiers, clang::OMPC_MAP_MODIFIER_present);
9771 bool HasAllocs = MapType == OMPC_MAP_alloc;
9772 MapModifiers = std::get<2>(RHS);
9773 MapType = std::get<1>(LHS);
9774 bool HasPresentR =
9775 llvm::is_contained(MapModifiers, clang::OMPC_MAP_MODIFIER_present);
9776 bool HasAllocsR = MapType == OMPC_MAP_alloc;
9777 return (HasPresent && !HasPresentR) || (HasAllocs && !HasAllocsR);
9778 });
9779 }
9780
9781 /// On a target construct, if there's an implicit map on a struct, or that of
9782 /// this[:], and an explicit map with a member of that struct/class as the
9783 /// base-pointer, we need to make sure that base-pointer is implicitly mapped,
9784 /// to make sure we don't map the full struct/class. For example:
9785 ///
9786 /// \code
9787 /// struct S {
9788 /// int dummy[10000];
9789 /// int *p;
9790 /// void f1() {
9791 /// #pragma omp target map(p[0:1])
9792 /// (void)this;
9793 /// }
9794 /// }; S s;
9795 ///
9796 /// void f2() {
9797 /// #pragma omp target map(s.p[0:10])
9798 /// (void)s;
9799 /// }
9800 /// \endcode
9801 ///
9802 /// Only `this-p` and `s.p` should be mapped in the two cases above.
9803 //
9804 // OpenMP 6.0: 7.9.6 map clause, pg 285
9805 // If a list item with an implicitly determined data-mapping attribute does
9806 // not have any corresponding storage in the device data environment prior to
9807 // a task encountering the construct associated with the map clause, and one
9808 // or more contiguous parts of the original storage are either list items or
9809 // base pointers to list items that are explicitly mapped on the construct,
9810 // only those parts of the original storage will have corresponding storage in
9811 // the device data environment as a result of the map clauses on the
9812 // construct.
9813 void addImplicitMapForAttachPtrBaseIfMemberOfCapturedVD(
9814 const ValueDecl *CapturedVD, MapDataArrayTy &DeclComponentLists,
9815 SmallVectorImpl<
9816 SmallVector<OMPClauseMappableExprCommon::MappableComponent, 8>>
9817 &ComponentVectorStorage) const {
9818 bool IsThisCapture = CapturedVD == nullptr;
9819
9820 for (const auto &ComponentsAndAttachPtr : AttachPtrExprMap) {
9822 ComponentsWithAttachPtr = ComponentsAndAttachPtr.first;
9823 const Expr *AttachPtrExpr = ComponentsAndAttachPtr.second;
9824 if (!AttachPtrExpr)
9825 continue;
9826
9827 const auto *ME = dyn_cast<MemberExpr>(AttachPtrExpr);
9828 if (!ME)
9829 continue;
9830
9831 const Expr *Base = ME->getBase()->IgnoreParenImpCasts();
9832
9833 // If we are handling a "this" capture, then we are looking for
9834 // attach-ptrs of form `this->p`, either explicitly or implicitly.
9835 if (IsThisCapture && !ME->isImplicitCXXThis() && !isa<CXXThisExpr>(Base))
9836 continue;
9837
9838 if (!IsThisCapture && (!isa<DeclRefExpr>(Base) ||
9839 cast<DeclRefExpr>(Base)->getDecl() != CapturedVD))
9840 continue;
9841
9842 // For non-this captures, we are looking for attach-ptrs of form
9843 // `s.p`.
9844 // For non-this captures, we are looking for attach-ptrs like `s.p`.
9845 if (!IsThisCapture && (ME->isArrow() || !isa<DeclRefExpr>(Base) ||
9846 cast<DeclRefExpr>(Base)->getDecl() != CapturedVD))
9847 continue;
9848
9849 // Check if we have an existing map on either:
9850 // this[:], s, this->p, or s.p, in which case, we don't need to add
9851 // an implicit one for the attach-ptr s.p/this->p.
9852 bool FoundExistingMap = false;
9853 for (const MapData &ExistingL : DeclComponentLists) {
9855 ExistingComponents = std::get<0>(ExistingL);
9856
9857 if (ExistingComponents.empty())
9858 continue;
9859
9860 // First check if we have a map like map(this->p) or map(s.p).
9861 const auto &FirstComponent = ExistingComponents.front();
9862 const Expr *FirstExpr = FirstComponent.getAssociatedExpression();
9863
9864 if (!FirstExpr)
9865 continue;
9866
9867 // First check if we have a map like map(this->p) or map(s.p).
9868 if (AttachPtrComparator.areEqual(FirstExpr, AttachPtrExpr)) {
9869 FoundExistingMap = true;
9870 break;
9871 }
9872
9873 // Check if we have a map like this[0:1]
9874 if (IsThisCapture) {
9875 if (const auto *OASE = dyn_cast<ArraySectionExpr>(FirstExpr)) {
9876 if (isa<CXXThisExpr>(OASE->getBase()->IgnoreParenImpCasts())) {
9877 FoundExistingMap = true;
9878 break;
9879 }
9880 }
9881 continue;
9882 }
9883
9884 // When the attach-ptr is something like `s.p`, check if
9885 // `s` itself is mapped explicitly.
9886 if (const auto *DRE = dyn_cast<DeclRefExpr>(FirstExpr)) {
9887 if (DRE->getDecl() == CapturedVD) {
9888 FoundExistingMap = true;
9889 break;
9890 }
9891 }
9892 }
9893
9894 if (FoundExistingMap)
9895 continue;
9896
9897 // If no base map is found, we need to create an implicit map for the
9898 // attach-pointer expr.
9899
9900 ComponentVectorStorage.emplace_back();
9901 auto &AttachPtrComponents = ComponentVectorStorage.back();
9902
9904 bool SeenAttachPtrComponent = false;
9905 // For creating a map on the attach-ptr `s.p/this->p`, we copy all
9906 // components from the component-list which has `s.p/this->p`
9907 // as the attach-ptr, starting from the component which matches
9908 // `s.p/this->p`. This way, we'll have component-lists of
9909 // `s.p` -> `s`, and `this->p` -> `this`.
9910 for (size_t i = 0; i < ComponentsWithAttachPtr.size(); ++i) {
9911 const auto &Component = ComponentsWithAttachPtr[i];
9912 const Expr *ComponentExpr = Component.getAssociatedExpression();
9913
9914 if (!SeenAttachPtrComponent && ComponentExpr != AttachPtrExpr)
9915 continue;
9916 SeenAttachPtrComponent = true;
9917
9918 AttachPtrComponents.emplace_back(Component.getAssociatedExpression(),
9919 Component.getAssociatedDeclaration(),
9920 Component.isNonContiguous());
9921 }
9922 assert(!AttachPtrComponents.empty() &&
9923 "Could not populate component-lists for mapping attach-ptr");
9924
9925 DeclComponentLists.emplace_back(
9926 AttachPtrComponents, OMPC_MAP_tofrom, Unknown,
9927 /*IsImplicit=*/true, /*mapper=*/nullptr, AttachPtrExpr);
9928 }
9929 }
9930
9931 /// For a capture that has an associated clause, generate the base pointers,
9932 /// section pointers, sizes, map types, and mappers (all included in
9933 /// \a CurCaptureVarInfo).
9934 void generateInfoForCaptureFromClauseInfo(
9935 const MapDataArrayTy &DeclComponentListsFromClauses,
9936 const CapturedStmt::Capture *Cap, llvm::Value *Arg,
9937 MapCombinedInfoTy &CurCaptureVarInfo, llvm::OpenMPIRBuilder &OMPBuilder,
9938 unsigned OffsetForMemberOfFlag) const {
9939 assert(!Cap->capturesVariableArrayType() &&
9940 "Not expecting to generate map info for a variable array type!");
9941
9942 // We need to know when we generating information for the first component
9943 const ValueDecl *VD = Cap->capturesThis()
9944 ? nullptr
9945 : Cap->getCapturedVar()->getCanonicalDecl();
9946
9947 // for map(to: lambda): skip here, processing it in
9948 // generateDefaultMapInfo
9949 if (LambdasMap.count(VD))
9950 return;
9951
9952 // If this declaration appears in a is_device_ptr clause we just have to
9953 // pass the pointer by value. If it is a reference to a declaration, we just
9954 // pass its value.
9955 if (VD && (DevPointersMap.count(VD) || HasDevAddrsMap.count(VD))) {
9956 CurCaptureVarInfo.Exprs.push_back(VD);
9957 CurCaptureVarInfo.BasePointers.emplace_back(Arg);
9958 CurCaptureVarInfo.DevicePtrDecls.emplace_back(VD);
9959 CurCaptureVarInfo.DevicePointers.emplace_back(DeviceInfoTy::Pointer);
9960 CurCaptureVarInfo.Pointers.push_back(Arg);
9961 CurCaptureVarInfo.Sizes.push_back(CGF.Builder.CreateIntCast(
9962 CGF.getTypeSize(CGF.getContext().VoidPtrTy), CGF.Int64Ty,
9963 /*isSigned=*/true));
9964 CurCaptureVarInfo.Types.push_back(
9965 OpenMPOffloadMappingFlags::OMP_MAP_LITERAL |
9966 OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM);
9967 CurCaptureVarInfo.HasAttachPtr.push_back(false);
9968 CurCaptureVarInfo.Mappers.push_back(nullptr);
9969 return;
9970 }
9971
9972 auto GenerateInfoForComponentLists =
9973 [&](ArrayRef<MapData> DeclComponentListsFromClauses,
9974 bool IsEligibleForTargetParamFlag) {
9975 MapCombinedInfoTy CurInfoForComponentLists;
9976 StructRangeInfoTy PartialStruct;
9977 AttachInfoTy AttachInfo;
9978
9979 if (DeclComponentListsFromClauses.empty())
9980 return;
9981
9982 generateInfoForCaptureFromComponentLists(
9983 VD, DeclComponentListsFromClauses, CurInfoForComponentLists,
9984 PartialStruct, AttachInfo, IsEligibleForTargetParamFlag);
9985
9986 // If there is an entry in PartialStruct it means we have a
9987 // struct with individual members mapped. Emit an extra combined
9988 // entry.
9989 if (PartialStruct.Base.isValid()) {
9990 CurCaptureVarInfo.append(PartialStruct.PreliminaryMapData);
9991 emitCombinedEntry(
9992 CurCaptureVarInfo, CurInfoForComponentLists.Types,
9993 PartialStruct, AttachInfo, Cap->capturesThis(), OMPBuilder,
9994 /*VD=*/nullptr, OffsetForMemberOfFlag,
9995 /*NotTargetParams*/ !IsEligibleForTargetParamFlag);
9996 }
9997
9998 // We do the appends to get the entries in the following order:
9999 // combined-entry -> individual-field-entries -> attach-entry,
10000 CurCaptureVarInfo.append(CurInfoForComponentLists);
10001 if (AttachInfo.isValid())
10002 emitAttachEntry(CGF, CurCaptureVarInfo, AttachInfo);
10003 };
10004
10005 // Group component lists by their AttachPtrExpr and process them in order
10006 // of increasing complexity (nullptr first, then simple expressions like p,
10007 // then more complex ones like p[0], etc.)
10008 //
10009 // This ensure that we:
10010 // * handle maps that can contribute towards setting the kernel argument,
10011 // (e.g. map(ps), or map(ps[0])), before any that cannot (e.g. ps->pt->d).
10012 // * allocate a single contiguous storage for all exprs with the same
10013 // captured var and having the same attach-ptr.
10014 //
10015 // Example: The map clauses below should be handled grouped together based
10016 // on their attachable-base-pointers:
10017 // map-clause | attachable-base-pointer
10018 // --------------------------+------------------------
10019 // map(p, ps) | nullptr
10020 // map(p[0]) | p
10021 // map(p[0]->b, p[0]->c) | p[0]
10022 // map(ps->d, ps->e, ps->pt) | ps
10023 // map(ps->pt->d, ps->pt->e) | ps->pt
10024
10025 // First, collect all MapData entries with their attach-ptr exprs.
10026 SmallVector<std::pair<const Expr *, MapData>, 16> AttachPtrMapDataPairs;
10027
10028 for (const MapData &L : DeclComponentListsFromClauses) {
10030 std::get<0>(L);
10031 const Expr *AttachPtrExpr = getAttachPtrExpr(Components);
10032 AttachPtrMapDataPairs.emplace_back(AttachPtrExpr, L);
10033 }
10034
10035 // Next, sort by increasing order of their complexity.
10036 llvm::stable_sort(AttachPtrMapDataPairs,
10037 [this](const auto &LHS, const auto &RHS) {
10038 return AttachPtrComparator(LHS.first, RHS.first);
10039 });
10040
10041 bool NoDefaultMappingDoneForVD = CurCaptureVarInfo.BasePointers.empty();
10042 bool IsFirstGroup = true;
10043
10044 // And finally, process them all in order, grouping those with
10045 // equivalent attach-ptr exprs together.
10046 auto *It = AttachPtrMapDataPairs.begin();
10047 while (It != AttachPtrMapDataPairs.end()) {
10048 const Expr *AttachPtrExpr = It->first;
10049
10050 MapDataArrayTy GroupLists;
10051 while (It != AttachPtrMapDataPairs.end() &&
10052 (It->first == AttachPtrExpr ||
10053 AttachPtrComparator.areEqual(It->first, AttachPtrExpr))) {
10054 GroupLists.push_back(It->second);
10055 ++It;
10056 }
10057 assert(!GroupLists.empty() && "GroupLists should not be empty");
10058
10059 // Determine if this group of component-lists is eligible for TARGET_PARAM
10060 // flag. Only the first group processed should be eligible, and only if no
10061 // default mapping was done.
10062 bool IsEligibleForTargetParamFlag =
10063 IsFirstGroup && NoDefaultMappingDoneForVD;
10064
10065 GenerateInfoForComponentLists(GroupLists, IsEligibleForTargetParamFlag);
10066 IsFirstGroup = false;
10067 }
10068 }
10069
10070 /// Generate the base pointers, section pointers, sizes, map types, and
10071 /// mappers associated to \a DeclComponentLists for a given capture
10072 /// \a VD (all included in \a CurComponentListInfo).
10073 void generateInfoForCaptureFromComponentLists(
10074 const ValueDecl *VD, ArrayRef<MapData> DeclComponentLists,
10075 MapCombinedInfoTy &CurComponentListInfo, StructRangeInfoTy &PartialStruct,
10076 AttachInfoTy &AttachInfo, bool IsListEligibleForTargetParamFlag) const {
10077 // Find overlapping elements (including the offset from the base element).
10078 llvm::SmallDenseMap<
10079 const MapData *,
10080 llvm::SmallVector<
10082 4>
10083 OverlappedData;
10084 size_t Count = 0;
10085 for (const MapData &L : DeclComponentLists) {
10087 OpenMPMapClauseKind MapType;
10088 ArrayRef<OpenMPMapModifierKind> MapModifiers;
10089 bool IsImplicit;
10090 const ValueDecl *Mapper;
10091 const Expr *VarRef;
10092 std::tie(Components, MapType, MapModifiers, IsImplicit, Mapper, VarRef) =
10093 L;
10094 ++Count;
10095 for (const MapData &L1 : ArrayRef(DeclComponentLists).slice(Count)) {
10097 std::tie(Components1, MapType, MapModifiers, IsImplicit, Mapper,
10098 VarRef) = L1;
10099 auto CI = Components.rbegin();
10100 auto CE = Components.rend();
10101 auto SI = Components1.rbegin();
10102 auto SE = Components1.rend();
10103 for (; CI != CE && SI != SE; ++CI, ++SI) {
10104 if (CI->getAssociatedExpression()->getStmtClass() !=
10105 SI->getAssociatedExpression()->getStmtClass())
10106 break;
10107 // Are we dealing with different variables/fields?
10108 if (CI->getAssociatedDeclaration() != SI->getAssociatedDeclaration())
10109 break;
10110 }
10111 // Found overlapping if, at least for one component, reached the head
10112 // of the components list.
10113 if (CI == CE || SI == SE) {
10114 // Ignore it if it is the same component.
10115 if (CI == CE && SI == SE)
10116 continue;
10117 const auto It = (SI == SE) ? CI : SI;
10118 // If one component is a pointer and another one is a kind of
10119 // dereference of this pointer (array subscript, section, dereference,
10120 // etc.), it is not an overlapping.
10121 // Same, if one component is a base and another component is a
10122 // dereferenced pointer memberexpr with the same base.
10123 if (!isa<MemberExpr>(It->getAssociatedExpression()) ||
10124 (std::prev(It)->getAssociatedDeclaration() &&
10125 std::prev(It)
10126 ->getAssociatedDeclaration()
10127 ->getType()
10128 ->isPointerType()) ||
10129 (It->getAssociatedDeclaration() &&
10130 It->getAssociatedDeclaration()->getType()->isPointerType() &&
10131 std::next(It) != CE && std::next(It) != SE))
10132 continue;
10133 const MapData &BaseData = CI == CE ? L : L1;
10135 SI == SE ? Components : Components1;
10136 OverlappedData[&BaseData].push_back(SubData);
10137 }
10138 }
10139 }
10140 // Sort the overlapped elements for each item.
10141 llvm::SmallVector<const FieldDecl *, 4> Layout;
10142 if (!OverlappedData.empty()) {
10143 const Type *BaseType = VD->getType().getCanonicalType().getTypePtr();
10144 const Type *OrigType = BaseType->getPointeeOrArrayElementType();
10145 while (BaseType != OrigType) {
10146 BaseType = OrigType->getCanonicalTypeInternal().getTypePtr();
10147 OrigType = BaseType->getPointeeOrArrayElementType();
10148 }
10149
10150 if (const auto *CRD = BaseType->getAsCXXRecordDecl())
10151 getPlainLayout(CRD, Layout, /*AsBase=*/false);
10152 else {
10153 const auto *RD = BaseType->getAsRecordDecl();
10154 Layout.append(RD->field_begin(), RD->field_end());
10155 }
10156 }
10157 for (auto &Pair : OverlappedData) {
10158 llvm::stable_sort(
10159 Pair.getSecond(),
10160 [&Layout](
10163 Second) {
10164 auto CI = First.rbegin();
10165 auto CE = First.rend();
10166 auto SI = Second.rbegin();
10167 auto SE = Second.rend();
10168 for (; CI != CE && SI != SE; ++CI, ++SI) {
10169 if (CI->getAssociatedExpression()->getStmtClass() !=
10170 SI->getAssociatedExpression()->getStmtClass())
10171 break;
10172 // Are we dealing with different variables/fields?
10173 if (CI->getAssociatedDeclaration() !=
10174 SI->getAssociatedDeclaration())
10175 break;
10176 }
10177
10178 // Lists contain the same elements.
10179 if (CI == CE && SI == SE)
10180 return false;
10181
10182 // List with less elements is less than list with more elements.
10183 if (CI == CE || SI == SE)
10184 return CI == CE;
10185
10186 const auto *FD1 = cast<FieldDecl>(CI->getAssociatedDeclaration());
10187 const auto *FD2 = cast<FieldDecl>(SI->getAssociatedDeclaration());
10188 if (FD1->getParent() == FD2->getParent())
10189 return FD1->getFieldIndex() < FD2->getFieldIndex();
10190 const auto *It =
10191 llvm::find_if(Layout, [FD1, FD2](const FieldDecl *FD) {
10192 return FD == FD1 || FD == FD2;
10193 });
10194 return *It == FD1;
10195 });
10196 }
10197
10198 // Associated with a capture, because the mapping flags depend on it.
10199 // Go through all of the elements with the overlapped elements.
10200 bool AddTargetParamFlag = IsListEligibleForTargetParamFlag;
10201 MapCombinedInfoTy StructBaseCombinedInfo;
10202 for (const auto &Pair : OverlappedData) {
10203 const MapData &L = *Pair.getFirst();
10205 OpenMPMapClauseKind MapType;
10206 ArrayRef<OpenMPMapModifierKind> MapModifiers;
10207 bool IsImplicit;
10208 const ValueDecl *Mapper;
10209 const Expr *VarRef;
10210 std::tie(Components, MapType, MapModifiers, IsImplicit, Mapper, VarRef) =
10211 L;
10212 ArrayRef<OMPClauseMappableExprCommon::MappableExprComponentListRef>
10213 OverlappedComponents = Pair.getSecond();
10214 generateInfoForComponentList(
10215 MapType, MapModifiers, {}, Components, CurComponentListInfo,
10216 StructBaseCombinedInfo, PartialStruct, AttachInfo, AddTargetParamFlag,
10217 IsImplicit, /*GenerateAllInfoForClauses*/ false, Mapper,
10218 /*ForDeviceAddr=*/false, VD, VarRef, OverlappedComponents);
10219 AddTargetParamFlag = false;
10220 }
10221 // Go through other elements without overlapped elements.
10222 for (const MapData &L : DeclComponentLists) {
10224 OpenMPMapClauseKind MapType;
10225 ArrayRef<OpenMPMapModifierKind> MapModifiers;
10226 bool IsImplicit;
10227 const ValueDecl *Mapper;
10228 const Expr *VarRef;
10229 std::tie(Components, MapType, MapModifiers, IsImplicit, Mapper, VarRef) =
10230 L;
10231 auto It = OverlappedData.find(&L);
10232 if (It == OverlappedData.end())
10233 generateInfoForComponentList(
10234 MapType, MapModifiers, {}, Components, CurComponentListInfo,
10235 StructBaseCombinedInfo, PartialStruct, AttachInfo,
10236 AddTargetParamFlag, IsImplicit, /*GenerateAllInfoForClauses*/ false,
10237 Mapper, /*ForDeviceAddr=*/false, VD, VarRef,
10238 /*OverlappedElements*/ {});
10239 AddTargetParamFlag = false;
10240 }
10241 }
10242
10243 /// Check if a variable should be treated as firstprivate due to explicit
10244 /// firstprivate clause or defaultmap(firstprivate:...).
10245 bool isEffectivelyFirstprivate(const VarDecl *VD, QualType Type) const {
10246 // Check explicit firstprivate clauses (not implicit from defaultmap)
10247 auto I = FirstPrivateDecls.find(VD);
10248 if (I != FirstPrivateDecls.end() && !I->getSecond())
10249 return true; // Explicit firstprivate only
10250
10251 // Check defaultmap(firstprivate:scalar) for scalar types
10252 if (DefaultmapFirstprivateKinds.count(OMPC_DEFAULTMAP_scalar)) {
10253 if (Type->isScalarType())
10254 return true;
10255 }
10256
10257 // Check defaultmap(firstprivate:pointer) for pointer types
10258 if (DefaultmapFirstprivateKinds.count(OMPC_DEFAULTMAP_pointer)) {
10259 if (Type->isAnyPointerType())
10260 return true;
10261 }
10262
10263 // Check defaultmap(firstprivate:aggregate) for aggregate types
10264 if (DefaultmapFirstprivateKinds.count(OMPC_DEFAULTMAP_aggregate)) {
10265 if (Type->isAggregateType())
10266 return true;
10267 }
10268
10269 // Check defaultmap(firstprivate:all) for all types
10270 return DefaultmapFirstprivateKinds.count(OMPC_DEFAULTMAP_all);
10271 }
10272
10273 /// Generate the default map information for a given capture \a CI,
10274 /// record field declaration \a RI and captured value \a CV.
10275 void generateDefaultMapInfo(const CapturedStmt::Capture &CI,
10276 const FieldDecl &RI, llvm::Value *CV,
10277 MapCombinedInfoTy &CombinedInfo) const {
10278 bool IsImplicit = true;
10279 // Do the default mapping.
10280 if (CI.capturesThis()) {
10281 CombinedInfo.Exprs.push_back(nullptr);
10282 CombinedInfo.BasePointers.push_back(CV);
10283 CombinedInfo.DevicePtrDecls.push_back(nullptr);
10284 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
10285 CombinedInfo.Pointers.push_back(CV);
10286 const auto *PtrTy = cast<PointerType>(RI.getType().getTypePtr());
10287 CombinedInfo.Sizes.push_back(
10288 CGF.Builder.CreateIntCast(CGF.getTypeSize(PtrTy->getPointeeType()),
10289 CGF.Int64Ty, /*isSigned=*/true));
10290 // Default map type.
10291 CombinedInfo.Types.push_back(OpenMPOffloadMappingFlags::OMP_MAP_TO |
10292 OpenMPOffloadMappingFlags::OMP_MAP_FROM);
10293 } else if (CI.capturesVariableByCopy()) {
10294 const VarDecl *VD = CI.getCapturedVar();
10295 CombinedInfo.Exprs.push_back(VD->getCanonicalDecl());
10296 CombinedInfo.BasePointers.push_back(CV);
10297 CombinedInfo.DevicePtrDecls.push_back(nullptr);
10298 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
10299 CombinedInfo.Pointers.push_back(CV);
10300 bool IsFirstprivate =
10301 isEffectivelyFirstprivate(VD, RI.getType().getNonReferenceType());
10302
10303 if (!RI.getType()->isAnyPointerType()) {
10304 // We have to signal to the runtime captures passed by value that are
10305 // not pointers.
10306 CombinedInfo.Types.push_back(
10307 OpenMPOffloadMappingFlags::OMP_MAP_LITERAL);
10308 CombinedInfo.Sizes.push_back(CGF.Builder.CreateIntCast(
10309 CGF.getTypeSize(RI.getType()), CGF.Int64Ty, /*isSigned=*/true));
10310 } else if (IsFirstprivate) {
10311 // Firstprivate pointers should be passed by value (as literals)
10312 // without performing a present table lookup at runtime.
10313 CombinedInfo.Types.push_back(
10314 OpenMPOffloadMappingFlags::OMP_MAP_LITERAL);
10315 // Use zero size for pointer literals (just passing the pointer value)
10316 CombinedInfo.Sizes.push_back(llvm::Constant::getNullValue(CGF.Int64Ty));
10317 } else {
10318 // Pointers are implicitly mapped with a zero size and no flags
10319 // (other than first map that is added for all implicit maps).
10320 CombinedInfo.Types.push_back(OpenMPOffloadMappingFlags::OMP_MAP_NONE);
10321 CombinedInfo.Sizes.push_back(llvm::Constant::getNullValue(CGF.Int64Ty));
10322 }
10323 auto I = FirstPrivateDecls.find(VD);
10324 if (I != FirstPrivateDecls.end())
10325 IsImplicit = I->getSecond();
10326 } else {
10327 assert(CI.capturesVariable() && "Expected captured reference.");
10328 const auto *PtrTy = cast<ReferenceType>(RI.getType().getTypePtr());
10329 QualType ElementType = PtrTy->getPointeeType();
10330 const VarDecl *VD = CI.getCapturedVar();
10331 bool IsFirstprivate = isEffectivelyFirstprivate(VD, ElementType);
10332 CombinedInfo.Exprs.push_back(VD->getCanonicalDecl());
10333 CombinedInfo.BasePointers.push_back(CV);
10334 CombinedInfo.DevicePtrDecls.push_back(nullptr);
10335 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
10336
10337 // For firstprivate pointers, pass by value instead of dereferencing
10338 if (IsFirstprivate && ElementType->isAnyPointerType()) {
10339 // Treat as a literal value (pass the pointer value itself)
10340 CombinedInfo.Pointers.push_back(CV);
10341 // Use zero size for pointer literals
10342 CombinedInfo.Sizes.push_back(llvm::Constant::getNullValue(CGF.Int64Ty));
10343 CombinedInfo.Types.push_back(
10344 OpenMPOffloadMappingFlags::OMP_MAP_LITERAL);
10345 } else {
10346 CombinedInfo.Sizes.push_back(CGF.Builder.CreateIntCast(
10347 CGF.getTypeSize(ElementType), CGF.Int64Ty, /*isSigned=*/true));
10348 // The default map type for a scalar/complex type is 'to' because by
10349 // default the value doesn't have to be retrieved. For an aggregate
10350 // type, the default is 'tofrom'.
10351 CombinedInfo.Types.push_back(getMapModifiersForPrivateClauses(CI));
10352 CombinedInfo.Pointers.push_back(CV);
10353 }
10354 auto I = FirstPrivateDecls.find(VD);
10355 if (I != FirstPrivateDecls.end())
10356 IsImplicit = I->getSecond();
10357 }
10358 // Every default map produces a single argument which is a target parameter.
10359 CombinedInfo.Types.back() |=
10360 OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM;
10361
10362 // Add flag stating this is an implicit map.
10363 if (IsImplicit)
10364 CombinedInfo.Types.back() |= OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT;
10365
10366 CombinedInfo.HasAttachPtr.push_back(false);
10367 // No user-defined mapper for default mapping.
10368 CombinedInfo.Mappers.push_back(nullptr);
10369 }
10370};
10371} // anonymous namespace
10372
10373// Try to extract the base declaration from a `this->x` expression if possible.
10375 if (!E)
10376 return nullptr;
10377
10378 if (const auto *OASE = dyn_cast<ArraySectionExpr>(E->IgnoreParenCasts()))
10379 if (const MemberExpr *ME =
10380 dyn_cast<MemberExpr>(OASE->getBase()->IgnoreParenImpCasts()))
10381 return ME->getMemberDecl();
10382 return nullptr;
10383}
10384
10385/// Emit a string constant containing the names of the values mapped to the
10386/// offloading runtime library.
10387static llvm::Constant *
10388emitMappingInformation(CodeGenFunction &CGF, llvm::OpenMPIRBuilder &OMPBuilder,
10389 MappableExprsHandler::MappingExprInfo &MapExprs) {
10390
10391 uint32_t SrcLocStrSize;
10392 if (!MapExprs.getMapDecl() && !MapExprs.getMapExpr())
10393 return OMPBuilder.getOrCreateDefaultSrcLocStr(SrcLocStrSize);
10394
10395 SourceLocation Loc;
10396 if (!MapExprs.getMapDecl() && MapExprs.getMapExpr()) {
10397 if (const ValueDecl *VD = getDeclFromThisExpr(MapExprs.getMapExpr()))
10398 Loc = VD->getLocation();
10399 else
10400 Loc = MapExprs.getMapExpr()->getExprLoc();
10401 } else {
10402 Loc = MapExprs.getMapDecl()->getLocation();
10403 }
10404
10405 std::string ExprName;
10406 if (MapExprs.getMapExpr()) {
10408 llvm::raw_string_ostream OS(ExprName);
10409 MapExprs.getMapExpr()->printPretty(OS, nullptr, P);
10410 } else {
10411 ExprName = MapExprs.getMapDecl()->getNameAsString();
10412 }
10413
10414 std::string FileName;
10416 if (auto *DbgInfo = CGF.getDebugInfo())
10417 FileName = DbgInfo->remapDIPath(PLoc.getFilename());
10418 else
10419 FileName = PLoc.getFilename();
10420 return OMPBuilder.getOrCreateSrcLocStr(FileName, ExprName, PLoc.getLine(),
10421 PLoc.getColumn(), SrcLocStrSize);
10422}
10423/// Emit the arrays used to pass the captures and map information to the
10424/// offloading runtime library. If there is no map or capture information,
10425/// return nullptr by reference.
10427 CodeGenFunction &CGF, MappableExprsHandler::MapCombinedInfoTy &CombinedInfo,
10428 CGOpenMPRuntime::TargetDataInfo &Info, llvm::OpenMPIRBuilder &OMPBuilder,
10429 bool IsNonContiguous = false, bool ForEndCall = false) {
10430 CodeGenModule &CGM = CGF.CGM;
10431
10432 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
10433 InsertPointTy AllocaIP(CGF.AllocaInsertPt->getParent(),
10434 CGF.AllocaInsertPt->getIterator());
10435 InsertPointTy CodeGenIP(CGF.Builder.GetInsertBlock(),
10436 CGF.Builder.GetInsertPoint());
10437
10438 auto DeviceAddrCB = [&](unsigned int I, llvm::Value *NewDecl) {
10439 if (const ValueDecl *DevVD = CombinedInfo.DevicePtrDecls[I]) {
10440 Info.CaptureDeviceAddrMap.try_emplace(DevVD, NewDecl);
10441 }
10442 };
10443
10444 auto CustomMapperCB = [&](unsigned int I) {
10445 llvm::Function *MFunc = nullptr;
10446 if (CombinedInfo.Mappers[I]) {
10447 Info.HasMapper = true;
10449 cast<OMPDeclareMapperDecl>(CombinedInfo.Mappers[I]));
10450 }
10451 return MFunc;
10452 };
10453 cantFail(OMPBuilder.emitOffloadingArraysAndArgs(
10454 AllocaIP, CodeGenIP, Info, Info.RTArgs, CombinedInfo, CustomMapperCB,
10455 IsNonContiguous, ForEndCall, DeviceAddrCB));
10456}
10457
10458/// Check for inner distribute directive.
10459static const OMPExecutableDirective *
10461 const auto *CS = D.getInnermostCapturedStmt();
10462 const auto *Body =
10463 CS->getCapturedStmt()->IgnoreContainers(/*IgnoreCaptured=*/true);
10464 const Stmt *ChildStmt =
10466
10467 if (const auto *NestedDir =
10468 dyn_cast_or_null<OMPExecutableDirective>(ChildStmt)) {
10469 OpenMPDirectiveKind DKind = NestedDir->getDirectiveKind();
10470 switch (D.getDirectiveKind()) {
10471 case OMPD_target:
10472 // For now, treat 'target' with nested 'teams loop' as if it's
10473 // distributed (target teams distribute).
10474 if (isOpenMPDistributeDirective(DKind) || DKind == OMPD_teams_loop)
10475 return NestedDir;
10476 if (DKind == OMPD_teams) {
10477 Body = NestedDir->getInnermostCapturedStmt()->IgnoreContainers(
10478 /*IgnoreCaptured=*/true);
10479 if (!Body)
10480 return nullptr;
10481 ChildStmt = CGOpenMPSIMDRuntime::getSingleCompoundChild(Ctx, Body);
10482 if (const auto *NND =
10483 dyn_cast_or_null<OMPExecutableDirective>(ChildStmt)) {
10484 DKind = NND->getDirectiveKind();
10485 if (isOpenMPDistributeDirective(DKind))
10486 return NND;
10487 }
10488 }
10489 return nullptr;
10490 case OMPD_target_teams:
10491 if (isOpenMPDistributeDirective(DKind))
10492 return NestedDir;
10493 return nullptr;
10494 case OMPD_target_parallel:
10495 case OMPD_target_simd:
10496 case OMPD_target_parallel_for:
10497 case OMPD_target_parallel_for_simd:
10498 return nullptr;
10499 case OMPD_target_teams_distribute:
10500 case OMPD_target_teams_distribute_simd:
10501 case OMPD_target_teams_distribute_parallel_for:
10502 case OMPD_target_teams_distribute_parallel_for_simd:
10503 case OMPD_parallel:
10504 case OMPD_for:
10505 case OMPD_parallel_for:
10506 case OMPD_parallel_master:
10507 case OMPD_parallel_sections:
10508 case OMPD_for_simd:
10509 case OMPD_parallel_for_simd:
10510 case OMPD_cancel:
10511 case OMPD_cancellation_point:
10512 case OMPD_ordered:
10513 case OMPD_threadprivate:
10514 case OMPD_allocate:
10515 case OMPD_task:
10516 case OMPD_simd:
10517 case OMPD_tile:
10518 case OMPD_unroll:
10519 case OMPD_sections:
10520 case OMPD_section:
10521 case OMPD_single:
10522 case OMPD_master:
10523 case OMPD_critical:
10524 case OMPD_taskyield:
10525 case OMPD_barrier:
10526 case OMPD_taskwait:
10527 case OMPD_taskgroup:
10528 case OMPD_atomic:
10529 case OMPD_flush:
10530 case OMPD_depobj:
10531 case OMPD_scan:
10532 case OMPD_teams:
10533 case OMPD_target_data:
10534 case OMPD_target_exit_data:
10535 case OMPD_target_enter_data:
10536 case OMPD_distribute:
10537 case OMPD_distribute_simd:
10538 case OMPD_distribute_parallel_for:
10539 case OMPD_distribute_parallel_for_simd:
10540 case OMPD_teams_distribute:
10541 case OMPD_teams_distribute_simd:
10542 case OMPD_teams_distribute_parallel_for:
10543 case OMPD_teams_distribute_parallel_for_simd:
10544 case OMPD_target_update:
10545 case OMPD_declare_simd:
10546 case OMPD_declare_variant:
10547 case OMPD_begin_declare_variant:
10548 case OMPD_end_declare_variant:
10549 case OMPD_declare_target:
10550 case OMPD_end_declare_target:
10551 case OMPD_declare_reduction:
10552 case OMPD_declare_mapper:
10553 case OMPD_taskloop:
10554 case OMPD_taskloop_simd:
10555 case OMPD_master_taskloop:
10556 case OMPD_master_taskloop_simd:
10557 case OMPD_parallel_master_taskloop:
10558 case OMPD_parallel_master_taskloop_simd:
10559 case OMPD_requires:
10560 case OMPD_metadirective:
10561 case OMPD_unknown:
10562 default:
10563 llvm_unreachable("Unexpected directive.");
10564 }
10565 }
10566
10567 return nullptr;
10568}
10569
10570/// Emit the user-defined mapper function. The code generation follows the
10571/// pattern in the example below.
10572/// \code
10573/// void .omp_mapper.<type_name>.<mapper_id>.(void *rt_mapper_handle,
10574/// void *base, void *begin,
10575/// int64_t size, int64_t type,
10576/// void *name = nullptr) {
10577/// // Allocate space for an array section first.
10578/// if ((size > 1 || (base != begin)) && !maptype.IsDelete)
10579/// __tgt_push_mapper_component(rt_mapper_handle, base, begin,
10580/// size*sizeof(Ty), clearToFromMember(type));
10581/// // Map members.
10582/// for (unsigned i = 0; i < size; i++) {
10583/// N = __tgt_mapper_num_components(rt_mapper_handle);
10584/// // For each component specified by this mapper:
10585/// for (auto c : begin[i]->all_components) {
10586/// // MEMBER_OF grouping: tie this component to the current array element
10587/// // (component N) by adding N<<48. Exceptions:
10588/// // - ATTACH entries are not members of any struct storage range.
10589/// // - Pointee entries (reached via a pointer member) occupy separate
10590/// // storage; their inner MEMBER_OF bits are shifted by N instead.
10591/// if (c.isAttach() || c.isPointee())
10592/// member_type = c.arg_type + (c.hasInnerMemberOf() ? N<<48 : 0);
10593/// else
10594/// member_type = c.arg_type + N<<48;
10595/// // Map-type-modifying bits (ALWAYS, DELETE, CLOSE) from the outer map
10596/// // clause are propagated to each component, except ATTACH entries
10597/// // (ATTACH|ALWAYS is reserved for attach(always), and other modifier
10598/// // bits have no meaning for ATTACH). PRESENT is additionally
10599/// // propagated to components with HasAttachPtr (the pointee data) at
10600/// // OpenMP >= 6.0.
10601/// present_bit = (v60 && c.hasAttachPtr()) ? PRESENT : 0;
10602/// imported_modifier_bits =
10603/// type & (ALWAYS | DELETE | CLOSE | present_bit);
10604/// effective_type = c.isAttach() ? member_type
10605/// : member_type | imported_modifier_bits;
10606/// if (c.hasMapper())
10607/// (*c.Mapper())(rt_mapper_handle, c.arg_base, c.arg_begin, c.arg_size,
10608/// effective_type, c.arg_name);
10609/// else
10610/// __tgt_push_mapper_component(rt_mapper_handle, c.arg_base,
10611/// c.arg_begin, c.arg_size, effective_type,
10612/// c.arg_name);
10613/// }
10614/// }
10615/// // Delete the array section.
10616/// if (size > 1 && maptype.IsDelete)
10617/// __tgt_push_mapper_component(rt_mapper_handle, base, begin,
10618/// size*sizeof(Ty), clearToFromMember(type));
10619/// }
10620/// \endcode
10622 CodeGenFunction *CGF) {
10623 if (UDMMap.count(D) > 0)
10624 return;
10625 ASTContext &C = CGM.getContext();
10626 QualType Ty = D->getType();
10627 auto *MapperVarDecl =
10629 CharUnits ElementSize = C.getTypeSizeInChars(Ty);
10630 llvm::Type *ElemTy = CGM.getTypes().ConvertTypeForMem(Ty);
10631
10632 CodeGenFunction MapperCGF(CGM);
10633 MappableExprsHandler::MapCombinedInfoTy CombinedInfo;
10634 auto PrivatizeAndGenMapInfoCB =
10635 [&](llvm::OpenMPIRBuilder::InsertPointTy CodeGenIP, llvm::Value *PtrPHI,
10636 llvm::Value *BeginArg) -> llvm::OpenMPIRBuilder::MapInfosTy & {
10637 MapperCGF.Builder.restoreIP(CodeGenIP);
10638
10639 // Privatize the declared variable of mapper to be the current array
10640 // element.
10641 Address PtrCurrent(
10642 PtrPHI, ElemTy,
10643 Address(BeginArg, MapperCGF.VoidPtrTy, CGM.getPointerAlign())
10644 .getAlignment()
10645 .alignmentOfArrayElement(ElementSize));
10647 Scope.addPrivate(MapperVarDecl, PtrCurrent);
10648 (void)Scope.Privatize();
10649
10650 // Get map clause information.
10651 MappableExprsHandler MEHandler(*D, MapperCGF);
10652 MEHandler.generateAllInfoForMapper(CombinedInfo, OMPBuilder);
10653
10654 auto FillInfoMap = [&](MappableExprsHandler::MappingExprInfo &MapExpr) {
10655 return emitMappingInformation(MapperCGF, OMPBuilder, MapExpr);
10656 };
10657 if (CGM.getCodeGenOpts().getDebugInfo() !=
10658 llvm::codegenoptions::NoDebugInfo) {
10659 CombinedInfo.Names.resize(CombinedInfo.Exprs.size());
10660 llvm::transform(CombinedInfo.Exprs, CombinedInfo.Names.begin(),
10661 FillInfoMap);
10662 }
10663
10664 return CombinedInfo;
10665 };
10666
10667 auto CustomMapperCB = [&](unsigned I) {
10668 llvm::Function *MapperFunc = nullptr;
10669 if (CombinedInfo.Mappers[I]) {
10670 // Call the corresponding mapper function.
10672 cast<OMPDeclareMapperDecl>(CombinedInfo.Mappers[I]));
10673 assert(MapperFunc && "Expect a valid mapper function is available.");
10674 }
10675 return MapperFunc;
10676 };
10677
10678 SmallString<64> TyStr;
10679 llvm::raw_svector_ostream Out(TyStr);
10680 CGM.getCXXABI().getMangleContext().mangleCanonicalTypeName(Ty, Out);
10681 std::string Name = getName({"omp_mapper", TyStr, D->getName()});
10682
10683 // Propagate the PRESENT modifier to the pointee entries (those with
10684 // HasAttachPtr) only for OpenMP >= 6.0; before 6.0 the present modifier does
10685 // not apply to the pointee (see the OpenMP 6.0 erratum on the present motion
10686 // vs. map-type modifier divergence).
10687 bool PropagatePresentToPointee = CGM.getLangOpts().OpenMP >= 60;
10688 llvm::Function *NewFn = cantFail(OMPBuilder.emitUserDefinedMapper(
10689 PrivatizeAndGenMapInfoCB, ElemTy, Name, CustomMapperCB,
10690 /*PreserveMemberOfFlags=*/false, PropagatePresentToPointee));
10691 UDMMap.try_emplace(D, NewFn);
10692 if (CGF)
10693 FunctionUDMMap[CGF->CurFn].push_back(D);
10694}
10695
10697 const OMPDeclareMapperDecl *D) {
10698 auto I = UDMMap.find(D);
10699 if (I != UDMMap.end())
10700 return I->second;
10702 return UDMMap.lookup(D);
10703}
10704
10707 llvm::function_ref<llvm::Value *(CodeGenFunction &CGF,
10708 const OMPLoopDirective &D)>
10709 SizeEmitter) {
10710 OpenMPDirectiveKind Kind = D.getDirectiveKind();
10711 const OMPExecutableDirective *TD = &D;
10712 // Get nested teams distribute kind directive, if any. For now, treat
10713 // 'target_teams_loop' as if it's really a target_teams_distribute.
10714 if ((!isOpenMPDistributeDirective(Kind) || !isOpenMPTeamsDirective(Kind)) &&
10715 Kind != OMPD_target_teams_loop)
10716 TD = getNestedDistributeDirective(CGM.getContext(), D);
10717 if (!TD)
10718 return llvm::ConstantInt::get(CGF.Int64Ty, 0);
10719
10720 const auto *LD = cast<OMPLoopDirective>(TD);
10721 if (llvm::Value *NumIterations = SizeEmitter(CGF, *LD))
10722 return NumIterations;
10723 return llvm::ConstantInt::get(CGF.Int64Ty, 0);
10724}
10725
10726static void
10727emitTargetCallFallback(CGOpenMPRuntime *OMPRuntime, llvm::Function *OutlinedFn,
10728 const OMPExecutableDirective &D,
10730 bool RequiresOuterTask, const CapturedStmt &CS,
10731 bool OffloadingMandatory, CodeGenFunction &CGF) {
10732 if (OffloadingMandatory) {
10733 CGF.Builder.CreateUnreachable();
10734 } else {
10735 if (RequiresOuterTask) {
10736 CapturedVars.clear();
10737 CGF.GenerateOpenMPCapturedVars(CS, CapturedVars);
10738 }
10739 llvm::SmallVector<llvm::Value *, 16> Args(CapturedVars.begin(),
10740 CapturedVars.end());
10741 Args.push_back(llvm::Constant::getNullValue(CGF.Builder.getPtrTy()));
10742 OMPRuntime->emitOutlinedFunctionCall(CGF, D.getBeginLoc(), OutlinedFn,
10743 Args);
10744 }
10745}
10746
10747static llvm::Value *emitDeviceID(
10748 llvm::PointerIntPair<const Expr *, 2, OpenMPDeviceClauseModifier> Device,
10749 CodeGenFunction &CGF) {
10750 // Emit device ID if any.
10751 llvm::Value *DeviceID;
10752 if (Device.getPointer()) {
10753 assert((Device.getInt() == OMPC_DEVICE_unknown ||
10754 Device.getInt() == OMPC_DEVICE_device_num) &&
10755 "Expected device_num modifier.");
10756 llvm::Value *DevVal = CGF.EmitScalarExpr(Device.getPointer());
10757 DeviceID =
10758 CGF.Builder.CreateIntCast(DevVal, CGF.Int64Ty, /*isSigned=*/true);
10759 } else {
10760 DeviceID = CGF.Builder.getInt64(OMP_DEVICEID_UNDEF);
10761 }
10762 return DeviceID;
10763}
10764
10765static std::pair<llvm::Value *, OMPDynGroupprivateFallbackType>
10767 llvm::Value *DynGP = CGF.Builder.getInt32(0);
10768 auto DynGPFallback = OMPDynGroupprivateFallbackType::Abort;
10769
10770 if (auto *DynGPClause = D.getSingleClause<OMPDynGroupprivateClause>()) {
10771 CodeGenFunction::RunCleanupsScope DynGPScope(CGF);
10772 llvm::Value *DynGPVal =
10773 CGF.EmitScalarExpr(DynGPClause->getSize(), /*IgnoreResultAssign=*/true);
10774 DynGP = CGF.Builder.CreateIntCast(DynGPVal, CGF.Int32Ty,
10775 /*isSigned=*/false);
10776 auto FallbackModifier = DynGPClause->getDynGroupprivateFallbackModifier();
10777 switch (FallbackModifier) {
10778 case OMPC_DYN_GROUPPRIVATE_FALLBACK_abort:
10779 DynGPFallback = OMPDynGroupprivateFallbackType::Abort;
10780 break;
10781 case OMPC_DYN_GROUPPRIVATE_FALLBACK_null:
10782 DynGPFallback = OMPDynGroupprivateFallbackType::Null;
10783 break;
10784 case OMPC_DYN_GROUPPRIVATE_FALLBACK_default_mem:
10786 // This is the default for dyn_groupprivate.
10787 DynGPFallback = OMPDynGroupprivateFallbackType::DefaultMem;
10788 break;
10789 default:
10790 llvm_unreachable("Unknown fallback modifier for OpenMP dyn_groupprivate");
10791 }
10792 } else if (auto *OMPXDynCGClause =
10793 D.getSingleClause<OMPXDynCGroupMemClause>()) {
10794 CodeGenFunction::RunCleanupsScope DynCGMemScope(CGF);
10795 llvm::Value *DynCGMemVal = CGF.EmitScalarExpr(OMPXDynCGClause->getSize(),
10796 /*IgnoreResultAssign=*/true);
10797 DynGP = CGF.Builder.CreateIntCast(DynCGMemVal, CGF.Int32Ty,
10798 /*isSigned=*/false);
10799 }
10800 return {DynGP, DynGPFallback};
10801}
10802
10804 MappableExprsHandler &MEHandler, CodeGenFunction &CGF,
10805 const CapturedStmt &CS, llvm::SmallVectorImpl<llvm::Value *> &CapturedVars,
10806 llvm::OpenMPIRBuilder &OMPBuilder,
10807 llvm::DenseSet<CanonicalDeclPtr<const Decl>> &MappedVarSet,
10808 MappableExprsHandler::MapCombinedInfoTy &CombinedInfo) {
10809
10810 llvm::DenseMap<llvm::Value *, llvm::Value *> LambdaPointers;
10811 auto RI = CS.getCapturedRecordDecl()->field_begin();
10812 auto *CV = CapturedVars.begin();
10814 CE = CS.capture_end();
10815 CI != CE; ++CI, ++RI, ++CV) {
10816 MappableExprsHandler::MapCombinedInfoTy CurInfo;
10817
10818 // VLA sizes are passed to the outlined region by copy and do not have map
10819 // information associated.
10820 if (CI->capturesVariableArrayType()) {
10821 CurInfo.Exprs.push_back(nullptr);
10822 CurInfo.BasePointers.push_back(*CV);
10823 CurInfo.DevicePtrDecls.push_back(nullptr);
10824 CurInfo.DevicePointers.push_back(
10825 MappableExprsHandler::DeviceInfoTy::None);
10826 CurInfo.Pointers.push_back(*CV);
10827 CurInfo.Sizes.push_back(CGF.Builder.CreateIntCast(
10828 CGF.getTypeSize(RI->getType()), CGF.Int64Ty, /*isSigned=*/true));
10829 // Copy to the device as an argument. No need to retrieve it.
10830 CurInfo.Types.push_back(OpenMPOffloadMappingFlags::OMP_MAP_LITERAL |
10831 OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM |
10832 OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT);
10833 CurInfo.HasAttachPtr.push_back(false);
10834 CurInfo.Mappers.push_back(nullptr);
10835 } else {
10836 const ValueDecl *CapturedVD =
10837 CI->capturesThis() ? nullptr
10839 bool HasEntryWithCVAsAttachPtr = false;
10840 if (CapturedVD)
10841 HasEntryWithCVAsAttachPtr =
10842 MEHandler.hasAttachEntryForCapturedVar(CapturedVD);
10843
10844 // Populate component lists for the captured variable from clauses.
10845 MappableExprsHandler::MapDataArrayTy DeclComponentLists;
10848 StorageForImplicitlyAddedComponentLists;
10849 MEHandler.populateComponentListsForNonLambdaCaptureFromClauses(
10850 CapturedVD, DeclComponentLists,
10851 StorageForImplicitlyAddedComponentLists);
10852
10853 // OpenMP 6.0, 15.8, target construct, restrictions:
10854 // * A list item in a map clause that is specified on a target construct
10855 // must have a base variable or base pointer.
10856 //
10857 // Map clauses on a target construct must either have a base pointer, or a
10858 // base-variable. So, if we don't have a base-pointer, that means that it
10859 // must have a base-variable, i.e. we have a map like `map(s)`, `map(s.x)`
10860 // etc. In such cases, we do not need to handle default map generation
10861 // for `s`.
10862 bool HasEntryWithoutAttachPtr =
10863 llvm::any_of(DeclComponentLists, [&](const auto &MapData) {
10865 Components = std::get<0>(MapData);
10866 return !MEHandler.getAttachPtrExpr(Components);
10867 });
10868
10869 // Generate default map info first if there's no direct map with CV as
10870 // the base-variable, or attach pointer.
10871 if (DeclComponentLists.empty() ||
10872 (!HasEntryWithCVAsAttachPtr && !HasEntryWithoutAttachPtr))
10873 MEHandler.generateDefaultMapInfo(*CI, **RI, *CV, CurInfo);
10874
10875 // If we have any information in the map clause, we use it, otherwise we
10876 // just do a default mapping.
10877 MEHandler.generateInfoForCaptureFromClauseInfo(
10878 DeclComponentLists, CI, *CV, CurInfo, OMPBuilder,
10879 /*OffsetForMemberOfFlag=*/CombinedInfo.BasePointers.size());
10880
10881 if (!CI->capturesThis())
10882 MappedVarSet.insert(CI->getCapturedVar());
10883 else
10884 MappedVarSet.insert(nullptr);
10885
10886 // Generate correct mapping for variables captured by reference in
10887 // lambdas.
10888 if (CI->capturesVariable())
10889 MEHandler.generateInfoForLambdaCaptures(CI->getCapturedVar(), *CV,
10890 CurInfo, LambdaPointers);
10891 }
10892 // We expect to have at least an element of information for this capture.
10893 assert(!CurInfo.BasePointers.empty() &&
10894 "Non-existing map pointer for capture!");
10895 assert(CurInfo.BasePointers.size() == CurInfo.Pointers.size() &&
10896 CurInfo.BasePointers.size() == CurInfo.Sizes.size() &&
10897 CurInfo.BasePointers.size() == CurInfo.Types.size() &&
10898 CurInfo.BasePointers.size() == CurInfo.Mappers.size() &&
10899 "Inconsistent map information sizes!");
10900
10901 // We need to append the results of this capture to what we already have.
10902 CombinedInfo.append(CurInfo);
10903 }
10904 // Adjust MEMBER_OF flags for the lambdas captures.
10905 MEHandler.adjustMemberOfForLambdaCaptures(
10906 OMPBuilder, LambdaPointers, CombinedInfo.BasePointers,
10907 CombinedInfo.Pointers, CombinedInfo.Types);
10908}
10909static void
10910genMapInfo(MappableExprsHandler &MEHandler, CodeGenFunction &CGF,
10911 MappableExprsHandler::MapCombinedInfoTy &CombinedInfo,
10912 llvm::OpenMPIRBuilder &OMPBuilder,
10913 const llvm::DenseSet<CanonicalDeclPtr<const Decl>> &SkippedVarSet =
10914 llvm::DenseSet<CanonicalDeclPtr<const Decl>>()) {
10915
10916 CodeGenModule &CGM = CGF.CGM;
10917 // Map any list items in a map clause that were not captures because they
10918 // weren't referenced within the construct.
10919 MEHandler.generateAllInfo(CombinedInfo, OMPBuilder, SkippedVarSet);
10920
10921 auto FillInfoMap = [&](MappableExprsHandler::MappingExprInfo &MapExpr) {
10922 return emitMappingInformation(CGF, OMPBuilder, MapExpr);
10923 };
10924 if (CGM.getCodeGenOpts().getDebugInfo() !=
10925 llvm::codegenoptions::NoDebugInfo) {
10926 CombinedInfo.Names.resize(CombinedInfo.Exprs.size());
10927 llvm::transform(CombinedInfo.Exprs, CombinedInfo.Names.begin(),
10928 FillInfoMap);
10929 }
10930}
10931
10933 const CapturedStmt &CS,
10935 llvm::OpenMPIRBuilder &OMPBuilder,
10936 MappableExprsHandler::MapCombinedInfoTy &CombinedInfo) {
10937 // Get mappable expression information.
10938 MappableExprsHandler MEHandler(D, CGF);
10939 llvm::DenseSet<CanonicalDeclPtr<const Decl>> MappedVarSet;
10940
10941 genMapInfoForCaptures(MEHandler, CGF, CS, CapturedVars, OMPBuilder,
10942 MappedVarSet, CombinedInfo);
10943 genMapInfo(MEHandler, CGF, CombinedInfo, OMPBuilder, MappedVarSet);
10944}
10945
10946template <typename ClauseTy>
10947static void
10949 const OMPExecutableDirective &D,
10951 const auto *C = D.getSingleClause<ClauseTy>();
10952 assert(!C->varlist_empty() &&
10953 "ompx_bare requires explicit num_teams and thread_limit");
10955 for (auto *E : C->varlist()) {
10956 llvm::Value *V = CGF.EmitScalarExpr(E);
10957 Values.push_back(
10958 CGF.Builder.CreateIntCast(V, CGF.Int32Ty, /*isSigned=*/true));
10959 }
10960}
10961
10963 CGOpenMPRuntime *OMPRuntime, llvm::Function *OutlinedFn,
10964 const OMPExecutableDirective &D,
10965 llvm::SmallVectorImpl<llvm::Value *> &CapturedVars, bool RequiresOuterTask,
10966 const CapturedStmt &CS, bool OffloadingMandatory,
10967 llvm::PointerIntPair<const Expr *, 2, OpenMPDeviceClauseModifier> Device,
10968 llvm::Value *OutlinedFnID, CodeGenFunction::OMPTargetDataInfo &InputInfo,
10969 llvm::Value *&MapTypesArray, llvm::Value *&MapNamesArray,
10970 llvm::function_ref<llvm::Value *(CodeGenFunction &CGF,
10971 const OMPLoopDirective &D)>
10972 SizeEmitter,
10973 CodeGenFunction &CGF, CodeGenModule &CGM) {
10974 llvm::OpenMPIRBuilder &OMPBuilder = OMPRuntime->getOMPBuilder();
10975
10976 // Fill up the arrays with all the captured variables.
10977 MappableExprsHandler::MapCombinedInfoTy CombinedInfo;
10979 genMapInfo(D, CGF, CS, CapturedVars, OMPBuilder, CombinedInfo);
10980
10981 // Append a null entry for the implicit dyn_ptr argument.
10982 using OpenMPOffloadMappingFlags = llvm::omp::OpenMPOffloadMappingFlags;
10983 auto *NullPtr = llvm::Constant::getNullValue(CGF.Builder.getPtrTy());
10984 CombinedInfo.BasePointers.push_back(NullPtr);
10985 CombinedInfo.Pointers.push_back(NullPtr);
10986 CombinedInfo.DevicePointers.push_back(
10987 llvm::OpenMPIRBuilder::DeviceInfoTy::None);
10988 CombinedInfo.Sizes.push_back(CGF.Builder.getInt64(0));
10989 CombinedInfo.Types.push_back(OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM |
10990 OpenMPOffloadMappingFlags::OMP_MAP_LITERAL);
10991 CombinedInfo.HasAttachPtr.push_back(false);
10992 if (!CombinedInfo.Names.empty())
10993 CombinedInfo.Names.push_back(NullPtr);
10994 CombinedInfo.Exprs.push_back(nullptr);
10995 CombinedInfo.Mappers.push_back(nullptr);
10996 CombinedInfo.DevicePtrDecls.push_back(nullptr);
10997
10998 emitOffloadingArraysAndArgs(CGF, CombinedInfo, Info, OMPBuilder,
10999 /*IsNonContiguous=*/true, /*ForEndCall=*/false);
11000
11001 InputInfo.NumberOfTargetItems = Info.NumberOfPtrs;
11002 InputInfo.BasePointersArray = Address(Info.RTArgs.BasePointersArray,
11003 CGF.VoidPtrTy, CGM.getPointerAlign());
11004 InputInfo.PointersArray =
11005 Address(Info.RTArgs.PointersArray, CGF.VoidPtrTy, CGM.getPointerAlign());
11006 InputInfo.SizesArray =
11007 Address(Info.RTArgs.SizesArray, CGF.Int64Ty, CGM.getPointerAlign());
11008 InputInfo.MappersArray =
11009 Address(Info.RTArgs.MappersArray, CGF.VoidPtrTy, CGM.getPointerAlign());
11010 MapTypesArray = Info.RTArgs.MapTypesArray;
11011 MapNamesArray = Info.RTArgs.MapNamesArray;
11012
11013 auto &&ThenGen = [&OMPRuntime, OutlinedFn, &D, &CapturedVars,
11014 RequiresOuterTask, &CS, OffloadingMandatory, Device,
11015 OutlinedFnID, &InputInfo, &MapTypesArray, &MapNamesArray,
11016 SizeEmitter](CodeGenFunction &CGF, PrePostActionTy &) {
11017 bool IsReverseOffloading = Device.getInt() == OMPC_DEVICE_ancestor;
11018
11019 if (IsReverseOffloading) {
11020 // Reverse offloading is not supported, so just execute on the host.
11021 // FIXME: This fallback solution is incorrect since it ignores the
11022 // OMP_TARGET_OFFLOAD environment variable. Instead it would be better to
11023 // assert here and ensure SEMA emits an error.
11024 emitTargetCallFallback(OMPRuntime, OutlinedFn, D, CapturedVars,
11025 RequiresOuterTask, CS, OffloadingMandatory, CGF);
11026 return;
11027 }
11028
11029 bool HasNoWait = D.hasClausesOfKind<OMPNowaitClause>();
11030 unsigned NumTargetItems = InputInfo.NumberOfTargetItems;
11031
11032 llvm::Value *BasePointersArray =
11033 InputInfo.BasePointersArray.emitRawPointer(CGF);
11034 llvm::Value *PointersArray = InputInfo.PointersArray.emitRawPointer(CGF);
11035 llvm::Value *SizesArray = InputInfo.SizesArray.emitRawPointer(CGF);
11036 llvm::Value *MappersArray = InputInfo.MappersArray.emitRawPointer(CGF);
11037
11038 auto &&EmitTargetCallFallbackCB =
11039 [&OMPRuntime, OutlinedFn, &D, &CapturedVars, RequiresOuterTask, &CS,
11040 OffloadingMandatory, &CGF](llvm::OpenMPIRBuilder::InsertPointTy IP)
11041 -> llvm::OpenMPIRBuilder::InsertPointTy {
11042 CGF.Builder.restoreIP(IP);
11043 emitTargetCallFallback(OMPRuntime, OutlinedFn, D, CapturedVars,
11044 RequiresOuterTask, CS, OffloadingMandatory, CGF);
11045 return CGF.Builder.saveIP();
11046 };
11047
11048 bool IsBare = D.hasClausesOfKind<OMPXBareClause>();
11051 if (IsBare) {
11054 NumThreads);
11055 } else {
11056 NumTeams.push_back(OMPRuntime->emitNumTeamsForTargetDirective(CGF, D));
11057 NumThreads.push_back(
11058 OMPRuntime->emitNumThreadsForTargetDirective(CGF, D));
11059 }
11060
11061 llvm::Value *DeviceID = emitDeviceID(Device, CGF);
11062 llvm::Value *RTLoc = OMPRuntime->emitUpdateLocation(CGF, D.getBeginLoc());
11063 llvm::Value *NumIterations =
11064 OMPRuntime->emitTargetNumIterationsCall(CGF, D, SizeEmitter);
11065 auto [DynCGroupMem, DynCGroupMemFallback] = emitDynCGroupMem(D, CGF);
11066 llvm::OpenMPIRBuilder::InsertPointTy AllocaIP(
11067 CGF.AllocaInsertPt->getParent(), CGF.AllocaInsertPt->getIterator());
11068
11069 llvm::OpenMPIRBuilder::TargetDataRTArgs RTArgs(
11070 BasePointersArray, PointersArray, SizesArray, MapTypesArray,
11071 nullptr /* MapTypesArrayEnd */, MappersArray, MapNamesArray);
11072
11073 llvm::OpenMPIRBuilder::TargetKernelArgs Args(
11074 NumTargetItems, RTArgs, NumIterations, NumTeams, NumThreads,
11075 DynCGroupMem, HasNoWait, /*StrictBlocksAndThreads=*/IsBare,
11076 DynCGroupMemFallback);
11077
11078 llvm::OpenMPIRBuilder::InsertPointTy AfterIP =
11079 cantFail(OMPRuntime->getOMPBuilder().emitKernelLaunch(
11080 CGF.Builder, OutlinedFnID, EmitTargetCallFallbackCB, Args, DeviceID,
11081 RTLoc, AllocaIP));
11082 CGF.Builder.restoreIP(AfterIP);
11083 };
11084
11085 if (RequiresOuterTask)
11086 CGF.EmitOMPTargetTaskBasedDirective(D, ThenGen, InputInfo);
11087 else
11088 OMPRuntime->emitInlinedDirective(CGF, D.getDirectiveKind(), ThenGen);
11089}
11090
11091static void
11092emitTargetCallElse(CGOpenMPRuntime *OMPRuntime, llvm::Function *OutlinedFn,
11093 const OMPExecutableDirective &D,
11095 bool RequiresOuterTask, const CapturedStmt &CS,
11096 bool OffloadingMandatory, CodeGenFunction &CGF) {
11097
11098 // Notify that the host version must be executed.
11099 auto &&ElseGen =
11100 [&OMPRuntime, OutlinedFn, &D, &CapturedVars, RequiresOuterTask, &CS,
11101 OffloadingMandatory](CodeGenFunction &CGF, PrePostActionTy &) {
11102 emitTargetCallFallback(OMPRuntime, OutlinedFn, D, CapturedVars,
11103 RequiresOuterTask, CS, OffloadingMandatory, CGF);
11104 };
11105
11106 if (RequiresOuterTask) {
11108 CGF.EmitOMPTargetTaskBasedDirective(D, ElseGen, InputInfo);
11109 } else {
11110 OMPRuntime->emitInlinedDirective(CGF, D.getDirectiveKind(), ElseGen);
11111 }
11112}
11113
11116 llvm::Function *OutlinedFn, llvm::Value *OutlinedFnID, const Expr *IfCond,
11117 llvm::PointerIntPair<const Expr *, 2, OpenMPDeviceClauseModifier> Device,
11118 llvm::function_ref<llvm::Value *(CodeGenFunction &CGF,
11119 const OMPLoopDirective &D)>
11120 SizeEmitter) {
11121 if (!CGF.HaveInsertPoint())
11122 return;
11123
11124 const bool OffloadingMandatory = !CGM.getLangOpts().OpenMPIsTargetDevice &&
11125 CGM.getLangOpts().OpenMPOffloadMandatory;
11126
11127 assert((OffloadingMandatory || OutlinedFn) && "Invalid outlined function!");
11128
11129 const bool RequiresOuterTask =
11130 D.hasClausesOfKind<OMPDependClause>() ||
11131 D.hasClausesOfKind<OMPNowaitClause>() ||
11132 D.hasClausesOfKind<OMPInReductionClause>() ||
11133 (CGM.getLangOpts().OpenMP >= 51 &&
11134 needsTaskBasedThreadLimit(D.getDirectiveKind()) &&
11135 D.hasClausesOfKind<OMPThreadLimitClause>());
11137 const CapturedStmt &CS = *D.getCapturedStmt(OMPD_target);
11138 auto &&ArgsCodegen = [&CS, &CapturedVars](CodeGenFunction &CGF,
11139 PrePostActionTy &) {
11140 CGF.GenerateOpenMPCapturedVars(CS, CapturedVars);
11141 };
11142 emitInlinedDirective(CGF, OMPD_unknown, ArgsCodegen);
11143
11145 llvm::Value *MapTypesArray = nullptr;
11146 llvm::Value *MapNamesArray = nullptr;
11147
11148 auto &&TargetThenGen = [this, OutlinedFn, &D, &CapturedVars,
11149 RequiresOuterTask, &CS, OffloadingMandatory, Device,
11150 OutlinedFnID, &InputInfo, &MapTypesArray,
11151 &MapNamesArray, SizeEmitter](CodeGenFunction &CGF,
11152 PrePostActionTy &) {
11153 emitTargetCallKernelLaunch(this, OutlinedFn, D, CapturedVars,
11154 RequiresOuterTask, CS, OffloadingMandatory,
11155 Device, OutlinedFnID, InputInfo, MapTypesArray,
11156 MapNamesArray, SizeEmitter, CGF, CGM);
11157 };
11158
11159 auto &&TargetElseGen =
11160 [this, OutlinedFn, &D, &CapturedVars, RequiresOuterTask, &CS,
11161 OffloadingMandatory](CodeGenFunction &CGF, PrePostActionTy &) {
11162 emitTargetCallElse(this, OutlinedFn, D, CapturedVars, RequiresOuterTask,
11163 CS, OffloadingMandatory, CGF);
11164 };
11165
11166 // If we have a target function ID it means that we need to support
11167 // offloading, otherwise, just execute on the host. We need to execute on host
11168 // regardless of the conditional in the if clause if, e.g., the user do not
11169 // specify target triples.
11170 if (OutlinedFnID) {
11171 if (IfCond) {
11172 emitIfClause(CGF, IfCond, TargetThenGen, TargetElseGen);
11173 } else {
11174 RegionCodeGenTy ThenRCG(TargetThenGen);
11175 ThenRCG(CGF);
11176 }
11177 } else {
11178 RegionCodeGenTy ElseRCG(TargetElseGen);
11179 ElseRCG(CGF);
11180 }
11181}
11182
11184 StringRef ParentName) {
11185 if (!S)
11186 return;
11187
11188 // Register vtable from device for target data and target directives.
11189 // Add this block here since scanForTargetRegionsFunctions ignores
11190 // target data by checking if S is a executable directive (target).
11191 if (auto *E = dyn_cast<OMPExecutableDirective>(S);
11192 E && isOpenMPTargetDataManagementDirective(E->getDirectiveKind())) {
11193 // Don't need to check if it's device compile
11194 // since scanForTargetRegionsFunctions currently only called
11195 // in device compilation.
11196 registerVTable(*E);
11197 }
11198
11199 // Codegen OMP target directives that offload compute to the device.
11200 bool RequiresDeviceCodegen =
11203 cast<OMPExecutableDirective>(S)->getDirectiveKind());
11204
11205 if (RequiresDeviceCodegen) {
11206 const auto &E = *cast<OMPExecutableDirective>(S);
11207
11208 llvm::TargetRegionEntryInfo EntryInfo = getEntryInfoFromPresumedLoc(
11209 CGM, OMPBuilder, E.getBeginLoc(), ParentName);
11210
11211 // Is this a target region that should not be emitted as an entry point? If
11212 // so just signal we are done with this target region.
11213 if (!OMPBuilder.OffloadInfoManager.hasTargetRegionEntryInfo(EntryInfo))
11214 return;
11215
11216 switch (E.getDirectiveKind()) {
11217 case OMPD_target:
11220 break;
11221 case OMPD_target_parallel:
11223 CGM, ParentName, cast<OMPTargetParallelDirective>(E));
11224 break;
11225 case OMPD_target_teams:
11227 CGM, ParentName, cast<OMPTargetTeamsDirective>(E));
11228 break;
11229 case OMPD_target_teams_distribute:
11232 break;
11233 case OMPD_target_teams_distribute_simd:
11236 break;
11237 case OMPD_target_parallel_for:
11240 break;
11241 case OMPD_target_parallel_for_simd:
11244 break;
11245 case OMPD_target_simd:
11247 CGM, ParentName, cast<OMPTargetSimdDirective>(E));
11248 break;
11249 case OMPD_target_teams_distribute_parallel_for:
11251 CGM, ParentName,
11253 break;
11254 case OMPD_target_teams_distribute_parallel_for_simd:
11257 CGM, ParentName,
11259 break;
11260 case OMPD_target_teams_loop:
11263 break;
11264 case OMPD_target_parallel_loop:
11267 break;
11268 case OMPD_parallel:
11269 case OMPD_for:
11270 case OMPD_parallel_for:
11271 case OMPD_parallel_master:
11272 case OMPD_parallel_sections:
11273 case OMPD_for_simd:
11274 case OMPD_parallel_for_simd:
11275 case OMPD_cancel:
11276 case OMPD_cancellation_point:
11277 case OMPD_ordered:
11278 case OMPD_threadprivate:
11279 case OMPD_allocate:
11280 case OMPD_task:
11281 case OMPD_simd:
11282 case OMPD_tile:
11283 case OMPD_unroll:
11284 case OMPD_sections:
11285 case OMPD_section:
11286 case OMPD_single:
11287 case OMPD_master:
11288 case OMPD_critical:
11289 case OMPD_taskyield:
11290 case OMPD_barrier:
11291 case OMPD_taskwait:
11292 case OMPD_taskgroup:
11293 case OMPD_atomic:
11294 case OMPD_flush:
11295 case OMPD_depobj:
11296 case OMPD_scan:
11297 case OMPD_teams:
11298 case OMPD_target_data:
11299 case OMPD_target_exit_data:
11300 case OMPD_target_enter_data:
11301 case OMPD_distribute:
11302 case OMPD_distribute_simd:
11303 case OMPD_distribute_parallel_for:
11304 case OMPD_distribute_parallel_for_simd:
11305 case OMPD_teams_distribute:
11306 case OMPD_teams_distribute_simd:
11307 case OMPD_teams_distribute_parallel_for:
11308 case OMPD_teams_distribute_parallel_for_simd:
11309 case OMPD_target_update:
11310 case OMPD_declare_simd:
11311 case OMPD_declare_variant:
11312 case OMPD_begin_declare_variant:
11313 case OMPD_end_declare_variant:
11314 case OMPD_declare_target:
11315 case OMPD_end_declare_target:
11316 case OMPD_declare_reduction:
11317 case OMPD_declare_mapper:
11318 case OMPD_taskloop:
11319 case OMPD_taskloop_simd:
11320 case OMPD_master_taskloop:
11321 case OMPD_master_taskloop_simd:
11322 case OMPD_parallel_master_taskloop:
11323 case OMPD_parallel_master_taskloop_simd:
11324 case OMPD_requires:
11325 case OMPD_metadirective:
11326 case OMPD_unknown:
11327 default:
11328 llvm_unreachable("Unknown target directive for OpenMP device codegen.");
11329 }
11330 return;
11331 }
11332
11333 if (const auto *E = dyn_cast<OMPExecutableDirective>(S)) {
11334 if (!E->hasAssociatedStmt() || !E->getAssociatedStmt())
11335 return;
11336
11337 scanForTargetRegionsFunctions(E->getRawStmt(), ParentName);
11338 return;
11339 }
11340
11341 // If this is a lambda function, look into its body.
11342 if (const auto *L = dyn_cast<LambdaExpr>(S))
11343 S = L->getBody();
11344
11345 // Keep looking for target regions recursively.
11346 for (const Stmt *II : S->children())
11347 scanForTargetRegionsFunctions(II, ParentName);
11348}
11349
11350static bool isAssumedToBeNotEmitted(const ValueDecl *VD, bool IsDevice) {
11351 std::optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
11352 OMPDeclareTargetDeclAttr::getDeviceType(VD);
11353 if (!DevTy)
11354 return false;
11355 // Do not emit device_type(nohost) functions for the host.
11356 if (!IsDevice && DevTy == OMPDeclareTargetDeclAttr::DT_NoHost)
11357 return true;
11358 // Do not emit device_type(host) functions for the device.
11359 if (IsDevice && DevTy == OMPDeclareTargetDeclAttr::DT_Host)
11360 return true;
11361 return false;
11362}
11363
11365 // If emitting code for the host, we do not process FD here. Instead we do
11366 // the normal code generation.
11367 if (!CGM.getLangOpts().OpenMPIsTargetDevice) {
11368 if (const auto *FD = dyn_cast<FunctionDecl>(GD.getDecl()))
11370 CGM.getLangOpts().OpenMPIsTargetDevice))
11371 return true;
11372 return false;
11373 }
11374
11375 const ValueDecl *VD = cast<ValueDecl>(GD.getDecl());
11376 // Try to detect target regions in the function.
11377 if (const auto *FD = dyn_cast<FunctionDecl>(VD)) {
11378 StringRef Name = CGM.getMangledName(GD);
11381 CGM.getLangOpts().OpenMPIsTargetDevice))
11382 return true;
11383 }
11384
11385 // Do not emit function if it is not marked as declare target.
11386 return !OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD) &&
11387 AlreadyEmittedTargetDecls.count(VD) == 0;
11388}
11389
11392 CGM.getLangOpts().OpenMPIsTargetDevice))
11393 return true;
11394
11395 if (!CGM.getLangOpts().OpenMPIsTargetDevice)
11396 return false;
11397
11398 // Check if there are Ctors/Dtors in this declaration and look for target
11399 // regions in it. We use the complete variant to produce the kernel name
11400 // mangling.
11401 QualType RDTy = cast<VarDecl>(GD.getDecl())->getType();
11402 if (const auto *RD = RDTy->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) {
11403 for (const CXXConstructorDecl *Ctor : RD->ctors()) {
11404 StringRef ParentName =
11405 CGM.getMangledName(GlobalDecl(Ctor, Ctor_Complete));
11406 scanForTargetRegionsFunctions(Ctor->getBody(), ParentName);
11407 }
11408 if (const CXXDestructorDecl *Dtor = RD->getDestructor()) {
11409 StringRef ParentName =
11410 CGM.getMangledName(GlobalDecl(Dtor, Dtor_Complete));
11411 scanForTargetRegionsFunctions(Dtor->getBody(), ParentName);
11412 }
11413 }
11414
11415 // Do not emit variable if it is not marked as declare target.
11416 std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
11417 OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(
11418 cast<VarDecl>(GD.getDecl()));
11419 if (!Res || *Res == OMPDeclareTargetDeclAttr::MT_Link ||
11420 ((*Res == OMPDeclareTargetDeclAttr::MT_To ||
11421 *Res == OMPDeclareTargetDeclAttr::MT_Enter) &&
11424 return true;
11425 }
11426 return false;
11427}
11428
11430 llvm::Constant *Addr) {
11431 if (CGM.getLangOpts().OMPTargetTriples.empty() &&
11432 !CGM.getLangOpts().OpenMPIsTargetDevice)
11433 return;
11434
11435 std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
11436 OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
11437
11438 // If this is an 'extern' declaration we defer to the canonical definition and
11439 // do not emit an offloading entry.
11440 if (Res && *Res != OMPDeclareTargetDeclAttr::MT_Link &&
11441 VD->hasExternalStorage())
11442 return;
11443
11444 // MT_Local variables use direct access with no host-device mapping.
11445 // No offload entry needed — the device global keeps its own initializer.
11446 if (Res && *Res == OMPDeclareTargetDeclAttr::MT_Local)
11447 return;
11448
11449 if (!Res) {
11450 if (CGM.getLangOpts().OpenMPIsTargetDevice) {
11451 // Register non-target variables being emitted in device code (debug info
11452 // may cause this).
11453 StringRef VarName = CGM.getMangledName(VD);
11454 EmittedNonTargetVariables.try_emplace(VarName, Addr);
11455 }
11456 return;
11457 }
11458
11459 auto AddrOfGlobal = [&VD, this]() { return CGM.GetAddrOfGlobal(VD); };
11460 auto LinkageForVariable = [&VD, this]() {
11461 return CGM.getLLVMLinkageVarDefinition(VD);
11462 };
11463
11464 std::vector<llvm::GlobalVariable *> GeneratedRefs;
11465 OMPBuilder.registerTargetGlobalVariable(
11467 VD->hasDefinition(CGM.getContext()) == VarDecl::DeclarationOnly,
11468 VD->isExternallyVisible(),
11470 VD->getCanonicalDecl()->getBeginLoc()),
11471 CGM.getMangledName(VD), GeneratedRefs, CGM.getLangOpts().OpenMPSimd,
11472 CGM.getLangOpts().OMPTargetTriples, AddrOfGlobal, LinkageForVariable,
11473 CGM.getTypes().ConvertTypeForMem(
11474 CGM.getContext().getPointerType(VD->getType())),
11475 Addr);
11476
11477 for (auto *ref : GeneratedRefs)
11478 CGM.addCompilerUsedGlobal(ref);
11479}
11480
11482 if (isa<FunctionDecl>(GD.getDecl()) ||
11484 return emitTargetFunctions(GD);
11485
11486 return emitTargetGlobalVariable(GD);
11487}
11488
11490 for (const VarDecl *VD : DeferredGlobalVariables) {
11491 std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
11492 OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
11493 if (!Res)
11494 continue;
11495 // MT_Local and MT_To/MT_Enter without USM are always emitted.
11496 if (*Res == OMPDeclareTargetDeclAttr::MT_Local ||
11497 ((*Res == OMPDeclareTargetDeclAttr::MT_To ||
11498 *Res == OMPDeclareTargetDeclAttr::MT_Enter) &&
11500 CGM.EmitGlobal(VD);
11501 } else {
11502 assert((*Res == OMPDeclareTargetDeclAttr::MT_Link ||
11503 ((*Res == OMPDeclareTargetDeclAttr::MT_To ||
11504 *Res == OMPDeclareTargetDeclAttr::MT_Enter ||
11505 *Res == OMPDeclareTargetDeclAttr::MT_Local) &&
11507 "Expected link clause or to clause with unified memory.");
11508 (void)CGM.getOpenMPRuntime().getAddrOfDeclareTargetVar(VD);
11509 }
11510 }
11511}
11512
11514 CodeGenFunction &CGF, const OMPExecutableDirective &D) const {
11515 assert(isOpenMPTargetExecutionDirective(D.getDirectiveKind()) &&
11516 " Expected target-based directive.");
11517}
11518
11520 for (const OMPClause *Clause : D->clauselists()) {
11521 if (Clause->getClauseKind() == OMPC_unified_shared_memory) {
11523 OMPBuilder.Config.setHasRequiresUnifiedSharedMemory(true);
11524 } else if (const auto *AC =
11525 dyn_cast<OMPAtomicDefaultMemOrderClause>(Clause)) {
11526 switch (AC->getAtomicDefaultMemOrderKind()) {
11527 case OMPC_ATOMIC_DEFAULT_MEM_ORDER_acq_rel:
11528 RequiresAtomicOrdering = llvm::AtomicOrdering::AcquireRelease;
11529 break;
11530 case OMPC_ATOMIC_DEFAULT_MEM_ORDER_seq_cst:
11531 RequiresAtomicOrdering = llvm::AtomicOrdering::SequentiallyConsistent;
11532 break;
11533 case OMPC_ATOMIC_DEFAULT_MEM_ORDER_relaxed:
11534 RequiresAtomicOrdering = llvm::AtomicOrdering::Monotonic;
11535 break;
11537 break;
11538 }
11539 }
11540 }
11541}
11542
11543llvm::AtomicOrdering CGOpenMPRuntime::getDefaultMemoryOrdering() const {
11545}
11546
11548 LangAS &AS) {
11549 if (!VD || !VD->hasAttr<OMPAllocateDeclAttr>())
11550 return false;
11551 const auto *A = VD->getAttr<OMPAllocateDeclAttr>();
11552 switch(A->getAllocatorType()) {
11553 case OMPAllocateDeclAttr::OMPNullMemAlloc:
11554 case OMPAllocateDeclAttr::OMPDefaultMemAlloc:
11555 // Not supported, fallback to the default mem space.
11556 case OMPAllocateDeclAttr::OMPLargeCapMemAlloc:
11557 case OMPAllocateDeclAttr::OMPCGroupMemAlloc:
11558 case OMPAllocateDeclAttr::OMPHighBWMemAlloc:
11559 case OMPAllocateDeclAttr::OMPLowLatMemAlloc:
11560 case OMPAllocateDeclAttr::OMPThreadMemAlloc:
11561 case OMPAllocateDeclAttr::OMPConstMemAlloc:
11562 case OMPAllocateDeclAttr::OMPPTeamMemAlloc:
11563 AS = LangAS::Default;
11564 return true;
11565 case OMPAllocateDeclAttr::OMPUserDefinedMemAlloc:
11566 llvm_unreachable("Expected predefined allocator for the variables with the "
11567 "static storage.");
11568 }
11569 return false;
11570}
11571
11575
11577 CodeGenModule &CGM)
11578 : CGM(CGM) {
11579 if (CGM.getLangOpts().OpenMPIsTargetDevice) {
11580 SavedShouldMarkAsGlobal = CGM.getOpenMPRuntime().ShouldMarkAsGlobal;
11581 CGM.getOpenMPRuntime().ShouldMarkAsGlobal = false;
11582 }
11583}
11584
11586 if (CGM.getLangOpts().OpenMPIsTargetDevice)
11587 CGM.getOpenMPRuntime().ShouldMarkAsGlobal = SavedShouldMarkAsGlobal;
11588}
11589
11591 if (!CGM.getLangOpts().OpenMPIsTargetDevice || !ShouldMarkAsGlobal)
11592 return true;
11593
11594 const auto *D = cast<FunctionDecl>(GD.getDecl());
11595 // Do not emit function if it is marked as declare target as it was already
11596 // emitted.
11597 if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(D)) {
11598 if (D->hasBody() && AlreadyEmittedTargetDecls.count(D) == 0) {
11599 if (auto *F = dyn_cast_or_null<llvm::Function>(
11600 CGM.GetGlobalValue(CGM.getMangledName(GD))))
11601 return !F->isDeclaration();
11602 return false;
11603 }
11604 return true;
11605 }
11606
11607 return !AlreadyEmittedTargetDecls.insert(D).second;
11608}
11609
11611 const OMPExecutableDirective &D,
11612 SourceLocation Loc,
11613 llvm::Function *OutlinedFn,
11614 ArrayRef<llvm::Value *> CapturedVars) {
11615 if (!CGF.HaveInsertPoint())
11616 return;
11617
11618 llvm::Value *RTLoc = emitUpdateLocation(CGF, Loc);
11620
11621 // Build call __kmpc_fork_teams(loc, n, microtask, var1, .., varn);
11622 llvm::Value *Args[] = {
11623 RTLoc,
11624 CGF.Builder.getInt32(CapturedVars.size()), // Number of captured vars
11625 OutlinedFn};
11627 RealArgs.append(std::begin(Args), std::end(Args));
11628 RealArgs.append(CapturedVars.begin(), CapturedVars.end());
11629
11630 llvm::FunctionCallee RTLFn = OMPBuilder.getOrCreateRuntimeFunction(
11631 CGM.getModule(), OMPRTL___kmpc_fork_teams);
11632 CGF.EmitRuntimeCall(RTLFn, RealArgs);
11633}
11634
11636 const Expr *NumTeams,
11637 const Expr *ThreadLimit,
11638 SourceLocation Loc) {
11639 if (!CGF.HaveInsertPoint())
11640 return;
11641
11642 llvm::Value *RTLoc = emitUpdateLocation(CGF, Loc);
11643
11644 llvm::Value *NumTeamsVal =
11645 NumTeams
11646 ? CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(NumTeams),
11647 CGF.CGM.Int32Ty, /* isSigned = */ true)
11648 : CGF.Builder.getInt32(0);
11649
11650 llvm::Value *ThreadLimitVal =
11651 ThreadLimit
11652 ? CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(ThreadLimit),
11653 CGF.CGM.Int32Ty, /* isSigned = */ true)
11654 : CGF.Builder.getInt32(0);
11655
11656 // Build call __kmpc_push_num_teamss(&loc, global_tid, num_teams, thread_limit)
11657 llvm::Value *PushNumTeamsArgs[] = {RTLoc, getThreadID(CGF, Loc), NumTeamsVal,
11658 ThreadLimitVal};
11659 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
11660 CGM.getModule(), OMPRTL___kmpc_push_num_teams),
11661 PushNumTeamsArgs);
11662}
11663
11665 const Expr *ThreadLimit,
11666 SourceLocation Loc) {
11667 llvm::Value *RTLoc = emitUpdateLocation(CGF, Loc);
11668 llvm::Value *ThreadLimitVal =
11669 ThreadLimit
11670 ? CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(ThreadLimit),
11671 CGF.CGM.Int32Ty, /* isSigned = */ true)
11672 : CGF.Builder.getInt32(0);
11673
11674 // Build call __kmpc_set_thread_limit(&loc, global_tid, thread_limit)
11675 llvm::Value *ThreadLimitArgs[] = {RTLoc, getThreadID(CGF, Loc),
11676 ThreadLimitVal};
11677 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
11678 CGM.getModule(), OMPRTL___kmpc_set_thread_limit),
11679 ThreadLimitArgs);
11680}
11681
11683 CodeGenFunction &CGF, const OMPExecutableDirective &D, const Expr *IfCond,
11684 const Expr *Device, const RegionCodeGenTy &CodeGen,
11686 if (!CGF.HaveInsertPoint())
11687 return;
11688
11689 // Action used to replace the default codegen action and turn privatization
11690 // off.
11691 PrePostActionTy NoPrivAction;
11692
11693 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
11694
11695 llvm::Value *IfCondVal = nullptr;
11696 if (IfCond)
11697 IfCondVal = CGF.EvaluateExprAsBool(IfCond);
11698
11699 // Emit device ID if any.
11700 llvm::Value *DeviceID = nullptr;
11701 if (Device) {
11702 DeviceID = CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(Device),
11703 CGF.Int64Ty, /*isSigned=*/true);
11704 } else {
11705 DeviceID = CGF.Builder.getInt64(OMP_DEVICEID_UNDEF);
11706 }
11707
11708 // Fill up the arrays with all the mapped variables.
11709 MappableExprsHandler::MapCombinedInfoTy CombinedInfo;
11710 auto GenMapInfoCB =
11711 [&](InsertPointTy CodeGenIP) -> llvm::OpenMPIRBuilder::MapInfosTy & {
11712 CGF.Builder.restoreIP(CodeGenIP);
11713 // Get map clause information.
11714 MappableExprsHandler MEHandler(D, CGF);
11715 MEHandler.generateAllInfo(CombinedInfo, OMPBuilder);
11716
11717 auto FillInfoMap = [&](MappableExprsHandler::MappingExprInfo &MapExpr) {
11718 return emitMappingInformation(CGF, OMPBuilder, MapExpr);
11719 };
11720 if (CGM.getCodeGenOpts().getDebugInfo() !=
11721 llvm::codegenoptions::NoDebugInfo) {
11722 CombinedInfo.Names.resize(CombinedInfo.Exprs.size());
11723 llvm::transform(CombinedInfo.Exprs, CombinedInfo.Names.begin(),
11724 FillInfoMap);
11725 }
11726
11727 return CombinedInfo;
11728 };
11729 using BodyGenTy = llvm::OpenMPIRBuilder::BodyGenTy;
11730 auto BodyCB = [&](InsertPointTy CodeGenIP, BodyGenTy BodyGenType) {
11731 CGF.Builder.restoreIP(CodeGenIP);
11732 switch (BodyGenType) {
11733 case BodyGenTy::Priv:
11734 if (!Info.CaptureDeviceAddrMap.empty())
11735 CodeGen(CGF);
11736 break;
11737 case BodyGenTy::DupNoPriv:
11738 if (!Info.CaptureDeviceAddrMap.empty()) {
11739 CodeGen.setAction(NoPrivAction);
11740 CodeGen(CGF);
11741 }
11742 break;
11743 case BodyGenTy::NoPriv:
11744 if (Info.CaptureDeviceAddrMap.empty()) {
11745 CodeGen.setAction(NoPrivAction);
11746 CodeGen(CGF);
11747 }
11748 break;
11749 }
11750 return InsertPointTy(CGF.Builder.GetInsertBlock(),
11751 CGF.Builder.GetInsertPoint());
11752 };
11753
11754 auto DeviceAddrCB = [&](unsigned int I, llvm::Value *NewDecl) {
11755 if (const ValueDecl *DevVD = CombinedInfo.DevicePtrDecls[I]) {
11756 Info.CaptureDeviceAddrMap.try_emplace(DevVD, NewDecl);
11757 }
11758 };
11759
11760 auto CustomMapperCB = [&](unsigned int I) {
11761 llvm::Function *MFunc = nullptr;
11762 if (CombinedInfo.Mappers[I]) {
11763 Info.HasMapper = true;
11765 cast<OMPDeclareMapperDecl>(CombinedInfo.Mappers[I]));
11766 }
11767 return MFunc;
11768 };
11769
11770 // Source location for the ident struct
11771 llvm::Value *RTLoc = emitUpdateLocation(CGF, D.getBeginLoc());
11772
11773 InsertPointTy AllocaIP(CGF.AllocaInsertPt->getParent(),
11774 CGF.AllocaInsertPt->getIterator());
11775 InsertPointTy CodeGenIP(CGF.Builder.GetInsertBlock(),
11776 CGF.Builder.GetInsertPoint());
11777 llvm::OpenMPIRBuilder::LocationDescription OmpLoc(CodeGenIP);
11778 llvm::OpenMPIRBuilder::InsertPointTy AfterIP =
11779 cantFail(OMPBuilder.createTargetData(
11780 OmpLoc, AllocaIP, CodeGenIP, /*DeallocBlocks=*/{}, DeviceID,
11781 IfCondVal, Info, GenMapInfoCB, CustomMapperCB,
11782 /*MapperFunc=*/nullptr, BodyCB, DeviceAddrCB, RTLoc));
11783 CGF.Builder.restoreIP(AfterIP);
11784}
11785
11787 CodeGenFunction &CGF, const OMPExecutableDirective &D, const Expr *IfCond,
11788 const Expr *Device) {
11789 if (!CGF.HaveInsertPoint())
11790 return;
11791
11795 "Expecting either target enter, exit data, or update directives.");
11796
11798 llvm::Value *MapTypesArray = nullptr;
11799 llvm::Value *MapNamesArray = nullptr;
11800 // Generate the code for the opening of the data environment.
11801 auto &&ThenGen = [this, &D, Device, &InputInfo, &MapTypesArray,
11802 &MapNamesArray](CodeGenFunction &CGF, PrePostActionTy &) {
11803 // Emit device ID if any.
11804 llvm::Value *DeviceID = nullptr;
11805 if (Device) {
11806 DeviceID = CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(Device),
11807 CGF.Int64Ty, /*isSigned=*/true);
11808 } else {
11809 DeviceID = CGF.Builder.getInt64(OMP_DEVICEID_UNDEF);
11810 }
11811
11812 // Emit the number of elements in the offloading arrays.
11813 llvm::Constant *PointerNum =
11814 CGF.Builder.getInt32(InputInfo.NumberOfTargetItems);
11815
11816 // Source location for the ident struct
11817 llvm::Value *RTLoc = emitUpdateLocation(CGF, D.getBeginLoc());
11818
11819 SmallVector<llvm::Value *, 13> OffloadingArgs(
11820 {RTLoc, DeviceID, PointerNum,
11821 InputInfo.BasePointersArray.emitRawPointer(CGF),
11822 InputInfo.PointersArray.emitRawPointer(CGF),
11823 InputInfo.SizesArray.emitRawPointer(CGF), MapTypesArray, MapNamesArray,
11824 InputInfo.MappersArray.emitRawPointer(CGF)});
11825
11826 // Select the right runtime function call for each standalone
11827 // directive.
11828 const bool HasNowait = D.hasClausesOfKind<OMPNowaitClause>();
11829 RuntimeFunction RTLFn;
11830 switch (D.getDirectiveKind()) {
11831 case OMPD_target_enter_data:
11832 RTLFn = HasNowait ? OMPRTL___tgt_target_data_begin_nowait_mapper
11833 : OMPRTL___tgt_target_data_begin_mapper;
11834 break;
11835 case OMPD_target_exit_data:
11836 RTLFn = HasNowait ? OMPRTL___tgt_target_data_end_nowait_mapper
11837 : OMPRTL___tgt_target_data_end_mapper;
11838 break;
11839 case OMPD_target_update:
11840 RTLFn = HasNowait ? OMPRTL___tgt_target_data_update_nowait_mapper
11841 : OMPRTL___tgt_target_data_update_mapper;
11842 break;
11843 case OMPD_parallel:
11844 case OMPD_for:
11845 case OMPD_parallel_for:
11846 case OMPD_parallel_master:
11847 case OMPD_parallel_sections:
11848 case OMPD_for_simd:
11849 case OMPD_parallel_for_simd:
11850 case OMPD_cancel:
11851 case OMPD_cancellation_point:
11852 case OMPD_ordered:
11853 case OMPD_threadprivate:
11854 case OMPD_allocate:
11855 case OMPD_task:
11856 case OMPD_simd:
11857 case OMPD_tile:
11858 case OMPD_unroll:
11859 case OMPD_sections:
11860 case OMPD_section:
11861 case OMPD_single:
11862 case OMPD_master:
11863 case OMPD_critical:
11864 case OMPD_taskyield:
11865 case OMPD_barrier:
11866 case OMPD_taskwait:
11867 case OMPD_taskgroup:
11868 case OMPD_atomic:
11869 case OMPD_flush:
11870 case OMPD_depobj:
11871 case OMPD_scan:
11872 case OMPD_teams:
11873 case OMPD_target_data:
11874 case OMPD_distribute:
11875 case OMPD_distribute_simd:
11876 case OMPD_distribute_parallel_for:
11877 case OMPD_distribute_parallel_for_simd:
11878 case OMPD_teams_distribute:
11879 case OMPD_teams_distribute_simd:
11880 case OMPD_teams_distribute_parallel_for:
11881 case OMPD_teams_distribute_parallel_for_simd:
11882 case OMPD_declare_simd:
11883 case OMPD_declare_variant:
11884 case OMPD_begin_declare_variant:
11885 case OMPD_end_declare_variant:
11886 case OMPD_declare_target:
11887 case OMPD_end_declare_target:
11888 case OMPD_declare_reduction:
11889 case OMPD_declare_mapper:
11890 case OMPD_taskloop:
11891 case OMPD_taskloop_simd:
11892 case OMPD_master_taskloop:
11893 case OMPD_master_taskloop_simd:
11894 case OMPD_parallel_master_taskloop:
11895 case OMPD_parallel_master_taskloop_simd:
11896 case OMPD_target:
11897 case OMPD_target_simd:
11898 case OMPD_target_teams_distribute:
11899 case OMPD_target_teams_distribute_simd:
11900 case OMPD_target_teams_distribute_parallel_for:
11901 case OMPD_target_teams_distribute_parallel_for_simd:
11902 case OMPD_target_teams:
11903 case OMPD_target_parallel:
11904 case OMPD_target_parallel_for:
11905 case OMPD_target_parallel_for_simd:
11906 case OMPD_requires:
11907 case OMPD_metadirective:
11908 case OMPD_unknown:
11909 default:
11910 llvm_unreachable("Unexpected standalone target data directive.");
11911 break;
11912 }
11913 if (HasNowait) {
11914 OffloadingArgs.push_back(llvm::Constant::getNullValue(CGF.Int32Ty));
11915 OffloadingArgs.push_back(llvm::Constant::getNullValue(CGF.VoidPtrTy));
11916 OffloadingArgs.push_back(llvm::Constant::getNullValue(CGF.Int32Ty));
11917 OffloadingArgs.push_back(llvm::Constant::getNullValue(CGF.VoidPtrTy));
11918 }
11919 CGF.EmitRuntimeCall(
11920 OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(), RTLFn),
11921 OffloadingArgs);
11922 };
11923
11924 auto &&TargetThenGen = [this, &ThenGen, &D, &InputInfo, &MapTypesArray,
11925 &MapNamesArray](CodeGenFunction &CGF,
11926 PrePostActionTy &) {
11927 // Fill up the arrays with all the mapped variables.
11928 MappableExprsHandler::MapCombinedInfoTy CombinedInfo;
11930 MappableExprsHandler MEHandler(D, CGF);
11931 genMapInfo(MEHandler, CGF, CombinedInfo, OMPBuilder);
11932 emitOffloadingArraysAndArgs(CGF, CombinedInfo, Info, OMPBuilder,
11933 /*IsNonContiguous=*/true, /*ForEndCall=*/false);
11934
11935 bool RequiresOuterTask = D.hasClausesOfKind<OMPDependClause>() ||
11936 D.hasClausesOfKind<OMPNowaitClause>();
11937
11938 InputInfo.NumberOfTargetItems = Info.NumberOfPtrs;
11939 InputInfo.BasePointersArray = Address(Info.RTArgs.BasePointersArray,
11940 CGF.VoidPtrTy, CGM.getPointerAlign());
11941 InputInfo.PointersArray = Address(Info.RTArgs.PointersArray, CGF.VoidPtrTy,
11942 CGM.getPointerAlign());
11943 InputInfo.SizesArray =
11944 Address(Info.RTArgs.SizesArray, CGF.Int64Ty, CGM.getPointerAlign());
11945 InputInfo.MappersArray =
11946 Address(Info.RTArgs.MappersArray, CGF.VoidPtrTy, CGM.getPointerAlign());
11947 MapTypesArray = Info.RTArgs.MapTypesArray;
11948 MapNamesArray = Info.RTArgs.MapNamesArray;
11949 if (RequiresOuterTask)
11950 CGF.EmitOMPTargetTaskBasedDirective(D, ThenGen, InputInfo);
11951 else
11952 emitInlinedDirective(CGF, D.getDirectiveKind(), ThenGen);
11953 };
11954
11955 if (IfCond) {
11956 emitIfClause(CGF, IfCond, TargetThenGen,
11957 [](CodeGenFunction &CGF, PrePostActionTy &) {});
11958 } else {
11959 RegionCodeGenTy ThenRCG(TargetThenGen);
11960 ThenRCG(CGF);
11961 }
11962}
11963
11964static unsigned
11967 // Every vector variant of a SIMD-enabled function has a vector length (VLEN).
11968 // If OpenMP clause "simdlen" is used, the VLEN is the value of the argument
11969 // of that clause. The VLEN value must be power of 2.
11970 // In other case the notion of the function`s "characteristic data type" (CDT)
11971 // is used to compute the vector length.
11972 // CDT is defined in the following order:
11973 // a) For non-void function, the CDT is the return type.
11974 // b) If the function has any non-uniform, non-linear parameters, then the
11975 // CDT is the type of the first such parameter.
11976 // c) If the CDT determined by a) or b) above is struct, union, or class
11977 // type which is pass-by-value (except for the type that maps to the
11978 // built-in complex data type), the characteristic data type is int.
11979 // d) If none of the above three cases is applicable, the CDT is int.
11980 // The VLEN is then determined based on the CDT and the size of vector
11981 // register of that ISA for which current vector version is generated. The
11982 // VLEN is computed using the formula below:
11983 // VLEN = sizeof(vector_register) / sizeof(CDT),
11984 // where vector register size specified in section 3.2.1 Registers and the
11985 // Stack Frame of original AMD64 ABI document.
11986 QualType RetType = FD->getReturnType();
11987 if (RetType.isNull())
11988 return 0;
11989 ASTContext &C = FD->getASTContext();
11990 QualType CDT;
11991 if (!RetType.isNull() && !RetType->isVoidType()) {
11992 CDT = RetType;
11993 } else {
11994 unsigned Offset = 0;
11995 if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
11996 if (ParamAttrs[Offset].Kind ==
11997 llvm::OpenMPIRBuilder::DeclareSimdKindTy::Vector)
11998 CDT = C.getPointerType(C.getCanonicalTagType(MD->getParent()));
11999 ++Offset;
12000 }
12001 if (CDT.isNull()) {
12002 for (unsigned I = 0, E = FD->getNumParams(); I < E; ++I) {
12003 if (ParamAttrs[I + Offset].Kind ==
12004 llvm::OpenMPIRBuilder::DeclareSimdKindTy::Vector) {
12005 CDT = FD->getParamDecl(I)->getType();
12006 break;
12007 }
12008 }
12009 }
12010 }
12011 if (CDT.isNull())
12012 CDT = C.IntTy;
12013 CDT = CDT->getCanonicalTypeUnqualified();
12014 if (CDT->isRecordType() || CDT->isUnionType())
12015 CDT = C.IntTy;
12016 return C.getTypeSize(CDT);
12017}
12018
12019// This are the Functions that are needed to mangle the name of the
12020// vector functions generated by the compiler, according to the rules
12021// defined in the "Vector Function ABI specifications for AArch64",
12022// available at
12023// https://developer.arm.com/products/software-development-tools/hpc/arm-compiler-for-hpc/vector-function-abi.
12024
12025/// Maps To Vector (MTV), as defined in 4.1.1 of the AAVFABI (2021Q1).
12027 llvm::OpenMPIRBuilder::DeclareSimdKindTy Kind) {
12028 QT = QT.getCanonicalType();
12029
12030 if (QT->isVoidType())
12031 return false;
12032
12033 if (Kind == llvm::OpenMPIRBuilder::DeclareSimdKindTy::Uniform)
12034 return false;
12035
12036 if (Kind == llvm::OpenMPIRBuilder::DeclareSimdKindTy::LinearUVal ||
12037 Kind == llvm::OpenMPIRBuilder::DeclareSimdKindTy::LinearRef)
12038 return false;
12039
12040 if ((Kind == llvm::OpenMPIRBuilder::DeclareSimdKindTy::Linear ||
12041 Kind == llvm::OpenMPIRBuilder::DeclareSimdKindTy::LinearVal) &&
12042 !QT->isReferenceType())
12043 return false;
12044
12045 return true;
12046}
12047
12048/// Pass By Value (PBV), as defined in 3.1.2 of the AAVFABI.
12050 QT = QT.getCanonicalType();
12051 unsigned Size = C.getTypeSize(QT);
12052
12053 // Only scalars and complex within 16 bytes wide set PVB to true.
12054 if (Size != 8 && Size != 16 && Size != 32 && Size != 64 && Size != 128)
12055 return false;
12056
12057 if (QT->isFloatingType())
12058 return true;
12059
12060 if (QT->isIntegerType())
12061 return true;
12062
12063 if (QT->isPointerType())
12064 return true;
12065
12066 // TODO: Add support for complex types (section 3.1.2, item 2).
12067
12068 return false;
12069}
12070
12071/// Computes the lane size (LS) of a return type or of an input parameter,
12072/// as defined by `LS(P)` in 3.2.1 of the AAVFABI.
12073/// TODO: Add support for references, section 3.2.1, item 1.
12074static unsigned getAArch64LS(QualType QT,
12075 llvm::OpenMPIRBuilder::DeclareSimdKindTy Kind,
12076 ASTContext &C) {
12077 if (!getAArch64MTV(QT, Kind) && QT.getCanonicalType()->isPointerType()) {
12079 if (getAArch64PBV(PTy, C))
12080 return C.getTypeSize(PTy);
12081 }
12082 if (getAArch64PBV(QT, C))
12083 return C.getTypeSize(QT);
12084
12085 return C.getTypeSize(C.getUIntPtrType());
12086}
12087
12088// Get Narrowest Data Size (NDS) and Widest Data Size (WDS) from the
12089// signature of the scalar function, as defined in 3.2.2 of the
12090// AAVFABI.
12091static std::tuple<unsigned, unsigned, bool>
12094 QualType RetType = FD->getReturnType().getCanonicalType();
12095
12096 ASTContext &C = FD->getASTContext();
12097
12098 bool OutputBecomesInput = false;
12099
12101 if (!RetType->isVoidType()) {
12102 Sizes.push_back(getAArch64LS(
12103 RetType, llvm::OpenMPIRBuilder::DeclareSimdKindTy::Vector, C));
12104 if (!getAArch64PBV(RetType, C) && getAArch64MTV(RetType, {}))
12105 OutputBecomesInput = true;
12106 }
12107 for (unsigned I = 0, E = FD->getNumParams(); I < E; ++I) {
12109 Sizes.push_back(getAArch64LS(QT, ParamAttrs[I].Kind, C));
12110 }
12111
12112 assert(!Sizes.empty() && "Unable to determine NDS and WDS.");
12113 // The LS of a function parameter / return value can only be a power
12114 // of 2, starting from 8 bits, up to 128.
12115 assert(llvm::all_of(Sizes,
12116 [](unsigned Size) {
12117 return Size == 8 || Size == 16 || Size == 32 ||
12118 Size == 64 || Size == 128;
12119 }) &&
12120 "Invalid size");
12121
12122 return std::make_tuple(*llvm::min_element(Sizes), *llvm::max_element(Sizes),
12123 OutputBecomesInput);
12124}
12125
12126static llvm::OpenMPIRBuilder::DeclareSimdBranch
12127convertDeclareSimdBranch(OMPDeclareSimdDeclAttr::BranchStateTy State) {
12128 switch (State) {
12129 case OMPDeclareSimdDeclAttr::BS_Undefined:
12130 return llvm::OpenMPIRBuilder::DeclareSimdBranch::Undefined;
12131 case OMPDeclareSimdDeclAttr::BS_Inbranch:
12132 return llvm::OpenMPIRBuilder::DeclareSimdBranch::Inbranch;
12133 case OMPDeclareSimdDeclAttr::BS_Notinbranch:
12134 return llvm::OpenMPIRBuilder::DeclareSimdBranch::Notinbranch;
12135 }
12136 llvm_unreachable("unexpected declare simd branch state");
12137}
12138
12139// Check the values provided via `simdlen` by the user.
12141 unsigned UserVLEN, unsigned WDS, char ISA) {
12142 // 1. A `simdlen(1)` doesn't produce vector signatures.
12143 if (UserVLEN == 1) {
12144 CGM.getDiags().Report(SLoc, diag::warn_simdlen_1_no_effect);
12145 return false;
12146 }
12147
12148 // 2. Section 3.3.1, item 1: user input must be a power of 2 for Advanced
12149 // SIMD.
12150 if (ISA == 'n' && UserVLEN && !llvm::isPowerOf2_32(UserVLEN)) {
12151 CGM.getDiags().Report(SLoc, diag::warn_simdlen_requires_power_of_2);
12152 return false;
12153 }
12154
12155 // 3. Section 3.4.1: SVE fixed length must obey the architectural limits.
12156 if (ISA == 's' && UserVLEN != 0 &&
12157 ((UserVLEN * WDS > 2048) || (UserVLEN * WDS % 128 != 0))) {
12158 CGM.getDiags().Report(SLoc, diag::warn_simdlen_must_fit_lanes) << WDS;
12159 return false;
12160 }
12161
12162 return true;
12163}
12164
12166 llvm::Function *Fn) {
12167 ASTContext &C = CGM.getContext();
12168 FD = FD->getMostRecentDecl();
12169 while (FD) {
12170 // Map params to their positions in function decl.
12171 llvm::DenseMap<const Decl *, unsigned> ParamPositions;
12172 if (isa<CXXMethodDecl>(FD))
12173 ParamPositions.try_emplace(FD, 0);
12174 unsigned ParamPos = ParamPositions.size();
12175 for (const ParmVarDecl *P : FD->parameters()) {
12176 ParamPositions.try_emplace(P->getCanonicalDecl(), ParamPos);
12177 ++ParamPos;
12178 }
12179 for (const auto *Attr : FD->specific_attrs<OMPDeclareSimdDeclAttr>()) {
12181 ParamPositions.size());
12182 // Mark uniform parameters.
12183 for (const Expr *E : Attr->uniforms()) {
12184 E = E->IgnoreParenImpCasts();
12185 unsigned Pos;
12186 if (isa<CXXThisExpr>(E)) {
12187 Pos = ParamPositions[FD];
12188 } else {
12189 const auto *PVD = cast<ParmVarDecl>(cast<DeclRefExpr>(E)->getDecl())
12190 ->getCanonicalDecl();
12191 auto It = ParamPositions.find(PVD);
12192 assert(It != ParamPositions.end() && "Function parameter not found");
12193 Pos = It->second;
12194 }
12195 ParamAttrs[Pos].Kind =
12196 llvm::OpenMPIRBuilder::DeclareSimdKindTy::Uniform;
12197 }
12198 // Get alignment info.
12199 auto *NI = Attr->alignments_begin();
12200 for (const Expr *E : Attr->aligneds()) {
12201 E = E->IgnoreParenImpCasts();
12202 unsigned Pos;
12203 QualType ParmTy;
12204 if (isa<CXXThisExpr>(E)) {
12205 Pos = ParamPositions[FD];
12206 ParmTy = E->getType();
12207 } else {
12208 const auto *PVD = cast<ParmVarDecl>(cast<DeclRefExpr>(E)->getDecl())
12209 ->getCanonicalDecl();
12210 auto It = ParamPositions.find(PVD);
12211 assert(It != ParamPositions.end() && "Function parameter not found");
12212 Pos = It->second;
12213 ParmTy = PVD->getType();
12214 }
12215 ParamAttrs[Pos].Alignment =
12216 (*NI)
12217 ? (*NI)->EvaluateKnownConstInt(C)
12218 : llvm::APSInt::getUnsigned(
12219 C.toCharUnitsFromBits(C.getOpenMPDefaultSimdAlign(ParmTy))
12220 .getQuantity());
12221 ++NI;
12222 }
12223 // Mark linear parameters.
12224 auto *SI = Attr->steps_begin();
12225 auto *MI = Attr->modifiers_begin();
12226 for (const Expr *E : Attr->linears()) {
12227 E = E->IgnoreParenImpCasts();
12228 unsigned Pos;
12229 bool IsReferenceType = false;
12230 // Rescaling factor needed to compute the linear parameter
12231 // value in the mangled name.
12232 unsigned PtrRescalingFactor = 1;
12233 if (isa<CXXThisExpr>(E)) {
12234 Pos = ParamPositions[FD];
12235 auto *P = cast<PointerType>(E->getType());
12236 PtrRescalingFactor = CGM.getContext()
12237 .getTypeSizeInChars(P->getPointeeType())
12238 .getQuantity();
12239 } else {
12240 const auto *PVD = cast<ParmVarDecl>(cast<DeclRefExpr>(E)->getDecl())
12241 ->getCanonicalDecl();
12242 auto It = ParamPositions.find(PVD);
12243 assert(It != ParamPositions.end() && "Function parameter not found");
12244 Pos = It->second;
12245 if (auto *P = dyn_cast<PointerType>(PVD->getType()))
12246 PtrRescalingFactor = CGM.getContext()
12247 .getTypeSizeInChars(P->getPointeeType())
12248 .getQuantity();
12249 else if (PVD->getType()->isReferenceType()) {
12250 IsReferenceType = true;
12251 PtrRescalingFactor =
12252 CGM.getContext()
12253 .getTypeSizeInChars(PVD->getType().getNonReferenceType())
12254 .getQuantity();
12255 }
12256 }
12257 llvm::OpenMPIRBuilder::DeclareSimdAttrTy &ParamAttr = ParamAttrs[Pos];
12258 if (*MI == OMPC_LINEAR_ref)
12259 ParamAttr.Kind = llvm::OpenMPIRBuilder::DeclareSimdKindTy::LinearRef;
12260 else if (*MI == OMPC_LINEAR_uval)
12261 ParamAttr.Kind = llvm::OpenMPIRBuilder::DeclareSimdKindTy::LinearUVal;
12262 else if (IsReferenceType)
12263 ParamAttr.Kind = llvm::OpenMPIRBuilder::DeclareSimdKindTy::LinearVal;
12264 else
12265 ParamAttr.Kind = llvm::OpenMPIRBuilder::DeclareSimdKindTy::Linear;
12266 // Assuming a stride of 1, for `linear` without modifiers.
12267 ParamAttr.StrideOrArg = llvm::APSInt::getUnsigned(1);
12268 if (*SI) {
12270 if (!(*SI)->EvaluateAsInt(Result, C, Expr::SE_AllowSideEffects)) {
12271 if (const auto *DRE =
12272 cast<DeclRefExpr>((*SI)->IgnoreParenImpCasts())) {
12273 if (const auto *StridePVD =
12274 dyn_cast<ParmVarDecl>(DRE->getDecl())) {
12275 ParamAttr.HasVarStride = true;
12276 auto It = ParamPositions.find(StridePVD->getCanonicalDecl());
12277 assert(It != ParamPositions.end() &&
12278 "Function parameter not found");
12279 ParamAttr.StrideOrArg = llvm::APSInt::getUnsigned(It->second);
12280 }
12281 }
12282 } else {
12283 ParamAttr.StrideOrArg = Result.Val.getInt();
12284 }
12285 }
12286 // If we are using a linear clause on a pointer, we need to
12287 // rescale the value of linear_step with the byte size of the
12288 // pointee type.
12289 if (!ParamAttr.HasVarStride &&
12290 (ParamAttr.Kind ==
12291 llvm::OpenMPIRBuilder::DeclareSimdKindTy::Linear ||
12292 ParamAttr.Kind ==
12293 llvm::OpenMPIRBuilder::DeclareSimdKindTy::LinearRef))
12294 ParamAttr.StrideOrArg = ParamAttr.StrideOrArg * PtrRescalingFactor;
12295 ++SI;
12296 ++MI;
12297 }
12298 llvm::APSInt VLENVal;
12299 SourceLocation ExprLoc;
12300 const Expr *VLENExpr = Attr->getSimdlen();
12301 if (VLENExpr) {
12302 VLENVal = VLENExpr->EvaluateKnownConstInt(C);
12303 ExprLoc = VLENExpr->getExprLoc();
12304 }
12305 llvm::OpenMPIRBuilder::DeclareSimdBranch State =
12306 convertDeclareSimdBranch(Attr->getBranchState());
12307 if (CGM.getTriple().isX86()) {
12308 unsigned NumElts = evaluateCDTSize(FD, ParamAttrs);
12309 assert(NumElts && "Non-zero simdlen/cdtsize expected");
12310 OMPBuilder.emitX86DeclareSimdFunction(Fn, NumElts, VLENVal, ParamAttrs,
12311 State);
12312 } else if (CGM.getTriple().getArch() == llvm::Triple::aarch64) {
12313 unsigned VLEN = VLENVal.getExtValue();
12314 // Get basic data for building the vector signature.
12315 const auto Data = getNDSWDS(FD, ParamAttrs);
12316 const unsigned NDS = std::get<0>(Data);
12317 const unsigned WDS = std::get<1>(Data);
12318 const bool OutputBecomesInput = std::get<2>(Data);
12319 if (CGM.getTarget().hasFeature("sve")) {
12320 if (validateAArch64Simdlen(CGM, ExprLoc, VLEN, WDS, 's'))
12321 OMPBuilder.emitAArch64DeclareSimdFunction(
12322 Fn, VLEN, ParamAttrs, State, 's', NDS, OutputBecomesInput);
12323 } else if (CGM.getTarget().hasFeature("neon")) {
12324 if (validateAArch64Simdlen(CGM, ExprLoc, VLEN, WDS, 'n'))
12325 OMPBuilder.emitAArch64DeclareSimdFunction(
12326 Fn, VLEN, ParamAttrs, State, 'n', NDS, OutputBecomesInput);
12327 }
12328 }
12329 }
12330 FD = FD->getPreviousDecl();
12331 }
12332}
12333
12334namespace {
12335/// Cleanup action for doacross support.
12336class DoacrossCleanupTy final : public EHScopeStack::Cleanup {
12337public:
12338 static const int DoacrossFinArgs = 2;
12339
12340private:
12341 llvm::FunctionCallee RTLFn;
12342 llvm::Value *Args[DoacrossFinArgs];
12343
12344public:
12345 DoacrossCleanupTy(llvm::FunctionCallee RTLFn,
12346 ArrayRef<llvm::Value *> CallArgs)
12347 : RTLFn(RTLFn) {
12348 assert(CallArgs.size() == DoacrossFinArgs);
12349 std::copy(CallArgs.begin(), CallArgs.end(), std::begin(Args));
12350 }
12351 void Emit(CodeGenFunction &CGF, Flags /*flags*/) override {
12352 if (!CGF.HaveInsertPoint())
12353 return;
12354 CGF.EmitRuntimeCall(RTLFn, Args);
12355 }
12356};
12357} // namespace
12358
12360 const OMPLoopDirective &D,
12361 ArrayRef<Expr *> NumIterations) {
12362 if (!CGF.HaveInsertPoint())
12363 return;
12364
12365 ASTContext &C = CGM.getContext();
12366 QualType Int64Ty = C.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/true);
12367 RecordDecl *RD;
12368 if (KmpDimTy.isNull()) {
12369 // Build struct kmp_dim { // loop bounds info casted to kmp_int64
12370 // kmp_int64 lo; // lower
12371 // kmp_int64 up; // upper
12372 // kmp_int64 st; // stride
12373 // };
12374 RD = C.buildImplicitRecord("kmp_dim");
12375 RD->startDefinition();
12376 addFieldToRecordDecl(C, RD, Int64Ty);
12377 addFieldToRecordDecl(C, RD, Int64Ty);
12378 addFieldToRecordDecl(C, RD, Int64Ty);
12379 RD->completeDefinition();
12380 KmpDimTy = C.getCanonicalTagType(RD);
12381 } else {
12382 RD = KmpDimTy->castAsRecordDecl();
12383 }
12384 llvm::APInt Size(/*numBits=*/32, NumIterations.size());
12385 QualType ArrayTy = C.getConstantArrayType(KmpDimTy, Size, nullptr,
12387
12388 Address DimsAddr = CGF.CreateMemTemp(ArrayTy, "dims");
12389 CGF.EmitNullInitialization(DimsAddr, ArrayTy);
12390 enum { LowerFD = 0, UpperFD, StrideFD };
12391 // Fill dims with data.
12392 for (unsigned I = 0, E = NumIterations.size(); I < E; ++I) {
12393 LValue DimsLVal = CGF.MakeAddrLValue(
12394 CGF.Builder.CreateConstArrayGEP(DimsAddr, I), KmpDimTy);
12395 // dims.upper = num_iterations;
12396 LValue UpperLVal = CGF.EmitLValueForField(
12397 DimsLVal, *std::next(RD->field_begin(), UpperFD));
12398 llvm::Value *NumIterVal = CGF.EmitScalarConversion(
12399 CGF.EmitScalarExpr(NumIterations[I]), NumIterations[I]->getType(),
12400 Int64Ty, NumIterations[I]->getExprLoc());
12401 CGF.EmitStoreOfScalar(NumIterVal, UpperLVal);
12402 // dims.stride = 1;
12403 LValue StrideLVal = CGF.EmitLValueForField(
12404 DimsLVal, *std::next(RD->field_begin(), StrideFD));
12405 CGF.EmitStoreOfScalar(llvm::ConstantInt::getSigned(CGM.Int64Ty, /*V=*/1),
12406 StrideLVal);
12407 }
12408
12409 // Build call void __kmpc_doacross_init(ident_t *loc, kmp_int32 gtid,
12410 // kmp_int32 num_dims, struct kmp_dim * dims);
12411 llvm::Value *Args[] = {
12412 emitUpdateLocation(CGF, D.getBeginLoc()),
12413 getThreadID(CGF, D.getBeginLoc()),
12414 llvm::ConstantInt::getSigned(CGM.Int32Ty, NumIterations.size()),
12416 CGF.Builder.CreateConstArrayGEP(DimsAddr, 0).emitRawPointer(CGF),
12417 CGM.VoidPtrTy)};
12418
12419 llvm::FunctionCallee RTLFn = OMPBuilder.getOrCreateRuntimeFunction(
12420 CGM.getModule(), OMPRTL___kmpc_doacross_init);
12421 CGF.EmitRuntimeCall(RTLFn, Args);
12422 llvm::Value *FiniArgs[DoacrossCleanupTy::DoacrossFinArgs] = {
12423 emitUpdateLocation(CGF, D.getEndLoc()), getThreadID(CGF, D.getEndLoc())};
12424 llvm::FunctionCallee FiniRTLFn = OMPBuilder.getOrCreateRuntimeFunction(
12425 CGM.getModule(), OMPRTL___kmpc_doacross_fini);
12426 CGF.EHStack.pushCleanup<DoacrossCleanupTy>(NormalAndEHCleanup, FiniRTLFn,
12427 llvm::ArrayRef(FiniArgs));
12428}
12429
12430template <typename T>
12432 const T *C, llvm::Value *ULoc,
12433 llvm::Value *ThreadID) {
12434 QualType Int64Ty =
12435 CGM.getContext().getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1);
12436 llvm::APInt Size(/*numBits=*/32, C->getNumLoops());
12438 Int64Ty, Size, nullptr, ArraySizeModifier::Normal, 0);
12439 Address CntAddr = CGF.CreateMemTemp(ArrayTy, ".cnt.addr");
12440 for (unsigned I = 0, E = C->getNumLoops(); I < E; ++I) {
12441 const Expr *CounterVal = C->getLoopData(I);
12442 assert(CounterVal);
12443 llvm::Value *CntVal = CGF.EmitScalarConversion(
12444 CGF.EmitScalarExpr(CounterVal), CounterVal->getType(), Int64Ty,
12445 CounterVal->getExprLoc());
12446 CGF.EmitStoreOfScalar(CntVal, CGF.Builder.CreateConstArrayGEP(CntAddr, I),
12447 /*Volatile=*/false, Int64Ty);
12448 }
12449 llvm::Value *Args[] = {
12450 ULoc, ThreadID,
12451 CGF.Builder.CreateConstArrayGEP(CntAddr, 0).emitRawPointer(CGF)};
12452 llvm::FunctionCallee RTLFn;
12453 llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
12454 OMPDoacrossKind<T> ODK;
12455 if (ODK.isSource(C)) {
12456 RTLFn = OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(),
12457 OMPRTL___kmpc_doacross_post);
12458 } else {
12459 assert(ODK.isSink(C) && "Expect sink modifier.");
12460 RTLFn = OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(),
12461 OMPRTL___kmpc_doacross_wait);
12462 }
12463 CGF.EmitRuntimeCall(RTLFn, Args);
12464}
12465
12467 const OMPDependClause *C) {
12469 CGF, CGM, C, emitUpdateLocation(CGF, C->getBeginLoc()),
12470 getThreadID(CGF, C->getBeginLoc()));
12471}
12472
12474 const OMPDoacrossClause *C) {
12476 CGF, CGM, C, emitUpdateLocation(CGF, C->getBeginLoc()),
12477 getThreadID(CGF, C->getBeginLoc()));
12478}
12479
12481 llvm::FunctionCallee Callee,
12482 ArrayRef<llvm::Value *> Args) const {
12483 assert(Loc.isValid() && "Outlined function call location must be valid.");
12485
12486 if (auto *Fn = dyn_cast<llvm::Function>(Callee.getCallee())) {
12487 if (Fn->doesNotThrow()) {
12488 CGF.EmitNounwindRuntimeCall(Fn, Args);
12489 return;
12490 }
12491 }
12492 CGF.EmitRuntimeCall(Callee, Args);
12493}
12494
12496 CodeGenFunction &CGF, SourceLocation Loc, llvm::FunctionCallee OutlinedFn,
12497 ArrayRef<llvm::Value *> Args) const {
12498 emitCall(CGF, Loc, OutlinedFn, Args);
12499}
12500
12502 if (const auto *FD = dyn_cast<FunctionDecl>(D))
12503 if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(FD))
12505}
12506
12508 const VarDecl *NativeParam,
12509 const VarDecl *TargetParam) const {
12510 return CGF.GetAddrOfLocalVar(NativeParam);
12511}
12512
12513/// Return allocator value from expression, or return a null allocator (default
12514/// when no allocator specified).
12515static llvm::Value *getAllocatorVal(CodeGenFunction &CGF,
12516 const Expr *Allocator) {
12517 llvm::Value *AllocVal;
12518 if (Allocator) {
12519 AllocVal = CGF.EmitScalarExpr(Allocator);
12520 // According to the standard, the original allocator type is a enum
12521 // (integer). Convert to pointer type, if required.
12522 AllocVal = CGF.EmitScalarConversion(AllocVal, Allocator->getType(),
12523 CGF.getContext().VoidPtrTy,
12524 Allocator->getExprLoc());
12525 } else {
12526 // If no allocator specified, it defaults to the null allocator.
12527 AllocVal = llvm::Constant::getNullValue(
12529 }
12530 return AllocVal;
12531}
12532
12533/// Return the alignment from an allocate directive if present.
12534static llvm::Value *getAlignmentValue(CodeGenModule &CGM, const VarDecl *VD) {
12535 std::optional<CharUnits> AllocateAlignment = CGM.getOMPAllocateAlignment(VD);
12536
12537 if (!AllocateAlignment)
12538 return nullptr;
12539
12540 return llvm::ConstantInt::get(CGM.SizeTy, AllocateAlignment->getQuantity());
12541}
12542
12544 const VarDecl *VD) {
12545 if (!VD)
12546 return Address::invalid();
12547 Address UntiedAddr = Address::invalid();
12548 Address UntiedRealAddr = Address::invalid();
12549 auto It = FunctionToUntiedTaskStackMap.find(CGF.CurFn);
12550 if (It != FunctionToUntiedTaskStackMap.end()) {
12551 const UntiedLocalVarsAddressesMap &UntiedData =
12552 UntiedLocalVarsStack[It->second];
12553 auto I = UntiedData.find(VD);
12554 if (I != UntiedData.end()) {
12555 UntiedAddr = I->second.first;
12556 UntiedRealAddr = I->second.second;
12557 }
12558 }
12559 const VarDecl *CVD = VD->getCanonicalDecl();
12560 if (CVD->hasAttr<OMPAllocateDeclAttr>()) {
12561 // Use the default allocation.
12562 if (!isAllocatableDecl(VD))
12563 return UntiedAddr;
12564 llvm::Value *Size;
12565 CharUnits Align = CGM.getContext().getDeclAlign(CVD);
12566 if (CVD->getType()->isVariablyModifiedType()) {
12567 Size = CGF.getTypeSize(CVD->getType());
12568 // Align the size: ((size + align - 1) / align) * align
12569 Size = CGF.Builder.CreateNUWAdd(
12570 Size, CGM.getSize(Align - CharUnits::fromQuantity(1)));
12571 Size = CGF.Builder.CreateUDiv(Size, CGM.getSize(Align));
12572 Size = CGF.Builder.CreateNUWMul(Size, CGM.getSize(Align));
12573 } else {
12574 CharUnits Sz = CGM.getContext().getTypeSizeInChars(CVD->getType());
12575 Size = CGM.getSize(Sz.alignTo(Align));
12576 }
12577 llvm::Value *ThreadID = getThreadID(CGF, CVD->getBeginLoc());
12578 const auto *AA = CVD->getAttr<OMPAllocateDeclAttr>();
12579 const Expr *Allocator = AA->getAllocator();
12580 llvm::Value *AllocVal = getAllocatorVal(CGF, Allocator);
12581 llvm::Value *Alignment = getAlignmentValue(CGM, CVD);
12583 Args.push_back(ThreadID);
12584 if (Alignment)
12585 Args.push_back(Alignment);
12586 Args.push_back(Size);
12587 Args.push_back(AllocVal);
12588 llvm::omp::RuntimeFunction FnID =
12589 Alignment ? OMPRTL___kmpc_aligned_alloc : OMPRTL___kmpc_alloc;
12590 llvm::Value *Addr = CGF.EmitRuntimeCall(
12591 OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(), FnID), Args,
12592 getName({CVD->getName(), ".void.addr"}));
12593 llvm::FunctionCallee FiniRTLFn = OMPBuilder.getOrCreateRuntimeFunction(
12594 CGM.getModule(), OMPRTL___kmpc_free);
12595 QualType Ty = CGM.getContext().getPointerType(CVD->getType());
12597 Addr, CGF.ConvertTypeForMem(Ty), getName({CVD->getName(), ".addr"}));
12598 if (UntiedAddr.isValid())
12599 CGF.EmitStoreOfScalar(Addr, UntiedAddr, /*Volatile=*/false, Ty);
12600
12601 // Cleanup action for allocate support.
12602 class OMPAllocateCleanupTy final : public EHScopeStack::Cleanup {
12603 llvm::FunctionCallee RTLFn;
12604 SourceLocation::UIntTy LocEncoding;
12605 Address Addr;
12606 const Expr *AllocExpr;
12607
12608 public:
12609 OMPAllocateCleanupTy(llvm::FunctionCallee RTLFn,
12610 SourceLocation::UIntTy LocEncoding, Address Addr,
12611 const Expr *AllocExpr)
12612 : RTLFn(RTLFn), LocEncoding(LocEncoding), Addr(Addr),
12613 AllocExpr(AllocExpr) {}
12614 void Emit(CodeGenFunction &CGF, Flags /*flags*/) override {
12615 if (!CGF.HaveInsertPoint())
12616 return;
12617 llvm::Value *Args[3];
12618 Args[0] = CGF.CGM.getOpenMPRuntime().getThreadID(
12619 CGF, SourceLocation::getFromRawEncoding(LocEncoding));
12621 Addr.emitRawPointer(CGF), CGF.VoidPtrTy);
12622 llvm::Value *AllocVal = getAllocatorVal(CGF, AllocExpr);
12623 Args[2] = AllocVal;
12624 CGF.EmitRuntimeCall(RTLFn, Args);
12625 }
12626 };
12627 Address VDAddr =
12628 UntiedRealAddr.isValid()
12629 ? UntiedRealAddr
12630 : Address(Addr, CGF.ConvertTypeForMem(CVD->getType()), Align);
12631 CGF.EHStack.pushCleanup<OMPAllocateCleanupTy>(
12632 NormalAndEHCleanup, FiniRTLFn, CVD->getLocation().getRawEncoding(),
12633 VDAddr, Allocator);
12634 if (UntiedRealAddr.isValid())
12635 if (auto *Region =
12636 dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo))
12637 Region->emitUntiedSwitch(CGF);
12638 return VDAddr;
12639 }
12640 return UntiedAddr;
12641}
12642
12644 const VarDecl *VD) const {
12645 auto It = FunctionToUntiedTaskStackMap.find(CGF.CurFn);
12646 if (It == FunctionToUntiedTaskStackMap.end())
12647 return false;
12648 return UntiedLocalVarsStack[It->second].count(VD) > 0;
12649}
12650
12652 CodeGenModule &CGM, const OMPLoopDirective &S)
12653 : CGM(CGM), NeedToPush(S.hasClausesOfKind<OMPNontemporalClause>()) {
12654 assert(CGM.getLangOpts().OpenMP && "Not in OpenMP mode.");
12655 if (!NeedToPush)
12656 return;
12658 CGM.getOpenMPRuntime().NontemporalDeclsStack.emplace_back();
12659 for (const auto *C : S.getClausesOfKind<OMPNontemporalClause>()) {
12660 for (const Stmt *Ref : C->private_refs()) {
12661 const auto *SimpleRefExpr = cast<Expr>(Ref)->IgnoreParenImpCasts();
12662 const ValueDecl *VD;
12663 if (const auto *DRE = dyn_cast<DeclRefExpr>(SimpleRefExpr)) {
12664 VD = DRE->getDecl();
12665 } else {
12666 const auto *ME = cast<MemberExpr>(SimpleRefExpr);
12667 assert((ME->isImplicitCXXThis() ||
12668 isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts())) &&
12669 "Expected member of current class.");
12670 VD = ME->getMemberDecl();
12671 }
12672 DS.insert(VD);
12673 }
12674 }
12675}
12676
12678 if (!NeedToPush)
12679 return;
12680 CGM.getOpenMPRuntime().NontemporalDeclsStack.pop_back();
12681}
12682
12684 CodeGenFunction &CGF,
12685 const llvm::MapVector<CanonicalDeclPtr<const VarDecl>,
12686 std::pair<Address, Address>> &LocalVars)
12687 : CGM(CGF.CGM), NeedToPush(!LocalVars.empty()) {
12688 if (!NeedToPush)
12689 return;
12690 CGM.getOpenMPRuntime().FunctionToUntiedTaskStackMap.try_emplace(
12691 CGF.CurFn, CGM.getOpenMPRuntime().UntiedLocalVarsStack.size());
12692 CGM.getOpenMPRuntime().UntiedLocalVarsStack.push_back(LocalVars);
12693}
12694
12696 if (!NeedToPush)
12697 return;
12698 CGM.getOpenMPRuntime().UntiedLocalVarsStack.pop_back();
12699}
12700
12702 assert(CGM.getLangOpts().OpenMP && "Not in OpenMP mode.");
12703
12704 return llvm::any_of(
12705 CGM.getOpenMPRuntime().NontemporalDeclsStack,
12706 [VD](const NontemporalDeclsSet &Set) { return Set.contains(VD); });
12707}
12708
12709void CGOpenMPRuntime::LastprivateConditionalRAII::tryToDisableInnerAnalysis(
12710 const OMPExecutableDirective &S,
12711 llvm::DenseSet<CanonicalDeclPtr<const Decl>> &NeedToAddForLPCsAsDisabled)
12712 const {
12713 llvm::DenseSet<CanonicalDeclPtr<const Decl>> NeedToCheckForLPCs;
12714 // Vars in target/task regions must be excluded completely.
12715 if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()) ||
12716 isOpenMPTaskingDirective(S.getDirectiveKind())) {
12718 getOpenMPCaptureRegions(CaptureRegions, S.getDirectiveKind());
12719 const CapturedStmt *CS = S.getCapturedStmt(CaptureRegions.front());
12720 for (const CapturedStmt::Capture &Cap : CS->captures()) {
12721 if (Cap.capturesVariable() || Cap.capturesVariableByCopy())
12722 NeedToCheckForLPCs.insert(Cap.getCapturedVar());
12723 }
12724 }
12725 // Exclude vars in private clauses.
12726 for (const auto *C : S.getClausesOfKind<OMPPrivateClause>()) {
12727 for (const Expr *Ref : C->varlist()) {
12728 if (!Ref->getType()->isScalarType())
12729 continue;
12730 const auto *DRE = dyn_cast<DeclRefExpr>(Ref->IgnoreParenImpCasts());
12731 if (!DRE)
12732 continue;
12733 NeedToCheckForLPCs.insert(DRE->getDecl());
12734 }
12735 }
12736 for (const auto *C : S.getClausesOfKind<OMPFirstprivateClause>()) {
12737 for (const Expr *Ref : C->varlist()) {
12738 if (!Ref->getType()->isScalarType())
12739 continue;
12740 const auto *DRE = dyn_cast<DeclRefExpr>(Ref->IgnoreParenImpCasts());
12741 if (!DRE)
12742 continue;
12743 NeedToCheckForLPCs.insert(DRE->getDecl());
12744 }
12745 }
12746 for (const auto *C : S.getClausesOfKind<OMPLastprivateClause>()) {
12747 for (const Expr *Ref : C->varlist()) {
12748 if (!Ref->getType()->isScalarType())
12749 continue;
12750 const auto *DRE = dyn_cast<DeclRefExpr>(Ref->IgnoreParenImpCasts());
12751 if (!DRE)
12752 continue;
12753 NeedToCheckForLPCs.insert(DRE->getDecl());
12754 }
12755 }
12756 for (const auto *C : S.getClausesOfKind<OMPReductionClause>()) {
12757 for (const Expr *Ref : C->varlist()) {
12758 if (!Ref->getType()->isScalarType())
12759 continue;
12760 const auto *DRE = dyn_cast<DeclRefExpr>(Ref->IgnoreParenImpCasts());
12761 if (!DRE)
12762 continue;
12763 NeedToCheckForLPCs.insert(DRE->getDecl());
12764 }
12765 }
12766 for (const auto *C : S.getClausesOfKind<OMPLinearClause>()) {
12767 for (const Expr *Ref : C->varlist()) {
12768 if (!Ref->getType()->isScalarType())
12769 continue;
12770 const auto *DRE = dyn_cast<DeclRefExpr>(Ref->IgnoreParenImpCasts());
12771 if (!DRE)
12772 continue;
12773 NeedToCheckForLPCs.insert(DRE->getDecl());
12774 }
12775 }
12776 for (const Decl *VD : NeedToCheckForLPCs) {
12777 for (const LastprivateConditionalData &Data :
12778 llvm::reverse(CGM.getOpenMPRuntime().LastprivateConditionalStack)) {
12779 if (Data.DeclToUniqueName.count(VD) > 0) {
12780 if (!Data.Disabled)
12781 NeedToAddForLPCsAsDisabled.insert(VD);
12782 break;
12783 }
12784 }
12785 }
12786}
12787
12788CGOpenMPRuntime::LastprivateConditionalRAII::LastprivateConditionalRAII(
12789 CodeGenFunction &CGF, const OMPExecutableDirective &S, LValue IVLVal)
12790 : CGM(CGF.CGM),
12791 Action((CGM.getLangOpts().OpenMP >= 50 &&
12792 llvm::any_of(S.getClausesOfKind<OMPLastprivateClause>(),
12793 [](const OMPLastprivateClause *C) {
12794 return C->getKind() ==
12795 OMPC_LASTPRIVATE_conditional;
12796 }))
12797 ? ActionToDo::PushAsLastprivateConditional
12798 : ActionToDo::DoNotPush) {
12799 assert(CGM.getLangOpts().OpenMP && "Not in OpenMP mode.");
12800 if (CGM.getLangOpts().OpenMP < 50 || Action == ActionToDo::DoNotPush)
12801 return;
12802 assert(Action == ActionToDo::PushAsLastprivateConditional &&
12803 "Expected a push action.");
12805 CGM.getOpenMPRuntime().LastprivateConditionalStack.emplace_back();
12806 for (const auto *C : S.getClausesOfKind<OMPLastprivateClause>()) {
12807 if (C->getKind() != OMPC_LASTPRIVATE_conditional)
12808 continue;
12809
12810 for (const Expr *Ref : C->varlist()) {
12811 Data.DeclToUniqueName.insert(std::make_pair(
12812 cast<DeclRefExpr>(Ref->IgnoreParenImpCasts())->getDecl(),
12813 SmallString<16>(generateUniqueName(CGM, "pl_cond", Ref))));
12814 }
12815 }
12816 Data.IVLVal = IVLVal;
12817 Data.Fn = CGF.CurFn;
12818}
12819
12820CGOpenMPRuntime::LastprivateConditionalRAII::LastprivateConditionalRAII(
12822 : CGM(CGF.CGM), Action(ActionToDo::DoNotPush) {
12823 assert(CGM.getLangOpts().OpenMP && "Not in OpenMP mode.");
12824 if (CGM.getLangOpts().OpenMP < 50)
12825 return;
12826 llvm::DenseSet<CanonicalDeclPtr<const Decl>> NeedToAddForLPCsAsDisabled;
12827 tryToDisableInnerAnalysis(S, NeedToAddForLPCsAsDisabled);
12828 if (!NeedToAddForLPCsAsDisabled.empty()) {
12829 Action = ActionToDo::DisableLastprivateConditional;
12830 LastprivateConditionalData &Data =
12832 for (const Decl *VD : NeedToAddForLPCsAsDisabled)
12833 Data.DeclToUniqueName.try_emplace(VD);
12834 Data.Fn = CGF.CurFn;
12835 Data.Disabled = true;
12836 }
12837}
12838
12839CGOpenMPRuntime::LastprivateConditionalRAII
12841 CodeGenFunction &CGF, const OMPExecutableDirective &S) {
12842 return LastprivateConditionalRAII(CGF, S);
12843}
12844
12846 if (CGM.getLangOpts().OpenMP < 50)
12847 return;
12848 if (Action == ActionToDo::DisableLastprivateConditional) {
12849 assert(CGM.getOpenMPRuntime().LastprivateConditionalStack.back().Disabled &&
12850 "Expected list of disabled private vars.");
12851 CGM.getOpenMPRuntime().LastprivateConditionalStack.pop_back();
12852 }
12853 if (Action == ActionToDo::PushAsLastprivateConditional) {
12854 assert(
12855 !CGM.getOpenMPRuntime().LastprivateConditionalStack.back().Disabled &&
12856 "Expected list of lastprivate conditional vars.");
12857 CGM.getOpenMPRuntime().LastprivateConditionalStack.pop_back();
12858 }
12859}
12860
12862 const VarDecl *VD) {
12863 ASTContext &C = CGM.getContext();
12864 auto I = LastprivateConditionalToTypes.try_emplace(CGF.CurFn).first;
12865 QualType NewType;
12866 const FieldDecl *VDField;
12867 const FieldDecl *FiredField;
12868 LValue BaseLVal;
12869 auto VI = I->getSecond().find(VD);
12870 if (VI == I->getSecond().end()) {
12871 RecordDecl *RD = C.buildImplicitRecord("lasprivate.conditional");
12872 RD->startDefinition();
12873 VDField = addFieldToRecordDecl(C, RD, VD->getType().getNonReferenceType());
12874 FiredField = addFieldToRecordDecl(C, RD, C.CharTy);
12875 RD->completeDefinition();
12876 NewType = C.getCanonicalTagType(RD);
12877 Address Addr = CGF.CreateMemTemp(NewType, C.getDeclAlign(VD), VD->getName());
12878 BaseLVal = CGF.MakeAddrLValue(Addr, NewType, AlignmentSource::Decl);
12879 I->getSecond().try_emplace(VD, NewType, VDField, FiredField, BaseLVal);
12880 } else {
12881 NewType = std::get<0>(VI->getSecond());
12882 VDField = std::get<1>(VI->getSecond());
12883 FiredField = std::get<2>(VI->getSecond());
12884 BaseLVal = std::get<3>(VI->getSecond());
12885 }
12886 LValue FiredLVal =
12887 CGF.EmitLValueForField(BaseLVal, FiredField);
12889 llvm::ConstantInt::getNullValue(CGF.ConvertTypeForMem(C.CharTy)),
12890 FiredLVal);
12891 return CGF.EmitLValueForField(BaseLVal, VDField).getAddress();
12892}
12893
12894namespace {
12895/// Checks if the lastprivate conditional variable is referenced in LHS.
12896class LastprivateConditionalRefChecker final
12897 : public ConstStmtVisitor<LastprivateConditionalRefChecker, bool> {
12899 const Expr *FoundE = nullptr;
12900 const Decl *FoundD = nullptr;
12901 StringRef UniqueDeclName;
12902 LValue IVLVal;
12903 llvm::Function *FoundFn = nullptr;
12904 SourceLocation Loc;
12905
12906public:
12907 bool VisitDeclRefExpr(const DeclRefExpr *E) {
12909 llvm::reverse(LPM)) {
12910 auto It = D.DeclToUniqueName.find(E->getDecl());
12911 if (It == D.DeclToUniqueName.end())
12912 continue;
12913 if (D.Disabled)
12914 return false;
12915 FoundE = E;
12916 FoundD = E->getDecl()->getCanonicalDecl();
12917 UniqueDeclName = It->second;
12918 IVLVal = D.IVLVal;
12919 FoundFn = D.Fn;
12920 break;
12921 }
12922 return FoundE == E;
12923 }
12924 bool VisitMemberExpr(const MemberExpr *E) {
12926 return false;
12928 llvm::reverse(LPM)) {
12929 auto It = D.DeclToUniqueName.find(E->getMemberDecl());
12930 if (It == D.DeclToUniqueName.end())
12931 continue;
12932 if (D.Disabled)
12933 return false;
12934 FoundE = E;
12935 FoundD = E->getMemberDecl()->getCanonicalDecl();
12936 UniqueDeclName = It->second;
12937 IVLVal = D.IVLVal;
12938 FoundFn = D.Fn;
12939 break;
12940 }
12941 return FoundE == E;
12942 }
12943 bool VisitStmt(const Stmt *S) {
12944 for (const Stmt *Child : S->children()) {
12945 if (!Child)
12946 continue;
12947 if (const auto *E = dyn_cast<Expr>(Child))
12948 if (!E->isGLValue())
12949 continue;
12950 if (Visit(Child))
12951 return true;
12952 }
12953 return false;
12954 }
12955 explicit LastprivateConditionalRefChecker(
12956 ArrayRef<CGOpenMPRuntime::LastprivateConditionalData> LPM)
12957 : LPM(LPM) {}
12958 std::tuple<const Expr *, const Decl *, StringRef, LValue, llvm::Function *>
12959 getFoundData() const {
12960 return std::make_tuple(FoundE, FoundD, UniqueDeclName, IVLVal, FoundFn);
12961 }
12962};
12963} // namespace
12964
12966 LValue IVLVal,
12967 StringRef UniqueDeclName,
12968 LValue LVal,
12969 SourceLocation Loc) {
12970 // Last updated loop counter for the lastprivate conditional var.
12971 // int<xx> last_iv = 0;
12972 llvm::Type *LLIVTy = CGF.ConvertTypeForMem(IVLVal.getType());
12973 llvm::Constant *LastIV = OMPBuilder.getOrCreateInternalVariable(
12974 LLIVTy, getName({UniqueDeclName, "iv"}));
12975 cast<llvm::GlobalVariable>(LastIV)->setAlignment(
12976 IVLVal.getAlignment().getAsAlign());
12977 LValue LastIVLVal =
12978 CGF.MakeNaturalAlignRawAddrLValue(LastIV, IVLVal.getType());
12979
12980 // Last value of the lastprivate conditional.
12981 // decltype(priv_a) last_a;
12982 llvm::GlobalVariable *Last = OMPBuilder.getOrCreateInternalVariable(
12983 CGF.ConvertTypeForMem(LVal.getType()), UniqueDeclName);
12984 cast<llvm::GlobalVariable>(Last)->setAlignment(
12985 LVal.getAlignment().getAsAlign());
12986 LValue LastLVal =
12987 CGF.MakeRawAddrLValue(Last, LVal.getType(), LVal.getAlignment());
12988
12989 // Global loop counter. Required to handle inner parallel-for regions.
12990 // iv
12991 llvm::Value *IVVal = CGF.EmitLoadOfScalar(IVLVal, Loc);
12992
12993 // #pragma omp critical(a)
12994 // if (last_iv <= iv) {
12995 // last_iv = iv;
12996 // last_a = priv_a;
12997 // }
12998 auto &&CodeGen = [&LastIVLVal, &IVLVal, IVVal, &LVal, &LastLVal,
12999 Loc](CodeGenFunction &CGF, PrePostActionTy &Action) {
13000 Action.Enter(CGF);
13001 llvm::Value *LastIVVal = CGF.EmitLoadOfScalar(LastIVLVal, Loc);
13002 // (last_iv <= iv) ? Check if the variable is updated and store new
13003 // value in global var.
13004 llvm::Value *CmpRes;
13005 if (IVLVal.getType()->isSignedIntegerType()) {
13006 CmpRes = CGF.Builder.CreateICmpSLE(LastIVVal, IVVal);
13007 } else {
13008 assert(IVLVal.getType()->isUnsignedIntegerType() &&
13009 "Loop iteration variable must be integer.");
13010 CmpRes = CGF.Builder.CreateICmpULE(LastIVVal, IVVal);
13011 }
13012 llvm::BasicBlock *ThenBB = CGF.createBasicBlock("lp_cond_then");
13013 llvm::BasicBlock *ExitBB = CGF.createBasicBlock("lp_cond_exit");
13014 CGF.Builder.CreateCondBr(CmpRes, ThenBB, ExitBB);
13015 // {
13016 CGF.EmitBlock(ThenBB);
13017
13018 // last_iv = iv;
13019 CGF.EmitStoreOfScalar(IVVal, LastIVLVal);
13020
13021 // last_a = priv_a;
13022 switch (CGF.getEvaluationKind(LVal.getType())) {
13023 case TEK_Scalar: {
13024 llvm::Value *PrivVal = CGF.EmitLoadOfScalar(LVal, Loc);
13025 CGF.EmitStoreOfScalar(PrivVal, LastLVal);
13026 break;
13027 }
13028 case TEK_Complex: {
13029 CodeGenFunction::ComplexPairTy PrivVal = CGF.EmitLoadOfComplex(LVal, Loc);
13030 CGF.EmitStoreOfComplex(PrivVal, LastLVal, /*isInit=*/false);
13031 break;
13032 }
13033 case TEK_Aggregate:
13034 llvm_unreachable(
13035 "Aggregates are not supported in lastprivate conditional.");
13036 }
13037 // }
13038 CGF.EmitBranch(ExitBB);
13039 // There is no need to emit line number for unconditional branch.
13041 CGF.EmitBlock(ExitBB, /*IsFinished=*/true);
13042 };
13043
13044 if (CGM.getLangOpts().OpenMPSimd) {
13045 // Do not emit as a critical region as no parallel region could be emitted.
13046 RegionCodeGenTy ThenRCG(CodeGen);
13047 ThenRCG(CGF);
13048 } else {
13049 emitCriticalRegion(CGF, UniqueDeclName, CodeGen, Loc);
13050 }
13051}
13052
13054 const Expr *LHS) {
13055 if (CGF.getLangOpts().OpenMP < 50 || LastprivateConditionalStack.empty())
13056 return;
13057 LastprivateConditionalRefChecker Checker(LastprivateConditionalStack);
13058 if (!Checker.Visit(LHS))
13059 return;
13060 const Expr *FoundE;
13061 const Decl *FoundD;
13062 StringRef UniqueDeclName;
13063 LValue IVLVal;
13064 llvm::Function *FoundFn;
13065 std::tie(FoundE, FoundD, UniqueDeclName, IVLVal, FoundFn) =
13066 Checker.getFoundData();
13067 if (FoundFn != CGF.CurFn) {
13068 // Special codegen for inner parallel regions.
13069 // ((struct.lastprivate.conditional*)&priv_a)->Fired = 1;
13070 auto It = LastprivateConditionalToTypes[FoundFn].find(FoundD);
13071 assert(It != LastprivateConditionalToTypes[FoundFn].end() &&
13072 "Lastprivate conditional is not found in outer region.");
13073 QualType StructTy = std::get<0>(It->getSecond());
13074 const FieldDecl* FiredDecl = std::get<2>(It->getSecond());
13075 LValue PrivLVal = CGF.EmitLValue(FoundE);
13077 PrivLVal.getAddress(),
13078 CGF.ConvertTypeForMem(CGF.getContext().getPointerType(StructTy)),
13079 CGF.ConvertTypeForMem(StructTy));
13080 LValue BaseLVal =
13081 CGF.MakeAddrLValue(StructAddr, StructTy, AlignmentSource::Decl);
13082 LValue FiredLVal = CGF.EmitLValueForField(BaseLVal, FiredDecl);
13083 CGF.EmitAtomicStore(RValue::get(llvm::ConstantInt::get(
13084 CGF.ConvertTypeForMem(FiredDecl->getType()), 1)),
13085 FiredLVal, llvm::AtomicOrdering::Unordered,
13086 /*IsVolatile=*/true, /*isInit=*/false);
13087 return;
13088 }
13089
13090 // Private address of the lastprivate conditional in the current context.
13091 // priv_a
13092 LValue LVal = CGF.EmitLValue(FoundE);
13093 emitLastprivateConditionalUpdate(CGF, IVLVal, UniqueDeclName, LVal,
13094 FoundE->getExprLoc());
13095}
13096
13099 const llvm::DenseSet<CanonicalDeclPtr<const VarDecl>> &IgnoredDecls) {
13100 if (CGF.getLangOpts().OpenMP < 50 || LastprivateConditionalStack.empty())
13101 return;
13102 auto Range = llvm::reverse(LastprivateConditionalStack);
13103 auto It = llvm::find_if(
13104 Range, [](const LastprivateConditionalData &D) { return !D.Disabled; });
13105 if (It == Range.end() || It->Fn != CGF.CurFn)
13106 return;
13107 auto LPCI = LastprivateConditionalToTypes.find(It->Fn);
13108 assert(LPCI != LastprivateConditionalToTypes.end() &&
13109 "Lastprivates must be registered already.");
13111 getOpenMPCaptureRegions(CaptureRegions, D.getDirectiveKind());
13112 const CapturedStmt *CS = D.getCapturedStmt(CaptureRegions.back());
13113 for (const auto &Pair : It->DeclToUniqueName) {
13114 const auto *VD = cast<VarDecl>(Pair.first->getCanonicalDecl());
13115 if (!CS->capturesVariable(VD) || IgnoredDecls.contains(VD))
13116 continue;
13117 auto I = LPCI->getSecond().find(Pair.first);
13118 assert(I != LPCI->getSecond().end() &&
13119 "Lastprivate must be rehistered already.");
13120 // bool Cmp = priv_a.Fired != 0;
13121 LValue BaseLVal = std::get<3>(I->getSecond());
13122 LValue FiredLVal =
13123 CGF.EmitLValueForField(BaseLVal, std::get<2>(I->getSecond()));
13124 llvm::Value *Res = CGF.EmitLoadOfScalar(FiredLVal, D.getBeginLoc());
13125 llvm::Value *Cmp = CGF.Builder.CreateIsNotNull(Res);
13126 llvm::BasicBlock *ThenBB = CGF.createBasicBlock("lpc.then");
13127 llvm::BasicBlock *DoneBB = CGF.createBasicBlock("lpc.done");
13128 // if (Cmp) {
13129 CGF.Builder.CreateCondBr(Cmp, ThenBB, DoneBB);
13130 CGF.EmitBlock(ThenBB);
13131 Address Addr = CGF.GetAddrOfLocalVar(VD);
13132 LValue LVal;
13133 if (VD->getType()->isReferenceType())
13134 LVal = CGF.EmitLoadOfReferenceLValue(Addr, VD->getType(),
13136 else
13137 LVal = CGF.MakeAddrLValue(Addr, VD->getType().getNonReferenceType(),
13139 emitLastprivateConditionalUpdate(CGF, It->IVLVal, Pair.second, LVal,
13140 D.getBeginLoc());
13142 CGF.EmitBlock(DoneBB, /*IsFinal=*/true);
13143 // }
13144 }
13145}
13146
13148 CodeGenFunction &CGF, LValue PrivLVal, const VarDecl *VD,
13149 SourceLocation Loc) {
13150 if (CGF.getLangOpts().OpenMP < 50)
13151 return;
13152 auto It = LastprivateConditionalStack.back().DeclToUniqueName.find(VD);
13153 assert(It != LastprivateConditionalStack.back().DeclToUniqueName.end() &&
13154 "Unknown lastprivate conditional variable.");
13155 StringRef UniqueName = It->second;
13156 llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(UniqueName);
13157 // The variable was not updated in the region - exit.
13158 if (!GV)
13159 return;
13160 LValue LPLVal = CGF.MakeRawAddrLValue(
13161 GV, PrivLVal.getType().getNonReferenceType(), PrivLVal.getAlignment());
13162 llvm::Value *Res = CGF.EmitLoadOfScalar(LPLVal, Loc);
13163 CGF.EmitStoreOfScalar(Res, PrivLVal);
13164}
13165
13168 const VarDecl *ThreadIDVar, OpenMPDirectiveKind InnermostKind,
13169 const RegionCodeGenTy &CodeGen) {
13170 llvm_unreachable("Not supported in SIMD-only mode");
13171}
13172
13175 const VarDecl *ThreadIDVar, OpenMPDirectiveKind InnermostKind,
13176 const RegionCodeGenTy &CodeGen) {
13177 llvm_unreachable("Not supported in SIMD-only mode");
13178}
13179
13181 const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
13182 const VarDecl *PartIDVar, const VarDecl *TaskTVar,
13183 OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen,
13184 bool Tied, unsigned &NumberOfParts) {
13185 llvm_unreachable("Not supported in SIMD-only mode");
13186}
13187
13189 CodeGenFunction &CGF, SourceLocation Loc, llvm::Function *OutlinedFn,
13190 ArrayRef<llvm::Value *> CapturedVars, const Expr *IfCond,
13191 llvm::Value *NumThreads, OpenMPNumThreadsClauseModifier NumThreadsModifier,
13192 OpenMPSeverityClauseKind Severity, const Expr *Message) {
13193 llvm_unreachable("Not supported in SIMD-only mode");
13194}
13195
13197 CodeGenFunction &CGF, StringRef CriticalName,
13198 const RegionCodeGenTy &CriticalOpGen, SourceLocation Loc,
13199 const Expr *Hint) {
13200 llvm_unreachable("Not supported in SIMD-only mode");
13201}
13202
13204 const RegionCodeGenTy &MasterOpGen,
13205 SourceLocation Loc) {
13206 llvm_unreachable("Not supported in SIMD-only mode");
13207}
13208
13210 const RegionCodeGenTy &MasterOpGen,
13211 SourceLocation Loc,
13212 const Expr *Filter) {
13213 llvm_unreachable("Not supported in SIMD-only mode");
13214}
13215
13217 SourceLocation Loc) {
13218 llvm_unreachable("Not supported in SIMD-only mode");
13219}
13220
13222 CodeGenFunction &CGF, const RegionCodeGenTy &TaskgroupOpGen,
13223 SourceLocation Loc) {
13224 llvm_unreachable("Not supported in SIMD-only mode");
13225}
13226
13228 CodeGenFunction &CGF, const RegionCodeGenTy &SingleOpGen,
13229 SourceLocation Loc, ArrayRef<const Expr *> CopyprivateVars,
13231 ArrayRef<const Expr *> AssignmentOps) {
13232 llvm_unreachable("Not supported in SIMD-only mode");
13233}
13234
13236 const RegionCodeGenTy &OrderedOpGen,
13237 SourceLocation Loc,
13238 bool IsThreads) {
13239 llvm_unreachable("Not supported in SIMD-only mode");
13240}
13241
13243 SourceLocation Loc,
13245 bool EmitChecks,
13246 bool ForceSimpleCall) {
13247 llvm_unreachable("Not supported in SIMD-only mode");
13248}
13249
13252 const OpenMPScheduleTy &ScheduleKind, unsigned IVSize, bool IVSigned,
13253 bool Ordered, const DispatchRTInput &DispatchValues) {
13254 llvm_unreachable("Not supported in SIMD-only mode");
13255}
13256
13258 SourceLocation Loc) {
13259 llvm_unreachable("Not supported in SIMD-only mode");
13260}
13261
13264 const OpenMPScheduleTy &ScheduleKind, const StaticRTInput &Values) {
13265 llvm_unreachable("Not supported in SIMD-only mode");
13266}
13267
13270 OpenMPDistScheduleClauseKind SchedKind, const StaticRTInput &Values) {
13271 llvm_unreachable("Not supported in SIMD-only mode");
13272}
13273
13275 SourceLocation Loc,
13276 unsigned IVSize,
13277 bool IVSigned) {
13278 llvm_unreachable("Not supported in SIMD-only mode");
13279}
13280
13282 SourceLocation Loc,
13283 OpenMPDirectiveKind DKind) {
13284 llvm_unreachable("Not supported in SIMD-only mode");
13285}
13286
13288 SourceLocation Loc,
13289 unsigned IVSize, bool IVSigned,
13290 Address IL, Address LB,
13291 Address UB, Address ST) {
13292 llvm_unreachable("Not supported in SIMD-only mode");
13293}
13294
13296 CodeGenFunction &CGF, llvm::Value *NumThreads, SourceLocation Loc,
13298 SourceLocation SeverityLoc, const Expr *Message,
13299 SourceLocation MessageLoc) {
13300 llvm_unreachable("Not supported in SIMD-only mode");
13301}
13302
13304 ProcBindKind ProcBind,
13305 SourceLocation Loc) {
13306 llvm_unreachable("Not supported in SIMD-only mode");
13307}
13308
13310 const VarDecl *VD,
13311 Address VDAddr,
13312 SourceLocation Loc) {
13313 llvm_unreachable("Not supported in SIMD-only mode");
13314}
13315
13317 const VarDecl *VD, Address VDAddr, SourceLocation Loc, bool PerformInit,
13318 CodeGenFunction *CGF) {
13319 llvm_unreachable("Not supported in SIMD-only mode");
13320}
13321
13323 CodeGenFunction &CGF, QualType VarType, StringRef Name) {
13324 llvm_unreachable("Not supported in SIMD-only mode");
13325}
13326
13329 SourceLocation Loc,
13330 llvm::AtomicOrdering AO) {
13331 llvm_unreachable("Not supported in SIMD-only mode");
13332}
13333
13335 const OMPExecutableDirective &D,
13336 llvm::Function *TaskFunction,
13337 QualType SharedsTy, Address Shareds,
13338 const Expr *IfCond,
13339 const OMPTaskDataTy &Data) {
13340 llvm_unreachable("Not supported in SIMD-only mode");
13341}
13342
13345 llvm::Function *TaskFunction, QualType SharedsTy, Address Shareds,
13346 const Expr *IfCond, const OMPTaskDataTy &Data) {
13347 llvm_unreachable("Not supported in SIMD-only mode");
13348}
13349
13353 ArrayRef<const Expr *> ReductionOps, ReductionOptionsTy Options) {
13354 assert(Options.SimpleReduction && "Only simple reduction is expected.");
13355 CGOpenMPRuntime::emitReduction(CGF, Loc, Privates, LHSExprs, RHSExprs,
13356 ReductionOps, Options);
13357}
13358
13361 ArrayRef<const Expr *> RHSExprs, const OMPTaskDataTy &Data) {
13362 llvm_unreachable("Not supported in SIMD-only mode");
13363}
13364
13366 SourceLocation Loc,
13367 bool IsWorksharingReduction) {
13368 llvm_unreachable("Not supported in SIMD-only mode");
13369}
13370
13372 SourceLocation Loc,
13373 ReductionCodeGen &RCG,
13374 unsigned N) {
13375 llvm_unreachable("Not supported in SIMD-only mode");
13376}
13377
13379 SourceLocation Loc,
13380 llvm::Value *ReductionsPtr,
13381 LValue SharedLVal) {
13382 llvm_unreachable("Not supported in SIMD-only mode");
13383}
13384
13386 SourceLocation Loc,
13387 const OMPTaskDataTy &Data) {
13388 llvm_unreachable("Not supported in SIMD-only mode");
13389}
13390
13393 OpenMPDirectiveKind CancelRegion) {
13394 llvm_unreachable("Not supported in SIMD-only mode");
13395}
13396
13398 SourceLocation Loc, const Expr *IfCond,
13399 OpenMPDirectiveKind CancelRegion) {
13400 llvm_unreachable("Not supported in SIMD-only mode");
13401}
13402
13404 const OMPExecutableDirective &D, StringRef ParentName,
13405 llvm::Function *&OutlinedFn, llvm::Constant *&OutlinedFnID,
13406 bool IsOffloadEntry, const RegionCodeGenTy &CodeGen) {
13407 llvm_unreachable("Not supported in SIMD-only mode");
13408}
13409
13412 llvm::Function *OutlinedFn, llvm::Value *OutlinedFnID, const Expr *IfCond,
13413 llvm::PointerIntPair<const Expr *, 2, OpenMPDeviceClauseModifier> Device,
13414 llvm::function_ref<llvm::Value *(CodeGenFunction &CGF,
13415 const OMPLoopDirective &D)>
13416 SizeEmitter) {
13417 llvm_unreachable("Not supported in SIMD-only mode");
13418}
13419
13421 llvm_unreachable("Not supported in SIMD-only mode");
13422}
13423
13425 llvm_unreachable("Not supported in SIMD-only mode");
13426}
13427
13429 return false;
13430}
13431
13433 const OMPExecutableDirective &D,
13434 SourceLocation Loc,
13435 llvm::Function *OutlinedFn,
13436 ArrayRef<llvm::Value *> CapturedVars) {
13437 llvm_unreachable("Not supported in SIMD-only mode");
13438}
13439
13441 const Expr *NumTeams,
13442 const Expr *ThreadLimit,
13443 SourceLocation Loc) {
13444 llvm_unreachable("Not supported in SIMD-only mode");
13445}
13446
13448 CodeGenFunction &CGF, const OMPExecutableDirective &D, const Expr *IfCond,
13449 const Expr *Device, const RegionCodeGenTy &CodeGen,
13451 llvm_unreachable("Not supported in SIMD-only mode");
13452}
13453
13455 CodeGenFunction &CGF, const OMPExecutableDirective &D, const Expr *IfCond,
13456 const Expr *Device) {
13457 llvm_unreachable("Not supported in SIMD-only mode");
13458}
13459
13461 const OMPLoopDirective &D,
13462 ArrayRef<Expr *> NumIterations) {
13463 llvm_unreachable("Not supported in SIMD-only mode");
13464}
13465
13467 const OMPDependClause *C) {
13468 llvm_unreachable("Not supported in SIMD-only mode");
13469}
13470
13472 const OMPDoacrossClause *C) {
13473 llvm_unreachable("Not supported in SIMD-only mode");
13474}
13475
13476const VarDecl *
13478 const VarDecl *NativeParam) const {
13479 llvm_unreachable("Not supported in SIMD-only mode");
13480}
13481
13482Address
13484 const VarDecl *NativeParam,
13485 const VarDecl *TargetParam) const {
13486 llvm_unreachable("Not supported in SIMD-only mode");
13487}
#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 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 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:223
SourceManager & getSourceManager()
Definition ASTContext.h:869
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
Definition ASTContext.h:965
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:5406
Represents an array type, per C99 6.7.5.2 - Array Declarators.
Definition TypeBase.h:3833
Attr - This represents one attribute.
Definition Attr.h:46
Represents a base class of a C++ class.
Definition DeclCXX.h:146
Represents a C++ constructor within a class.
Definition DeclCXX.h:2633
Represents a C++ destructor within a class.
Definition DeclCXX.h:2898
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Definition DeclCXX.h:2284
QualType getFunctionObjectParameterType() const
Definition DeclCXX.h:2308
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
base_class_range bases()
Definition DeclCXX.h:608
bool isLambda() const
Determine whether this class describes a lambda function object.
Definition DeclCXX.h:1023
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:602
base_class_range vbases()
Definition DeclCXX.h:625
capture_const_range captures() const
Definition DeclCXX.h:1102
ctor_range ctors() const
Definition DeclCXX.h:670
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:3959
bool capturesVariableByCopy() const
Determine whether this capture handles a variable by copy.
Definition Stmt.h:3993
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:3999
bool capturesThis() const
Determine whether this capture handles the C++ 'this' pointer.
Definition Stmt.h:3987
bool capturesVariable() const
Determine whether this capture handles a variable (by reference).
Definition Stmt.h:3990
This captures a statement into a function.
Definition Stmt.h:3946
const Capture * const_capture_iterator
Definition Stmt.h:4080
capture_iterator capture_end() const
Retrieve an iterator pointing past the end of the sequence of captures.
Definition Stmt.h:4097
const RecordDecl * getCapturedRecordDecl() const
Retrieve the record declaration for captured variables.
Definition Stmt.h:4067
Stmt * getCapturedStmt()
Retrieve the statement being captured.
Definition Stmt.h:4050
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:4092
capture_range captures()
Definition Stmt.h:4084
CharUnits - This is an opaque type for sizes expressed in character units.
Definition CharUnits.h:38
bool isZero() const
isZero - Test whether the quantity equals zero.
Definition CharUnits.h:122
llvm::Align getAsAlign() const
getAsAlign - Returns Quantity as a valid llvm::Align, Beware llvm::Align assumes power of two 8-bit b...
Definition CharUnits.h:189
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
Definition CharUnits.h:185
CharUnits alignmentOfArrayElement(CharUnits elementSize) const
Given that this is the alignment of the first element of an array, return the minimum alignment of an...
Definition CharUnits.h:214
static CharUnits fromQuantity(QuantityType Quantity)
fromQuantity - Construct a CharUnits quantity from a raw integer type.
Definition CharUnits.h:63
CharUnits alignTo(const CharUnits &Align) const
alignTo - Returns the next integer (mod 2**64) that is greater than or equal to this quantity and is ...
Definition CharUnits.h:201
std::string SampleProfileFile
Name of the profile file to use with -fprofile-sample-use.
Like RawAddress, an abstract representation of an aligned address, but the pointer contained in this ...
Definition Address.h:128
static Address invalid()
Definition Address.h:176
llvm::Value * emitRawPointer(CodeGenFunction &CGF) const
Return the pointer contained in this class after authenticating it and adding offset to it if necessa...
Definition Address.h:253
CharUnits getAlignment() const
Definition Address.h:194
llvm::Type * getElementType() const
Return the type of the values stored in this address.
Definition Address.h:209
Address 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:146
Address CreateGEP(CodeGenFunction &CGF, Address Addr, llvm::Value *Index, const llvm::Twine &Name="")
Definition CGBuilder.h:302
Address CreatePointerBitCastOrAddrSpaceCast(Address Addr, llvm::Type *Ty, llvm::Type *ElementTy, const llvm::Twine &Name="")
Definition CGBuilder.h:213
Address CreateConstArrayGEP(Address Addr, uint64_t Index, const llvm::Twine &Name="")
Given addr = [n x T]* ... produce name = getelementptr inbounds addr, i64 0, i64 index where i64 is a...
Definition CGBuilder.h:251
llvm::LoadInst * CreateLoad(Address Addr, const llvm::Twine &Name="")
Definition CGBuilder.h:118
llvm::CallInst * CreateMemCpy(Address Dest, Address Src, llvm::Value *Size, bool IsVolatile=false)
Definition CGBuilder.h:397
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:288
Address CreateAddrSpaceCast(Address Addr, llvm::Type *Ty, llvm::Type *ElementTy, const llvm::Twine &Name="")
Definition CGBuilder.h:199
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 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 VarDecl *LocalVD, Address Addr)
Registers LocalVD variable as a private with Addr as the address of the corresponding private variabl...
An RAII object to set (and then clear) a mapping for an OpaqueValueExpr.
Enters a new scope for capturing cleanups, all of which will be executed once the scope is exited.
CodeGenFunction - This class organizes the per-function state that is used while generating LLVM code...
LValue EmitLoadOfReferenceLValue(LValue RefLVal)
Definition CGExpr.cpp:3436
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:2422
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:1490
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:2306
Address EmitLoadOfPointer(Address Ptr, const PointerType *PtrTy, LValueBaseInfo *BaseInfo=nullptr, TBAAAccessInfo *TBAAInfo=nullptr)
Load a pointer with type PtrTy stored at address Ptr.
Definition CGExpr.cpp:3445
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:2279
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:5796
RawAddress CreateDefaultAlignTempAlloca(llvm::Type *Ty, const Twine &Name="tmp")
CreateDefaultAlignedTempAlloca - This creates an alloca with the default ABI alignment of the given L...
Definition CGExpr.cpp:183
void GenerateOpenMPCapturedVars(const CapturedStmt &S, SmallVectorImpl< llvm::Value * > &CapturedVars)
void EmitIgnoredExpr(const Expr *E)
EmitIgnoredExpr - Emit an expression in a context which ignores the result.
Definition CGExpr.cpp:259
RValue EmitLoadOfLValue(LValue V, SourceLocation Loc)
EmitLoadOfLValue - Given an expression that represents a value lvalue, this method emits the address ...
Definition CGExpr.cpp:2542
LValue EmitArraySectionExpr(const ArraySectionExpr *E, bool IsLowerBound=true)
Definition CGExpr.cpp:5305
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:240
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:5970
RawAddress CreateMemTempWithoutCast(QualType T, const Twine &Name="tmp")
CreateMemTemp - Create a temporary memory object of the given type, with appropriate alignmen without...
Definition CGExpr.cpp:232
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:2225
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:2793
LValue EmitLoadOfPointerLValue(Address Ptr, const PointerType *PtrTy)
Definition CGExpr.cpp:3455
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:310
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:1621
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:668
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:196
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:1679
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:5574
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:1737
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:1830
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:648
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:2115
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)
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:2974
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:2046
const CGFunctionInfo & arrangeBuiltinFunctionDeclaration(QualType resultType, const FunctionArgList &args)
A builtin function is a freestanding function using the default C conventions.
Definition CGCall.cpp:775
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:646
FunctionArgList - Type for representing both the decl and type of parameters to a function.
Definition CGCall.h:377
LValue - This represents an lvalue references.
Definition CGValue.h:183
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:1276
ValueDecl * getDecl()
Definition Expr.h:1344
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:831
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
This represents one expression.
Definition Expr.h:112
bool isIntegerConstantExpr(const ASTContext &Ctx) const
bool isGLValue() const
Definition Expr.h:287
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:3128
@ SE_AllowSideEffects
Allow any unmodeled side effect.
Definition Expr.h:681
@ SE_AllowUndefinedBehavior
Allow UB that we can give a value, but not arbitrary unmodeled side effects.
Definition Expr.h:679
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Definition Expr.cpp:3106
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:3101
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...
std::optional< llvm::APSInt > getIntegerConstantExpr(const ASTContext &Ctx) const
isIntegerConstantExpr - Return the value if this expression is a valid integer constant expression.
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:3700
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:4333
QualType getType() const
Definition Expr.h:144
bool hasNonTrivialCall(const ASTContext &Ctx) const
Determine whether this expression involves a call to any function that is not trivial.
Definition Expr.cpp:4069
Represents a member of a struct/union/class.
Definition Decl.h:3204
unsigned getFieldIndex() const
Returns the index of this field within its record, as appropriate for passing to ASTRecordLayout::get...
Definition Decl.h:3289
const RecordDecl * getParent() const
Returns the parent of this field declaration, which is the struct in which this field is defined.
Definition Decl.h:3440
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:4700
Represents a function declaration or definition.
Definition Decl.h:2029
const ParmVarDecl * getParamDecl(unsigned i) const
Definition Decl.h:2837
QualType getReturnType() const
Definition Decl.h:2885
ArrayRef< ParmVarDecl * > parameters() const
Definition Decl.h:2814
FunctionDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
Definition Decl.cpp:3727
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:3806
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:57
const Decl * getDecl() const
Definition GlobalDecl.h:106
static ImplicitParamDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation IdLoc, const IdentifierInfo *Id, QualType T, ImplicitParamKind ParamKind)
Create implicit parameter.
Definition Decl.cpp:5602
static IntegerLiteral * Create(const ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l)
Returns a new integer literal with value 'V' and type 'type'.
Definition Expr.cpp:981
An lvalue reference type, per C++11 [dcl.ref].
Definition TypeBase.h:3728
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition Expr.h:3370
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
Definition Expr.h:3453
Expr * getBase() const
Definition Expr.h:3447
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition Decl.h:301
bool isExternallyVisible() const
Definition Decl.h:433
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:5614
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:1184
Represents a parameter to a function.
Definition Decl.h:1819
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition TypeBase.h:3405
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:8501
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
Definition TypeBase.h:8541
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:8686
QualType getCanonicalType() const
Definition TypeBase.h:8553
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:4369
field_iterator field_end() const
Definition Decl.h:4575
field_range fields() const
Definition Decl.h:4572
virtual void completeDefinition()
Note that the definition of this type is now complete.
Definition Decl.cpp:5291
bool field_empty() const
Definition Decl.h:4580
field_iterator field_begin() const
Definition Decl.cpp:5275
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:1502
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:4906
bool isUnion() const
Definition Decl.h:3972
The base class of the type hierarchy.
Definition TypeBase.h:1876
bool isVoidType() const
Definition TypeBase.h:9110
const Type * getPointeeOrArrayElementType() const
If this is a pointer type, return the pointee type.
Definition TypeBase.h:9297
bool isSignedIntegerType() const
Return true if this is an integer type that is signed, according to C99 6.2.5p4 [char,...
Definition Type.cpp:2270
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:8837
bool isPointerType() const
Definition TypeBase.h:8738
CanQualType getCanonicalTypeUnqualified() const
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
Definition TypeBase.h:9154
const T * castAs() const
Member-template castAs<specific type>.
Definition TypeBase.h:9404
bool isReferenceType() const
Definition TypeBase.h:8762
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:789
bool isLValueReferenceType() const
Definition TypeBase.h:8766
bool isAggregateType() const
Determines whether the type is a C++ aggregate type or C aggregate or union type.
Definition Type.cpp:2507
RecordDecl * castAsRecordDecl() const
Definition Type.h:48
QualType getCanonicalTypeInternal() const
Definition TypeBase.h:3193
const Type * getBaseElementTypeUnsafe() const
Get the base element type of this type, potentially discarding type qualifiers.
Definition TypeBase.h:9290
bool isVariablyModifiedType() const
Whether this type is a variably-modified type (C99 6.7.5).
Definition TypeBase.h:2874
const ArrayType * getAsArrayTypeUnsafe() const
A variant of getAs<> for array types which silently discards qualifiers from the outermost type.
Definition TypeBase.h:9390
bool isFloatingType() const
Definition Type.cpp:2393
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:2336
bool isAnyPointerType() const
Definition TypeBase.h:8746
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9337
bool isRecordType() const
Definition TypeBase.h:8865
bool isUnionType() const
Definition Type.cpp:755
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:712
QualType getType() const
Definition Decl.h:723
Represents a variable declaration or definition.
Definition Decl.h:932
VarDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
Definition Decl.cpp:2238
VarDecl * getDefinition(ASTContext &)
Get the real (not just tentative) definition for this declaration.
Definition Decl.cpp:2347
const Expr * getInit() const
Definition Decl.h:1391
bool hasExternalStorage() const
Returns true if a variable has extern or private_extern storage.
Definition Decl.h:1238
@ DeclarationOnly
This declaration is only a declaration.
Definition Decl.h:1318
DefinitionKind hasDefinition(ASTContext &) const
Check whether this variable is defined in this translation unit.
Definition Decl.cpp:2356
bool isLocalVarDeclOrParm() const
Similar to isLocalVarDecl but also includes parameters.
Definition Decl.h:1285
const Expr * getAnyInitializer() const
Get the initializer for this variable, no matter which declaration it is attached to.
Definition Decl.h:1381
Represents a C array with a specified size that is not an integer-constant-expression.
Definition TypeBase.h:4077
Expr * getSizeExpr() const
Definition TypeBase.h:4091
specific_attr_iterator - Iterates over a subrange of an AttrVec, only providing attributes that are o...
Definition SPIR.cpp:35
bool isEmptyRecordForLayout(const ASTContext &Context, QualType T)
isEmptyRecordForLayout - Return true iff a structure contains only empty base classes (per isEmptyRec...
@ Type
The l-value was considered opaque, so the alignment was determined from a type.
Definition CGValue.h:155
@ Decl
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
Definition CGValue.h:146
bool isEmptyFieldForLayout(const ASTContext &Context, const FieldDecl *FD)
isEmptyFieldForLayout - Return true iff the field is "empty", that is, either a zero-width bit-field ...
ComparisonResult
Indicates the result of a tentative comparison.
@ Address
A pointer to a ValueDecl.
Definition Primitives.h:28
The JSON file list parser is used to communicate input to InstallAPI.
bool isOpenMPWorksharingDirective(OpenMPDirectiveKind DKind)
Checks if the specified directive is a worksharing directive.
CanQual< Type > CanQualType
Represents a canonical, potentially-qualified type.
bool needsTaskBasedThreadLimit(OpenMPDirectiveKind DKind)
Checks if the specified target directive, combined or not, needs task based thread_limit.
@ Match
This is not an overload because the signature exactly matches an existing declaration.
Definition Sema.h:830
@ 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)
@ Conditional
A conditional (?:) operator.
Definition Sema.h:669
@ ICIS_NoInit
No in-class initializer.
Definition Specifiers.h:273
bool isOpenMPDistributeDirective(OpenMPDirectiveKind DKind)
Checks if the specified directive is a distribute directive.
@ LCK_ByRef
Capturing by reference.
Definition Lambda.h:37
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:125
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.
Expr * Cond
};
bool isOpenMPTaskingDirective(OpenMPDirectiveKind Kind)
Checks if the specified directive kind is one of tasking directives - task, taskloop,...
bool isOpenMPTargetExecutionDirective(OpenMPDirectiveKind DKind)
Checks if the specified directive is a target code offload directive.
@ 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:6050
bool isOpenMPTargetMapEnteringDirective(OpenMPDirectiveKind DKind)
Checks if the specified directive is a map-entering target directive.
@ Type
The name was classified as a type.
Definition Sema.h:564
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:136
@ VK_LValue
An l-value expression is a reference to an object with independent storage.
Definition Specifiers.h:140
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:1774
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
__packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 int32_t
__packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 __packed_splat2 __packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 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:652
Extra information about a function prototype.
Definition TypeBase.h:5503
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.