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/VirtualFileSystem.h"
43#include "llvm/Support/raw_ostream.h"
44#include <cassert>
45#include <cstdint>
46#include <numeric>
47#include <optional>
48
49using namespace clang;
50using namespace CodeGen;
51using namespace llvm::omp;
52
53namespace {
54/// Base class for handling code generation inside OpenMP regions.
55class CGOpenMPRegionInfo : public CodeGenFunction::CGCapturedStmtInfo {
56public:
57 /// Kinds of OpenMP regions used in codegen.
58 enum CGOpenMPRegionKind {
59 /// Region with outlined function for standalone 'parallel'
60 /// directive.
61 ParallelOutlinedRegion,
62 /// Region with outlined function for standalone 'task' directive.
63 TaskOutlinedRegion,
64 /// Region for constructs that do not require function outlining,
65 /// like 'for', 'sections', 'atomic' etc. directives.
66 InlinedRegion,
67 /// Region with outlined function for standalone 'target' directive.
68 TargetRegion,
69 };
70
71 CGOpenMPRegionInfo(const CapturedStmt &CS,
72 const CGOpenMPRegionKind RegionKind,
73 const RegionCodeGenTy &CodeGen, OpenMPDirectiveKind Kind,
74 bool HasCancel)
75 : CGCapturedStmtInfo(CS, CR_OpenMP), RegionKind(RegionKind),
76 CodeGen(CodeGen), Kind(Kind), HasCancel(HasCancel) {}
77
78 CGOpenMPRegionInfo(const CGOpenMPRegionKind RegionKind,
79 const RegionCodeGenTy &CodeGen, OpenMPDirectiveKind Kind,
80 bool HasCancel)
81 : CGCapturedStmtInfo(CR_OpenMP), RegionKind(RegionKind), CodeGen(CodeGen),
82 Kind(Kind), HasCancel(HasCancel) {}
83
84 /// Get a variable or parameter for storing global thread id
85 /// inside OpenMP construct.
86 virtual const VarDecl *getThreadIDVariable() const = 0;
87
88 /// Emit the captured statement body.
89 void EmitBody(CodeGenFunction &CGF, const Stmt *S) override;
90
91 /// Get an LValue for the current ThreadID variable.
92 /// \return LValue for thread id variable. This LValue always has type int32*.
93 virtual LValue getThreadIDVariableLValue(CodeGenFunction &CGF);
94
95 virtual void emitUntiedSwitch(CodeGenFunction & /*CGF*/) {}
96
97 CGOpenMPRegionKind getRegionKind() const { return RegionKind; }
98
99 OpenMPDirectiveKind getDirectiveKind() const { return Kind; }
100
101 bool hasCancel() const { return HasCancel; }
102
103 static bool classof(const CGCapturedStmtInfo *Info) {
104 return Info->getKind() == CR_OpenMP;
105 }
106
107 ~CGOpenMPRegionInfo() override = default;
108
109protected:
110 CGOpenMPRegionKind RegionKind;
111 RegionCodeGenTy CodeGen;
113 bool HasCancel;
114};
115
116/// API for captured statement code generation in OpenMP constructs.
117class CGOpenMPOutlinedRegionInfo final : public CGOpenMPRegionInfo {
118public:
119 CGOpenMPOutlinedRegionInfo(const CapturedStmt &CS, const VarDecl *ThreadIDVar,
120 const RegionCodeGenTy &CodeGen,
121 OpenMPDirectiveKind Kind, bool HasCancel,
122 StringRef HelperName)
123 : CGOpenMPRegionInfo(CS, ParallelOutlinedRegion, CodeGen, Kind,
124 HasCancel),
125 ThreadIDVar(ThreadIDVar), HelperName(HelperName) {
126 assert(ThreadIDVar != nullptr && "No ThreadID in OpenMP region.");
127 }
128
129 /// Get a variable or parameter for storing global thread id
130 /// inside OpenMP construct.
131 const VarDecl *getThreadIDVariable() const override { return ThreadIDVar; }
132
133 /// Get the name of the capture helper.
134 StringRef getHelperName() const override { return HelperName; }
135
136 static bool classof(const CGCapturedStmtInfo *Info) {
137 return CGOpenMPRegionInfo::classof(Info) &&
138 cast<CGOpenMPRegionInfo>(Info)->getRegionKind() ==
139 ParallelOutlinedRegion;
140 }
141
142private:
143 /// A variable or parameter storing global thread id for OpenMP
144 /// constructs.
145 const VarDecl *ThreadIDVar;
146 StringRef HelperName;
147};
148
149/// API for captured statement code generation in OpenMP constructs.
150class CGOpenMPTaskOutlinedRegionInfo final : public CGOpenMPRegionInfo {
151public:
152 class UntiedTaskActionTy final : public PrePostActionTy {
153 bool Untied;
154 const VarDecl *PartIDVar;
155 const RegionCodeGenTy UntiedCodeGen;
156 llvm::SwitchInst *UntiedSwitch = nullptr;
157
158 public:
159 UntiedTaskActionTy(bool Tied, const VarDecl *PartIDVar,
160 const RegionCodeGenTy &UntiedCodeGen)
161 : Untied(!Tied), PartIDVar(PartIDVar), UntiedCodeGen(UntiedCodeGen) {}
162 void Enter(CodeGenFunction &CGF) override {
163 if (Untied) {
164 // Emit task switching point.
165 LValue PartIdLVal = CGF.EmitLoadOfPointerLValue(
166 CGF.GetAddrOfLocalVar(PartIDVar),
167 PartIDVar->getType()->castAs<PointerType>());
168 llvm::Value *Res =
169 CGF.EmitLoadOfScalar(PartIdLVal, PartIDVar->getLocation());
170 llvm::BasicBlock *DoneBB = CGF.createBasicBlock(".untied.done.");
171 UntiedSwitch = CGF.Builder.CreateSwitch(Res, DoneBB);
172 CGF.EmitBlock(DoneBB);
174 CGF.EmitBlock(CGF.createBasicBlock(".untied.jmp."));
175 UntiedSwitch->addCase(CGF.Builder.getInt32(0),
176 CGF.Builder.GetInsertBlock());
177 emitUntiedSwitch(CGF);
178 }
179 }
180 void emitUntiedSwitch(CodeGenFunction &CGF) const {
181 if (Untied) {
182 LValue PartIdLVal = CGF.EmitLoadOfPointerLValue(
183 CGF.GetAddrOfLocalVar(PartIDVar),
184 PartIDVar->getType()->castAs<PointerType>());
185 CGF.EmitStoreOfScalar(CGF.Builder.getInt32(UntiedSwitch->getNumCases()),
186 PartIdLVal);
187 UntiedCodeGen(CGF);
188 CodeGenFunction::JumpDest CurPoint =
189 CGF.getJumpDestInCurrentScope(".untied.next.");
191 CGF.EmitBlock(CGF.createBasicBlock(".untied.jmp."));
192 UntiedSwitch->addCase(CGF.Builder.getInt32(UntiedSwitch->getNumCases()),
193 CGF.Builder.GetInsertBlock());
194 CGF.EmitBranchThroughCleanup(CurPoint);
195 CGF.EmitBlock(CurPoint.getBlock());
196 }
197 }
198 unsigned getNumberOfParts() const { return UntiedSwitch->getNumCases(); }
199 };
200 CGOpenMPTaskOutlinedRegionInfo(const CapturedStmt &CS,
201 const VarDecl *ThreadIDVar,
202 const RegionCodeGenTy &CodeGen,
203 OpenMPDirectiveKind Kind, bool HasCancel,
204 const UntiedTaskActionTy &Action)
205 : CGOpenMPRegionInfo(CS, TaskOutlinedRegion, CodeGen, Kind, HasCancel),
206 ThreadIDVar(ThreadIDVar), Action(Action) {
207 assert(ThreadIDVar != nullptr && "No ThreadID in OpenMP region.");
208 }
209
210 /// Get a variable or parameter for storing global thread id
211 /// inside OpenMP construct.
212 const VarDecl *getThreadIDVariable() const override { return ThreadIDVar; }
213
214 /// Get an LValue for the current ThreadID variable.
215 LValue getThreadIDVariableLValue(CodeGenFunction &CGF) override;
216
217 /// Get the name of the capture helper.
218 StringRef getHelperName() const override { return ".omp_outlined."; }
219
220 void emitUntiedSwitch(CodeGenFunction &CGF) override {
221 Action.emitUntiedSwitch(CGF);
222 }
223
224 static bool classof(const CGCapturedStmtInfo *Info) {
225 return CGOpenMPRegionInfo::classof(Info) &&
226 cast<CGOpenMPRegionInfo>(Info)->getRegionKind() ==
227 TaskOutlinedRegion;
228 }
229
230private:
231 /// A variable or parameter storing global thread id for OpenMP
232 /// constructs.
233 const VarDecl *ThreadIDVar;
234 /// Action for emitting code for untied tasks.
235 const UntiedTaskActionTy &Action;
236};
237
238/// API for inlined captured statement code generation in OpenMP
239/// constructs.
240class CGOpenMPInlinedRegionInfo : public CGOpenMPRegionInfo {
241public:
242 CGOpenMPInlinedRegionInfo(CodeGenFunction::CGCapturedStmtInfo *OldCSI,
243 const RegionCodeGenTy &CodeGen,
244 OpenMPDirectiveKind Kind, bool HasCancel)
245 : CGOpenMPRegionInfo(InlinedRegion, CodeGen, Kind, HasCancel),
246 OldCSI(OldCSI),
247 OuterRegionInfo(dyn_cast_or_null<CGOpenMPRegionInfo>(OldCSI)) {}
248
249 // Retrieve the value of the context parameter.
250 llvm::Value *getContextValue() const override {
251 if (OuterRegionInfo)
252 return OuterRegionInfo->getContextValue();
253 llvm_unreachable("No context value for inlined OpenMP region");
254 }
255
256 void setContextValue(llvm::Value *V) override {
257 if (OuterRegionInfo) {
258 OuterRegionInfo->setContextValue(V);
259 return;
260 }
261 llvm_unreachable("No context value for inlined OpenMP region");
262 }
263
264 /// Lookup the captured field decl for a variable.
265 const FieldDecl *lookup(const VarDecl *VD) const override {
266 if (OuterRegionInfo)
267 return OuterRegionInfo->lookup(VD);
268 // If there is no outer outlined region,no need to lookup in a list of
269 // captured variables, we can use the original one.
270 return nullptr;
271 }
272
273 FieldDecl *getThisFieldDecl() const override {
274 if (OuterRegionInfo)
275 return OuterRegionInfo->getThisFieldDecl();
276 return nullptr;
277 }
278
279 /// Get a variable or parameter for storing global thread id
280 /// inside OpenMP construct.
281 const VarDecl *getThreadIDVariable() const override {
282 if (OuterRegionInfo)
283 return OuterRegionInfo->getThreadIDVariable();
284 return nullptr;
285 }
286
287 /// Get an LValue for the current ThreadID variable.
288 LValue getThreadIDVariableLValue(CodeGenFunction &CGF) override {
289 if (OuterRegionInfo)
290 return OuterRegionInfo->getThreadIDVariableLValue(CGF);
291 llvm_unreachable("No LValue for inlined OpenMP construct");
292 }
293
294 /// Get the name of the capture helper.
295 StringRef getHelperName() const override {
296 if (auto *OuterRegionInfo = getOldCSI())
297 return OuterRegionInfo->getHelperName();
298 llvm_unreachable("No helper name for inlined OpenMP construct");
299 }
300
301 void emitUntiedSwitch(CodeGenFunction &CGF) override {
302 if (OuterRegionInfo)
303 OuterRegionInfo->emitUntiedSwitch(CGF);
304 }
305
306 CodeGenFunction::CGCapturedStmtInfo *getOldCSI() const { return OldCSI; }
307
308 static bool classof(const CGCapturedStmtInfo *Info) {
309 return CGOpenMPRegionInfo::classof(Info) &&
310 cast<CGOpenMPRegionInfo>(Info)->getRegionKind() == InlinedRegion;
311 }
312
313 ~CGOpenMPInlinedRegionInfo() override = default;
314
315private:
316 /// CodeGen info about outer OpenMP region.
317 CodeGenFunction::CGCapturedStmtInfo *OldCSI;
318 CGOpenMPRegionInfo *OuterRegionInfo;
319};
320
321/// API for captured statement code generation in OpenMP target
322/// constructs. For this captures, implicit parameters are used instead of the
323/// captured fields. The name of the target region has to be unique in a given
324/// application so it is provided by the client, because only the client has
325/// the information to generate that.
326class CGOpenMPTargetRegionInfo final : public CGOpenMPRegionInfo {
327public:
328 CGOpenMPTargetRegionInfo(const CapturedStmt &CS,
329 const RegionCodeGenTy &CodeGen, StringRef HelperName)
330 : CGOpenMPRegionInfo(CS, TargetRegion, CodeGen, OMPD_target,
331 /*HasCancel=*/false),
332 HelperName(HelperName) {}
333
334 /// This is unused for target regions because each starts executing
335 /// with a single thread.
336 const VarDecl *getThreadIDVariable() const override { return nullptr; }
337
338 /// Get the name of the capture helper.
339 StringRef getHelperName() const override { return HelperName; }
340
341 static bool classof(const CGCapturedStmtInfo *Info) {
342 return CGOpenMPRegionInfo::classof(Info) &&
343 cast<CGOpenMPRegionInfo>(Info)->getRegionKind() == TargetRegion;
344 }
345
346private:
347 StringRef HelperName;
348};
349
350static void EmptyCodeGen(CodeGenFunction &, PrePostActionTy &) {
351 llvm_unreachable("No codegen for expressions");
352}
353/// API for generation of expressions captured in a innermost OpenMP
354/// region.
355class CGOpenMPInnerExprInfo final : public CGOpenMPInlinedRegionInfo {
356public:
357 CGOpenMPInnerExprInfo(CodeGenFunction &CGF, const CapturedStmt &CS)
358 : CGOpenMPInlinedRegionInfo(CGF.CapturedStmtInfo, EmptyCodeGen,
359 OMPD_unknown,
360 /*HasCancel=*/false),
361 PrivScope(CGF) {
362 // Make sure the globals captured in the provided statement are local by
363 // using the privatization logic. We assume the same variable is not
364 // captured more than once.
365 for (const auto &C : CS.captures()) {
366 if (!C.capturesVariable() && !C.capturesVariableByCopy())
367 continue;
368
369 const VarDecl *VD = C.getCapturedVar();
370 if (VD->isLocalVarDeclOrParm())
371 continue;
372
373 DeclRefExpr DRE(CGF.getContext(), const_cast<VarDecl *>(VD),
374 /*RefersToEnclosingVariableOrCapture=*/false,
375 VD->getType().getNonReferenceType(), VK_LValue,
376 C.getLocation());
377 PrivScope.addPrivate(VD, CGF.EmitLValue(&DRE).getAddress());
378 }
379 (void)PrivScope.Privatize();
380 }
381
382 /// Lookup the captured field decl for a variable.
383 const FieldDecl *lookup(const VarDecl *VD) const override {
384 if (const FieldDecl *FD = CGOpenMPInlinedRegionInfo::lookup(VD))
385 return FD;
386 return nullptr;
387 }
388
389 /// Emit the captured statement body.
390 void EmitBody(CodeGenFunction &CGF, const Stmt *S) override {
391 llvm_unreachable("No body for expressions");
392 }
393
394 /// Get a variable or parameter for storing global thread id
395 /// inside OpenMP construct.
396 const VarDecl *getThreadIDVariable() const override {
397 llvm_unreachable("No thread id for expressions");
398 }
399
400 /// Get the name of the capture helper.
401 StringRef getHelperName() const override {
402 llvm_unreachable("No helper name for expressions");
403 }
404
405 static bool classof(const CGCapturedStmtInfo *Info) { return false; }
406
407private:
408 /// Private scope to capture global variables.
409 CodeGenFunction::OMPPrivateScope PrivScope;
410};
411
412/// RAII for emitting code of OpenMP constructs.
413class InlinedOpenMPRegionRAII {
414 CodeGenFunction &CGF;
415 llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
416 FieldDecl *LambdaThisCaptureField = nullptr;
417 const CodeGen::CGBlockInfo *BlockInfo = nullptr;
418 bool NoInheritance = false;
419
420public:
421 /// Constructs region for combined constructs.
422 /// \param CodeGen Code generation sequence for combined directives. Includes
423 /// a list of functions used for code generation of implicitly inlined
424 /// regions.
425 InlinedOpenMPRegionRAII(CodeGenFunction &CGF, const RegionCodeGenTy &CodeGen,
426 OpenMPDirectiveKind Kind, bool HasCancel,
427 bool NoInheritance = true)
428 : CGF(CGF), NoInheritance(NoInheritance) {
429 // Start emission for the construct.
430 CGF.CapturedStmtInfo = new CGOpenMPInlinedRegionInfo(
431 CGF.CapturedStmtInfo, CodeGen, Kind, HasCancel);
432 if (NoInheritance) {
433 std::swap(CGF.LambdaCaptureFields, LambdaCaptureFields);
434 LambdaThisCaptureField = CGF.LambdaThisCaptureField;
435 CGF.LambdaThisCaptureField = nullptr;
436 BlockInfo = CGF.BlockInfo;
437 CGF.BlockInfo = nullptr;
438 }
439 }
440
441 ~InlinedOpenMPRegionRAII() {
442 // Restore original CapturedStmtInfo only if we're done with code emission.
443 auto *OldCSI =
444 cast<CGOpenMPInlinedRegionInfo>(CGF.CapturedStmtInfo)->getOldCSI();
445 delete CGF.CapturedStmtInfo;
446 CGF.CapturedStmtInfo = OldCSI;
447 if (NoInheritance) {
448 std::swap(CGF.LambdaCaptureFields, LambdaCaptureFields);
449 CGF.LambdaThisCaptureField = LambdaThisCaptureField;
450 CGF.BlockInfo = BlockInfo;
451 }
452 }
453};
454
455/// Values for bit flags used in the ident_t to describe the fields.
456/// All enumeric elements are named and described in accordance with the code
457/// from https://github.com/llvm/llvm-project/blob/main/openmp/runtime/src/kmp.h
458enum OpenMPLocationFlags : unsigned {
459 /// Use trampoline for internal microtask.
460 OMP_IDENT_IMD = 0x01,
461 /// Use c-style ident structure.
462 OMP_IDENT_KMPC = 0x02,
463 /// Atomic reduction option for kmpc_reduce.
464 OMP_ATOMIC_REDUCE = 0x10,
465 /// Explicit 'barrier' directive.
466 OMP_IDENT_BARRIER_EXPL = 0x20,
467 /// Implicit barrier in code.
468 OMP_IDENT_BARRIER_IMPL = 0x40,
469 /// Implicit barrier in 'for' directive.
470 OMP_IDENT_BARRIER_IMPL_FOR = 0x40,
471 /// Implicit barrier in 'sections' directive.
472 OMP_IDENT_BARRIER_IMPL_SECTIONS = 0xC0,
473 /// Implicit barrier in 'single' directive.
474 OMP_IDENT_BARRIER_IMPL_SINGLE = 0x140,
475 /// Call of __kmp_for_static_init for static loop.
476 OMP_IDENT_WORK_LOOP = 0x200,
477 /// Call of __kmp_for_static_init for sections.
478 OMP_IDENT_WORK_SECTIONS = 0x400,
479 /// Call of __kmp_for_static_init for distribute.
480 OMP_IDENT_WORK_DISTRIBUTE = 0x800,
481 LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/OMP_IDENT_WORK_DISTRIBUTE)
482};
483
484/// Describes ident structure that describes a source location.
485/// All descriptions are taken from
486/// https://github.com/llvm/llvm-project/blob/main/openmp/runtime/src/kmp.h
487/// Original structure:
488/// typedef struct ident {
489/// kmp_int32 reserved_1; /**< might be used in Fortran;
490/// see above */
491/// kmp_int32 flags; /**< also f.flags; KMP_IDENT_xxx flags;
492/// KMP_IDENT_KMPC identifies this union
493/// member */
494/// kmp_int32 reserved_2; /**< not really used in Fortran any more;
495/// see above */
496///#if USE_ITT_BUILD
497/// /* but currently used for storing
498/// region-specific ITT */
499/// /* contextual information. */
500///#endif /* USE_ITT_BUILD */
501/// kmp_int32 reserved_3; /**< source[4] in Fortran, do not use for
502/// C++ */
503/// char const *psource; /**< String describing the source location.
504/// The string is composed of semi-colon separated
505// fields which describe the source file,
506/// the function and a pair of line numbers that
507/// delimit the construct.
508/// */
509/// } ident_t;
510enum IdentFieldIndex {
511 /// might be used in Fortran
512 IdentField_Reserved_1,
513 /// OMP_IDENT_xxx flags; OMP_IDENT_KMPC identifies this union member.
514 IdentField_Flags,
515 /// Not really used in Fortran any more
516 IdentField_Reserved_2,
517 /// Source[4] in Fortran, do not use for C++
518 IdentField_Reserved_3,
519 /// String describing the source location. The string is composed of
520 /// semi-colon separated fields which describe the source file, the function
521 /// and a pair of line numbers that delimit the construct.
522 IdentField_PSource
523};
524
525/// Schedule types for 'omp for' loops (these enumerators are taken from
526/// the enum sched_type in kmp.h).
527enum OpenMPSchedType {
528 /// Lower bound for default (unordered) versions.
529 OMP_sch_lower = 32,
530 OMP_sch_static_chunked = 33,
531 OMP_sch_static = 34,
532 OMP_sch_dynamic_chunked = 35,
533 OMP_sch_guided_chunked = 36,
534 OMP_sch_runtime = 37,
535 OMP_sch_auto = 38,
536 /// static with chunk adjustment (e.g., simd)
537 OMP_sch_static_balanced_chunked = 45,
538 /// Lower bound for 'ordered' versions.
539 OMP_ord_lower = 64,
540 OMP_ord_static_chunked = 65,
541 OMP_ord_static = 66,
542 OMP_ord_dynamic_chunked = 67,
543 OMP_ord_guided_chunked = 68,
544 OMP_ord_runtime = 69,
545 OMP_ord_auto = 70,
546 OMP_sch_default = OMP_sch_static,
547 /// dist_schedule types
548 OMP_dist_sch_static_chunked = 91,
549 OMP_dist_sch_static = 92,
550 /// Fused distribute+for static schedule (entityId = team*nthreads + tid,
551 /// num_entities = nteams*nthreads). One for_static_init call, no
552 /// surrounding distribute_static_init. Matches
553 /// kmp_sched_distr_static_chunk_sched_static_chunkone in the device RTL
554 /// (openmp/device/include/DeviceTypes.h).
555 OMP_dist_sch_static_chunked_sch_static_chunkone = 93,
556 /// Support for OpenMP 4.5 monotonic and nonmonotonic schedule modifiers.
557 /// Set if the monotonic schedule modifier was present.
558 OMP_sch_modifier_monotonic = (1 << 29),
559 /// Set if the nonmonotonic schedule modifier was present.
560 OMP_sch_modifier_nonmonotonic = (1 << 30),
561};
562
563/// A basic class for pre|post-action for advanced codegen sequence for OpenMP
564/// region.
565class CleanupTy final : public EHScopeStack::Cleanup {
566 PrePostActionTy *Action;
567
568public:
569 explicit CleanupTy(PrePostActionTy *Action) : Action(Action) {}
570 void Emit(CodeGenFunction &CGF, Flags /*flags*/) override {
571 if (!CGF.HaveInsertPoint())
572 return;
573 Action->Exit(CGF);
574 }
575};
576
577} // anonymous namespace
578
581 if (PrePostAction) {
582 CGF.EHStack.pushCleanup<CleanupTy>(NormalAndEHCleanup, PrePostAction);
583 Callback(CodeGen, CGF, *PrePostAction);
584 } else {
585 PrePostActionTy Action;
586 Callback(CodeGen, CGF, Action);
587 }
588}
589
590/// Check if the combiner is a call to UDR combiner and if it is so return the
591/// UDR decl used for reduction.
592static const OMPDeclareReductionDecl *
593getReductionInit(const Expr *ReductionOp) {
594 if (const auto *CE = dyn_cast<CallExpr>(ReductionOp))
595 if (const auto *OVE = dyn_cast<OpaqueValueExpr>(CE->getCallee()))
596 if (const auto *DRE =
597 dyn_cast<DeclRefExpr>(OVE->getSourceExpr()->IgnoreImpCasts()))
598 if (const auto *DRD = dyn_cast<OMPDeclareReductionDecl>(DRE->getDecl()))
599 return DRD;
600 return nullptr;
601}
602
604 const OMPDeclareReductionDecl *DRD,
605 const Expr *InitOp,
606 Address Private, Address Original,
607 QualType Ty) {
608 if (DRD->getInitializer()) {
609 std::pair<llvm::Function *, llvm::Function *> Reduction =
611 const auto *CE = cast<CallExpr>(InitOp);
612 const auto *OVE = cast<OpaqueValueExpr>(CE->getCallee());
613 const Expr *LHS = CE->getArg(/*Arg=*/0)->IgnoreParenImpCasts();
614 const Expr *RHS = CE->getArg(/*Arg=*/1)->IgnoreParenImpCasts();
615 const auto *LHSDRE =
616 cast<DeclRefExpr>(cast<UnaryOperator>(LHS)->getSubExpr());
617 const auto *RHSDRE =
618 cast<DeclRefExpr>(cast<UnaryOperator>(RHS)->getSubExpr());
619 CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
620 PrivateScope.addPrivate(cast<VarDecl>(LHSDRE->getDecl()), Private);
621 PrivateScope.addPrivate(cast<VarDecl>(RHSDRE->getDecl()), Original);
622 (void)PrivateScope.Privatize();
625 CGF.EmitIgnoredExpr(InitOp);
626 } else {
627 llvm::Constant *Init = CGF.CGM.EmitNullConstant(Ty);
628 std::string Name = CGF.CGM.getOpenMPRuntime().getName({"init"});
629 auto *GV = new llvm::GlobalVariable(
630 CGF.CGM.getModule(), Init->getType(), /*isConstant=*/true,
631 llvm::GlobalValue::PrivateLinkage, Init, Name);
632 LValue LV = CGF.MakeNaturalAlignRawAddrLValue(GV, Ty);
633 RValue InitRVal;
634 switch (CGF.getEvaluationKind(Ty)) {
635 case TEK_Scalar:
636 InitRVal = CGF.EmitLoadOfLValue(LV, DRD->getLocation());
637 break;
638 case TEK_Complex:
639 InitRVal =
641 break;
642 case TEK_Aggregate: {
643 OpaqueValueExpr OVE(DRD->getLocation(), Ty, VK_LValue);
644 CodeGenFunction::OpaqueValueMapping OpaqueMap(CGF, &OVE, LV);
645 CGF.EmitAnyExprToMem(&OVE, Private, Ty.getQualifiers(),
646 /*IsInitializer=*/false);
647 return;
648 }
649 }
650 OpaqueValueExpr OVE(DRD->getLocation(), Ty, VK_PRValue);
651 CodeGenFunction::OpaqueValueMapping OpaqueMap(CGF, &OVE, InitRVal);
652 CGF.EmitAnyExprToMem(&OVE, Private, Ty.getQualifiers(),
653 /*IsInitializer=*/false);
654 }
655}
656
657/// Emit initialization of arrays of complex types.
658/// \param DestAddr Address of the array.
659/// \param Type Type of array.
660/// \param Init Initial expression of array.
661/// \param SrcAddr Address of the original array.
663 QualType Type, bool EmitDeclareReductionInit,
664 const Expr *Init,
665 const OMPDeclareReductionDecl *DRD,
666 Address SrcAddr = Address::invalid()) {
667 // Perform element-by-element initialization.
668 QualType ElementTy;
669
670 // Drill down to the base element type on both arrays.
671 const ArrayType *ArrayTy = Type->getAsArrayTypeUnsafe();
672 llvm::Value *NumElements = CGF.emitArrayLength(ArrayTy, ElementTy, DestAddr);
673 if (DRD)
674 SrcAddr = SrcAddr.withElementType(DestAddr.getElementType());
675
676 llvm::Value *SrcBegin = nullptr;
677 if (DRD)
678 SrcBegin = SrcAddr.emitRawPointer(CGF);
679 llvm::Value *DestBegin = DestAddr.emitRawPointer(CGF);
680 // Cast from pointer to array type to pointer to single element.
681 llvm::Value *DestEnd =
682 CGF.Builder.CreateGEP(DestAddr.getElementType(), DestBegin, NumElements);
683 // The basic structure here is a while-do loop.
684 llvm::BasicBlock *BodyBB = CGF.createBasicBlock("omp.arrayinit.body");
685 llvm::BasicBlock *DoneBB = CGF.createBasicBlock("omp.arrayinit.done");
686 llvm::Value *IsEmpty =
687 CGF.Builder.CreateICmpEQ(DestBegin, DestEnd, "omp.arrayinit.isempty");
688 CGF.Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB);
689
690 // Enter the loop body, making that address the current address.
691 llvm::BasicBlock *EntryBB = CGF.Builder.GetInsertBlock();
692 CGF.EmitBlock(BodyBB);
693
694 CharUnits ElementSize = CGF.getContext().getTypeSizeInChars(ElementTy);
695
696 llvm::PHINode *SrcElementPHI = nullptr;
697 Address SrcElementCurrent = Address::invalid();
698 if (DRD) {
699 SrcElementPHI = CGF.Builder.CreatePHI(SrcBegin->getType(), 2,
700 "omp.arraycpy.srcElementPast");
701 SrcElementPHI->addIncoming(SrcBegin, EntryBB);
702 SrcElementCurrent =
703 Address(SrcElementPHI, SrcAddr.getElementType(),
704 SrcAddr.getAlignment().alignmentOfArrayElement(ElementSize));
705 }
706 llvm::PHINode *DestElementPHI = CGF.Builder.CreatePHI(
707 DestBegin->getType(), 2, "omp.arraycpy.destElementPast");
708 DestElementPHI->addIncoming(DestBegin, EntryBB);
709 Address DestElementCurrent =
710 Address(DestElementPHI, DestAddr.getElementType(),
711 DestAddr.getAlignment().alignmentOfArrayElement(ElementSize));
712
713 // Emit copy.
714 {
716 if (EmitDeclareReductionInit) {
717 emitInitWithReductionInitializer(CGF, DRD, Init, DestElementCurrent,
718 SrcElementCurrent, ElementTy);
719 } else
720 CGF.EmitAnyExprToMem(Init, DestElementCurrent, ElementTy.getQualifiers(),
721 /*IsInitializer=*/false);
722 }
723
724 if (DRD) {
725 // Shift the address forward by one element.
726 llvm::Value *SrcElementNext = CGF.Builder.CreateConstGEP1_32(
727 SrcAddr.getElementType(), SrcElementPHI, /*Idx0=*/1,
728 "omp.arraycpy.dest.element");
729 SrcElementPHI->addIncoming(SrcElementNext, CGF.Builder.GetInsertBlock());
730 }
731
732 // Shift the address forward by one element.
733 llvm::Value *DestElementNext = CGF.Builder.CreateConstGEP1_32(
734 DestAddr.getElementType(), DestElementPHI, /*Idx0=*/1,
735 "omp.arraycpy.dest.element");
736 // Check whether we've reached the end.
737 llvm::Value *Done =
738 CGF.Builder.CreateICmpEQ(DestElementNext, DestEnd, "omp.arraycpy.done");
739 CGF.Builder.CreateCondBr(Done, DoneBB, BodyBB);
740 DestElementPHI->addIncoming(DestElementNext, CGF.Builder.GetInsertBlock());
741
742 // Done.
743 CGF.EmitBlock(DoneBB, /*IsFinished=*/true);
744}
745
746LValue ReductionCodeGen::emitSharedLValue(CodeGenFunction &CGF, const Expr *E) {
747 return CGF.EmitOMPSharedLValue(E);
748}
749
750LValue ReductionCodeGen::emitSharedLValueUB(CodeGenFunction &CGF,
751 const Expr *E) {
752 if (const auto *OASE = dyn_cast<ArraySectionExpr>(E))
753 return CGF.EmitArraySectionExpr(OASE, /*IsLowerBound=*/false);
754 return LValue();
755}
756
757void ReductionCodeGen::emitAggregateInitialization(
758 CodeGenFunction &CGF, unsigned N, Address PrivateAddr, Address SharedAddr,
759 const OMPDeclareReductionDecl *DRD) {
760 // Emit VarDecl with copy init for arrays.
761 // Get the address of the original variable captured in current
762 // captured region.
763 const auto *PrivateVD =
764 cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Private)->getDecl());
765 bool EmitDeclareReductionInit =
766 DRD && (DRD->getInitializer() || !PrivateVD->hasInit());
767 EmitOMPAggregateInit(CGF, PrivateAddr, PrivateVD->getType(),
768 EmitDeclareReductionInit,
769 EmitDeclareReductionInit ? ClausesData[N].ReductionOp
770 : PrivateVD->getInit(),
771 DRD, SharedAddr);
772}
773
777 ArrayRef<const Expr *> ReductionOps) {
778 ClausesData.reserve(Shareds.size());
779 SharedAddresses.reserve(Shareds.size());
780 Sizes.reserve(Shareds.size());
781 BaseDecls.reserve(Shareds.size());
782 const auto *IOrig = Origs.begin();
783 const auto *IPriv = Privates.begin();
784 const auto *IRed = ReductionOps.begin();
785 for (const Expr *Ref : Shareds) {
786 ClausesData.emplace_back(Ref, *IOrig, *IPriv, *IRed);
787 std::advance(IOrig, 1);
788 std::advance(IPriv, 1);
789 std::advance(IRed, 1);
790 }
791}
792
794 assert(SharedAddresses.size() == N && OrigAddresses.size() == N &&
795 "Number of generated lvalues must be exactly N.");
796 LValue First = emitSharedLValue(CGF, ClausesData[N].Shared);
797 LValue Second = emitSharedLValueUB(CGF, ClausesData[N].Shared);
798 SharedAddresses.emplace_back(First, Second);
799 if (ClausesData[N].Shared == ClausesData[N].Ref) {
800 OrigAddresses.emplace_back(First, Second);
801 } else {
802 LValue First = emitSharedLValue(CGF, ClausesData[N].Ref);
803 LValue Second = emitSharedLValueUB(CGF, ClausesData[N].Ref);
804 OrigAddresses.emplace_back(First, Second);
805 }
806}
807
809 QualType PrivateType = getPrivateType(N);
810 bool AsArraySection = isa<ArraySectionExpr>(ClausesData[N].Ref);
811 if (!PrivateType->isVariablyModifiedType()) {
812 Sizes.emplace_back(
813 CGF.getTypeSize(OrigAddresses[N].first.getType().getNonReferenceType()),
814 nullptr);
815 return;
816 }
817 llvm::Value *Size;
818 llvm::Value *SizeInChars;
819 auto *ElemType = OrigAddresses[N].first.getAddress().getElementType();
820 auto *ElemSizeOf = llvm::ConstantExpr::getSizeOf(ElemType);
821 if (AsArraySection) {
822 Size = CGF.Builder.CreatePtrDiff(ElemType,
823 OrigAddresses[N].second.getPointer(CGF),
824 OrigAddresses[N].first.getPointer(CGF));
825 Size = CGF.Builder.CreateZExtOrTrunc(Size, ElemSizeOf->getType());
826 Size = CGF.Builder.CreateNUWAdd(
827 Size, llvm::ConstantInt::get(Size->getType(), /*V=*/1));
828 SizeInChars = CGF.Builder.CreateNUWMul(Size, ElemSizeOf);
829 } else {
830 SizeInChars =
831 CGF.getTypeSize(OrigAddresses[N].first.getType().getNonReferenceType());
832 Size = CGF.Builder.CreateExactUDiv(SizeInChars, ElemSizeOf);
833 }
834 Sizes.emplace_back(SizeInChars, Size);
836 CGF,
838 CGF.getContext().getAsVariableArrayType(PrivateType)->getSizeExpr()),
839 RValue::get(Size));
840 CGF.EmitVariablyModifiedType(PrivateType);
841}
842
844 llvm::Value *Size) {
845 QualType PrivateType = getPrivateType(N);
846 if (!PrivateType->isVariablyModifiedType()) {
847 assert(!Size && !Sizes[N].second &&
848 "Size should be nullptr for non-variably modified reduction "
849 "items.");
850 return;
851 }
853 CGF,
855 CGF.getContext().getAsVariableArrayType(PrivateType)->getSizeExpr()),
856 RValue::get(Size));
857 CGF.EmitVariablyModifiedType(PrivateType);
858}
859
861 CodeGenFunction &CGF, unsigned N, Address PrivateAddr, Address SharedAddr,
862 llvm::function_ref<bool(CodeGenFunction &)> DefaultInit) {
863 assert(SharedAddresses.size() > N && "No variable was generated");
864 const auto *PrivateVD =
865 cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Private)->getDecl());
866 const OMPDeclareReductionDecl *DRD =
867 getReductionInit(ClausesData[N].ReductionOp);
868 if (CGF.getContext().getAsArrayType(PrivateVD->getType())) {
869 if (DRD && DRD->getInitializer())
870 (void)DefaultInit(CGF);
871 emitAggregateInitialization(CGF, N, PrivateAddr, SharedAddr, DRD);
872 } else if (DRD && (DRD->getInitializer() || !PrivateVD->hasInit())) {
873 (void)DefaultInit(CGF);
874 QualType SharedType = SharedAddresses[N].first.getType();
875 emitInitWithReductionInitializer(CGF, DRD, ClausesData[N].ReductionOp,
876 PrivateAddr, SharedAddr, SharedType);
877 } else if (!DefaultInit(CGF) && PrivateVD->hasInit() &&
878 !CGF.isTrivialInitializer(PrivateVD->getInit())) {
879 CGF.EmitAnyExprToMem(PrivateVD->getInit(), PrivateAddr,
880 PrivateVD->getType().getQualifiers(),
881 /*IsInitializer=*/false);
882 }
883}
884
886 QualType PrivateType = getPrivateType(N);
887 QualType::DestructionKind DTorKind = PrivateType.isDestructedType();
888 return DTorKind != QualType::DK_none;
889}
890
892 Address PrivateAddr) {
893 QualType PrivateType = getPrivateType(N);
894 QualType::DestructionKind DTorKind = PrivateType.isDestructedType();
895 if (needCleanups(N)) {
896 PrivateAddr =
897 PrivateAddr.withElementType(CGF.ConvertTypeForMem(PrivateType));
898 CGF.pushDestroy(DTorKind, PrivateAddr, PrivateType);
899 }
900}
901
902static LValue loadToBegin(CodeGenFunction &CGF, QualType BaseTy, QualType ElTy,
903 LValue BaseLV) {
904 BaseTy = BaseTy.getNonReferenceType();
905 while ((BaseTy->isPointerType() || BaseTy->isReferenceType()) &&
906 !CGF.getContext().hasSameType(BaseTy, ElTy)) {
907 if (const auto *PtrTy = BaseTy->getAs<PointerType>()) {
908 BaseLV = CGF.EmitLoadOfPointerLValue(BaseLV.getAddress(), PtrTy);
909 } else {
910 LValue RefLVal = CGF.MakeAddrLValue(BaseLV.getAddress(), BaseTy);
911 BaseLV = CGF.EmitLoadOfReferenceLValue(RefLVal);
912 }
913 BaseTy = BaseTy->getPointeeType();
914 }
915 return CGF.MakeAddrLValue(
916 BaseLV.getAddress().withElementType(CGF.ConvertTypeForMem(ElTy)),
917 BaseLV.getType(), BaseLV.getBaseInfo(),
918 CGF.CGM.getTBAAInfoForSubobject(BaseLV, BaseLV.getType()));
919}
920
922 Address OriginalBaseAddress, llvm::Value *Addr) {
924 Address TopTmp = Address::invalid();
925 Address MostTopTmp = Address::invalid();
926 BaseTy = BaseTy.getNonReferenceType();
927 while ((BaseTy->isPointerType() || BaseTy->isReferenceType()) &&
928 !CGF.getContext().hasSameType(BaseTy, ElTy)) {
929 Tmp = CGF.CreateMemTempWithoutCast(BaseTy);
930 if (TopTmp.isValid())
931 CGF.Builder.CreateStore(Tmp.getPointer(), TopTmp);
932 else
933 MostTopTmp = Tmp;
934 TopTmp = Tmp;
935 BaseTy = BaseTy->getPointeeType();
936 }
937
938 if (Tmp.isValid()) {
940 Addr, Tmp.getElementType());
941 CGF.Builder.CreateStore(Addr, Tmp);
942 return MostTopTmp;
943 }
944
946 Addr, OriginalBaseAddress.getType());
947 return OriginalBaseAddress.withPointer(Addr, NotKnownNonNull);
948}
949
950static const VarDecl *getBaseDecl(const Expr *Ref, const DeclRefExpr *&DE) {
951 const VarDecl *OrigVD = nullptr;
952 if (const auto *OASE = dyn_cast<ArraySectionExpr>(Ref)) {
953 const Expr *Base = OASE->getBase()->IgnoreParenImpCasts();
954 while (const auto *TempOASE = dyn_cast<ArraySectionExpr>(Base))
955 Base = TempOASE->getBase()->IgnoreParenImpCasts();
956 while (const auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
957 Base = TempASE->getBase()->IgnoreParenImpCasts();
959 OrigVD = cast<VarDecl>(DE->getDecl());
960 } else if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(Ref)) {
961 const Expr *Base = ASE->getBase()->IgnoreParenImpCasts();
962 while (const auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
963 Base = TempASE->getBase()->IgnoreParenImpCasts();
965 OrigVD = cast<VarDecl>(DE->getDecl());
966 }
967 return OrigVD;
968}
969
971 Address PrivateAddr) {
972 const DeclRefExpr *DE;
973 if (const VarDecl *OrigVD = ::getBaseDecl(ClausesData[N].Ref, DE)) {
974 BaseDecls.emplace_back(OrigVD);
975 LValue OriginalBaseLValue = CGF.EmitLValue(DE);
976 LValue BaseLValue =
977 loadToBegin(CGF, OrigVD->getType(), SharedAddresses[N].first.getType(),
978 OriginalBaseLValue);
979 Address SharedAddr = SharedAddresses[N].first.getAddress();
980 llvm::Value *Adjustment = CGF.Builder.CreatePtrDiff(
981 SharedAddr.getElementType(), BaseLValue.getPointer(CGF),
982 SharedAddr.emitRawPointer(CGF));
983 llvm::Value *PrivatePointer =
985 PrivateAddr.emitRawPointer(CGF), SharedAddr.getType());
986 llvm::Value *Ptr = CGF.Builder.CreateGEP(
987 SharedAddr.getElementType(), PrivatePointer, Adjustment);
988 return castToBase(CGF, OrigVD->getType(),
989 SharedAddresses[N].first.getType(),
990 OriginalBaseLValue.getAddress(), Ptr);
991 }
992 BaseDecls.emplace_back(
993 cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Ref)->getDecl()));
994 return PrivateAddr;
995}
996
998 const OMPDeclareReductionDecl *DRD =
999 getReductionInit(ClausesData[N].ReductionOp);
1000 return DRD && DRD->getInitializer();
1001}
1002
1003LValue CGOpenMPRegionInfo::getThreadIDVariableLValue(CodeGenFunction &CGF) {
1004 return CGF.EmitLoadOfPointerLValue(
1005 CGF.GetAddrOfLocalVar(getThreadIDVariable()),
1006 getThreadIDVariable()->getType()->castAs<PointerType>());
1007}
1008
1009void CGOpenMPRegionInfo::EmitBody(CodeGenFunction &CGF, const Stmt *S) {
1010 if (!CGF.HaveInsertPoint())
1011 return;
1012 // 1.2.2 OpenMP Language Terminology
1013 // Structured block - An executable statement with a single entry at the
1014 // top and a single exit at the bottom.
1015 // The point of exit cannot be a branch out of the structured block.
1016 // longjmp() and throw() must not violate the entry/exit criteria.
1017 CGF.EHStack.pushTerminate();
1018 if (S)
1020 CodeGen(CGF);
1021 CGF.EHStack.popTerminate();
1022}
1023
1024LValue CGOpenMPTaskOutlinedRegionInfo::getThreadIDVariableLValue(
1025 CodeGenFunction &CGF) {
1026 return CGF.MakeAddrLValue(CGF.GetAddrOfLocalVar(getThreadIDVariable()),
1027 getThreadIDVariable()->getType(),
1029}
1030
1032 QualType FieldTy) {
1033 auto *Field = FieldDecl::Create(
1034 C, DC, SourceLocation(), SourceLocation(), /*Id=*/nullptr, FieldTy,
1035 C.getTrivialTypeSourceInfo(FieldTy, SourceLocation()),
1036 /*BW=*/nullptr, /*Mutable=*/false, /*InitStyle=*/ICIS_NoInit);
1037 Field->setAccess(AS_public);
1038 DC->addDecl(Field);
1039 return Field;
1040}
1041
1043 : CGM(CGM), OMPBuilder(CGM.getModule()) {
1044 KmpCriticalNameTy = llvm::ArrayType::get(CGM.Int32Ty, /*NumElements*/ 8);
1045 llvm::OpenMPIRBuilderConfig Config(
1046 CGM.getLangOpts().OpenMPIsTargetDevice, isGPU(),
1047 CGM.getLangOpts().OpenMPOffloadMandatory,
1048 /*HasRequiresReverseOffload*/ false, /*HasRequiresUnifiedAddress*/ false,
1049 hasRequiresUnifiedSharedMemory(), /*HasRequiresDynamicAllocators*/ false);
1050 Config.setDefaultTargetAS(
1051 CGM.getContext().getTargetInfo().getTargetAddressSpace(LangAS::Default));
1052 Config.setRuntimeCC(CGM.getRuntimeCC());
1053
1054 OMPBuilder.setConfig(Config);
1055 OMPBuilder.initialize();
1056 OMPBuilder.loadOffloadInfoMetadata(*CGM.getFileSystem(),
1057 CGM.getLangOpts().OpenMPIsTargetDevice
1058 ? CGM.getLangOpts().OMPHostIRFile
1059 : StringRef{});
1060
1061 // The user forces the compiler to behave as if omp requires
1062 // unified_shared_memory was given.
1063 if (CGM.getLangOpts().OpenMPForceUSM) {
1065 OMPBuilder.Config.setHasRequiresUnifiedSharedMemory(true);
1066 }
1067}
1068
1070 InternalVars.clear();
1071 // Clean non-target variable declarations possibly used only in debug info.
1072 for (const auto &Data : EmittedNonTargetVariables) {
1073 if (!Data.getValue().pointsToAliveValue())
1074 continue;
1075 auto *GV = dyn_cast<llvm::GlobalVariable>(Data.getValue());
1076 if (!GV)
1077 continue;
1078 if (!GV->isDeclaration() || GV->getNumUses() > 0)
1079 continue;
1080 GV->eraseFromParent();
1081 }
1082}
1083
1085 return OMPBuilder.createPlatformSpecificName(Parts);
1086}
1087
1088static llvm::Function *
1090 const Expr *CombinerInitializer, const VarDecl *In,
1091 const VarDecl *Out, bool IsCombiner) {
1092 // void .omp_combiner.(Ty *in, Ty *out);
1093 ASTContext &C = CGM.getContext();
1094 QualType PtrTy = C.getPointerType(Ty).withRestrict();
1095 auto *OmpOutParm = ImplicitParamDecl::Create(
1096 C, /*DC=*/nullptr, Out->getLocation(),
1097 /*Id=*/nullptr, PtrTy, ImplicitParamKind::Other);
1098 auto *OmpInParm = ImplicitParamDecl::Create(
1099 C, /*DC=*/nullptr, In->getLocation(),
1100 /*Id=*/nullptr, PtrTy, ImplicitParamKind::Other);
1101 FunctionArgList Args{OmpOutParm, OmpInParm};
1102 const CGFunctionInfo &FnInfo =
1103 CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
1104 llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
1105 std::string Name = CGM.getOpenMPRuntime().getName(
1106 {IsCombiner ? "omp_combiner" : "omp_initializer", ""});
1107 auto *Fn = llvm::Function::Create(FnTy, llvm::GlobalValue::InternalLinkage,
1108 Name, &CGM.getModule());
1109 CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FnInfo);
1110 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
1111 Fn->addFnAttr("sample-profile-suffix-elision-policy", "selected");
1112 if (CGM.getCodeGenOpts().OptimizationLevel != 0) {
1113 Fn->removeFnAttr(llvm::Attribute::NoInline);
1114 Fn->removeFnAttr(llvm::Attribute::OptimizeNone);
1115 Fn->addFnAttr(llvm::Attribute::AlwaysInline);
1116 }
1117 CodeGenFunction CGF(CGM);
1118 // Map "T omp_in;" variable to "*omp_in_parm" value in all expressions.
1119 // Map "T omp_out;" variable to "*omp_out_parm" value in all expressions.
1120 CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, FnInfo, Args, In->getLocation(),
1121 Out->getLocation());
1123 Address AddrIn = CGF.GetAddrOfLocalVar(OmpInParm);
1124 Scope.addPrivate(
1125 In, CGF.EmitLoadOfPointerLValue(AddrIn, PtrTy->castAs<PointerType>())
1126 .getAddress());
1127 Address AddrOut = CGF.GetAddrOfLocalVar(OmpOutParm);
1128 Scope.addPrivate(
1129 Out, CGF.EmitLoadOfPointerLValue(AddrOut, PtrTy->castAs<PointerType>())
1130 .getAddress());
1131 (void)Scope.Privatize();
1132 if (!IsCombiner && Out->hasInit() &&
1133 !CGF.isTrivialInitializer(Out->getInit())) {
1134 CGF.EmitAnyExprToMem(Out->getInit(), CGF.GetAddrOfLocalVar(Out),
1135 Out->getType().getQualifiers(),
1136 /*IsInitializer=*/true);
1137 }
1138 if (CombinerInitializer)
1139 CGF.EmitIgnoredExpr(CombinerInitializer);
1140 Scope.ForceCleanup();
1141 CGF.FinishFunction();
1142 return Fn;
1143}
1144
1147 if (UDRMap.count(D) > 0)
1148 return;
1149 llvm::Function *Combiner = emitCombinerOrInitializer(
1150 CGM, D->getType(), D->getCombiner(),
1153 /*IsCombiner=*/true);
1154 llvm::Function *Initializer = nullptr;
1155 if (const Expr *Init = D->getInitializer()) {
1157 CGM, D->getType(),
1159 : nullptr,
1162 /*IsCombiner=*/false);
1163 }
1164 UDRMap.try_emplace(D, Combiner, Initializer);
1165 if (CGF)
1166 FunctionUDRMap[CGF->CurFn].push_back(D);
1167}
1168
1169std::pair<llvm::Function *, llvm::Function *>
1171 auto I = UDRMap.find(D);
1172 if (I != UDRMap.end())
1173 return I->second;
1174 emitUserDefinedReduction(/*CGF=*/nullptr, D);
1175 return UDRMap.lookup(D);
1176}
1177
1178namespace {
1179// Temporary RAII solution to perform a push/pop stack event on the OpenMP IR
1180// Builder if one is present.
1181struct PushAndPopStackRAII {
1182 PushAndPopStackRAII(llvm::OpenMPIRBuilder *OMPBuilder, CodeGenFunction &CGF,
1183 bool HasCancel, llvm::omp::Directive Kind)
1184 : OMPBuilder(OMPBuilder) {
1185 if (!OMPBuilder)
1186 return;
1187
1188 // The following callback is the crucial part of clangs cleanup process.
1189 //
1190 // NOTE:
1191 // Once the OpenMPIRBuilder is used to create parallel regions (and
1192 // similar), the cancellation destination (Dest below) is determined via
1193 // IP. That means if we have variables to finalize we split the block at IP,
1194 // use the new block (=BB) as destination to build a JumpDest (via
1195 // getJumpDestInCurrentScope(BB)) which then is fed to
1196 // EmitBranchThroughCleanup. Furthermore, there will not be the need
1197 // to push & pop an FinalizationInfo object.
1198 // The FiniCB will still be needed but at the point where the
1199 // OpenMPIRBuilder is asked to construct a parallel (or similar) construct.
1200 auto FiniCB = [&CGF](llvm::OpenMPIRBuilder::InsertPointTy IP) {
1201 assert(IP.getBlock()->end() == IP.getPoint() &&
1202 "Clang CG should cause non-terminated block!");
1203 CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
1204 CGF.Builder.restoreIP(IP);
1206 CGF.getOMPCancelDestination(OMPD_parallel);
1207 CGF.EmitBranchThroughCleanup(Dest);
1208 return llvm::Error::success();
1209 };
1210
1211 // TODO: Remove this once we emit parallel regions through the
1212 // OpenMPIRBuilder as it can do this setup internally.
1213 llvm::OpenMPIRBuilder::FinalizationInfo FI({FiniCB, Kind, HasCancel});
1214 OMPBuilder->pushFinalizationCB(std::move(FI));
1215 }
1216 ~PushAndPopStackRAII() {
1217 if (OMPBuilder)
1218 OMPBuilder->popFinalizationCB();
1219 }
1220 llvm::OpenMPIRBuilder *OMPBuilder;
1221};
1222} // namespace
1223
1225 CodeGenModule &CGM, const OMPExecutableDirective &D, const CapturedStmt *CS,
1226 const VarDecl *ThreadIDVar, OpenMPDirectiveKind InnermostKind,
1227 const StringRef OutlinedHelperName, const RegionCodeGenTy &CodeGen) {
1228 assert(ThreadIDVar->getType()->isPointerType() &&
1229 "thread id variable must be of type kmp_int32 *");
1230 CodeGenFunction CGF(CGM, true);
1231 bool HasCancel = false;
1232 if (const auto *OPD = dyn_cast<OMPParallelDirective>(&D))
1233 HasCancel = OPD->hasCancel();
1234 else if (const auto *OPD = dyn_cast<OMPTargetParallelDirective>(&D))
1235 HasCancel = OPD->hasCancel();
1236 else if (const auto *OPSD = dyn_cast<OMPParallelSectionsDirective>(&D))
1237 HasCancel = OPSD->hasCancel();
1238 else if (const auto *OPFD = dyn_cast<OMPParallelForDirective>(&D))
1239 HasCancel = OPFD->hasCancel();
1240 else if (const auto *OPFD = dyn_cast<OMPTargetParallelForDirective>(&D))
1241 HasCancel = OPFD->hasCancel();
1242 else if (const auto *OPFD = dyn_cast<OMPDistributeParallelForDirective>(&D))
1243 HasCancel = OPFD->hasCancel();
1244 else if (const auto *OPFD =
1245 dyn_cast<OMPTeamsDistributeParallelForDirective>(&D))
1246 HasCancel = OPFD->hasCancel();
1247 else if (const auto *OPFD =
1248 dyn_cast<OMPTargetTeamsDistributeParallelForDirective>(&D))
1249 HasCancel = OPFD->hasCancel();
1250
1251 // TODO: Temporarily inform the OpenMPIRBuilder, if any, about the new
1252 // parallel region to make cancellation barriers work properly.
1253 llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
1254 PushAndPopStackRAII PSR(&OMPBuilder, CGF, HasCancel, InnermostKind);
1255 CGOpenMPOutlinedRegionInfo CGInfo(*CS, ThreadIDVar, CodeGen, InnermostKind,
1256 HasCancel, OutlinedHelperName);
1257 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
1258 return CGF.GenerateOpenMPCapturedStmtFunction(*CS, D);
1259}
1260
1261std::string CGOpenMPRuntime::getOutlinedHelperName(StringRef Name) const {
1262 std::string Suffix = getName({"omp_outlined"});
1263 return (Name + Suffix).str();
1264}
1265
1267 return getOutlinedHelperName(CGF.CurFn->getName());
1268}
1269
1270std::string CGOpenMPRuntime::getReductionFuncName(StringRef Name) const {
1271 std::string Suffix = getName({"omp", "reduction", "reduction_func"});
1272 return (Name + Suffix).str();
1273}
1274
1277 const VarDecl *ThreadIDVar, OpenMPDirectiveKind InnermostKind,
1278 const RegionCodeGenTy &CodeGen) {
1279 const CapturedStmt *CS = D.getCapturedStmt(OMPD_parallel);
1281 CGM, D, CS, ThreadIDVar, InnermostKind, getOutlinedHelperName(CGF),
1282 CodeGen);
1283}
1284
1287 const VarDecl *ThreadIDVar, OpenMPDirectiveKind InnermostKind,
1288 const RegionCodeGenTy &CodeGen) {
1289 const CapturedStmt *CS = D.getCapturedStmt(OMPD_teams);
1291 CGM, D, CS, ThreadIDVar, InnermostKind, getOutlinedHelperName(CGF),
1292 CodeGen);
1293}
1294
1296 const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
1297 const VarDecl *PartIDVar, const VarDecl *TaskTVar,
1298 OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen,
1299 bool Tied, unsigned &NumberOfParts) {
1300 auto &&UntiedCodeGen = [this, &D, TaskTVar](CodeGenFunction &CGF,
1301 PrePostActionTy &) {
1302 llvm::Value *ThreadID = getThreadID(CGF, D.getBeginLoc());
1303 llvm::Value *UpLoc = emitUpdateLocation(CGF, D.getBeginLoc());
1304 llvm::Value *TaskArgs[] = {
1305 UpLoc, ThreadID,
1306 CGF.EmitLoadOfPointerLValue(CGF.GetAddrOfLocalVar(TaskTVar),
1307 TaskTVar->getType()->castAs<PointerType>())
1308 .getPointer(CGF)};
1309 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
1310 CGM.getModule(), OMPRTL___kmpc_omp_task),
1311 TaskArgs);
1312 };
1313 CGOpenMPTaskOutlinedRegionInfo::UntiedTaskActionTy Action(Tied, PartIDVar,
1314 UntiedCodeGen);
1315 CodeGen.setAction(Action);
1316 assert(!ThreadIDVar->getType()->isPointerType() &&
1317 "thread id variable must be of type kmp_int32 for tasks");
1318 const OpenMPDirectiveKind Region =
1319 isOpenMPTaskLoopDirective(D.getDirectiveKind()) ? OMPD_taskloop
1320 : OMPD_task;
1321 const CapturedStmt *CS = D.getCapturedStmt(Region);
1322 bool HasCancel = false;
1323 if (const auto *TD = dyn_cast<OMPTaskDirective>(&D))
1324 HasCancel = TD->hasCancel();
1325 else if (const auto *TD = dyn_cast<OMPTaskLoopDirective>(&D))
1326 HasCancel = TD->hasCancel();
1327 else if (const auto *TD = dyn_cast<OMPMasterTaskLoopDirective>(&D))
1328 HasCancel = TD->hasCancel();
1329 else if (const auto *TD = dyn_cast<OMPParallelMasterTaskLoopDirective>(&D))
1330 HasCancel = TD->hasCancel();
1331
1332 CodeGenFunction CGF(CGM, true);
1333 CGOpenMPTaskOutlinedRegionInfo CGInfo(*CS, ThreadIDVar, CodeGen,
1334 InnermostKind, HasCancel, Action);
1335 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
1336 llvm::Function *Res = CGF.GenerateCapturedStmtFunction(*CS);
1337 if (!Tied)
1338 NumberOfParts = Action.getNumberOfParts();
1339 return Res;
1340}
1341
1343 bool AtCurrentPoint) {
1344 auto &Elem = OpenMPLocThreadIDMap[CGF.CurFn];
1345 assert(!Elem.ServiceInsertPt && "Insert point is set already.");
1346
1347 llvm::Value *Undef = llvm::UndefValue::get(CGF.Int32Ty);
1348 if (AtCurrentPoint) {
1349 Elem.ServiceInsertPt = new llvm::BitCastInst(Undef, CGF.Int32Ty, "svcpt",
1350 CGF.Builder.GetInsertBlock());
1351 } else {
1352 Elem.ServiceInsertPt = new llvm::BitCastInst(Undef, CGF.Int32Ty, "svcpt");
1353 Elem.ServiceInsertPt->insertAfter(CGF.AllocaInsertPt->getIterator());
1354 }
1355}
1356
1358 auto &Elem = OpenMPLocThreadIDMap[CGF.CurFn];
1359 if (Elem.ServiceInsertPt) {
1360 llvm::Instruction *Ptr = Elem.ServiceInsertPt;
1361 Elem.ServiceInsertPt = nullptr;
1362 Ptr->eraseFromParent();
1363 }
1364}
1365
1367 SourceLocation Loc,
1368 SmallString<128> &Buffer) {
1369 llvm::raw_svector_ostream OS(Buffer);
1370 // Build debug location
1372 OS << ";";
1373 if (auto *DbgInfo = CGF.getDebugInfo())
1374 OS << DbgInfo->remapDIPath(PLoc.getFilename());
1375 else
1376 OS << PLoc.getFilename();
1377 OS << ";";
1378 if (const auto *FD = dyn_cast_or_null<FunctionDecl>(CGF.CurFuncDecl))
1379 OS << FD->getQualifiedNameAsString();
1380 OS << ";" << PLoc.getLine() << ";" << PLoc.getColumn() << ";;";
1381 return OS.str();
1382}
1383
1385 SourceLocation Loc,
1386 unsigned Flags, bool EmitLoc) {
1387 uint32_t SrcLocStrSize;
1388 llvm::Constant *SrcLocStr;
1389 if ((!EmitLoc && CGM.getCodeGenOpts().getDebugInfo() ==
1390 llvm::codegenoptions::NoDebugInfo) ||
1391 Loc.isInvalid()) {
1392 SrcLocStr = OMPBuilder.getOrCreateDefaultSrcLocStr(SrcLocStrSize);
1393 } else {
1394 std::string FunctionName;
1395 std::string FileName;
1396 if (const auto *FD = dyn_cast_or_null<FunctionDecl>(CGF.CurFuncDecl))
1397 FunctionName = FD->getQualifiedNameAsString();
1399 if (auto *DbgInfo = CGF.getDebugInfo())
1400 FileName = DbgInfo->remapDIPath(PLoc.getFilename());
1401 else
1402 FileName = PLoc.getFilename();
1403 unsigned Line = PLoc.getLine();
1404 unsigned Column = PLoc.getColumn();
1405 SrcLocStr = OMPBuilder.getOrCreateSrcLocStr(FunctionName, FileName, Line,
1406 Column, SrcLocStrSize);
1407 }
1408 unsigned Reserved2Flags = getDefaultLocationReserved2Flags();
1409 return OMPBuilder.getOrCreateIdent(
1410 SrcLocStr, SrcLocStrSize, llvm::omp::IdentFlag(Flags), Reserved2Flags);
1411}
1412
1414 SourceLocation Loc) {
1415 assert(CGF.CurFn && "No function in current CodeGenFunction.");
1416 // If the OpenMPIRBuilder is used we need to use it for all thread id calls as
1417 // the clang invariants used below might be broken.
1418 if (CGM.getLangOpts().OpenMPIRBuilder) {
1419 SmallString<128> Buffer;
1420 OMPBuilder.updateToLocation(CGF.Builder.saveIP());
1421 uint32_t SrcLocStrSize;
1422 auto *SrcLocStr = OMPBuilder.getOrCreateSrcLocStr(
1423 getIdentStringFromSourceLocation(CGF, Loc, Buffer), SrcLocStrSize);
1424 return OMPBuilder.getOrCreateThreadID(
1425 OMPBuilder.getOrCreateIdent(SrcLocStr, SrcLocStrSize));
1426 }
1427
1428 llvm::Value *ThreadID = nullptr;
1429 // Check whether we've already cached a load of the thread id in this
1430 // function.
1431 auto I = OpenMPLocThreadIDMap.find(CGF.CurFn);
1432 if (I != OpenMPLocThreadIDMap.end()) {
1433 ThreadID = I->second.ThreadID;
1434 if (ThreadID != nullptr)
1435 return ThreadID;
1436 }
1437 // If exceptions are enabled, do not use parameter to avoid possible crash.
1438 if (auto *OMPRegionInfo =
1439 dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) {
1440 if (OMPRegionInfo->getThreadIDVariable()) {
1441 // Check if this an outlined function with thread id passed as argument.
1442 LValue LVal = OMPRegionInfo->getThreadIDVariableLValue(CGF);
1443 llvm::BasicBlock *TopBlock = CGF.AllocaInsertPt->getParent();
1444 if (!CGF.EHStack.requiresLandingPad() || !CGF.getLangOpts().Exceptions ||
1445 !CGF.getLangOpts().CXXExceptions ||
1446 CGF.Builder.GetInsertBlock() == TopBlock ||
1447 !isa<llvm::Instruction>(LVal.getPointer(CGF)) ||
1448 cast<llvm::Instruction>(LVal.getPointer(CGF))->getParent() ==
1449 TopBlock ||
1450 cast<llvm::Instruction>(LVal.getPointer(CGF))->getParent() ==
1451 CGF.Builder.GetInsertBlock()) {
1452 ThreadID = CGF.EmitLoadOfScalar(LVal, Loc);
1453 // If value loaded in entry block, cache it and use it everywhere in
1454 // function.
1455 if (CGF.Builder.GetInsertBlock() == TopBlock)
1456 OpenMPLocThreadIDMap[CGF.CurFn].ThreadID = ThreadID;
1457 return ThreadID;
1458 }
1459 }
1460 }
1461
1462 // This is not an outlined function region - need to call __kmpc_int32
1463 // kmpc_global_thread_num(ident_t *loc).
1464 // Generate thread id value and cache this value for use across the
1465 // function.
1466 auto &Elem = OpenMPLocThreadIDMap[CGF.CurFn];
1467 if (!Elem.ServiceInsertPt)
1469 CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
1470 CGF.Builder.SetInsertPoint(Elem.ServiceInsertPt);
1472 llvm::CallInst *Call = CGF.Builder.CreateCall(
1473 OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(),
1474 OMPRTL___kmpc_global_thread_num),
1475 emitUpdateLocation(CGF, Loc));
1476 Call->setCallingConv(CGF.getRuntimeCC());
1477 Elem.ThreadID = Call;
1478 return Call;
1479}
1480
1482 assert(CGF.CurFn && "No function in current CodeGenFunction.");
1483 if (OpenMPLocThreadIDMap.count(CGF.CurFn)) {
1485 OpenMPLocThreadIDMap.erase(CGF.CurFn);
1486 }
1487 if (auto I = FunctionUDRMap.find(CGF.CurFn); I != FunctionUDRMap.end()) {
1488 for (const auto *D : I->second)
1489 UDRMap.erase(D);
1490 FunctionUDRMap.erase(I);
1491 }
1492 if (auto I = FunctionUDMMap.find(CGF.CurFn); I != FunctionUDMMap.end()) {
1493 for (const auto *D : I->second)
1494 UDMMap.erase(D);
1495 FunctionUDMMap.erase(I);
1496 }
1499}
1500
1502 return OMPBuilder.IdentPtr;
1503}
1504
1505static llvm::OffloadEntriesInfoManager::OMPTargetDeviceClauseKind
1507 std::optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
1508 OMPDeclareTargetDeclAttr::getDeviceType(VD);
1509 if (!DevTy)
1510 return llvm::OffloadEntriesInfoManager::OMPTargetDeviceClauseNone;
1511
1512 switch ((int)*DevTy) { // Avoid -Wcovered-switch-default
1513 case OMPDeclareTargetDeclAttr::DT_Host:
1514 return llvm::OffloadEntriesInfoManager::OMPTargetDeviceClauseHost;
1515 break;
1516 case OMPDeclareTargetDeclAttr::DT_NoHost:
1517 return llvm::OffloadEntriesInfoManager::OMPTargetDeviceClauseNoHost;
1518 break;
1519 case OMPDeclareTargetDeclAttr::DT_Any:
1520 return llvm::OffloadEntriesInfoManager::OMPTargetDeviceClauseAny;
1521 break;
1522 default:
1523 return llvm::OffloadEntriesInfoManager::OMPTargetDeviceClauseNone;
1524 break;
1525 }
1526}
1527
1528static llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryKind
1530 std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> MapType =
1531 OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
1532 if (!MapType)
1533 return llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryNone;
1534 switch ((int)*MapType) { // Avoid -Wcovered-switch-default
1535 case OMPDeclareTargetDeclAttr::MapTypeTy::MT_To:
1536 return llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryTo;
1537 break;
1538 case OMPDeclareTargetDeclAttr::MapTypeTy::MT_Enter:
1539 return llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryEnter;
1540 case OMPDeclareTargetDeclAttr::MapTypeTy::MT_Link:
1541 return llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryLink;
1542 break;
1543 case OMPDeclareTargetDeclAttr::MapTypeTy::MT_Local:
1544 // MT_Local variables don't need offload entry (device-local).
1545 llvm_unreachable("MT_Local should not reach convertCaptureClause");
1546 break;
1547 default:
1548 return llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryNone;
1549 break;
1550 }
1551}
1552
1553static llvm::TargetRegionEntryInfo getEntryInfoFromPresumedLoc(
1554 CodeGenModule &CGM, llvm::OpenMPIRBuilder &OMPBuilder,
1555 SourceLocation BeginLoc, llvm::StringRef ParentName = "") {
1556
1557 auto FileInfoCallBack = [&]() {
1559 PresumedLoc PLoc = SM.getPresumedLoc(BeginLoc);
1560
1561 if (!CGM.getFileSystem()->exists(PLoc.getFilename()))
1562 PLoc = SM.getPresumedLoc(BeginLoc, /*UseLineDirectives=*/false);
1563
1564 return std::pair<std::string, uint64_t>(PLoc.getFilename(), PLoc.getLine());
1565 };
1566
1567 return OMPBuilder.getTargetEntryUniqueInfo(FileInfoCallBack,
1568 *CGM.getFileSystem(), ParentName);
1569}
1570
1572 auto AddrOfGlobal = [&VD, this]() { return CGM.GetAddrOfGlobal(VD); };
1573
1574 auto LinkageForVariable = [&VD, this]() {
1575 return CGM.getLLVMLinkageVarDefinition(VD);
1576 };
1577
1578 std::vector<llvm::GlobalVariable *> GeneratedRefs;
1579
1580 llvm::Type *LlvmPtrTy = CGM.getTypes().ConvertTypeForMem(
1581 CGM.getContext().getPointerType(VD->getType()));
1582 llvm::Constant *addr = OMPBuilder.getAddrOfDeclareTargetVar(
1584 VD->hasDefinition(CGM.getContext()) == VarDecl::DeclarationOnly,
1585 VD->isExternallyVisible(),
1587 VD->getCanonicalDecl()->getBeginLoc()),
1588 CGM.getMangledName(VD), GeneratedRefs, CGM.getLangOpts().OpenMPSimd,
1589 CGM.getLangOpts().OMPTargetTriples, LlvmPtrTy, AddrOfGlobal,
1590 LinkageForVariable);
1591
1592 if (!addr)
1593 return ConstantAddress::invalid();
1594 return ConstantAddress(addr, LlvmPtrTy, CGM.getContext().getDeclAlign(VD));
1595}
1596
1597llvm::Constant *
1599 assert(!CGM.getLangOpts().OpenMPUseTLS ||
1600 !CGM.getContext().getTargetInfo().isTLSSupported());
1601 // Lookup the entry, lazily creating it if necessary.
1602 std::string Suffix = getName({"cache", ""});
1603 return OMPBuilder.getOrCreateInternalVariable(
1604 CGM.Int8PtrPtrTy, Twine(CGM.getMangledName(VD)).concat(Suffix).str());
1605}
1606
1608 const VarDecl *VD,
1609 Address VDAddr,
1610 SourceLocation Loc) {
1611 if (CGM.getLangOpts().OpenMPUseTLS &&
1612 CGM.getContext().getTargetInfo().isTLSSupported())
1613 return VDAddr;
1614
1615 llvm::Type *VarTy = VDAddr.getElementType();
1616 llvm::Value *Args[] = {
1617 emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
1618 CGF.Builder.CreatePointerCast(VDAddr.emitRawPointer(CGF), CGM.Int8PtrTy),
1619 CGM.getSize(CGM.GetTargetTypeStoreSize(VarTy)),
1621 return Address(
1622 CGF.EmitRuntimeCall(
1623 OMPBuilder.getOrCreateRuntimeFunction(
1624 CGM.getModule(), OMPRTL___kmpc_threadprivate_cached),
1625 Args),
1626 CGF.Int8Ty, VDAddr.getAlignment());
1627}
1628
1630 CodeGenFunction &CGF, Address VDAddr, llvm::Value *Ctor,
1631 llvm::Value *CopyCtor, llvm::Value *Dtor, SourceLocation Loc) {
1632 // Call kmp_int32 __kmpc_global_thread_num(&loc) to init OpenMP runtime
1633 // library.
1634 llvm::Value *OMPLoc = emitUpdateLocation(CGF, Loc);
1635 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
1636 CGM.getModule(), OMPRTL___kmpc_global_thread_num),
1637 OMPLoc);
1638 // Call __kmpc_threadprivate_register(&loc, &var, ctor, cctor/*NULL*/, dtor)
1639 // to register constructor/destructor for variable.
1640 llvm::Value *Args[] = {
1641 OMPLoc,
1642 CGF.Builder.CreatePointerCast(VDAddr.emitRawPointer(CGF), CGM.VoidPtrTy),
1643 Ctor, CopyCtor, Dtor};
1644 CGF.EmitRuntimeCall(
1645 OMPBuilder.getOrCreateRuntimeFunction(
1646 CGM.getModule(), OMPRTL___kmpc_threadprivate_register),
1647 Args);
1648}
1649
1651 const VarDecl *VD, Address VDAddr, SourceLocation Loc,
1652 bool PerformInit, CodeGenFunction *CGF) {
1653 if (CGM.getLangOpts().OpenMPUseTLS &&
1654 CGM.getContext().getTargetInfo().isTLSSupported())
1655 return nullptr;
1656
1657 VD = VD->getDefinition(CGM.getContext());
1658 if (VD && ThreadPrivateWithDefinition.insert(CGM.getMangledName(VD)).second) {
1659 QualType ASTTy = VD->getType();
1660
1661 llvm::Value *Ctor = nullptr, *CopyCtor = nullptr, *Dtor = nullptr;
1662 const Expr *Init = VD->getAnyInitializer();
1663 if (CGM.getLangOpts().CPlusPlus && PerformInit) {
1664 // Generate function that re-emits the declaration's initializer into the
1665 // threadprivate copy of the variable VD
1666 CodeGenFunction CtorCGF(CGM);
1667 auto *Dst = ImplicitParamDecl::Create(
1668 CGM.getContext(), /*DC=*/nullptr, Loc,
1669 /*Id=*/nullptr, CGM.getContext().VoidPtrTy, ImplicitParamKind::Other);
1670
1671 FunctionArgList Args{Dst};
1672 const auto &FI = CGM.getTypes().arrangeBuiltinFunctionDeclaration(
1673 CGM.getContext().VoidPtrTy, Args);
1674 llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
1675 std::string Name = getName({"__kmpc_global_ctor_", ""});
1676 llvm::Function *Fn =
1677 CGM.CreateGlobalInitOrCleanUpFunction(FTy, Name, FI, Loc);
1678 CtorCGF.StartFunction(GlobalDecl(), CGM.getContext().VoidPtrTy, Fn, FI,
1679 Args, Loc, Loc);
1680 llvm::Value *ArgVal = CtorCGF.EmitLoadOfScalar(
1681 CtorCGF.GetAddrOfLocalVar(Dst), /*Volatile=*/false,
1682 CGM.getContext().VoidPtrTy, Dst->getLocation());
1683 Address Arg(ArgVal, CtorCGF.ConvertTypeForMem(ASTTy),
1684 VDAddr.getAlignment());
1685 CtorCGF.EmitAnyExprToMem(Init, Arg, Init->getType().getQualifiers(),
1686 /*IsInitializer=*/true);
1687 ArgVal = CtorCGF.EmitLoadOfScalar(
1688 CtorCGF.GetAddrOfLocalVar(Dst), /*Volatile=*/false,
1689 CGM.getContext().VoidPtrTy, Dst->getLocation());
1690 CtorCGF.Builder.CreateStore(ArgVal, CtorCGF.ReturnValue);
1691 CtorCGF.FinishFunction();
1692 Ctor = Fn;
1693 }
1695 // Generate function that emits destructor call for the threadprivate copy
1696 // of the variable VD
1697 CodeGenFunction DtorCGF(CGM);
1698 auto *Dst = ImplicitParamDecl::Create(
1699 CGM.getContext(), /*DC=*/nullptr, Loc,
1700 /*Id=*/nullptr, CGM.getContext().VoidPtrTy, ImplicitParamKind::Other);
1701
1702 FunctionArgList Args{Dst};
1703 const auto &FI = CGM.getTypes().arrangeBuiltinFunctionDeclaration(
1704 CGM.getContext().VoidTy, Args);
1705 llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
1706 std::string Name = getName({"__kmpc_global_dtor_", ""});
1707 llvm::Function *Fn =
1708 CGM.CreateGlobalInitOrCleanUpFunction(FTy, Name, FI, Loc);
1709 auto NL = ApplyDebugLocation::CreateEmpty(DtorCGF);
1710 DtorCGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, Fn, FI, Args,
1711 Loc, Loc);
1712 // Create a scope with an artificial location for the body of this function.
1713 auto AL = ApplyDebugLocation::CreateArtificial(DtorCGF);
1714 llvm::Value *ArgVal = DtorCGF.EmitLoadOfScalar(
1715 DtorCGF.GetAddrOfLocalVar(Dst),
1716 /*Volatile=*/false, CGM.getContext().VoidPtrTy, Dst->getLocation());
1717 DtorCGF.emitDestroy(
1718 Address(ArgVal, DtorCGF.Int8Ty, VDAddr.getAlignment()), ASTTy,
1719 DtorCGF.getDestroyer(ASTTy.isDestructedType()),
1720 DtorCGF.needsEHCleanup(ASTTy.isDestructedType()));
1721 DtorCGF.FinishFunction();
1722 Dtor = Fn;
1723 }
1724 // Do not emit init function if it is not required.
1725 if (!Ctor && !Dtor)
1726 return nullptr;
1727
1728 // Copying constructor for the threadprivate variable.
1729 // Must be NULL - reserved by runtime, but currently it requires that this
1730 // parameter is always NULL. Otherwise it fires assertion.
1731 CopyCtor = llvm::Constant::getNullValue(CGM.DefaultPtrTy);
1732 if (Ctor == nullptr) {
1733 Ctor = llvm::Constant::getNullValue(CGM.DefaultPtrTy);
1734 }
1735 if (Dtor == nullptr) {
1736 Dtor = llvm::Constant::getNullValue(CGM.DefaultPtrTy);
1737 }
1738 if (!CGF) {
1739 auto *InitFunctionTy =
1740 llvm::FunctionType::get(CGM.VoidTy, /*isVarArg*/ false);
1741 std::string Name = getName({"__omp_threadprivate_init_", ""});
1742 llvm::Function *InitFunction = CGM.CreateGlobalInitOrCleanUpFunction(
1743 InitFunctionTy, Name, CGM.getTypes().arrangeNullaryFunction());
1744 CodeGenFunction InitCGF(CGM);
1745 FunctionArgList ArgList;
1746 InitCGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, InitFunction,
1747 CGM.getTypes().arrangeNullaryFunction(), ArgList,
1748 Loc, Loc);
1749 emitThreadPrivateVarInit(InitCGF, VDAddr, Ctor, CopyCtor, Dtor, Loc);
1750 InitCGF.FinishFunction();
1751 return InitFunction;
1752 }
1753 emitThreadPrivateVarInit(*CGF, VDAddr, Ctor, CopyCtor, Dtor, Loc);
1754 }
1755 return nullptr;
1756}
1757
1759 llvm::GlobalValue *GV) {
1760 std::optional<OMPDeclareTargetDeclAttr *> ActiveAttr =
1761 OMPDeclareTargetDeclAttr::getActiveAttr(FD);
1762
1763 // We only need to handle active 'indirect' declare target functions.
1764 if (!ActiveAttr || !(*ActiveAttr)->getIndirect())
1765 return;
1766
1767 // Get a mangled name to store the new device global in.
1768 llvm::TargetRegionEntryInfo EntryInfo = getEntryInfoFromPresumedLoc(
1770 SmallString<128> Name;
1771 OMPBuilder.OffloadInfoManager.getTargetRegionEntryFnName(Name, EntryInfo);
1772
1773 // We need to generate a new global to hold the address of the indirectly
1774 // called device function. Doing this allows us to keep the visibility and
1775 // linkage of the associated function unchanged while allowing the runtime to
1776 // access its value.
1777 llvm::GlobalValue *Addr = GV;
1778 if (CGM.getLangOpts().OpenMPIsTargetDevice) {
1779 llvm::PointerType *FnPtrTy = llvm::PointerType::get(
1780 CGM.getLLVMContext(),
1781 CGM.getModule().getDataLayout().getProgramAddressSpace());
1782 Addr = new llvm::GlobalVariable(
1783 CGM.getModule(), FnPtrTy,
1784 /*isConstant=*/true, llvm::GlobalValue::ExternalLinkage, GV, Name,
1785 nullptr, llvm::GlobalValue::NotThreadLocal,
1786 CGM.getModule().getDataLayout().getDefaultGlobalsAddressSpace());
1787 Addr->setVisibility(llvm::GlobalValue::ProtectedVisibility);
1788 }
1789
1790 // Register the indirect Vtable:
1791 // This is similar to OMPTargetGlobalVarEntryIndirect, except that the
1792 // size field refers to the size of memory pointed to, not the size of
1793 // the pointer symbol itself (which is implicitly the size of a pointer).
1794 OMPBuilder.OffloadInfoManager.registerDeviceGlobalVarEntryInfo(
1795 Name, Addr, CGM.GetTargetTypeStoreSize(CGM.VoidPtrTy).getQuantity(),
1796 llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryIndirect,
1797 llvm::GlobalValue::WeakODRLinkage);
1798}
1799
1800void CGOpenMPRuntime::registerVTableOffloadEntry(llvm::GlobalVariable *VTable,
1801 const VarDecl *VD) {
1802 // TODO: add logic to avoid duplicate vtable registrations per
1803 // translation unit; though for external linkage, this should no
1804 // longer be an issue - or at least we can avoid the issue by
1805 // checking for an existing offloading entry. But, perhaps the
1806 // better approach is to defer emission of the vtables and offload
1807 // entries until later (by tracking a list of items that need to be
1808 // emitted).
1809
1810 llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
1811
1812 // Generate a new externally visible global to point to the
1813 // internally visible vtable. Doing this allows us to keep the
1814 // visibility and linkage of the associated vtable unchanged while
1815 // allowing the runtime to access its value. The externally
1816 // visible global var needs to be emitted with a unique mangled
1817 // name that won't conflict with similarly named (internal)
1818 // vtables in other translation units.
1819
1820 // Register vtable with source location of dynamic object in map
1821 // clause.
1822 llvm::TargetRegionEntryInfo EntryInfo = getEntryInfoFromPresumedLoc(
1824 VTable->getName());
1825
1826 llvm::GlobalVariable *Addr = VTable;
1827 SmallString<128> AddrName;
1828 OMPBuilder.OffloadInfoManager.getTargetRegionEntryFnName(AddrName, EntryInfo);
1829 AddrName.append("addr");
1830
1831 if (CGM.getLangOpts().OpenMPIsTargetDevice) {
1832 Addr = new llvm::GlobalVariable(
1833 CGM.getModule(), VTable->getType(),
1834 /*isConstant=*/true, llvm::GlobalValue::ExternalLinkage, VTable,
1835 AddrName,
1836 /*InsertBefore=*/nullptr, llvm::GlobalValue::NotThreadLocal,
1837 CGM.getModule().getDataLayout().getDefaultGlobalsAddressSpace());
1838 Addr->setVisibility(llvm::GlobalValue::ProtectedVisibility);
1839 }
1840 OMPBuilder.OffloadInfoManager.registerDeviceGlobalVarEntryInfo(
1841 AddrName, VTable,
1842 CGM.getDataLayout().getTypeAllocSize(VTable->getInitializer()->getType()),
1843 llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryIndirectVTable,
1844 llvm::GlobalValue::WeakODRLinkage);
1845}
1846
1849 const VarDecl *VD) {
1850 // Register C++ VTable to OpenMP Offload Entry if it's a new
1851 // CXXRecordDecl.
1852 if (CXXRecord && CXXRecord->isDynamicClass() &&
1853 !CGM.getOpenMPRuntime().VTableDeclMap.contains(CXXRecord)) {
1854 auto Res = CGM.getOpenMPRuntime().VTableDeclMap.try_emplace(CXXRecord, VD);
1855 if (Res.second) {
1856 CGM.EmitVTable(CXXRecord);
1857 CodeGenVTables VTables = CGM.getVTables();
1858 llvm::GlobalVariable *VTablesAddr = VTables.GetAddrOfVTable(CXXRecord);
1859 assert(VTablesAddr && "Expected non-null VTable address");
1860 // Must set VTables to weak since we're emitting them in multiple TUs now
1861 if (VTablesAddr->hasExternalLinkage())
1862 VTablesAddr->setLinkage(llvm::GlobalValue::WeakODRLinkage);
1863 CGM.getOpenMPRuntime().registerVTableOffloadEntry(VTablesAddr, VD);
1864 // Emit VTable for all the fields containing dynamic CXXRecord
1865 for (const FieldDecl *Field : CXXRecord->fields()) {
1866 if (CXXRecordDecl *RecordDecl = Field->getType()->getAsCXXRecordDecl())
1868 }
1869 // Emit VTable for all dynamic parent class
1870 for (CXXBaseSpecifier &Base : CXXRecord->bases()) {
1871 if (CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl())
1872 emitAndRegisterVTable(CGM, BaseDecl, VD);
1873 }
1874 }
1875 }
1876}
1877
1879 // Register VTable by scanning through the map clause of OpenMP target region.
1880 // Get CXXRecordDecl and VarDecl from Expr.
1881 auto GetVTableDecl = [](const Expr *E) {
1882 QualType VDTy = E->getType();
1883 CXXRecordDecl *CXXRecord = nullptr;
1884 if (const auto *RefType = VDTy->getAs<LValueReferenceType>())
1885 VDTy = RefType->getPointeeType();
1886 if (VDTy->isPointerType())
1888 else
1889 CXXRecord = VDTy->getAsCXXRecordDecl();
1890
1891 const VarDecl *VD = nullptr;
1892 if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
1893 VD = cast<VarDecl>(DRE->getDecl());
1894 } else if (auto *MRE = dyn_cast<MemberExpr>(E)) {
1895 if (auto *BaseDRE = dyn_cast<DeclRefExpr>(MRE->getBase())) {
1896 if (auto *BaseVD = dyn_cast<VarDecl>(BaseDRE->getDecl()))
1897 VD = BaseVD;
1898 }
1899 }
1900 return std::pair<CXXRecordDecl *, const VarDecl *>(CXXRecord, VD);
1901 };
1902 // Collect VTable from OpenMP map clause.
1903 for (const auto *C : D.getClausesOfKind<OMPMapClause>()) {
1904 for (const auto *E : C->varlist()) {
1905 auto DeclPair = GetVTableDecl(E);
1906 // Ensure VD is not null
1907 if (DeclPair.second)
1908 emitAndRegisterVTable(CGM, DeclPair.first, DeclPair.second);
1909 }
1910 }
1911}
1912
1914 QualType VarType,
1915 StringRef Name) {
1916 std::string Suffix = getName({"artificial", ""});
1917 llvm::Type *VarLVType = CGF.ConvertTypeForMem(VarType);
1918 llvm::GlobalVariable *GAddr = OMPBuilder.getOrCreateInternalVariable(
1919 VarLVType, Twine(Name).concat(Suffix).str());
1920 if (CGM.getLangOpts().OpenMP && CGM.getLangOpts().OpenMPUseTLS &&
1921 CGM.getTarget().isTLSSupported()) {
1922 GAddr->setThreadLocal(/*Val=*/true);
1923 return Address(GAddr, GAddr->getValueType(),
1924 CGM.getContext().getTypeAlignInChars(VarType));
1925 }
1926 std::string CacheSuffix = getName({"cache", ""});
1927 llvm::Value *Args[] = {
1930 CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(GAddr, CGM.VoidPtrTy),
1931 CGF.Builder.CreateIntCast(CGF.getTypeSize(VarType), CGM.SizeTy,
1932 /*isSigned=*/false),
1933 OMPBuilder.getOrCreateInternalVariable(
1934 CGM.VoidPtrPtrTy,
1935 Twine(Name).concat(Suffix).concat(CacheSuffix).str())};
1936 return Address(
1938 CGF.EmitRuntimeCall(
1939 OMPBuilder.getOrCreateRuntimeFunction(
1940 CGM.getModule(), OMPRTL___kmpc_threadprivate_cached),
1941 Args),
1942 CGF.Builder.getPtrTy(0)),
1943 VarLVType, CGM.getContext().getTypeAlignInChars(VarType));
1944}
1945
1947 const RegionCodeGenTy &ThenGen,
1948 const RegionCodeGenTy &ElseGen) {
1949 CodeGenFunction::LexicalScope ConditionScope(CGF, Cond->getSourceRange());
1950
1951 // If the condition constant folds and can be elided, try to avoid emitting
1952 // the condition and the dead arm of the if/else.
1953 bool CondConstant;
1954 if (CGF.ConstantFoldsToSimpleInteger(Cond, CondConstant)) {
1955 if (CondConstant)
1956 ThenGen(CGF);
1957 else
1958 ElseGen(CGF);
1959 return;
1960 }
1961
1962 // Otherwise, the condition did not fold, or we couldn't elide it. Just
1963 // emit the conditional branch.
1964 llvm::BasicBlock *ThenBlock = CGF.createBasicBlock("omp_if.then");
1965 llvm::BasicBlock *ElseBlock = CGF.createBasicBlock("omp_if.else");
1966 llvm::BasicBlock *ContBlock = CGF.createBasicBlock("omp_if.end");
1967 CGF.EmitBranchOnBoolExpr(Cond, ThenBlock, ElseBlock, /*TrueCount=*/0);
1968
1969 // Emit the 'then' code.
1970 CGF.EmitBlock(ThenBlock);
1971 ThenGen(CGF);
1972 CGF.EmitBranch(ContBlock);
1973 // Emit the 'else' code if present.
1974 // There is no need to emit line number for unconditional branch.
1976 CGF.EmitBlock(ElseBlock);
1977 ElseGen(CGF);
1978 // There is no need to emit line number for unconditional branch.
1980 CGF.EmitBranch(ContBlock);
1981 // Emit the continuation block for code after the if.
1982 CGF.EmitBlock(ContBlock, /*IsFinished=*/true);
1983}
1984
1986 CodeGenFunction &CGF, SourceLocation Loc, llvm::Function *OutlinedFn,
1987 ArrayRef<llvm::Value *> CapturedVars, const Expr *IfCond,
1988 llvm::Value *NumThreads, OpenMPNumThreadsClauseModifier NumThreadsModifier,
1989 OpenMPSeverityClauseKind Severity, const Expr *Message) {
1990 if (!CGF.HaveInsertPoint())
1991 return;
1992 llvm::Value *RTLoc = emitUpdateLocation(CGF, Loc);
1993 auto &M = CGM.getModule();
1994 auto &&ThenGen = [&M, OutlinedFn, CapturedVars, RTLoc,
1995 this](CodeGenFunction &CGF, PrePostActionTy &) {
1996 // Build call __kmpc_fork_call(loc, n, microtask, var1, .., varn);
1997 llvm::Value *Args[] = {
1998 RTLoc,
1999 CGF.Builder.getInt32(CapturedVars.size()), // Number of captured vars
2000 OutlinedFn};
2002 RealArgs.append(std::begin(Args), std::end(Args));
2003 RealArgs.append(CapturedVars.begin(), CapturedVars.end());
2004
2005 llvm::FunctionCallee RTLFn =
2006 OMPBuilder.getOrCreateRuntimeFunction(M, OMPRTL___kmpc_fork_call);
2007 CGF.EmitRuntimeCall(RTLFn, RealArgs);
2008 };
2009 auto &&ElseGen = [&M, OutlinedFn, CapturedVars, RTLoc, Loc,
2010 this](CodeGenFunction &CGF, PrePostActionTy &) {
2012 llvm::Value *ThreadID = RT.getThreadID(CGF, Loc);
2013 // Build calls:
2014 // __kmpc_serialized_parallel(&Loc, GTid);
2015 llvm::Value *Args[] = {RTLoc, ThreadID};
2016 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
2017 M, OMPRTL___kmpc_serialized_parallel),
2018 Args);
2019
2020 // OutlinedFn(&GTid, &zero_bound, CapturedStruct);
2021 Address ThreadIDAddr = RT.emitThreadIDAddress(CGF, Loc);
2022 RawAddress ZeroAddrBound =
2024 /*Name=*/".bound.zero.addr");
2025 CGF.Builder.CreateStore(CGF.Builder.getInt32(/*C*/ 0), ZeroAddrBound);
2027 // ThreadId for serialized parallels is 0.
2028 OutlinedFnArgs.push_back(ThreadIDAddr.emitRawPointer(CGF));
2029 OutlinedFnArgs.push_back(ZeroAddrBound.getPointer());
2030 OutlinedFnArgs.append(CapturedVars.begin(), CapturedVars.end());
2031
2032 // Ensure we do not inline the function. This is trivially true for the ones
2033 // passed to __kmpc_fork_call but the ones called in serialized regions
2034 // could be inlined. This is not a perfect but it is closer to the invariant
2035 // we want, namely, every data environment starts with a new function.
2036 // TODO: We should pass the if condition to the runtime function and do the
2037 // handling there. Much cleaner code.
2038 OutlinedFn->removeFnAttr(llvm::Attribute::AlwaysInline);
2039 OutlinedFn->addFnAttr(llvm::Attribute::NoInline);
2040 RT.emitOutlinedFunctionCall(CGF, Loc, OutlinedFn, OutlinedFnArgs);
2041
2042 // __kmpc_end_serialized_parallel(&Loc, GTid);
2043 llvm::Value *EndArgs[] = {RT.emitUpdateLocation(CGF, Loc), ThreadID};
2044 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
2045 M, OMPRTL___kmpc_end_serialized_parallel),
2046 EndArgs);
2047 };
2048 if (IfCond) {
2049 emitIfClause(CGF, IfCond, ThenGen, ElseGen);
2050 } else {
2051 RegionCodeGenTy ThenRCG(ThenGen);
2052 ThenRCG(CGF);
2053 }
2054}
2055
2056// If we're inside an (outlined) parallel region, use the region info's
2057// thread-ID variable (it is passed in a first argument of the outlined function
2058// as "kmp_int32 *gtid"). Otherwise, if we're not inside parallel region, but in
2059// regular serial code region, get thread ID by calling kmp_int32
2060// kmpc_global_thread_num(ident_t *loc), stash this thread ID in a temporary and
2061// return the address of that temp.
2063 SourceLocation Loc) {
2064 if (auto *OMPRegionInfo =
2065 dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo))
2066 if (OMPRegionInfo->getThreadIDVariable())
2067 return OMPRegionInfo->getThreadIDVariableLValue(CGF).getAddress();
2068
2069 llvm::Value *ThreadID = getThreadID(CGF, Loc);
2070 QualType Int32Ty =
2071 CGF.getContext().getIntTypeForBitwidth(/*DestWidth*/ 32, /*Signed*/ true);
2072 Address ThreadIDTemp =
2073 CGF.CreateMemTempWithoutCast(Int32Ty, /*Name*/ ".threadid_temp.");
2074 CGF.EmitStoreOfScalar(ThreadID,
2075 CGF.MakeAddrLValue(ThreadIDTemp, Int32Ty));
2076
2077 return ThreadIDTemp;
2078}
2079
2080llvm::Value *CGOpenMPRuntime::getCriticalRegionLock(StringRef CriticalName) {
2081 std::string Prefix = Twine("gomp_critical_user_", CriticalName).str();
2082 std::string Name = getName({Prefix, "var"});
2083 llvm::GlobalVariable *GV =
2084 OMPBuilder.getOrCreateInternalVariable(KmpCriticalNameTy, Name);
2085 CGM.setDSOLocal(GV);
2086 return GV;
2087}
2088
2089namespace {
2090/// Common pre(post)-action for different OpenMP constructs.
2091class CommonActionTy final : public PrePostActionTy {
2092 llvm::FunctionCallee EnterCallee;
2093 ArrayRef<llvm::Value *> EnterArgs;
2094 llvm::FunctionCallee ExitCallee;
2095 ArrayRef<llvm::Value *> ExitArgs;
2096 bool Conditional;
2097 llvm::BasicBlock *ContBlock = nullptr;
2098
2099public:
2100 CommonActionTy(llvm::FunctionCallee EnterCallee,
2101 ArrayRef<llvm::Value *> EnterArgs,
2102 llvm::FunctionCallee ExitCallee,
2103 ArrayRef<llvm::Value *> ExitArgs, bool Conditional = false)
2104 : EnterCallee(EnterCallee), EnterArgs(EnterArgs), ExitCallee(ExitCallee),
2105 ExitArgs(ExitArgs), Conditional(Conditional) {}
2106 void Enter(CodeGenFunction &CGF) override {
2107 llvm::Value *EnterRes = CGF.EmitRuntimeCall(EnterCallee, EnterArgs);
2108 if (Conditional) {
2109 llvm::Value *CallBool = CGF.Builder.CreateIsNotNull(EnterRes);
2110 auto *ThenBlock = CGF.createBasicBlock("omp_if.then");
2111 ContBlock = CGF.createBasicBlock("omp_if.end");
2112 // Generate the branch (If-stmt)
2113 CGF.Builder.CreateCondBr(CallBool, ThenBlock, ContBlock);
2114 CGF.EmitBlock(ThenBlock);
2115 }
2116 }
2117 void Done(CodeGenFunction &CGF) {
2118 // Emit the rest of blocks/branches
2119 CGF.EmitBranch(ContBlock);
2120 CGF.EmitBlock(ContBlock, true);
2121 }
2122 void Exit(CodeGenFunction &CGF) override {
2123 CGF.EmitRuntimeCall(ExitCallee, ExitArgs);
2124 }
2125};
2126} // anonymous namespace
2127
2129 StringRef CriticalName,
2130 const RegionCodeGenTy &CriticalOpGen,
2131 SourceLocation Loc, const Expr *Hint) {
2132 // __kmpc_critical[_with_hint](ident_t *, gtid, Lock[, hint]);
2133 // CriticalOpGen();
2134 // __kmpc_end_critical(ident_t *, gtid, Lock);
2135 // Prepare arguments and build a call to __kmpc_critical
2136 if (!CGF.HaveInsertPoint())
2137 return;
2138 llvm::FunctionCallee RuntimeFcn = OMPBuilder.getOrCreateRuntimeFunction(
2139 CGM.getModule(),
2140 Hint ? OMPRTL___kmpc_critical_with_hint : OMPRTL___kmpc_critical);
2141 llvm::Value *LockVar = getCriticalRegionLock(CriticalName);
2142 unsigned LockVarArgIdx = 2;
2143 if (cast<llvm::GlobalVariable>(LockVar)->getAddressSpace() !=
2144 RuntimeFcn.getFunctionType()
2145 ->getParamType(LockVarArgIdx)
2146 ->getPointerAddressSpace())
2147 LockVar = CGF.Builder.CreateAddrSpaceCast(
2148 LockVar, RuntimeFcn.getFunctionType()->getParamType(LockVarArgIdx));
2149 llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
2150 LockVar};
2151 llvm::SmallVector<llvm::Value *, 4> EnterArgs(std::begin(Args),
2152 std::end(Args));
2153 if (Hint) {
2154 EnterArgs.push_back(CGF.Builder.CreateIntCast(
2155 CGF.EmitScalarExpr(Hint), CGM.Int32Ty, /*isSigned=*/false));
2156 }
2157 CommonActionTy Action(RuntimeFcn, EnterArgs,
2158 OMPBuilder.getOrCreateRuntimeFunction(
2159 CGM.getModule(), OMPRTL___kmpc_end_critical),
2160 Args);
2161 CriticalOpGen.setAction(Action);
2162 emitInlinedDirective(CGF, OMPD_critical, CriticalOpGen);
2163}
2164
2166 const RegionCodeGenTy &MasterOpGen,
2167 SourceLocation Loc) {
2168 if (!CGF.HaveInsertPoint())
2169 return;
2170 // if(__kmpc_master(ident_t *, gtid)) {
2171 // MasterOpGen();
2172 // __kmpc_end_master(ident_t *, gtid);
2173 // }
2174 // Prepare arguments and build a call to __kmpc_master
2175 llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
2176 CommonActionTy Action(OMPBuilder.getOrCreateRuntimeFunction(
2177 CGM.getModule(), OMPRTL___kmpc_master),
2178 Args,
2179 OMPBuilder.getOrCreateRuntimeFunction(
2180 CGM.getModule(), OMPRTL___kmpc_end_master),
2181 Args,
2182 /*Conditional=*/true);
2183 MasterOpGen.setAction(Action);
2184 emitInlinedDirective(CGF, OMPD_master, MasterOpGen);
2185 Action.Done(CGF);
2186}
2187
2189 const RegionCodeGenTy &MaskedOpGen,
2190 SourceLocation Loc, const Expr *Filter) {
2191 if (!CGF.HaveInsertPoint())
2192 return;
2193 // if(__kmpc_masked(ident_t *, gtid, filter)) {
2194 // MaskedOpGen();
2195 // __kmpc_end_masked(iden_t *, gtid);
2196 // }
2197 // Prepare arguments and build a call to __kmpc_masked
2198 llvm::Value *FilterVal = Filter
2199 ? CGF.EmitScalarExpr(Filter, CGF.Int32Ty)
2200 : llvm::ConstantInt::get(CGM.Int32Ty, /*V=*/0);
2201 llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
2202 FilterVal};
2203 llvm::Value *ArgsEnd[] = {emitUpdateLocation(CGF, Loc),
2204 getThreadID(CGF, Loc)};
2205 CommonActionTy Action(OMPBuilder.getOrCreateRuntimeFunction(
2206 CGM.getModule(), OMPRTL___kmpc_masked),
2207 Args,
2208 OMPBuilder.getOrCreateRuntimeFunction(
2209 CGM.getModule(), OMPRTL___kmpc_end_masked),
2210 ArgsEnd,
2211 /*Conditional=*/true);
2212 MaskedOpGen.setAction(Action);
2213 emitInlinedDirective(CGF, OMPD_masked, MaskedOpGen);
2214 Action.Done(CGF);
2215}
2216
2218 SourceLocation Loc) {
2219 if (!CGF.HaveInsertPoint())
2220 return;
2221 if (CGF.CGM.getLangOpts().OpenMPIRBuilder) {
2222 OMPBuilder.createTaskyield(CGF.Builder);
2223 } else {
2224 // Build call __kmpc_omp_taskyield(loc, thread_id, 0);
2225 llvm::Value *Args[] = {
2226 emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
2227 llvm::ConstantInt::get(CGM.IntTy, /*V=*/0, /*isSigned=*/true)};
2228 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
2229 CGM.getModule(), OMPRTL___kmpc_omp_taskyield),
2230 Args);
2231 }
2232
2233 if (auto *Region = dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo))
2234 Region->emitUntiedSwitch(CGF);
2235}
2236
2238 const RegionCodeGenTy &TaskgroupOpGen,
2239 SourceLocation Loc) {
2240 if (!CGF.HaveInsertPoint())
2241 return;
2242 // __kmpc_taskgroup(ident_t *, gtid);
2243 // TaskgroupOpGen();
2244 // __kmpc_end_taskgroup(ident_t *, gtid);
2245 // Prepare arguments and build a call to __kmpc_taskgroup
2246 llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
2247 CommonActionTy Action(OMPBuilder.getOrCreateRuntimeFunction(
2248 CGM.getModule(), OMPRTL___kmpc_taskgroup),
2249 Args,
2250 OMPBuilder.getOrCreateRuntimeFunction(
2251 CGM.getModule(), OMPRTL___kmpc_end_taskgroup),
2252 Args);
2253 TaskgroupOpGen.setAction(Action);
2254 emitInlinedDirective(CGF, OMPD_taskgroup, TaskgroupOpGen);
2255}
2256
2257/// Given an array of pointers to variables, project the address of a
2258/// given variable.
2260 unsigned Index, const VarDecl *Var) {
2261 // Pull out the pointer to the variable.
2262 Address PtrAddr = CGF.Builder.CreateConstArrayGEP(Array, Index);
2263 llvm::Value *Ptr = CGF.Builder.CreateLoad(PtrAddr);
2264
2265 llvm::Type *ElemTy = CGF.ConvertTypeForMem(Var->getType());
2266 return Address(Ptr, ElemTy, CGF.getContext().getDeclAlign(Var));
2267}
2268
2270 CodeGenModule &CGM, llvm::Type *ArgsElemType,
2271 ArrayRef<const Expr *> CopyprivateVars, ArrayRef<const Expr *> DestExprs,
2272 ArrayRef<const Expr *> SrcExprs, ArrayRef<const Expr *> AssignmentOps,
2273 SourceLocation Loc) {
2274 ASTContext &C = CGM.getContext();
2275 // void copy_func(void *LHSArg, void *RHSArg);
2276
2277 auto *LHSArg =
2278 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
2279 C.VoidPtrTy, ImplicitParamKind::Other);
2280 auto *RHSArg =
2281 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
2282 C.VoidPtrTy, ImplicitParamKind::Other);
2283 FunctionArgList Args{LHSArg, RHSArg};
2284 const auto &CGFI =
2285 CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
2286 std::string Name =
2287 CGM.getOpenMPRuntime().getName({"omp", "copyprivate", "copy_func"});
2288 auto *Fn = llvm::Function::Create(CGM.getTypes().GetFunctionType(CGFI),
2289 llvm::GlobalValue::InternalLinkage, Name,
2290 &CGM.getModule());
2292 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
2293 Fn->addFnAttr("sample-profile-suffix-elision-policy", "selected");
2294 Fn->setDoesNotRecurse();
2295 CodeGenFunction CGF(CGM);
2296 CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, CGFI, Args, Loc, Loc);
2297 // Dest = (void*[n])(LHSArg);
2298 // Src = (void*[n])(RHSArg);
2300 CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(LHSArg)),
2301 CGF.Builder.getPtrTy(0)),
2302 ArgsElemType, CGF.getPointerAlign());
2304 CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(RHSArg)),
2305 CGF.Builder.getPtrTy(0)),
2306 ArgsElemType, CGF.getPointerAlign());
2307 // *(Type0*)Dst[0] = *(Type0*)Src[0];
2308 // *(Type1*)Dst[1] = *(Type1*)Src[1];
2309 // ...
2310 // *(Typen*)Dst[n] = *(Typen*)Src[n];
2311 for (unsigned I = 0, E = AssignmentOps.size(); I < E; ++I) {
2312 const auto *DestVar =
2313 cast<VarDecl>(cast<DeclRefExpr>(DestExprs[I])->getDecl());
2314 Address DestAddr = emitAddrOfVarFromArray(CGF, LHS, I, DestVar);
2315
2316 const auto *SrcVar =
2317 cast<VarDecl>(cast<DeclRefExpr>(SrcExprs[I])->getDecl());
2318 Address SrcAddr = emitAddrOfVarFromArray(CGF, RHS, I, SrcVar);
2319
2320 const auto *VD = cast<DeclRefExpr>(CopyprivateVars[I])->getDecl();
2321 QualType Type = VD->getType();
2322 CGF.EmitOMPCopy(Type, DestAddr, SrcAddr, DestVar, SrcVar, AssignmentOps[I]);
2323 }
2324 CGF.FinishFunction();
2325 return Fn;
2326}
2327
2329 const RegionCodeGenTy &SingleOpGen,
2330 SourceLocation Loc,
2331 ArrayRef<const Expr *> CopyprivateVars,
2332 ArrayRef<const Expr *> SrcExprs,
2333 ArrayRef<const Expr *> DstExprs,
2334 ArrayRef<const Expr *> AssignmentOps) {
2335 if (!CGF.HaveInsertPoint())
2336 return;
2337 assert(CopyprivateVars.size() == SrcExprs.size() &&
2338 CopyprivateVars.size() == DstExprs.size() &&
2339 CopyprivateVars.size() == AssignmentOps.size());
2340 ASTContext &C = CGM.getContext();
2341 // int32 did_it = 0;
2342 // if(__kmpc_single(ident_t *, gtid)) {
2343 // SingleOpGen();
2344 // __kmpc_end_single(ident_t *, gtid);
2345 // did_it = 1;
2346 // }
2347 // call __kmpc_copyprivate(ident_t *, gtid, <buf_size>, <copyprivate list>,
2348 // <copy_func>, did_it);
2349
2350 Address DidIt = Address::invalid();
2351 if (!CopyprivateVars.empty()) {
2352 // int32 did_it = 0;
2353 QualType KmpInt32Ty =
2354 C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1);
2355 DidIt = CGF.CreateMemTempWithoutCast(KmpInt32Ty, ".omp.copyprivate.did_it");
2356 CGF.Builder.CreateStore(CGF.Builder.getInt32(0), DidIt);
2357 }
2358 // Prepare arguments and build a call to __kmpc_single
2359 llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
2360 CommonActionTy Action(OMPBuilder.getOrCreateRuntimeFunction(
2361 CGM.getModule(), OMPRTL___kmpc_single),
2362 Args,
2363 OMPBuilder.getOrCreateRuntimeFunction(
2364 CGM.getModule(), OMPRTL___kmpc_end_single),
2365 Args,
2366 /*Conditional=*/true);
2367 SingleOpGen.setAction(Action);
2368 emitInlinedDirective(CGF, OMPD_single, SingleOpGen);
2369 if (DidIt.isValid()) {
2370 // did_it = 1;
2371 CGF.Builder.CreateStore(CGF.Builder.getInt32(1), DidIt);
2372 }
2373 Action.Done(CGF);
2374 // call __kmpc_copyprivate(ident_t *, gtid, <buf_size>, <copyprivate list>,
2375 // <copy_func>, did_it);
2376 if (DidIt.isValid()) {
2377 llvm::APInt ArraySize(/*unsigned int numBits=*/32, CopyprivateVars.size());
2378 QualType CopyprivateArrayTy = C.getConstantArrayType(
2379 C.VoidPtrTy, ArraySize, nullptr, ArraySizeModifier::Normal,
2380 /*IndexTypeQuals=*/0);
2381 // Create a list of all private variables for copyprivate.
2382 Address CopyprivateList = CGF.CreateMemTempWithoutCast(
2383 CopyprivateArrayTy, ".omp.copyprivate.cpr_list");
2384 for (unsigned I = 0, E = CopyprivateVars.size(); I < E; ++I) {
2385 Address Elem = CGF.Builder.CreateConstArrayGEP(CopyprivateList, I);
2386 CGF.Builder.CreateStore(
2388 CGF.EmitLValue(CopyprivateVars[I]).getPointer(CGF),
2389 CGF.VoidPtrTy),
2390 Elem);
2391 }
2392 // Build function that copies private values from single region to all other
2393 // threads in the corresponding parallel region.
2394 llvm::Value *CpyFn = emitCopyprivateCopyFunction(
2395 CGM, CGF.ConvertTypeForMem(CopyprivateArrayTy), CopyprivateVars,
2396 SrcExprs, DstExprs, AssignmentOps, Loc);
2397 llvm::Value *BufSize = CGF.getTypeSize(CopyprivateArrayTy);
2399 CopyprivateList, CGF.VoidPtrTy, CGF.Int8Ty);
2400 llvm::Value *DidItVal = CGF.Builder.CreateLoad(DidIt);
2401 llvm::Value *Args[] = {
2402 emitUpdateLocation(CGF, Loc), // ident_t *<loc>
2403 getThreadID(CGF, Loc), // i32 <gtid>
2404 BufSize, // size_t <buf_size>
2405 CL.emitRawPointer(CGF), // void *<copyprivate list>
2406 CpyFn, // void (*) (void *, void *) <copy_func>
2407 DidItVal // i32 did_it
2408 };
2409 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
2410 CGM.getModule(), OMPRTL___kmpc_copyprivate),
2411 Args);
2412 }
2413}
2414
2416 const RegionCodeGenTy &OrderedOpGen,
2417 SourceLocation Loc, bool IsThreads) {
2418 if (!CGF.HaveInsertPoint())
2419 return;
2420 // __kmpc_ordered(ident_t *, gtid);
2421 // OrderedOpGen();
2422 // __kmpc_end_ordered(ident_t *, gtid);
2423 // Prepare arguments and build a call to __kmpc_ordered
2424 if (IsThreads) {
2425 llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
2426 CommonActionTy Action(OMPBuilder.getOrCreateRuntimeFunction(
2427 CGM.getModule(), OMPRTL___kmpc_ordered),
2428 Args,
2429 OMPBuilder.getOrCreateRuntimeFunction(
2430 CGM.getModule(), OMPRTL___kmpc_end_ordered),
2431 Args);
2432 OrderedOpGen.setAction(Action);
2433 emitInlinedDirective(CGF, OMPD_ordered_blockassoc, OrderedOpGen);
2434 return;
2435 }
2436 emitInlinedDirective(CGF, OMPD_ordered_blockassoc, OrderedOpGen);
2437}
2438
2440 unsigned Flags;
2441 if (Kind == OMPD_for)
2442 Flags = OMP_IDENT_BARRIER_IMPL_FOR;
2443 else if (Kind == OMPD_sections)
2444 Flags = OMP_IDENT_BARRIER_IMPL_SECTIONS;
2445 else if (Kind == OMPD_single)
2446 Flags = OMP_IDENT_BARRIER_IMPL_SINGLE;
2447 else if (Kind == OMPD_barrier)
2448 Flags = OMP_IDENT_BARRIER_EXPL;
2449 else
2450 Flags = OMP_IDENT_BARRIER_IMPL;
2451 return Flags;
2452}
2453
2455 CodeGenFunction &CGF, const OMPLoopDirective &S,
2456 OpenMPScheduleClauseKind &ScheduleKind, const Expr *&ChunkExpr) const {
2457 // Check if the loop directive is actually a doacross loop directive. In this
2458 // case choose static, 1 schedule.
2459 if (llvm::any_of(
2460 S.getClausesOfKind<OMPOrderedClause>(),
2461 [](const OMPOrderedClause *C) { return C->getNumForLoops(); })) {
2462 ScheduleKind = OMPC_SCHEDULE_static;
2463 // Chunk size is 1 in this case.
2464 llvm::APInt ChunkSize(32, 1);
2465 ChunkExpr = IntegerLiteral::Create(
2466 CGF.getContext(), ChunkSize,
2467 CGF.getContext().getIntTypeForBitwidth(32, /*Signed=*/0),
2468 SourceLocation());
2469 }
2470}
2471
2473 OpenMPDirectiveKind Kind, bool EmitChecks,
2474 bool ForceSimpleCall) {
2475 // Check if we should use the OMPBuilder
2476 auto *OMPRegionInfo =
2477 dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo);
2478 if (CGF.CGM.getLangOpts().OpenMPIRBuilder) {
2479 llvm::OpenMPIRBuilder::InsertPointTy AfterIP =
2480 cantFail(OMPBuilder.createBarrier(CGF.Builder, Kind, ForceSimpleCall,
2481 EmitChecks));
2482 CGF.Builder.restoreIP(AfterIP);
2483 return;
2484 }
2485
2486 if (!CGF.HaveInsertPoint())
2487 return;
2488 // Build call __kmpc_cancel_barrier(loc, thread_id);
2489 // Build call __kmpc_barrier(loc, thread_id);
2490 unsigned Flags = getDefaultFlagsForBarriers(Kind);
2491 // Build call __kmpc_cancel_barrier(loc, thread_id) or __kmpc_barrier(loc,
2492 // thread_id);
2493 llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc, Flags),
2494 getThreadID(CGF, Loc)};
2495 if (OMPRegionInfo) {
2496 if (!ForceSimpleCall && OMPRegionInfo->hasCancel()) {
2497 llvm::Value *Result = CGF.EmitRuntimeCall(
2498 OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(),
2499 OMPRTL___kmpc_cancel_barrier),
2500 Args);
2501 if (EmitChecks) {
2502 // if (__kmpc_cancel_barrier()) {
2503 // exit from construct;
2504 // }
2505 llvm::BasicBlock *ExitBB = CGF.createBasicBlock(".cancel.exit");
2506 llvm::BasicBlock *ContBB = CGF.createBasicBlock(".cancel.continue");
2507 llvm::Value *Cmp = CGF.Builder.CreateIsNotNull(Result);
2508 CGF.Builder.CreateCondBr(Cmp, ExitBB, ContBB);
2509 CGF.EmitBlock(ExitBB);
2510 // exit from construct;
2511 CodeGenFunction::JumpDest CancelDestination =
2512 CGF.getOMPCancelDestination(OMPRegionInfo->getDirectiveKind());
2513 CGF.EmitBranchThroughCleanup(CancelDestination);
2514 CGF.EmitBlock(ContBB, /*IsFinished=*/true);
2515 }
2516 return;
2517 }
2518 }
2519 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
2520 CGM.getModule(), OMPRTL___kmpc_barrier),
2521 Args);
2522}
2523
2525 Expr *ME, bool IsFatal) {
2526 llvm::Value *MVL = ME ? CGF.EmitScalarExpr(ME)
2527 : llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
2528 // Build call void __kmpc_error(ident_t *loc, int severity, const char
2529 // *message)
2530 llvm::Value *Args[] = {
2531 emitUpdateLocation(CGF, Loc, /*Flags=*/0, /*GenLoc=*/true),
2532 llvm::ConstantInt::get(CGM.Int32Ty, IsFatal ? 2 : 1),
2533 CGF.Builder.CreatePointerCast(MVL, CGM.Int8PtrTy)};
2534 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
2535 CGM.getModule(), OMPRTL___kmpc_error),
2536 Args);
2537}
2538
2539/// Map the OpenMP loop schedule to the runtime enumeration.
2540static OpenMPSchedType getRuntimeSchedule(OpenMPScheduleClauseKind ScheduleKind,
2541 bool Chunked, bool Ordered) {
2542 switch (ScheduleKind) {
2543 case OMPC_SCHEDULE_static:
2544 return Chunked ? (Ordered ? OMP_ord_static_chunked : OMP_sch_static_chunked)
2545 : (Ordered ? OMP_ord_static : OMP_sch_static);
2546 case OMPC_SCHEDULE_dynamic:
2547 return Ordered ? OMP_ord_dynamic_chunked : OMP_sch_dynamic_chunked;
2548 case OMPC_SCHEDULE_guided:
2549 return Ordered ? OMP_ord_guided_chunked : OMP_sch_guided_chunked;
2550 case OMPC_SCHEDULE_runtime:
2551 return Ordered ? OMP_ord_runtime : OMP_sch_runtime;
2552 case OMPC_SCHEDULE_auto:
2553 return Ordered ? OMP_ord_auto : OMP_sch_auto;
2555 assert(!Chunked && "chunk was specified but schedule kind not known");
2556 return Ordered ? OMP_ord_static : OMP_sch_static;
2557 }
2558 llvm_unreachable("Unexpected runtime schedule");
2559}
2560
2561/// Map the OpenMP distribute schedule to the runtime enumeration.
2562static OpenMPSchedType
2564 // only static is allowed for dist_schedule
2565 return Chunked ? OMP_dist_sch_static_chunked : OMP_dist_sch_static;
2566}
2567
2569 bool Chunked) const {
2570 OpenMPSchedType Schedule =
2571 getRuntimeSchedule(ScheduleKind, Chunked, /*Ordered=*/false);
2572 return Schedule == OMP_sch_static;
2573}
2574
2576 OpenMPDistScheduleClauseKind ScheduleKind, bool Chunked) const {
2577 OpenMPSchedType Schedule = getRuntimeSchedule(ScheduleKind, Chunked);
2578 return Schedule == OMP_dist_sch_static;
2579}
2580
2582 bool Chunked) const {
2583 OpenMPSchedType Schedule =
2584 getRuntimeSchedule(ScheduleKind, Chunked, /*Ordered=*/false);
2585 return Schedule == OMP_sch_static_chunked;
2586}
2587
2589 OpenMPDistScheduleClauseKind ScheduleKind, bool Chunked) const {
2590 OpenMPSchedType Schedule = getRuntimeSchedule(ScheduleKind, Chunked);
2591 return Schedule == OMP_dist_sch_static_chunked;
2592}
2593
2595 OpenMPSchedType Schedule =
2596 getRuntimeSchedule(ScheduleKind, /*Chunked=*/false, /*Ordered=*/false);
2597 assert(Schedule != OMP_sch_static_chunked && "cannot be chunked here");
2598 return Schedule != OMP_sch_static;
2599}
2600
2601static int addMonoNonMonoModifier(CodeGenModule &CGM, OpenMPSchedType Schedule,
2604 int Modifier = 0;
2605 switch (M1) {
2606 case OMPC_SCHEDULE_MODIFIER_monotonic:
2607 Modifier = OMP_sch_modifier_monotonic;
2608 break;
2609 case OMPC_SCHEDULE_MODIFIER_nonmonotonic:
2610 Modifier = OMP_sch_modifier_nonmonotonic;
2611 break;
2612 case OMPC_SCHEDULE_MODIFIER_simd:
2613 if (Schedule == OMP_sch_static_chunked)
2614 Schedule = OMP_sch_static_balanced_chunked;
2615 break;
2618 break;
2619 }
2620 switch (M2) {
2621 case OMPC_SCHEDULE_MODIFIER_monotonic:
2622 Modifier = OMP_sch_modifier_monotonic;
2623 break;
2624 case OMPC_SCHEDULE_MODIFIER_nonmonotonic:
2625 Modifier = OMP_sch_modifier_nonmonotonic;
2626 break;
2627 case OMPC_SCHEDULE_MODIFIER_simd:
2628 if (Schedule == OMP_sch_static_chunked)
2629 Schedule = OMP_sch_static_balanced_chunked;
2630 break;
2633 break;
2634 }
2635 // OpenMP 5.0, 2.9.2 Worksharing-Loop Construct, Desription.
2636 // If the static schedule kind is specified or if the ordered clause is
2637 // specified, and if the nonmonotonic modifier is not specified, the effect is
2638 // as if the monotonic modifier is specified. Otherwise, unless the monotonic
2639 // modifier is specified, the effect is as if the nonmonotonic modifier is
2640 // specified.
2641 if (CGM.getLangOpts().OpenMP >= 50 && Modifier == 0) {
2642 if (!(Schedule == OMP_sch_static_chunked || Schedule == OMP_sch_static ||
2643 Schedule == OMP_sch_static_balanced_chunked ||
2644 Schedule == OMP_ord_static_chunked || Schedule == OMP_ord_static ||
2645 Schedule == OMP_dist_sch_static_chunked ||
2646 Schedule == OMP_dist_sch_static ||
2647 Schedule == OMP_dist_sch_static_chunked_sch_static_chunkone))
2648 Modifier = OMP_sch_modifier_nonmonotonic;
2649 }
2650 return Schedule | Modifier;
2651}
2652
2655 const OpenMPScheduleTy &ScheduleKind, unsigned IVSize, bool IVSigned,
2656 bool Ordered, const DispatchRTInput &DispatchValues) {
2657 if (!CGF.HaveInsertPoint())
2658 return;
2659 OpenMPSchedType Schedule = getRuntimeSchedule(
2660 ScheduleKind.Schedule, DispatchValues.Chunk != nullptr, Ordered);
2661 assert(Ordered ||
2662 (Schedule != OMP_sch_static && Schedule != OMP_sch_static_chunked &&
2663 Schedule != OMP_ord_static && Schedule != OMP_ord_static_chunked &&
2664 Schedule != OMP_sch_static_balanced_chunked));
2665 // Call __kmpc_dispatch_init(
2666 // ident_t *loc, kmp_int32 tid, kmp_int32 schedule,
2667 // kmp_int[32|64] lower, kmp_int[32|64] upper,
2668 // kmp_int[32|64] stride, kmp_int[32|64] chunk);
2669
2670 // If the Chunk was not specified in the clause - use default value 1.
2671 llvm::Value *Chunk = DispatchValues.Chunk ? DispatchValues.Chunk
2672 : CGF.Builder.getIntN(IVSize, 1);
2673 llvm::Value *Args[] = {
2674 emitUpdateLocation(CGF, Loc),
2675 getThreadID(CGF, Loc),
2676 CGF.Builder.getInt32(addMonoNonMonoModifier(
2677 CGM, Schedule, ScheduleKind.M1, ScheduleKind.M2)), // Schedule type
2678 DispatchValues.LB, // Lower
2679 DispatchValues.UB, // Upper
2680 CGF.Builder.getIntN(IVSize, 1), // Stride
2681 Chunk // Chunk
2682 };
2683 CGF.EmitRuntimeCall(OMPBuilder.createDispatchInitFunction(IVSize, IVSigned),
2684 Args);
2685}
2686
2688 SourceLocation Loc) {
2689 if (!CGF.HaveInsertPoint())
2690 return;
2691 // Call __kmpc_dispatch_deinit(ident_t *loc, kmp_int32 tid);
2692 llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
2693 CGF.EmitRuntimeCall(OMPBuilder.createDispatchDeinitFunction(), Args);
2694}
2695
2697 CodeGenFunction &CGF, llvm::Value *UpdateLocation, llvm::Value *ThreadId,
2698 llvm::FunctionCallee ForStaticInitFunction, OpenMPSchedType Schedule,
2700 const CGOpenMPRuntime::StaticRTInput &Values) {
2701 if (!CGF.HaveInsertPoint())
2702 return;
2703
2704 assert(!Values.Ordered);
2705 assert(Schedule == OMP_sch_static || Schedule == OMP_sch_static_chunked ||
2706 Schedule == OMP_sch_static_balanced_chunked ||
2707 Schedule == OMP_ord_static || Schedule == OMP_ord_static_chunked ||
2708 Schedule == OMP_dist_sch_static ||
2709 Schedule == OMP_dist_sch_static_chunked ||
2710 Schedule == OMP_dist_sch_static_chunked_sch_static_chunkone);
2711
2712 // Call __kmpc_for_static_init(
2713 // ident_t *loc, kmp_int32 tid, kmp_int32 schedtype,
2714 // kmp_int32 *p_lastiter, kmp_int[32|64] *p_lower,
2715 // kmp_int[32|64] *p_upper, kmp_int[32|64] *p_stride,
2716 // kmp_int[32|64] incr, kmp_int[32|64] chunk);
2717 llvm::Value *Chunk = Values.Chunk;
2718 if (Chunk == nullptr) {
2719 assert((Schedule == OMP_sch_static || Schedule == OMP_ord_static ||
2720 Schedule == OMP_dist_sch_static) &&
2721 "expected static non-chunked schedule");
2722 // If the Chunk was not specified in the clause - use default value 1.
2723 Chunk = CGF.Builder.getIntN(Values.IVSize, 1);
2724 } else {
2725 assert((Schedule == OMP_sch_static_chunked ||
2726 Schedule == OMP_sch_static_balanced_chunked ||
2727 Schedule == OMP_ord_static_chunked ||
2728 Schedule == OMP_dist_sch_static_chunked ||
2729 Schedule == OMP_dist_sch_static_chunked_sch_static_chunkone) &&
2730 "expected static chunked schedule");
2731 }
2732 llvm::Value *Args[] = {
2733 UpdateLocation,
2734 ThreadId,
2735 CGF.Builder.getInt32(addMonoNonMonoModifier(CGF.CGM, Schedule, M1,
2736 M2)), // Schedule type
2737 Values.IL.emitRawPointer(CGF), // &isLastIter
2738 Values.LB.emitRawPointer(CGF), // &LB
2739 Values.UB.emitRawPointer(CGF), // &UB
2740 Values.ST.emitRawPointer(CGF), // &Stride
2741 CGF.Builder.getIntN(Values.IVSize, 1), // Incr
2742 Chunk // Chunk
2743 };
2744 CGF.EmitRuntimeCall(ForStaticInitFunction, Args);
2745}
2746
2748 SourceLocation Loc,
2749 OpenMPDirectiveKind DKind,
2750 const OpenMPScheduleTy &ScheduleKind,
2751 const StaticRTInput &Values) {
2752 OpenMPSchedType ScheduleNum =
2753 ScheduleKind.UseFusedDistChunkSchedule
2754 ? OMP_dist_sch_static_chunked_sch_static_chunkone
2755 : getRuntimeSchedule(ScheduleKind.Schedule, Values.Chunk != nullptr,
2756 Values.Ordered);
2757 assert((isOpenMPWorksharingDirective(DKind) || (DKind == OMPD_loop)) &&
2758 "Expected loop-based or sections-based directive.");
2759 llvm::Value *UpdatedLocation = emitUpdateLocation(CGF, Loc,
2761 ? OMP_IDENT_WORK_LOOP
2762 : OMP_IDENT_WORK_SECTIONS);
2763 llvm::Value *ThreadId = getThreadID(CGF, Loc);
2764 llvm::FunctionCallee StaticInitFunction =
2765 OMPBuilder.createForStaticInitFunction(Values.IVSize, Values.IVSigned,
2766 false);
2768 emitForStaticInitCall(CGF, UpdatedLocation, ThreadId, StaticInitFunction,
2769 ScheduleNum, ScheduleKind.M1, ScheduleKind.M2, Values);
2770}
2771
2775 const CGOpenMPRuntime::StaticRTInput &Values) {
2776 OpenMPSchedType ScheduleNum =
2777 getRuntimeSchedule(SchedKind, Values.Chunk != nullptr);
2778 llvm::Value *UpdatedLocation =
2779 emitUpdateLocation(CGF, Loc, OMP_IDENT_WORK_DISTRIBUTE);
2780 llvm::Value *ThreadId = getThreadID(CGF, Loc);
2781 llvm::FunctionCallee StaticInitFunction;
2782 bool isGPUDistribute =
2783 CGM.getLangOpts().OpenMPIsTargetDevice && CGM.getTriple().isGPU();
2784 StaticInitFunction = OMPBuilder.createForStaticInitFunction(
2785 Values.IVSize, Values.IVSigned, isGPUDistribute);
2786
2787 emitForStaticInitCall(CGF, UpdatedLocation, ThreadId, StaticInitFunction,
2788 ScheduleNum, OMPC_SCHEDULE_MODIFIER_unknown,
2790}
2791
2793 SourceLocation Loc,
2794 OpenMPDirectiveKind DKind) {
2795 assert((DKind == OMPD_distribute || DKind == OMPD_for ||
2796 DKind == OMPD_sections) &&
2797 "Expected distribute, for, or sections directive kind");
2798 if (!CGF.HaveInsertPoint())
2799 return;
2800 // Call __kmpc_for_static_fini(ident_t *loc, kmp_int32 tid);
2801 llvm::Value *Args[] = {
2802 emitUpdateLocation(CGF, Loc,
2804 (DKind == OMPD_target_teams_loop)
2805 ? OMP_IDENT_WORK_DISTRIBUTE
2806 : isOpenMPLoopDirective(DKind)
2807 ? OMP_IDENT_WORK_LOOP
2808 : OMP_IDENT_WORK_SECTIONS),
2809 getThreadID(CGF, Loc)};
2811 if (isOpenMPDistributeDirective(DKind) &&
2812 CGM.getLangOpts().OpenMPIsTargetDevice && CGM.getTriple().isGPU())
2813 CGF.EmitRuntimeCall(
2814 OMPBuilder.getOrCreateRuntimeFunction(
2815 CGM.getModule(), OMPRTL___kmpc_distribute_static_fini),
2816 Args);
2817 else
2818 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
2819 CGM.getModule(), OMPRTL___kmpc_for_static_fini),
2820 Args);
2821}
2822
2824 SourceLocation Loc,
2825 unsigned IVSize,
2826 bool IVSigned) {
2827 if (!CGF.HaveInsertPoint())
2828 return;
2829 // Call __kmpc_for_dynamic_fini_(4|8)[u](ident_t *loc, kmp_int32 tid);
2830 llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
2831 CGF.EmitRuntimeCall(OMPBuilder.createDispatchFiniFunction(IVSize, IVSigned),
2832 Args);
2833}
2834
2836 SourceLocation Loc, unsigned IVSize,
2837 bool IVSigned, Address IL,
2838 Address LB, Address UB,
2839 Address ST) {
2840 // Call __kmpc_dispatch_next(
2841 // ident_t *loc, kmp_int32 tid, kmp_int32 *p_lastiter,
2842 // kmp_int[32|64] *p_lower, kmp_int[32|64] *p_upper,
2843 // kmp_int[32|64] *p_stride);
2844 llvm::Value *Args[] = {
2845 emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
2846 IL.emitRawPointer(CGF), // &isLastIter
2847 LB.emitRawPointer(CGF), // &Lower
2848 UB.emitRawPointer(CGF), // &Upper
2849 ST.emitRawPointer(CGF) // &Stride
2850 };
2851 llvm::Value *Call = CGF.EmitRuntimeCall(
2852 OMPBuilder.createDispatchNextFunction(IVSize, IVSigned), Args);
2853 return CGF.EmitScalarConversion(
2854 Call, CGF.getContext().getIntTypeForBitwidth(32, /*Signed=*/1),
2855 CGF.getContext().BoolTy, Loc);
2856}
2857
2859 const Expr *Message,
2860 SourceLocation Loc) {
2861 if (!Message)
2862 return llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
2863 return CGF.EmitScalarExpr(Message);
2864}
2865
2866llvm::Value *
2868 SourceLocation Loc) {
2869 // OpenMP 6.0, 10.4: "If no severity clause is specified then the effect is
2870 // as if sev-level is fatal."
2871 return llvm::ConstantInt::get(CGM.Int32Ty,
2872 Severity == OMPC_SEVERITY_warning ? 1 : 2);
2873}
2874
2876 CodeGenFunction &CGF, llvm::Value *NumThreads, SourceLocation Loc,
2878 SourceLocation SeverityLoc, const Expr *Message,
2879 SourceLocation MessageLoc) {
2880 if (!CGF.HaveInsertPoint())
2881 return;
2883 {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
2884 CGF.Builder.CreateIntCast(NumThreads, CGF.Int32Ty, /*isSigned*/ true)});
2885 // Build call __kmpc_push_num_threads(&loc, global_tid, num_threads)
2886 // or __kmpc_push_num_threads_strict(&loc, global_tid, num_threads, severity,
2887 // messsage) if strict modifier is used.
2888 RuntimeFunction FnID = OMPRTL___kmpc_push_num_threads;
2889 if (Modifier == OMPC_NUMTHREADS_strict) {
2890 FnID = OMPRTL___kmpc_push_num_threads_strict;
2891 Args.push_back(emitSeverityClause(Severity, SeverityLoc));
2892 Args.push_back(emitMessageClause(CGF, Message, MessageLoc));
2893 }
2894 CGF.EmitRuntimeCall(
2895 OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(), FnID), Args);
2896}
2897
2899 ProcBindKind ProcBind,
2900 SourceLocation Loc) {
2901 if (!CGF.HaveInsertPoint())
2902 return;
2903 assert(ProcBind != OMP_PROC_BIND_unknown && "Unsupported proc_bind value.");
2904 // Build call __kmpc_push_proc_bind(&loc, global_tid, proc_bind)
2905 llvm::Value *Args[] = {
2906 emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
2907 llvm::ConstantInt::get(CGM.IntTy, unsigned(ProcBind), /*isSigned=*/true)};
2908 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
2909 CGM.getModule(), OMPRTL___kmpc_push_proc_bind),
2910 Args);
2911}
2912
2914 SourceLocation Loc, llvm::AtomicOrdering AO) {
2915 if (CGF.CGM.getLangOpts().OpenMPIRBuilder) {
2916 OMPBuilder.createFlush(CGF.Builder);
2917 } else {
2918 if (!CGF.HaveInsertPoint())
2919 return;
2920 // Build call void __kmpc_flush(ident_t *loc)
2921 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
2922 CGM.getModule(), OMPRTL___kmpc_flush),
2923 emitUpdateLocation(CGF, Loc));
2924 }
2925}
2926
2927namespace {
2928/// Indexes of fields for type kmp_task_t.
2929enum KmpTaskTFields {
2930 /// List of shared variables.
2931 KmpTaskTShareds,
2932 /// Task routine.
2933 KmpTaskTRoutine,
2934 /// Partition id for the untied tasks.
2935 KmpTaskTPartId,
2936 /// Function with call of destructors for private variables.
2937 Data1,
2938 /// Task priority.
2939 Data2,
2940 /// (Taskloops only) Lower bound.
2941 KmpTaskTLowerBound,
2942 /// (Taskloops only) Upper bound.
2943 KmpTaskTUpperBound,
2944 /// (Taskloops only) Stride.
2945 KmpTaskTStride,
2946 /// (Taskloops only) Is last iteration flag.
2947 KmpTaskTLastIter,
2948 /// (Taskloops only) Reduction data.
2949 KmpTaskTReductions,
2950};
2951} // anonymous namespace
2952
2954 // If we are in simd mode or there are no entries, we don't need to do
2955 // anything.
2956 if (CGM.getLangOpts().OpenMPSimd || OMPBuilder.OffloadInfoManager.empty())
2957 return;
2958
2959 llvm::OpenMPIRBuilder::EmitMetadataErrorReportFunctionTy &&ErrorReportFn =
2960 [this](llvm::OpenMPIRBuilder::EmitMetadataErrorKind Kind,
2961 const llvm::TargetRegionEntryInfo &EntryInfo) -> void {
2962 SourceLocation Loc;
2963 if (Kind != llvm::OpenMPIRBuilder::EMIT_MD_GLOBAL_VAR_LINK_ERROR) {
2964 for (auto I = CGM.getContext().getSourceManager().fileinfo_begin(),
2965 E = CGM.getContext().getSourceManager().fileinfo_end();
2966 I != E; ++I) {
2967 if (I->getFirst().getUniqueID().getDevice() == EntryInfo.DeviceID &&
2968 I->getFirst().getUniqueID().getFile() == EntryInfo.FileID) {
2969 Loc = CGM.getContext().getSourceManager().translateFileLineCol(
2970 I->getFirst(), EntryInfo.Line, 1);
2971 break;
2972 }
2973 }
2974 }
2975 switch (Kind) {
2976 case llvm::OpenMPIRBuilder::EMIT_MD_TARGET_REGION_ERROR: {
2977 CGM.getDiags().Report(Loc,
2978 diag::err_target_region_offloading_entry_incorrect)
2979 << EntryInfo.ParentName;
2980 } break;
2981 case llvm::OpenMPIRBuilder::EMIT_MD_DECLARE_TARGET_ERROR: {
2982 CGM.getDiags().Report(
2983 Loc, diag::err_target_var_offloading_entry_incorrect_with_parent)
2984 << EntryInfo.ParentName;
2985 } break;
2986 case llvm::OpenMPIRBuilder::EMIT_MD_GLOBAL_VAR_LINK_ERROR: {
2987 CGM.getDiags().Report(diag::err_target_var_offloading_entry_incorrect);
2988 } break;
2989 case llvm::OpenMPIRBuilder::EMIT_MD_GLOBAL_VAR_INDIRECT_ERROR: {
2990 unsigned DiagID = CGM.getDiags().getCustomDiagID(
2991 DiagnosticsEngine::Error, "Offloading entry for indirect declare "
2992 "target variable is incorrect: the "
2993 "address is invalid.");
2994 CGM.getDiags().Report(DiagID);
2995 } break;
2996 }
2997 };
2998
2999 OMPBuilder.createOffloadEntriesAndInfoMetadata(ErrorReportFn);
3000}
3001
3003 if (!KmpRoutineEntryPtrTy) {
3004 // Build typedef kmp_int32 (* kmp_routine_entry_t)(kmp_int32, void *); type.
3005 ASTContext &C = CGM.getContext();
3006 QualType KmpRoutineEntryTyArgs[] = {KmpInt32Ty, C.VoidPtrTy};
3008 KmpRoutineEntryPtrQTy = C.getPointerType(
3009 C.getFunctionType(KmpInt32Ty, KmpRoutineEntryTyArgs, EPI));
3010 KmpRoutineEntryPtrTy = CGM.getTypes().ConvertType(KmpRoutineEntryPtrQTy);
3011 }
3012}
3013
3014namespace {
3015struct PrivateHelpersTy {
3016 PrivateHelpersTy(const Expr *OriginalRef, const VarDecl *Original,
3017 const VarDecl *PrivateCopy, const VarDecl *PrivateElemInit)
3018 : OriginalRef(OriginalRef), Original(Original), PrivateCopy(PrivateCopy),
3019 PrivateElemInit(PrivateElemInit) {}
3020 PrivateHelpersTy(const VarDecl *Original) : Original(Original) {}
3021 const Expr *OriginalRef = nullptr;
3022 const VarDecl *Original = nullptr;
3023 const VarDecl *PrivateCopy = nullptr;
3024 const VarDecl *PrivateElemInit = nullptr;
3025 bool isLocalPrivate() const {
3026 return !OriginalRef && !PrivateCopy && !PrivateElemInit;
3027 }
3028};
3029typedef std::pair<CharUnits /*Align*/, PrivateHelpersTy> PrivateDataTy;
3030} // anonymous namespace
3031
3032static bool isAllocatableDecl(const VarDecl *VD) {
3033 const VarDecl *CVD = VD->getCanonicalDecl();
3034 if (!CVD->hasAttr<OMPAllocateDeclAttr>())
3035 return false;
3036 const auto *AA = CVD->getAttr<OMPAllocateDeclAttr>();
3037 // Use the default allocation.
3038 return !(AA->getAllocatorType() == OMPAllocateDeclAttr::OMPDefaultMemAlloc &&
3039 !AA->getAllocator());
3040}
3041
3042static RecordDecl *
3044 if (!Privates.empty()) {
3045 ASTContext &C = CGM.getContext();
3046 // Build struct .kmp_privates_t. {
3047 // /* private vars */
3048 // };
3049 RecordDecl *RD = C.buildImplicitRecord(".kmp_privates.t");
3050 RD->startDefinition();
3051 for (const auto &Pair : Privates) {
3052 const VarDecl *VD = Pair.second.Original;
3054 // If the private variable is a local variable with lvalue ref type,
3055 // allocate the pointer instead of the pointee type.
3056 if (Pair.second.isLocalPrivate()) {
3057 if (VD->getType()->isLValueReferenceType())
3058 Type = C.getPointerType(Type);
3059 if (isAllocatableDecl(VD))
3060 Type = C.getPointerType(Type);
3061 }
3063 if (VD->hasAttrs()) {
3064 for (specific_attr_iterator<AlignedAttr> I(VD->getAttrs().begin()),
3065 E(VD->getAttrs().end());
3066 I != E; ++I)
3067 FD->addAttr(*I);
3068 }
3069 }
3070 RD->completeDefinition();
3071 return RD;
3072 }
3073 return nullptr;
3074}
3075
3076static RecordDecl *
3078 QualType KmpInt32Ty,
3079 QualType KmpRoutineEntryPointerQTy) {
3080 ASTContext &C = CGM.getContext();
3081 // Build struct kmp_task_t {
3082 // void * shareds;
3083 // kmp_routine_entry_t routine;
3084 // kmp_int32 part_id;
3085 // kmp_cmplrdata_t data1;
3086 // kmp_cmplrdata_t data2;
3087 // For taskloops additional fields:
3088 // kmp_uint64 lb;
3089 // kmp_uint64 ub;
3090 // kmp_int64 st;
3091 // kmp_int32 liter;
3092 // void * reductions;
3093 // };
3094 RecordDecl *UD = C.buildImplicitRecord("kmp_cmplrdata_t", TagTypeKind::Union);
3095 UD->startDefinition();
3096 addFieldToRecordDecl(C, UD, KmpInt32Ty);
3097 addFieldToRecordDecl(C, UD, KmpRoutineEntryPointerQTy);
3098 UD->completeDefinition();
3099 CanQualType KmpCmplrdataTy = C.getCanonicalTagType(UD);
3100 RecordDecl *RD = C.buildImplicitRecord("kmp_task_t");
3101 RD->startDefinition();
3102 addFieldToRecordDecl(C, RD, C.VoidPtrTy);
3103 addFieldToRecordDecl(C, RD, KmpRoutineEntryPointerQTy);
3104 addFieldToRecordDecl(C, RD, KmpInt32Ty);
3105 addFieldToRecordDecl(C, RD, KmpCmplrdataTy);
3106 addFieldToRecordDecl(C, RD, KmpCmplrdataTy);
3107 if (isOpenMPTaskLoopDirective(Kind)) {
3108 QualType KmpUInt64Ty =
3109 CGM.getContext().getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/0);
3110 QualType KmpInt64Ty =
3111 CGM.getContext().getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1);
3112 addFieldToRecordDecl(C, RD, KmpUInt64Ty);
3113 addFieldToRecordDecl(C, RD, KmpUInt64Ty);
3114 addFieldToRecordDecl(C, RD, KmpInt64Ty);
3115 addFieldToRecordDecl(C, RD, KmpInt32Ty);
3116 addFieldToRecordDecl(C, RD, C.VoidPtrTy);
3117 }
3118 RD->completeDefinition();
3119 return RD;
3120}
3121
3122static RecordDecl *
3125 ASTContext &C = CGM.getContext();
3126 // Build struct kmp_task_t_with_privates {
3127 // kmp_task_t task_data;
3128 // .kmp_privates_t. privates;
3129 // };
3130 RecordDecl *RD = C.buildImplicitRecord("kmp_task_t_with_privates");
3131 RD->startDefinition();
3132 addFieldToRecordDecl(C, RD, KmpTaskTQTy);
3133 if (const RecordDecl *PrivateRD = createPrivatesRecordDecl(CGM, Privates))
3134 addFieldToRecordDecl(C, RD, C.getCanonicalTagType(PrivateRD));
3135 RD->completeDefinition();
3136 return RD;
3137}
3138
3139/// Emit a proxy function which accepts kmp_task_t as the second
3140/// argument.
3141/// \code
3142/// kmp_int32 .omp_task_entry.(kmp_int32 gtid, kmp_task_t *tt) {
3143/// TaskFunction(gtid, tt->part_id, &tt->privates, task_privates_map, tt,
3144/// For taskloops:
3145/// tt->task_data.lb, tt->task_data.ub, tt->task_data.st, tt->task_data.liter,
3146/// tt->reductions, tt->shareds);
3147/// return 0;
3148/// }
3149/// \endcode
3150static llvm::Function *
3152 OpenMPDirectiveKind Kind, QualType KmpInt32Ty,
3153 QualType KmpTaskTWithPrivatesPtrQTy,
3154 QualType KmpTaskTWithPrivatesQTy, QualType KmpTaskTQTy,
3155 QualType SharedsPtrTy, llvm::Function *TaskFunction,
3156 llvm::Value *TaskPrivatesMap) {
3157 ASTContext &C = CGM.getContext();
3158 auto *GtidArg =
3159 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
3160 KmpInt32Ty, ImplicitParamKind::Other);
3161 auto *TaskTypeArg = ImplicitParamDecl::Create(
3162 C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
3163 KmpTaskTWithPrivatesPtrQTy.withRestrict(), ImplicitParamKind::Other);
3164 FunctionArgList Args{GtidArg, TaskTypeArg};
3165 const auto &TaskEntryFnInfo =
3166 CGM.getTypes().arrangeBuiltinFunctionDeclaration(KmpInt32Ty, Args);
3167 llvm::FunctionType *TaskEntryTy =
3168 CGM.getTypes().GetFunctionType(TaskEntryFnInfo);
3169 std::string Name = CGM.getOpenMPRuntime().getName({"omp_task_entry", ""});
3170 auto *TaskEntry = llvm::Function::Create(
3171 TaskEntryTy, llvm::GlobalValue::InternalLinkage, Name, &CGM.getModule());
3172 CGM.SetInternalFunctionAttributes(GlobalDecl(), TaskEntry, TaskEntryFnInfo);
3173 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
3174 TaskEntry->addFnAttr("sample-profile-suffix-elision-policy", "selected");
3175 TaskEntry->setDoesNotRecurse();
3176 CodeGenFunction CGF(CGM);
3177 CGF.StartFunction(GlobalDecl(), KmpInt32Ty, TaskEntry, TaskEntryFnInfo, Args,
3178 Loc, Loc);
3179
3180 // TaskFunction(gtid, tt->task_data.part_id, &tt->privates, task_privates_map,
3181 // tt,
3182 // For taskloops:
3183 // tt->task_data.lb, tt->task_data.ub, tt->task_data.st, tt->task_data.liter,
3184 // tt->task_data.shareds);
3185 llvm::Value *GtidParam = CGF.EmitLoadOfScalar(
3186 CGF.GetAddrOfLocalVar(GtidArg), /*Volatile=*/false, KmpInt32Ty, Loc);
3187 LValue TDBase = CGF.EmitLoadOfPointerLValue(
3188 CGF.GetAddrOfLocalVar(TaskTypeArg),
3189 KmpTaskTWithPrivatesPtrQTy->castAs<PointerType>());
3190 const auto *KmpTaskTWithPrivatesQTyRD =
3191 KmpTaskTWithPrivatesQTy->castAsRecordDecl();
3192 LValue Base =
3193 CGF.EmitLValueForField(TDBase, *KmpTaskTWithPrivatesQTyRD->field_begin());
3194 const auto *KmpTaskTQTyRD = KmpTaskTQTy->castAsRecordDecl();
3195 auto PartIdFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTPartId);
3196 LValue PartIdLVal = CGF.EmitLValueForField(Base, *PartIdFI);
3197 llvm::Value *PartidParam = PartIdLVal.getPointer(CGF);
3198
3199 auto SharedsFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTShareds);
3200 LValue SharedsLVal = CGF.EmitLValueForField(Base, *SharedsFI);
3201 llvm::Value *SharedsParam = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
3202 CGF.EmitLoadOfScalar(SharedsLVal, Loc),
3203 CGF.ConvertTypeForMem(SharedsPtrTy));
3204
3205 auto PrivatesFI = std::next(KmpTaskTWithPrivatesQTyRD->field_begin(), 1);
3206 llvm::Value *PrivatesParam;
3207 if (PrivatesFI != KmpTaskTWithPrivatesQTyRD->field_end()) {
3208 LValue PrivatesLVal = CGF.EmitLValueForField(TDBase, *PrivatesFI);
3209 PrivatesParam = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
3210 PrivatesLVal.getPointer(CGF), CGF.VoidPtrTy);
3211 } else {
3212 PrivatesParam = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
3213 }
3214
3215 llvm::Value *CommonArgs[] = {
3216 GtidParam, PartidParam, PrivatesParam, TaskPrivatesMap,
3217 CGF.Builder
3218 .CreatePointerBitCastOrAddrSpaceCast(TDBase.getAddress(),
3219 CGF.VoidPtrTy, CGF.Int8Ty)
3220 .emitRawPointer(CGF)};
3221 SmallVector<llvm::Value *, 16> CallArgs(std::begin(CommonArgs),
3222 std::end(CommonArgs));
3223 if (isOpenMPTaskLoopDirective(Kind)) {
3224 auto LBFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTLowerBound);
3225 LValue LBLVal = CGF.EmitLValueForField(Base, *LBFI);
3226 llvm::Value *LBParam = CGF.EmitLoadOfScalar(LBLVal, Loc);
3227 auto UBFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTUpperBound);
3228 LValue UBLVal = CGF.EmitLValueForField(Base, *UBFI);
3229 llvm::Value *UBParam = CGF.EmitLoadOfScalar(UBLVal, Loc);
3230 auto StFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTStride);
3231 LValue StLVal = CGF.EmitLValueForField(Base, *StFI);
3232 llvm::Value *StParam = CGF.EmitLoadOfScalar(StLVal, Loc);
3233 auto LIFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTLastIter);
3234 LValue LILVal = CGF.EmitLValueForField(Base, *LIFI);
3235 llvm::Value *LIParam = CGF.EmitLoadOfScalar(LILVal, Loc);
3236 auto RFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTReductions);
3237 LValue RLVal = CGF.EmitLValueForField(Base, *RFI);
3238 llvm::Value *RParam = CGF.EmitLoadOfScalar(RLVal, Loc);
3239 CallArgs.push_back(LBParam);
3240 CallArgs.push_back(UBParam);
3241 CallArgs.push_back(StParam);
3242 CallArgs.push_back(LIParam);
3243 CallArgs.push_back(RParam);
3244 }
3245 CallArgs.push_back(SharedsParam);
3246
3247 CGM.getOpenMPRuntime().emitOutlinedFunctionCall(CGF, Loc, TaskFunction,
3248 CallArgs);
3249 CGF.EmitStoreThroughLValue(RValue::get(CGF.Builder.getInt32(/*C=*/0)),
3250 CGF.MakeAddrLValue(CGF.ReturnValue, KmpInt32Ty));
3251 CGF.FinishFunction();
3252 return TaskEntry;
3253}
3254
3256 SourceLocation Loc,
3257 QualType KmpInt32Ty,
3258 QualType KmpTaskTWithPrivatesPtrQTy,
3259 QualType KmpTaskTWithPrivatesQTy) {
3260 ASTContext &C = CGM.getContext();
3261 auto *GtidArg =
3262 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
3263 KmpInt32Ty, ImplicitParamKind::Other);
3264 auto *TaskTypeArg = ImplicitParamDecl::Create(
3265 C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
3266 KmpTaskTWithPrivatesPtrQTy.withRestrict(), ImplicitParamKind::Other);
3267 FunctionArgList Args{GtidArg, TaskTypeArg};
3268 const auto &DestructorFnInfo =
3269 CGM.getTypes().arrangeBuiltinFunctionDeclaration(KmpInt32Ty, Args);
3270 llvm::FunctionType *DestructorFnTy =
3271 CGM.getTypes().GetFunctionType(DestructorFnInfo);
3272 std::string Name =
3273 CGM.getOpenMPRuntime().getName({"omp_task_destructor", ""});
3274 auto *DestructorFn =
3275 llvm::Function::Create(DestructorFnTy, llvm::GlobalValue::InternalLinkage,
3276 Name, &CGM.getModule());
3277 CGM.SetInternalFunctionAttributes(GlobalDecl(), DestructorFn,
3278 DestructorFnInfo);
3279 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
3280 DestructorFn->addFnAttr("sample-profile-suffix-elision-policy", "selected");
3281 DestructorFn->setDoesNotRecurse();
3282 CodeGenFunction CGF(CGM);
3283 CGF.StartFunction(GlobalDecl(), KmpInt32Ty, DestructorFn, DestructorFnInfo,
3284 Args, Loc, Loc);
3285
3286 LValue Base = CGF.EmitLoadOfPointerLValue(
3287 CGF.GetAddrOfLocalVar(TaskTypeArg),
3288 KmpTaskTWithPrivatesPtrQTy->castAs<PointerType>());
3289 const auto *KmpTaskTWithPrivatesQTyRD =
3290 KmpTaskTWithPrivatesQTy->castAsRecordDecl();
3291 auto FI = std::next(KmpTaskTWithPrivatesQTyRD->field_begin());
3292 Base = CGF.EmitLValueForField(Base, *FI);
3293 for (const auto *Field : FI->getType()->castAsRecordDecl()->fields()) {
3294 if (QualType::DestructionKind DtorKind =
3295 Field->getType().isDestructedType()) {
3296 LValue FieldLValue = CGF.EmitLValueForField(Base, Field);
3297 CGF.pushDestroy(DtorKind, FieldLValue.getAddress(), Field->getType());
3298 }
3299 }
3300 CGF.FinishFunction();
3301 return DestructorFn;
3302}
3303
3304/// Emit a privates mapping function for correct handling of private and
3305/// firstprivate variables.
3306/// \code
3307/// void .omp_task_privates_map.(const .privates. *noalias privs, <ty1>
3308/// **noalias priv1,..., <tyn> **noalias privn) {
3309/// *priv1 = &.privates.priv1;
3310/// ...;
3311/// *privn = &.privates.privn;
3312/// }
3313/// \endcode
3314static llvm::Value *
3316 const OMPTaskDataTy &Data, QualType PrivatesQTy,
3318 ASTContext &C = CGM.getContext();
3319 FunctionArgList Args;
3320 auto *TaskPrivatesArg = ImplicitParamDecl::Create(
3321 C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
3322 C.getPointerType(PrivatesQTy).withConst().withRestrict(),
3324 Args.push_back(TaskPrivatesArg);
3325 llvm::DenseMap<CanonicalDeclPtr<const VarDecl>, unsigned> PrivateVarsPos;
3326 unsigned Counter = 1;
3327 for (const Expr *E : Data.PrivateVars) {
3328 Args.push_back(ImplicitParamDecl::Create(
3329 C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
3330 C.getPointerType(C.getPointerType(E->getType()))
3331 .withConst()
3332 .withRestrict(),
3334 const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
3335 PrivateVarsPos[VD] = Counter;
3336 ++Counter;
3337 }
3338 for (const Expr *E : Data.FirstprivateVars) {
3339 Args.push_back(ImplicitParamDecl::Create(
3340 C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
3341 C.getPointerType(C.getPointerType(E->getType()))
3342 .withConst()
3343 .withRestrict(),
3345 const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
3346 PrivateVarsPos[VD] = Counter;
3347 ++Counter;
3348 }
3349 for (const Expr *E : Data.LastprivateVars) {
3350 Args.push_back(ImplicitParamDecl::Create(
3351 C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
3352 C.getPointerType(C.getPointerType(E->getType()))
3353 .withConst()
3354 .withRestrict(),
3356 const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
3357 PrivateVarsPos[VD] = Counter;
3358 ++Counter;
3359 }
3360 for (const VarDecl *VD : Data.PrivateLocals) {
3362 if (VD->getType()->isLValueReferenceType())
3363 Ty = C.getPointerType(Ty);
3364 if (isAllocatableDecl(VD))
3365 Ty = C.getPointerType(Ty);
3366 Args.push_back(ImplicitParamDecl::Create(
3367 C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
3368 C.getPointerType(C.getPointerType(Ty)).withConst().withRestrict(),
3370 PrivateVarsPos[VD] = Counter;
3371 ++Counter;
3372 }
3373 const auto &TaskPrivatesMapFnInfo =
3374 CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
3375 llvm::FunctionType *TaskPrivatesMapTy =
3376 CGM.getTypes().GetFunctionType(TaskPrivatesMapFnInfo);
3377 std::string Name =
3378 CGM.getOpenMPRuntime().getName({"omp_task_privates_map", ""});
3379 auto *TaskPrivatesMap = llvm::Function::Create(
3380 TaskPrivatesMapTy, llvm::GlobalValue::InternalLinkage, Name,
3381 &CGM.getModule());
3382 CGM.SetInternalFunctionAttributes(GlobalDecl(), TaskPrivatesMap,
3383 TaskPrivatesMapFnInfo);
3384 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
3385 TaskPrivatesMap->addFnAttr("sample-profile-suffix-elision-policy",
3386 "selected");
3387 if (CGM.getCodeGenOpts().OptimizationLevel != 0) {
3388 TaskPrivatesMap->removeFnAttr(llvm::Attribute::NoInline);
3389 TaskPrivatesMap->removeFnAttr(llvm::Attribute::OptimizeNone);
3390 TaskPrivatesMap->addFnAttr(llvm::Attribute::AlwaysInline);
3391 }
3392 CodeGenFunction CGF(CGM);
3393 CGF.StartFunction(GlobalDecl(), C.VoidTy, TaskPrivatesMap,
3394 TaskPrivatesMapFnInfo, Args, Loc, Loc);
3395
3396 // *privi = &.privates.privi;
3397 LValue Base = CGF.EmitLoadOfPointerLValue(
3398 CGF.GetAddrOfLocalVar(TaskPrivatesArg),
3399 TaskPrivatesArg->getType()->castAs<PointerType>());
3400 const auto *PrivatesQTyRD = PrivatesQTy->castAsRecordDecl();
3401 Counter = 0;
3402 for (const FieldDecl *Field : PrivatesQTyRD->fields()) {
3403 LValue FieldLVal = CGF.EmitLValueForField(Base, Field);
3404 const VarDecl *VD = Args[PrivateVarsPos[Privates[Counter].second.Original]];
3405 LValue RefLVal =
3406 CGF.MakeAddrLValue(CGF.GetAddrOfLocalVar(VD), VD->getType());
3407 LValue RefLoadLVal = CGF.EmitLoadOfPointerLValue(
3408 RefLVal.getAddress(), RefLVal.getType()->castAs<PointerType>());
3409 CGF.EmitStoreOfScalar(FieldLVal.getPointer(CGF), RefLoadLVal);
3410 ++Counter;
3411 }
3412 CGF.FinishFunction();
3413 return TaskPrivatesMap;
3414}
3415
3416/// Emit initialization for private variables in task-based directives.
3418 const OMPExecutableDirective &D,
3419 Address KmpTaskSharedsPtr, LValue TDBase,
3420 const RecordDecl *KmpTaskTWithPrivatesQTyRD,
3421 QualType SharedsTy, QualType SharedsPtrTy,
3422 const OMPTaskDataTy &Data,
3423 ArrayRef<PrivateDataTy> Privates, bool ForDup) {
3424 ASTContext &C = CGF.getContext();
3425 auto FI = std::next(KmpTaskTWithPrivatesQTyRD->field_begin());
3426 LValue PrivatesBase = CGF.EmitLValueForField(TDBase, *FI);
3427 OpenMPDirectiveKind Kind = isOpenMPTaskLoopDirective(D.getDirectiveKind())
3428 ? OMPD_taskloop
3429 : OMPD_task;
3430 const CapturedStmt &CS = *D.getCapturedStmt(Kind);
3431 CodeGenFunction::CGCapturedStmtInfo CapturesInfo(CS);
3432 LValue SrcBase;
3433 bool IsTargetTask =
3434 isOpenMPTargetDataManagementDirective(D.getDirectiveKind()) ||
3435 isOpenMPTargetExecutionDirective(D.getDirectiveKind());
3436 // For target-based directives skip 4 firstprivate arrays BasePointersArray,
3437 // PointersArray, SizesArray, and MappersArray. The original variables for
3438 // these arrays are not captured and we get their addresses explicitly.
3439 if ((!IsTargetTask && !Data.FirstprivateVars.empty() && ForDup) ||
3440 (IsTargetTask && KmpTaskSharedsPtr.isValid())) {
3441 SrcBase = CGF.MakeAddrLValue(
3443 KmpTaskSharedsPtr, CGF.ConvertTypeForMem(SharedsPtrTy),
3444 CGF.ConvertTypeForMem(SharedsTy)),
3445 SharedsTy);
3446 }
3447 FI = FI->getType()->castAsRecordDecl()->field_begin();
3448 for (const PrivateDataTy &Pair : Privates) {
3449 // Do not initialize private locals.
3450 if (Pair.second.isLocalPrivate()) {
3451 ++FI;
3452 continue;
3453 }
3454 const VarDecl *VD = Pair.second.PrivateCopy;
3455 const Expr *Init = VD->getAnyInitializer();
3456 if (Init && (!ForDup || (isa<CXXConstructExpr>(Init) &&
3457 !CGF.isTrivialInitializer(Init)))) {
3458 LValue PrivateLValue = CGF.EmitLValueForField(PrivatesBase, *FI);
3459 if (const VarDecl *Elem = Pair.second.PrivateElemInit) {
3460 const VarDecl *OriginalVD = Pair.second.Original;
3461 // Check if the variable is the target-based BasePointersArray,
3462 // PointersArray, SizesArray, or MappersArray.
3463 LValue SharedRefLValue;
3464 QualType Type = PrivateLValue.getType();
3465 const FieldDecl *SharedField = CapturesInfo.lookup(OriginalVD);
3466 if (IsTargetTask && !SharedField) {
3467 assert(isa<ImplicitParamDecl>(OriginalVD) &&
3468 isa<CapturedDecl>(OriginalVD->getDeclContext()) &&
3469 cast<CapturedDecl>(OriginalVD->getDeclContext())
3470 ->getNumParams() == 0 &&
3472 cast<CapturedDecl>(OriginalVD->getDeclContext())
3473 ->getDeclContext()) &&
3474 "Expected artificial target data variable.");
3475 SharedRefLValue =
3476 CGF.MakeAddrLValue(CGF.GetAddrOfLocalVar(OriginalVD), Type);
3477 } else if (ForDup) {
3478 SharedRefLValue = CGF.EmitLValueForField(SrcBase, SharedField);
3479 SharedRefLValue = CGF.MakeAddrLValue(
3480 SharedRefLValue.getAddress().withAlignment(
3481 C.getDeclAlign(OriginalVD)),
3482 SharedRefLValue.getType(), LValueBaseInfo(AlignmentSource::Decl),
3483 SharedRefLValue.getTBAAInfo());
3484 } else if (CGF.LambdaCaptureFields.count(
3485 Pair.second.Original->getCanonicalDecl()) > 0 ||
3486 isa_and_nonnull<BlockDecl>(CGF.CurCodeDecl)) {
3487 SharedRefLValue = CGF.EmitLValue(Pair.second.OriginalRef);
3488 } else {
3489 // Processing for implicitly captured variables.
3490 InlinedOpenMPRegionRAII Region(
3491 CGF, [](CodeGenFunction &, PrePostActionTy &) {}, OMPD_unknown,
3492 /*HasCancel=*/false, /*NoInheritance=*/true);
3493 SharedRefLValue = CGF.EmitLValue(Pair.second.OriginalRef);
3494 }
3495 if (Type->isArrayType()) {
3496 // Initialize firstprivate array.
3498 // Perform simple memcpy.
3499 CGF.EmitAggregateAssign(PrivateLValue, SharedRefLValue, Type);
3500 } else {
3501 // Initialize firstprivate array using element-by-element
3502 // initialization.
3504 PrivateLValue.getAddress(), SharedRefLValue.getAddress(), Type,
3505 [&CGF, Elem, Init, &CapturesInfo](Address DestElement,
3506 Address SrcElement) {
3507 // Clean up any temporaries needed by the initialization.
3508 CodeGenFunction::OMPPrivateScope InitScope(CGF);
3509 InitScope.addPrivate(Elem, SrcElement);
3510 (void)InitScope.Privatize();
3511 // Emit initialization for single element.
3512 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(
3513 CGF, &CapturesInfo);
3514 CGF.EmitAnyExprToMem(Init, DestElement,
3515 Init->getType().getQualifiers(),
3516 /*IsInitializer=*/false);
3517 });
3518 }
3519 } else {
3520 CodeGenFunction::OMPPrivateScope InitScope(CGF);
3521 InitScope.addPrivate(Elem, SharedRefLValue.getAddress());
3522 (void)InitScope.Privatize();
3523 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CapturesInfo);
3524 CGF.EmitExprAsInit(Init, VD, PrivateLValue,
3525 /*capturedByInit=*/false);
3526 }
3527 } else {
3528 CGF.EmitExprAsInit(Init, VD, PrivateLValue, /*capturedByInit=*/false);
3529 }
3530 }
3531 ++FI;
3532 }
3533}
3534
3535/// Check if duplication function is required for taskloops.
3538 bool InitRequired = false;
3539 for (const PrivateDataTy &Pair : Privates) {
3540 if (Pair.second.isLocalPrivate())
3541 continue;
3542 const VarDecl *VD = Pair.second.PrivateCopy;
3543 const Expr *Init = VD->getAnyInitializer();
3544 InitRequired = InitRequired || (isa_and_nonnull<CXXConstructExpr>(Init) &&
3546 if (InitRequired)
3547 break;
3548 }
3549 return InitRequired;
3550}
3551
3552
3553/// Emit task_dup function (for initialization of
3554/// private/firstprivate/lastprivate vars and last_iter flag)
3555/// \code
3556/// void __task_dup_entry(kmp_task_t *task_dst, const kmp_task_t *task_src, int
3557/// lastpriv) {
3558/// // setup lastprivate flag
3559/// task_dst->last = lastpriv;
3560/// // could be constructor calls here...
3561/// }
3562/// \endcode
3563static llvm::Value *
3565 const OMPExecutableDirective &D,
3566 QualType KmpTaskTWithPrivatesPtrQTy,
3567 const RecordDecl *KmpTaskTWithPrivatesQTyRD,
3568 const RecordDecl *KmpTaskTQTyRD, QualType SharedsTy,
3569 QualType SharedsPtrTy, const OMPTaskDataTy &Data,
3570 ArrayRef<PrivateDataTy> Privates, bool WithLastIter) {
3571 ASTContext &C = CGM.getContext();
3572 auto *DstArg = ImplicitParamDecl::Create(
3573 C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, KmpTaskTWithPrivatesPtrQTy,
3575 auto *SrcArg = ImplicitParamDecl::Create(
3576 C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, KmpTaskTWithPrivatesPtrQTy,
3578 auto *LastprivArg =
3579 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, C.IntTy,
3581 FunctionArgList Args{DstArg, SrcArg, LastprivArg};
3582 const auto &TaskDupFnInfo =
3583 CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
3584 llvm::FunctionType *TaskDupTy = CGM.getTypes().GetFunctionType(TaskDupFnInfo);
3585 std::string Name = CGM.getOpenMPRuntime().getName({"omp_task_dup", ""});
3586 auto *TaskDup = llvm::Function::Create(
3587 TaskDupTy, llvm::GlobalValue::InternalLinkage, Name, &CGM.getModule());
3588 CGM.SetInternalFunctionAttributes(GlobalDecl(), TaskDup, TaskDupFnInfo);
3589 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
3590 TaskDup->addFnAttr("sample-profile-suffix-elision-policy", "selected");
3591 TaskDup->setDoesNotRecurse();
3592 CodeGenFunction CGF(CGM);
3593 CGF.StartFunction(GlobalDecl(), C.VoidTy, TaskDup, TaskDupFnInfo, Args, Loc,
3594 Loc);
3595
3596 LValue TDBase = CGF.EmitLoadOfPointerLValue(
3597 CGF.GetAddrOfLocalVar(DstArg),
3598 KmpTaskTWithPrivatesPtrQTy->castAs<PointerType>());
3599 // task_dst->liter = lastpriv;
3600 if (WithLastIter) {
3601 auto LIFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTLastIter);
3602 LValue Base = CGF.EmitLValueForField(
3603 TDBase, *KmpTaskTWithPrivatesQTyRD->field_begin());
3604 LValue LILVal = CGF.EmitLValueForField(Base, *LIFI);
3605 llvm::Value *Lastpriv = CGF.EmitLoadOfScalar(
3606 CGF.GetAddrOfLocalVar(LastprivArg), /*Volatile=*/false, C.IntTy, Loc);
3607 CGF.EmitStoreOfScalar(Lastpriv, LILVal);
3608 }
3609
3610 // Emit initial values for private copies (if any).
3611 assert(!Privates.empty());
3612 Address KmpTaskSharedsPtr = Address::invalid();
3613 if (!Data.FirstprivateVars.empty()) {
3614 LValue TDBase = CGF.EmitLoadOfPointerLValue(
3615 CGF.GetAddrOfLocalVar(SrcArg),
3616 KmpTaskTWithPrivatesPtrQTy->castAs<PointerType>());
3617 LValue Base = CGF.EmitLValueForField(
3618 TDBase, *KmpTaskTWithPrivatesQTyRD->field_begin());
3619 KmpTaskSharedsPtr = Address(
3621 Base, *std::next(KmpTaskTQTyRD->field_begin(),
3622 KmpTaskTShareds)),
3623 Loc),
3624 CGF.Int8Ty, CGM.getNaturalTypeAlignment(SharedsTy));
3625 }
3626 emitPrivatesInit(CGF, D, KmpTaskSharedsPtr, TDBase, KmpTaskTWithPrivatesQTyRD,
3627 SharedsTy, SharedsPtrTy, Data, Privates, /*ForDup=*/true);
3628 CGF.FinishFunction();
3629 return TaskDup;
3630}
3631
3632/// Checks if destructor function is required to be generated.
3633/// \return true if cleanups are required, false otherwise.
3634static bool
3635checkDestructorsRequired(const RecordDecl *KmpTaskTWithPrivatesQTyRD,
3637 for (const PrivateDataTy &P : Privates) {
3638 if (P.second.isLocalPrivate())
3639 continue;
3640 QualType Ty = P.second.Original->getType().getNonReferenceType();
3641 if (Ty.isDestructedType())
3642 return true;
3643 }
3644 return false;
3645}
3646
3647namespace {
3648/// Loop generator for OpenMP iterator expression.
3649class OMPIteratorGeneratorScope final
3651 CodeGenFunction &CGF;
3652 const OMPIteratorExpr *E = nullptr;
3653 SmallVector<CodeGenFunction::JumpDest, 4> ContDests;
3654 SmallVector<CodeGenFunction::JumpDest, 4> ExitDests;
3655 OMPIteratorGeneratorScope() = delete;
3656 OMPIteratorGeneratorScope(OMPIteratorGeneratorScope &) = delete;
3657
3658public:
3659 OMPIteratorGeneratorScope(CodeGenFunction &CGF, const OMPIteratorExpr *E)
3660 : CodeGenFunction::OMPPrivateScope(CGF), CGF(CGF), E(E) {
3661 if (!E)
3662 return;
3663 SmallVector<llvm::Value *, 4> Uppers;
3664 for (unsigned I = 0, End = E->numOfIterators(); I < End; ++I) {
3665 Uppers.push_back(CGF.EmitScalarExpr(E->getHelper(I).Upper));
3666 const auto *VD = cast<VarDecl>(E->getIteratorDecl(I));
3667 addPrivate(VD, CGF.CreateMemTemp(VD->getType(), VD->getName()));
3668 const OMPIteratorHelperData &HelperData = E->getHelper(I);
3669 addPrivate(
3670 HelperData.CounterVD,
3671 CGF.CreateMemTemp(HelperData.CounterVD->getType(), "counter.addr"));
3672 }
3673 Privatize();
3674
3675 for (unsigned I = 0, End = E->numOfIterators(); I < End; ++I) {
3676 const OMPIteratorHelperData &HelperData = E->getHelper(I);
3677 LValue CLVal =
3678 CGF.MakeAddrLValue(CGF.GetAddrOfLocalVar(HelperData.CounterVD),
3679 HelperData.CounterVD->getType());
3680 // Counter = 0;
3681 CGF.EmitStoreOfScalar(
3682 llvm::ConstantInt::get(CLVal.getAddress().getElementType(), 0),
3683 CLVal);
3684 CodeGenFunction::JumpDest &ContDest =
3685 ContDests.emplace_back(CGF.getJumpDestInCurrentScope("iter.cont"));
3686 CodeGenFunction::JumpDest &ExitDest =
3687 ExitDests.emplace_back(CGF.getJumpDestInCurrentScope("iter.exit"));
3688 // N = <number-of_iterations>;
3689 llvm::Value *N = Uppers[I];
3690 // cont:
3691 // if (Counter < N) goto body; else goto exit;
3692 CGF.EmitBlock(ContDest.getBlock());
3693 auto *CVal =
3694 CGF.EmitLoadOfScalar(CLVal, HelperData.CounterVD->getLocation());
3695 llvm::Value *Cmp =
3696 HelperData.CounterVD->getType()->isSignedIntegerOrEnumerationType()
3697 ? CGF.Builder.CreateICmpSLT(CVal, N)
3698 : CGF.Builder.CreateICmpULT(CVal, N);
3699 llvm::BasicBlock *BodyBB = CGF.createBasicBlock("iter.body");
3700 CGF.Builder.CreateCondBr(Cmp, BodyBB, ExitDest.getBlock());
3701 // body:
3702 CGF.EmitBlock(BodyBB);
3703 // Iteri = Begini + Counter * Stepi;
3704 CGF.EmitIgnoredExpr(HelperData.Update);
3705 }
3706 }
3707 ~OMPIteratorGeneratorScope() {
3708 if (!E)
3709 return;
3710 for (unsigned I = E->numOfIterators(); I > 0; --I) {
3711 // Counter = Counter + 1;
3712 const OMPIteratorHelperData &HelperData = E->getHelper(I - 1);
3713 CGF.EmitIgnoredExpr(HelperData.CounterUpdate);
3714 // goto cont;
3715 CGF.EmitBranchThroughCleanup(ContDests[I - 1]);
3716 // exit:
3717 CGF.EmitBlock(ExitDests[I - 1].getBlock(), /*IsFinished=*/I == 1);
3718 }
3719 }
3720};
3721} // namespace
3722
3723static std::pair<llvm::Value *, llvm::Value *>
3725 const auto *OASE = dyn_cast<OMPArrayShapingExpr>(E);
3726 llvm::Value *Addr;
3727 if (OASE) {
3728 const Expr *Base = OASE->getBase();
3729 Addr = CGF.EmitScalarExpr(Base);
3730 } else {
3731 Addr = CGF.EmitLValue(E).getPointer(CGF);
3732 }
3733 llvm::Value *SizeVal;
3734 QualType Ty = E->getType();
3735 if (OASE) {
3736 SizeVal = CGF.getTypeSize(OASE->getBase()->getType()->getPointeeType());
3737 for (const Expr *SE : OASE->getDimensions()) {
3738 llvm::Value *Sz = CGF.EmitScalarExpr(SE);
3739 Sz = CGF.EmitScalarConversion(
3740 Sz, SE->getType(), CGF.getContext().getSizeType(), SE->getExprLoc());
3741 SizeVal = CGF.Builder.CreateNUWMul(SizeVal, Sz);
3742 }
3743 } else if (const auto *ASE =
3744 dyn_cast<ArraySectionExpr>(E->IgnoreParenImpCasts())) {
3745 LValue UpAddrLVal = CGF.EmitArraySectionExpr(ASE, /*IsLowerBound=*/false);
3746 Address UpAddrAddress = UpAddrLVal.getAddress();
3747 llvm::Value *UpAddr = CGF.Builder.CreateConstGEP1_32(
3748 UpAddrAddress.getElementType(), UpAddrAddress.emitRawPointer(CGF),
3749 /*Idx0=*/1);
3750 SizeVal = CGF.Builder.CreatePtrDiff(UpAddr, Addr, "", /*IsNUW=*/true);
3751 } else {
3752 SizeVal = CGF.getTypeSize(Ty);
3753 }
3754 return std::make_pair(Addr, SizeVal);
3755}
3756
3757/// Builds kmp_depend_info, if it is not built yet, and builds flags type.
3758static void getKmpAffinityType(ASTContext &C, QualType &KmpTaskAffinityInfoTy) {
3759 QualType FlagsTy = C.getIntTypeForBitwidth(32, /*Signed=*/false);
3760 if (KmpTaskAffinityInfoTy.isNull()) {
3761 RecordDecl *KmpAffinityInfoRD =
3762 C.buildImplicitRecord("kmp_task_affinity_info_t");
3763 KmpAffinityInfoRD->startDefinition();
3764 addFieldToRecordDecl(C, KmpAffinityInfoRD, C.getIntPtrType());
3765 addFieldToRecordDecl(C, KmpAffinityInfoRD, C.getSizeType());
3766 addFieldToRecordDecl(C, KmpAffinityInfoRD, FlagsTy);
3767 KmpAffinityInfoRD->completeDefinition();
3768 KmpTaskAffinityInfoTy = C.getCanonicalTagType(KmpAffinityInfoRD);
3769 }
3770}
3771
3774 const OMPExecutableDirective &D,
3775 llvm::Function *TaskFunction, QualType SharedsTy,
3776 Address Shareds, const OMPTaskDataTy &Data) {
3777 ASTContext &C = CGM.getContext();
3779 // Aggregate privates and sort them by the alignment.
3780 const auto *I = Data.PrivateCopies.begin();
3781 for (const Expr *E : Data.PrivateVars) {
3782 const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
3783 Privates.emplace_back(
3784 C.getDeclAlign(VD),
3785 PrivateHelpersTy(E, VD, cast<VarDecl>(cast<DeclRefExpr>(*I)->getDecl()),
3786 /*PrivateElemInit=*/nullptr));
3787 ++I;
3788 }
3789 I = Data.FirstprivateCopies.begin();
3790 const auto *IElemInitRef = Data.FirstprivateInits.begin();
3791 for (const Expr *E : Data.FirstprivateVars) {
3792 const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
3793 Privates.emplace_back(
3794 C.getDeclAlign(VD),
3795 PrivateHelpersTy(
3796 E, VD, cast<VarDecl>(cast<DeclRefExpr>(*I)->getDecl()),
3797 cast<VarDecl>(cast<DeclRefExpr>(*IElemInitRef)->getDecl())));
3798 ++I;
3799 ++IElemInitRef;
3800 }
3801 I = Data.LastprivateCopies.begin();
3802 for (const Expr *E : Data.LastprivateVars) {
3803 const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
3804 Privates.emplace_back(
3805 C.getDeclAlign(VD),
3806 PrivateHelpersTy(E, VD, cast<VarDecl>(cast<DeclRefExpr>(*I)->getDecl()),
3807 /*PrivateElemInit=*/nullptr));
3808 ++I;
3809 }
3810 for (const VarDecl *VD : Data.PrivateLocals) {
3811 if (isAllocatableDecl(VD))
3812 Privates.emplace_back(CGM.getPointerAlign(), PrivateHelpersTy(VD));
3813 else
3814 Privates.emplace_back(C.getDeclAlign(VD), PrivateHelpersTy(VD));
3815 }
3816 llvm::stable_sort(Privates,
3817 [](const PrivateDataTy &L, const PrivateDataTy &R) {
3818 return L.first > R.first;
3819 });
3820 QualType KmpInt32Ty = C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1);
3821 // Build type kmp_routine_entry_t (if not built yet).
3822 emitKmpRoutineEntryT(KmpInt32Ty);
3823 // Build type kmp_task_t (if not built yet).
3824 if (isOpenMPTaskLoopDirective(D.getDirectiveKind())) {
3825 if (SavedKmpTaskloopTQTy.isNull()) {
3826 SavedKmpTaskloopTQTy = C.getCanonicalTagType(createKmpTaskTRecordDecl(
3827 CGM, D.getDirectiveKind(), KmpInt32Ty, KmpRoutineEntryPtrQTy));
3828 }
3830 } else {
3831 assert((D.getDirectiveKind() == OMPD_task ||
3832 isOpenMPTargetExecutionDirective(D.getDirectiveKind()) ||
3833 isOpenMPTargetDataManagementDirective(D.getDirectiveKind())) &&
3834 "Expected taskloop, task or target directive");
3835 if (SavedKmpTaskTQTy.isNull()) {
3836 SavedKmpTaskTQTy = C.getCanonicalTagType(createKmpTaskTRecordDecl(
3837 CGM, D.getDirectiveKind(), KmpInt32Ty, KmpRoutineEntryPtrQTy));
3838 }
3840 }
3841 const auto *KmpTaskTQTyRD = KmpTaskTQTy->castAsRecordDecl();
3842 // Build particular struct kmp_task_t for the given task.
3843 const RecordDecl *KmpTaskTWithPrivatesQTyRD =
3845 CanQualType KmpTaskTWithPrivatesQTy =
3846 C.getCanonicalTagType(KmpTaskTWithPrivatesQTyRD);
3847 QualType KmpTaskTWithPrivatesPtrQTy =
3848 C.getPointerType(KmpTaskTWithPrivatesQTy);
3849 llvm::Type *KmpTaskTWithPrivatesPtrTy = CGF.Builder.getPtrTy(0);
3850 llvm::Value *KmpTaskTWithPrivatesTySize =
3851 CGF.getTypeSize(KmpTaskTWithPrivatesQTy);
3852 QualType SharedsPtrTy = C.getPointerType(SharedsTy);
3853
3854 // Emit initial values for private copies (if any).
3855 llvm::Value *TaskPrivatesMap = nullptr;
3856 llvm::Type *TaskPrivatesMapTy =
3857 std::next(TaskFunction->arg_begin(), 3)->getType();
3858 if (!Privates.empty()) {
3859 auto FI = std::next(KmpTaskTWithPrivatesQTyRD->field_begin());
3860 TaskPrivatesMap =
3861 emitTaskPrivateMappingFunction(CGM, Loc, Data, FI->getType(), Privates);
3862 TaskPrivatesMap = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
3863 TaskPrivatesMap, TaskPrivatesMapTy);
3864 } else {
3865 TaskPrivatesMap = llvm::ConstantPointerNull::get(
3866 cast<llvm::PointerType>(TaskPrivatesMapTy));
3867 }
3868 // Build a proxy function kmp_int32 .omp_task_entry.(kmp_int32 gtid,
3869 // kmp_task_t *tt);
3870 llvm::Function *TaskEntry = emitProxyTaskFunction(
3871 CGM, Loc, D.getDirectiveKind(), KmpInt32Ty, KmpTaskTWithPrivatesPtrQTy,
3872 KmpTaskTWithPrivatesQTy, KmpTaskTQTy, SharedsPtrTy, TaskFunction,
3873 TaskPrivatesMap);
3874
3875 // Build call kmp_task_t * __kmpc_omp_task_alloc(ident_t *, kmp_int32 gtid,
3876 // kmp_int32 flags, size_t sizeof_kmp_task_t, size_t sizeof_shareds,
3877 // kmp_routine_entry_t *task_entry);
3878 // Task flags. Format is taken from
3879 // https://github.com/llvm/llvm-project/blob/main/openmp/runtime/src/kmp.h,
3880 // description of kmp_tasking_flags struct.
3881 enum {
3882 TiedFlag = 0x1,
3883 FinalFlag = 0x2,
3884 DestructorsFlag = 0x8,
3885 PriorityFlag = 0x20,
3886 DetachableFlag = 0x40,
3887 FreeAgentFlag = 0x80,
3888 TransparentFlag = 0x100,
3889 };
3890 unsigned Flags = Data.Tied ? TiedFlag : 0;
3891 bool NeedsCleanup = false;
3892 if (!Privates.empty()) {
3893 NeedsCleanup =
3894 checkDestructorsRequired(KmpTaskTWithPrivatesQTyRD, Privates);
3895 if (NeedsCleanup)
3896 Flags = Flags | DestructorsFlag;
3897 }
3898 if (const auto *Clause = D.getSingleClause<OMPThreadsetClause>()) {
3899 OpenMPThreadsetKind Kind = Clause->getThreadsetKind();
3900 if (Kind == OMPC_THREADSET_omp_pool)
3901 Flags = Flags | FreeAgentFlag;
3902 }
3903 if (D.getSingleClause<OMPTransparentClause>())
3904 Flags |= TransparentFlag;
3905
3906 if (Data.Priority.getInt())
3907 Flags = Flags | PriorityFlag;
3908 if (D.hasClausesOfKind<OMPDetachClause>())
3909 Flags = Flags | DetachableFlag;
3910 llvm::Value *TaskFlags =
3911 Data.Final.getPointer()
3912 ? CGF.Builder.CreateSelect(Data.Final.getPointer(),
3913 CGF.Builder.getInt32(FinalFlag),
3914 CGF.Builder.getInt32(/*C=*/0))
3915 : CGF.Builder.getInt32(Data.Final.getInt() ? FinalFlag : 0);
3916 TaskFlags = CGF.Builder.CreateOr(TaskFlags, CGF.Builder.getInt32(Flags));
3917 llvm::Value *SharedsSize = CGM.getSize(C.getTypeSizeInChars(SharedsTy));
3919 getThreadID(CGF, Loc), TaskFlags, KmpTaskTWithPrivatesTySize,
3921 TaskEntry, KmpRoutineEntryPtrTy)};
3922 llvm::Value *NewTask;
3923 if (D.hasClausesOfKind<OMPNowaitClause>()) {
3924 // Check if we have any device clause associated with the directive.
3925 const Expr *Device = nullptr;
3926 if (auto *C = D.getSingleClause<OMPDeviceClause>())
3927 Device = C->getDevice();
3928 // Emit device ID if any otherwise use default value.
3929 llvm::Value *DeviceID;
3930 if (Device)
3931 DeviceID = CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(Device),
3932 CGF.Int64Ty, /*isSigned=*/true);
3933 else
3934 DeviceID = CGF.Builder.getInt64(OMP_DEVICEID_UNDEF);
3935 AllocArgs.push_back(DeviceID);
3936 NewTask = CGF.EmitRuntimeCall(
3937 OMPBuilder.getOrCreateRuntimeFunction(
3938 CGM.getModule(), OMPRTL___kmpc_omp_target_task_alloc),
3939 AllocArgs);
3940 } else {
3941 NewTask =
3942 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
3943 CGM.getModule(), OMPRTL___kmpc_omp_task_alloc),
3944 AllocArgs);
3945 }
3946 // Emit detach clause initialization.
3947 // evt = (typeof(evt))__kmpc_task_allow_completion_event(loc, tid,
3948 // task_descriptor);
3949 if (const auto *DC = D.getSingleClause<OMPDetachClause>()) {
3950 const Expr *Evt = DC->getEventHandler()->IgnoreParenImpCasts();
3951 LValue EvtLVal = CGF.EmitLValue(Evt);
3952
3953 // Build kmp_event_t *__kmpc_task_allow_completion_event(ident_t *loc_ref,
3954 // int gtid, kmp_task_t *task);
3955 llvm::Value *Loc = emitUpdateLocation(CGF, DC->getBeginLoc());
3956 llvm::Value *Tid = getThreadID(CGF, DC->getBeginLoc());
3957 Tid = CGF.Builder.CreateIntCast(Tid, CGF.IntTy, /*isSigned=*/false);
3958 llvm::Value *EvtVal = CGF.EmitRuntimeCall(
3959 OMPBuilder.getOrCreateRuntimeFunction(
3960 CGM.getModule(), OMPRTL___kmpc_task_allow_completion_event),
3961 {Loc, Tid, NewTask});
3962 EvtVal = CGF.EmitScalarConversion(EvtVal, C.VoidPtrTy, Evt->getType(),
3963 Evt->getExprLoc());
3964 CGF.EmitStoreOfScalar(EvtVal, EvtLVal);
3965 }
3966 // Process affinity clauses.
3967 if (D.hasClausesOfKind<OMPAffinityClause>()) {
3968 // Process list of affinity data.
3969 ASTContext &C = CGM.getContext();
3970 Address AffinitiesArray = Address::invalid();
3971 // Calculate number of elements to form the array of affinity data.
3972 llvm::Value *NumOfElements = nullptr;
3973 unsigned NumAffinities = 0;
3974 for (const auto *C : D.getClausesOfKind<OMPAffinityClause>()) {
3975 if (const Expr *Modifier = C->getModifier()) {
3976 const auto *IE = cast<OMPIteratorExpr>(Modifier->IgnoreParenImpCasts());
3977 for (unsigned I = 0, E = IE->numOfIterators(); I < E; ++I) {
3978 llvm::Value *Sz = CGF.EmitScalarExpr(IE->getHelper(I).Upper);
3979 Sz = CGF.Builder.CreateIntCast(Sz, CGF.SizeTy, /*isSigned=*/false);
3980 NumOfElements =
3981 NumOfElements ? CGF.Builder.CreateNUWMul(NumOfElements, Sz) : Sz;
3982 }
3983 } else {
3984 NumAffinities += C->varlist_size();
3985 }
3986 }
3988 // Fields ids in kmp_task_affinity_info record.
3989 enum RTLAffinityInfoFieldsTy { BaseAddr, Len, Flags };
3990
3991 QualType KmpTaskAffinityInfoArrayTy;
3992 if (NumOfElements) {
3993 NumOfElements = CGF.Builder.CreateNUWAdd(
3994 llvm::ConstantInt::get(CGF.SizeTy, NumAffinities), NumOfElements);
3995 auto *OVE = new (C) OpaqueValueExpr(
3996 Loc,
3997 C.getIntTypeForBitwidth(C.getTypeSize(C.getSizeType()), /*Signed=*/0),
3998 VK_PRValue);
3999 CodeGenFunction::OpaqueValueMapping OpaqueMap(CGF, OVE,
4000 RValue::get(NumOfElements));
4001 KmpTaskAffinityInfoArrayTy = C.getVariableArrayType(
4003 /*IndexTypeQuals=*/0);
4004 // Properly emit variable-sized array.
4005 auto *PD = ImplicitParamDecl::Create(C, KmpTaskAffinityInfoArrayTy,
4007 CGF.EmitVarDecl(*PD);
4008 AffinitiesArray = CGF.GetAddrOfLocalVar(PD);
4009 NumOfElements = CGF.Builder.CreateIntCast(NumOfElements, CGF.Int32Ty,
4010 /*isSigned=*/false);
4011 } else {
4012 KmpTaskAffinityInfoArrayTy = C.getConstantArrayType(
4014 llvm::APInt(C.getTypeSize(C.getSizeType()), NumAffinities), nullptr,
4015 ArraySizeModifier::Normal, /*IndexTypeQuals=*/0);
4016 AffinitiesArray = CGF.CreateMemTempWithoutCast(KmpTaskAffinityInfoArrayTy,
4017 ".affs.arr.addr");
4018 AffinitiesArray = CGF.Builder.CreateConstArrayGEP(AffinitiesArray, 0);
4019 NumOfElements = llvm::ConstantInt::get(CGM.Int32Ty, NumAffinities,
4020 /*isSigned=*/false);
4021 }
4022
4023 const auto *KmpAffinityInfoRD = KmpTaskAffinityInfoTy->getAsRecordDecl();
4024 // Fill array by elements without iterators.
4025 unsigned Pos = 0;
4026 bool HasIterator = false;
4027 for (const auto *C : D.getClausesOfKind<OMPAffinityClause>()) {
4028 if (C->getModifier()) {
4029 HasIterator = true;
4030 continue;
4031 }
4032 for (const Expr *E : C->varlist()) {
4033 llvm::Value *Addr;
4034 llvm::Value *Size;
4035 std::tie(Addr, Size) = getPointerAndSize(CGF, E);
4036 LValue Base =
4037 CGF.MakeAddrLValue(CGF.Builder.CreateConstGEP(AffinitiesArray, Pos),
4039 // affs[i].base_addr = &<Affinities[i].second>;
4040 LValue BaseAddrLVal = CGF.EmitLValueForField(
4041 Base, *std::next(KmpAffinityInfoRD->field_begin(), BaseAddr));
4042 CGF.EmitStoreOfScalar(CGF.Builder.CreatePtrToInt(Addr, CGF.IntPtrTy),
4043 BaseAddrLVal);
4044 // affs[i].len = sizeof(<Affinities[i].second>);
4045 LValue LenLVal = CGF.EmitLValueForField(
4046 Base, *std::next(KmpAffinityInfoRD->field_begin(), Len));
4047 CGF.EmitStoreOfScalar(Size, LenLVal);
4048 ++Pos;
4049 }
4050 }
4051 LValue PosLVal;
4052 if (HasIterator) {
4053 PosLVal = CGF.MakeAddrLValue(
4054 CGF.CreateMemTempWithoutCast(C.getSizeType(), "affs.counter.addr"),
4055 C.getSizeType());
4056 CGF.EmitStoreOfScalar(llvm::ConstantInt::get(CGF.SizeTy, Pos), PosLVal);
4057 }
4058 // Process elements with iterators.
4059 for (const auto *C : D.getClausesOfKind<OMPAffinityClause>()) {
4060 const Expr *Modifier = C->getModifier();
4061 if (!Modifier)
4062 continue;
4063 OMPIteratorGeneratorScope IteratorScope(
4064 CGF, cast_or_null<OMPIteratorExpr>(Modifier->IgnoreParenImpCasts()));
4065 for (const Expr *E : C->varlist()) {
4066 llvm::Value *Addr;
4067 llvm::Value *Size;
4068 std::tie(Addr, Size) = getPointerAndSize(CGF, E);
4069 llvm::Value *Idx = CGF.EmitLoadOfScalar(PosLVal, E->getExprLoc());
4070 LValue Base =
4071 CGF.MakeAddrLValue(CGF.Builder.CreateGEP(CGF, AffinitiesArray, Idx),
4073 // affs[i].base_addr = &<Affinities[i].second>;
4074 LValue BaseAddrLVal = CGF.EmitLValueForField(
4075 Base, *std::next(KmpAffinityInfoRD->field_begin(), BaseAddr));
4076 CGF.EmitStoreOfScalar(CGF.Builder.CreatePtrToInt(Addr, CGF.IntPtrTy),
4077 BaseAddrLVal);
4078 // affs[i].len = sizeof(<Affinities[i].second>);
4079 LValue LenLVal = CGF.EmitLValueForField(
4080 Base, *std::next(KmpAffinityInfoRD->field_begin(), Len));
4081 CGF.EmitStoreOfScalar(Size, LenLVal);
4082 Idx = CGF.Builder.CreateNUWAdd(
4083 Idx, llvm::ConstantInt::get(Idx->getType(), 1));
4084 CGF.EmitStoreOfScalar(Idx, PosLVal);
4085 }
4086 }
4087 // Call to kmp_int32 __kmpc_omp_reg_task_with_affinity(ident_t *loc_ref,
4088 // kmp_int32 gtid, kmp_task_t *new_task, kmp_int32
4089 // naffins, kmp_task_affinity_info_t *affin_list);
4090 llvm::Value *LocRef = emitUpdateLocation(CGF, Loc);
4091 llvm::Value *GTid = getThreadID(CGF, Loc);
4092 llvm::Value *AffinListPtr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
4093 AffinitiesArray.emitRawPointer(CGF), CGM.VoidPtrTy);
4094 // FIXME: Emit the function and ignore its result for now unless the
4095 // runtime function is properly implemented.
4096 (void)CGF.EmitRuntimeCall(
4097 OMPBuilder.getOrCreateRuntimeFunction(
4098 CGM.getModule(), OMPRTL___kmpc_omp_reg_task_with_affinity),
4099 {LocRef, GTid, NewTask, NumOfElements, AffinListPtr});
4100 }
4101 llvm::Value *NewTaskNewTaskTTy =
4103 NewTask, KmpTaskTWithPrivatesPtrTy);
4104 LValue Base = CGF.MakeNaturalAlignRawAddrLValue(NewTaskNewTaskTTy,
4105 KmpTaskTWithPrivatesQTy);
4106 LValue TDBase =
4107 CGF.EmitLValueForField(Base, *KmpTaskTWithPrivatesQTyRD->field_begin());
4108 // Fill the data in the resulting kmp_task_t record.
4109 // Copy shareds if there are any.
4110 Address KmpTaskSharedsPtr = Address::invalid();
4111 if (!SharedsTy->castAsRecordDecl()->field_empty()) {
4112 KmpTaskSharedsPtr = Address(
4113 CGF.EmitLoadOfScalar(
4115 TDBase,
4116 *std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTShareds)),
4117 Loc),
4118 CGF.Int8Ty, CGM.getNaturalTypeAlignment(SharedsTy));
4119 LValue Dest = CGF.MakeAddrLValue(KmpTaskSharedsPtr, SharedsTy);
4120 LValue Src = CGF.MakeAddrLValue(Shareds, SharedsTy);
4121 CGF.EmitAggregateCopy(Dest, Src, SharedsTy, AggValueSlot::DoesNotOverlap);
4122 }
4123 // Emit initial values for private copies (if any).
4125 if (!Privates.empty()) {
4126 emitPrivatesInit(CGF, D, KmpTaskSharedsPtr, Base, KmpTaskTWithPrivatesQTyRD,
4127 SharedsTy, SharedsPtrTy, Data, Privates,
4128 /*ForDup=*/false);
4129 if (isOpenMPTaskLoopDirective(D.getDirectiveKind()) &&
4130 (!Data.LastprivateVars.empty() || checkInitIsRequired(CGF, Privates))) {
4131 Result.TaskDupFn = emitTaskDupFunction(
4132 CGM, Loc, D, KmpTaskTWithPrivatesPtrQTy, KmpTaskTWithPrivatesQTyRD,
4133 KmpTaskTQTyRD, SharedsTy, SharedsPtrTy, Data, Privates,
4134 /*WithLastIter=*/!Data.LastprivateVars.empty());
4135 }
4136 }
4137 // Fields of union "kmp_cmplrdata_t" for destructors and priority.
4138 enum { Priority = 0, Destructors = 1 };
4139 // Provide pointer to function with destructors for privates.
4140 auto FI = std::next(KmpTaskTQTyRD->field_begin(), Data1);
4141 const auto *KmpCmplrdataUD = (*FI)->getType()->castAsRecordDecl();
4142 assert(KmpCmplrdataUD->isUnion());
4143 if (NeedsCleanup) {
4144 llvm::Value *DestructorFn = emitDestructorsFunction(
4145 CGM, Loc, KmpInt32Ty, KmpTaskTWithPrivatesPtrQTy,
4146 KmpTaskTWithPrivatesQTy);
4147 LValue Data1LV = CGF.EmitLValueForField(TDBase, *FI);
4148 LValue DestructorsLV = CGF.EmitLValueForField(
4149 Data1LV, *std::next(KmpCmplrdataUD->field_begin(), Destructors));
4151 DestructorFn, KmpRoutineEntryPtrTy),
4152 DestructorsLV);
4153 }
4154 // Set priority.
4155 if (Data.Priority.getInt()) {
4156 LValue Data2LV = CGF.EmitLValueForField(
4157 TDBase, *std::next(KmpTaskTQTyRD->field_begin(), Data2));
4158 LValue PriorityLV = CGF.EmitLValueForField(
4159 Data2LV, *std::next(KmpCmplrdataUD->field_begin(), Priority));
4160 CGF.EmitStoreOfScalar(Data.Priority.getPointer(), PriorityLV);
4161 }
4162 Result.NewTask = NewTask;
4163 Result.TaskEntry = TaskEntry;
4164 Result.NewTaskNewTaskTTy = NewTaskNewTaskTTy;
4165 Result.TDBase = TDBase;
4166 Result.KmpTaskTQTyRD = KmpTaskTQTyRD;
4167 return Result;
4168}
4169
4170/// Translates internal dependency kind into the runtime kind.
4172 RTLDependenceKindTy DepKind;
4173 switch (K) {
4174 case OMPC_DEPEND_in:
4175 DepKind = RTLDependenceKindTy::DepIn;
4176 break;
4177 // Out and InOut dependencies must use the same code.
4178 case OMPC_DEPEND_out:
4179 case OMPC_DEPEND_inout:
4180 DepKind = RTLDependenceKindTy::DepInOut;
4181 break;
4182 case OMPC_DEPEND_mutexinoutset:
4183 DepKind = RTLDependenceKindTy::DepMutexInOutSet;
4184 break;
4185 case OMPC_DEPEND_inoutset:
4186 DepKind = RTLDependenceKindTy::DepInOutSet;
4187 break;
4188 case OMPC_DEPEND_outallmemory:
4189 DepKind = RTLDependenceKindTy::DepOmpAllMem;
4190 break;
4191 case OMPC_DEPEND_source:
4192 case OMPC_DEPEND_sink:
4193 case OMPC_DEPEND_depobj:
4194 case OMPC_DEPEND_inoutallmemory:
4196 llvm_unreachable("Unknown task dependence type");
4197 }
4198 return DepKind;
4199}
4200
4201/// Builds kmp_depend_info, if it is not built yet, and builds flags type.
4202static void getDependTypes(ASTContext &C, QualType &KmpDependInfoTy,
4203 QualType &FlagsTy) {
4204 FlagsTy = C.getIntTypeForBitwidth(C.getTypeSize(C.BoolTy), /*Signed=*/false);
4205 if (KmpDependInfoTy.isNull()) {
4206 RecordDecl *KmpDependInfoRD = C.buildImplicitRecord("kmp_depend_info");
4207 KmpDependInfoRD->startDefinition();
4208 addFieldToRecordDecl(C, KmpDependInfoRD, C.getIntPtrType());
4209 addFieldToRecordDecl(C, KmpDependInfoRD, C.getSizeType());
4210 addFieldToRecordDecl(C, KmpDependInfoRD, FlagsTy);
4211 KmpDependInfoRD->completeDefinition();
4212 KmpDependInfoTy = C.getCanonicalTagType(KmpDependInfoRD);
4213 }
4214}
4215
4216std::pair<llvm::Value *, LValue>
4218 SourceLocation Loc) {
4219 ASTContext &C = CGM.getContext();
4220 QualType FlagsTy;
4221 getDependTypes(C, KmpDependInfoTy, FlagsTy);
4222 auto *KmpDependInfoRD = KmpDependInfoTy->castAsRecordDecl();
4223 QualType KmpDependInfoPtrTy = C.getPointerType(KmpDependInfoTy);
4225 DepobjLVal.getAddress().withElementType(
4226 CGF.ConvertTypeForMem(KmpDependInfoPtrTy)),
4227 KmpDependInfoPtrTy->castAs<PointerType>());
4228 Address DepObjAddr = CGF.Builder.CreateGEP(
4229 CGF, Base.getAddress(),
4230 llvm::ConstantInt::get(CGF.IntPtrTy, -1, /*isSigned=*/true));
4231 LValue NumDepsBase = CGF.MakeAddrLValue(
4232 DepObjAddr, KmpDependInfoTy, Base.getBaseInfo(), Base.getTBAAInfo());
4233 // NumDeps = deps[i].base_addr;
4234 LValue BaseAddrLVal = CGF.EmitLValueForField(
4235 NumDepsBase,
4236 *std::next(KmpDependInfoRD->field_begin(),
4237 static_cast<unsigned int>(RTLDependInfoFields::BaseAddr)));
4238 llvm::Value *NumDeps = CGF.EmitLoadOfScalar(BaseAddrLVal, Loc);
4239 return std::make_pair(NumDeps, Base);
4240}
4241
4242static void emitDependData(CodeGenFunction &CGF, QualType &KmpDependInfoTy,
4243 llvm::PointerUnion<unsigned *, LValue *> Pos,
4245 Address DependenciesArray) {
4246 CodeGenModule &CGM = CGF.CGM;
4247 ASTContext &C = CGM.getContext();
4248 QualType FlagsTy;
4249 getDependTypes(C, KmpDependInfoTy, FlagsTy);
4250 auto *KmpDependInfoRD = KmpDependInfoTy->castAsRecordDecl();
4251 llvm::Type *LLVMFlagsTy = CGF.ConvertTypeForMem(FlagsTy);
4252
4253 OMPIteratorGeneratorScope IteratorScope(
4254 CGF, cast_or_null<OMPIteratorExpr>(
4255 Data.IteratorExpr ? Data.IteratorExpr->IgnoreParenImpCasts()
4256 : nullptr));
4257 for (const Expr *E : Data.DepExprs) {
4258 llvm::Value *Addr;
4259 llvm::Value *Size;
4260
4261 // The expression will be a nullptr in the 'omp_all_memory' case.
4262 if (E) {
4263 std::tie(Addr, Size) = getPointerAndSize(CGF, E);
4264 Addr = CGF.Builder.CreatePtrToInt(Addr, CGF.IntPtrTy);
4265 } else {
4266 Addr = llvm::ConstantInt::get(CGF.IntPtrTy, 0);
4267 Size = llvm::ConstantInt::get(CGF.SizeTy, 0);
4268 }
4269 LValue Base;
4270 if (unsigned *P = dyn_cast<unsigned *>(Pos)) {
4271 Base = CGF.MakeAddrLValue(
4272 CGF.Builder.CreateConstGEP(DependenciesArray, *P), KmpDependInfoTy);
4273 } else {
4274 assert(E && "Expected a non-null expression");
4275 LValue &PosLVal = *cast<LValue *>(Pos);
4276 llvm::Value *Idx = CGF.EmitLoadOfScalar(PosLVal, E->getExprLoc());
4277 Base = CGF.MakeAddrLValue(
4278 CGF.Builder.CreateGEP(CGF, DependenciesArray, Idx), KmpDependInfoTy);
4279 }
4280 // deps[i].base_addr = &<Dependencies[i].second>;
4281 LValue BaseAddrLVal = CGF.EmitLValueForField(
4282 Base,
4283 *std::next(KmpDependInfoRD->field_begin(),
4284 static_cast<unsigned int>(RTLDependInfoFields::BaseAddr)));
4285 CGF.EmitStoreOfScalar(Addr, BaseAddrLVal);
4286 // deps[i].len = sizeof(<Dependencies[i].second>);
4287 LValue LenLVal = CGF.EmitLValueForField(
4288 Base, *std::next(KmpDependInfoRD->field_begin(),
4289 static_cast<unsigned int>(RTLDependInfoFields::Len)));
4290 CGF.EmitStoreOfScalar(Size, LenLVal);
4291 // deps[i].flags = <Dependencies[i].first>;
4292 RTLDependenceKindTy DepKind = translateDependencyKind(Data.DepKind);
4293 LValue FlagsLVal = CGF.EmitLValueForField(
4294 Base,
4295 *std::next(KmpDependInfoRD->field_begin(),
4296 static_cast<unsigned int>(RTLDependInfoFields::Flags)));
4298 llvm::ConstantInt::get(LLVMFlagsTy, static_cast<unsigned int>(DepKind)),
4299 FlagsLVal);
4300 if (unsigned *P = dyn_cast<unsigned *>(Pos)) {
4301 ++(*P);
4302 } else {
4303 LValue &PosLVal = *cast<LValue *>(Pos);
4304 llvm::Value *Idx = CGF.EmitLoadOfScalar(PosLVal, E->getExprLoc());
4305 Idx = CGF.Builder.CreateNUWAdd(Idx,
4306 llvm::ConstantInt::get(Idx->getType(), 1));
4307 CGF.EmitStoreOfScalar(Idx, PosLVal);
4308 }
4309 }
4310}
4311
4315 assert(Data.DepKind == OMPC_DEPEND_depobj &&
4316 "Expected depobj dependency kind.");
4318 SmallVector<LValue, 4> SizeLVals;
4319 ASTContext &C = CGF.getContext();
4320 {
4321 OMPIteratorGeneratorScope IteratorScope(
4322 CGF, cast_or_null<OMPIteratorExpr>(
4323 Data.IteratorExpr ? Data.IteratorExpr->IgnoreParenImpCasts()
4324 : nullptr));
4325 for (const Expr *E : Data.DepExprs) {
4326 llvm::Value *NumDeps;
4327 LValue Base;
4328 LValue DepobjLVal = CGF.EmitLValue(E->IgnoreParenImpCasts());
4329 std::tie(NumDeps, Base) =
4330 getDepobjElements(CGF, DepobjLVal, E->getExprLoc());
4331 LValue NumLVal = CGF.MakeAddrLValue(
4332 CGF.CreateMemTempWithoutCast(C.getUIntPtrType(), "depobj.size.addr"),
4333 C.getUIntPtrType());
4334 CGF.Builder.CreateStore(llvm::ConstantInt::get(CGF.IntPtrTy, 0),
4335 NumLVal.getAddress());
4336 llvm::Value *PrevVal = CGF.EmitLoadOfScalar(NumLVal, E->getExprLoc());
4337 llvm::Value *Add = CGF.Builder.CreateNUWAdd(PrevVal, NumDeps);
4338 CGF.EmitStoreOfScalar(Add, NumLVal);
4339 SizeLVals.push_back(NumLVal);
4340 }
4341 }
4342 for (unsigned I = 0, E = SizeLVals.size(); I < E; ++I) {
4343 llvm::Value *Size =
4344 CGF.EmitLoadOfScalar(SizeLVals[I], Data.DepExprs[I]->getExprLoc());
4345 Sizes.push_back(Size);
4346 }
4347 return Sizes;
4348}
4349
4352 LValue PosLVal,
4354 Address DependenciesArray) {
4355 assert(Data.DepKind == OMPC_DEPEND_depobj &&
4356 "Expected depobj dependency kind.");
4357 llvm::Value *ElSize = CGF.getTypeSize(KmpDependInfoTy);
4358 {
4359 OMPIteratorGeneratorScope IteratorScope(
4360 CGF, cast_or_null<OMPIteratorExpr>(
4361 Data.IteratorExpr ? Data.IteratorExpr->IgnoreParenImpCasts()
4362 : nullptr));
4363 for (const Expr *E : Data.DepExprs) {
4364 llvm::Value *NumDeps;
4365 LValue Base;
4366 LValue DepobjLVal = CGF.EmitLValue(E->IgnoreParenImpCasts());
4367 std::tie(NumDeps, Base) =
4368 getDepobjElements(CGF, DepobjLVal, E->getExprLoc());
4369
4370 // memcopy dependency data.
4371 llvm::Value *Size = CGF.Builder.CreateNUWMul(
4372 ElSize,
4373 CGF.Builder.CreateIntCast(NumDeps, CGF.SizeTy, /*isSigned=*/false));
4374 llvm::Value *Pos = CGF.EmitLoadOfScalar(PosLVal, E->getExprLoc());
4375 Address DepAddr = CGF.Builder.CreateGEP(CGF, DependenciesArray, Pos);
4376 CGF.Builder.CreateMemCpy(DepAddr, Base.getAddress(), Size);
4377
4378 // Increase pos.
4379 // pos += size;
4380 llvm::Value *Add = CGF.Builder.CreateNUWAdd(Pos, NumDeps);
4381 CGF.EmitStoreOfScalar(Add, PosLVal);
4382 }
4383 }
4384}
4385
4386std::pair<llvm::Value *, Address> CGOpenMPRuntime::emitDependClause(
4388 SourceLocation Loc) {
4389 if (llvm::all_of(Dependencies, [](const OMPTaskDataTy::DependData &D) {
4390 return D.DepExprs.empty();
4391 }))
4392 return std::make_pair(nullptr, Address::invalid());
4393 // Process list of dependencies.
4394 ASTContext &C = CGM.getContext();
4395 Address DependenciesArray = Address::invalid();
4396 llvm::Value *NumOfElements = nullptr;
4397 unsigned NumDependencies = std::accumulate(
4398 Dependencies.begin(), Dependencies.end(), 0,
4399 [](unsigned V, const OMPTaskDataTy::DependData &D) {
4400 return D.DepKind == OMPC_DEPEND_depobj
4401 ? V
4402 : (V + (D.IteratorExpr ? 0 : D.DepExprs.size()));
4403 });
4404 QualType FlagsTy;
4405 getDependTypes(C, KmpDependInfoTy, FlagsTy);
4406 bool HasDepobjDeps = false;
4407 bool HasRegularWithIterators = false;
4408 llvm::Value *NumOfDepobjElements = llvm::ConstantInt::get(CGF.IntPtrTy, 0);
4409 llvm::Value *NumOfRegularWithIterators =
4410 llvm::ConstantInt::get(CGF.IntPtrTy, 0);
4411 // Calculate number of depobj dependencies and regular deps with the
4412 // iterators.
4413 for (const OMPTaskDataTy::DependData &D : Dependencies) {
4414 if (D.DepKind == OMPC_DEPEND_depobj) {
4417 for (llvm::Value *Size : Sizes) {
4418 NumOfDepobjElements =
4419 CGF.Builder.CreateNUWAdd(NumOfDepobjElements, Size);
4420 }
4421 HasDepobjDeps = true;
4422 continue;
4423 }
4424 // Include number of iterations, if any.
4425
4426 if (const auto *IE = cast_or_null<OMPIteratorExpr>(D.IteratorExpr)) {
4427 llvm::Value *ClauseIteratorSpace =
4428 llvm::ConstantInt::get(CGF.IntPtrTy, 1);
4429 for (unsigned I = 0, E = IE->numOfIterators(); I < E; ++I) {
4430 llvm::Value *Sz = CGF.EmitScalarExpr(IE->getHelper(I).Upper);
4431 Sz = CGF.Builder.CreateIntCast(Sz, CGF.IntPtrTy, /*isSigned=*/false);
4432 ClauseIteratorSpace = CGF.Builder.CreateNUWMul(Sz, ClauseIteratorSpace);
4433 }
4434 llvm::Value *NumClauseDeps = CGF.Builder.CreateNUWMul(
4435 ClauseIteratorSpace,
4436 llvm::ConstantInt::get(CGF.IntPtrTy, D.DepExprs.size()));
4437 NumOfRegularWithIterators =
4438 CGF.Builder.CreateNUWAdd(NumOfRegularWithIterators, NumClauseDeps);
4439 HasRegularWithIterators = true;
4440 continue;
4441 }
4442 }
4443
4444 QualType KmpDependInfoArrayTy;
4445 if (HasDepobjDeps || HasRegularWithIterators) {
4446 NumOfElements = llvm::ConstantInt::get(CGM.IntPtrTy, NumDependencies,
4447 /*isSigned=*/false);
4448 if (HasDepobjDeps) {
4449 NumOfElements =
4450 CGF.Builder.CreateNUWAdd(NumOfDepobjElements, NumOfElements);
4451 }
4452 if (HasRegularWithIterators) {
4453 NumOfElements =
4454 CGF.Builder.CreateNUWAdd(NumOfRegularWithIterators, NumOfElements);
4455 }
4456 auto *OVE = new (C) OpaqueValueExpr(
4457 Loc, C.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/0),
4458 VK_PRValue);
4459 CodeGenFunction::OpaqueValueMapping OpaqueMap(CGF, OVE,
4460 RValue::get(NumOfElements));
4461 KmpDependInfoArrayTy =
4462 C.getVariableArrayType(KmpDependInfoTy, OVE, ArraySizeModifier::Normal,
4463 /*IndexTypeQuals=*/0);
4464 // CGF.EmitVariablyModifiedType(KmpDependInfoArrayTy);
4465 // Properly emit variable-sized array.
4466 auto *PD = ImplicitParamDecl::Create(C, KmpDependInfoArrayTy,
4468 CGF.EmitVarDecl(*PD);
4469 DependenciesArray = CGF.GetAddrOfLocalVar(PD);
4470 NumOfElements = CGF.Builder.CreateIntCast(NumOfElements, CGF.Int32Ty,
4471 /*isSigned=*/false);
4472 } else {
4473 KmpDependInfoArrayTy = C.getConstantArrayType(
4474 KmpDependInfoTy, llvm::APInt(/*numBits=*/64, NumDependencies), nullptr,
4475 ArraySizeModifier::Normal, /*IndexTypeQuals=*/0);
4476 DependenciesArray =
4477 CGF.CreateMemTempWithoutCast(KmpDependInfoArrayTy, ".dep.arr.addr");
4478 DependenciesArray = CGF.Builder.CreateConstArrayGEP(DependenciesArray, 0);
4479 NumOfElements = llvm::ConstantInt::get(CGM.Int32Ty, NumDependencies,
4480 /*isSigned=*/false);
4481 }
4482 unsigned Pos = 0;
4483 for (const OMPTaskDataTy::DependData &Dep : Dependencies) {
4484 if (Dep.DepKind == OMPC_DEPEND_depobj || Dep.IteratorExpr)
4485 continue;
4486 emitDependData(CGF, KmpDependInfoTy, &Pos, Dep, DependenciesArray);
4487 }
4488 // Copy regular dependencies with iterators.
4489 LValue PosLVal = CGF.MakeAddrLValue(
4490 CGF.CreateMemTempWithoutCast(C.getSizeType(), "dep.counter.addr"),
4491 C.getSizeType());
4492 CGF.EmitStoreOfScalar(llvm::ConstantInt::get(CGF.SizeTy, Pos), PosLVal);
4493 for (const OMPTaskDataTy::DependData &Dep : Dependencies) {
4494 if (Dep.DepKind == OMPC_DEPEND_depobj || !Dep.IteratorExpr)
4495 continue;
4496 emitDependData(CGF, KmpDependInfoTy, &PosLVal, Dep, DependenciesArray);
4497 }
4498 // Copy final depobj arrays without iterators.
4499 if (HasDepobjDeps) {
4500 for (const OMPTaskDataTy::DependData &Dep : Dependencies) {
4501 if (Dep.DepKind != OMPC_DEPEND_depobj)
4502 continue;
4503 emitDepobjElements(CGF, KmpDependInfoTy, PosLVal, Dep, DependenciesArray);
4504 }
4505 }
4506 DependenciesArray = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
4507 DependenciesArray, CGF.VoidPtrTy, CGF.Int8Ty);
4508 return std::make_pair(NumOfElements, DependenciesArray);
4509}
4510
4512 CodeGenFunction &CGF, const OMPTaskDataTy::DependData &Dependencies,
4513 SourceLocation Loc) {
4514 if (Dependencies.DepExprs.empty())
4515 return Address::invalid();
4516 // Process list of dependencies.
4517 ASTContext &C = CGM.getContext();
4518 Address DependenciesArray = Address::invalid();
4519 unsigned NumDependencies = Dependencies.DepExprs.size();
4520 QualType FlagsTy;
4521 getDependTypes(C, KmpDependInfoTy, FlagsTy);
4522 auto *KmpDependInfoRD = KmpDependInfoTy->castAsRecordDecl();
4523
4524 llvm::Value *Size;
4525 // Define type kmp_depend_info[<Dependencies.size()>];
4526 // For depobj reserve one extra element to store the number of elements.
4527 // It is required to handle depobj(x) update(in) construct.
4528 // kmp_depend_info[<Dependencies.size()>] deps;
4529 llvm::Value *NumDepsVal;
4530 CharUnits Align = C.getTypeAlignInChars(KmpDependInfoTy);
4531 if (const auto *IE =
4532 cast_or_null<OMPIteratorExpr>(Dependencies.IteratorExpr)) {
4533 NumDepsVal = llvm::ConstantInt::get(CGF.SizeTy, 1);
4534 for (unsigned I = 0, E = IE->numOfIterators(); I < E; ++I) {
4535 llvm::Value *Sz = CGF.EmitScalarExpr(IE->getHelper(I).Upper);
4536 Sz = CGF.Builder.CreateIntCast(Sz, CGF.SizeTy, /*isSigned=*/false);
4537 NumDepsVal = CGF.Builder.CreateNUWMul(NumDepsVal, Sz);
4538 }
4539 Size = CGF.Builder.CreateNUWAdd(llvm::ConstantInt::get(CGF.SizeTy, 1),
4540 NumDepsVal);
4541 CharUnits SizeInBytes =
4542 C.getTypeSizeInChars(KmpDependInfoTy).alignTo(Align);
4543 llvm::Value *RecSize = CGM.getSize(SizeInBytes);
4544 Size = CGF.Builder.CreateNUWMul(Size, RecSize);
4545 NumDepsVal =
4546 CGF.Builder.CreateIntCast(NumDepsVal, CGF.IntPtrTy, /*isSigned=*/false);
4547 } else {
4548 QualType KmpDependInfoArrayTy = C.getConstantArrayType(
4549 KmpDependInfoTy, llvm::APInt(/*numBits=*/64, NumDependencies + 1),
4550 nullptr, ArraySizeModifier::Normal, /*IndexTypeQuals=*/0);
4551 CharUnits Sz = C.getTypeSizeInChars(KmpDependInfoArrayTy);
4552 Size = CGM.getSize(Sz.alignTo(Align));
4553 NumDepsVal = llvm::ConstantInt::get(CGF.IntPtrTy, NumDependencies);
4554 }
4555 // Need to allocate on the dynamic memory.
4556 llvm::Value *ThreadID = getThreadID(CGF, Loc);
4557 // Use default allocator.
4558 llvm::Value *Allocator = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
4559 llvm::Value *Args[] = {ThreadID, Size, Allocator};
4560
4561 llvm::Value *Addr =
4562 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
4563 CGM.getModule(), OMPRTL___kmpc_alloc),
4564 Args, ".dep.arr.addr");
4565 llvm::Type *KmpDependInfoLlvmTy = CGF.ConvertTypeForMem(KmpDependInfoTy);
4567 Addr, CGF.Builder.getPtrTy(0));
4568 DependenciesArray = Address(Addr, KmpDependInfoLlvmTy, Align);
4569 // Write number of elements in the first element of array for depobj.
4570 LValue Base = CGF.MakeAddrLValue(DependenciesArray, KmpDependInfoTy);
4571 // deps[i].base_addr = NumDependencies;
4572 LValue BaseAddrLVal = CGF.EmitLValueForField(
4573 Base,
4574 *std::next(KmpDependInfoRD->field_begin(),
4575 static_cast<unsigned int>(RTLDependInfoFields::BaseAddr)));
4576 CGF.EmitStoreOfScalar(NumDepsVal, BaseAddrLVal);
4577 llvm::PointerUnion<unsigned *, LValue *> Pos;
4578 unsigned Idx = 1;
4579 LValue PosLVal;
4580 if (Dependencies.IteratorExpr) {
4581 PosLVal = CGF.MakeAddrLValue(
4582 CGF.CreateMemTempWithoutCast(C.getSizeType(), "iterator.counter.addr"),
4583 C.getSizeType());
4584 CGF.EmitStoreOfScalar(llvm::ConstantInt::get(CGF.SizeTy, Idx), PosLVal,
4585 /*IsInit=*/true);
4586 Pos = &PosLVal;
4587 } else {
4588 Pos = &Idx;
4589 }
4590 emitDependData(CGF, KmpDependInfoTy, Pos, Dependencies, DependenciesArray);
4591 DependenciesArray = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
4592 CGF.Builder.CreateConstGEP(DependenciesArray, 1), CGF.VoidPtrTy,
4593 CGF.Int8Ty);
4594 return DependenciesArray;
4595}
4596
4598 SourceLocation Loc) {
4599 ASTContext &C = CGM.getContext();
4600 QualType FlagsTy;
4601 getDependTypes(C, KmpDependInfoTy, FlagsTy);
4602 LValue Base = CGF.EmitLoadOfPointerLValue(DepobjLVal.getAddress(),
4603 C.VoidPtrTy.castAs<PointerType>());
4604 QualType KmpDependInfoPtrTy = C.getPointerType(KmpDependInfoTy);
4606 Base.getAddress(), CGF.ConvertTypeForMem(KmpDependInfoPtrTy),
4608 llvm::Value *DepObjAddr = CGF.Builder.CreateGEP(
4609 Addr.getElementType(), Addr.emitRawPointer(CGF),
4610 llvm::ConstantInt::get(CGF.IntPtrTy, -1, /*isSigned=*/true));
4611 DepObjAddr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(DepObjAddr,
4612 CGF.VoidPtrTy);
4613 llvm::Value *ThreadID = getThreadID(CGF, Loc);
4614 // Use default allocator.
4615 llvm::Value *Allocator = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
4616 llvm::Value *Args[] = {ThreadID, DepObjAddr, Allocator};
4617
4618 // _kmpc_free(gtid, addr, nullptr);
4619 (void)CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
4620 CGM.getModule(), OMPRTL___kmpc_free),
4621 Args);
4622}
4623
4625 CodeGenFunction &CGF, LValue DepobjLVal, OpenMPDependClauseKind NewDepKind,
4626 SourceLocation Loc) {
4627 ASTContext &C = CGM.getContext();
4628 QualType FlagsTy;
4629 getDependTypes(C, KmpDependInfoTy, FlagsTy);
4630 auto *KmpDependInfoRD = KmpDependInfoTy->castAsRecordDecl();
4631 llvm::Type *LLVMFlagsTy = CGF.ConvertTypeForMem(FlagsTy);
4632 llvm::Value *NumDeps;
4633 LValue Base;
4634 std::tie(NumDeps, Base) = getDepobjElements(CGF, DepobjLVal, Loc);
4635
4636 Address Begin = Base.getAddress();
4637 // Cast from pointer to array type to pointer to single element.
4638 llvm::Value *End = CGF.Builder.CreateGEP(Begin.getElementType(),
4639 Begin.emitRawPointer(CGF), NumDeps);
4640 // The basic structure here is a while-do loop.
4641 llvm::BasicBlock *BodyBB = CGF.createBasicBlock("omp.body");
4642 llvm::BasicBlock *DoneBB = CGF.createBasicBlock("omp.done");
4643 llvm::BasicBlock *EntryBB = CGF.Builder.GetInsertBlock();
4644 CGF.EmitBlock(BodyBB);
4645 llvm::PHINode *ElementPHI =
4646 CGF.Builder.CreatePHI(Begin.getType(), 2, "omp.elementPast");
4647 ElementPHI->addIncoming(Begin.emitRawPointer(CGF), EntryBB);
4648 Begin = Begin.withPointer(ElementPHI, KnownNonNull);
4649 Base = CGF.MakeAddrLValue(Begin, KmpDependInfoTy, Base.getBaseInfo(),
4650 Base.getTBAAInfo());
4651 // deps[i].flags = NewDepKind;
4652 RTLDependenceKindTy DepKind = translateDependencyKind(NewDepKind);
4653 LValue FlagsLVal = CGF.EmitLValueForField(
4654 Base, *std::next(KmpDependInfoRD->field_begin(),
4655 static_cast<unsigned int>(RTLDependInfoFields::Flags)));
4657 llvm::ConstantInt::get(LLVMFlagsTy, static_cast<unsigned int>(DepKind)),
4658 FlagsLVal);
4659
4660 // Shift the address forward by one element.
4661 llvm::Value *ElementNext =
4662 CGF.Builder.CreateConstGEP(Begin, /*Index=*/1, "omp.elementNext")
4663 .emitRawPointer(CGF);
4664 ElementPHI->addIncoming(ElementNext, CGF.Builder.GetInsertBlock());
4665 llvm::Value *IsEmpty =
4666 CGF.Builder.CreateICmpEQ(ElementNext, End, "omp.isempty");
4667 CGF.Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB);
4668 // Done.
4669 CGF.EmitBlock(DoneBB, /*IsFinished=*/true);
4670}
4671
4673 const OMPExecutableDirective &D,
4674 llvm::Function *TaskFunction,
4675 QualType SharedsTy, Address Shareds,
4676 const Expr *IfCond,
4677 const OMPTaskDataTy &Data) {
4678 if (!CGF.HaveInsertPoint())
4679 return;
4680
4682 emitTaskInit(CGF, Loc, D, TaskFunction, SharedsTy, Shareds, Data);
4683 llvm::Value *NewTask = Result.NewTask;
4684 llvm::Function *TaskEntry = Result.TaskEntry;
4685 llvm::Value *NewTaskNewTaskTTy = Result.NewTaskNewTaskTTy;
4686 LValue TDBase = Result.TDBase;
4687 const RecordDecl *KmpTaskTQTyRD = Result.KmpTaskTQTyRD;
4688 // Process list of dependences.
4689 Address DependenciesArray = Address::invalid();
4690 llvm::Value *NumOfElements;
4691 std::tie(NumOfElements, DependenciesArray) =
4692 emitDependClause(CGF, Data.Dependences, Loc);
4693
4694 // NOTE: routine and part_id fields are initialized by __kmpc_omp_task_alloc()
4695 // libcall.
4696 // Build kmp_int32 __kmpc_omp_task_with_deps(ident_t *, kmp_int32 gtid,
4697 // kmp_task_t *new_task, kmp_int32 ndeps, kmp_depend_info_t *dep_list,
4698 // kmp_int32 ndeps_noalias, kmp_depend_info_t *noalias_dep_list) if dependence
4699 // list is not empty
4700 llvm::Value *ThreadID = getThreadID(CGF, Loc);
4701 llvm::Value *UpLoc = emitUpdateLocation(CGF, Loc);
4702 llvm::Value *TaskArgs[] = { UpLoc, ThreadID, NewTask };
4703 llvm::Value *DepTaskArgs[7];
4704 if (!Data.Dependences.empty()) {
4705 DepTaskArgs[0] = UpLoc;
4706 DepTaskArgs[1] = ThreadID;
4707 DepTaskArgs[2] = NewTask;
4708 DepTaskArgs[3] = NumOfElements;
4709 DepTaskArgs[4] = DependenciesArray.emitRawPointer(CGF);
4710 DepTaskArgs[5] = CGF.Builder.getInt32(0);
4711 DepTaskArgs[6] = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
4712 }
4713 auto &&ThenCodeGen = [this, &Data, TDBase, KmpTaskTQTyRD, &TaskArgs,
4714 &DepTaskArgs](CodeGenFunction &CGF, PrePostActionTy &) {
4715 if (!Data.Tied) {
4716 auto PartIdFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTPartId);
4717 LValue PartIdLVal = CGF.EmitLValueForField(TDBase, *PartIdFI);
4718 CGF.EmitStoreOfScalar(CGF.Builder.getInt32(0), PartIdLVal);
4719 }
4720 if (!Data.Dependences.empty()) {
4721 CGF.EmitRuntimeCall(
4722 OMPBuilder.getOrCreateRuntimeFunction(
4723 CGM.getModule(), OMPRTL___kmpc_omp_task_with_deps),
4724 DepTaskArgs);
4725 } else {
4726 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
4727 CGM.getModule(), OMPRTL___kmpc_omp_task),
4728 TaskArgs);
4729 }
4730 // Check if parent region is untied and build return for untied task;
4731 if (auto *Region =
4732 dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo))
4733 Region->emitUntiedSwitch(CGF);
4734 };
4735
4736 llvm::Value *DepWaitTaskArgs[7];
4737 if (!Data.Dependences.empty()) {
4738 DepWaitTaskArgs[0] = UpLoc;
4739 DepWaitTaskArgs[1] = ThreadID;
4740 DepWaitTaskArgs[2] = NumOfElements;
4741 DepWaitTaskArgs[3] = DependenciesArray.emitRawPointer(CGF);
4742 DepWaitTaskArgs[4] = CGF.Builder.getInt32(0);
4743 DepWaitTaskArgs[5] = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
4744 DepWaitTaskArgs[6] =
4745 llvm::ConstantInt::get(CGF.Int32Ty, Data.HasNowaitClause);
4746 }
4747 auto &M = CGM.getModule();
4748 auto &&ElseCodeGen = [this, &M, &TaskArgs, ThreadID, NewTaskNewTaskTTy,
4749 TaskEntry, &Data, &DepWaitTaskArgs,
4750 Loc](CodeGenFunction &CGF, PrePostActionTy &) {
4751 CodeGenFunction::RunCleanupsScope LocalScope(CGF);
4752 // Build void __kmpc_omp_wait_deps(ident_t *, kmp_int32 gtid,
4753 // kmp_int32 ndeps, kmp_depend_info_t *dep_list, kmp_int32
4754 // ndeps_noalias, kmp_depend_info_t *noalias_dep_list); if dependence info
4755 // is specified.
4756 if (!Data.Dependences.empty())
4757 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
4758 M, OMPRTL___kmpc_omp_taskwait_deps_51),
4759 DepWaitTaskArgs);
4760 // Call proxy_task_entry(gtid, new_task);
4761 auto &&CodeGen = [TaskEntry, ThreadID, NewTaskNewTaskTTy,
4762 Loc](CodeGenFunction &CGF, PrePostActionTy &Action) {
4763 Action.Enter(CGF);
4764 llvm::Value *OutlinedFnArgs[] = {ThreadID, NewTaskNewTaskTTy};
4765 CGF.CGM.getOpenMPRuntime().emitOutlinedFunctionCall(CGF, Loc, TaskEntry,
4766 OutlinedFnArgs);
4767 };
4768
4769 // Build void __kmpc_omp_task_begin_if0(ident_t *, kmp_int32 gtid,
4770 // kmp_task_t *new_task);
4771 // Build void __kmpc_omp_task_complete_if0(ident_t *, kmp_int32 gtid,
4772 // kmp_task_t *new_task);
4774 CommonActionTy Action(OMPBuilder.getOrCreateRuntimeFunction(
4775 M, OMPRTL___kmpc_omp_task_begin_if0),
4776 TaskArgs,
4777 OMPBuilder.getOrCreateRuntimeFunction(
4778 M, OMPRTL___kmpc_omp_task_complete_if0),
4779 TaskArgs);
4780 RCG.setAction(Action);
4781 RCG(CGF);
4782 };
4783
4784 if (IfCond) {
4785 emitIfClause(CGF, IfCond, ThenCodeGen, ElseCodeGen);
4786 } else {
4787 RegionCodeGenTy ThenRCG(ThenCodeGen);
4788 ThenRCG(CGF);
4789 }
4790}
4791
4793 const OMPLoopDirective &D,
4794 llvm::Function *TaskFunction,
4795 QualType SharedsTy, Address Shareds,
4796 const Expr *IfCond,
4797 const OMPTaskDataTy &Data) {
4798 if (!CGF.HaveInsertPoint())
4799 return;
4801 emitTaskInit(CGF, Loc, D, TaskFunction, SharedsTy, Shareds, Data);
4802 // NOTE: routine and part_id fields are initialized by __kmpc_omp_task_alloc()
4803 // libcall.
4804 // Call to void __kmpc_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int
4805 // if_val, kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, int nogroup, int
4806 // sched, kmp_uint64 grainsize, void *task_dup);
4807 llvm::Value *ThreadID = getThreadID(CGF, Loc);
4808 llvm::Value *UpLoc = emitUpdateLocation(CGF, Loc);
4809 llvm::Value *IfVal;
4810 if (IfCond) {
4811 IfVal = CGF.Builder.CreateIntCast(CGF.EvaluateExprAsBool(IfCond), CGF.IntTy,
4812 /*isSigned=*/true);
4813 } else {
4814 IfVal = llvm::ConstantInt::getSigned(CGF.IntTy, /*V=*/1);
4815 }
4816
4817 LValue LBLVal = CGF.EmitLValueForField(
4818 Result.TDBase,
4819 *std::next(Result.KmpTaskTQTyRD->field_begin(), KmpTaskTLowerBound));
4820 const auto *LBVar =
4821 cast<VarDecl>(cast<DeclRefExpr>(D.getLowerBoundVariable())->getDecl());
4822 CGF.EmitAnyExprToMem(LBVar->getInit(), LBLVal.getAddress(), LBLVal.getQuals(),
4823 /*IsInitializer=*/true);
4824 LValue UBLVal = CGF.EmitLValueForField(
4825 Result.TDBase,
4826 *std::next(Result.KmpTaskTQTyRD->field_begin(), KmpTaskTUpperBound));
4827 const auto *UBVar =
4828 cast<VarDecl>(cast<DeclRefExpr>(D.getUpperBoundVariable())->getDecl());
4829 CGF.EmitAnyExprToMem(UBVar->getInit(), UBLVal.getAddress(), UBLVal.getQuals(),
4830 /*IsInitializer=*/true);
4831 LValue StLVal = CGF.EmitLValueForField(
4832 Result.TDBase,
4833 *std::next(Result.KmpTaskTQTyRD->field_begin(), KmpTaskTStride));
4834 const auto *StVar =
4835 cast<VarDecl>(cast<DeclRefExpr>(D.getStrideVariable())->getDecl());
4836 CGF.EmitAnyExprToMem(StVar->getInit(), StLVal.getAddress(), StLVal.getQuals(),
4837 /*IsInitializer=*/true);
4838 // Store reductions address.
4839 LValue RedLVal = CGF.EmitLValueForField(
4840 Result.TDBase,
4841 *std::next(Result.KmpTaskTQTyRD->field_begin(), KmpTaskTReductions));
4842 if (Data.Reductions) {
4843 CGF.EmitStoreOfScalar(Data.Reductions, RedLVal);
4844 } else {
4845 CGF.EmitNullInitialization(RedLVal.getAddress(),
4846 CGF.getContext().VoidPtrTy);
4847 }
4848 enum { NoSchedule = 0, Grainsize = 1, NumTasks = 2 };
4850 UpLoc,
4851 ThreadID,
4852 Result.NewTask,
4853 IfVal,
4854 LBLVal.getPointer(CGF),
4855 UBLVal.getPointer(CGF),
4856 CGF.EmitLoadOfScalar(StLVal, Loc),
4857 llvm::ConstantInt::getSigned(
4858 CGF.IntTy, 1), // Always 1 because taskgroup emitted by the compiler
4859 llvm::ConstantInt::getSigned(
4860 CGF.IntTy, Data.Schedule.getPointer()
4861 ? Data.Schedule.getInt() ? NumTasks : Grainsize
4862 : NoSchedule),
4863 Data.Schedule.getPointer()
4864 ? CGF.Builder.CreateIntCast(Data.Schedule.getPointer(), CGF.Int64Ty,
4865 /*isSigned=*/false)
4866 : llvm::ConstantInt::get(CGF.Int64Ty, /*V=*/0)};
4867 if (Data.HasModifier)
4868 TaskArgs.push_back(llvm::ConstantInt::get(CGF.Int32Ty, 1));
4869
4870 TaskArgs.push_back(Result.TaskDupFn
4872 Result.TaskDupFn, CGF.VoidPtrTy)
4873 : llvm::ConstantPointerNull::get(CGF.VoidPtrTy));
4874 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
4875 CGM.getModule(), Data.HasModifier
4876 ? OMPRTL___kmpc_taskloop_5
4877 : OMPRTL___kmpc_taskloop),
4878 TaskArgs);
4879}
4880
4881/// Emit reduction operation for each element of array (required for
4882/// array sections) LHS op = RHS.
4883/// \param Type Type of array.
4884/// \param LHSVar Variable on the left side of the reduction operation
4885/// (references element of array in original variable).
4886/// \param RHSVar Variable on the right side of the reduction operation
4887/// (references element of array in original variable).
4888/// \param RedOpGen Generator of reduction operation with use of LHSVar and
4889/// RHSVar.
4891 CodeGenFunction &CGF, QualType Type, const VarDecl *LHSVar,
4892 const VarDecl *RHSVar,
4893 const llvm::function_ref<void(CodeGenFunction &CGF, const Expr *,
4894 const Expr *, const Expr *)> &RedOpGen,
4895 const Expr *XExpr = nullptr, const Expr *EExpr = nullptr,
4896 const Expr *UpExpr = nullptr) {
4897 // Perform element-by-element initialization.
4898 QualType ElementTy;
4899 Address LHSAddr = CGF.GetAddrOfLocalVar(LHSVar);
4900 Address RHSAddr = CGF.GetAddrOfLocalVar(RHSVar);
4901
4902 // Drill down to the base element type on both arrays.
4903 const ArrayType *ArrayTy = Type->getAsArrayTypeUnsafe();
4904 llvm::Value *NumElements = CGF.emitArrayLength(ArrayTy, ElementTy, LHSAddr);
4905
4906 llvm::Value *RHSBegin = RHSAddr.emitRawPointer(CGF);
4907 llvm::Value *LHSBegin = LHSAddr.emitRawPointer(CGF);
4908 // Cast from pointer to array type to pointer to single element.
4909 llvm::Value *LHSEnd =
4910 CGF.Builder.CreateGEP(LHSAddr.getElementType(), LHSBegin, NumElements);
4911 // The basic structure here is a while-do loop.
4912 llvm::BasicBlock *BodyBB = CGF.createBasicBlock("omp.arraycpy.body");
4913 llvm::BasicBlock *DoneBB = CGF.createBasicBlock("omp.arraycpy.done");
4914 llvm::Value *IsEmpty =
4915 CGF.Builder.CreateICmpEQ(LHSBegin, LHSEnd, "omp.arraycpy.isempty");
4916 CGF.Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB);
4917
4918 // Enter the loop body, making that address the current address.
4919 llvm::BasicBlock *EntryBB = CGF.Builder.GetInsertBlock();
4920 CGF.EmitBlock(BodyBB);
4921
4922 CharUnits ElementSize = CGF.getContext().getTypeSizeInChars(ElementTy);
4923
4924 llvm::PHINode *RHSElementPHI = CGF.Builder.CreatePHI(
4925 RHSBegin->getType(), 2, "omp.arraycpy.srcElementPast");
4926 RHSElementPHI->addIncoming(RHSBegin, EntryBB);
4927 Address RHSElementCurrent(
4928 RHSElementPHI, RHSAddr.getElementType(),
4929 RHSAddr.getAlignment().alignmentOfArrayElement(ElementSize));
4930
4931 llvm::PHINode *LHSElementPHI = CGF.Builder.CreatePHI(
4932 LHSBegin->getType(), 2, "omp.arraycpy.destElementPast");
4933 LHSElementPHI->addIncoming(LHSBegin, EntryBB);
4934 Address LHSElementCurrent(
4935 LHSElementPHI, LHSAddr.getElementType(),
4936 LHSAddr.getAlignment().alignmentOfArrayElement(ElementSize));
4937
4938 // Emit copy.
4940 Scope.addPrivate(LHSVar, LHSElementCurrent);
4941 Scope.addPrivate(RHSVar, RHSElementCurrent);
4942 Scope.Privatize();
4943 RedOpGen(CGF, XExpr, EExpr, UpExpr);
4944 Scope.ForceCleanup();
4945
4946 // Shift the address forward by one element.
4947 llvm::Value *LHSElementNext = CGF.Builder.CreateConstGEP1_32(
4948 LHSAddr.getElementType(), LHSElementPHI, /*Idx0=*/1,
4949 "omp.arraycpy.dest.element");
4950 llvm::Value *RHSElementNext = CGF.Builder.CreateConstGEP1_32(
4951 RHSAddr.getElementType(), RHSElementPHI, /*Idx0=*/1,
4952 "omp.arraycpy.src.element");
4953 // Check whether we've reached the end.
4954 llvm::Value *Done =
4955 CGF.Builder.CreateICmpEQ(LHSElementNext, LHSEnd, "omp.arraycpy.done");
4956 CGF.Builder.CreateCondBr(Done, DoneBB, BodyBB);
4957 LHSElementPHI->addIncoming(LHSElementNext, CGF.Builder.GetInsertBlock());
4958 RHSElementPHI->addIncoming(RHSElementNext, CGF.Builder.GetInsertBlock());
4959
4960 // Done.
4961 CGF.EmitBlock(DoneBB, /*IsFinished=*/true);
4962}
4963
4964/// Emit reduction combiner. If the combiner is a simple expression emit it as
4965/// is, otherwise consider it as combiner of UDR decl and emit it as a call of
4966/// UDR combiner function.
4968 const Expr *ReductionOp) {
4969 if (const auto *CE = dyn_cast<CallExpr>(ReductionOp))
4970 if (const auto *OVE = dyn_cast<OpaqueValueExpr>(CE->getCallee()))
4971 if (const auto *DRE =
4972 dyn_cast<DeclRefExpr>(OVE->getSourceExpr()->IgnoreImpCasts()))
4973 if (const auto *DRD =
4974 dyn_cast<OMPDeclareReductionDecl>(DRE->getDecl())) {
4975 std::pair<llvm::Function *, llvm::Function *> Reduction =
4979 CGF.EmitIgnoredExpr(ReductionOp);
4980 return;
4981 }
4982 CGF.EmitIgnoredExpr(ReductionOp);
4983}
4984
4986 StringRef ReducerName, SourceLocation Loc, llvm::Type *ArgsElemType,
4988 ArrayRef<const Expr *> RHSExprs, ArrayRef<const Expr *> ReductionOps) {
4989 ASTContext &C = CGM.getContext();
4990
4991 // void reduction_func(void *LHSArg, void *RHSArg);
4992 auto *LHSArg =
4993 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
4994 C.VoidPtrTy, ImplicitParamKind::Other);
4995 auto *RHSArg =
4996 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
4997 C.VoidPtrTy, ImplicitParamKind::Other);
4998 FunctionArgList Args{LHSArg, RHSArg};
4999 const auto &CGFI =
5000 CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
5001 std::string Name = getReductionFuncName(ReducerName);
5002 auto *Fn = llvm::Function::Create(CGM.getTypes().GetFunctionType(CGFI),
5003 llvm::GlobalValue::InternalLinkage, Name,
5004 &CGM.getModule());
5005 CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, CGFI);
5006 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
5007 Fn->addFnAttr("sample-profile-suffix-elision-policy", "selected");
5008 Fn->setDoesNotRecurse();
5009 CodeGenFunction CGF(CGM);
5010 CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, CGFI, Args, Loc, Loc);
5011
5012 // Dst = (void*[n])(LHSArg);
5013 // Src = (void*[n])(RHSArg);
5015 CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(LHSArg)),
5016 CGF.Builder.getPtrTy(0)),
5017 ArgsElemType, CGF.getPointerAlign());
5019 CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(RHSArg)),
5020 CGF.Builder.getPtrTy(0)),
5021 ArgsElemType, CGF.getPointerAlign());
5022
5023 // ...
5024 // *(Type<i>*)lhs[i] = RedOp<i>(*(Type<i>*)lhs[i], *(Type<i>*)rhs[i]);
5025 // ...
5027 const auto *IPriv = Privates.begin();
5028 unsigned Idx = 0;
5029 for (unsigned I = 0, E = ReductionOps.size(); I < E; ++I, ++IPriv, ++Idx) {
5030 const auto *RHSVar =
5031 cast<VarDecl>(cast<DeclRefExpr>(RHSExprs[I])->getDecl());
5032 Scope.addPrivate(RHSVar, emitAddrOfVarFromArray(CGF, RHS, Idx, RHSVar));
5033 const auto *LHSVar =
5034 cast<VarDecl>(cast<DeclRefExpr>(LHSExprs[I])->getDecl());
5035 Scope.addPrivate(LHSVar, emitAddrOfVarFromArray(CGF, LHS, Idx, LHSVar));
5036 QualType PrivTy = (*IPriv)->getType();
5037 if (PrivTy->isVariablyModifiedType()) {
5038 // Get array size and emit VLA type.
5039 ++Idx;
5040 Address Elem = CGF.Builder.CreateConstArrayGEP(LHS, Idx);
5041 llvm::Value *Ptr = CGF.Builder.CreateLoad(Elem);
5042 const VariableArrayType *VLA =
5043 CGF.getContext().getAsVariableArrayType(PrivTy);
5044 const auto *OVE = cast<OpaqueValueExpr>(VLA->getSizeExpr());
5046 CGF, OVE, RValue::get(CGF.Builder.CreatePtrToInt(Ptr, CGF.SizeTy)));
5047 CGF.EmitVariablyModifiedType(PrivTy);
5048 }
5049 }
5050 Scope.Privatize();
5051 IPriv = Privates.begin();
5052 const auto *ILHS = LHSExprs.begin();
5053 const auto *IRHS = RHSExprs.begin();
5054 for (const Expr *E : ReductionOps) {
5055 if ((*IPriv)->getType()->isArrayType()) {
5056 // Emit reduction for array section.
5057 const auto *LHSVar = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
5058 const auto *RHSVar = cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
5060 CGF, (*IPriv)->getType(), LHSVar, RHSVar,
5061 [=](CodeGenFunction &CGF, const Expr *, const Expr *, const Expr *) {
5062 emitReductionCombiner(CGF, E);
5063 });
5064 } else {
5065 // Emit reduction for array subscript or single variable.
5066 emitReductionCombiner(CGF, E);
5067 }
5068 ++IPriv;
5069 ++ILHS;
5070 ++IRHS;
5071 }
5072 Scope.ForceCleanup();
5073 CGF.FinishFunction();
5074 return Fn;
5075}
5076
5078 const Expr *ReductionOp,
5079 const Expr *PrivateRef,
5080 const DeclRefExpr *LHS,
5081 const DeclRefExpr *RHS) {
5082 if (PrivateRef->getType()->isArrayType()) {
5083 // Emit reduction for array section.
5084 const auto *LHSVar = cast<VarDecl>(LHS->getDecl());
5085 const auto *RHSVar = cast<VarDecl>(RHS->getDecl());
5087 CGF, PrivateRef->getType(), LHSVar, RHSVar,
5088 [=](CodeGenFunction &CGF, const Expr *, const Expr *, const Expr *) {
5089 emitReductionCombiner(CGF, ReductionOp);
5090 });
5091 } else {
5092 // Emit reduction for array subscript or single variable.
5093 emitReductionCombiner(CGF, ReductionOp);
5094 }
5095}
5096
5097static std::string generateUniqueName(CodeGenModule &CGM,
5098 llvm::StringRef Prefix, const Expr *Ref);
5099
5101 CodeGenFunction &CGF, SourceLocation Loc, const Expr *Privates,
5102 const Expr *LHSExprs, const Expr *RHSExprs, const Expr *ReductionOps) {
5103
5104 // Create a shared global variable (__shared_reduction_var) to accumulate the
5105 // final result.
5106 //
5107 // Call __kmpc_barrier to synchronize threads before initialization.
5108 //
5109 // The master thread (thread_id == 0) initializes __shared_reduction_var
5110 // with the identity value or initializer.
5111 //
5112 // Call __kmpc_barrier to synchronize before combining.
5113 // For each i:
5114 // - Thread enters critical section.
5115 // - Reads its private value from LHSExprs[i].
5116 // - Updates __shared_reduction_var[i] = RedOp_i(__shared_reduction_var[i],
5117 // Privates[i]).
5118 // - Exits critical section.
5119 //
5120 // Call __kmpc_barrier after combining.
5121 //
5122 // Each thread copies __shared_reduction_var[i] back to RHSExprs[i].
5123 //
5124 // Final __kmpc_barrier to synchronize after broadcasting
5125 QualType PrivateType = Privates->getType();
5126 llvm::Type *LLVMType = CGF.ConvertTypeForMem(PrivateType);
5127
5128 const OMPDeclareReductionDecl *UDR = getReductionInit(ReductionOps);
5129 std::string ReductionVarNameStr;
5130 if (const auto *DRE = dyn_cast<DeclRefExpr>(Privates->IgnoreParenCasts()))
5131 ReductionVarNameStr =
5132 generateUniqueName(CGM, DRE->getDecl()->getNameAsString(), Privates);
5133 else
5134 ReductionVarNameStr = "unnamed_priv_var";
5135
5136 // Create an internal shared variable
5137 std::string SharedName =
5138 CGM.getOpenMPRuntime().getName({"internal_pivate_", ReductionVarNameStr});
5139 llvm::GlobalVariable *SharedVar = OMPBuilder.getOrCreateInternalVariable(
5140 LLVMType, ".omp.reduction." + SharedName);
5141
5142 SharedVar->setAlignment(
5143 llvm::MaybeAlign(CGF.getContext().getTypeAlign(PrivateType) / 8));
5144
5145 Address SharedResult =
5146 CGF.MakeNaturalAlignRawAddrLValue(SharedVar, PrivateType).getAddress();
5147
5148 llvm::Value *ThreadId = getThreadID(CGF, Loc);
5149 llvm::Value *BarrierLoc = emitUpdateLocation(CGF, Loc, OMP_ATOMIC_REDUCE);
5150 llvm::Value *BarrierArgs[] = {BarrierLoc, ThreadId};
5151
5152 llvm::BasicBlock *InitBB = CGF.createBasicBlock("init");
5153 llvm::BasicBlock *InitEndBB = CGF.createBasicBlock("init.end");
5154
5155 llvm::Value *IsWorker = CGF.Builder.CreateICmpEQ(
5156 ThreadId, llvm::ConstantInt::get(ThreadId->getType(), 0));
5157 CGF.Builder.CreateCondBr(IsWorker, InitBB, InitEndBB);
5158
5159 CGF.EmitBlock(InitBB);
5160
5161 auto EmitSharedInit = [&]() {
5162 if (UDR) { // Check if it's a User-Defined Reduction
5163 if (const Expr *UDRInitExpr = UDR->getInitializer()) {
5164 std::pair<llvm::Function *, llvm::Function *> FnPair =
5166 llvm::Function *InitializerFn = FnPair.second;
5167 if (InitializerFn) {
5168 if (const auto *CE =
5169 dyn_cast<CallExpr>(UDRInitExpr->IgnoreParenImpCasts())) {
5170 const auto *OutDRE = cast<DeclRefExpr>(
5171 cast<UnaryOperator>(CE->getArg(0)->IgnoreParenImpCasts())
5172 ->getSubExpr());
5173 const VarDecl *OutVD = cast<VarDecl>(OutDRE->getDecl());
5174
5175 CodeGenFunction::OMPPrivateScope LocalScope(CGF);
5176 LocalScope.addPrivate(OutVD, SharedResult);
5177
5178 (void)LocalScope.Privatize();
5179 if (const auto *OVE = dyn_cast<OpaqueValueExpr>(
5180 CE->getCallee()->IgnoreParenImpCasts())) {
5182 CGF, OVE, RValue::get(InitializerFn));
5183 CGF.EmitIgnoredExpr(CE);
5184 } else {
5185 CGF.EmitAnyExprToMem(UDRInitExpr, SharedResult,
5186 PrivateType.getQualifiers(),
5187 /*IsInitializer=*/true);
5188 }
5189 } else {
5190 CGF.EmitAnyExprToMem(UDRInitExpr, SharedResult,
5191 PrivateType.getQualifiers(),
5192 /*IsInitializer=*/true);
5193 }
5194 } else {
5195 CGF.EmitAnyExprToMem(UDRInitExpr, SharedResult,
5196 PrivateType.getQualifiers(),
5197 /*IsInitializer=*/true);
5198 }
5199 } else {
5200 // EmitNullInitialization handles default construction for C++ classes
5201 // and zeroing for scalars, which is a reasonable default.
5202 CGF.EmitNullInitialization(SharedResult, PrivateType);
5203 }
5204 return; // UDR initialization handled
5205 }
5206 if (const auto *DRE = dyn_cast<DeclRefExpr>(Privates)) {
5207 if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
5208 if (const Expr *InitExpr = VD->getInit()) {
5209 CGF.EmitAnyExprToMem(InitExpr, SharedResult,
5210 PrivateType.getQualifiers(), true);
5211 return;
5212 }
5213 }
5214 }
5215 CGF.EmitNullInitialization(SharedResult, PrivateType);
5216 };
5217 EmitSharedInit();
5218 CGF.Builder.CreateBr(InitEndBB);
5219 CGF.EmitBlock(InitEndBB);
5220
5221 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
5222 CGM.getModule(), OMPRTL___kmpc_barrier),
5223 BarrierArgs);
5224
5225 const Expr *ReductionOp = ReductionOps;
5226 const OMPDeclareReductionDecl *CurrentUDR = getReductionInit(ReductionOp);
5227 LValue SharedLV = CGF.MakeAddrLValue(SharedResult, PrivateType);
5228 LValue LHSLV = CGF.EmitLValue(Privates);
5229
5230 auto EmitCriticalReduction = [&](auto ReductionGen) {
5231 std::string CriticalName = getName({"reduction_critical"});
5232 emitCriticalRegion(CGF, CriticalName, ReductionGen, Loc);
5233 };
5234
5235 if (CurrentUDR) {
5236 // Handle user-defined reduction.
5237 auto ReductionGen = [&](CodeGenFunction &CGF, PrePostActionTy &Action) {
5238 Action.Enter(CGF);
5239 std::pair<llvm::Function *, llvm::Function *> FnPair =
5240 getUserDefinedReduction(CurrentUDR);
5241 if (FnPair.first) {
5242 if (const auto *CE = dyn_cast<CallExpr>(ReductionOp)) {
5243 const auto *OutDRE = cast<DeclRefExpr>(
5244 cast<UnaryOperator>(CE->getArg(0)->IgnoreParenImpCasts())
5245 ->getSubExpr());
5246 const auto *InDRE = cast<DeclRefExpr>(
5247 cast<UnaryOperator>(CE->getArg(1)->IgnoreParenImpCasts())
5248 ->getSubExpr());
5249 CodeGenFunction::OMPPrivateScope LocalScope(CGF);
5250 LocalScope.addPrivate(cast<VarDecl>(OutDRE->getDecl()),
5251 SharedLV.getAddress());
5252 LocalScope.addPrivate(cast<VarDecl>(InDRE->getDecl()),
5253 LHSLV.getAddress());
5254 (void)LocalScope.Privatize();
5255 emitReductionCombiner(CGF, ReductionOp);
5256 }
5257 }
5258 };
5259 EmitCriticalReduction(ReductionGen);
5260 } else {
5261 // Handle built-in reduction operations.
5262#ifndef NDEBUG
5263 const Expr *ReductionClauseExpr = ReductionOp->IgnoreParenCasts();
5264 if (const auto *Cleanup = dyn_cast<ExprWithCleanups>(ReductionClauseExpr))
5265 ReductionClauseExpr = Cleanup->getSubExpr()->IgnoreParenCasts();
5266
5267 const Expr *AssignRHS = nullptr;
5268 if (const auto *BinOp = dyn_cast<BinaryOperator>(ReductionClauseExpr)) {
5269 if (BinOp->getOpcode() == BO_Assign)
5270 AssignRHS = BinOp->getRHS();
5271 } else if (const auto *OpCall =
5272 dyn_cast<CXXOperatorCallExpr>(ReductionClauseExpr)) {
5273 if (OpCall->getOperator() == OO_Equal)
5274 AssignRHS = OpCall->getArg(1);
5275 }
5276
5277 assert(AssignRHS &&
5278 "Private Variable Reduction : Invalid ReductionOp expression");
5279#endif
5280
5281 auto ReductionGen = [&](CodeGenFunction &CGF, PrePostActionTy &Action) {
5282 Action.Enter(CGF);
5283 const auto *OmpOutDRE =
5284 dyn_cast<DeclRefExpr>(LHSExprs->IgnoreParenImpCasts());
5285 const auto *OmpInDRE =
5286 dyn_cast<DeclRefExpr>(RHSExprs->IgnoreParenImpCasts());
5287 assert(
5288 OmpOutDRE && OmpInDRE &&
5289 "Private Variable Reduction : LHSExpr/RHSExpr must be DeclRefExprs");
5290 const VarDecl *OmpOutVD = cast<VarDecl>(OmpOutDRE->getDecl());
5291 const VarDecl *OmpInVD = cast<VarDecl>(OmpInDRE->getDecl());
5292 CodeGenFunction::OMPPrivateScope LocalScope(CGF);
5293 LocalScope.addPrivate(OmpOutVD, SharedLV.getAddress());
5294 LocalScope.addPrivate(OmpInVD, LHSLV.getAddress());
5295 (void)LocalScope.Privatize();
5296 // Emit the actual reduction operation
5297 CGF.EmitIgnoredExpr(ReductionOp);
5298 };
5299 EmitCriticalReduction(ReductionGen);
5300 }
5301
5302 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
5303 CGM.getModule(), OMPRTL___kmpc_barrier),
5304 BarrierArgs);
5305
5306 // Broadcast final result
5307 bool IsAggregate = PrivateType->isAggregateType();
5308 LValue SharedLV1 = CGF.MakeAddrLValue(SharedResult, PrivateType);
5309 llvm::Value *FinalResultVal = nullptr;
5310 Address FinalResultAddr = Address::invalid();
5311
5312 if (IsAggregate)
5313 FinalResultAddr = SharedResult;
5314 else
5315 FinalResultVal = CGF.EmitLoadOfScalar(SharedLV1, Loc);
5316
5317 LValue TargetLHSLV = CGF.EmitLValue(RHSExprs);
5318 if (IsAggregate) {
5319 CGF.EmitAggregateCopy(TargetLHSLV,
5320 CGF.MakeAddrLValue(FinalResultAddr, PrivateType),
5321 PrivateType, AggValueSlot::DoesNotOverlap, false);
5322 } else {
5323 CGF.EmitStoreOfScalar(FinalResultVal, TargetLHSLV);
5324 }
5325 // Final synchronization barrier
5326 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
5327 CGM.getModule(), OMPRTL___kmpc_barrier),
5328 BarrierArgs);
5329
5330 // Combiner with original list item
5331 auto OriginalListCombiner = [&](CodeGenFunction &CGF,
5332 PrePostActionTy &Action) {
5333 Action.Enter(CGF);
5334 emitSingleReductionCombiner(CGF, ReductionOps, Privates,
5335 cast<DeclRefExpr>(LHSExprs),
5336 cast<DeclRefExpr>(RHSExprs));
5337 };
5338 EmitCriticalReduction(OriginalListCombiner);
5339}
5340
5342 ArrayRef<const Expr *> OrgPrivates,
5343 ArrayRef<const Expr *> OrgLHSExprs,
5344 ArrayRef<const Expr *> OrgRHSExprs,
5345 ArrayRef<const Expr *> OrgReductionOps,
5346 ReductionOptionsTy Options) {
5347 if (!CGF.HaveInsertPoint())
5348 return;
5349
5350 bool WithNowait = Options.WithNowait;
5351 bool SimpleReduction = Options.SimpleReduction;
5352
5353 // Next code should be emitted for reduction:
5354 //
5355 // static kmp_critical_name lock = { 0 };
5356 //
5357 // void reduce_func(void *lhs[<n>], void *rhs[<n>]) {
5358 // *(Type0*)lhs[0] = ReductionOperation0(*(Type0*)lhs[0], *(Type0*)rhs[0]);
5359 // ...
5360 // *(Type<n>-1*)lhs[<n>-1] = ReductionOperation<n>-1(*(Type<n>-1*)lhs[<n>-1],
5361 // *(Type<n>-1*)rhs[<n>-1]);
5362 // }
5363 //
5364 // ...
5365 // void *RedList[<n>] = {&<RHSExprs>[0], ..., &<RHSExprs>[<n>-1]};
5366 // switch (__kmpc_reduce{_nowait}(<loc>, <gtid>, <n>, sizeof(RedList),
5367 // RedList, reduce_func, &<lock>)) {
5368 // case 1:
5369 // ...
5370 // <LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]);
5371 // ...
5372 // __kmpc_end_reduce{_nowait}(<loc>, <gtid>, &<lock>);
5373 // break;
5374 // case 2:
5375 // ...
5376 // Atomic(<LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]));
5377 // ...
5378 // [__kmpc_end_reduce(<loc>, <gtid>, &<lock>);]
5379 // break;
5380 // default:;
5381 // }
5382 //
5383 // if SimpleReduction is true, only the next code is generated:
5384 // ...
5385 // <LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]);
5386 // ...
5387
5388 ASTContext &C = CGM.getContext();
5389
5390 if (SimpleReduction) {
5392 const auto *IPriv = OrgPrivates.begin();
5393 const auto *ILHS = OrgLHSExprs.begin();
5394 const auto *IRHS = OrgRHSExprs.begin();
5395 for (const Expr *E : OrgReductionOps) {
5396 emitSingleReductionCombiner(CGF, E, *IPriv, cast<DeclRefExpr>(*ILHS),
5397 cast<DeclRefExpr>(*IRHS));
5398 ++IPriv;
5399 ++ILHS;
5400 ++IRHS;
5401 }
5402 return;
5403 }
5404
5405 // Filter out shared reduction variables based on IsPrivateVarReduction flag.
5406 // Only keep entries where the corresponding variable is not private.
5407 SmallVector<const Expr *> FilteredPrivates, FilteredLHSExprs,
5408 FilteredRHSExprs, FilteredReductionOps;
5409 for (unsigned I : llvm::seq<unsigned>(
5410 std::min(OrgReductionOps.size(), OrgLHSExprs.size()))) {
5411 if (!Options.IsPrivateVarReduction[I]) {
5412 FilteredPrivates.emplace_back(OrgPrivates[I]);
5413 FilteredLHSExprs.emplace_back(OrgLHSExprs[I]);
5414 FilteredRHSExprs.emplace_back(OrgRHSExprs[I]);
5415 FilteredReductionOps.emplace_back(OrgReductionOps[I]);
5416 }
5417 }
5418 // Wrap filtered vectors in ArrayRef for downstream shared reduction
5419 // processing.
5420 ArrayRef<const Expr *> Privates = FilteredPrivates;
5421 ArrayRef<const Expr *> LHSExprs = FilteredLHSExprs;
5422 ArrayRef<const Expr *> RHSExprs = FilteredRHSExprs;
5423 ArrayRef<const Expr *> ReductionOps = FilteredReductionOps;
5424
5425 // 1. Build a list of reduction variables.
5426 // void *RedList[<n>] = {<ReductionVars>[0], ..., <ReductionVars>[<n>-1]};
5427 auto Size = RHSExprs.size();
5428 for (const Expr *E : Privates) {
5429 if (E->getType()->isVariablyModifiedType())
5430 // Reserve place for array size.
5431 ++Size;
5432 }
5433 llvm::APInt ArraySize(/*unsigned int numBits=*/32, Size);
5434 QualType ReductionArrayTy = C.getConstantArrayType(
5435 C.VoidPtrTy, ArraySize, nullptr, ArraySizeModifier::Normal,
5436 /*IndexTypeQuals=*/0);
5437 RawAddress ReductionList =
5438 CGF.CreateMemTemp(ReductionArrayTy, ".omp.reduction.red_list");
5439 const auto *IPriv = Privates.begin();
5440 unsigned Idx = 0;
5441 for (unsigned I = 0, E = RHSExprs.size(); I < E; ++I, ++IPriv, ++Idx) {
5442 Address Elem = CGF.Builder.CreateConstArrayGEP(ReductionList, Idx);
5443 CGF.Builder.CreateStore(
5445 CGF.EmitLValue(RHSExprs[I]).getPointer(CGF), CGF.VoidPtrTy),
5446 Elem);
5447 if ((*IPriv)->getType()->isVariablyModifiedType()) {
5448 // Store array size.
5449 ++Idx;
5450 Elem = CGF.Builder.CreateConstArrayGEP(ReductionList, Idx);
5451 llvm::Value *Size = CGF.Builder.CreateIntCast(
5452 CGF.getVLASize(
5453 CGF.getContext().getAsVariableArrayType((*IPriv)->getType()))
5454 .NumElts,
5455 CGF.SizeTy, /*isSigned=*/false);
5456 CGF.Builder.CreateStore(CGF.Builder.CreateIntToPtr(Size, CGF.VoidPtrTy),
5457 Elem);
5458 }
5459 }
5460
5461 // 2. Emit reduce_func().
5462 llvm::Function *ReductionFn = emitReductionFunction(
5463 CGF.CurFn->getName(), Loc, CGF.ConvertTypeForMem(ReductionArrayTy),
5464 Privates, LHSExprs, RHSExprs, ReductionOps);
5465
5466 // 3. Create static kmp_critical_name lock = { 0 };
5467 std::string Name = getName({"reduction"});
5468 llvm::Value *Lock = getCriticalRegionLock(Name);
5469
5470 // 4. Build res = __kmpc_reduce{_nowait}(<loc>, <gtid>, <n>, sizeof(RedList),
5471 // RedList, reduce_func, &<lock>);
5472 llvm::Value *IdentTLoc = emitUpdateLocation(CGF, Loc, OMP_ATOMIC_REDUCE);
5473 llvm::Value *ThreadId = getThreadID(CGF, Loc);
5474 llvm::Value *ReductionArrayTySize = CGF.getTypeSize(ReductionArrayTy);
5475 llvm::Value *RL = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
5476 ReductionList.getPointer(), CGF.VoidPtrTy);
5477 llvm::Value *Args[] = {
5478 IdentTLoc, // ident_t *<loc>
5479 ThreadId, // i32 <gtid>
5480 CGF.Builder.getInt32(RHSExprs.size()), // i32 <n>
5481 ReductionArrayTySize, // size_type sizeof(RedList)
5482 RL, // void *RedList
5483 ReductionFn, // void (*) (void *, void *) <reduce_func>
5484 Lock // kmp_critical_name *&<lock>
5485 };
5486 llvm::Value *Res = CGF.EmitRuntimeCall(
5487 OMPBuilder.getOrCreateRuntimeFunction(
5488 CGM.getModule(),
5489 WithNowait ? OMPRTL___kmpc_reduce_nowait : OMPRTL___kmpc_reduce),
5490 Args);
5491
5492 // 5. Build switch(res)
5493 llvm::BasicBlock *DefaultBB = CGF.createBasicBlock(".omp.reduction.default");
5494 llvm::SwitchInst *SwInst =
5495 CGF.Builder.CreateSwitch(Res, DefaultBB, /*NumCases=*/2);
5496
5497 // 6. Build case 1:
5498 // ...
5499 // <LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]);
5500 // ...
5501 // __kmpc_end_reduce{_nowait}(<loc>, <gtid>, &<lock>);
5502 // break;
5503 llvm::BasicBlock *Case1BB = CGF.createBasicBlock(".omp.reduction.case1");
5504 SwInst->addCase(CGF.Builder.getInt32(1), Case1BB);
5505 CGF.EmitBlock(Case1BB);
5506
5507 // Add emission of __kmpc_end_reduce{_nowait}(<loc>, <gtid>, &<lock>);
5508 llvm::Value *EndArgs[] = {
5509 IdentTLoc, // ident_t *<loc>
5510 ThreadId, // i32 <gtid>
5511 Lock // kmp_critical_name *&<lock>
5512 };
5513 auto &&CodeGen = [Privates, LHSExprs, RHSExprs, ReductionOps](
5514 CodeGenFunction &CGF, PrePostActionTy &Action) {
5516 const auto *IPriv = Privates.begin();
5517 const auto *ILHS = LHSExprs.begin();
5518 const auto *IRHS = RHSExprs.begin();
5519 for (const Expr *E : ReductionOps) {
5520 RT.emitSingleReductionCombiner(CGF, E, *IPriv, cast<DeclRefExpr>(*ILHS),
5521 cast<DeclRefExpr>(*IRHS));
5522 ++IPriv;
5523 ++ILHS;
5524 ++IRHS;
5525 }
5526 };
5528 CommonActionTy Action(
5529 nullptr, {},
5530 OMPBuilder.getOrCreateRuntimeFunction(
5531 CGM.getModule(), WithNowait ? OMPRTL___kmpc_end_reduce_nowait
5532 : OMPRTL___kmpc_end_reduce),
5533 EndArgs);
5534 RCG.setAction(Action);
5535 RCG(CGF);
5536
5537 CGF.EmitBranch(DefaultBB);
5538
5539 // 7. Build case 2:
5540 // ...
5541 // Atomic(<LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]));
5542 // ...
5543 // break;
5544 llvm::BasicBlock *Case2BB = CGF.createBasicBlock(".omp.reduction.case2");
5545 SwInst->addCase(CGF.Builder.getInt32(2), Case2BB);
5546 CGF.EmitBlock(Case2BB);
5547
5548 auto &&AtomicCodeGen = [Loc, Privates, LHSExprs, RHSExprs, ReductionOps](
5549 CodeGenFunction &CGF, PrePostActionTy &Action) {
5550 const auto *ILHS = LHSExprs.begin();
5551 const auto *IRHS = RHSExprs.begin();
5552 const auto *IPriv = Privates.begin();
5553 for (const Expr *E : ReductionOps) {
5554 const Expr *XExpr = nullptr;
5555 const Expr *EExpr = nullptr;
5556 const Expr *UpExpr = nullptr;
5557 BinaryOperatorKind BO = BO_Comma;
5558 if (const auto *BO = dyn_cast<BinaryOperator>(E)) {
5559 if (BO->getOpcode() == BO_Assign) {
5560 XExpr = BO->getLHS();
5561 UpExpr = BO->getRHS();
5562 }
5563 }
5564 // Try to emit update expression as a simple atomic.
5565 const Expr *RHSExpr = UpExpr;
5566 if (RHSExpr) {
5567 // Analyze RHS part of the whole expression.
5568 if (const auto *ACO = dyn_cast<AbstractConditionalOperator>(
5569 RHSExpr->IgnoreParenImpCasts())) {
5570 // If this is a conditional operator, analyze its condition for
5571 // min/max reduction operator.
5572 RHSExpr = ACO->getCond();
5573 }
5574 if (const auto *BORHS =
5575 dyn_cast<BinaryOperator>(RHSExpr->IgnoreParenImpCasts())) {
5576 EExpr = BORHS->getRHS();
5577 BO = BORHS->getOpcode();
5578 }
5579 }
5580 if (XExpr) {
5581 const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
5582 auto &&AtomicRedGen = [BO, VD,
5583 Loc](CodeGenFunction &CGF, const Expr *XExpr,
5584 const Expr *EExpr, const Expr *UpExpr) {
5585 LValue X = CGF.EmitLValue(XExpr);
5586 RValue E;
5587 if (EExpr)
5588 E = CGF.EmitAnyExpr(EExpr);
5589 CGF.EmitOMPAtomicSimpleUpdateExpr(
5590 X, E, BO, /*IsXLHSInRHSPart=*/true,
5591 llvm::AtomicOrdering::Monotonic, Loc,
5592 [&CGF, UpExpr, VD, Loc](RValue XRValue) {
5593 CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
5594 Address LHSTemp = CGF.CreateMemTemp(VD->getType());
5595 CGF.emitOMPSimpleStore(
5596 CGF.MakeAddrLValue(LHSTemp, VD->getType()), XRValue,
5597 VD->getType().getNonReferenceType(), Loc);
5598 PrivateScope.addPrivate(VD, LHSTemp);
5599 (void)PrivateScope.Privatize();
5600 return CGF.EmitAnyExpr(UpExpr);
5601 });
5602 };
5603 if ((*IPriv)->getType()->isArrayType()) {
5604 // Emit atomic reduction for array section.
5605 const auto *RHSVar =
5606 cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
5607 EmitOMPAggregateReduction(CGF, (*IPriv)->getType(), VD, RHSVar,
5608 AtomicRedGen, XExpr, EExpr, UpExpr);
5609 } else {
5610 // Emit atomic reduction for array subscript or single variable.
5611 AtomicRedGen(CGF, XExpr, EExpr, UpExpr);
5612 }
5613 } else {
5614 // Emit as a critical region.
5615 auto &&CritRedGen = [E, Loc](CodeGenFunction &CGF, const Expr *,
5616 const Expr *, const Expr *) {
5617 CGOpenMPRuntime &RT = CGF.CGM.getOpenMPRuntime();
5618 std::string Name = RT.getName({"atomic_reduction"});
5620 CGF, Name,
5621 [=](CodeGenFunction &CGF, PrePostActionTy &Action) {
5622 Action.Enter(CGF);
5623 emitReductionCombiner(CGF, E);
5624 },
5625 Loc);
5626 };
5627 if ((*IPriv)->getType()->isArrayType()) {
5628 const auto *LHSVar =
5629 cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
5630 const auto *RHSVar =
5631 cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
5632 EmitOMPAggregateReduction(CGF, (*IPriv)->getType(), LHSVar, RHSVar,
5633 CritRedGen);
5634 } else {
5635 CritRedGen(CGF, nullptr, nullptr, nullptr);
5636 }
5637 }
5638 ++ILHS;
5639 ++IRHS;
5640 ++IPriv;
5641 }
5642 };
5643 RegionCodeGenTy AtomicRCG(AtomicCodeGen);
5644 if (!WithNowait) {
5645 // Add emission of __kmpc_end_reduce(<loc>, <gtid>, &<lock>);
5646 llvm::Value *EndArgs[] = {
5647 IdentTLoc, // ident_t *<loc>
5648 ThreadId, // i32 <gtid>
5649 Lock // kmp_critical_name *&<lock>
5650 };
5651 CommonActionTy Action(nullptr, {},
5652 OMPBuilder.getOrCreateRuntimeFunction(
5653 CGM.getModule(), OMPRTL___kmpc_end_reduce),
5654 EndArgs);
5655 AtomicRCG.setAction(Action);
5656 AtomicRCG(CGF);
5657 } else {
5658 AtomicRCG(CGF);
5659 }
5660
5661 CGF.EmitBranch(DefaultBB);
5662 CGF.EmitBlock(DefaultBB, /*IsFinished=*/true);
5663 assert(OrgLHSExprs.size() == OrgPrivates.size() &&
5664 "PrivateVarReduction: Privates size mismatch");
5665 assert(OrgLHSExprs.size() == OrgReductionOps.size() &&
5666 "PrivateVarReduction: ReductionOps size mismatch");
5667 for (unsigned I : llvm::seq<unsigned>(
5668 std::min(OrgReductionOps.size(), OrgLHSExprs.size()))) {
5669 if (Options.IsPrivateVarReduction[I])
5670 emitPrivateReduction(CGF, Loc, OrgPrivates[I], OrgLHSExprs[I],
5671 OrgRHSExprs[I], OrgReductionOps[I]);
5672 }
5673}
5674
5675/// Generates unique name for artificial threadprivate variables.
5676/// Format is: <Prefix> "." <Decl_mangled_name> "_" "<Decl_start_loc_raw_enc>"
5677static std::string generateUniqueName(CodeGenModule &CGM, StringRef Prefix,
5678 const Expr *Ref) {
5679 SmallString<256> Buffer;
5680 llvm::raw_svector_ostream Out(Buffer);
5681 const clang::DeclRefExpr *DE;
5682 const VarDecl *D = ::getBaseDecl(Ref, DE);
5683 if (!D)
5684 D = cast<VarDecl>(cast<DeclRefExpr>(Ref)->getDecl());
5685 D = D->getCanonicalDecl();
5686 std::string Name = CGM.getOpenMPRuntime().getName(
5687 {D->isLocalVarDeclOrParm() ? D->getName() : CGM.getMangledName(D)});
5688 Out << Prefix << Name << "_"
5690 return std::string(Out.str());
5691}
5692
5693/// Emits reduction initializer function:
5694/// \code
5695/// void @.red_init(void* %arg, void* %orig) {
5696/// %0 = bitcast void* %arg to <type>*
5697/// store <type> <init>, <type>* %0
5698/// ret void
5699/// }
5700/// \endcode
5701static llvm::Value *emitReduceInitFunction(CodeGenModule &CGM,
5702 SourceLocation Loc,
5703 ReductionCodeGen &RCG, unsigned N) {
5704 ASTContext &C = CGM.getContext();
5705 QualType VoidPtrTy = C.VoidPtrTy;
5706 VoidPtrTy.addRestrict();
5707 FunctionArgList Args;
5708 auto *Param =
5709 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
5710 VoidPtrTy, ImplicitParamKind::Other);
5711 auto *ParamOrig =
5712 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
5713 VoidPtrTy, ImplicitParamKind::Other);
5714 Args.emplace_back(Param);
5715 Args.emplace_back(ParamOrig);
5716 const auto &FnInfo =
5717 CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
5718 llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
5719 std::string Name = CGM.getOpenMPRuntime().getName({"red_init", ""});
5720 auto *Fn = llvm::Function::Create(FnTy, llvm::GlobalValue::InternalLinkage,
5721 Name, &CGM.getModule());
5722 CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FnInfo);
5723 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
5724 Fn->addFnAttr("sample-profile-suffix-elision-policy", "selected");
5725 Fn->setDoesNotRecurse();
5726 CodeGenFunction CGF(CGM);
5727 CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, FnInfo, Args, Loc, Loc);
5728 QualType PrivateType = RCG.getPrivateType(N);
5729 Address PrivateAddr = CGF.EmitLoadOfPointer(
5730 CGF.GetAddrOfLocalVar(Param).withElementType(CGF.Builder.getPtrTy(0)),
5731 C.getPointerType(PrivateType)->castAs<PointerType>());
5732 llvm::Value *Size = nullptr;
5733 // If the size of the reduction item is non-constant, load it from global
5734 // threadprivate variable.
5735 if (RCG.getSizes(N).second) {
5737 CGF, CGM.getContext().getSizeType(),
5738 generateUniqueName(CGM, "reduction_size", RCG.getRefExpr(N)));
5739 Size = CGF.EmitLoadOfScalar(SizeAddr, /*Volatile=*/false,
5740 CGM.getContext().getSizeType(), Loc);
5741 }
5742 RCG.emitAggregateType(CGF, N, Size);
5743 Address OrigAddr = Address::invalid();
5744 // If initializer uses initializer from declare reduction construct, emit a
5745 // pointer to the address of the original reduction item (reuired by reduction
5746 // initializer)
5747 if (RCG.usesReductionInitializer(N)) {
5748 Address SharedAddr = CGF.GetAddrOfLocalVar(ParamOrig);
5749 OrigAddr = CGF.EmitLoadOfPointer(
5750 SharedAddr,
5751 CGM.getContext().VoidPtrTy.castAs<PointerType>()->getTypePtr());
5752 }
5753 // Emit the initializer:
5754 // %0 = bitcast void* %arg to <type>*
5755 // store <type> <init>, <type>* %0
5756 RCG.emitInitialization(CGF, N, PrivateAddr, OrigAddr,
5757 [](CodeGenFunction &) { return false; });
5758 CGF.FinishFunction();
5759 return Fn;
5760}
5761
5762/// Emits reduction combiner function:
5763/// \code
5764/// void @.red_comb(void* %arg0, void* %arg1) {
5765/// %lhs = bitcast void* %arg0 to <type>*
5766/// %rhs = bitcast void* %arg1 to <type>*
5767/// %2 = <ReductionOp>(<type>* %lhs, <type>* %rhs)
5768/// store <type> %2, <type>* %lhs
5769/// ret void
5770/// }
5771/// \endcode
5772static llvm::Value *emitReduceCombFunction(CodeGenModule &CGM,
5773 SourceLocation Loc,
5774 ReductionCodeGen &RCG, unsigned N,
5775 const Expr *ReductionOp,
5776 const Expr *LHS, const Expr *RHS,
5777 const Expr *PrivateRef) {
5778 ASTContext &C = CGM.getContext();
5779 const auto *LHSVD = cast<VarDecl>(cast<DeclRefExpr>(LHS)->getDecl());
5780 const auto *RHSVD = cast<VarDecl>(cast<DeclRefExpr>(RHS)->getDecl());
5781 FunctionArgList Args;
5782 auto *ParamInOut =
5783 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
5784 C.VoidPtrTy, ImplicitParamKind::Other);
5785 auto *ParamIn =
5786 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
5787 C.VoidPtrTy, ImplicitParamKind::Other);
5788 Args.emplace_back(ParamInOut);
5789 Args.emplace_back(ParamIn);
5790 const auto &FnInfo =
5791 CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
5792 llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
5793 std::string Name = CGM.getOpenMPRuntime().getName({"red_comb", ""});
5794 auto *Fn = llvm::Function::Create(FnTy, llvm::GlobalValue::InternalLinkage,
5795 Name, &CGM.getModule());
5796 CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FnInfo);
5797 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
5798 Fn->addFnAttr("sample-profile-suffix-elision-policy", "selected");
5799 Fn->setDoesNotRecurse();
5800 CodeGenFunction CGF(CGM);
5801 CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, FnInfo, Args, Loc, Loc);
5802 llvm::Value *Size = nullptr;
5803 // If the size of the reduction item is non-constant, load it from global
5804 // threadprivate variable.
5805 if (RCG.getSizes(N).second) {
5807 CGF, CGM.getContext().getSizeType(),
5808 generateUniqueName(CGM, "reduction_size", RCG.getRefExpr(N)));
5809 Size = CGF.EmitLoadOfScalar(SizeAddr, /*Volatile=*/false,
5810 CGM.getContext().getSizeType(), Loc);
5811 }
5812 RCG.emitAggregateType(CGF, N, Size);
5813 // Remap lhs and rhs variables to the addresses of the function arguments.
5814 // %lhs = bitcast void* %arg0 to <type>*
5815 // %rhs = bitcast void* %arg1 to <type>*
5816 CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
5817 PrivateScope.addPrivate(
5818 LHSVD,
5819 // Pull out the pointer to the variable.
5821 CGF.GetAddrOfLocalVar(ParamInOut)
5822 .withElementType(CGF.Builder.getPtrTy(0)),
5823 C.getPointerType(LHSVD->getType())->castAs<PointerType>()));
5824 PrivateScope.addPrivate(
5825 RHSVD,
5826 // Pull out the pointer to the variable.
5829 CGF.Builder.getPtrTy(0)),
5830 C.getPointerType(RHSVD->getType())->castAs<PointerType>()));
5831 PrivateScope.Privatize();
5832 // Emit the combiner body:
5833 // %2 = <ReductionOp>(<type> *%lhs, <type> *%rhs)
5834 // store <type> %2, <type>* %lhs
5836 CGF, ReductionOp, PrivateRef, cast<DeclRefExpr>(LHS),
5837 cast<DeclRefExpr>(RHS));
5838 CGF.FinishFunction();
5839 return Fn;
5840}
5841
5842/// Emits reduction finalizer function:
5843/// \code
5844/// void @.red_fini(void* %arg) {
5845/// %0 = bitcast void* %arg to <type>*
5846/// <destroy>(<type>* %0)
5847/// ret void
5848/// }
5849/// \endcode
5850static llvm::Value *emitReduceFiniFunction(CodeGenModule &CGM,
5851 SourceLocation Loc,
5852 ReductionCodeGen &RCG, unsigned N) {
5853 if (!RCG.needCleanups(N))
5854 return nullptr;
5855 ASTContext &C = CGM.getContext();
5856 FunctionArgList Args;
5857 auto *Param =
5858 ImplicitParamDecl::Create(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
5859 C.VoidPtrTy, ImplicitParamKind::Other);
5860 Args.emplace_back(Param);
5861 const auto &FnInfo =
5862 CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
5863 llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
5864 std::string Name = CGM.getOpenMPRuntime().getName({"red_fini", ""});
5865 auto *Fn = llvm::Function::Create(FnTy, llvm::GlobalValue::InternalLinkage,
5866 Name, &CGM.getModule());
5867 CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FnInfo);
5868 if (!CGM.getCodeGenOpts().SampleProfileFile.empty())
5869 Fn->addFnAttr("sample-profile-suffix-elision-policy", "selected");
5870 Fn->setDoesNotRecurse();
5871 CodeGenFunction CGF(CGM);
5872 CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, FnInfo, Args, Loc, Loc);
5873 Address PrivateAddr = CGF.EmitLoadOfPointer(
5874 CGF.GetAddrOfLocalVar(Param), C.VoidPtrTy.castAs<PointerType>());
5875 llvm::Value *Size = nullptr;
5876 // If the size of the reduction item is non-constant, load it from global
5877 // threadprivate variable.
5878 if (RCG.getSizes(N).second) {
5880 CGF, CGM.getContext().getSizeType(),
5881 generateUniqueName(CGM, "reduction_size", RCG.getRefExpr(N)));
5882 Size = CGF.EmitLoadOfScalar(SizeAddr, /*Volatile=*/false,
5883 CGM.getContext().getSizeType(), Loc);
5884 }
5885 RCG.emitAggregateType(CGF, N, Size);
5886 // Emit the finalizer body:
5887 // <destroy>(<type>* %0)
5888 RCG.emitCleanups(CGF, N, PrivateAddr);
5889 CGF.FinishFunction(Loc);
5890 return Fn;
5891}
5892
5895 ArrayRef<const Expr *> RHSExprs, const OMPTaskDataTy &Data) {
5896 if (!CGF.HaveInsertPoint() || Data.ReductionVars.empty())
5897 return nullptr;
5898
5899 // Build typedef struct:
5900 // kmp_taskred_input {
5901 // void *reduce_shar; // shared reduction item
5902 // void *reduce_orig; // original reduction item used for initialization
5903 // size_t reduce_size; // size of data item
5904 // void *reduce_init; // data initialization routine
5905 // void *reduce_fini; // data finalization routine
5906 // void *reduce_comb; // data combiner routine
5907 // kmp_task_red_flags_t flags; // flags for additional info from compiler
5908 // } kmp_taskred_input_t;
5909 ASTContext &C = CGM.getContext();
5910 RecordDecl *RD = C.buildImplicitRecord("kmp_taskred_input_t");
5911 RD->startDefinition();
5912 const FieldDecl *SharedFD = addFieldToRecordDecl(C, RD, C.VoidPtrTy);
5913 const FieldDecl *OrigFD = addFieldToRecordDecl(C, RD, C.VoidPtrTy);
5914 const FieldDecl *SizeFD = addFieldToRecordDecl(C, RD, C.getSizeType());
5915 const FieldDecl *InitFD = addFieldToRecordDecl(C, RD, C.VoidPtrTy);
5916 const FieldDecl *FiniFD = addFieldToRecordDecl(C, RD, C.VoidPtrTy);
5917 const FieldDecl *CombFD = addFieldToRecordDecl(C, RD, C.VoidPtrTy);
5918 const FieldDecl *FlagsFD = addFieldToRecordDecl(
5919 C, RD, C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/false));
5920 RD->completeDefinition();
5921 CanQualType RDType = C.getCanonicalTagType(RD);
5922 unsigned Size = Data.ReductionVars.size();
5923 llvm::APInt ArraySize(/*numBits=*/64, Size);
5924 QualType ArrayRDType =
5925 C.getConstantArrayType(RDType, ArraySize, nullptr,
5926 ArraySizeModifier::Normal, /*IndexTypeQuals=*/0);
5927 // kmp_task_red_input_t .rd_input.[Size];
5928 RawAddress TaskRedInput = CGF.CreateMemTemp(ArrayRDType, ".rd_input.");
5929 ReductionCodeGen RCG(Data.ReductionVars, Data.ReductionOrigs,
5930 Data.ReductionCopies, Data.ReductionOps);
5931 for (unsigned Cnt = 0; Cnt < Size; ++Cnt) {
5932 // kmp_task_red_input_t &ElemLVal = .rd_input.[Cnt];
5933 llvm::Value *Idxs[] = {llvm::ConstantInt::get(CGM.SizeTy, /*V=*/0),
5934 llvm::ConstantInt::get(CGM.SizeTy, Cnt)};
5935 llvm::Value *GEP = CGF.EmitCheckedInBoundsGEP(
5936 TaskRedInput.getElementType(), TaskRedInput.getPointer(), Idxs,
5937 /*SignedIndices=*/false, /*IsSubtraction=*/false, Loc,
5938 ".rd_input.gep.");
5939 LValue ElemLVal = CGF.MakeNaturalAlignRawAddrLValue(GEP, RDType);
5940 // ElemLVal.reduce_shar = &Shareds[Cnt];
5941 LValue SharedLVal = CGF.EmitLValueForField(ElemLVal, SharedFD);
5942 RCG.emitSharedOrigLValue(CGF, Cnt);
5943 llvm::Value *Shared = RCG.getSharedLValue(Cnt).getPointer(CGF);
5944 CGF.EmitStoreOfScalar(Shared, SharedLVal);
5945 // ElemLVal.reduce_orig = &Origs[Cnt];
5946 LValue OrigLVal = CGF.EmitLValueForField(ElemLVal, OrigFD);
5947 llvm::Value *Orig = RCG.getOrigLValue(Cnt).getPointer(CGF);
5948 CGF.EmitStoreOfScalar(Orig, OrigLVal);
5949 RCG.emitAggregateType(CGF, Cnt);
5950 llvm::Value *SizeValInChars;
5951 llvm::Value *SizeVal;
5952 std::tie(SizeValInChars, SizeVal) = RCG.getSizes(Cnt);
5953 // We use delayed creation/initialization for VLAs and array sections. It is
5954 // required because runtime does not provide the way to pass the sizes of
5955 // VLAs/array sections to initializer/combiner/finalizer functions. Instead
5956 // threadprivate global variables are used to store these values and use
5957 // them in the functions.
5958 bool DelayedCreation = !!SizeVal;
5959 SizeValInChars = CGF.Builder.CreateIntCast(SizeValInChars, CGM.SizeTy,
5960 /*isSigned=*/false);
5961 LValue SizeLVal = CGF.EmitLValueForField(ElemLVal, SizeFD);
5962 CGF.EmitStoreOfScalar(SizeValInChars, SizeLVal);
5963 // ElemLVal.reduce_init = init;
5964 LValue InitLVal = CGF.EmitLValueForField(ElemLVal, InitFD);
5965 llvm::Value *InitAddr = emitReduceInitFunction(CGM, Loc, RCG, Cnt);
5966 CGF.EmitStoreOfScalar(InitAddr, InitLVal);
5967 // ElemLVal.reduce_fini = fini;
5968 LValue FiniLVal = CGF.EmitLValueForField(ElemLVal, FiniFD);
5969 llvm::Value *Fini = emitReduceFiniFunction(CGM, Loc, RCG, Cnt);
5970 llvm::Value *FiniAddr =
5971 Fini ? Fini : llvm::ConstantPointerNull::get(CGM.VoidPtrTy);
5972 CGF.EmitStoreOfScalar(FiniAddr, FiniLVal);
5973 // ElemLVal.reduce_comb = comb;
5974 LValue CombLVal = CGF.EmitLValueForField(ElemLVal, CombFD);
5975 llvm::Value *CombAddr = emitReduceCombFunction(
5976 CGM, Loc, RCG, Cnt, Data.ReductionOps[Cnt], LHSExprs[Cnt],
5977 RHSExprs[Cnt], Data.ReductionCopies[Cnt]);
5978 CGF.EmitStoreOfScalar(CombAddr, CombLVal);
5979 // ElemLVal.flags = 0;
5980 LValue FlagsLVal = CGF.EmitLValueForField(ElemLVal, FlagsFD);
5981 if (DelayedCreation) {
5983 llvm::ConstantInt::get(CGM.Int32Ty, /*V=*/1, /*isSigned=*/true),
5984 FlagsLVal);
5985 } else
5986 CGF.EmitNullInitialization(FlagsLVal.getAddress(), FlagsLVal.getType());
5987 }
5988 if (Data.IsReductionWithTaskMod) {
5989 // Build call void *__kmpc_taskred_modifier_init(ident_t *loc, int gtid, int
5990 // is_ws, int num, void *data);
5991 llvm::Value *IdentTLoc = emitUpdateLocation(CGF, Loc);
5992 llvm::Value *GTid = CGF.Builder.CreateIntCast(getThreadID(CGF, Loc),
5993 CGM.IntTy, /*isSigned=*/true);
5994 llvm::Value *Args[] = {
5995 IdentTLoc, GTid,
5996 llvm::ConstantInt::get(CGM.IntTy, Data.IsWorksharingReduction ? 1 : 0,
5997 /*isSigned=*/true),
5998 llvm::ConstantInt::get(CGM.IntTy, Size, /*isSigned=*/true),
6000 TaskRedInput.getPointer(), CGM.VoidPtrTy)};
6001 return CGF.EmitRuntimeCall(
6002 OMPBuilder.getOrCreateRuntimeFunction(
6003 CGM.getModule(), OMPRTL___kmpc_taskred_modifier_init),
6004 Args);
6005 }
6006 // Build call void *__kmpc_taskred_init(int gtid, int num_data, void *data);
6007 llvm::Value *Args[] = {
6008 CGF.Builder.CreateIntCast(getThreadID(CGF, Loc), CGM.IntTy,
6009 /*isSigned=*/true),
6010 llvm::ConstantInt::get(CGM.IntTy, Size, /*isSigned=*/true),
6012 CGM.VoidPtrTy)};
6013 return CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
6014 CGM.getModule(), OMPRTL___kmpc_taskred_init),
6015 Args);
6016}
6017
6019 SourceLocation Loc,
6020 bool IsWorksharingReduction) {
6021 // Build call void *__kmpc_taskred_modifier_init(ident_t *loc, int gtid, int
6022 // is_ws, int num, void *data);
6023 llvm::Value *IdentTLoc = emitUpdateLocation(CGF, Loc);
6024 llvm::Value *GTid = CGF.Builder.CreateIntCast(getThreadID(CGF, Loc),
6025 CGM.IntTy, /*isSigned=*/true);
6026 llvm::Value *Args[] = {IdentTLoc, GTid,
6027 llvm::ConstantInt::get(CGM.IntTy,
6028 IsWorksharingReduction ? 1 : 0,
6029 /*isSigned=*/true)};
6030 (void)CGF.EmitRuntimeCall(
6031 OMPBuilder.getOrCreateRuntimeFunction(
6032 CGM.getModule(), OMPRTL___kmpc_task_reduction_modifier_fini),
6033 Args);
6034}
6035
6037 SourceLocation Loc,
6038 ReductionCodeGen &RCG,
6039 unsigned N) {
6040 auto Sizes = RCG.getSizes(N);
6041 // Emit threadprivate global variable if the type is non-constant
6042 // (Sizes.second = nullptr).
6043 if (Sizes.second) {
6044 llvm::Value *SizeVal = CGF.Builder.CreateIntCast(Sizes.second, CGM.SizeTy,
6045 /*isSigned=*/false);
6047 CGF, CGM.getContext().getSizeType(),
6048 generateUniqueName(CGM, "reduction_size", RCG.getRefExpr(N)));
6049 CGF.Builder.CreateStore(SizeVal, SizeAddr, /*IsVolatile=*/false);
6050 }
6051}
6052
6054 SourceLocation Loc,
6055 llvm::Value *ReductionsPtr,
6056 LValue SharedLVal) {
6057 // Build call void *__kmpc_task_reduction_get_th_data(int gtid, void *tg, void
6058 // *d);
6059 llvm::Value *Args[] = {CGF.Builder.CreateIntCast(getThreadID(CGF, Loc),
6060 CGM.IntTy,
6061 /*isSigned=*/true),
6062 ReductionsPtr,
6064 SharedLVal.getPointer(CGF), CGM.VoidPtrTy)};
6065 return Address(
6066 CGF.EmitRuntimeCall(
6067 OMPBuilder.getOrCreateRuntimeFunction(
6068 CGM.getModule(), OMPRTL___kmpc_task_reduction_get_th_data),
6069 Args),
6070 CGF.Int8Ty, SharedLVal.getAlignment());
6071}
6072
6074 const OMPTaskDataTy &Data) {
6075 if (!CGF.HaveInsertPoint())
6076 return;
6077
6078 if (CGF.CGM.getLangOpts().OpenMPIRBuilder && Data.Dependences.empty()) {
6079 // TODO: Need to support taskwait with dependences in the OpenMPIRBuilder.
6080 OMPBuilder.createTaskwait(CGF.Builder);
6081 } else {
6082 llvm::Value *ThreadID = getThreadID(CGF, Loc);
6083 llvm::Value *UpLoc = emitUpdateLocation(CGF, Loc);
6084 auto &M = CGM.getModule();
6085 Address DependenciesArray = Address::invalid();
6086 llvm::Value *NumOfElements;
6087 std::tie(NumOfElements, DependenciesArray) =
6088 emitDependClause(CGF, Data.Dependences, Loc);
6089 if (!Data.Dependences.empty()) {
6090 llvm::Value *DepWaitTaskArgs[7];
6091 DepWaitTaskArgs[0] = UpLoc;
6092 DepWaitTaskArgs[1] = ThreadID;
6093 DepWaitTaskArgs[2] = NumOfElements;
6094 DepWaitTaskArgs[3] = DependenciesArray.emitRawPointer(CGF);
6095 DepWaitTaskArgs[4] = CGF.Builder.getInt32(0);
6096 DepWaitTaskArgs[5] = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
6097 DepWaitTaskArgs[6] =
6098 llvm::ConstantInt::get(CGF.Int32Ty, Data.HasNowaitClause);
6099
6100 CodeGenFunction::RunCleanupsScope LocalScope(CGF);
6101
6102 // Build void __kmpc_omp_taskwait_deps_51(ident_t *, kmp_int32 gtid,
6103 // kmp_int32 ndeps, kmp_depend_info_t *dep_list, kmp_int32
6104 // ndeps_noalias, kmp_depend_info_t *noalias_dep_list,
6105 // kmp_int32 has_no_wait); if dependence info is specified.
6106 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
6107 M, OMPRTL___kmpc_omp_taskwait_deps_51),
6108 DepWaitTaskArgs);
6109
6110 } else {
6111
6112 // Build call kmp_int32 __kmpc_omp_taskwait(ident_t *loc, kmp_int32
6113 // global_tid);
6114 llvm::Value *Args[] = {UpLoc, ThreadID};
6115 // Ignore return result until untied tasks are supported.
6116 CGF.EmitRuntimeCall(
6117 OMPBuilder.getOrCreateRuntimeFunction(M, OMPRTL___kmpc_omp_taskwait),
6118 Args);
6119 }
6120 }
6121
6122 if (auto *Region = dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo))
6123 Region->emitUntiedSwitch(CGF);
6124}
6125
6127 OpenMPDirectiveKind InnerKind,
6128 const RegionCodeGenTy &CodeGen,
6129 bool HasCancel) {
6130 if (!CGF.HaveInsertPoint())
6131 return;
6132 InlinedOpenMPRegionRAII Region(CGF, CodeGen, InnerKind, HasCancel,
6133 InnerKind != OMPD_critical &&
6134 InnerKind != OMPD_master &&
6135 InnerKind != OMPD_masked);
6136 CGF.CapturedStmtInfo->EmitBody(CGF, /*S=*/nullptr);
6137}
6138
6139namespace {
6140enum RTCancelKind {
6141 CancelNoreq = 0,
6142 CancelParallel = 1,
6143 CancelLoop = 2,
6144 CancelSections = 3,
6145 CancelTaskgroup = 4
6146};
6147} // anonymous namespace
6148
6149static RTCancelKind getCancellationKind(OpenMPDirectiveKind CancelRegion) {
6150 RTCancelKind CancelKind = CancelNoreq;
6151 if (CancelRegion == OMPD_parallel)
6152 CancelKind = CancelParallel;
6153 else if (CancelRegion == OMPD_for)
6154 CancelKind = CancelLoop;
6155 else if (CancelRegion == OMPD_sections)
6156 CancelKind = CancelSections;
6157 else {
6158 assert(CancelRegion == OMPD_taskgroup);
6159 CancelKind = CancelTaskgroup;
6160 }
6161 return CancelKind;
6162}
6163
6166 OpenMPDirectiveKind CancelRegion) {
6167 if (!CGF.HaveInsertPoint())
6168 return;
6169 // Build call kmp_int32 __kmpc_cancellationpoint(ident_t *loc, kmp_int32
6170 // global_tid, kmp_int32 cncl_kind);
6171 if (auto *OMPRegionInfo =
6172 dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) {
6173 // For 'cancellation point taskgroup', the task region info may not have a
6174 // cancel. This may instead happen in another adjacent task.
6175 if (CancelRegion == OMPD_taskgroup || OMPRegionInfo->hasCancel()) {
6176 llvm::Value *Args[] = {
6177 emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
6178 CGF.Builder.getInt32(getCancellationKind(CancelRegion))};
6179 // Ignore return result until untied tasks are supported.
6180 llvm::Value *Result = CGF.EmitRuntimeCall(
6181 OMPBuilder.getOrCreateRuntimeFunction(
6182 CGM.getModule(), OMPRTL___kmpc_cancellationpoint),
6183 Args);
6184 // if (__kmpc_cancellationpoint()) {
6185 // call i32 @__kmpc_cancel_barrier( // for parallel cancellation only
6186 // exit from construct;
6187 // }
6188 llvm::BasicBlock *ExitBB = CGF.createBasicBlock(".cancel.exit");
6189 llvm::BasicBlock *ContBB = CGF.createBasicBlock(".cancel.continue");
6190 llvm::Value *Cmp = CGF.Builder.CreateIsNotNull(Result);
6191 CGF.Builder.CreateCondBr(Cmp, ExitBB, ContBB);
6192 CGF.EmitBlock(ExitBB);
6193 if (CancelRegion == OMPD_parallel)
6194 emitBarrierCall(CGF, Loc, OMPD_unknown, /*EmitChecks=*/false);
6195 // exit from construct;
6196 CodeGenFunction::JumpDest CancelDest =
6197 CGF.getOMPCancelDestination(OMPRegionInfo->getDirectiveKind());
6198 CGF.EmitBranchThroughCleanup(CancelDest);
6199 CGF.EmitBlock(ContBB, /*IsFinished=*/true);
6200 }
6201 }
6202}
6203
6205 const Expr *IfCond,
6206 OpenMPDirectiveKind CancelRegion) {
6207 if (!CGF.HaveInsertPoint())
6208 return;
6209 // Build call kmp_int32 __kmpc_cancel(ident_t *loc, kmp_int32 global_tid,
6210 // kmp_int32 cncl_kind);
6211 auto &M = CGM.getModule();
6212 if (auto *OMPRegionInfo =
6213 dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) {
6214 auto &&ThenGen = [this, &M, Loc, CancelRegion,
6215 OMPRegionInfo](CodeGenFunction &CGF, PrePostActionTy &) {
6216 CGOpenMPRuntime &RT = CGF.CGM.getOpenMPRuntime();
6217 llvm::Value *Args[] = {
6218 RT.emitUpdateLocation(CGF, Loc), RT.getThreadID(CGF, Loc),
6219 CGF.Builder.getInt32(getCancellationKind(CancelRegion))};
6220 // Ignore return result until untied tasks are supported.
6221 llvm::Value *Result = CGF.EmitRuntimeCall(
6222 OMPBuilder.getOrCreateRuntimeFunction(M, OMPRTL___kmpc_cancel), Args);
6223 // if (__kmpc_cancel()) {
6224 // call i32 @__kmpc_cancel_barrier( // for parallel cancellation only
6225 // exit from construct;
6226 // }
6227 llvm::BasicBlock *ExitBB = CGF.createBasicBlock(".cancel.exit");
6228 llvm::BasicBlock *ContBB = CGF.createBasicBlock(".cancel.continue");
6229 llvm::Value *Cmp = CGF.Builder.CreateIsNotNull(Result);
6230 CGF.Builder.CreateCondBr(Cmp, ExitBB, ContBB);
6231 CGF.EmitBlock(ExitBB);
6232 if (CancelRegion == OMPD_parallel)
6233 RT.emitBarrierCall(CGF, Loc, OMPD_unknown, /*EmitChecks=*/false);
6234 // exit from construct;
6235 CodeGenFunction::JumpDest CancelDest =
6236 CGF.getOMPCancelDestination(OMPRegionInfo->getDirectiveKind());
6237 CGF.EmitBranchThroughCleanup(CancelDest);
6238 CGF.EmitBlock(ContBB, /*IsFinished=*/true);
6239 };
6240 if (IfCond) {
6241 emitIfClause(CGF, IfCond, ThenGen,
6242 [](CodeGenFunction &, PrePostActionTy &) {});
6243 } else {
6244 RegionCodeGenTy ThenRCG(ThenGen);
6245 ThenRCG(CGF);
6246 }
6247 }
6248}
6249
6250namespace {
6251/// Cleanup action for uses_allocators support.
6252class OMPUsesAllocatorsActionTy final : public PrePostActionTy {
6254
6255public:
6256 OMPUsesAllocatorsActionTy(
6257 ArrayRef<std::pair<const Expr *, const Expr *>> Allocators)
6258 : Allocators(Allocators) {}
6259 void Enter(CodeGenFunction &CGF) override {
6260 if (!CGF.HaveInsertPoint())
6261 return;
6262 for (const auto &AllocatorData : Allocators) {
6264 CGF, AllocatorData.first, AllocatorData.second);
6265 }
6266 }
6267 void Exit(CodeGenFunction &CGF) override {
6268 if (!CGF.HaveInsertPoint())
6269 return;
6270 for (const auto &AllocatorData : Allocators) {
6272 AllocatorData.first);
6273 }
6274 }
6275};
6276} // namespace
6277
6279 const OMPExecutableDirective &D, StringRef ParentName,
6280 llvm::Function *&OutlinedFn, llvm::Constant *&OutlinedFnID,
6281 bool IsOffloadEntry, const RegionCodeGenTy &CodeGen) {
6282 assert(!ParentName.empty() && "Invalid target entry parent name!");
6285 for (const auto *C : D.getClausesOfKind<OMPUsesAllocatorsClause>()) {
6286 for (unsigned I = 0, E = C->getNumberOfAllocators(); I < E; ++I) {
6287 const OMPUsesAllocatorsClause::Data D = C->getAllocatorData(I);
6288 if (!D.AllocatorTraits)
6289 continue;
6290 Allocators.emplace_back(D.Allocator, D.AllocatorTraits);
6291 }
6292 }
6293 OMPUsesAllocatorsActionTy UsesAllocatorAction(Allocators);
6294 CodeGen.setAction(UsesAllocatorAction);
6295 emitTargetOutlinedFunctionHelper(D, ParentName, OutlinedFn, OutlinedFnID,
6296 IsOffloadEntry, CodeGen);
6297}
6298
6300 const Expr *Allocator,
6301 const Expr *AllocatorTraits) {
6302 llvm::Value *ThreadId = getThreadID(CGF, Allocator->getExprLoc());
6303 ThreadId = CGF.Builder.CreateIntCast(ThreadId, CGF.IntTy, /*isSigned=*/true);
6304 // Use default memspace handle.
6305 llvm::Value *MemSpaceHandle = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
6306 llvm::Value *NumTraits = llvm::ConstantInt::get(
6308 AllocatorTraits->getType()->getAsArrayTypeUnsafe())
6309 ->getSize()
6310 .getLimitedValue());
6311 LValue AllocatorTraitsLVal = CGF.EmitLValue(AllocatorTraits);
6313 AllocatorTraitsLVal.getAddress(), CGF.VoidPtrPtrTy, CGF.VoidPtrTy);
6314 AllocatorTraitsLVal = CGF.MakeAddrLValue(Addr, CGF.getContext().VoidPtrTy,
6315 AllocatorTraitsLVal.getBaseInfo(),
6316 AllocatorTraitsLVal.getTBAAInfo());
6317 llvm::Value *Traits = Addr.emitRawPointer(CGF);
6318
6319 llvm::Value *AllocatorVal =
6320 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
6321 CGM.getModule(), OMPRTL___kmpc_init_allocator),
6322 {ThreadId, MemSpaceHandle, NumTraits, Traits});
6323 // Store to allocator.
6325 cast<DeclRefExpr>(Allocator->IgnoreParenImpCasts())->getDecl()));
6326 LValue AllocatorLVal = CGF.EmitLValue(Allocator->IgnoreParenImpCasts());
6327 AllocatorVal =
6328 CGF.EmitScalarConversion(AllocatorVal, CGF.getContext().VoidPtrTy,
6329 Allocator->getType(), Allocator->getExprLoc());
6330 CGF.EmitStoreOfScalar(AllocatorVal, AllocatorLVal);
6331}
6332
6334 const Expr *Allocator) {
6335 llvm::Value *ThreadId = getThreadID(CGF, Allocator->getExprLoc());
6336 ThreadId = CGF.Builder.CreateIntCast(ThreadId, CGF.IntTy, /*isSigned=*/true);
6337 LValue AllocatorLVal = CGF.EmitLValue(Allocator->IgnoreParenImpCasts());
6338 llvm::Value *AllocatorVal =
6339 CGF.EmitLoadOfScalar(AllocatorLVal, Allocator->getExprLoc());
6340 AllocatorVal = CGF.EmitScalarConversion(AllocatorVal, Allocator->getType(),
6341 CGF.getContext().VoidPtrTy,
6342 Allocator->getExprLoc());
6343 (void)CGF.EmitRuntimeCall(
6344 OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(),
6345 OMPRTL___kmpc_destroy_allocator),
6346 {ThreadId, AllocatorVal});
6347}
6348
6351 llvm::OpenMPIRBuilder::TargetKernelDefaultAttrs &Attrs) {
6352 assert(Attrs.MaxTeams.size() == 1 && Attrs.MaxThreads.size() == 1 &&
6353 "invalid default attrs structure");
6354 int32_t &MaxTeamsVal = Attrs.MaxTeams.front();
6355 int32_t &MaxThreadsVal = Attrs.MaxThreads.front();
6356
6357 getNumTeamsExprForTargetDirective(CGF, D, Attrs.MinTeams.front(),
6358 MaxTeamsVal);
6359 getNumThreadsExprForTargetDirective(CGF, D, MaxThreadsVal,
6360 /*UpperBoundOnly=*/true);
6361
6362 for (auto *C : D.getClausesOfKind<OMPXAttributeClause>()) {
6363 for (auto *A : C->getAttrs()) {
6364 int32_t AttrMinThreadsVal = 1, AttrMaxThreadsVal = -1;
6365 int32_t AttrMinBlocksVal = 1, AttrMaxBlocksVal = -1;
6366 if (auto *Attr = dyn_cast<CUDALaunchBoundsAttr>(A))
6367 CGM.handleCUDALaunchBoundsAttr(nullptr, Attr, &AttrMaxThreadsVal,
6368 &AttrMinBlocksVal, &AttrMaxBlocksVal);
6369 else if (auto *Attr = dyn_cast<AMDGPUFlatWorkGroupSizeAttr>(A))
6370 CGM.handleAMDGPUFlatWorkGroupSizeAttr(
6371 nullptr, Attr, /*ReqdWGS=*/nullptr, &AttrMinThreadsVal,
6372 &AttrMaxThreadsVal);
6373 else
6374 continue;
6375
6376 Attrs.MinThreads.front() =
6377 std::max(Attrs.MinThreads.front(), AttrMinThreadsVal);
6378 if (AttrMaxThreadsVal > 0)
6379 MaxThreadsVal = MaxThreadsVal > 0
6380 ? std::min(MaxThreadsVal, AttrMaxThreadsVal)
6381 : AttrMaxThreadsVal;
6382 Attrs.MinTeams.front() =
6383 std::max(Attrs.MinTeams.front(), AttrMinBlocksVal);
6384 if (AttrMaxBlocksVal > 0)
6385 MaxTeamsVal = MaxTeamsVal > 0 ? std::min(MaxTeamsVal, AttrMaxBlocksVal)
6386 : AttrMaxBlocksVal;
6387 }
6388 }
6389}
6390
6392 const OMPExecutableDirective &D, StringRef ParentName,
6393 llvm::Function *&OutlinedFn, llvm::Constant *&OutlinedFnID,
6394 bool IsOffloadEntry, const RegionCodeGenTy &CodeGen) {
6395
6396 llvm::TargetRegionEntryInfo EntryInfo =
6397 getEntryInfoFromPresumedLoc(CGM, OMPBuilder, D.getBeginLoc(), ParentName);
6398
6399 CodeGenFunction CGF(CGM, true);
6400 llvm::OpenMPIRBuilder::FunctionGenCallback &&GenerateOutlinedFunction =
6401 [&CGF, &D, &CodeGen, this](StringRef EntryFnName) {
6402 const CapturedStmt &CS = *D.getCapturedStmt(OMPD_target);
6403
6404 CGOpenMPTargetRegionInfo CGInfo(CS, CodeGen, EntryFnName);
6405 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
6406 if (CGM.getLangOpts().OpenMPIsTargetDevice && !isGPU())
6408 return CGF.GenerateOpenMPCapturedStmtFunction(CS, D);
6409 };
6410
6411 cantFail(OMPBuilder.emitTargetRegionFunction(
6412 EntryInfo, GenerateOutlinedFunction, IsOffloadEntry, OutlinedFn,
6413 OutlinedFnID));
6414
6415 if (!OutlinedFn)
6416 return;
6417
6418 CGM.getTargetCodeGenInfo().setTargetAttributes(nullptr, OutlinedFn, CGM);
6419
6420 for (auto *C : D.getClausesOfKind<OMPXAttributeClause>()) {
6421 for (auto *A : C->getAttrs()) {
6422 if (auto *Attr = dyn_cast<AMDGPUWavesPerEUAttr>(A))
6423 CGM.handleAMDGPUWavesPerEUAttr(OutlinedFn, Attr);
6424 }
6425 }
6426 registerVTable(D);
6427}
6428
6429/// Checks if the expression is constant or does not have non-trivial function
6430/// calls.
6431static bool isTrivial(ASTContext &Ctx, const Expr * E) {
6432 // We can skip constant expressions.
6433 // We can skip expressions with trivial calls or simple expressions.
6435 !E->hasNonTrivialCall(Ctx)) &&
6436 !E->HasSideEffects(Ctx, /*IncludePossibleEffects=*/true);
6437}
6438
6440 const Stmt *Body) {
6441 const Stmt *Child = Body->IgnoreContainers();
6442 while (const auto *C = dyn_cast_or_null<CompoundStmt>(Child)) {
6443 Child = nullptr;
6444 for (const Stmt *S : C->body()) {
6445 if (const auto *E = dyn_cast<Expr>(S)) {
6446 if (isTrivial(Ctx, E))
6447 continue;
6448 }
6449 // Some of the statements can be ignored.
6452 continue;
6453 // Analyze declarations.
6454 if (const auto *DS = dyn_cast<DeclStmt>(S)) {
6455 if (llvm::all_of(DS->decls(), [](const Decl *D) {
6456 if (isa<EmptyDecl>(D) || isa<DeclContext>(D) ||
6457 isa<TypeDecl>(D) || isa<PragmaCommentDecl>(D) ||
6458 isa<PragmaDetectMismatchDecl>(D) || isa<UsingDecl>(D) ||
6459 isa<UsingDirectiveDecl>(D) ||
6460 isa<OMPDeclareReductionDecl>(D) ||
6461 isa<OMPThreadPrivateDecl>(D) || isa<OMPAllocateDecl>(D))
6462 return true;
6463 const auto *VD = dyn_cast<VarDecl>(D);
6464 if (!VD)
6465 return false;
6466 return VD->hasGlobalStorage() || !VD->isUsed();
6467 }))
6468 continue;
6469 }
6470 // Found multiple children - cannot get the one child only.
6471 if (Child)
6472 return nullptr;
6473 Child = S;
6474 }
6475 if (Child)
6476 Child = Child->IgnoreContainers();
6477 }
6478 return Child;
6479}
6480
6482 CodeGenFunction &CGF, const OMPExecutableDirective &D, int32_t &MinTeamsVal,
6483 int32_t &MaxTeamsVal) {
6484
6485 OpenMPDirectiveKind DirectiveKind = D.getDirectiveKind();
6486 assert(isOpenMPTargetExecutionDirective(DirectiveKind) &&
6487 "Expected target-based executable directive.");
6488 switch (DirectiveKind) {
6489 case OMPD_target: {
6490 const auto *CS = D.getInnermostCapturedStmt();
6491 const auto *Body =
6492 CS->getCapturedStmt()->IgnoreContainers(/*IgnoreCaptured=*/true);
6493 const Stmt *ChildStmt =
6495 if (const auto *NestedDir =
6496 dyn_cast_or_null<OMPExecutableDirective>(ChildStmt)) {
6497 if (isOpenMPTeamsDirective(NestedDir->getDirectiveKind())) {
6498 if (NestedDir->hasClausesOfKind<OMPNumTeamsClause>()) {
6499 const Expr *NumTeams = NestedDir->getSingleClause<OMPNumTeamsClause>()
6500 ->getNumTeams()
6501 .front();
6502 if (NumTeams->isIntegerConstantExpr(CGF.getContext()))
6503 if (auto Constant =
6504 NumTeams->getIntegerConstantExpr(CGF.getContext()))
6505 MinTeamsVal = MaxTeamsVal = Constant->getExtValue();
6506 return NumTeams;
6507 }
6508 MinTeamsVal = MaxTeamsVal = 0;
6509 return nullptr;
6510 }
6511 MinTeamsVal = MaxTeamsVal = 1;
6512 return nullptr;
6513 }
6514 // A value of -1 is used to check if we need to emit no teams region
6515 MinTeamsVal = MaxTeamsVal = -1;
6516 return nullptr;
6517 }
6518 case OMPD_target_teams_loop:
6519 case OMPD_target_teams:
6520 case OMPD_target_teams_distribute:
6521 case OMPD_target_teams_distribute_simd:
6522 case OMPD_target_teams_distribute_parallel_for:
6523 case OMPD_target_teams_distribute_parallel_for_simd: {
6524 if (D.hasClausesOfKind<OMPNumTeamsClause>()) {
6525 const Expr *NumTeams =
6526 D.getSingleClause<OMPNumTeamsClause>()->getNumTeams().front();
6527 if (NumTeams->isIntegerConstantExpr(CGF.getContext()))
6528 if (auto Constant = NumTeams->getIntegerConstantExpr(CGF.getContext()))
6529 MinTeamsVal = MaxTeamsVal = Constant->getExtValue();
6530 return NumTeams;
6531 }
6532 MinTeamsVal = MaxTeamsVal = 0;
6533 return nullptr;
6534 }
6535 case OMPD_target_parallel:
6536 case OMPD_target_parallel_for:
6537 case OMPD_target_parallel_for_simd:
6538 case OMPD_target_parallel_loop:
6539 case OMPD_target_simd:
6540 MinTeamsVal = MaxTeamsVal = 1;
6541 return nullptr;
6542 case OMPD_parallel:
6543 case OMPD_for:
6544 case OMPD_parallel_for:
6545 case OMPD_parallel_loop:
6546 case OMPD_parallel_master:
6547 case OMPD_parallel_sections:
6548 case OMPD_for_simd:
6549 case OMPD_parallel_for_simd:
6550 case OMPD_cancel:
6551 case OMPD_cancellation_point:
6552 case OMPD_ordered_standalone:
6553 case OMPD_ordered_blockassoc:
6554 case OMPD_threadprivate:
6555 case OMPD_allocate:
6556 case OMPD_task:
6557 case OMPD_simd:
6558 case OMPD_tile:
6559 case OMPD_unroll:
6560 case OMPD_sections:
6561 case OMPD_section:
6562 case OMPD_single:
6563 case OMPD_master:
6564 case OMPD_critical:
6565 case OMPD_taskyield:
6566 case OMPD_barrier:
6567 case OMPD_taskwait:
6568 case OMPD_taskgroup:
6569 case OMPD_atomic:
6570 case OMPD_flush:
6571 case OMPD_depobj:
6572 case OMPD_scan:
6573 case OMPD_teams:
6574 case OMPD_target_data:
6575 case OMPD_target_exit_data:
6576 case OMPD_target_enter_data:
6577 case OMPD_distribute:
6578 case OMPD_distribute_simd:
6579 case OMPD_distribute_parallel_for:
6580 case OMPD_distribute_parallel_for_simd:
6581 case OMPD_teams_distribute:
6582 case OMPD_teams_distribute_simd:
6583 case OMPD_teams_distribute_parallel_for:
6584 case OMPD_teams_distribute_parallel_for_simd:
6585 case OMPD_target_update:
6586 case OMPD_declare_simd:
6587 case OMPD_declare_variant:
6588 case OMPD_begin_declare_variant:
6589 case OMPD_end_declare_variant:
6590 case OMPD_declare_target:
6591 case OMPD_end_declare_target:
6592 case OMPD_declare_reduction:
6593 case OMPD_declare_mapper:
6594 case OMPD_taskloop:
6595 case OMPD_taskloop_simd:
6596 case OMPD_master_taskloop:
6597 case OMPD_master_taskloop_simd:
6598 case OMPD_parallel_master_taskloop:
6599 case OMPD_parallel_master_taskloop_simd:
6600 case OMPD_requires:
6601 case OMPD_metadirective:
6602 case OMPD_unknown:
6603 break;
6604 default:
6605 break;
6606 }
6607 llvm_unreachable("Unexpected directive kind.");
6608}
6609
6611 CodeGenFunction &CGF, const OMPExecutableDirective &D) {
6612 assert(!CGF.getLangOpts().OpenMPIsTargetDevice &&
6613 "Clauses associated with the teams directive expected to be emitted "
6614 "only for the host!");
6615 CGBuilderTy &Bld = CGF.Builder;
6616 int32_t MinNT = -1, MaxNT = -1;
6617 const Expr *NumTeams =
6618 getNumTeamsExprForTargetDirective(CGF, D, MinNT, MaxNT);
6619 if (NumTeams != nullptr) {
6620 OpenMPDirectiveKind DirectiveKind = D.getDirectiveKind();
6621
6622 switch (DirectiveKind) {
6623 case OMPD_target: {
6624 const auto *CS = D.getInnermostCapturedStmt();
6625 CGOpenMPInnerExprInfo CGInfo(CGF, *CS);
6626 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
6627 llvm::Value *NumTeamsVal = CGF.EmitScalarExpr(NumTeams,
6628 /*IgnoreResultAssign*/ true);
6629 return Bld.CreateIntCast(NumTeamsVal, CGF.Int32Ty,
6630 /*isSigned=*/true);
6631 }
6632 case OMPD_target_teams:
6633 case OMPD_target_teams_distribute:
6634 case OMPD_target_teams_distribute_simd:
6635 case OMPD_target_teams_distribute_parallel_for:
6636 case OMPD_target_teams_distribute_parallel_for_simd: {
6637 CodeGenFunction::RunCleanupsScope NumTeamsScope(CGF);
6638 llvm::Value *NumTeamsVal = CGF.EmitScalarExpr(NumTeams,
6639 /*IgnoreResultAssign*/ true);
6640 return Bld.CreateIntCast(NumTeamsVal, CGF.Int32Ty,
6641 /*isSigned=*/true);
6642 }
6643 default:
6644 break;
6645 }
6646 }
6647
6648 assert(MinNT == MaxNT && "Num threads ranges require handling here.");
6649 return llvm::ConstantInt::getSigned(CGF.Int32Ty, MinNT);
6650}
6651
6652/// Check for a num threads constant value (stored in \p DefaultVal), or
6653/// expression (stored in \p E). If the value is conditional (via an if-clause),
6654/// store the condition in \p CondVal. If \p E, and \p CondVal respectively, are
6655/// nullptr, no expression evaluation is perfomed.
6656static void getNumThreads(CodeGenFunction &CGF, const CapturedStmt *CS,
6657 const Expr **E, int32_t &UpperBound,
6658 bool UpperBoundOnly, llvm::Value **CondVal) {
6660 CGF.getContext(), CS->getCapturedStmt());
6661 const auto *Dir = dyn_cast_or_null<OMPExecutableDirective>(Child);
6662 if (!Dir)
6663 return;
6664
6665 if (isOpenMPParallelDirective(Dir->getDirectiveKind())) {
6666 // Handle if clause. If if clause present, the number of threads is
6667 // calculated as <cond> ? (<numthreads> ? <numthreads> : 0 ) : 1.
6668 if (CondVal && Dir->hasClausesOfKind<OMPIfClause>()) {
6669 CGOpenMPInnerExprInfo CGInfo(CGF, *CS);
6670 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
6671 const OMPIfClause *IfClause = nullptr;
6672 for (const auto *C : Dir->getClausesOfKind<OMPIfClause>()) {
6673 if (C->getNameModifier() == OMPD_unknown ||
6674 C->getNameModifier() == OMPD_parallel) {
6675 IfClause = C;
6676 break;
6677 }
6678 }
6679 if (IfClause) {
6680 const Expr *CondExpr = IfClause->getCondition();
6681 bool Result;
6682 if (CondExpr->EvaluateAsBooleanCondition(Result, CGF.getContext())) {
6683 if (!Result) {
6684 UpperBound = 1;
6685 return;
6686 }
6687 } else {
6689 if (const auto *PreInit =
6690 cast_or_null<DeclStmt>(IfClause->getPreInitStmt())) {
6691 for (const auto *I : PreInit->decls()) {
6692 if (!I->hasAttr<OMPCaptureNoInitAttr>()) {
6693 CGF.EmitVarDecl(cast<VarDecl>(*I));
6694 } else {
6697 CGF.EmitAutoVarCleanups(Emission);
6698 }
6699 }
6700 *CondVal = CGF.EvaluateExprAsBool(CondExpr);
6701 }
6702 }
6703 }
6704 }
6705 // Check the value of num_threads clause iff if clause was not specified
6706 // or is not evaluated to false.
6707 if (Dir->hasClausesOfKind<OMPNumThreadsClause>()) {
6708 CGOpenMPInnerExprInfo CGInfo(CGF, *CS);
6709 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
6710 const auto *NumThreadsClause =
6711 Dir->getSingleClause<OMPNumThreadsClause>();
6712 const Expr *NTExpr = NumThreadsClause->getNumThreads().front();
6713 if (NTExpr->isIntegerConstantExpr(CGF.getContext()))
6714 if (auto Constant = NTExpr->getIntegerConstantExpr(CGF.getContext()))
6715 UpperBound =
6716 UpperBound
6717 ? Constant->getZExtValue()
6718 : std::min(UpperBound,
6719 static_cast<int32_t>(Constant->getZExtValue()));
6720 // If we haven't found a upper bound, remember we saw a thread limiting
6721 // clause.
6722 if (UpperBound == -1)
6723 UpperBound = 0;
6724 if (!E)
6725 return;
6726 CodeGenFunction::LexicalScope Scope(CGF, NTExpr->getSourceRange());
6727 if (const auto *PreInit =
6728 cast_or_null<DeclStmt>(NumThreadsClause->getPreInitStmt())) {
6729 for (const auto *I : PreInit->decls()) {
6730 if (!I->hasAttr<OMPCaptureNoInitAttr>()) {
6731 CGF.EmitVarDecl(cast<VarDecl>(*I));
6732 } else {
6735 CGF.EmitAutoVarCleanups(Emission);
6736 }
6737 }
6738 }
6739 *E = NTExpr;
6740 }
6741 return;
6742 }
6743 if (isOpenMPSimdDirective(Dir->getDirectiveKind()))
6744 UpperBound = 1;
6745}
6746
6748 CodeGenFunction &CGF, const OMPExecutableDirective &D, int32_t &UpperBound,
6749 bool UpperBoundOnly, llvm::Value **CondVal, const Expr **ThreadLimitExpr) {
6750 assert((!CGF.getLangOpts().OpenMPIsTargetDevice || UpperBoundOnly) &&
6751 "Clauses associated with the teams directive expected to be emitted "
6752 "only for the host!");
6753 OpenMPDirectiveKind DirectiveKind = D.getDirectiveKind();
6754 assert(isOpenMPTargetExecutionDirective(DirectiveKind) &&
6755 "Expected target-based executable directive.");
6756
6757 const Expr *NT = nullptr;
6758 const Expr **NTPtr = UpperBoundOnly ? nullptr : &NT;
6759
6760 auto CheckForConstExpr = [&](const Expr *E, const Expr **EPtr) {
6761 if (E->isIntegerConstantExpr(CGF.getContext())) {
6762 if (auto Constant = E->getIntegerConstantExpr(CGF.getContext()))
6763 UpperBound = UpperBound ? Constant->getZExtValue()
6764 : std::min(UpperBound,
6765 int32_t(Constant->getZExtValue()));
6766 }
6767 // If we haven't found a upper bound, remember we saw a thread limiting
6768 // clause.
6769 if (UpperBound == -1)
6770 UpperBound = 0;
6771 if (EPtr)
6772 *EPtr = E;
6773 };
6774
6775 auto ReturnSequential = [&]() {
6776 UpperBound = 1;
6777 return NT;
6778 };
6779
6780 switch (DirectiveKind) {
6781 case OMPD_target: {
6782 const CapturedStmt *CS = D.getInnermostCapturedStmt();
6783 getNumThreads(CGF, CS, NTPtr, UpperBound, UpperBoundOnly, CondVal);
6785 CGF.getContext(), CS->getCapturedStmt());
6786 // TODO: The standard is not clear how to resolve two thread limit clauses,
6787 // let's pick the teams one if it's present, otherwise the target one.
6788 const auto *ThreadLimitClause = D.getSingleClause<OMPThreadLimitClause>();
6789 if (const auto *Dir = dyn_cast_or_null<OMPExecutableDirective>(Child)) {
6790 if (const auto *TLC = Dir->getSingleClause<OMPThreadLimitClause>()) {
6791 ThreadLimitClause = TLC;
6792 if (ThreadLimitExpr) {
6793 CGOpenMPInnerExprInfo CGInfo(CGF, *CS);
6794 CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
6796 CGF,
6797 ThreadLimitClause->getThreadLimit().front()->getSourceRange());
6798 if (const auto *PreInit =
6799 cast_or_null<DeclStmt>(ThreadLimitClause->getPreInitStmt())) {
6800 for (const auto *I : PreInit->decls()) {
6801 if (!I->hasAttr<OMPCaptureNoInitAttr>()) {
6802 CGF.EmitVarDecl(cast<VarDecl>(*I));
6803 } else {
6806 CGF.EmitAutoVarCleanups(Emission);
6807 }
6808 }
6809 }
6810 }
6811 }
6812 }
6813 if (ThreadLimitClause)
6814 CheckForConstExpr(ThreadLimitClause->getThreadLimit().front(),
6815 ThreadLimitExpr);
6816 if (const auto *Dir = dyn_cast_or_null<OMPExecutableDirective>(Child)) {
6817 if (isOpenMPTeamsDirective(Dir->getDirectiveKind()) &&
6818 !isOpenMPDistributeDirective(Dir->getDirectiveKind())) {
6819 CS = Dir->getInnermostCapturedStmt();
6821 CGF.getContext(), CS->getCapturedStmt());
6822 Dir = dyn_cast_or_null<OMPExecutableDirective>(Child);
6823 }
6824 if (Dir && isOpenMPParallelDirective(Dir->getDirectiveKind())) {
6825 CS = Dir->getInnermostCapturedStmt();
6826 getNumThreads(CGF, CS, NTPtr, UpperBound, UpperBoundOnly, CondVal);
6827 } else if (Dir && isOpenMPSimdDirective(Dir->getDirectiveKind()))
6828 return ReturnSequential();
6829 }
6830 return NT;
6831 }
6832 case OMPD_target_teams: {
6833 if (D.hasClausesOfKind<OMPThreadLimitClause>()) {
6834 CodeGenFunction::RunCleanupsScope ThreadLimitScope(CGF);
6835 const auto *ThreadLimitClause = D.getSingleClause<OMPThreadLimitClause>();
6836 CheckForConstExpr(ThreadLimitClause->getThreadLimit().front(),
6837 ThreadLimitExpr);
6838 }
6839 const CapturedStmt *CS = D.getInnermostCapturedStmt();
6840 getNumThreads(CGF, CS, NTPtr, UpperBound, UpperBoundOnly, CondVal);
6842 CGF.getContext(), CS->getCapturedStmt());
6843 if (const auto *Dir = dyn_cast_or_null<OMPExecutableDirective>(Child)) {
6844 if (Dir->getDirectiveKind() == OMPD_distribute) {
6845 CS = Dir->getInnermostCapturedStmt();
6846 getNumThreads(CGF, CS, NTPtr, UpperBound, UpperBoundOnly, CondVal);
6847 }
6848 }
6849 return NT;
6850 }
6851 case OMPD_target_teams_distribute:
6852 if (D.hasClausesOfKind<OMPThreadLimitClause>()) {
6853 CodeGenFunction::RunCleanupsScope ThreadLimitScope(CGF);
6854 const auto *ThreadLimitClause = D.getSingleClause<OMPThreadLimitClause>();
6855 CheckForConstExpr(ThreadLimitClause->getThreadLimit().front(),
6856 ThreadLimitExpr);
6857 }
6858 getNumThreads(CGF, D.getInnermostCapturedStmt(), NTPtr, UpperBound,
6859 UpperBoundOnly, CondVal);
6860 return NT;
6861 case OMPD_target_teams_loop:
6862 case OMPD_target_parallel_loop:
6863 case OMPD_target_parallel:
6864 case OMPD_target_parallel_for:
6865 case OMPD_target_parallel_for_simd:
6866 case OMPD_target_teams_distribute_parallel_for:
6867 case OMPD_target_teams_distribute_parallel_for_simd: {
6868 if (CondVal && D.hasClausesOfKind<OMPIfClause>()) {
6869 const OMPIfClause *IfClause = nullptr;
6870 for (const auto *C : D.getClausesOfKind<OMPIfClause>()) {
6871 if (C->getNameModifier() == OMPD_unknown ||
6872 C->getNameModifier() == OMPD_parallel) {
6873 IfClause = C;
6874 break;
6875 }
6876 }
6877 if (IfClause) {
6878 const Expr *Cond = IfClause->getCondition();
6879 bool Result;
6880 if (Cond->EvaluateAsBooleanCondition(Result, CGF.getContext())) {
6881 if (!Result)
6882 return ReturnSequential();
6883 } else {
6885 *CondVal = CGF.EvaluateExprAsBool(Cond);
6886 }
6887 }
6888 }
6889 if (D.hasClausesOfKind<OMPThreadLimitClause>()) {
6890 CodeGenFunction::RunCleanupsScope ThreadLimitScope(CGF);
6891 const auto *ThreadLimitClause = D.getSingleClause<OMPThreadLimitClause>();
6892 CheckForConstExpr(ThreadLimitClause->getThreadLimit().front(),
6893 ThreadLimitExpr);
6894 }
6895 if (D.hasClausesOfKind<OMPNumThreadsClause>()) {
6896 CodeGenFunction::RunCleanupsScope NumThreadsScope(CGF);
6897 const auto *NumThreadsClause = D.getSingleClause<OMPNumThreadsClause>();
6898 CheckForConstExpr(NumThreadsClause->getNumThreads().front(), nullptr);
6899 return NumThreadsClause->getNumThreads().front();
6900 }
6901 return NT;
6902 }
6903 case OMPD_target_teams_distribute_simd:
6904 case OMPD_target_simd:
6905 return ReturnSequential();
6906 default:
6907 break;
6908 }
6909 llvm_unreachable("Unsupported directive kind.");
6910}
6911
6913 CodeGenFunction &CGF, const OMPExecutableDirective &D) {
6914 llvm::Value *NumThreadsVal = nullptr;
6915 llvm::Value *CondVal = nullptr;
6916 llvm::Value *ThreadLimitVal = nullptr;
6917 const Expr *ThreadLimitExpr = nullptr;
6918 int32_t UpperBound = -1;
6919
6921 CGF, D, UpperBound, /* UpperBoundOnly */ false, &CondVal,
6922 &ThreadLimitExpr);
6923
6924 // Thread limit expressions are used below, emit them.
6925 if (ThreadLimitExpr) {
6926 ThreadLimitVal =
6927 CGF.EmitScalarExpr(ThreadLimitExpr, /*IgnoreResultAssign=*/true);
6928 ThreadLimitVal = CGF.Builder.CreateIntCast(ThreadLimitVal, CGF.Int32Ty,
6929 /*isSigned=*/false);
6930 }
6931
6932 // Generate the num teams expression.
6933 if (UpperBound == 1) {
6934 NumThreadsVal = CGF.Builder.getInt32(UpperBound);
6935 } else if (NT) {
6936 NumThreadsVal = CGF.EmitScalarExpr(NT, /*IgnoreResultAssign=*/true);
6937 NumThreadsVal = CGF.Builder.CreateIntCast(NumThreadsVal, CGF.Int32Ty,
6938 /*isSigned=*/false);
6939 } else if (ThreadLimitVal) {
6940 // If we do not have a num threads value but a thread limit, replace the
6941 // former with the latter. We know handled the thread limit expression.
6942 NumThreadsVal = ThreadLimitVal;
6943 ThreadLimitVal = nullptr;
6944 } else {
6945 // Default to "0" which means runtime choice.
6946 assert(!ThreadLimitVal && "Default not applicable with thread limit value");
6947 NumThreadsVal = CGF.Builder.getInt32(0);
6948 }
6949
6950 // Handle if clause. If if clause present, the number of threads is
6951 // calculated as <cond> ? (<numthreads> ? <numthreads> : 0 ) : 1.
6952 if (CondVal) {
6954 NumThreadsVal = CGF.Builder.CreateSelect(CondVal, NumThreadsVal,
6955 CGF.Builder.getInt32(1));
6956 }
6957
6958 // If the thread limit and num teams expression were present, take the
6959 // minimum.
6960 if (ThreadLimitVal) {
6961 NumThreadsVal = CGF.Builder.CreateSelect(
6962 CGF.Builder.CreateICmpULT(ThreadLimitVal, NumThreadsVal),
6963 ThreadLimitVal, NumThreadsVal);
6964 }
6965
6966 return NumThreadsVal;
6967}
6968
6969namespace {
6971
6972// Utility to handle information from clauses associated with a given
6973// construct that use mappable expressions (e.g. 'map' clause, 'to' clause).
6974// It provides a convenient interface to obtain the information and generate
6975// code for that information.
6976class MappableExprsHandler {
6977public:
6978 /// Custom comparator for attach-pointer expressions that compares them by
6979 /// complexity (i.e. their component-depth) first, then by the order in which
6980 /// they were computed by collectAttachPtrExprInfo(), if they are semantically
6981 /// different.
6982 struct AttachPtrExprComparator {
6983 const MappableExprsHandler &Handler;
6984 // Cache of previous equality comparison results.
6985 mutable llvm::DenseMap<std::pair<const Expr *, const Expr *>, bool>
6986 CachedEqualityComparisons;
6987
6988 AttachPtrExprComparator(const MappableExprsHandler &H) : Handler(H) {}
6989 AttachPtrExprComparator() = delete;
6990
6991 // Return true iff LHS is "less than" RHS.
6992 bool operator()(const Expr *LHS, const Expr *RHS) const {
6993 if (LHS == RHS)
6994 return false;
6995
6996 // First, compare by complexity (depth)
6997 const auto ItLHS = Handler.AttachPtrComponentDepthMap.find(LHS);
6998 const auto ItRHS = Handler.AttachPtrComponentDepthMap.find(RHS);
6999
7000 std::optional<size_t> DepthLHS =
7001 (ItLHS != Handler.AttachPtrComponentDepthMap.end()) ? ItLHS->second
7002 : std::nullopt;
7003 std::optional<size_t> DepthRHS =
7004 (ItRHS != Handler.AttachPtrComponentDepthMap.end()) ? ItRHS->second
7005 : std::nullopt;
7006
7007 // std::nullopt (no attach pointer) has lowest complexity
7008 if (!DepthLHS.has_value() && !DepthRHS.has_value()) {
7009 // Both have same complexity, now check semantic equality
7010 if (areEqual(LHS, RHS))
7011 return false;
7012 // Different semantically, compare by computation order
7013 return wasComputedBefore(LHS, RHS);
7014 }
7015 if (!DepthLHS.has_value())
7016 return true; // LHS has lower complexity
7017 if (!DepthRHS.has_value())
7018 return false; // RHS has lower complexity
7019
7020 // Both have values, compare by depth (lower depth = lower complexity)
7021 if (DepthLHS.value() != DepthRHS.value())
7022 return DepthLHS.value() < DepthRHS.value();
7023
7024 // Same complexity, now check semantic equality
7025 if (areEqual(LHS, RHS))
7026 return false;
7027 // Different semantically, compare by computation order
7028 return wasComputedBefore(LHS, RHS);
7029 }
7030
7031 public:
7032 /// Return true if \p LHS and \p RHS are semantically equal. Uses pre-cached
7033 /// results, if available, otherwise does a recursive semantic comparison.
7034 bool areEqual(const Expr *LHS, const Expr *RHS) const {
7035 // Check cache first for faster lookup
7036 const auto CachedResultIt = CachedEqualityComparisons.find({LHS, RHS});
7037 if (CachedResultIt != CachedEqualityComparisons.end())
7038 return CachedResultIt->second;
7039
7040 bool ComparisonResult = areSemanticallyEqual(LHS, RHS);
7041
7042 // Cache the result for future lookups (both orders since semantic
7043 // equality is commutative)
7044 CachedEqualityComparisons[{LHS, RHS}] = ComparisonResult;
7045 CachedEqualityComparisons[{RHS, LHS}] = ComparisonResult;
7046 return ComparisonResult;
7047 }
7048
7049 /// Compare the two attach-ptr expressions by their computation order.
7050 /// Returns true iff LHS was computed before RHS by
7051 /// collectAttachPtrExprInfo().
7052 bool wasComputedBefore(const Expr *LHS, const Expr *RHS) const {
7053 const size_t &OrderLHS = Handler.AttachPtrComputationOrderMap.at(LHS);
7054 const size_t &OrderRHS = Handler.AttachPtrComputationOrderMap.at(RHS);
7055
7056 return OrderLHS < OrderRHS;
7057 }
7058
7059 private:
7060 /// Helper function to compare attach-pointer expressions semantically.
7061 /// This function handles various expression types that can be part of an
7062 /// attach-pointer.
7063 /// TODO: Not urgent, but we should ideally return true when comparing
7064 /// `p[10]`, `*(p + 10)`, `*(p + 5 + 5)`, `p[10:1]` etc.
7065 bool areSemanticallyEqual(const Expr *LHS, const Expr *RHS) const {
7066 if (LHS == RHS)
7067 return true;
7068
7069 // If only one is null, they aren't equal
7070 if (!LHS || !RHS)
7071 return false;
7072
7073 ASTContext &Ctx = Handler.CGF.getContext();
7074 // Strip away parentheses and no-op casts to get to the core expression
7075 LHS = LHS->IgnoreParenNoopCasts(Ctx);
7076 RHS = RHS->IgnoreParenNoopCasts(Ctx);
7077
7078 // Direct pointer comparison of the underlying expressions
7079 if (LHS == RHS)
7080 return true;
7081
7082 // Check if the expression classes match
7083 if (LHS->getStmtClass() != RHS->getStmtClass())
7084 return false;
7085
7086 // Handle DeclRefExpr (variable references)
7087 if (const auto *LD = dyn_cast<DeclRefExpr>(LHS)) {
7088 const auto *RD = dyn_cast<DeclRefExpr>(RHS);
7089 if (!RD)
7090 return false;
7091 return LD->getDecl()->getCanonicalDecl() ==
7092 RD->getDecl()->getCanonicalDecl();
7093 }
7094
7095 // Handle ArraySubscriptExpr (array indexing like a[i])
7096 if (const auto *LA = dyn_cast<ArraySubscriptExpr>(LHS)) {
7097 const auto *RA = dyn_cast<ArraySubscriptExpr>(RHS);
7098 if (!RA)
7099 return false;
7100 return areSemanticallyEqual(LA->getBase(), RA->getBase()) &&
7101 areSemanticallyEqual(LA->getIdx(), RA->getIdx());
7102 }
7103
7104 // Handle MemberExpr (member access like s.m or p->m)
7105 if (const auto *LM = dyn_cast<MemberExpr>(LHS)) {
7106 const auto *RM = dyn_cast<MemberExpr>(RHS);
7107 if (!RM)
7108 return false;
7109 if (LM->getMemberDecl()->getCanonicalDecl() !=
7110 RM->getMemberDecl()->getCanonicalDecl())
7111 return false;
7112 return areSemanticallyEqual(LM->getBase(), RM->getBase());
7113 }
7114
7115 // Handle UnaryOperator (unary operations like *p, &x, etc.)
7116 if (const auto *LU = dyn_cast<UnaryOperator>(LHS)) {
7117 const auto *RU = dyn_cast<UnaryOperator>(RHS);
7118 if (!RU)
7119 return false;
7120 if (LU->getOpcode() != RU->getOpcode())
7121 return false;
7122 return areSemanticallyEqual(LU->getSubExpr(), RU->getSubExpr());
7123 }
7124
7125 // Handle BinaryOperator (binary operations like p + offset)
7126 if (const auto *LB = dyn_cast<BinaryOperator>(LHS)) {
7127 const auto *RB = dyn_cast<BinaryOperator>(RHS);
7128 if (!RB)
7129 return false;
7130 if (LB->getOpcode() != RB->getOpcode())
7131 return false;
7132 return areSemanticallyEqual(LB->getLHS(), RB->getLHS()) &&
7133 areSemanticallyEqual(LB->getRHS(), RB->getRHS());
7134 }
7135
7136 // Handle ArraySectionExpr (array sections like a[0:1])
7137 // Attach pointers should not contain array-sections, but currently we
7138 // don't emit an error.
7139 if (const auto *LAS = dyn_cast<ArraySectionExpr>(LHS)) {
7140 const auto *RAS = dyn_cast<ArraySectionExpr>(RHS);
7141 if (!RAS)
7142 return false;
7143 return areSemanticallyEqual(LAS->getBase(), RAS->getBase()) &&
7144 areSemanticallyEqual(LAS->getLowerBound(),
7145 RAS->getLowerBound()) &&
7146 areSemanticallyEqual(LAS->getLength(), RAS->getLength());
7147 }
7148
7149 // Handle CastExpr (explicit casts)
7150 if (const auto *LC = dyn_cast<CastExpr>(LHS)) {
7151 const auto *RC = dyn_cast<CastExpr>(RHS);
7152 if (!RC)
7153 return false;
7154 if (LC->getCastKind() != RC->getCastKind())
7155 return false;
7156 return areSemanticallyEqual(LC->getSubExpr(), RC->getSubExpr());
7157 }
7158
7159 // Handle CXXThisExpr (this pointer)
7160 if (isa<CXXThisExpr>(LHS) && isa<CXXThisExpr>(RHS))
7161 return true;
7162
7163 // Handle IntegerLiteral (integer constants)
7164 if (const auto *LI = dyn_cast<IntegerLiteral>(LHS)) {
7165 const auto *RI = dyn_cast<IntegerLiteral>(RHS);
7166 if (!RI)
7167 return false;
7168 return LI->getValue() == RI->getValue();
7169 }
7170
7171 // Handle CharacterLiteral (character constants)
7172 if (const auto *LC = dyn_cast<CharacterLiteral>(LHS)) {
7173 const auto *RC = dyn_cast<CharacterLiteral>(RHS);
7174 if (!RC)
7175 return false;
7176 return LC->getValue() == RC->getValue();
7177 }
7178
7179 // Handle FloatingLiteral (floating point constants)
7180 if (const auto *LF = dyn_cast<FloatingLiteral>(LHS)) {
7181 const auto *RF = dyn_cast<FloatingLiteral>(RHS);
7182 if (!RF)
7183 return false;
7184 // Use bitwise comparison for floating point literals
7185 return LF->getValue().bitwiseIsEqual(RF->getValue());
7186 }
7187
7188 // Handle StringLiteral (string constants)
7189 if (const auto *LS = dyn_cast<StringLiteral>(LHS)) {
7190 const auto *RS = dyn_cast<StringLiteral>(RHS);
7191 if (!RS)
7192 return false;
7193 return LS->getString() == RS->getString();
7194 }
7195
7196 // Handle CXXNullPtrLiteralExpr (nullptr)
7198 return true;
7199
7200 // Handle CXXBoolLiteralExpr (true/false)
7201 if (const auto *LB = dyn_cast<CXXBoolLiteralExpr>(LHS)) {
7202 const auto *RB = dyn_cast<CXXBoolLiteralExpr>(RHS);
7203 if (!RB)
7204 return false;
7205 return LB->getValue() == RB->getValue();
7206 }
7207
7208 // Fallback for other forms - use the existing comparison method
7209 return Expr::isSameComparisonOperand(LHS, RHS);
7210 }
7211 };
7212
7213 /// Get the offset of the OMP_MAP_MEMBER_OF field.
7214 static unsigned getFlagMemberOffset() {
7215 unsigned Offset = 0;
7216 for (uint64_t Remain =
7217 static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
7218 OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF);
7219 !(Remain & 1); Remain = Remain >> 1)
7220 Offset++;
7221 return Offset;
7222 }
7223
7224 /// Class that holds debugging information for a data mapping to be passed to
7225 /// the runtime library.
7226 class MappingExprInfo {
7227 /// The variable declaration used for the data mapping.
7228 const ValueDecl *MapDecl = nullptr;
7229 /// The original expression used in the map clause, or null if there is
7230 /// none.
7231 const Expr *MapExpr = nullptr;
7232
7233 public:
7234 MappingExprInfo(const ValueDecl *MapDecl, const Expr *MapExpr = nullptr)
7235 : MapDecl(MapDecl), MapExpr(MapExpr) {}
7236
7237 const ValueDecl *getMapDecl() const { return MapDecl; }
7238 const Expr *getMapExpr() const { return MapExpr; }
7239 };
7240
7241 using DeviceInfoTy = llvm::OpenMPIRBuilder::DeviceInfoTy;
7242 using MapBaseValuesArrayTy = llvm::OpenMPIRBuilder::MapValuesArrayTy;
7243 using MapValuesArrayTy = llvm::OpenMPIRBuilder::MapValuesArrayTy;
7244 using MapFlagsArrayTy = llvm::OpenMPIRBuilder::MapFlagsArrayTy;
7245 using MapDimArrayTy = llvm::OpenMPIRBuilder::MapDimArrayTy;
7246 using MapNonContiguousArrayTy =
7247 llvm::OpenMPIRBuilder::MapNonContiguousArrayTy;
7248 using MapExprsArrayTy = SmallVector<MappingExprInfo, 4>;
7249 using MapValueDeclsArrayTy = SmallVector<const ValueDecl *, 4>;
7250 using MapData =
7252 OpenMPMapClauseKind, ArrayRef<OpenMPMapModifierKind>,
7253 bool /*IsImplicit*/, const ValueDecl *, const Expr *>;
7254 using MapDataArrayTy = SmallVector<MapData, 4>;
7255
7256 /// This structure contains combined information generated for mappable
7257 /// clauses, including base pointers, pointers, sizes, map types, user-defined
7258 /// mappers, and non-contiguous information.
7259 struct MapCombinedInfoTy : llvm::OpenMPIRBuilder::MapInfosTy {
7260 MapExprsArrayTy Exprs;
7261 MapValueDeclsArrayTy Mappers;
7262 MapValueDeclsArrayTy DevicePtrDecls;
7263
7264 /// Append arrays in \a CurInfo.
7265 void append(MapCombinedInfoTy &CurInfo) {
7266 Exprs.append(CurInfo.Exprs.begin(), CurInfo.Exprs.end());
7267 DevicePtrDecls.append(CurInfo.DevicePtrDecls.begin(),
7268 CurInfo.DevicePtrDecls.end());
7269 Mappers.append(CurInfo.Mappers.begin(), CurInfo.Mappers.end());
7270 llvm::OpenMPIRBuilder::MapInfosTy::append(CurInfo);
7271 }
7272 };
7273
7274 /// Map between a struct and the its lowest & highest elements which have been
7275 /// mapped.
7276 /// [ValueDecl *] --> {LE(FieldIndex, Pointer),
7277 /// HE(FieldIndex, Pointer)}
7278 struct StructRangeInfoTy {
7279 MapCombinedInfoTy PreliminaryMapData;
7280 std::pair<unsigned /*FieldIndex*/, Address /*Pointer*/> LowestElem = {
7281 0, Address::invalid()};
7282 std::pair<unsigned /*FieldIndex*/, Address /*Pointer*/> HighestElem = {
7283 0, Address::invalid()};
7286 bool IsArraySection = false;
7287 bool HasCompleteRecord = false;
7288 };
7289
7290 /// A struct to store the attach pointer and pointee information, to be used
7291 /// when emitting an attach entry.
7292 struct AttachInfoTy {
7293 Address AttachPtrAddr = Address::invalid();
7294 Address AttachPteeAddr = Address::invalid();
7295 const ValueDecl *AttachPtrDecl = nullptr;
7296 const Expr *AttachMapExpr = nullptr;
7297
7298 bool isValid() const {
7299 return AttachPtrAddr.isValid() && AttachPteeAddr.isValid();
7300 }
7301 };
7302
7303 /// Check if there's any component list where the attach pointer expression
7304 /// matches the given captured variable.
7305 bool hasAttachEntryForCapturedVar(const ValueDecl *VD) const {
7306 for (const auto &AttachEntry : AttachPtrExprMap) {
7307 if (AttachEntry.second) {
7308 // Check if the attach pointer expression is a DeclRefExpr that
7309 // references the captured variable
7310 if (const auto *DRE = dyn_cast<DeclRefExpr>(AttachEntry.second))
7311 if (DRE->getDecl() == VD)
7312 return true;
7313 }
7314 }
7315 return false;
7316 }
7317
7318 /// Get the previously-cached attach pointer for a component list, if-any.
7319 const Expr *getAttachPtrExpr(
7321 const {
7322 const auto It = AttachPtrExprMap.find(Components);
7323 if (It != AttachPtrExprMap.end())
7324 return It->second;
7325
7326 return nullptr;
7327 }
7328
7329private:
7330 /// Kind that defines how a device pointer has to be returned.
7331 struct MapInfo {
7334 ArrayRef<OpenMPMapModifierKind> MapModifiers;
7335 ArrayRef<OpenMPMotionModifierKind> MotionModifiers;
7336 bool ReturnDevicePointer = false;
7337 bool IsImplicit = false;
7338 const ValueDecl *Mapper = nullptr;
7339 const Expr *VarRef = nullptr;
7340 bool ForDeviceAddr = false;
7341 bool HasUdpFbNullify = false;
7342
7343 MapInfo() = default;
7344 MapInfo(
7346 OpenMPMapClauseKind MapType,
7347 ArrayRef<OpenMPMapModifierKind> MapModifiers,
7348 ArrayRef<OpenMPMotionModifierKind> MotionModifiers,
7349 bool ReturnDevicePointer, bool IsImplicit,
7350 const ValueDecl *Mapper = nullptr, const Expr *VarRef = nullptr,
7351 bool ForDeviceAddr = false, bool HasUdpFbNullify = false)
7352 : Components(Components), MapType(MapType), MapModifiers(MapModifiers),
7353 MotionModifiers(MotionModifiers),
7354 ReturnDevicePointer(ReturnDevicePointer), IsImplicit(IsImplicit),
7355 Mapper(Mapper), VarRef(VarRef), ForDeviceAddr(ForDeviceAddr),
7356 HasUdpFbNullify(HasUdpFbNullify) {}
7357 };
7358
7359 /// The target directive from where the mappable clauses were extracted. It
7360 /// is either a executable directive or a user-defined mapper directive.
7361 llvm::PointerUnion<const OMPExecutableDirective *,
7362 const OMPDeclareMapperDecl *>
7363 CurDir;
7364
7365 /// Function the directive is being generated for.
7366 CodeGenFunction &CGF;
7367
7368 /// Set of all first private variables in the current directive.
7369 /// bool data is set to true if the variable is implicitly marked as
7370 /// firstprivate, false otherwise.
7371 llvm::DenseMap<CanonicalDeclPtr<const VarDecl>, bool> FirstPrivateDecls;
7372
7373 /// Set of defaultmap clause kinds that use firstprivate behavior.
7374 llvm::SmallSet<OpenMPDefaultmapClauseKind, 4> DefaultmapFirstprivateKinds;
7375
7376 /// Map between device pointer declarations and their expression components.
7377 /// The key value for declarations in 'this' is null.
7378 llvm::DenseMap<
7379 const ValueDecl *,
7380 SmallVector<OMPClauseMappableExprCommon::MappableExprComponentListRef, 4>>
7381 DevPointersMap;
7382
7383 /// Map between device addr declarations and their expression components.
7384 /// The key value for declarations in 'this' is null.
7385 llvm::DenseMap<
7386 const ValueDecl *,
7387 SmallVector<OMPClauseMappableExprCommon::MappableExprComponentListRef, 4>>
7388 HasDevAddrsMap;
7389
7390 /// Map between lambda declarations and their map type.
7391 llvm::DenseMap<const ValueDecl *, const OMPMapClause *> LambdasMap;
7392
7393 /// Map from component lists to their attach pointer expressions.
7395 const Expr *>
7396 AttachPtrExprMap;
7397
7398 /// Map from attach pointer expressions to their component depth.
7399 /// nullptr key has std::nullopt depth. This can be used to order attach-ptr
7400 /// expressions with increasing/decreasing depth.
7401 /// The component-depth of `nullptr` (i.e. no attach-ptr) is `std::nullopt`.
7402 /// TODO: Not urgent, but we should ideally use the number of pointer
7403 /// dereferences in an expr as an indicator of its complexity, instead of the
7404 /// component-depth. That would be needed for us to treat `p[1]`, `*(p + 10)`,
7405 /// `*(p + 5 + 5)` together.
7406 llvm::DenseMap<const Expr *, std::optional<size_t>>
7407 AttachPtrComponentDepthMap = {{nullptr, std::nullopt}};
7408
7409 /// Map from attach pointer expressions to the order they were computed in, in
7410 /// collectAttachPtrExprInfo().
7411 llvm::DenseMap<const Expr *, size_t> AttachPtrComputationOrderMap = {
7412 {nullptr, 0}};
7413
7414 /// An instance of attach-ptr-expr comparator that can be used throughout the
7415 /// lifetime of this handler.
7416 AttachPtrExprComparator AttachPtrComparator;
7417
7418 llvm::Value *getExprTypeSize(const Expr *E) const {
7419 QualType ExprTy = E->getType().getCanonicalType();
7420
7421 // Calculate the size for array shaping expression.
7422 if (const auto *OAE = dyn_cast<OMPArrayShapingExpr>(E)) {
7423 llvm::Value *Size =
7424 CGF.getTypeSize(OAE->getBase()->getType()->getPointeeType());
7425 for (const Expr *SE : OAE->getDimensions()) {
7426 llvm::Value *Sz = CGF.EmitScalarExpr(SE);
7427 Sz = CGF.EmitScalarConversion(Sz, SE->getType(),
7428 CGF.getContext().getSizeType(),
7429 SE->getExprLoc());
7430 Size = CGF.Builder.CreateNUWMul(Size, Sz);
7431 }
7432 return Size;
7433 }
7434
7435 // Reference types are ignored for mapping purposes.
7436 if (const auto *RefTy = ExprTy->getAs<ReferenceType>())
7437 ExprTy = RefTy->getPointeeType().getCanonicalType();
7438
7439 // Given that an array section is considered a built-in type, we need to
7440 // do the calculation based on the length of the section instead of relying
7441 // on CGF.getTypeSize(E->getType()).
7442 if (const auto *OAE = dyn_cast<ArraySectionExpr>(E)) {
7443 QualType BaseTy = ArraySectionExpr::getBaseOriginalType(
7444 OAE->getBase()->IgnoreParenImpCasts())
7446
7447 // If there is no length associated with the expression and lower bound is
7448 // not specified too, that means we are using the whole length of the
7449 // base.
7450 if (!OAE->getLength() && OAE->getColonLocFirst().isValid() &&
7451 !OAE->getLowerBound())
7452 return CGF.getTypeSize(BaseTy);
7453
7454 llvm::Value *ElemSize;
7455 if (const auto *PTy = BaseTy->getAs<PointerType>()) {
7456 ElemSize = CGF.getTypeSize(PTy->getPointeeType().getCanonicalType());
7457 } else {
7458 const auto *ATy = cast<ArrayType>(BaseTy.getTypePtr());
7459 assert(ATy && "Expecting array type if not a pointer type.");
7460 ElemSize = CGF.getTypeSize(ATy->getElementType().getCanonicalType());
7461 }
7462
7463 // If we don't have a length at this point, that is because we have an
7464 // array section with a single element.
7465 if (!OAE->getLength() && OAE->getColonLocFirst().isInvalid())
7466 return ElemSize;
7467
7468 if (const Expr *LenExpr = OAE->getLength()) {
7469 llvm::Value *LengthVal = CGF.EmitScalarExpr(LenExpr);
7470 LengthVal = CGF.EmitScalarConversion(LengthVal, LenExpr->getType(),
7471 CGF.getContext().getSizeType(),
7472 LenExpr->getExprLoc());
7473 return CGF.Builder.CreateNUWMul(LengthVal, ElemSize);
7474 }
7475 assert(!OAE->getLength() && OAE->getColonLocFirst().isValid() &&
7476 OAE->getLowerBound() && "expected array_section[lb:].");
7477 // Size = sizetype - lb * elemtype;
7478 llvm::Value *LengthVal = CGF.getTypeSize(BaseTy);
7479 llvm::Value *LBVal = CGF.EmitScalarExpr(OAE->getLowerBound());
7480 LBVal = CGF.EmitScalarConversion(LBVal, OAE->getLowerBound()->getType(),
7481 CGF.getContext().getSizeType(),
7482 OAE->getLowerBound()->getExprLoc());
7483 LBVal = CGF.Builder.CreateNUWMul(LBVal, ElemSize);
7484 llvm::Value *Cmp = CGF.Builder.CreateICmpUGT(LengthVal, LBVal);
7485 llvm::Value *TrueVal = CGF.Builder.CreateNUWSub(LengthVal, LBVal);
7486 LengthVal = CGF.Builder.CreateSelect(
7487 Cmp, TrueVal, llvm::ConstantInt::get(CGF.SizeTy, 0));
7488 return LengthVal;
7489 }
7490 return CGF.getTypeSize(ExprTy);
7491 }
7492
7493 /// Return the corresponding bits for a given map clause modifier. Add
7494 /// a flag marking the map as a pointer if requested. Add a flag marking the
7495 /// map as the first one of a series of maps that relate to the same map
7496 /// expression.
7497 OpenMPOffloadMappingFlags getMapTypeBits(
7498 OpenMPMapClauseKind MapType, ArrayRef<OpenMPMapModifierKind> MapModifiers,
7499 ArrayRef<OpenMPMotionModifierKind> MotionModifiers, bool IsImplicit,
7500 bool AddPtrFlag, bool AddIsTargetParamFlag, bool IsNonContiguous) const {
7501 OpenMPOffloadMappingFlags Bits =
7502 IsImplicit ? OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT
7503 : OpenMPOffloadMappingFlags::OMP_MAP_NONE;
7504 switch (MapType) {
7505 case OMPC_MAP_alloc:
7506 case OMPC_MAP_release:
7507 // alloc and release is the default behavior in the runtime library, i.e.
7508 // if we don't pass any bits alloc/release that is what the runtime is
7509 // going to do. Therefore, we don't need to signal anything for these two
7510 // type modifiers.
7511 break;
7512 case OMPC_MAP_to:
7513 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_TO;
7514 break;
7515 case OMPC_MAP_from:
7516 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_FROM;
7517 break;
7518 case OMPC_MAP_tofrom:
7519 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_TO |
7520 OpenMPOffloadMappingFlags::OMP_MAP_FROM;
7521 break;
7522 case OMPC_MAP_delete:
7523 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_DELETE;
7524 break;
7525 case OMPC_MAP_unknown:
7526 llvm_unreachable("Unexpected map type!");
7527 }
7528 if (AddPtrFlag)
7529 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ;
7530 if (AddIsTargetParamFlag)
7531 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM;
7532 if (llvm::is_contained(MapModifiers, OMPC_MAP_MODIFIER_always))
7533 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_ALWAYS;
7534 if (llvm::is_contained(MapModifiers, OMPC_MAP_MODIFIER_close))
7535 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_CLOSE;
7536 if (llvm::is_contained(MapModifiers, OMPC_MAP_MODIFIER_present) ||
7537 llvm::is_contained(MotionModifiers, OMPC_MOTION_MODIFIER_present))
7538 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_PRESENT;
7539 if (llvm::is_contained(MapModifiers, OMPC_MAP_MODIFIER_ompx_hold))
7540 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_OMPX_HOLD;
7541 if (IsNonContiguous)
7542 Bits |= OpenMPOffloadMappingFlags::OMP_MAP_NON_CONTIG;
7543 return Bits;
7544 }
7545
7546 /// Return true if the provided expression is a final array section. A
7547 /// final array section, is one whose length can't be proved to be one.
7548 bool isFinalArraySectionExpression(const Expr *E) const {
7549 const auto *OASE = dyn_cast<ArraySectionExpr>(E);
7550
7551 // It is not an array section and therefore not a unity-size one.
7552 if (!OASE)
7553 return false;
7554
7555 // An array section with no colon always refer to a single element.
7556 if (OASE->getColonLocFirst().isInvalid())
7557 return false;
7558
7559 const Expr *Length = OASE->getLength();
7560
7561 // If we don't have a length we have to check if the array has size 1
7562 // for this dimension. Also, we should always expect a length if the
7563 // base type is pointer.
7564 if (!Length) {
7565 QualType BaseQTy = ArraySectionExpr::getBaseOriginalType(
7566 OASE->getBase()->IgnoreParenImpCasts())
7568 if (const auto *ATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr()))
7569 return ATy->getSExtSize() != 1;
7570 // If we don't have a constant dimension length, we have to consider
7571 // the current section as having any size, so it is not necessarily
7572 // unitary. If it happen to be unity size, that's user fault.
7573 return true;
7574 }
7575
7576 // Check if the length evaluates to 1.
7577 Expr::EvalResult Result;
7578 if (!Length->EvaluateAsInt(Result, CGF.getContext()))
7579 return true; // Can have more that size 1.
7580
7581 llvm::APSInt ConstLength = Result.Val.getInt();
7582 return ConstLength.getSExtValue() != 1;
7583 }
7584
7585 /// Emit an attach entry into \p CombinedInfo, using the information from \p
7586 /// AttachInfo. For example, for a map of form `int *p; ... map(p[1:10])`,
7587 /// an attach entry has the following form:
7588 /// &p, &p[1], sizeof(void*), ATTACH
7589 void emitAttachEntry(CodeGenFunction &CGF, MapCombinedInfoTy &CombinedInfo,
7590 const AttachInfoTy &AttachInfo) const {
7591 assert(AttachInfo.isValid() &&
7592 "Expected valid attach pointer/pointee information!");
7593
7594 // Size is the size of the pointer itself - use pointer size, not BaseDecl
7595 // size
7596 llvm::Value *PointerSize = CGF.Builder.CreateIntCast(
7597 llvm::ConstantInt::get(
7598 CGF.CGM.SizeTy, CGF.getContext()
7600 .getQuantity()),
7601 CGF.Int64Ty, /*isSigned=*/true);
7602
7603 CombinedInfo.Exprs.emplace_back(AttachInfo.AttachPtrDecl,
7604 AttachInfo.AttachMapExpr);
7605 CombinedInfo.BasePointers.push_back(
7606 AttachInfo.AttachPtrAddr.emitRawPointer(CGF));
7607 CombinedInfo.DevicePtrDecls.push_back(nullptr);
7608 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
7609 CombinedInfo.Pointers.push_back(
7610 AttachInfo.AttachPteeAddr.emitRawPointer(CGF));
7611 CombinedInfo.Sizes.push_back(PointerSize);
7612 CombinedInfo.Types.push_back(OpenMPOffloadMappingFlags::OMP_MAP_ATTACH);
7613 // ATTACH entries themselves don't "have" a base attach-ptr.
7614 CombinedInfo.HasAttachPtr.push_back(false);
7615 CombinedInfo.Mappers.push_back(nullptr);
7616 CombinedInfo.NonContigInfo.Dims.push_back(1);
7617 }
7618
7619 /// A helper class to copy structures with overlapped elements, i.e. those
7620 /// which have mappings of both "s" and "s.mem". Consecutive elements that
7621 /// are not explicitly copied have mapping nodes synthesized for them,
7622 /// taking care to avoid generating zero-sized copies.
7623 class CopyOverlappedEntryGaps {
7624 CodeGenFunction &CGF;
7625 MapCombinedInfoTy &CombinedInfo;
7626 OpenMPOffloadMappingFlags Flags = OpenMPOffloadMappingFlags::OMP_MAP_NONE;
7627 const ValueDecl *MapDecl = nullptr;
7628 const Expr *MapExpr = nullptr;
7630 bool IsNonContiguous = false;
7631 uint64_t DimSize = 0;
7632 // These elements track the position as the struct is iterated over
7633 // (in order of increasing element address).
7634 const RecordDecl *LastParent = nullptr;
7635 uint64_t Cursor = 0;
7636 unsigned LastIndex = -1u;
7638
7639 public:
7640 CopyOverlappedEntryGaps(CodeGenFunction &CGF,
7641 MapCombinedInfoTy &CombinedInfo,
7642 OpenMPOffloadMappingFlags Flags,
7643 const ValueDecl *MapDecl, const Expr *MapExpr,
7644 Address BP, Address LB, bool IsNonContiguous,
7645 uint64_t DimSize)
7646 : CGF(CGF), CombinedInfo(CombinedInfo), Flags(Flags), MapDecl(MapDecl),
7647 MapExpr(MapExpr), BP(BP), IsNonContiguous(IsNonContiguous),
7648 DimSize(DimSize), LB(LB) {}
7649
7650 void processField(
7651 const OMPClauseMappableExprCommon::MappableComponent &MC,
7652 const FieldDecl *FD,
7653 llvm::function_ref<LValue(CodeGenFunction &, const MemberExpr *)>
7654 EmitMemberExprBase) {
7655 const RecordDecl *RD = FD->getParent();
7656 const ASTRecordLayout &RL = CGF.getContext().getASTRecordLayout(RD);
7657 uint64_t FieldOffset = RL.getFieldOffset(FD->getFieldIndex());
7658 uint64_t FieldSize =
7660 Address ComponentLB = Address::invalid();
7661
7662 if (FD->getType()->isLValueReferenceType()) {
7663 const auto *ME = cast<MemberExpr>(MC.getAssociatedExpression());
7664 LValue BaseLVal = EmitMemberExprBase(CGF, ME);
7665 ComponentLB =
7666 CGF.EmitLValueForFieldInitialization(BaseLVal, FD).getAddress();
7667 } else {
7668 ComponentLB =
7670 }
7671
7672 if (!LastParent)
7673 LastParent = RD;
7674 if (FD->getParent() == LastParent) {
7675 if (FD->getFieldIndex() != LastIndex + 1)
7676 copyUntilField(FD, ComponentLB);
7677 } else {
7678 LastParent = FD->getParent();
7679 if (((int64_t)FieldOffset - (int64_t)Cursor) > 0)
7680 copyUntilField(FD, ComponentLB);
7681 }
7682 Cursor = FieldOffset + FieldSize;
7683 LastIndex = FD->getFieldIndex();
7684 LB = CGF.Builder.CreateConstGEP(ComponentLB, 1);
7685 }
7686
7687 void copyUntilField(const FieldDecl *FD, Address ComponentLB) {
7688 llvm::Value *ComponentLBPtr = ComponentLB.emitRawPointer(CGF);
7689 llvm::Value *LBPtr = LB.emitRawPointer(CGF);
7690 llvm::Value *Size = CGF.Builder.CreatePtrDiff(ComponentLBPtr, LBPtr);
7691 copySizedChunk(LBPtr, Size);
7692 }
7693
7694 void copyUntilEnd(Address HB) {
7695 if (LastParent) {
7696 const ASTRecordLayout &RL =
7697 CGF.getContext().getASTRecordLayout(LastParent);
7698 if ((uint64_t)CGF.getContext().toBits(RL.getSize()) <= Cursor)
7699 return;
7700 }
7701 llvm::Value *LBPtr = LB.emitRawPointer(CGF);
7702 llvm::Value *Size = CGF.Builder.CreatePtrDiff(
7703 CGF.Builder.CreateConstGEP(HB, 1).emitRawPointer(CGF), LBPtr);
7704 copySizedChunk(LBPtr, Size);
7705 }
7706
7707 void copySizedChunk(llvm::Value *Base, llvm::Value *Size) {
7708 CombinedInfo.Exprs.emplace_back(MapDecl, MapExpr);
7709 CombinedInfo.BasePointers.push_back(BP.emitRawPointer(CGF));
7710 CombinedInfo.DevicePtrDecls.push_back(nullptr);
7711 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
7712 CombinedInfo.Pointers.push_back(Base);
7713 CombinedInfo.Sizes.push_back(
7714 CGF.Builder.CreateIntCast(Size, CGF.Int64Ty, /*isSigned=*/false));
7715 CombinedInfo.Types.push_back(Flags);
7716 CombinedInfo.HasAttachPtr.push_back(false);
7717 CombinedInfo.Mappers.push_back(nullptr);
7718 CombinedInfo.NonContigInfo.Dims.push_back(IsNonContiguous ? DimSize : 1);
7719 }
7720 };
7721
7722 /// Generate the base pointers, section pointers, sizes, map type bits, and
7723 /// user-defined mappers (all included in \a CombinedInfo) for the provided
7724 /// map type, map or motion modifiers, and expression components.
7725 /// \a IsFirstComponent should be set to true if the provided set of
7726 /// components is the first associated with a capture.
7727 void generateInfoForComponentList(
7728 OpenMPMapClauseKind MapType, ArrayRef<OpenMPMapModifierKind> MapModifiers,
7729 ArrayRef<OpenMPMotionModifierKind> MotionModifiers,
7731 MapCombinedInfoTy &CombinedInfo,
7732 MapCombinedInfoTy &StructBaseCombinedInfo,
7733 StructRangeInfoTy &PartialStruct, AttachInfoTy &AttachInfo,
7734 bool IsFirstComponentList, bool IsImplicit,
7735 bool GenerateAllInfoForClauses, const ValueDecl *Mapper = nullptr,
7736 bool ForDeviceAddr = false, const ValueDecl *BaseDecl = nullptr,
7737 const Expr *MapExpr = nullptr,
7738 ArrayRef<OMPClauseMappableExprCommon::MappableExprComponentListRef>
7739 OverlappedElements = {}) const {
7740
7741 // The following summarizes what has to be generated for each map and the
7742 // types below. The generated information is expressed in this order:
7743 // base pointer, section pointer, size, flags
7744 // (to add to the ones that come from the map type and modifier).
7745 // Entries annotated with (+) are only generated for "target" constructs,
7746 // and only if the variable at the beginning of the expression is used in
7747 // the region.
7748 //
7749 // double d;
7750 // int i[100];
7751 // float *p;
7752 // int **a = &i;
7753 //
7754 // struct S1 {
7755 // int i;
7756 // float f[50];
7757 // }
7758 // struct S2 {
7759 // int i;
7760 // float f[50];
7761 // S1 s;
7762 // double *p;
7763 // double *&pref;
7764 // struct S2 *ps;
7765 // int &ref;
7766 // }
7767 // S2 s;
7768 // S2 *ps;
7769 //
7770 // map(d)
7771 // &d, &d, sizeof(double), TARGET_PARAM | TO | FROM
7772 //
7773 // map(i)
7774 // &i, &i, 100*sizeof(int), TARGET_PARAM | TO | FROM
7775 //
7776 // map(i[1:23])
7777 // &i(=&i[0]), &i[1], 23*sizeof(int), TARGET_PARAM | TO | FROM
7778 //
7779 // map(p)
7780 // &p, &p, sizeof(float*), TARGET_PARAM | TO | FROM
7781 //
7782 // map(p[1:24])
7783 // p, &p[1], 24*sizeof(float), TARGET_PARAM | TO | FROM // map pointee
7784 // &p, &p[1], sizeof(void*), ATTACH // attach pointer/pointee, if both
7785 // // are present, and either is new
7786 //
7787 // map(([22])p)
7788 // p, p, 22*sizeof(float), TARGET_PARAM | TO | FROM
7789 // &p, p, sizeof(void*), ATTACH
7790 //
7791 // map((*a)[0:3])
7792 // a, a, 0, TARGET_PARAM | IMPLICIT // (+)
7793 // (*a)[0], &(*a)[0], 3 * sizeof(int), TO | FROM
7794 // &(*a), &(*a)[0], sizeof(void*), ATTACH
7795 // (+) Only on target, if a is used in the region
7796 // Note: Since the attach base-pointer is `*a`, which is not a scalar
7797 // variable, it doesn't determine the clause on `a`. `a` is mapped using
7798 // a zero-length-array-section map by generateDefaultMapInfo, if it is
7799 // referenced in the target region, because it is a pointer.
7800 //
7801 // map(**a)
7802 // a, a, 0, TARGET_PARAM | IMPLICIT // (+)
7803 // &(*a)[0], &(*a)[0], sizeof(int), TO | FROM
7804 // &(*a), &(*a)[0], sizeof(void*), ATTACH
7805 // (+) Only on target, if a is used in the region
7806 //
7807 // map(s)
7808 // FIXME: This needs to also imply map(ref_ptr_ptee: s.ref), since the
7809 // effect is supposed to be same as if the user had a map for every element
7810 // of the struct. We currently do a shallow-map of s.
7811 // &s, &s, sizeof(S2), TARGET_PARAM | TO | FROM
7812 //
7813 // map(s.i)
7814 // &s, &(s.i), sizeof(int), TARGET_PARAM | TO | FROM
7815 //
7816 // map(s.s.f)
7817 // &s, &(s.s.f[0]), 50*sizeof(float), TARGET_PARAM | TO | FROM
7818 //
7819 // map(s.p)
7820 // &s, &(s.p), sizeof(double*), TARGET_PARAM | TO | FROM
7821 //
7822 // map(to: s.p[:22])
7823 // &s, &(s.p), sizeof(double*), TARGET_PARAM | IMPLICIT // (+)
7824 // &(s.p[0]), &(s.p[0]), 22 * sizeof(double*), TO | FROM
7825 // &(s.p), &(s.p[0]), sizeof(void*), ATTACH
7826 //
7827 // map(to: s.ref)
7828 // &s, &(ptr(s.ref)), sizeof(int*), TARGET_PARAM (*)
7829 // &s, &(ptee(s.ref)), sizeof(int), MEMBER_OF(1) | PTR_AND_OBJ | TO (***)
7830 // (*) alloc space for struct members, only this is a target parameter.
7831 // (**) map the pointer (nothing to be mapped in this example) (the compiler
7832 // optimizes this entry out, same in the examples below)
7833 // (***) map the pointee (map: to)
7834 // Note: ptr(s.ref) represents the referring pointer of s.ref
7835 // ptee(s.ref) represents the referenced pointee of s.ref
7836 //
7837 // map(to: s.pref)
7838 // &s, &(ptr(s.pref)), sizeof(double**), TARGET_PARAM
7839 // &s, &(ptee(s.pref)), sizeof(double*), MEMBER_OF(1) | PTR_AND_OBJ | TO
7840 //
7841 // map(to: s.pref[:22])
7842 // &s, &(ptr(s.pref)), sizeof(double**), TARGET_PARAM | IMPLICIT // (+)
7843 // &s, &(ptee(s.pref)), sizeof(double*), MEMBER_OF(1) | PTR_AND_OBJ | TO |
7844 // FROM | IMPLICIT // (+)
7845 // &(ptee(s.pref)[0]), &(ptee(s.pref)[0]), 22 * sizeof(double), TO
7846 // &(ptee(s.pref)), &(ptee(s.pref)[0]), sizeof(void*), ATTACH
7847 //
7848 // map(s.ps)
7849 // &s, &(s.ps), sizeof(S2*), TARGET_PARAM | TO | FROM
7850 //
7851 // map(from: s.ps->s.i)
7852 // &s, &(s.ps), sizeof(S2*), TARGET_PARAM | TO | FROM | IMPLICIT // (+)
7853 // &(s.ps[0]), &(s.ps->s.i), sizeof(int), FROM
7854 // &(s.ps), &(s.ps->s.i), sizeof(void*), ATTACH
7855 //
7856 // map(to: s.ps->ps)
7857 // &s, &(s.ps), sizeof(S2*), TARGET_PARAM | TO | FROM | IMPLICIT // (+)
7858 // &(s.ps[0]), &(s.ps->ps), sizeof(S2*), TO
7859 // &(s.ps), &(s.ps->ps), sizeof(void*), ATTACH
7860 //
7861 // map(s.ps->ps->ps)
7862 // &s, &(s.ps), sizeof(S2*), TARGET_PARAM | TO | FROM | IMPLICIT // (+)
7863 // &(s.ps->ps[0]), &(s.ps->ps->ps), sizeof(S2*), TO
7864 // &(s.ps->ps), &(s.ps->ps->ps), sizeof(void*), ATTACH
7865 //
7866 // map(to: s.ps->ps->s.f[:22])
7867 // &s, &(s.ps), sizeof(S2*), TARGET_PARAM | TO | FROM | IMPLICIT // (+)
7868 // &(s.ps->ps[0]), &(s.ps->ps->s.f[0]), 22*sizeof(float), TO
7869 // &(s.ps->ps), &(s.ps->ps->s.f[0]), sizeof(void*), ATTACH
7870 //
7871 // map(ps)
7872 // &ps, &ps, sizeof(S2*), TARGET_PARAM | TO | FROM
7873 //
7874 // map(ps->i)
7875 // ps, &(ps->i), sizeof(int), TARGET_PARAM | TO | FROM
7876 // &ps, &(ps->i), sizeof(void*), ATTACH
7877 //
7878 // map(ps->s.f)
7879 // ps, &(ps->s.f[0]), 50*sizeof(float), TARGET_PARAM | TO | FROM
7880 // &ps, &(ps->s.f[0]), sizeof(ps), ATTACH
7881 //
7882 // map(from: ps->p)
7883 // ps, &(ps->p), sizeof(double*), TARGET_PARAM | FROM
7884 // &ps, &(ps->p), sizeof(ps), ATTACH
7885 //
7886 // map(to: ps->p[:22])
7887 // ps, &(ps[0]), 0, TARGET_PARAM | IMPLICIT // (+)
7888 // &(ps->p[0]), &(ps->p[0]), 22*sizeof(double), TO
7889 // &(ps->p), &(ps->p[0]), sizeof(void*), ATTACH
7890 //
7891 // map(ps->ps)
7892 // ps, &(ps->ps), sizeof(S2*), TARGET_PARAM | TO | FROM
7893 // &ps, &(ps->ps), sizeof(ps), ATTACH
7894 //
7895 // map(from: ps->ps->s.i)
7896 // ps, &(ps[0]), 0, TARGET_PARAM | IMPLICIT // (+)
7897 // &(ps->ps[0]), &(ps->ps->s.i), sizeof(int), FROM
7898 // &(ps->ps), &(ps->ps->s.i), sizeof(void*), ATTACH
7899 //
7900 // map(from: ps->ps->ps)
7901 // ps, &ps[0], 0, TARGET_PARAM | IMPLICIT // (+)
7902 // &(ps->ps[0]), &(ps->ps->ps), sizeof(S2*), FROM
7903 // &(ps->ps), &(ps->ps->ps), sizeof(void*), ATTACH
7904 //
7905 // map(ps->ps->ps->ps)
7906 // ps, &ps[0], 0, TARGET_PARAM | IMPLICIT // (+)
7907 // &(ps->ps->ps[0]), &(ps->ps->ps->ps), sizeof(S2*), FROM
7908 // &(ps->ps->ps), &(ps->ps->ps->ps), sizeof(void*), ATTACH
7909 //
7910 // map(to: ps->ps->ps->s.f[:22])
7911 // ps, &ps[0], 0, TARGET_PARAM | IMPLICIT // (+)
7912 // &(ps->ps->ps[0]), &(ps->ps->ps->s.f[0]), 22*sizeof(float), TO
7913 // &(ps->ps->ps), &(ps->ps->ps->s.f[0]), sizeof(void*), ATTACH
7914 //
7915 // map(to: s.f[:22]) map(from: s.p[:33])
7916 // On target, and if s is used in the region:
7917 //
7918 // &s, &(s.f[0]), 50*sizeof(float) +
7919 // sizeof(struct S1) +
7920 // sizeof(double*) (**), TARGET_PARAM
7921 // &s, &(s.f[0]), 22*sizeof(float), MEMBER_OF(1) | TO
7922 // &s, &(s.p), sizeof(double*), MEMBER_OF(1) | TO |
7923 // FROM | IMPLICIT
7924 // &(s.p[0]), &(s.p[0]), 33*sizeof(double), FROM
7925 // &(s.p), &(s.p[0]), sizeof(void*), ATTACH
7926 // (**) allocate contiguous space needed to fit all mapped members even if
7927 // we allocate space for members not mapped (in this example,
7928 // s.f[22..49] and s.s are not mapped, yet we must allocate space for
7929 // them as well because they fall between &s.f[0] and &s.p)
7930 //
7931 // On other constructs, and, if s is not used in the region, on target:
7932 // &s, &(s.f[0]), 22*sizeof(float), TO
7933 // &(s.p[0]), &(s.p[0]), 33*sizeof(double), FROM
7934 // &(s.p), &(s.p[0]), sizeof(void*), ATTACH
7935 //
7936 // map(from: s.f[:22]) map(to: ps->p[:33])
7937 // &s, &(s.f[0]), 22*sizeof(float), TARGET_PARAM | FROM
7938 // &ps[0], &ps[0], 0, TARGET_PARAM | IMPLICIT // (+)
7939 // &(ps->p[0]), &(ps->p[0]), 33*sizeof(double), TO
7940 // &(ps->p), &(ps->p[0]), sizeof(void*), ATTACH
7941 //
7942 // map(from: s.f[:22], s.s) map(to: ps->p[:33])
7943 // &s, &(s.f[0]), 50*sizeof(float) +
7944 // sizeof(struct S1), TARGET_PARAM
7945 // &s, &(s.f[0]), 22*sizeof(float), MEMBER_OF(1) | FROM
7946 // &s, &(s.s), sizeof(struct S1), MEMBER_OF(1) | FROM
7947 // ps, &ps[0], 0, TARGET_PARAM | IMPLICIT // (+)
7948 // &(ps->p[0]), &(ps->p[0]), 33*sizeof(double), TO
7949 // &(ps->p), &(ps->p[0]), sizeof(void*), ATTACH
7950 //
7951 // map(p[:100], p)
7952 // &p, &p, sizeof(float*), TARGET_PARAM | TO | FROM
7953 // p, &p[0], 100*sizeof(float), TO | FROM
7954 // &p, &p[0], sizeof(float*), ATTACH
7955
7956 // Track if the map information being generated is the first for a capture.
7957 bool IsCaptureFirstInfo = IsFirstComponentList;
7958 // When the variable is on a declare target link or in a to clause with
7959 // unified memory, a reference is needed to hold the host/device address
7960 // of the variable.
7961 bool RequiresReference = false;
7962
7963 // Scan the components from the base to the complete expression.
7964 auto CI = Components.rbegin();
7965 auto CE = Components.rend();
7966 auto I = CI;
7967
7968 // Track if the map information being generated is the first for a list of
7969 // components.
7970 bool IsExpressionFirstInfo = true;
7971 bool FirstPointerInComplexData = false;
7973 Address FinalLowestElem = Address::invalid();
7974 const Expr *AssocExpr = I->getAssociatedExpression();
7975 const auto *AE = dyn_cast<ArraySubscriptExpr>(AssocExpr);
7976 const auto *OASE = dyn_cast<ArraySectionExpr>(AssocExpr);
7977 const auto *OAShE = dyn_cast<OMPArrayShapingExpr>(AssocExpr);
7978
7979 // Get the pointer-attachment base-pointer for the given list, if any.
7980 const Expr *AttachPtrExpr = getAttachPtrExpr(Components);
7981 auto [AttachPtrAddr, AttachPteeBaseAddr] =
7982 getAttachPtrAddrAndPteeBaseAddr(AttachPtrExpr, CGF);
7983
7984 bool HasAttachPtr = AttachPtrExpr != nullptr;
7985 bool FirstComponentIsForAttachPtr = AssocExpr == AttachPtrExpr;
7986 bool SeenAttachPtr = FirstComponentIsForAttachPtr;
7987
7988 if (FirstComponentIsForAttachPtr) {
7989 // No need to process AttachPtr here. It will be processed at the end
7990 // after we have computed the pointee's address.
7991 ++I;
7992 } else if (isa<MemberExpr>(AssocExpr)) {
7993 // The base is the 'this' pointer. The content of the pointer is going
7994 // to be the base of the field being mapped.
7995 BP = CGF.LoadCXXThisAddress();
7996 } else if ((AE && isa<CXXThisExpr>(AE->getBase()->IgnoreParenImpCasts())) ||
7997 (OASE &&
7998 isa<CXXThisExpr>(OASE->getBase()->IgnoreParenImpCasts()))) {
7999 BP = CGF.EmitOMPSharedLValue(AssocExpr).getAddress();
8000 } else if (OAShE &&
8001 isa<CXXThisExpr>(OAShE->getBase()->IgnoreParenCasts())) {
8002 BP = Address(
8003 CGF.EmitScalarExpr(OAShE->getBase()),
8004 CGF.ConvertTypeForMem(OAShE->getBase()->getType()->getPointeeType()),
8005 CGF.getContext().getTypeAlignInChars(OAShE->getBase()->getType()));
8006 } else {
8007 // The base is the reference to the variable.
8008 // BP = &Var.
8009 BP = CGF.EmitOMPSharedLValue(AssocExpr).getAddress();
8010 if (const auto *VD =
8011 dyn_cast_or_null<VarDecl>(I->getAssociatedDeclaration())) {
8012 if (std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
8013 OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD)) {
8014 if ((*Res == OMPDeclareTargetDeclAttr::MT_Link) ||
8015 ((*Res == OMPDeclareTargetDeclAttr::MT_To ||
8016 *Res == OMPDeclareTargetDeclAttr::MT_Enter) &&
8018 RequiresReference = true;
8020 }
8021 }
8022 }
8023
8024 // If the variable is a pointer and is being dereferenced (i.e. is not
8025 // the last component), the base has to be the pointer itself, not its
8026 // reference. References are ignored for mapping purposes.
8027 QualType Ty =
8028 I->getAssociatedDeclaration()->getType().getNonReferenceType();
8029 if (Ty->isAnyPointerType() && std::next(I) != CE) {
8030 // No need to generate individual map information for the pointer, it
8031 // can be associated with the combined storage if shared memory mode is
8032 // active or the base declaration is not global variable.
8033 const auto *VD = dyn_cast<VarDecl>(I->getAssociatedDeclaration());
8035 !VD || VD->hasLocalStorage() || HasAttachPtr)
8036 BP = CGF.EmitLoadOfPointer(BP, Ty->castAs<PointerType>());
8037 else
8038 FirstPointerInComplexData = true;
8039 ++I;
8040 }
8041 }
8042
8043 // Track whether a component of the list should be marked as MEMBER_OF some
8044 // combined entry (for partial structs). Only the first PTR_AND_OBJ entry
8045 // in a component list should be marked as MEMBER_OF, all subsequent entries
8046 // do not belong to the base struct. E.g.
8047 // struct S2 s;
8048 // s.ps->ps->ps->f[:]
8049 // (1) (2) (3) (4)
8050 // ps(1) is a member pointer, ps(2) is a pointee of ps(1), so it is a
8051 // PTR_AND_OBJ entry; the PTR is ps(1), so MEMBER_OF the base struct. ps(3)
8052 // is the pointee of ps(2) which is not member of struct s, so it should not
8053 // be marked as such (it is still PTR_AND_OBJ).
8054 // The variable is initialized to false so that PTR_AND_OBJ entries which
8055 // are not struct members are not considered (e.g. array of pointers to
8056 // data).
8057 bool ShouldBeMemberOf = false;
8058
8059 // Variable keeping track of whether or not we have encountered a component
8060 // in the component list which is a member expression. Useful when we have a
8061 // pointer or a final array section, in which case it is the previous
8062 // component in the list which tells us whether we have a member expression.
8063 // E.g. X.f[:]
8064 // While processing the final array section "[:]" it is "f" which tells us
8065 // whether we are dealing with a member of a declared struct.
8066 const MemberExpr *EncounteredME = nullptr;
8067
8068 // Track for the total number of dimension. Start from one for the dummy
8069 // dimension.
8070 uint64_t DimSize = 1;
8071
8072 // Detects non-contiguous updates due to strided accesses.
8073 // Sets the 'IsNonContiguous' flag so that the 'MapType' bits are set
8074 // correctly when generating information to be passed to the runtime. The
8075 // flag is set to true if any array section has a stride not equal to 1, or
8076 // if the stride is not a constant expression (conservatively assumed
8077 // non-contiguous).
8078 bool IsNonContiguous =
8079 CombinedInfo.NonContigInfo.IsNonContiguous ||
8080 any_of(Components, [&](const auto &Component) {
8081 const auto *OASE =
8082 dyn_cast<ArraySectionExpr>(Component.getAssociatedExpression());
8083 if (!OASE)
8084 return false;
8085
8086 const Expr *StrideExpr = OASE->getStride();
8087 if (!StrideExpr)
8088 return false;
8089
8090 assert(StrideExpr->getType()->isIntegerType() &&
8091 "Stride expression must be of integer type");
8092
8093 // If stride is not evaluatable as a constant, treat as
8094 // non-contiguous.
8095 const auto Constant =
8096 StrideExpr->getIntegerConstantExpr(CGF.getContext());
8097 if (!Constant)
8098 return true;
8099
8100 // Treat non-unitary strides as non-contiguous.
8101 return !Constant->isOne();
8102 });
8103
8104 bool IsPrevMemberReference = false;
8105
8106 bool IsPartialMapped =
8107 !PartialStruct.PreliminaryMapData.BasePointers.empty();
8108
8109 // We need to check if we will be encountering any MEs. If we do not
8110 // encounter any ME expression it means we will be mapping the whole struct.
8111 // In that case we need to skip adding an entry for the struct to the
8112 // CombinedInfo list and instead add an entry to the StructBaseCombinedInfo
8113 // list only when generating all info for clauses.
8114 bool IsMappingWholeStruct = true;
8115 if (!GenerateAllInfoForClauses) {
8116 IsMappingWholeStruct = false;
8117 } else {
8118 for (auto TempI = I; TempI != CE; ++TempI) {
8119 const MemberExpr *PossibleME =
8120 dyn_cast<MemberExpr>(TempI->getAssociatedExpression());
8121 if (PossibleME) {
8122 IsMappingWholeStruct = false;
8123 break;
8124 }
8125 }
8126 }
8127
8128 bool SeenFirstNonBinOpExprAfterAttachPtr = false;
8129 for (; I != CE; ++I) {
8130 // If we have a valid attach-ptr, we skip processing all components until
8131 // after the attach-ptr.
8132 if (HasAttachPtr && !SeenAttachPtr) {
8133 SeenAttachPtr = I->getAssociatedExpression() == AttachPtrExpr;
8134 continue;
8135 }
8136
8137 // After finding the attach pointer, skip binary-ops, to skip past
8138 // expressions like (p + 10), for a map like map(*(p + 10)), where p is
8139 // the attach-ptr.
8140 if (HasAttachPtr && !SeenFirstNonBinOpExprAfterAttachPtr) {
8141 const auto *BO = dyn_cast<BinaryOperator>(I->getAssociatedExpression());
8142 if (BO)
8143 continue;
8144
8145 // Found the first non-binary-operator component after attach
8146 SeenFirstNonBinOpExprAfterAttachPtr = true;
8147 BP = AttachPteeBaseAddr;
8148 }
8149
8150 // If the current component is member of a struct (parent struct) mark it.
8151 if (!EncounteredME) {
8152 EncounteredME = dyn_cast<MemberExpr>(I->getAssociatedExpression());
8153 // If we encounter a PTR_AND_OBJ entry from now on it should be marked
8154 // as MEMBER_OF the parent struct.
8155 if (EncounteredME) {
8156 ShouldBeMemberOf = true;
8157 // Do not emit as complex pointer if this is actually not array-like
8158 // expression.
8159 if (FirstPointerInComplexData) {
8160 QualType Ty = std::prev(I)
8161 ->getAssociatedDeclaration()
8162 ->getType()
8163 .getNonReferenceType();
8164 BP = CGF.EmitLoadOfPointer(BP, Ty->castAs<PointerType>());
8165 FirstPointerInComplexData = false;
8166 }
8167 }
8168 }
8169
8170 auto Next = std::next(I);
8171
8172 // We need to generate the addresses and sizes if this is the last
8173 // component, if the component is a pointer or if it is an array section
8174 // whose length can't be proved to be one. If this is a pointer, it
8175 // becomes the base address for the following components.
8176
8177 // A final array section, is one whose length can't be proved to be one.
8178 // If the map item is non-contiguous then we don't treat any array section
8179 // as final array section.
8180 bool IsFinalArraySection =
8181 !IsNonContiguous &&
8182 isFinalArraySectionExpression(I->getAssociatedExpression());
8183
8184 // If we have a declaration for the mapping use that, otherwise use
8185 // the base declaration of the map clause.
8186 const ValueDecl *MapDecl = (I->getAssociatedDeclaration())
8187 ? I->getAssociatedDeclaration()
8188 : BaseDecl;
8189 MapExpr = (I->getAssociatedExpression()) ? I->getAssociatedExpression()
8190 : MapExpr;
8191
8192 // Get information on whether the element is a pointer. Have to do a
8193 // special treatment for array sections given that they are built-in
8194 // types.
8195 const auto *OASE =
8196 dyn_cast<ArraySectionExpr>(I->getAssociatedExpression());
8197 const auto *OAShE =
8198 dyn_cast<OMPArrayShapingExpr>(I->getAssociatedExpression());
8199 const auto *UO = dyn_cast<UnaryOperator>(I->getAssociatedExpression());
8200 const auto *BO = dyn_cast<BinaryOperator>(I->getAssociatedExpression());
8201 bool IsPointer =
8202 OAShE ||
8205 ->isAnyPointerType()) ||
8206 I->getAssociatedExpression()->getType()->isAnyPointerType();
8207 bool IsMemberReference = isa<MemberExpr>(I->getAssociatedExpression()) &&
8208 MapDecl &&
8209 MapDecl->getType()->isLValueReferenceType();
8210 bool IsNonDerefPointer = IsPointer &&
8211 !(UO && UO->getOpcode() != UO_Deref) && !BO &&
8212 !IsNonContiguous;
8213
8214 if (OASE)
8215 ++DimSize;
8216
8217 if (Next == CE || IsMemberReference || IsNonDerefPointer ||
8218 IsFinalArraySection) {
8219 // If this is not the last component, we expect the pointer to be
8220 // associated with an array expression or member expression.
8221 assert((Next == CE ||
8222 isa<MemberExpr>(Next->getAssociatedExpression()) ||
8223 isa<ArraySubscriptExpr>(Next->getAssociatedExpression()) ||
8224 isa<ArraySectionExpr>(Next->getAssociatedExpression()) ||
8225 isa<OMPArrayShapingExpr>(Next->getAssociatedExpression()) ||
8226 isa<UnaryOperator>(Next->getAssociatedExpression()) ||
8227 isa<BinaryOperator>(Next->getAssociatedExpression())) &&
8228 "Unexpected expression");
8229
8231 Address LowestElem = Address::invalid();
8232 auto &&EmitMemberExprBase = [](CodeGenFunction &CGF,
8233 const MemberExpr *E) {
8234 const Expr *BaseExpr = E->getBase();
8235 // If this is s.x, emit s as an lvalue. If it is s->x, emit s as a
8236 // scalar.
8237 LValue BaseLV;
8238 if (E->isArrow()) {
8239 LValueBaseInfo BaseInfo;
8240 TBAAAccessInfo TBAAInfo;
8241 Address Addr =
8242 CGF.EmitPointerWithAlignment(BaseExpr, &BaseInfo, &TBAAInfo);
8243 QualType PtrTy = BaseExpr->getType()->getPointeeType();
8244 BaseLV = CGF.MakeAddrLValue(Addr, PtrTy, BaseInfo, TBAAInfo);
8245 } else {
8246 BaseLV = CGF.EmitOMPSharedLValue(BaseExpr);
8247 }
8248 return BaseLV;
8249 };
8250 if (OAShE) {
8251 LowestElem = LB =
8252 Address(CGF.EmitScalarExpr(OAShE->getBase()),
8254 OAShE->getBase()->getType()->getPointeeType()),
8256 OAShE->getBase()->getType()));
8257 } else if (IsMemberReference) {
8258 const auto *ME = cast<MemberExpr>(I->getAssociatedExpression());
8259 LValue BaseLVal = EmitMemberExprBase(CGF, ME);
8260 LowestElem = CGF.EmitLValueForFieldInitialization(
8261 BaseLVal, cast<FieldDecl>(MapDecl))
8262 .getAddress();
8263 LB = CGF.EmitLoadOfReferenceLValue(LowestElem, MapDecl->getType())
8264 .getAddress();
8265 } else {
8266 LowestElem = LB =
8267 CGF.EmitOMPSharedLValue(I->getAssociatedExpression())
8268 .getAddress();
8269 }
8270
8271 // Save the final LowestElem, to use it as the pointee in attach maps,
8272 // if emitted.
8273 if (Next == CE)
8274 FinalLowestElem = LowestElem;
8275
8276 // If this component is a pointer inside the base struct then we don't
8277 // need to create any entry for it - it will be combined with the object
8278 // it is pointing to into a single PTR_AND_OBJ entry.
8279 bool IsMemberPointerOrAddr =
8280 EncounteredME &&
8281 (((IsPointer || ForDeviceAddr) &&
8282 I->getAssociatedExpression() == EncounteredME) ||
8283 (IsPrevMemberReference && !IsPointer) ||
8284 (IsMemberReference && Next != CE &&
8285 !Next->getAssociatedExpression()->getType()->isPointerType()));
8286 if (!OverlappedElements.empty() && Next == CE) {
8287 // Handle base element with the info for overlapped elements.
8288 assert(!PartialStruct.Base.isValid() && "The base element is set.");
8289 assert(!IsPointer &&
8290 "Unexpected base element with the pointer type.");
8291 // Mark the whole struct as the struct that requires allocation on the
8292 // device.
8293 PartialStruct.LowestElem = {0, LowestElem};
8294 CharUnits TypeSize = CGF.getContext().getTypeSizeInChars(
8295 I->getAssociatedExpression()->getType());
8298 LowestElem, CGF.VoidPtrTy, CGF.Int8Ty),
8299 TypeSize.getQuantity() - 1);
8300 PartialStruct.HighestElem = {
8301 std::numeric_limits<decltype(
8302 PartialStruct.HighestElem.first)>::max(),
8303 HB};
8304 PartialStruct.Base = BP;
8305 PartialStruct.LB = LB;
8306 assert(
8307 PartialStruct.PreliminaryMapData.BasePointers.empty() &&
8308 "Overlapped elements must be used only once for the variable.");
8309 std::swap(PartialStruct.PreliminaryMapData, CombinedInfo);
8310 // Emit data for non-overlapped data.
8311 OpenMPOffloadMappingFlags Flags =
8312 OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF |
8313 getMapTypeBits(MapType, MapModifiers, MotionModifiers, IsImplicit,
8314 /*AddPtrFlag=*/false,
8315 /*AddIsTargetParamFlag=*/false, IsNonContiguous);
8316 CopyOverlappedEntryGaps CopyGaps(CGF, CombinedInfo, Flags, MapDecl,
8317 MapExpr, BP, LB, IsNonContiguous,
8318 DimSize);
8319 // Do bitcopy of all non-overlapped structure elements.
8321 Component : OverlappedElements) {
8322 for (const OMPClauseMappableExprCommon::MappableComponent &MC :
8323 Component) {
8324 if (const ValueDecl *VD = MC.getAssociatedDeclaration()) {
8325 if (const auto *FD = dyn_cast<FieldDecl>(VD)) {
8326 CopyGaps.processField(MC, FD, EmitMemberExprBase);
8327 }
8328 }
8329 }
8330 }
8331 CopyGaps.copyUntilEnd(HB);
8332 break;
8333 }
8334 llvm::Value *Size = getExprTypeSize(I->getAssociatedExpression());
8335 // Skip adding an entry in the CurInfo of this combined entry if the
8336 // whole struct is currently being mapped. The struct needs to be added
8337 // in the first position before any data internal to the struct is being
8338 // mapped.
8339 // Skip adding an entry in the CurInfo of this combined entry if the
8340 // PartialStruct.PreliminaryMapData.BasePointers has been mapped.
8341 if ((!IsMemberPointerOrAddr && !IsPartialMapped) ||
8342 (Next == CE && MapType != OMPC_MAP_unknown)) {
8343 if (!IsMappingWholeStruct) {
8344 CombinedInfo.Exprs.emplace_back(MapDecl, MapExpr);
8345 CombinedInfo.BasePointers.push_back(BP.emitRawPointer(CGF));
8346 CombinedInfo.DevicePtrDecls.push_back(nullptr);
8347 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
8348 CombinedInfo.Pointers.push_back(LB.emitRawPointer(CGF));
8349 CombinedInfo.Sizes.push_back(CGF.Builder.CreateIntCast(
8350 Size, CGF.Int64Ty, /*isSigned=*/true));
8351 CombinedInfo.NonContigInfo.Dims.push_back(IsNonContiguous ? DimSize
8352 : 1);
8353 } else {
8354 StructBaseCombinedInfo.Exprs.emplace_back(MapDecl, MapExpr);
8355 StructBaseCombinedInfo.BasePointers.push_back(
8356 BP.emitRawPointer(CGF));
8357 StructBaseCombinedInfo.DevicePtrDecls.push_back(nullptr);
8358 StructBaseCombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
8359 StructBaseCombinedInfo.Pointers.push_back(LB.emitRawPointer(CGF));
8360 StructBaseCombinedInfo.Sizes.push_back(CGF.Builder.CreateIntCast(
8361 Size, CGF.Int64Ty, /*isSigned=*/true));
8362 StructBaseCombinedInfo.NonContigInfo.Dims.push_back(
8363 IsNonContiguous ? DimSize : 1);
8364 }
8365
8366 // If Mapper is valid, the last component inherits the mapper.
8367 bool HasMapper = Mapper && Next == CE;
8368 if (!IsMappingWholeStruct)
8369 CombinedInfo.Mappers.push_back(HasMapper ? Mapper : nullptr);
8370 else
8371 StructBaseCombinedInfo.Mappers.push_back(HasMapper ? Mapper
8372 : nullptr);
8373
8374 // We need to add a pointer flag for each map that comes from the
8375 // same expression except for the first one. We also need to signal
8376 // this map is the first one that relates with the current capture
8377 // (there is a set of entries for each capture).
8378 OpenMPOffloadMappingFlags Flags = getMapTypeBits(
8379 MapType, MapModifiers, MotionModifiers, IsImplicit,
8380 !IsExpressionFirstInfo || RequiresReference ||
8381 FirstPointerInComplexData || IsMemberReference,
8382 IsCaptureFirstInfo && !RequiresReference, IsNonContiguous);
8383
8384 if (!IsExpressionFirstInfo || IsMemberReference) {
8385 // If we have a PTR_AND_OBJ pair where the OBJ is a pointer as well,
8386 // then we reset the TO/FROM/ALWAYS/DELETE/CLOSE flags.
8387 if (IsPointer || (IsMemberReference && Next != CE))
8388 Flags &= ~(OpenMPOffloadMappingFlags::OMP_MAP_TO |
8389 OpenMPOffloadMappingFlags::OMP_MAP_FROM |
8390 OpenMPOffloadMappingFlags::OMP_MAP_ALWAYS |
8391 OpenMPOffloadMappingFlags::OMP_MAP_DELETE |
8392 OpenMPOffloadMappingFlags::OMP_MAP_CLOSE);
8393
8394 if (ShouldBeMemberOf) {
8395 // Set placeholder value MEMBER_OF=FFFF to indicate that the flag
8396 // should be later updated with the correct value of MEMBER_OF.
8397 Flags |= OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF;
8398 // From now on, all subsequent PTR_AND_OBJ entries should not be
8399 // marked as MEMBER_OF.
8400 ShouldBeMemberOf = false;
8401 }
8402 }
8403
8404 if (!IsMappingWholeStruct) {
8405 CombinedInfo.Types.push_back(Flags);
8406 // HasAttachPtr marks pointee entries, which have a base attach-ptr.
8407 CombinedInfo.HasAttachPtr.push_back(HasAttachPtr);
8408 } else {
8409 StructBaseCombinedInfo.Types.push_back(Flags);
8410 StructBaseCombinedInfo.HasAttachPtr.push_back(HasAttachPtr);
8411 }
8412 }
8413
8414 // If we have encountered a member expression so far, keep track of the
8415 // mapped member. If the parent is "*this", then the value declaration
8416 // is nullptr.
8417 if (EncounteredME) {
8418 const auto *FD = cast<FieldDecl>(EncounteredME->getMemberDecl());
8419 unsigned FieldIndex = FD->getFieldIndex();
8420
8421 // Update info about the lowest and highest elements for this struct
8422 if (!PartialStruct.Base.isValid()) {
8423 PartialStruct.LowestElem = {FieldIndex, LowestElem};
8424 if (IsFinalArraySection && OASE) {
8425 Address HB =
8426 CGF.EmitArraySectionExpr(OASE, /*IsLowerBound=*/false)
8427 .getAddress();
8428 PartialStruct.HighestElem = {FieldIndex, HB};
8429 } else {
8430 PartialStruct.HighestElem = {FieldIndex, LowestElem};
8431 }
8432 PartialStruct.Base = BP;
8433 PartialStruct.LB = BP;
8434 } else if (FieldIndex < PartialStruct.LowestElem.first) {
8435 PartialStruct.LowestElem = {FieldIndex, LowestElem};
8436 } else if (FieldIndex > PartialStruct.HighestElem.first) {
8437 if (IsFinalArraySection && OASE) {
8438 Address HB =
8439 CGF.EmitArraySectionExpr(OASE, /*IsLowerBound=*/false)
8440 .getAddress();
8441 PartialStruct.HighestElem = {FieldIndex, HB};
8442 } else {
8443 PartialStruct.HighestElem = {FieldIndex, LowestElem};
8444 }
8445 }
8446 }
8447
8448 // Need to emit combined struct for array sections.
8449 if (IsFinalArraySection || IsNonContiguous)
8450 PartialStruct.IsArraySection = true;
8451
8452 // If we have a final array section, we are done with this expression.
8453 if (IsFinalArraySection)
8454 break;
8455
8456 // The pointer becomes the base for the next element.
8457 if (Next != CE)
8458 BP = IsMemberReference ? LowestElem : LB;
8459 if (!IsPartialMapped)
8460 IsExpressionFirstInfo = false;
8461 IsCaptureFirstInfo = false;
8462 FirstPointerInComplexData = false;
8463 IsPrevMemberReference = IsMemberReference;
8464 } else if (FirstPointerInComplexData) {
8465 QualType Ty = Components.rbegin()
8466 ->getAssociatedDeclaration()
8467 ->getType()
8468 .getNonReferenceType();
8469 BP = CGF.EmitLoadOfPointer(BP, Ty->castAs<PointerType>());
8470 FirstPointerInComplexData = false;
8471 }
8472 }
8473 // If ran into the whole component - allocate the space for the whole
8474 // record.
8475 if (!EncounteredME)
8476 PartialStruct.HasCompleteRecord = true;
8477
8478 // Populate ATTACH information for later processing by emitAttachEntry.
8479 if (shouldEmitAttachEntry(AttachPtrExpr, BaseDecl, CGF, CurDir)) {
8480 AttachInfo.AttachPtrAddr = AttachPtrAddr;
8481 AttachInfo.AttachPteeAddr = FinalLowestElem;
8482 AttachInfo.AttachPtrDecl = BaseDecl;
8483 AttachInfo.AttachMapExpr = MapExpr;
8484 }
8485
8486 if (!IsNonContiguous)
8487 return;
8488
8489 const ASTContext &Context = CGF.getContext();
8490
8491 // For supporting stride in array section, we need to initialize the first
8492 // dimension size as 1, first offset as 0, and first count as 1
8493 MapValuesArrayTy CurOffsets = {llvm::ConstantInt::get(CGF.CGM.Int64Ty, 0)};
8494 MapValuesArrayTy CurCounts;
8495 MapValuesArrayTy CurStrides = {llvm::ConstantInt::get(CGF.CGM.Int64Ty, 1)};
8496 MapValuesArrayTy DimSizes{llvm::ConstantInt::get(CGF.CGM.Int64Ty, 1)};
8497 uint64_t ElementTypeSize;
8498
8499 // Collect Size information for each dimension and get the element size as
8500 // the first Stride. For example, for `int arr[10][10]`, the DimSizes
8501 // should be [10, 10] and the first stride is 4 btyes.
8502 for (const OMPClauseMappableExprCommon::MappableComponent &Component :
8503 Components) {
8504 const Expr *AssocExpr = Component.getAssociatedExpression();
8505 const auto *OASE = dyn_cast<ArraySectionExpr>(AssocExpr);
8506
8507 if (!OASE)
8508 continue;
8509
8510 QualType Ty = ArraySectionExpr::getBaseOriginalType(OASE->getBase());
8511 auto *CAT = Context.getAsConstantArrayType(Ty);
8512 auto *VAT = Context.getAsVariableArrayType(Ty);
8513
8514 // We need all the dimension size except for the last dimension.
8515 assert((VAT || CAT || &Component == &*Components.begin()) &&
8516 "Should be either ConstantArray or VariableArray if not the "
8517 "first Component");
8518
8519 // Get element size if CurCounts is empty.
8520 if (CurCounts.empty()) {
8521 const Type *ElementType = nullptr;
8522 if (CAT)
8523 ElementType = CAT->getElementType().getTypePtr();
8524 else if (VAT)
8525 ElementType = VAT->getElementType().getTypePtr();
8526 else if (&Component == &*Components.begin()) {
8527 // If the base is a raw pointer (e.g. T *data with data[a:b:c]),
8528 // there was no earlier CAT/VAT/array handling to establish
8529 // ElementType. Capture the pointee type now so that subsequent
8530 // components (offset/length/stride) have a concrete element type to
8531 // work with. This makes pointer-backed sections behave consistently
8532 // with CAT/VAT/array bases.
8533 if (const auto *PtrType = Ty->getAs<PointerType>())
8534 ElementType = PtrType->getPointeeType().getTypePtr();
8535 } else {
8536 // Any component after the first should never have a raw pointer type;
8537 // by this point. ElementType must already be known (set above or in
8538 // prior array / CAT / VAT handling).
8539 assert(!Ty->isPointerType() &&
8540 "Non-first components should not be raw pointers");
8541 }
8542
8543 // At this stage, if ElementType was a base pointer and we are in the
8544 // first iteration, it has been computed.
8545 if (ElementType) {
8546 // For the case that having pointer as base, we need to remove one
8547 // level of indirection.
8548 if (&Component != &*Components.begin())
8549 ElementType = ElementType->getPointeeOrArrayElementType();
8550 ElementTypeSize =
8551 Context.getTypeSizeInChars(ElementType).getQuantity();
8552 CurCounts.push_back(
8553 llvm::ConstantInt::get(CGF.Int64Ty, ElementTypeSize));
8554 }
8555 }
8556 // Get dimension value except for the last dimension since we don't need
8557 // it.
8558 if (DimSizes.size() < Components.size() - 1) {
8559 if (CAT)
8560 DimSizes.push_back(
8561 llvm::ConstantInt::get(CGF.Int64Ty, CAT->getZExtSize()));
8562 else if (VAT)
8563 DimSizes.push_back(CGF.Builder.CreateIntCast(
8564 CGF.EmitScalarExpr(VAT->getSizeExpr()), CGF.Int64Ty,
8565 /*IsSigned=*/false));
8566 }
8567 }
8568
8569 // Skip the dummy dimension since we have already have its information.
8570 auto *DI = DimSizes.begin() + 1;
8571 // Product of dimension.
8572 llvm::Value *DimProd =
8573 llvm::ConstantInt::get(CGF.CGM.Int64Ty, ElementTypeSize);
8574
8575 // Collect info for non-contiguous. Notice that offset, count, and stride
8576 // are only meaningful for array-section, so we insert a null for anything
8577 // other than array-section.
8578 // Also, the size of offset, count, and stride are not the same as
8579 // pointers, base_pointers, sizes, or dims. Instead, the size of offset,
8580 // count, and stride are the same as the number of non-contiguous
8581 // declaration in target update to/from clause.
8582 for (const OMPClauseMappableExprCommon::MappableComponent &Component :
8583 Components) {
8584 const Expr *AssocExpr = Component.getAssociatedExpression();
8585
8586 if (const auto *AE = dyn_cast<ArraySubscriptExpr>(AssocExpr)) {
8587 llvm::Value *Offset = CGF.Builder.CreateIntCast(
8588 CGF.EmitScalarExpr(AE->getIdx()), CGF.Int64Ty,
8589 /*isSigned=*/false);
8590 CurOffsets.push_back(Offset);
8591 CurCounts.push_back(llvm::ConstantInt::get(CGF.Int64Ty, /*V=*/1));
8592 CurStrides.push_back(CurStrides.back());
8593 continue;
8594 }
8595
8596 const auto *OASE = dyn_cast<ArraySectionExpr>(AssocExpr);
8597
8598 if (!OASE)
8599 continue;
8600
8601 // Offset
8602 const Expr *OffsetExpr = OASE->getLowerBound();
8603 llvm::Value *Offset = nullptr;
8604 if (!OffsetExpr) {
8605 // If offset is absent, then we just set it to zero.
8606 Offset = llvm::ConstantInt::get(CGF.Int64Ty, 0);
8607 } else {
8608 Offset = CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(OffsetExpr),
8609 CGF.Int64Ty,
8610 /*isSigned=*/false);
8611 }
8612
8613 // Count
8614 const Expr *CountExpr = OASE->getLength();
8615 llvm::Value *Count = nullptr;
8616 if (!CountExpr) {
8617 // In Clang, once a high dimension is an array section, we construct all
8618 // the lower dimension as array section, however, for case like
8619 // arr[0:2][2], Clang construct the inner dimension as an array section
8620 // but it actually is not in an array section form according to spec.
8621 if (!OASE->getColonLocFirst().isValid() &&
8622 !OASE->getColonLocSecond().isValid()) {
8623 Count = llvm::ConstantInt::get(CGF.Int64Ty, 1);
8624 } else {
8625 // OpenMP 5.0, 2.1.5 Array Sections, Description.
8626 // When the length is absent it defaults to ⌈(size −
8627 // lower-bound)/stride⌉, where size is the size of the array
8628 // dimension.
8629 const Expr *StrideExpr = OASE->getStride();
8630 llvm::Value *Stride =
8631 StrideExpr
8632 ? CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(StrideExpr),
8633 CGF.Int64Ty, /*isSigned=*/false)
8634 : nullptr;
8635 if (Stride)
8636 Count = CGF.Builder.CreateUDiv(
8637 CGF.Builder.CreateNUWSub(*DI, Offset), Stride);
8638 else
8639 Count = CGF.Builder.CreateNUWSub(*DI, Offset);
8640 }
8641 } else {
8642 Count = CGF.EmitScalarExpr(CountExpr);
8643 }
8644 Count = CGF.Builder.CreateIntCast(Count, CGF.Int64Ty, /*isSigned=*/false);
8645 CurCounts.push_back(Count);
8646
8647 // Stride_n' = Stride_n * (D_0 * D_1 ... * D_n-1) * Unit size
8648 // Offset_n' = Offset_n * (D_0 * D_1 ... * D_n-1) * Unit size
8649 // Take `int arr[5][5][5]` and `arr[0:2:2][1:2:1][0:2:2]` as an example:
8650 // Offset Count Stride
8651 // D0 0 4 1 (int) <- dummy dimension
8652 // D1 0 2 8 (2 * (1) * 4)
8653 // D2 100 2 20 (1 * (1 * 5) * 4)
8654 // D3 0 2 200 (2 * (1 * 5 * 4) * 4)
8655 const Expr *StrideExpr = OASE->getStride();
8656 llvm::Value *Stride =
8657 StrideExpr
8658 ? CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(StrideExpr),
8659 CGF.Int64Ty, /*isSigned=*/false)
8660 : nullptr;
8661 DimProd = CGF.Builder.CreateNUWMul(DimProd, *(DI - 1));
8662 if (Stride)
8663 CurStrides.push_back(CGF.Builder.CreateNUWMul(DimProd, Stride));
8664 else
8665 CurStrides.push_back(DimProd);
8666
8667 Offset = CGF.Builder.CreateNUWMul(DimProd, Offset);
8668 CurOffsets.push_back(Offset);
8669
8670 if (DI != DimSizes.end())
8671 ++DI;
8672 }
8673
8674 CombinedInfo.NonContigInfo.Offsets.push_back(CurOffsets);
8675 CombinedInfo.NonContigInfo.Counts.push_back(CurCounts);
8676 CombinedInfo.NonContigInfo.Strides.push_back(CurStrides);
8677 }
8678
8679 /// Return the adjusted map modifiers if the declaration a capture refers to
8680 /// appears in a first-private clause. This is expected to be used only with
8681 /// directives that start with 'target'.
8682 OpenMPOffloadMappingFlags
8683 getMapModifiersForPrivateClauses(const CapturedStmt::Capture &Cap) const {
8684 assert(Cap.capturesVariable() && "Expected capture by reference only!");
8685
8686 // A first private variable captured by reference will use only the
8687 // 'private ptr' and 'map to' flag. Return the right flags if the captured
8688 // declaration is known as first-private in this handler.
8689 if (FirstPrivateDecls.count(Cap.getCapturedVar())) {
8690 if (Cap.getCapturedVar()->getType()->isAnyPointerType())
8691 return OpenMPOffloadMappingFlags::OMP_MAP_TO |
8692 OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ;
8693 return OpenMPOffloadMappingFlags::OMP_MAP_PRIVATE |
8694 OpenMPOffloadMappingFlags::OMP_MAP_TO;
8695 }
8696 auto I = LambdasMap.find(Cap.getCapturedVar()->getCanonicalDecl());
8697 if (I != LambdasMap.end())
8698 // for map(to: lambda): using user specified map type.
8699 return getMapTypeBits(
8700 I->getSecond()->getMapType(), I->getSecond()->getMapTypeModifiers(),
8701 /*MotionModifiers=*/{}, I->getSecond()->isImplicit(),
8702 /*AddPtrFlag=*/false,
8703 /*AddIsTargetParamFlag=*/false,
8704 /*isNonContiguous=*/false);
8705 return OpenMPOffloadMappingFlags::OMP_MAP_TO |
8706 OpenMPOffloadMappingFlags::OMP_MAP_FROM;
8707 }
8708
8709 void getPlainLayout(const CXXRecordDecl *RD,
8710 llvm::SmallVectorImpl<const FieldDecl *> &Layout,
8711 bool AsBase) const {
8712 const CGRecordLayout &RL = CGF.getTypes().getCGRecordLayout(RD);
8713
8714 llvm::StructType *St =
8715 AsBase ? RL.getBaseSubobjectLLVMType() : RL.getLLVMType();
8716
8717 unsigned NumElements = St->getNumElements();
8718 llvm::SmallVector<
8719 llvm::PointerUnion<const CXXRecordDecl *, const FieldDecl *>, 4>
8720 RecordLayout(NumElements);
8721
8722 // Fill bases.
8723 for (const auto &I : RD->bases()) {
8724 if (I.isVirtual())
8725 continue;
8726
8727 QualType BaseTy = I.getType();
8728 const auto *Base = BaseTy->getAsCXXRecordDecl();
8729 // Ignore empty bases.
8730 if (isEmptyRecordForLayout(CGF.getContext(), BaseTy) ||
8731 CGF.getContext()
8732 .getASTRecordLayout(Base)
8734 .isZero())
8735 continue;
8736
8737 unsigned FieldIndex = RL.getNonVirtualBaseLLVMFieldNo(Base);
8738 RecordLayout[FieldIndex] = Base;
8739 }
8740 // Fill in virtual bases.
8741 for (const auto &I : RD->vbases()) {
8742 QualType BaseTy = I.getType();
8743 // Ignore empty bases.
8744 if (isEmptyRecordForLayout(CGF.getContext(), BaseTy))
8745 continue;
8746
8747 const auto *Base = BaseTy->getAsCXXRecordDecl();
8748 unsigned FieldIndex = RL.getVirtualBaseIndex(Base);
8749 if (RecordLayout[FieldIndex])
8750 continue;
8751 RecordLayout[FieldIndex] = Base;
8752 }
8753 // Fill in all the fields.
8754 assert(!RD->isUnion() && "Unexpected union.");
8755 for (const auto *Field : RD->fields()) {
8756 // Fill in non-bitfields. (Bitfields always use a zero pattern, which we
8757 // will fill in later.)
8758 if (!Field->isBitField() &&
8759 !isEmptyFieldForLayout(CGF.getContext(), Field)) {
8760 unsigned FieldIndex = RL.getLLVMFieldNo(Field);
8761 RecordLayout[FieldIndex] = Field;
8762 }
8763 }
8764 for (const llvm::PointerUnion<const CXXRecordDecl *, const FieldDecl *>
8765 &Data : RecordLayout) {
8766 if (Data.isNull())
8767 continue;
8768 if (const auto *Base = dyn_cast<const CXXRecordDecl *>(Data))
8769 getPlainLayout(Base, Layout, /*AsBase=*/true);
8770 else
8771 Layout.push_back(cast<const FieldDecl *>(Data));
8772 }
8773 }
8774
8775 /// Returns the address corresponding to \p PointerExpr.
8776 static Address getAttachPtrAddr(const Expr *PointerExpr,
8777 CodeGenFunction &CGF) {
8778 assert(PointerExpr && "Cannot get addr from null attach-ptr expr");
8779 Address AttachPtrAddr = Address::invalid();
8780
8781 if (auto *DRE = dyn_cast<DeclRefExpr>(PointerExpr)) {
8782 // If the pointer is a variable, we can use its address directly.
8783 AttachPtrAddr = CGF.EmitLValue(DRE).getAddress();
8784 } else if (auto *OASE = dyn_cast<ArraySectionExpr>(PointerExpr)) {
8785 AttachPtrAddr =
8786 CGF.EmitArraySectionExpr(OASE, /*IsLowerBound=*/true).getAddress();
8787 } else if (auto *ASE = dyn_cast<ArraySubscriptExpr>(PointerExpr)) {
8788 AttachPtrAddr = CGF.EmitLValue(ASE).getAddress();
8789 } else if (auto *ME = dyn_cast<MemberExpr>(PointerExpr)) {
8790 AttachPtrAddr = CGF.EmitMemberExpr(ME).getAddress();
8791 } else if (auto *UO = dyn_cast<UnaryOperator>(PointerExpr)) {
8792 assert(UO->getOpcode() == UO_Deref &&
8793 "Unexpected unary-operator on attach-ptr-expr");
8794 AttachPtrAddr = CGF.EmitLValue(UO).getAddress();
8795 }
8796 assert(AttachPtrAddr.isValid() &&
8797 "Failed to get address for attach pointer expression");
8798 return AttachPtrAddr;
8799 }
8800
8801 /// Get the address of the attach pointer, and a load from it, to get the
8802 /// pointee base address.
8803 /// \return A pair containing AttachPtrAddr and AttachPteeBaseAddr. The pair
8804 /// contains invalid addresses if \p AttachPtrExpr is null.
8805 static std::pair<Address, Address>
8806 getAttachPtrAddrAndPteeBaseAddr(const Expr *AttachPtrExpr,
8807 CodeGenFunction &CGF) {
8808
8809 if (!AttachPtrExpr)
8810 return {Address::invalid(), Address::invalid()};
8811
8812 Address AttachPtrAddr = getAttachPtrAddr(AttachPtrExpr, CGF);
8813 assert(AttachPtrAddr.isValid() && "Invalid attach pointer addr");
8814
8815 QualType AttachPtrType =
8818
8819 Address AttachPteeBaseAddr = CGF.EmitLoadOfPointer(
8820 AttachPtrAddr, AttachPtrType->castAs<PointerType>());
8821 assert(AttachPteeBaseAddr.isValid() && "Invalid attach pointee base addr");
8822
8823 return {AttachPtrAddr, AttachPteeBaseAddr};
8824 }
8825
8826 /// Returns whether an attach entry should be emitted for a map on
8827 /// \p MapBaseDecl on the directive \p CurDir.
8828 static bool
8829 shouldEmitAttachEntry(const Expr *PointerExpr, const ValueDecl *MapBaseDecl,
8830 CodeGenFunction &CGF,
8831 llvm::PointerUnion<const OMPExecutableDirective *,
8832 const OMPDeclareMapperDecl *>
8833 CurDir) {
8834 if (!PointerExpr)
8835 return false;
8836
8837 // Pointer attachment is needed at map-entering time or for declare
8838 // mappers.
8839 return isa<const OMPDeclareMapperDecl *>(CurDir) ||
8842 ->getDirectiveKind());
8843 }
8844
8845 /// Computes the attach-ptr expr for \p Components, and updates various maps
8846 /// with the information.
8847 /// It internally calls OMPClauseMappableExprCommon::findAttachPtrExpr()
8848 /// with the OpenMPDirectiveKind extracted from \p CurDir.
8849 /// It updates AttachPtrComputationOrderMap, AttachPtrComponentDepthMap, and
8850 /// AttachPtrExprMap.
8851 void collectAttachPtrExprInfo(
8853 llvm::PointerUnion<const OMPExecutableDirective *,
8854 const OMPDeclareMapperDecl *>
8855 CurDir) {
8856
8857 OpenMPDirectiveKind CurDirectiveID =
8859 ? OMPD_declare_mapper
8860 : cast<const OMPExecutableDirective *>(CurDir)->getDirectiveKind();
8861
8862 const auto &[AttachPtrExpr, Depth] =
8864 CurDirectiveID);
8865
8866 AttachPtrComputationOrderMap.try_emplace(
8867 AttachPtrExpr, AttachPtrComputationOrderMap.size());
8868 AttachPtrComponentDepthMap.try_emplace(AttachPtrExpr, Depth);
8869 AttachPtrExprMap.try_emplace(Components, AttachPtrExpr);
8870 }
8871
8872 /// Generate all the base pointers, section pointers, sizes, map types, and
8873 /// mappers for the extracted mappable expressions (all included in \a
8874 /// CombinedInfo). Also, for each item that relates with a device pointer, a
8875 /// pair of the relevant declaration and index where it occurs is appended to
8876 /// the device pointers info array.
8877 void generateAllInfoForClauses(
8878 ArrayRef<const OMPClause *> Clauses, MapCombinedInfoTy &CombinedInfo,
8879 llvm::OpenMPIRBuilder &OMPBuilder,
8880 const llvm::DenseSet<CanonicalDeclPtr<const Decl>> &SkipVarSet =
8881 llvm::DenseSet<CanonicalDeclPtr<const Decl>>()) const {
8882 // We have to process the component lists that relate with the same
8883 // declaration in a single chunk so that we can generate the map flags
8884 // correctly. Therefore, we organize all lists in a map.
8885 enum MapKind { Present, Allocs, Other, Total };
8886 llvm::MapVector<CanonicalDeclPtr<const Decl>,
8887 SmallVector<SmallVector<MapInfo, 8>, 4>>
8888 Info;
8889
8890 // Helper function to fill the information map for the different supported
8891 // clauses.
8892 auto &&InfoGen =
8893 [&Info, &SkipVarSet](
8894 const ValueDecl *D, MapKind Kind,
8896 OpenMPMapClauseKind MapType,
8897 ArrayRef<OpenMPMapModifierKind> MapModifiers,
8898 ArrayRef<OpenMPMotionModifierKind> MotionModifiers,
8899 bool ReturnDevicePointer, bool IsImplicit, const ValueDecl *Mapper,
8900 const Expr *VarRef = nullptr, bool ForDeviceAddr = false) {
8901 if (SkipVarSet.contains(D))
8902 return;
8903 auto It = Info.try_emplace(D, Total).first;
8904 It->second[Kind].emplace_back(
8905 L, MapType, MapModifiers, MotionModifiers, ReturnDevicePointer,
8906 IsImplicit, Mapper, VarRef, ForDeviceAddr);
8907 };
8908
8909 for (const auto *Cl : Clauses) {
8910 const auto *C = dyn_cast<OMPMapClause>(Cl);
8911 if (!C)
8912 continue;
8913 MapKind Kind = Other;
8914 if (llvm::is_contained(C->getMapTypeModifiers(),
8915 OMPC_MAP_MODIFIER_present))
8916 Kind = Present;
8917 else if (C->getMapType() == OMPC_MAP_alloc)
8918 Kind = Allocs;
8919 const auto *EI = C->getVarRefs().begin();
8920 for (const auto L : C->component_lists()) {
8921 const Expr *E = (C->getMapLoc().isValid()) ? *EI : nullptr;
8922 InfoGen(std::get<0>(L), Kind, std::get<1>(L), C->getMapType(),
8923 C->getMapTypeModifiers(), {},
8924 /*ReturnDevicePointer=*/false, C->isImplicit(), std::get<2>(L),
8925 E);
8926 ++EI;
8927 }
8928 }
8929 for (const auto *Cl : Clauses) {
8930 const auto *C = dyn_cast<OMPToClause>(Cl);
8931 if (!C)
8932 continue;
8933 MapKind Kind = Other;
8934 if (llvm::is_contained(C->getMotionModifiers(),
8935 OMPC_MOTION_MODIFIER_present))
8936 Kind = Present;
8937 if (llvm::is_contained(C->getMotionModifiers(),
8938 OMPC_MOTION_MODIFIER_iterator)) {
8939 if (auto *IteratorExpr = dyn_cast<OMPIteratorExpr>(
8940 C->getIteratorModifier()->IgnoreParenImpCasts())) {
8941 const auto *VD = cast<VarDecl>(IteratorExpr->getIteratorDecl(0));
8942 CGF.EmitVarDecl(*VD);
8943 }
8944 }
8945
8946 const auto *EI = C->getVarRefs().begin();
8947 for (const auto L : C->component_lists()) {
8948 InfoGen(std::get<0>(L), Kind, std::get<1>(L), OMPC_MAP_to, {},
8949 C->getMotionModifiers(), /*ReturnDevicePointer=*/false,
8950 C->isImplicit(), std::get<2>(L), *EI);
8951 ++EI;
8952 }
8953 }
8954 for (const auto *Cl : Clauses) {
8955 const auto *C = dyn_cast<OMPFromClause>(Cl);
8956 if (!C)
8957 continue;
8958 MapKind Kind = Other;
8959 if (llvm::is_contained(C->getMotionModifiers(),
8960 OMPC_MOTION_MODIFIER_present))
8961 Kind = Present;
8962 if (llvm::is_contained(C->getMotionModifiers(),
8963 OMPC_MOTION_MODIFIER_iterator)) {
8964 if (auto *IteratorExpr = dyn_cast<OMPIteratorExpr>(
8965 C->getIteratorModifier()->IgnoreParenImpCasts())) {
8966 const auto *VD = cast<VarDecl>(IteratorExpr->getIteratorDecl(0));
8967 CGF.EmitVarDecl(*VD);
8968 }
8969 }
8970
8971 const auto *EI = C->getVarRefs().begin();
8972 for (const auto L : C->component_lists()) {
8973 InfoGen(std::get<0>(L), Kind, std::get<1>(L), OMPC_MAP_from, {},
8974 C->getMotionModifiers(),
8975 /*ReturnDevicePointer=*/false, C->isImplicit(), std::get<2>(L),
8976 *EI);
8977 ++EI;
8978 }
8979 }
8980
8981 // Look at the use_device_ptr and use_device_addr clauses information and
8982 // mark the existing map entries as such. If there is no map information for
8983 // an entry in the use_device_ptr and use_device_addr list, we create one
8984 // with map type 'return_param' and zero size section. It is the user's
8985 // fault if that was not mapped before. If there is no map information, then
8986 // we defer the emission of that entry until all the maps for the same VD
8987 // have been handled.
8988 MapCombinedInfoTy UseDeviceDataCombinedInfo;
8989
8990 auto &&UseDeviceDataCombinedInfoGen =
8991 [&UseDeviceDataCombinedInfo](const ValueDecl *VD, llvm::Value *Ptr,
8992 CodeGenFunction &CGF, bool IsDevAddr,
8993 bool HasUdpFbNullify = false) {
8994 UseDeviceDataCombinedInfo.Exprs.push_back(VD);
8995 UseDeviceDataCombinedInfo.BasePointers.emplace_back(Ptr);
8996 UseDeviceDataCombinedInfo.DevicePtrDecls.emplace_back(VD);
8997 UseDeviceDataCombinedInfo.DevicePointers.emplace_back(
8998 IsDevAddr ? DeviceInfoTy::Address : DeviceInfoTy::Pointer);
8999 // FIXME: For use_device_addr on array-sections, this should
9000 // be the starting address of the section.
9001 // e.g. int *p;
9002 // ... use_device_addr(p[3])
9003 // &p[0], &p[3], /*size=*/0, RETURN_PARAM
9004 UseDeviceDataCombinedInfo.Pointers.push_back(Ptr);
9005 UseDeviceDataCombinedInfo.Sizes.push_back(
9006 llvm::Constant::getNullValue(CGF.Int64Ty));
9007 OpenMPOffloadMappingFlags Flags =
9008 OpenMPOffloadMappingFlags::OMP_MAP_RETURN_PARAM;
9009 if (HasUdpFbNullify)
9010 Flags |= OpenMPOffloadMappingFlags::OMP_MAP_FB_NULLIFY;
9011 UseDeviceDataCombinedInfo.Types.push_back(Flags);
9012 UseDeviceDataCombinedInfo.HasAttachPtr.push_back(false);
9013 UseDeviceDataCombinedInfo.Mappers.push_back(nullptr);
9014 };
9015
9016 auto &&MapInfoGen =
9017 [&UseDeviceDataCombinedInfoGen](
9018 CodeGenFunction &CGF, const Expr *IE, const ValueDecl *VD,
9020 Components,
9021 bool IsDevAddr, bool IEIsAttachPtrForDevAddr = false,
9022 bool HasUdpFbNullify = false) {
9023 // We didn't find any match in our map information - generate a zero
9024 // size array section.
9025 llvm::Value *Ptr;
9026 if (IsDevAddr && !IEIsAttachPtrForDevAddr) {
9027 if (IE->isGLValue())
9028 Ptr = CGF.EmitLValue(IE).getPointer(CGF);
9029 else
9030 Ptr = CGF.EmitScalarExpr(IE);
9031 } else {
9032 Ptr = CGF.EmitLoadOfScalar(CGF.EmitLValue(IE), IE->getExprLoc());
9033 }
9034 bool TreatDevAddrAsDevPtr = IEIsAttachPtrForDevAddr;
9035 // For the purpose of address-translation, treat something like the
9036 // following:
9037 // int *p;
9038 // ... use_device_addr(p[1])
9039 // equivalent to
9040 // ... use_device_ptr(p)
9041 UseDeviceDataCombinedInfoGen(VD, Ptr, CGF, /*IsDevAddr=*/IsDevAddr &&
9042 !TreatDevAddrAsDevPtr,
9043 HasUdpFbNullify);
9044 };
9045
9046 auto &&IsMapInfoExist =
9047 [&Info, this](CodeGenFunction &CGF, const ValueDecl *VD, const Expr *IE,
9048 const Expr *DesiredAttachPtrExpr, bool IsDevAddr,
9049 bool HasUdpFbNullify = false) -> bool {
9050 // We potentially have map information for this declaration already.
9051 // Look for the first set of components that refer to it. If found,
9052 // return true.
9053 // If the first component is a member expression, we have to look into
9054 // 'this', which maps to null in the map of map information. Otherwise
9055 // look directly for the information.
9056 auto It = Info.find(isa<MemberExpr>(IE) ? nullptr : VD);
9057 if (It != Info.end()) {
9058 bool Found = false;
9059 for (auto &Data : It->second) {
9060 MapInfo *CI = nullptr;
9061 // We potentially have multiple maps for the same decl. We need to
9062 // only consider those for which the attach-ptr matches the desired
9063 // attach-ptr.
9064 auto *It = llvm::find_if(Data, [&](const MapInfo &MI) {
9065 if (MI.Components.back().getAssociatedDeclaration() != VD)
9066 return false;
9067
9068 const Expr *MapAttachPtr = getAttachPtrExpr(MI.Components);
9069 bool Match = AttachPtrComparator.areEqual(MapAttachPtr,
9070 DesiredAttachPtrExpr);
9071 return Match;
9072 });
9073
9074 if (It != Data.end())
9075 CI = &*It;
9076
9077 if (CI) {
9078 if (IsDevAddr) {
9079 CI->ForDeviceAddr = true;
9080 CI->ReturnDevicePointer = true;
9081 CI->HasUdpFbNullify = HasUdpFbNullify;
9082 Found = true;
9083 break;
9084 } else {
9085 auto PrevCI = std::next(CI->Components.rbegin());
9086 const auto *VarD = dyn_cast<VarDecl>(VD);
9087 const Expr *AttachPtrExpr = getAttachPtrExpr(CI->Components);
9088 if (CGF.CGM.getOpenMPRuntime().hasRequiresUnifiedSharedMemory() ||
9089 isa<MemberExpr>(IE) ||
9090 !VD->getType().getNonReferenceType()->isPointerType() ||
9091 PrevCI == CI->Components.rend() ||
9092 isa<MemberExpr>(PrevCI->getAssociatedExpression()) || !VarD ||
9093 VarD->hasLocalStorage() ||
9094 (isa_and_nonnull<DeclRefExpr>(AttachPtrExpr) &&
9095 VD == cast<DeclRefExpr>(AttachPtrExpr)->getDecl())) {
9096 CI->ForDeviceAddr = IsDevAddr;
9097 CI->ReturnDevicePointer = true;
9098 CI->HasUdpFbNullify = HasUdpFbNullify;
9099 Found = true;
9100 break;
9101 }
9102 }
9103 }
9104 }
9105 return Found;
9106 }
9107 return false;
9108 };
9109
9110 // Look at the use_device_ptr clause information and mark the existing map
9111 // entries as such. If there is no map information for an entry in the
9112 // use_device_ptr list, we create one with map type 'alloc' and zero size
9113 // section. It is the user fault if that was not mapped before. If there is
9114 // no map information and the pointer is a struct member, then we defer the
9115 // emission of that entry until the whole struct has been processed.
9116 for (const auto *Cl : Clauses) {
9117 const auto *C = dyn_cast<OMPUseDevicePtrClause>(Cl);
9118 if (!C)
9119 continue;
9120 bool HasUdpFbNullify =
9121 C->getFallbackModifier() == OMPC_USE_DEVICE_PTR_FALLBACK_fb_nullify;
9122 for (const auto L : C->component_lists()) {
9124 std::get<1>(L);
9125 assert(!Components.empty() &&
9126 "Not expecting empty list of components!");
9127 const ValueDecl *VD = Components.back().getAssociatedDeclaration();
9129 const Expr *IE = Components.back().getAssociatedExpression();
9130 // For use_device_ptr, we match an existing map clause if its attach-ptr
9131 // is same as the use_device_ptr operand. e.g.
9132 // map expr | use_device_ptr expr | current behavior
9133 // ---------|---------------------|-----------------
9134 // p[1] | p | match
9135 // ps->a | ps | match
9136 // p | p | no match
9137 const Expr *UDPOperandExpr =
9138 Components.front().getAssociatedExpression();
9139 if (IsMapInfoExist(CGF, VD, IE,
9140 /*DesiredAttachPtrExpr=*/UDPOperandExpr,
9141 /*IsDevAddr=*/false, HasUdpFbNullify))
9142 continue;
9143 MapInfoGen(CGF, IE, VD, Components, /*IsDevAddr=*/false,
9144 /*IEIsAttachPtrForDevAddr=*/false, HasUdpFbNullify);
9145 }
9146 }
9147
9148 llvm::SmallDenseSet<CanonicalDeclPtr<const Decl>, 4> Processed;
9149 for (const auto *Cl : Clauses) {
9150 const auto *C = dyn_cast<OMPUseDeviceAddrClause>(Cl);
9151 if (!C)
9152 continue;
9153 for (const auto L : C->component_lists()) {
9155 std::get<1>(L);
9156 assert(!std::get<1>(L).empty() &&
9157 "Not expecting empty list of components!");
9158 const ValueDecl *VD = std::get<1>(L).back().getAssociatedDeclaration();
9159 if (!Processed.insert(VD).second)
9160 continue;
9162 // For use_device_addr, we match an existing map clause if the
9163 // use_device_addr operand's attach-ptr matches the map operand's
9164 // attach-ptr.
9165 // We chould also restrict to only match cases when there is a full
9166 // match between the map/use_device_addr clause exprs, but that may be
9167 // unnecessary.
9168 //
9169 // map expr | use_device_addr expr | current | possible restrictive/
9170 // | | behavior | safer behavior
9171 // ---------|----------------------|-----------|-----------------------
9172 // p | p | match | match
9173 // p[0] | p[0] | match | match
9174 // p[0:1] | p[0] | match | no match
9175 // p[0:1] | p[2:1] | match | no match
9176 // p[1] | p[0] | match | no match
9177 // ps->a | ps->b | match | no match
9178 // p | p[0] | no match | no match
9179 // pp | pp[0][0] | no match | no match
9180 const Expr *UDAAttachPtrExpr = getAttachPtrExpr(Components);
9181 const Expr *IE = std::get<1>(L).back().getAssociatedExpression();
9182 assert((!UDAAttachPtrExpr || UDAAttachPtrExpr == IE) &&
9183 "use_device_addr operand has an attach-ptr, but does not match "
9184 "last component's expr.");
9185 if (IsMapInfoExist(CGF, VD, IE,
9186 /*DesiredAttachPtrExpr=*/UDAAttachPtrExpr,
9187 /*IsDevAddr=*/true))
9188 continue;
9189 MapInfoGen(CGF, IE, VD, Components,
9190 /*IsDevAddr=*/true,
9191 /*IEIsAttachPtrForDevAddr=*/UDAAttachPtrExpr != nullptr);
9192 }
9193 }
9194
9195 for (const auto &Data : Info) {
9196 MapCombinedInfoTy CurInfo;
9197 const Decl *D = Data.first;
9198 const ValueDecl *VD = cast_or_null<ValueDecl>(D);
9199 // Group component lists by their AttachPtrExpr and process them in order
9200 // of increasing complexity (nullptr first, then simple expressions like
9201 // p, then more complex ones like p[0], etc.)
9202 //
9203 // This is similar to how generateInfoForCaptureFromClauseInfo handles
9204 // grouping for target constructs.
9205 SmallVector<std::pair<const Expr *, MapInfo>, 16> AttachPtrMapInfoPairs;
9206
9207 // First, collect all MapData entries with their attach-ptr exprs.
9208 for (const auto &M : Data.second) {
9209 for (const MapInfo &L : M) {
9210 assert(!L.Components.empty() &&
9211 "Not expecting declaration with no component lists.");
9212
9213 const Expr *AttachPtrExpr = getAttachPtrExpr(L.Components);
9214 AttachPtrMapInfoPairs.emplace_back(AttachPtrExpr, L);
9215 }
9216 }
9217
9218 // Next, sort by increasing order of their complexity.
9219 llvm::stable_sort(AttachPtrMapInfoPairs,
9220 [this](const auto &LHS, const auto &RHS) {
9221 return AttachPtrComparator(LHS.first, RHS.first);
9222 });
9223
9224 // And finally, process them all in order, grouping those with
9225 // equivalent attach-ptr exprs together.
9226 auto *It = AttachPtrMapInfoPairs.begin();
9227 while (It != AttachPtrMapInfoPairs.end()) {
9228 const Expr *AttachPtrExpr = It->first;
9229
9230 SmallVector<MapInfo, 8> GroupLists;
9231 while (It != AttachPtrMapInfoPairs.end() &&
9232 (It->first == AttachPtrExpr ||
9233 AttachPtrComparator.areEqual(It->first, AttachPtrExpr))) {
9234 GroupLists.push_back(It->second);
9235 ++It;
9236 }
9237 assert(!GroupLists.empty() && "GroupLists should not be empty");
9238
9239 StructRangeInfoTy PartialStruct;
9240 AttachInfoTy AttachInfo;
9241 MapCombinedInfoTy GroupCurInfo;
9242 // Current group's struct base information:
9243 MapCombinedInfoTy GroupStructBaseCurInfo;
9244 for (const MapInfo &L : GroupLists) {
9245 // Remember the current base pointer index.
9246 unsigned CurrentBasePointersIdx = GroupCurInfo.BasePointers.size();
9247 unsigned StructBasePointersIdx =
9248 GroupStructBaseCurInfo.BasePointers.size();
9249
9250 GroupCurInfo.NonContigInfo.IsNonContiguous =
9251 L.Components.back().isNonContiguous();
9252 generateInfoForComponentList(
9253 L.MapType, L.MapModifiers, L.MotionModifiers, L.Components,
9254 GroupCurInfo, GroupStructBaseCurInfo, PartialStruct, AttachInfo,
9255 /*IsFirstComponentList=*/false, L.IsImplicit,
9256 /*GenerateAllInfoForClauses*/ true, L.Mapper, L.ForDeviceAddr, VD,
9257 L.VarRef, /*OverlappedElements*/ {});
9258
9259 // If this entry relates to a device pointer, set the relevant
9260 // declaration and add the 'return pointer' flag.
9261 if (L.ReturnDevicePointer) {
9262 // Check whether a value was added to either GroupCurInfo or
9263 // GroupStructBaseCurInfo and error if no value was added to either
9264 // of them:
9265 assert((CurrentBasePointersIdx < GroupCurInfo.BasePointers.size() ||
9266 StructBasePointersIdx <
9267 GroupStructBaseCurInfo.BasePointers.size()) &&
9268 "Unexpected number of mapped base pointers.");
9269
9270 // Choose a base pointer index which is always valid:
9271 const ValueDecl *RelevantVD =
9272 L.Components.back().getAssociatedDeclaration();
9273 assert(RelevantVD &&
9274 "No relevant declaration related with device pointer??");
9275
9276 // If GroupStructBaseCurInfo has been updated this iteration then
9277 // work on the first new entry added to it i.e. make sure that when
9278 // multiple values are added to any of the lists, the first value
9279 // added is being modified by the assignments below (not the last
9280 // value added).
9281 auto SetDevicePointerInfo = [&](MapCombinedInfoTy &Info,
9282 unsigned Idx) {
9283 Info.DevicePtrDecls[Idx] = RelevantVD;
9284 Info.DevicePointers[Idx] = L.ForDeviceAddr
9285 ? DeviceInfoTy::Address
9286 : DeviceInfoTy::Pointer;
9287 Info.Types[Idx] |=
9288 OpenMPOffloadMappingFlags::OMP_MAP_RETURN_PARAM;
9289 if (L.HasUdpFbNullify)
9290 Info.Types[Idx] |=
9291 OpenMPOffloadMappingFlags::OMP_MAP_FB_NULLIFY;
9292 };
9293
9294 if (StructBasePointersIdx <
9295 GroupStructBaseCurInfo.BasePointers.size())
9296 SetDevicePointerInfo(GroupStructBaseCurInfo,
9297 StructBasePointersIdx);
9298 else
9299 SetDevicePointerInfo(GroupCurInfo, CurrentBasePointersIdx);
9300 }
9301 }
9302
9303 // Unify entries in one list making sure the struct mapping precedes the
9304 // individual fields:
9305 MapCombinedInfoTy GroupUnionCurInfo;
9306 GroupUnionCurInfo.append(GroupStructBaseCurInfo);
9307 GroupUnionCurInfo.append(GroupCurInfo);
9308
9309 // If there is an entry in PartialStruct it means we have a struct with
9310 // individual members mapped. Emit an extra combined entry.
9311 if (PartialStruct.Base.isValid()) {
9312 // Prepend a synthetic dimension of length 1 to represent the
9313 // aggregated struct object. Using 1 (not 0, as 0 produced an
9314 // incorrect non-contiguous descriptor (DimSize==1), causing the
9315 // non-contiguous motion clause path to be skipped.) is important:
9316 // * It preserves the correct rank so targetDataUpdate() computes
9317 // DimSize == 2 for cases like strided array sections originating
9318 // from user-defined mappers (e.g. test with s.data[0:8:2]).
9319 GroupUnionCurInfo.NonContigInfo.Dims.insert(
9320 GroupUnionCurInfo.NonContigInfo.Dims.begin(), 1);
9321 emitCombinedEntry(
9322 CurInfo, GroupUnionCurInfo.Types, PartialStruct, AttachInfo,
9323 /*IsMapThis=*/!VD, OMPBuilder, VD,
9324 /*OffsetForMemberOfFlag=*/CombinedInfo.BasePointers.size(),
9325 /*NotTargetParams=*/true);
9326 }
9327
9328 // Append this group's results to the overall CurInfo in the correct
9329 // order: combined-entry -> original-field-entries -> attach-entry
9330 CurInfo.append(GroupUnionCurInfo);
9331 if (AttachInfo.isValid())
9332 emitAttachEntry(CGF, CurInfo, AttachInfo);
9333 }
9334
9335 // We need to append the results of this capture to what we already have.
9336 CombinedInfo.append(CurInfo);
9337 }
9338 // Append data for use_device_ptr/addr clauses.
9339 CombinedInfo.append(UseDeviceDataCombinedInfo);
9340 }
9341
9342public:
9343 MappableExprsHandler(const OMPExecutableDirective &Dir, CodeGenFunction &CGF)
9344 : CurDir(&Dir), CGF(CGF), AttachPtrComparator(*this) {
9345 // Extract firstprivate clause information.
9346 for (const auto *C : Dir.getClausesOfKind<OMPFirstprivateClause>())
9347 for (const auto *D : C->varlist())
9348 FirstPrivateDecls.try_emplace(
9349 cast<VarDecl>(cast<DeclRefExpr>(D)->getDecl()), C->isImplicit());
9350 // Extract implicit firstprivates from uses_allocators clauses.
9351 for (const auto *C : Dir.getClausesOfKind<OMPUsesAllocatorsClause>()) {
9352 for (unsigned I = 0, E = C->getNumberOfAllocators(); I < E; ++I) {
9353 OMPUsesAllocatorsClause::Data D = C->getAllocatorData(I);
9354 if (const auto *DRE = dyn_cast_or_null<DeclRefExpr>(D.AllocatorTraits))
9355 FirstPrivateDecls.try_emplace(cast<VarDecl>(DRE->getDecl()),
9356 /*Implicit=*/true);
9357 else if (const auto *VD = dyn_cast<VarDecl>(
9358 cast<DeclRefExpr>(D.Allocator->IgnoreParenImpCasts())
9359 ->getDecl()))
9360 FirstPrivateDecls.try_emplace(VD, /*Implicit=*/true);
9361 }
9362 }
9363 // Extract defaultmap clause information.
9364 for (const auto *C : Dir.getClausesOfKind<OMPDefaultmapClause>())
9365 if (C->getDefaultmapModifier() == OMPC_DEFAULTMAP_MODIFIER_firstprivate)
9366 DefaultmapFirstprivateKinds.insert(C->getDefaultmapKind());
9367 // Extract device pointer clause information.
9368 for (const auto *C : Dir.getClausesOfKind<OMPIsDevicePtrClause>())
9369 for (auto L : C->component_lists())
9370 DevPointersMap[std::get<0>(L)].push_back(std::get<1>(L));
9371 // Extract device addr clause information.
9372 for (const auto *C : Dir.getClausesOfKind<OMPHasDeviceAddrClause>())
9373 for (auto L : C->component_lists())
9374 HasDevAddrsMap[std::get<0>(L)].push_back(std::get<1>(L));
9375 // Extract map information.
9376 for (const auto *C : Dir.getClausesOfKind<OMPMapClause>()) {
9377 if (C->getMapType() != OMPC_MAP_to)
9378 continue;
9379 for (auto L : C->component_lists()) {
9380 const ValueDecl *VD = std::get<0>(L);
9381 const auto *RD = VD ? VD->getType()
9382 .getCanonicalType()
9383 .getNonReferenceType()
9384 ->getAsCXXRecordDecl()
9385 : nullptr;
9386 if (RD && RD->isLambda())
9387 LambdasMap.try_emplace(std::get<0>(L), C);
9388 }
9389 }
9390
9391 auto CollectAttachPtrExprsForClauseComponents = [this](const auto *C) {
9392 for (auto L : C->component_lists()) {
9394 std::get<1>(L);
9395 if (!Components.empty())
9396 collectAttachPtrExprInfo(Components, CurDir);
9397 }
9398 };
9399
9400 // Populate the AttachPtrExprMap for all component lists from map-related
9401 // clauses.
9402 for (const auto *C : Dir.getClausesOfKind<OMPMapClause>())
9403 CollectAttachPtrExprsForClauseComponents(C);
9404 for (const auto *C : Dir.getClausesOfKind<OMPToClause>())
9405 CollectAttachPtrExprsForClauseComponents(C);
9406 for (const auto *C : Dir.getClausesOfKind<OMPFromClause>())
9407 CollectAttachPtrExprsForClauseComponents(C);
9408 for (const auto *C : Dir.getClausesOfKind<OMPUseDevicePtrClause>())
9409 CollectAttachPtrExprsForClauseComponents(C);
9410 for (const auto *C : Dir.getClausesOfKind<OMPUseDeviceAddrClause>())
9411 CollectAttachPtrExprsForClauseComponents(C);
9412 for (const auto *C : Dir.getClausesOfKind<OMPIsDevicePtrClause>())
9413 CollectAttachPtrExprsForClauseComponents(C);
9414 for (const auto *C : Dir.getClausesOfKind<OMPHasDeviceAddrClause>())
9415 CollectAttachPtrExprsForClauseComponents(C);
9416 }
9417
9418 /// Constructor for the declare mapper directive.
9419 MappableExprsHandler(const OMPDeclareMapperDecl &Dir, CodeGenFunction &CGF)
9420 : CurDir(&Dir), CGF(CGF), AttachPtrComparator(*this) {
9421 auto CollectAttachPtrExprsForClauseComponents = [this](const auto *C) {
9422 for (auto L : C->component_lists()) {
9424 std::get<1>(L);
9425 if (!Components.empty())
9426 collectAttachPtrExprInfo(Components, CurDir);
9427 }
9428 };
9429
9430 // Populate the AttachPtrExprMap for all component lists from map-related
9431 // clauses in the declare mapper directive, to enable attach-style mapping
9432 // for mappers.
9433 for (const auto *Cl : Dir.clauses()) {
9434 if (const auto *C = dyn_cast<OMPMapClause>(Cl))
9435 CollectAttachPtrExprsForClauseComponents(C);
9436 else if (const auto *C = dyn_cast<OMPToClause>(Cl))
9437 CollectAttachPtrExprsForClauseComponents(C);
9438 else if (const auto *C = dyn_cast<OMPFromClause>(Cl))
9439 CollectAttachPtrExprsForClauseComponents(C);
9440 }
9441 }
9442
9443 /// Generate code for the combined entry if we have a partially mapped struct
9444 /// and take care of the mapping flags of the arguments corresponding to
9445 /// individual struct members.
9446 /// If a valid \p AttachInfo exists, its pointee addr will be updated to point
9447 /// to the combined-entry's begin address, if emitted.
9448 /// \p PartialStruct contains attach base-pointer information.
9449 /// \returns The index of the combined entry if one was added, std::nullopt
9450 /// otherwise.
9451 void emitCombinedEntry(MapCombinedInfoTy &CombinedInfo,
9452 MapFlagsArrayTy &CurTypes,
9453 const StructRangeInfoTy &PartialStruct,
9454 AttachInfoTy &AttachInfo, bool IsMapThis,
9455 llvm::OpenMPIRBuilder &OMPBuilder, const ValueDecl *VD,
9456 unsigned OffsetForMemberOfFlag,
9457 bool NotTargetParams) const {
9458 if (CurTypes.size() == 1 &&
9459 ((CurTypes.back() & OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF) !=
9460 OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF) &&
9461 !PartialStruct.IsArraySection)
9462 return;
9463 Address LBAddr = PartialStruct.LowestElem.second;
9464 Address HBAddr = PartialStruct.HighestElem.second;
9465 if (PartialStruct.HasCompleteRecord) {
9466 LBAddr = PartialStruct.LB;
9467 HBAddr = PartialStruct.LB;
9468 }
9469 CombinedInfo.Exprs.push_back(VD);
9470 // Base is the base of the struct
9471 CombinedInfo.BasePointers.push_back(PartialStruct.Base.emitRawPointer(CGF));
9472 CombinedInfo.DevicePtrDecls.push_back(nullptr);
9473 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
9474 // Pointer is the address of the lowest element
9475 llvm::Value *LB = LBAddr.emitRawPointer(CGF);
9476 const CXXMethodDecl *MD =
9477 CGF.CurFuncDecl ? dyn_cast<CXXMethodDecl>(CGF.CurFuncDecl) : nullptr;
9478 const CXXRecordDecl *RD = MD ? MD->getParent() : nullptr;
9479 bool HasBaseClass = RD && IsMapThis ? RD->getNumBases() > 0 : false;
9480 // There should not be a mapper for a combined entry.
9481 if (HasBaseClass) {
9482 // OpenMP 5.2 148:21:
9483 // If the target construct is within a class non-static member function,
9484 // and a variable is an accessible data member of the object for which the
9485 // non-static data member function is invoked, the variable is treated as
9486 // if the this[:1] expression had appeared in a map clause with a map-type
9487 // of tofrom.
9488 // Emit this[:1]
9489 CombinedInfo.Pointers.push_back(PartialStruct.Base.emitRawPointer(CGF));
9490 QualType Ty = MD->getFunctionObjectParameterType();
9491 llvm::Value *Size =
9492 CGF.Builder.CreateIntCast(CGF.getTypeSize(Ty), CGF.Int64Ty,
9493 /*isSigned=*/true);
9494 CombinedInfo.Sizes.push_back(Size);
9495 } else {
9496 CombinedInfo.Pointers.push_back(LB);
9497 // Size is (addr of {highest+1} element) - (addr of lowest element)
9498 llvm::Value *HB = HBAddr.emitRawPointer(CGF);
9499 llvm::Value *HAddr = CGF.Builder.CreateConstGEP1_32(
9500 HBAddr.getElementType(), HB, /*Idx0=*/1);
9501 llvm::Value *CLAddr = CGF.Builder.CreatePointerCast(LB, CGF.VoidPtrTy);
9502 llvm::Value *CHAddr = CGF.Builder.CreatePointerCast(HAddr, CGF.VoidPtrTy);
9503 llvm::Value *Diff = CGF.Builder.CreatePtrDiff(CHAddr, CLAddr);
9504 llvm::Value *Size = CGF.Builder.CreateIntCast(Diff, CGF.Int64Ty,
9505 /*isSigned=*/false);
9506 CombinedInfo.Sizes.push_back(Size);
9507 }
9508 CombinedInfo.Mappers.push_back(nullptr);
9509 // Map type is always TARGET_PARAM, if generate info for captures.
9510 CombinedInfo.Types.push_back(
9511 NotTargetParams ? OpenMPOffloadMappingFlags::OMP_MAP_NONE
9512 : !PartialStruct.PreliminaryMapData.BasePointers.empty()
9513 ? OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ
9514 : OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM);
9515 // A combined entry has a base attach-ptr if its constituents do. e.g.:
9516 // map(s2.s1p->x, s2.s1p->y)
9517 // combined entry:
9518 // s2.s1p[0], s2.s1p->x, sizeof(s1p->x..y), ALLOC
9519 // here s2.s1p is the attach-ptr for the combined entry.
9520 // See the inline comments in emitUserDefinedMapper's definition for how
9521 // entries with an attach-ptr are treated.
9522 CombinedInfo.HasAttachPtr.push_back(AttachInfo.isValid());
9523 // If any element has the present modifier, then make sure the runtime
9524 // doesn't attempt to allocate the struct.
9525 if (CurTypes.end() !=
9526 llvm::find_if(CurTypes, [](OpenMPOffloadMappingFlags Type) {
9527 return static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
9528 Type & OpenMPOffloadMappingFlags::OMP_MAP_PRESENT);
9529 }))
9530 CombinedInfo.Types.back() |= OpenMPOffloadMappingFlags::OMP_MAP_PRESENT;
9531 // Remove TARGET_PARAM flag from the first element
9532 (*CurTypes.begin()) &= ~OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM;
9533 // If any element has the ompx_hold modifier, then make sure the runtime
9534 // uses the hold reference count for the struct as a whole so that it won't
9535 // be unmapped by an extra dynamic reference count decrement. Add it to all
9536 // elements as well so the runtime knows which reference count to check
9537 // when determining whether it's time for device-to-host transfers of
9538 // individual elements.
9539 if (CurTypes.end() !=
9540 llvm::find_if(CurTypes, [](OpenMPOffloadMappingFlags Type) {
9541 return static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
9542 Type & OpenMPOffloadMappingFlags::OMP_MAP_OMPX_HOLD);
9543 })) {
9544 CombinedInfo.Types.back() |= OpenMPOffloadMappingFlags::OMP_MAP_OMPX_HOLD;
9545 for (auto &M : CurTypes)
9546 M |= OpenMPOffloadMappingFlags::OMP_MAP_OMPX_HOLD;
9547 }
9548
9549 // All other current entries will be MEMBER_OF the combined entry
9550 // (except for PTR_AND_OBJ entries which do not have a placeholder value
9551 // 0xFFFF in the MEMBER_OF field, or ATTACH entries since they are expected
9552 // to be handled by themselves, after all other maps).
9553 OpenMPOffloadMappingFlags MemberOfFlag = OMPBuilder.getMemberOfFlag(
9554 OffsetForMemberOfFlag + CombinedInfo.BasePointers.size() - 1);
9555 for (auto &M : CurTypes)
9556 OMPBuilder.setCorrectMemberOfFlag(M, MemberOfFlag);
9557
9558 // When we are emitting a combined entry. If there were any pending
9559 // attachments to be done, we do them to the begin address of the combined
9560 // entry. Note that this means only one attachment per combined-entry will
9561 // be done. So, for instance, if we have:
9562 // S *ps;
9563 // ... map(ps->a, ps->b)
9564 // When we are emitting a combined entry. If AttachInfo is valid,
9565 // update the pointee address to point to the begin address of the combined
9566 // entry. This ensures that if we have multiple maps like:
9567 // `map(ps->a, ps->b)`, we still get a single ATTACH entry, like:
9568 //
9569 // &ps[0], &ps->a, sizeof(ps->a to ps->b), ALLOC // combined-entry
9570 // &ps[0], &ps->a, sizeof(ps->a), TO | FROM
9571 // &ps[0], &ps->b, sizeof(ps->b), TO | FROM
9572 // &ps, &ps->a, sizeof(void*), ATTACH // Use combined-entry's LB
9573 if (AttachInfo.isValid())
9574 AttachInfo.AttachPteeAddr = LBAddr;
9575 }
9576
9577 /// Generate all the base pointers, section pointers, sizes, map types, and
9578 /// mappers for the extracted mappable expressions (all included in \a
9579 /// CombinedInfo). Also, for each item that relates with a device pointer, a
9580 /// pair of the relevant declaration and index where it occurs is appended to
9581 /// the device pointers info array.
9582 void generateAllInfo(
9583 MapCombinedInfoTy &CombinedInfo, llvm::OpenMPIRBuilder &OMPBuilder,
9584 const llvm::DenseSet<CanonicalDeclPtr<const Decl>> &SkipVarSet =
9585 llvm::DenseSet<CanonicalDeclPtr<const Decl>>()) const {
9586 assert(isa<const OMPExecutableDirective *>(CurDir) &&
9587 "Expect a executable directive");
9588 const auto *CurExecDir = cast<const OMPExecutableDirective *>(CurDir);
9589 generateAllInfoForClauses(CurExecDir->clauses(), CombinedInfo, OMPBuilder,
9590 SkipVarSet);
9591 }
9592
9593 /// Generate all the base pointers, section pointers, sizes, map types, and
9594 /// mappers for the extracted map clauses of user-defined mapper (all included
9595 /// in \a CombinedInfo).
9596 void generateAllInfoForMapper(MapCombinedInfoTy &CombinedInfo,
9597 llvm::OpenMPIRBuilder &OMPBuilder) const {
9598 assert(isa<const OMPDeclareMapperDecl *>(CurDir) &&
9599 "Expect a declare mapper directive");
9600 const auto *CurMapperDir = cast<const OMPDeclareMapperDecl *>(CurDir);
9601 generateAllInfoForClauses(CurMapperDir->clauses(), CombinedInfo,
9602 OMPBuilder);
9603 }
9604
9605 /// Emit capture info for lambdas for variables captured by reference.
9606 void generateInfoForLambdaCaptures(
9607 const ValueDecl *VD, llvm::Value *Arg, MapCombinedInfoTy &CombinedInfo,
9608 llvm::DenseMap<llvm::Value *, llvm::Value *> &LambdaPointers) const {
9609 QualType VDType = VD->getType().getCanonicalType().getNonReferenceType();
9610 const auto *RD = VDType->getAsCXXRecordDecl();
9611 if (!RD || !RD->isLambda())
9612 return;
9613 Address VDAddr(Arg, CGF.ConvertTypeForMem(VDType),
9614 CGF.getContext().getDeclAlign(VD));
9615 LValue VDLVal = CGF.MakeAddrLValue(VDAddr, VDType);
9616 llvm::DenseMap<const ValueDecl *, FieldDecl *> Captures;
9617 FieldDecl *ThisCapture = nullptr;
9618 RD->getCaptureFields(Captures, ThisCapture);
9619 if (ThisCapture) {
9620 LValue ThisLVal =
9621 CGF.EmitLValueForFieldInitialization(VDLVal, ThisCapture);
9622 LValue ThisLValVal = CGF.EmitLValueForField(VDLVal, ThisCapture);
9623 LambdaPointers.try_emplace(ThisLVal.getPointer(CGF),
9624 VDLVal.getPointer(CGF));
9625 CombinedInfo.Exprs.push_back(VD);
9626 CombinedInfo.BasePointers.push_back(ThisLVal.getPointer(CGF));
9627 CombinedInfo.DevicePtrDecls.push_back(nullptr);
9628 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
9629 CombinedInfo.Pointers.push_back(ThisLValVal.getPointer(CGF));
9630 CombinedInfo.Sizes.push_back(
9631 CGF.Builder.CreateIntCast(CGF.getTypeSize(CGF.getContext().VoidPtrTy),
9632 CGF.Int64Ty, /*isSigned=*/true));
9633 CombinedInfo.Types.push_back(
9634 OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ |
9635 OpenMPOffloadMappingFlags::OMP_MAP_LITERAL |
9636 OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF |
9637 OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT);
9638 CombinedInfo.HasAttachPtr.push_back(false);
9639 CombinedInfo.Mappers.push_back(nullptr);
9640 }
9641 for (const LambdaCapture &LC : RD->captures()) {
9642 if (!LC.capturesVariable())
9643 continue;
9644 const VarDecl *VD = cast<VarDecl>(LC.getCapturedVar());
9645 if (LC.getCaptureKind() != LCK_ByRef && !VD->getType()->isPointerType())
9646 continue;
9647 auto It = Captures.find(VD);
9648 assert(It != Captures.end() && "Found lambda capture without field.");
9649 LValue VarLVal = CGF.EmitLValueForFieldInitialization(VDLVal, It->second);
9650 if (LC.getCaptureKind() == LCK_ByRef) {
9651 LValue VarLValVal = CGF.EmitLValueForField(VDLVal, It->second);
9652 LambdaPointers.try_emplace(VarLVal.getPointer(CGF),
9653 VDLVal.getPointer(CGF));
9654 CombinedInfo.Exprs.push_back(VD);
9655 CombinedInfo.BasePointers.push_back(VarLVal.getPointer(CGF));
9656 CombinedInfo.DevicePtrDecls.push_back(nullptr);
9657 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
9658 CombinedInfo.Pointers.push_back(VarLValVal.getPointer(CGF));
9659 CombinedInfo.Sizes.push_back(CGF.Builder.CreateIntCast(
9660 CGF.getTypeSize(
9662 CGF.Int64Ty, /*isSigned=*/true));
9663 } else {
9664 RValue VarRVal = CGF.EmitLoadOfLValue(VarLVal, RD->getLocation());
9665 LambdaPointers.try_emplace(VarLVal.getPointer(CGF),
9666 VDLVal.getPointer(CGF));
9667 CombinedInfo.Exprs.push_back(VD);
9668 CombinedInfo.BasePointers.push_back(VarLVal.getPointer(CGF));
9669 CombinedInfo.DevicePtrDecls.push_back(nullptr);
9670 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
9671 CombinedInfo.Pointers.push_back(VarRVal.getScalarVal());
9672 CombinedInfo.Sizes.push_back(llvm::ConstantInt::get(CGF.Int64Ty, 0));
9673 }
9674 CombinedInfo.Types.push_back(
9675 OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ |
9676 OpenMPOffloadMappingFlags::OMP_MAP_LITERAL |
9677 OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF |
9678 OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT);
9679 CombinedInfo.HasAttachPtr.push_back(false);
9680 CombinedInfo.Mappers.push_back(nullptr);
9681 }
9682 }
9683
9684 /// Set correct indices for lambdas captures.
9685 void adjustMemberOfForLambdaCaptures(
9686 llvm::OpenMPIRBuilder &OMPBuilder,
9687 const llvm::DenseMap<llvm::Value *, llvm::Value *> &LambdaPointers,
9688 MapBaseValuesArrayTy &BasePointers, MapValuesArrayTy &Pointers,
9689 MapFlagsArrayTy &Types) const {
9690 for (unsigned I = 0, E = Types.size(); I < E; ++I) {
9691 // Set correct member_of idx for all implicit lambda captures.
9692 if (Types[I] != (OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ |
9693 OpenMPOffloadMappingFlags::OMP_MAP_LITERAL |
9694 OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF |
9695 OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT))
9696 continue;
9697 llvm::Value *BasePtr = LambdaPointers.lookup(BasePointers[I]);
9698 assert(BasePtr && "Unable to find base lambda address.");
9699 int TgtIdx = -1;
9700 for (unsigned J = I; J > 0; --J) {
9701 unsigned Idx = J - 1;
9702 if (Pointers[Idx] != BasePtr)
9703 continue;
9704 TgtIdx = Idx;
9705 break;
9706 }
9707 assert(TgtIdx != -1 && "Unable to find parent lambda.");
9708 // All other current entries will be MEMBER_OF the combined entry
9709 // (except for PTR_AND_OBJ entries which do not have a placeholder value
9710 // 0xFFFF in the MEMBER_OF field).
9711 OpenMPOffloadMappingFlags MemberOfFlag =
9712 OMPBuilder.getMemberOfFlag(TgtIdx);
9713 OMPBuilder.setCorrectMemberOfFlag(Types[I], MemberOfFlag);
9714 }
9715 }
9716
9717 /// Populate component lists for non-lambda captured variables from map,
9718 /// is_device_ptr and has_device_addr clause info.
9719 void populateComponentListsForNonLambdaCaptureFromClauses(
9720 const ValueDecl *VD, MapDataArrayTy &DeclComponentLists,
9721 SmallVectorImpl<
9722 SmallVector<OMPClauseMappableExprCommon::MappableComponent, 8>>
9723 &StorageForImplicitlyAddedComponentLists) const {
9724 if (VD && LambdasMap.count(VD))
9725 return;
9726
9727 // For member fields list in is_device_ptr, store it in
9728 // DeclComponentLists for generating components info.
9730 auto It = DevPointersMap.find(VD);
9731 if (It != DevPointersMap.end())
9732 for (const auto &MCL : It->second)
9733 DeclComponentLists.emplace_back(MCL, OMPC_MAP_to, Unknown,
9734 /*IsImpicit = */ true, nullptr,
9735 nullptr);
9736 auto I = HasDevAddrsMap.find(VD);
9737 if (I != HasDevAddrsMap.end())
9738 for (const auto &MCL : I->second)
9739 DeclComponentLists.emplace_back(MCL, OMPC_MAP_tofrom, Unknown,
9740 /*IsImpicit = */ true, nullptr,
9741 nullptr);
9742 assert(isa<const OMPExecutableDirective *>(CurDir) &&
9743 "Expect a executable directive");
9744 const auto *CurExecDir = cast<const OMPExecutableDirective *>(CurDir);
9745 for (const auto *C : CurExecDir->getClausesOfKind<OMPMapClause>()) {
9746 const auto *EI = C->getVarRefs().begin();
9747 for (const auto L : C->decl_component_lists(VD)) {
9748 const ValueDecl *VDecl, *Mapper;
9749 // The Expression is not correct if the mapping is implicit
9750 const Expr *E = (C->getMapLoc().isValid()) ? *EI : nullptr;
9752 std::tie(VDecl, Components, Mapper) = L;
9753 assert(VDecl == VD && "We got information for the wrong declaration??");
9754 assert(!Components.empty() &&
9755 "Not expecting declaration with no component lists.");
9756 DeclComponentLists.emplace_back(Components, C->getMapType(),
9757 C->getMapTypeModifiers(),
9758 C->isImplicit(), Mapper, E);
9759 ++EI;
9760 }
9761 }
9762
9763 // For the target construct, if there's a map with a base-pointer that's
9764 // a member of an implicitly captured struct, of the current class,
9765 // we need to emit an implicit map on the pointer.
9766 if (isOpenMPTargetExecutionDirective(CurExecDir->getDirectiveKind()))
9767 addImplicitMapForAttachPtrBaseIfMemberOfCapturedVD(
9768 VD, DeclComponentLists, StorageForImplicitlyAddedComponentLists);
9769
9770 llvm::stable_sort(DeclComponentLists, [](const MapData &LHS,
9771 const MapData &RHS) {
9772 ArrayRef<OpenMPMapModifierKind> MapModifiers = std::get<2>(LHS);
9773 OpenMPMapClauseKind MapType = std::get<1>(RHS);
9774 bool HasPresent =
9775 llvm::is_contained(MapModifiers, clang::OMPC_MAP_MODIFIER_present);
9776 bool HasAllocs = MapType == OMPC_MAP_alloc;
9777 MapModifiers = std::get<2>(RHS);
9778 MapType = std::get<1>(LHS);
9779 bool HasPresentR =
9780 llvm::is_contained(MapModifiers, clang::OMPC_MAP_MODIFIER_present);
9781 bool HasAllocsR = MapType == OMPC_MAP_alloc;
9782 return (HasPresent && !HasPresentR) || (HasAllocs && !HasAllocsR);
9783 });
9784 }
9785
9786 /// On a target construct, if there's an implicit map on a struct, or that of
9787 /// this[:], and an explicit map with a member of that struct/class as the
9788 /// base-pointer, we need to make sure that base-pointer is implicitly mapped,
9789 /// to make sure we don't map the full struct/class. For example:
9790 ///
9791 /// \code
9792 /// struct S {
9793 /// int dummy[10000];
9794 /// int *p;
9795 /// void f1() {
9796 /// #pragma omp target map(p[0:1])
9797 /// (void)this;
9798 /// }
9799 /// }; S s;
9800 ///
9801 /// void f2() {
9802 /// #pragma omp target map(s.p[0:10])
9803 /// (void)s;
9804 /// }
9805 /// \endcode
9806 ///
9807 /// Only `this-p` and `s.p` should be mapped in the two cases above.
9808 //
9809 // OpenMP 6.0: 7.9.6 map clause, pg 285
9810 // If a list item with an implicitly determined data-mapping attribute does
9811 // not have any corresponding storage in the device data environment prior to
9812 // a task encountering the construct associated with the map clause, and one
9813 // or more contiguous parts of the original storage are either list items or
9814 // base pointers to list items that are explicitly mapped on the construct,
9815 // only those parts of the original storage will have corresponding storage in
9816 // the device data environment as a result of the map clauses on the
9817 // construct.
9818 void addImplicitMapForAttachPtrBaseIfMemberOfCapturedVD(
9819 const ValueDecl *CapturedVD, MapDataArrayTy &DeclComponentLists,
9820 SmallVectorImpl<
9821 SmallVector<OMPClauseMappableExprCommon::MappableComponent, 8>>
9822 &ComponentVectorStorage) const {
9823 bool IsThisCapture = CapturedVD == nullptr;
9824
9825 for (const auto &ComponentsAndAttachPtr : AttachPtrExprMap) {
9827 ComponentsWithAttachPtr = ComponentsAndAttachPtr.first;
9828 const Expr *AttachPtrExpr = ComponentsAndAttachPtr.second;
9829 if (!AttachPtrExpr)
9830 continue;
9831
9832 const auto *ME = dyn_cast<MemberExpr>(AttachPtrExpr);
9833 if (!ME)
9834 continue;
9835
9836 const Expr *Base = ME->getBase()->IgnoreParenImpCasts();
9837
9838 // If we are handling a "this" capture, then we are looking for
9839 // attach-ptrs of form `this->p`, either explicitly or implicitly.
9840 if (IsThisCapture && !ME->isImplicitCXXThis() && !isa<CXXThisExpr>(Base))
9841 continue;
9842
9843 if (!IsThisCapture && (!isa<DeclRefExpr>(Base) ||
9844 cast<DeclRefExpr>(Base)->getDecl() != CapturedVD))
9845 continue;
9846
9847 // For non-this captures, we are looking for attach-ptrs of form
9848 // `s.p`.
9849 // For non-this captures, we are looking for attach-ptrs like `s.p`.
9850 if (!IsThisCapture && (ME->isArrow() || !isa<DeclRefExpr>(Base) ||
9851 cast<DeclRefExpr>(Base)->getDecl() != CapturedVD))
9852 continue;
9853
9854 // Check if we have an existing map on either:
9855 // this[:], s, this->p, or s.p, in which case, we don't need to add
9856 // an implicit one for the attach-ptr s.p/this->p.
9857 bool FoundExistingMap = false;
9858 for (const MapData &ExistingL : DeclComponentLists) {
9860 ExistingComponents = std::get<0>(ExistingL);
9861
9862 if (ExistingComponents.empty())
9863 continue;
9864
9865 // First check if we have a map like map(this->p) or map(s.p).
9866 const auto &FirstComponent = ExistingComponents.front();
9867 const Expr *FirstExpr = FirstComponent.getAssociatedExpression();
9868
9869 if (!FirstExpr)
9870 continue;
9871
9872 // First check if we have a map like map(this->p) or map(s.p).
9873 if (AttachPtrComparator.areEqual(FirstExpr, AttachPtrExpr)) {
9874 FoundExistingMap = true;
9875 break;
9876 }
9877
9878 // Check if we have a map like this[0:1]
9879 if (IsThisCapture) {
9880 if (const auto *OASE = dyn_cast<ArraySectionExpr>(FirstExpr)) {
9881 if (isa<CXXThisExpr>(OASE->getBase()->IgnoreParenImpCasts())) {
9882 FoundExistingMap = true;
9883 break;
9884 }
9885 }
9886 continue;
9887 }
9888
9889 // When the attach-ptr is something like `s.p`, check if
9890 // `s` itself is mapped explicitly.
9891 if (const auto *DRE = dyn_cast<DeclRefExpr>(FirstExpr)) {
9892 if (DRE->getDecl() == CapturedVD) {
9893 FoundExistingMap = true;
9894 break;
9895 }
9896 }
9897 }
9898
9899 if (FoundExistingMap)
9900 continue;
9901
9902 // If no base map is found, we need to create an implicit map for the
9903 // attach-pointer expr.
9904
9905 ComponentVectorStorage.emplace_back();
9906 auto &AttachPtrComponents = ComponentVectorStorage.back();
9907
9909 bool SeenAttachPtrComponent = false;
9910 // For creating a map on the attach-ptr `s.p/this->p`, we copy all
9911 // components from the component-list which has `s.p/this->p`
9912 // as the attach-ptr, starting from the component which matches
9913 // `s.p/this->p`. This way, we'll have component-lists of
9914 // `s.p` -> `s`, and `this->p` -> `this`.
9915 for (size_t i = 0; i < ComponentsWithAttachPtr.size(); ++i) {
9916 const auto &Component = ComponentsWithAttachPtr[i];
9917 const Expr *ComponentExpr = Component.getAssociatedExpression();
9918
9919 if (!SeenAttachPtrComponent && ComponentExpr != AttachPtrExpr)
9920 continue;
9921 SeenAttachPtrComponent = true;
9922
9923 AttachPtrComponents.emplace_back(Component.getAssociatedExpression(),
9924 Component.getAssociatedDeclaration(),
9925 Component.isNonContiguous());
9926 }
9927 assert(!AttachPtrComponents.empty() &&
9928 "Could not populate component-lists for mapping attach-ptr");
9929
9930 DeclComponentLists.emplace_back(
9931 AttachPtrComponents, OMPC_MAP_tofrom, Unknown,
9932 /*IsImplicit=*/true, /*mapper=*/nullptr, AttachPtrExpr);
9933 }
9934 }
9935
9936 /// For a capture that has an associated clause, generate the base pointers,
9937 /// section pointers, sizes, map types, and mappers (all included in
9938 /// \a CurCaptureVarInfo).
9939 void generateInfoForCaptureFromClauseInfo(
9940 const MapDataArrayTy &DeclComponentListsFromClauses,
9941 const CapturedStmt::Capture *Cap, llvm::Value *Arg,
9942 MapCombinedInfoTy &CurCaptureVarInfo, llvm::OpenMPIRBuilder &OMPBuilder,
9943 unsigned OffsetForMemberOfFlag) const {
9944 assert(!Cap->capturesVariableArrayType() &&
9945 "Not expecting to generate map info for a variable array type!");
9946
9947 // We need to know when we generating information for the first component
9948 const ValueDecl *VD = Cap->capturesThis()
9949 ? nullptr
9950 : Cap->getCapturedVar()->getCanonicalDecl();
9951
9952 // for map(to: lambda): skip here, processing it in
9953 // generateDefaultMapInfo
9954 if (LambdasMap.count(VD))
9955 return;
9956
9957 // If this declaration appears in a is_device_ptr clause we just have to
9958 // pass the pointer by value. If it is a reference to a declaration, we just
9959 // pass its value.
9960 if (VD && (DevPointersMap.count(VD) || HasDevAddrsMap.count(VD))) {
9961 CurCaptureVarInfo.Exprs.push_back(VD);
9962 CurCaptureVarInfo.BasePointers.emplace_back(Arg);
9963 CurCaptureVarInfo.DevicePtrDecls.emplace_back(VD);
9964 CurCaptureVarInfo.DevicePointers.emplace_back(DeviceInfoTy::Pointer);
9965 CurCaptureVarInfo.Pointers.push_back(Arg);
9966 CurCaptureVarInfo.Sizes.push_back(CGF.Builder.CreateIntCast(
9967 CGF.getTypeSize(CGF.getContext().VoidPtrTy), CGF.Int64Ty,
9968 /*isSigned=*/true));
9969 CurCaptureVarInfo.Types.push_back(
9970 OpenMPOffloadMappingFlags::OMP_MAP_LITERAL |
9971 OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM);
9972 CurCaptureVarInfo.HasAttachPtr.push_back(false);
9973 CurCaptureVarInfo.Mappers.push_back(nullptr);
9974 return;
9975 }
9976
9977 auto GenerateInfoForComponentLists =
9978 [&](ArrayRef<MapData> DeclComponentListsFromClauses,
9979 bool IsEligibleForTargetParamFlag) {
9980 MapCombinedInfoTy CurInfoForComponentLists;
9981 StructRangeInfoTy PartialStruct;
9982 AttachInfoTy AttachInfo;
9983
9984 if (DeclComponentListsFromClauses.empty())
9985 return;
9986
9987 generateInfoForCaptureFromComponentLists(
9988 VD, DeclComponentListsFromClauses, CurInfoForComponentLists,
9989 PartialStruct, AttachInfo, IsEligibleForTargetParamFlag);
9990
9991 // If there is an entry in PartialStruct it means we have a
9992 // struct with individual members mapped. Emit an extra combined
9993 // entry.
9994 if (PartialStruct.Base.isValid()) {
9995 CurCaptureVarInfo.append(PartialStruct.PreliminaryMapData);
9996 emitCombinedEntry(
9997 CurCaptureVarInfo, CurInfoForComponentLists.Types,
9998 PartialStruct, AttachInfo, Cap->capturesThis(), OMPBuilder,
9999 /*VD=*/nullptr, OffsetForMemberOfFlag,
10000 /*NotTargetParams*/ !IsEligibleForTargetParamFlag);
10001 }
10002
10003 // We do the appends to get the entries in the following order:
10004 // combined-entry -> individual-field-entries -> attach-entry,
10005 CurCaptureVarInfo.append(CurInfoForComponentLists);
10006 if (AttachInfo.isValid())
10007 emitAttachEntry(CGF, CurCaptureVarInfo, AttachInfo);
10008 };
10009
10010 // Group component lists by their AttachPtrExpr and process them in order
10011 // of increasing complexity (nullptr first, then simple expressions like p,
10012 // then more complex ones like p[0], etc.)
10013 //
10014 // This ensure that we:
10015 // * handle maps that can contribute towards setting the kernel argument,
10016 // (e.g. map(ps), or map(ps[0])), before any that cannot (e.g. ps->pt->d).
10017 // * allocate a single contiguous storage for all exprs with the same
10018 // captured var and having the same attach-ptr.
10019 //
10020 // Example: The map clauses below should be handled grouped together based
10021 // on their attachable-base-pointers:
10022 // map-clause | attachable-base-pointer
10023 // --------------------------+------------------------
10024 // map(p, ps) | nullptr
10025 // map(p[0]) | p
10026 // map(p[0]->b, p[0]->c) | p[0]
10027 // map(ps->d, ps->e, ps->pt) | ps
10028 // map(ps->pt->d, ps->pt->e) | ps->pt
10029
10030 // First, collect all MapData entries with their attach-ptr exprs.
10031 SmallVector<std::pair<const Expr *, MapData>, 16> AttachPtrMapDataPairs;
10032
10033 for (const MapData &L : DeclComponentListsFromClauses) {
10035 std::get<0>(L);
10036 const Expr *AttachPtrExpr = getAttachPtrExpr(Components);
10037 AttachPtrMapDataPairs.emplace_back(AttachPtrExpr, L);
10038 }
10039
10040 // Next, sort by increasing order of their complexity.
10041 llvm::stable_sort(AttachPtrMapDataPairs,
10042 [this](const auto &LHS, const auto &RHS) {
10043 return AttachPtrComparator(LHS.first, RHS.first);
10044 });
10045
10046 bool NoDefaultMappingDoneForVD = CurCaptureVarInfo.BasePointers.empty();
10047 bool IsFirstGroup = true;
10048
10049 // And finally, process them all in order, grouping those with
10050 // equivalent attach-ptr exprs together.
10051 auto *It = AttachPtrMapDataPairs.begin();
10052 while (It != AttachPtrMapDataPairs.end()) {
10053 const Expr *AttachPtrExpr = It->first;
10054
10055 MapDataArrayTy GroupLists;
10056 while (It != AttachPtrMapDataPairs.end() &&
10057 (It->first == AttachPtrExpr ||
10058 AttachPtrComparator.areEqual(It->first, AttachPtrExpr))) {
10059 GroupLists.push_back(It->second);
10060 ++It;
10061 }
10062 assert(!GroupLists.empty() && "GroupLists should not be empty");
10063
10064 // Determine if this group of component-lists is eligible for TARGET_PARAM
10065 // flag. Only the first group processed should be eligible, and only if no
10066 // default mapping was done.
10067 bool IsEligibleForTargetParamFlag =
10068 IsFirstGroup && NoDefaultMappingDoneForVD;
10069
10070 GenerateInfoForComponentLists(GroupLists, IsEligibleForTargetParamFlag);
10071 IsFirstGroup = false;
10072 }
10073 }
10074
10075 /// Generate the base pointers, section pointers, sizes, map types, and
10076 /// mappers associated to \a DeclComponentLists for a given capture
10077 /// \a VD (all included in \a CurComponentListInfo).
10078 void generateInfoForCaptureFromComponentLists(
10079 const ValueDecl *VD, ArrayRef<MapData> DeclComponentLists,
10080 MapCombinedInfoTy &CurComponentListInfo, StructRangeInfoTy &PartialStruct,
10081 AttachInfoTy &AttachInfo, bool IsListEligibleForTargetParamFlag) const {
10082 // Find overlapping elements (including the offset from the base element).
10083 llvm::SmallDenseMap<
10084 const MapData *,
10085 llvm::SmallVector<
10087 4>
10088 OverlappedData;
10089 size_t Count = 0;
10090 for (const MapData &L : DeclComponentLists) {
10092 OpenMPMapClauseKind MapType;
10093 ArrayRef<OpenMPMapModifierKind> MapModifiers;
10094 bool IsImplicit;
10095 const ValueDecl *Mapper;
10096 const Expr *VarRef;
10097 std::tie(Components, MapType, MapModifiers, IsImplicit, Mapper, VarRef) =
10098 L;
10099 ++Count;
10100 for (const MapData &L1 : ArrayRef(DeclComponentLists).slice(Count)) {
10102 std::tie(Components1, MapType, MapModifiers, IsImplicit, Mapper,
10103 VarRef) = L1;
10104 auto CI = Components.rbegin();
10105 auto CE = Components.rend();
10106 auto SI = Components1.rbegin();
10107 auto SE = Components1.rend();
10108 for (; CI != CE && SI != SE; ++CI, ++SI) {
10109 if (CI->getAssociatedExpression()->getStmtClass() !=
10110 SI->getAssociatedExpression()->getStmtClass())
10111 break;
10112 // Are we dealing with different variables/fields?
10113 if (CI->getAssociatedDeclaration() != SI->getAssociatedDeclaration())
10114 break;
10115 }
10116 // Found overlapping if, at least for one component, reached the head
10117 // of the components list.
10118 if (CI == CE || SI == SE) {
10119 // Ignore it if it is the same component.
10120 if (CI == CE && SI == SE)
10121 continue;
10122 const auto It = (SI == SE) ? CI : SI;
10123 // If one component is a pointer and another one is a kind of
10124 // dereference of this pointer (array subscript, section, dereference,
10125 // etc.), it is not an overlapping.
10126 // Same, if one component is a base and another component is a
10127 // dereferenced pointer memberexpr with the same base.
10128 if (!isa<MemberExpr>(It->getAssociatedExpression()) ||
10129 (std::prev(It)->getAssociatedDeclaration() &&
10130 std::prev(It)
10131 ->getAssociatedDeclaration()
10132 ->getType()
10133 ->isPointerType()) ||
10134 (It->getAssociatedDeclaration() &&
10135 It->getAssociatedDeclaration()->getType()->isPointerType() &&
10136 std::next(It) != CE && std::next(It) != SE))
10137 continue;
10138 const MapData &BaseData = CI == CE ? L : L1;
10140 SI == SE ? Components : Components1;
10141 OverlappedData[&BaseData].push_back(SubData);
10142 }
10143 }
10144 }
10145 // Sort the overlapped elements for each item.
10146 llvm::SmallVector<const FieldDecl *, 4> Layout;
10147 if (!OverlappedData.empty()) {
10148 const Type *BaseType = VD->getType().getCanonicalType().getTypePtr();
10149 const Type *OrigType = BaseType->getPointeeOrArrayElementType();
10150 while (BaseType != OrigType) {
10151 BaseType = OrigType->getCanonicalTypeInternal().getTypePtr();
10152 OrigType = BaseType->getPointeeOrArrayElementType();
10153 }
10154
10155 if (const auto *CRD = BaseType->getAsCXXRecordDecl())
10156 getPlainLayout(CRD, Layout, /*AsBase=*/false);
10157 else {
10158 const auto *RD = BaseType->getAsRecordDecl();
10159 Layout.append(RD->field_begin(), RD->field_end());
10160 }
10161 }
10162 for (auto &Pair : OverlappedData) {
10163 llvm::stable_sort(
10164 Pair.getSecond(),
10165 [&Layout](
10168 Second) {
10169 auto CI = First.rbegin();
10170 auto CE = First.rend();
10171 auto SI = Second.rbegin();
10172 auto SE = Second.rend();
10173 for (; CI != CE && SI != SE; ++CI, ++SI) {
10174 if (CI->getAssociatedExpression()->getStmtClass() !=
10175 SI->getAssociatedExpression()->getStmtClass())
10176 break;
10177 // Are we dealing with different variables/fields?
10178 if (CI->getAssociatedDeclaration() !=
10179 SI->getAssociatedDeclaration())
10180 break;
10181 }
10182
10183 // Lists contain the same elements.
10184 if (CI == CE && SI == SE)
10185 return false;
10186
10187 // List with less elements is less than list with more elements.
10188 if (CI == CE || SI == SE)
10189 return CI == CE;
10190
10191 const auto *FD1 = cast<FieldDecl>(CI->getAssociatedDeclaration());
10192 const auto *FD2 = cast<FieldDecl>(SI->getAssociatedDeclaration());
10193 if (FD1->getParent() == FD2->getParent())
10194 return FD1->getFieldIndex() < FD2->getFieldIndex();
10195 const auto *It =
10196 llvm::find_if(Layout, [FD1, FD2](const FieldDecl *FD) {
10197 return FD == FD1 || FD == FD2;
10198 });
10199 return *It == FD1;
10200 });
10201 }
10202
10203 // Associated with a capture, because the mapping flags depend on it.
10204 // Go through all of the elements with the overlapped elements.
10205 bool AddTargetParamFlag = IsListEligibleForTargetParamFlag;
10206 MapCombinedInfoTy StructBaseCombinedInfo;
10207 for (const auto &Pair : OverlappedData) {
10208 const MapData &L = *Pair.getFirst();
10210 OpenMPMapClauseKind MapType;
10211 ArrayRef<OpenMPMapModifierKind> MapModifiers;
10212 bool IsImplicit;
10213 const ValueDecl *Mapper;
10214 const Expr *VarRef;
10215 std::tie(Components, MapType, MapModifiers, IsImplicit, Mapper, VarRef) =
10216 L;
10217 ArrayRef<OMPClauseMappableExprCommon::MappableExprComponentListRef>
10218 OverlappedComponents = Pair.getSecond();
10219 generateInfoForComponentList(
10220 MapType, MapModifiers, {}, Components, CurComponentListInfo,
10221 StructBaseCombinedInfo, PartialStruct, AttachInfo, AddTargetParamFlag,
10222 IsImplicit, /*GenerateAllInfoForClauses*/ false, Mapper,
10223 /*ForDeviceAddr=*/false, VD, VarRef, OverlappedComponents);
10224 AddTargetParamFlag = false;
10225 }
10226 // Go through other elements without overlapped elements.
10227 for (const MapData &L : DeclComponentLists) {
10229 OpenMPMapClauseKind MapType;
10230 ArrayRef<OpenMPMapModifierKind> MapModifiers;
10231 bool IsImplicit;
10232 const ValueDecl *Mapper;
10233 const Expr *VarRef;
10234 std::tie(Components, MapType, MapModifiers, IsImplicit, Mapper, VarRef) =
10235 L;
10236 auto It = OverlappedData.find(&L);
10237 if (It == OverlappedData.end())
10238 generateInfoForComponentList(
10239 MapType, MapModifiers, {}, Components, CurComponentListInfo,
10240 StructBaseCombinedInfo, PartialStruct, AttachInfo,
10241 AddTargetParamFlag, IsImplicit, /*GenerateAllInfoForClauses*/ false,
10242 Mapper, /*ForDeviceAddr=*/false, VD, VarRef,
10243 /*OverlappedElements*/ {});
10244 AddTargetParamFlag = false;
10245 }
10246 }
10247
10248 /// Check if a variable should be treated as firstprivate due to explicit
10249 /// firstprivate clause or defaultmap(firstprivate:...).
10250 bool isEffectivelyFirstprivate(const VarDecl *VD, QualType Type) const {
10251 // Check explicit firstprivate clauses (not implicit from defaultmap)
10252 auto I = FirstPrivateDecls.find(VD);
10253 if (I != FirstPrivateDecls.end() && !I->getSecond())
10254 return true; // Explicit firstprivate only
10255
10256 // Check defaultmap(firstprivate:scalar) for scalar types
10257 if (DefaultmapFirstprivateKinds.count(OMPC_DEFAULTMAP_scalar)) {
10258 if (Type->isScalarType())
10259 return true;
10260 }
10261
10262 // Check defaultmap(firstprivate:pointer) for pointer types
10263 if (DefaultmapFirstprivateKinds.count(OMPC_DEFAULTMAP_pointer)) {
10264 if (Type->isAnyPointerType())
10265 return true;
10266 }
10267
10268 // Check defaultmap(firstprivate:aggregate) for aggregate types
10269 if (DefaultmapFirstprivateKinds.count(OMPC_DEFAULTMAP_aggregate)) {
10270 if (Type->isAggregateType())
10271 return true;
10272 }
10273
10274 // Check defaultmap(firstprivate:all) for all types
10275 return DefaultmapFirstprivateKinds.count(OMPC_DEFAULTMAP_all);
10276 }
10277
10278 /// Generate the default map information for a given capture \a CI,
10279 /// record field declaration \a RI and captured value \a CV.
10280 void generateDefaultMapInfo(const CapturedStmt::Capture &CI,
10281 const FieldDecl &RI, llvm::Value *CV,
10282 MapCombinedInfoTy &CombinedInfo) const {
10283 bool IsImplicit = true;
10284 // Do the default mapping.
10285 if (CI.capturesThis()) {
10286 CombinedInfo.Exprs.push_back(nullptr);
10287 CombinedInfo.BasePointers.push_back(CV);
10288 CombinedInfo.DevicePtrDecls.push_back(nullptr);
10289 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
10290 CombinedInfo.Pointers.push_back(CV);
10291 const auto *PtrTy = cast<PointerType>(RI.getType().getTypePtr());
10292 CombinedInfo.Sizes.push_back(
10293 CGF.Builder.CreateIntCast(CGF.getTypeSize(PtrTy->getPointeeType()),
10294 CGF.Int64Ty, /*isSigned=*/true));
10295 // Default map type.
10296 CombinedInfo.Types.push_back(OpenMPOffloadMappingFlags::OMP_MAP_TO |
10297 OpenMPOffloadMappingFlags::OMP_MAP_FROM);
10298 } else if (CI.capturesVariableByCopy()) {
10299 const VarDecl *VD = CI.getCapturedVar();
10300 CombinedInfo.Exprs.push_back(VD->getCanonicalDecl());
10301 CombinedInfo.BasePointers.push_back(CV);
10302 CombinedInfo.DevicePtrDecls.push_back(nullptr);
10303 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
10304 CombinedInfo.Pointers.push_back(CV);
10305 bool IsFirstprivate =
10306 isEffectivelyFirstprivate(VD, RI.getType().getNonReferenceType());
10307
10308 if (!RI.getType()->isAnyPointerType()) {
10309 // We have to signal to the runtime captures passed by value that are
10310 // not pointers.
10311 CombinedInfo.Types.push_back(
10312 OpenMPOffloadMappingFlags::OMP_MAP_LITERAL);
10313 CombinedInfo.Sizes.push_back(CGF.Builder.CreateIntCast(
10314 CGF.getTypeSize(RI.getType()), CGF.Int64Ty, /*isSigned=*/true));
10315 } else if (IsFirstprivate) {
10316 // Firstprivate pointers should be passed by value (as literals)
10317 // without performing a present table lookup at runtime.
10318 CombinedInfo.Types.push_back(
10319 OpenMPOffloadMappingFlags::OMP_MAP_LITERAL);
10320 // Use zero size for pointer literals (just passing the pointer value)
10321 CombinedInfo.Sizes.push_back(llvm::Constant::getNullValue(CGF.Int64Ty));
10322 } else {
10323 // Pointers are implicitly mapped with a zero size and no flags
10324 // (other than first map that is added for all implicit maps).
10325 CombinedInfo.Types.push_back(OpenMPOffloadMappingFlags::OMP_MAP_NONE);
10326 CombinedInfo.Sizes.push_back(llvm::Constant::getNullValue(CGF.Int64Ty));
10327 }
10328 auto I = FirstPrivateDecls.find(VD);
10329 if (I != FirstPrivateDecls.end())
10330 IsImplicit = I->getSecond();
10331 } else {
10332 assert(CI.capturesVariable() && "Expected captured reference.");
10333 const auto *PtrTy = cast<ReferenceType>(RI.getType().getTypePtr());
10334 QualType ElementType = PtrTy->getPointeeType();
10335 const VarDecl *VD = CI.getCapturedVar();
10336 bool IsFirstprivate = isEffectivelyFirstprivate(VD, ElementType);
10337 CombinedInfo.Exprs.push_back(VD->getCanonicalDecl());
10338 CombinedInfo.BasePointers.push_back(CV);
10339 CombinedInfo.DevicePtrDecls.push_back(nullptr);
10340 CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
10341
10342 // For firstprivate pointers, pass by value instead of dereferencing
10343 if (IsFirstprivate && ElementType->isAnyPointerType()) {
10344 // Treat as a literal value (pass the pointer value itself)
10345 CombinedInfo.Pointers.push_back(CV);
10346 // Use zero size for pointer literals
10347 CombinedInfo.Sizes.push_back(llvm::Constant::getNullValue(CGF.Int64Ty));
10348 CombinedInfo.Types.push_back(
10349 OpenMPOffloadMappingFlags::OMP_MAP_LITERAL);
10350 } else {
10351 CombinedInfo.Sizes.push_back(CGF.Builder.CreateIntCast(
10352 CGF.getTypeSize(ElementType), CGF.Int64Ty, /*isSigned=*/true));
10353 // The default map type for a scalar/complex type is 'to' because by
10354 // default the value doesn't have to be retrieved. For an aggregate
10355 // type, the default is 'tofrom'.
10356 CombinedInfo.Types.push_back(getMapModifiersForPrivateClauses(CI));
10357 CombinedInfo.Pointers.push_back(CV);
10358 }
10359 auto I = FirstPrivateDecls.find(VD);
10360 if (I != FirstPrivateDecls.end())
10361 IsImplicit = I->getSecond();
10362 }
10363 // Every default map produces a single argument which is a target parameter.
10364 CombinedInfo.Types.back() |=
10365 OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM;
10366
10367 // Add flag stating this is an implicit map.
10368 if (IsImplicit)
10369 CombinedInfo.Types.back() |= OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT;
10370
10371 CombinedInfo.HasAttachPtr.push_back(false);
10372 // No user-defined mapper for default mapping.
10373 CombinedInfo.Mappers.push_back(nullptr);
10374 }
10375};
10376} // anonymous namespace
10377
10378// Try to extract the base declaration from a `this->x` expression if possible.
10380 if (!E)
10381 return nullptr;
10382
10383 if (const auto *OASE = dyn_cast<ArraySectionExpr>(E->IgnoreParenCasts()))
10384 if (const MemberExpr *ME =
10385 dyn_cast<MemberExpr>(OASE->getBase()->IgnoreParenImpCasts()))
10386 return ME->getMemberDecl();
10387 return nullptr;
10388}
10389
10390/// Emit a string constant containing the names of the values mapped to the
10391/// offloading runtime library.
10392static llvm::Constant *
10393emitMappingInformation(CodeGenFunction &CGF, llvm::OpenMPIRBuilder &OMPBuilder,
10394 MappableExprsHandler::MappingExprInfo &MapExprs) {
10395
10396 uint32_t SrcLocStrSize;
10397 if (!MapExprs.getMapDecl() && !MapExprs.getMapExpr())
10398 return OMPBuilder.getOrCreateDefaultSrcLocStr(SrcLocStrSize);
10399
10400 SourceLocation Loc;
10401 if (!MapExprs.getMapDecl() && MapExprs.getMapExpr()) {
10402 if (const ValueDecl *VD = getDeclFromThisExpr(MapExprs.getMapExpr()))
10403 Loc = VD->getLocation();
10404 else
10405 Loc = MapExprs.getMapExpr()->getExprLoc();
10406 } else {
10407 Loc = MapExprs.getMapDecl()->getLocation();
10408 }
10409
10410 std::string ExprName;
10411 if (MapExprs.getMapExpr()) {
10413 llvm::raw_string_ostream OS(ExprName);
10414 MapExprs.getMapExpr()->printPretty(OS, nullptr, P);
10415 } else {
10416 ExprName = MapExprs.getMapDecl()->getNameAsString();
10417 }
10418
10419 std::string FileName;
10421 if (auto *DbgInfo = CGF.getDebugInfo())
10422 FileName = DbgInfo->remapDIPath(PLoc.getFilename());
10423 else
10424 FileName = PLoc.getFilename();
10425 return OMPBuilder.getOrCreateSrcLocStr(FileName, ExprName, PLoc.getLine(),
10426 PLoc.getColumn(), SrcLocStrSize);
10427}
10428/// Emit the arrays used to pass the captures and map information to the
10429/// offloading runtime library. If there is no map or capture information,
10430/// return nullptr by reference.
10432 CodeGenFunction &CGF, MappableExprsHandler::MapCombinedInfoTy &CombinedInfo,
10433 CGOpenMPRuntime::TargetDataInfo &Info, llvm::OpenMPIRBuilder &OMPBuilder,
10434 bool IsNonContiguous = false, bool ForEndCall = false) {
10435 CodeGenModule &CGM = CGF.CGM;
10436
10437 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
10438 InsertPointTy AllocaIP(CGF.AllocaInsertPt->getParent(),
10439 CGF.AllocaInsertPt->getIterator());
10440 InsertPointTy CodeGenIP(CGF.Builder.GetInsertBlock(),
10441 CGF.Builder.GetInsertPoint());
10442
10443 auto DeviceAddrCB = [&](unsigned int I, llvm::Value *NewDecl) {
10444 if (const ValueDecl *DevVD = CombinedInfo.DevicePtrDecls[I]) {
10445 Info.CaptureDeviceAddrMap.try_emplace(DevVD, NewDecl);
10446 }
10447 };
10448
10449 auto CustomMapperCB = [&](unsigned int I) {
10450 llvm::Function *MFunc = nullptr;
10451 if (CombinedInfo.Mappers[I]) {
10452 Info.HasMapper = true;
10454 cast<OMPDeclareMapperDecl>(CombinedInfo.Mappers[I]));
10455 }
10456 return MFunc;
10457 };
10458 cantFail(OMPBuilder.emitOffloadingArraysAndArgs(
10459 AllocaIP, CodeGenIP, Info, Info.RTArgs, CombinedInfo, CustomMapperCB,
10460 IsNonContiguous, ForEndCall, DeviceAddrCB));
10461}
10462
10463/// Check for inner distribute directive.
10464static const OMPExecutableDirective *
10466 const auto *CS = D.getInnermostCapturedStmt();
10467 const auto *Body =
10468 CS->getCapturedStmt()->IgnoreContainers(/*IgnoreCaptured=*/true);
10469 const Stmt *ChildStmt =
10471
10472 if (const auto *NestedDir =
10473 dyn_cast_or_null<OMPExecutableDirective>(ChildStmt)) {
10474 OpenMPDirectiveKind DKind = NestedDir->getDirectiveKind();
10475 switch (D.getDirectiveKind()) {
10476 case OMPD_target:
10477 // For now, treat 'target' with nested 'teams loop' as if it's
10478 // distributed (target teams distribute).
10479 if (isOpenMPDistributeDirective(DKind) || DKind == OMPD_teams_loop)
10480 return NestedDir;
10481 if (DKind == OMPD_teams) {
10482 Body = NestedDir->getInnermostCapturedStmt()->IgnoreContainers(
10483 /*IgnoreCaptured=*/true);
10484 if (!Body)
10485 return nullptr;
10486 ChildStmt = CGOpenMPSIMDRuntime::getSingleCompoundChild(Ctx, Body);
10487 if (const auto *NND =
10488 dyn_cast_or_null<OMPExecutableDirective>(ChildStmt)) {
10489 DKind = NND->getDirectiveKind();
10490 if (isOpenMPDistributeDirective(DKind))
10491 return NND;
10492 }
10493 }
10494 return nullptr;
10495 case OMPD_target_teams:
10496 if (isOpenMPDistributeDirective(DKind))
10497 return NestedDir;
10498 return nullptr;
10499 case OMPD_target_parallel:
10500 case OMPD_target_simd:
10501 case OMPD_target_parallel_for:
10502 case OMPD_target_parallel_for_simd:
10503 return nullptr;
10504 case OMPD_target_teams_distribute:
10505 case OMPD_target_teams_distribute_simd:
10506 case OMPD_target_teams_distribute_parallel_for:
10507 case OMPD_target_teams_distribute_parallel_for_simd:
10508 case OMPD_parallel:
10509 case OMPD_for:
10510 case OMPD_parallel_for:
10511 case OMPD_parallel_master:
10512 case OMPD_parallel_sections:
10513 case OMPD_for_simd:
10514 case OMPD_parallel_for_simd:
10515 case OMPD_cancel:
10516 case OMPD_cancellation_point:
10517 case OMPD_ordered_standalone:
10518 case OMPD_ordered_blockassoc:
10519 case OMPD_threadprivate:
10520 case OMPD_allocate:
10521 case OMPD_task:
10522 case OMPD_simd:
10523 case OMPD_tile:
10524 case OMPD_unroll:
10525 case OMPD_sections:
10526 case OMPD_section:
10527 case OMPD_single:
10528 case OMPD_master:
10529 case OMPD_critical:
10530 case OMPD_taskyield:
10531 case OMPD_barrier:
10532 case OMPD_taskwait:
10533 case OMPD_taskgroup:
10534 case OMPD_atomic:
10535 case OMPD_flush:
10536 case OMPD_depobj:
10537 case OMPD_scan:
10538 case OMPD_teams:
10539 case OMPD_target_data:
10540 case OMPD_target_exit_data:
10541 case OMPD_target_enter_data:
10542 case OMPD_distribute:
10543 case OMPD_distribute_simd:
10544 case OMPD_distribute_parallel_for:
10545 case OMPD_distribute_parallel_for_simd:
10546 case OMPD_teams_distribute:
10547 case OMPD_teams_distribute_simd:
10548 case OMPD_teams_distribute_parallel_for:
10549 case OMPD_teams_distribute_parallel_for_simd:
10550 case OMPD_target_update:
10551 case OMPD_declare_simd:
10552 case OMPD_declare_variant:
10553 case OMPD_begin_declare_variant:
10554 case OMPD_end_declare_variant:
10555 case OMPD_declare_target:
10556 case OMPD_end_declare_target:
10557 case OMPD_declare_reduction:
10558 case OMPD_declare_mapper:
10559 case OMPD_taskloop:
10560 case OMPD_taskloop_simd:
10561 case OMPD_master_taskloop:
10562 case OMPD_master_taskloop_simd:
10563 case OMPD_parallel_master_taskloop:
10564 case OMPD_parallel_master_taskloop_simd:
10565 case OMPD_requires:
10566 case OMPD_metadirective:
10567 case OMPD_unknown:
10568 default:
10569 llvm_unreachable("Unexpected directive.");
10570 }
10571 }
10572
10573 return nullptr;
10574}
10575
10576/// Emit the user-defined mapper function. The code generation follows the
10577/// pattern in the example below.
10578/// \code
10579/// void .omp_mapper.<type_name>.<mapper_id>.(void *rt_mapper_handle,
10580/// void *base, void *begin,
10581/// int64_t size, int64_t type,
10582/// void *name = nullptr) {
10583/// // Allocate space for an array section first.
10584/// if ((size > 1 || (base != begin)) && !maptype.IsDelete)
10585/// __tgt_push_mapper_component(rt_mapper_handle, base, begin,
10586/// size*sizeof(Ty), clearToFromMember(type));
10587/// // Map members.
10588/// for (unsigned i = 0; i < size; i++) {
10589/// N = __tgt_mapper_num_components(rt_mapper_handle);
10590/// // For each component specified by this mapper:
10591/// for (auto c : begin[i]->all_components) {
10592/// // MEMBER_OF grouping: tie this component to the current array element
10593/// // (component N) by adding N<<48. Exceptions:
10594/// // - ATTACH entries are not members of any struct storage range.
10595/// // - Pointee entries (reached via a pointer member) occupy separate
10596/// // storage; their inner MEMBER_OF bits are shifted by N instead.
10597/// if (c.isAttach() || c.isPointee())
10598/// member_type = c.arg_type + (c.hasInnerMemberOf() ? N<<48 : 0);
10599/// else
10600/// member_type = c.arg_type + N<<48;
10601/// // Map-type-modifying bits (ALWAYS, DELETE, CLOSE) from the outer map
10602/// // clause are propagated to each component, except ATTACH entries
10603/// // (ATTACH|ALWAYS is reserved for attach(always), and other modifier
10604/// // bits have no meaning for ATTACH). PRESENT is additionally
10605/// // propagated to components with HasAttachPtr (the pointee data) at
10606/// // OpenMP >= 6.0.
10607/// present_bit = (v60 && c.hasAttachPtr()) ? PRESENT : 0;
10608/// imported_modifier_bits =
10609/// type & (ALWAYS | DELETE | CLOSE | present_bit);
10610/// effective_type = c.isAttach() ? member_type
10611/// : member_type | imported_modifier_bits;
10612/// if (c.hasMapper())
10613/// (*c.Mapper())(rt_mapper_handle, c.arg_base, c.arg_begin, c.arg_size,
10614/// effective_type, c.arg_name);
10615/// else
10616/// __tgt_push_mapper_component(rt_mapper_handle, c.arg_base,
10617/// c.arg_begin, c.arg_size, effective_type,
10618/// c.arg_name);
10619/// }
10620/// }
10621/// // Delete the array section.
10622/// if (size > 1 && maptype.IsDelete)
10623/// __tgt_push_mapper_component(rt_mapper_handle, base, begin,
10624/// size*sizeof(Ty), clearToFromMember(type));
10625/// }
10626/// \endcode
10628 CodeGenFunction *CGF) {
10629 if (UDMMap.count(D) > 0)
10630 return;
10631 ASTContext &C = CGM.getContext();
10632 QualType Ty = D->getType();
10633 auto *MapperVarDecl =
10635 CharUnits ElementSize = C.getTypeSizeInChars(Ty);
10636 llvm::Type *ElemTy = CGM.getTypes().ConvertTypeForMem(Ty);
10637
10638 CodeGenFunction MapperCGF(CGM);
10639 MappableExprsHandler::MapCombinedInfoTy CombinedInfo;
10640 auto PrivatizeAndGenMapInfoCB =
10641 [&](llvm::OpenMPIRBuilder::InsertPointTy CodeGenIP, llvm::Value *PtrPHI,
10642 llvm::Value *BeginArg) -> llvm::OpenMPIRBuilder::MapInfosTy & {
10643 MapperCGF.Builder.restoreIP(CodeGenIP);
10644
10645 // Privatize the declared variable of mapper to be the current array
10646 // element.
10647 Address PtrCurrent(
10648 PtrPHI, ElemTy,
10649 Address(BeginArg, MapperCGF.VoidPtrTy, CGM.getPointerAlign())
10650 .getAlignment()
10651 .alignmentOfArrayElement(ElementSize));
10653 Scope.addPrivate(MapperVarDecl, PtrCurrent);
10654 (void)Scope.Privatize();
10655
10656 // Get map clause information.
10657 MappableExprsHandler MEHandler(*D, MapperCGF);
10658 MEHandler.generateAllInfoForMapper(CombinedInfo, OMPBuilder);
10659
10660 auto FillInfoMap = [&](MappableExprsHandler::MappingExprInfo &MapExpr) {
10661 return emitMappingInformation(MapperCGF, OMPBuilder, MapExpr);
10662 };
10663 if (CGM.getCodeGenOpts().getDebugInfo() !=
10664 llvm::codegenoptions::NoDebugInfo) {
10665 CombinedInfo.Names.resize(CombinedInfo.Exprs.size());
10666 llvm::transform(CombinedInfo.Exprs, CombinedInfo.Names.begin(),
10667 FillInfoMap);
10668 }
10669
10670 return CombinedInfo;
10671 };
10672
10673 auto CustomMapperCB = [&](unsigned I) {
10674 llvm::Function *MapperFunc = nullptr;
10675 if (CombinedInfo.Mappers[I]) {
10676 // Call the corresponding mapper function.
10678 cast<OMPDeclareMapperDecl>(CombinedInfo.Mappers[I]));
10679 assert(MapperFunc && "Expect a valid mapper function is available.");
10680 }
10681 return MapperFunc;
10682 };
10683
10684 SmallString<64> TyStr;
10685 llvm::raw_svector_ostream Out(TyStr);
10686 CGM.getCXXABI().getMangleContext().mangleCanonicalTypeName(Ty, Out);
10687 std::string Name = getName({"omp_mapper", TyStr, D->getName()});
10688
10689 // Propagate the PRESENT modifier to the pointee entries (those with
10690 // HasAttachPtr) only for OpenMP >= 6.0; before 6.0 the present modifier does
10691 // not apply to the pointee (see the OpenMP 6.0 erratum on the present motion
10692 // vs. map-type modifier divergence).
10693 bool PropagatePresentToPointee = CGM.getLangOpts().OpenMP >= 60;
10694 llvm::Function *NewFn = cantFail(OMPBuilder.emitUserDefinedMapper(
10695 PrivatizeAndGenMapInfoCB, ElemTy, Name, CustomMapperCB,
10696 /*PreserveMemberOfFlags=*/false, PropagatePresentToPointee));
10697 UDMMap.try_emplace(D, NewFn);
10698 if (CGF)
10699 FunctionUDMMap[CGF->CurFn].push_back(D);
10700}
10701
10703 const OMPDeclareMapperDecl *D) {
10704 auto I = UDMMap.find(D);
10705 if (I != UDMMap.end())
10706 return I->second;
10708 return UDMMap.lookup(D);
10709}
10710
10713 llvm::function_ref<llvm::Value *(CodeGenFunction &CGF,
10714 const OMPLoopDirective &D)>
10715 SizeEmitter) {
10716 OpenMPDirectiveKind Kind = D.getDirectiveKind();
10717 const OMPExecutableDirective *TD = &D;
10718 // Get nested teams distribute kind directive, if any. For now, treat
10719 // 'target_teams_loop' as if it's really a target_teams_distribute.
10720 if ((!isOpenMPDistributeDirective(Kind) || !isOpenMPTeamsDirective(Kind)) &&
10721 Kind != OMPD_target_teams_loop)
10722 TD = getNestedDistributeDirective(CGM.getContext(), D);
10723 if (!TD)
10724 return llvm::ConstantInt::get(CGF.Int64Ty, 0);
10725
10726 const auto *LD = cast<OMPLoopDirective>(TD);
10727 if (llvm::Value *NumIterations = SizeEmitter(CGF, *LD))
10728 return NumIterations;
10729 return llvm::ConstantInt::get(CGF.Int64Ty, 0);
10730}
10731
10732static void
10733emitTargetCallFallback(CGOpenMPRuntime *OMPRuntime, llvm::Function *OutlinedFn,
10734 const OMPExecutableDirective &D,
10736 bool RequiresOuterTask, const CapturedStmt &CS,
10737 bool OffloadingMandatory, CodeGenFunction &CGF) {
10738 if (OffloadingMandatory) {
10739 CGF.Builder.CreateUnreachable();
10740 } else {
10741 if (RequiresOuterTask) {
10742 CapturedVars.clear();
10743 CGF.GenerateOpenMPCapturedVars(CS, CapturedVars);
10744 }
10745 llvm::SmallVector<llvm::Value *, 16> Args(CapturedVars.begin(),
10746 CapturedVars.end());
10747 Args.push_back(llvm::Constant::getNullValue(CGF.Builder.getPtrTy()));
10748 OMPRuntime->emitOutlinedFunctionCall(CGF, D.getBeginLoc(), OutlinedFn,
10749 Args);
10750 }
10751}
10752
10753static llvm::Value *emitDeviceID(
10754 llvm::PointerIntPair<const Expr *, 2, OpenMPDeviceClauseModifier> Device,
10755 CodeGenFunction &CGF) {
10756 // Emit device ID if any.
10757 llvm::Value *DeviceID;
10758 if (Device.getPointer()) {
10759 assert((Device.getInt() == OMPC_DEVICE_unknown ||
10760 Device.getInt() == OMPC_DEVICE_device_num) &&
10761 "Expected device_num modifier.");
10762 llvm::Value *DevVal = CGF.EmitScalarExpr(Device.getPointer());
10763 DeviceID =
10764 CGF.Builder.CreateIntCast(DevVal, CGF.Int64Ty, /*isSigned=*/true);
10765 } else {
10766 DeviceID = CGF.Builder.getInt64(OMP_DEVICEID_UNDEF);
10767 }
10768 return DeviceID;
10769}
10770
10771static std::pair<llvm::Value *, OMPDynGroupprivateFallbackType>
10773 llvm::Value *DynGP = CGF.Builder.getInt32(0);
10774 auto DynGPFallback = OMPDynGroupprivateFallbackType::Abort;
10775
10776 if (auto *DynGPClause = D.getSingleClause<OMPDynGroupprivateClause>()) {
10777 CodeGenFunction::RunCleanupsScope DynGPScope(CGF);
10778 llvm::Value *DynGPVal =
10779 CGF.EmitScalarExpr(DynGPClause->getSize(), /*IgnoreResultAssign=*/true);
10780 DynGP = CGF.Builder.CreateIntCast(DynGPVal, CGF.Int32Ty,
10781 /*isSigned=*/false);
10782 auto FallbackModifier = DynGPClause->getDynGroupprivateFallbackModifier();
10783 switch (FallbackModifier) {
10784 case OMPC_DYN_GROUPPRIVATE_FALLBACK_abort:
10785 DynGPFallback = OMPDynGroupprivateFallbackType::Abort;
10786 break;
10787 case OMPC_DYN_GROUPPRIVATE_FALLBACK_null:
10788 DynGPFallback = OMPDynGroupprivateFallbackType::Null;
10789 break;
10790 case OMPC_DYN_GROUPPRIVATE_FALLBACK_default_mem:
10792 // This is the default for dyn_groupprivate.
10793 DynGPFallback = OMPDynGroupprivateFallbackType::DefaultMem;
10794 break;
10795 default:
10796 llvm_unreachable("Unknown fallback modifier for OpenMP dyn_groupprivate");
10797 }
10798 } else if (auto *OMPXDynCGClause =
10799 D.getSingleClause<OMPXDynCGroupMemClause>()) {
10800 CodeGenFunction::RunCleanupsScope DynCGMemScope(CGF);
10801 llvm::Value *DynCGMemVal = CGF.EmitScalarExpr(OMPXDynCGClause->getSize(),
10802 /*IgnoreResultAssign=*/true);
10803 DynGP = CGF.Builder.CreateIntCast(DynCGMemVal, CGF.Int32Ty,
10804 /*isSigned=*/false);
10805 }
10806 return {DynGP, DynGPFallback};
10807}
10808
10810 MappableExprsHandler &MEHandler, CodeGenFunction &CGF,
10811 const CapturedStmt &CS, llvm::SmallVectorImpl<llvm::Value *> &CapturedVars,
10812 llvm::OpenMPIRBuilder &OMPBuilder,
10813 llvm::DenseSet<CanonicalDeclPtr<const Decl>> &MappedVarSet,
10814 MappableExprsHandler::MapCombinedInfoTy &CombinedInfo) {
10815
10816 llvm::DenseMap<llvm::Value *, llvm::Value *> LambdaPointers;
10817 auto RI = CS.getCapturedRecordDecl()->field_begin();
10818 auto *CV = CapturedVars.begin();
10820 CE = CS.capture_end();
10821 CI != CE; ++CI, ++RI, ++CV) {
10822 MappableExprsHandler::MapCombinedInfoTy CurInfo;
10823
10824 // VLA sizes are passed to the outlined region by copy and do not have map
10825 // information associated.
10826 if (CI->capturesVariableArrayType()) {
10827 CurInfo.Exprs.push_back(nullptr);
10828 CurInfo.BasePointers.push_back(*CV);
10829 CurInfo.DevicePtrDecls.push_back(nullptr);
10830 CurInfo.DevicePointers.push_back(
10831 MappableExprsHandler::DeviceInfoTy::None);
10832 CurInfo.Pointers.push_back(*CV);
10833 CurInfo.Sizes.push_back(CGF.Builder.CreateIntCast(
10834 CGF.getTypeSize(RI->getType()), CGF.Int64Ty, /*isSigned=*/true));
10835 // Copy to the device as an argument. No need to retrieve it.
10836 CurInfo.Types.push_back(OpenMPOffloadMappingFlags::OMP_MAP_LITERAL |
10837 OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM |
10838 OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT);
10839 CurInfo.HasAttachPtr.push_back(false);
10840 CurInfo.Mappers.push_back(nullptr);
10841 } else {
10842 const ValueDecl *CapturedVD =
10843 CI->capturesThis() ? nullptr
10845 bool HasEntryWithCVAsAttachPtr = false;
10846 if (CapturedVD)
10847 HasEntryWithCVAsAttachPtr =
10848 MEHandler.hasAttachEntryForCapturedVar(CapturedVD);
10849
10850 // Populate component lists for the captured variable from clauses.
10851 MappableExprsHandler::MapDataArrayTy DeclComponentLists;
10854 StorageForImplicitlyAddedComponentLists;
10855 MEHandler.populateComponentListsForNonLambdaCaptureFromClauses(
10856 CapturedVD, DeclComponentLists,
10857 StorageForImplicitlyAddedComponentLists);
10858
10859 // OpenMP 6.0, 15.8, target construct, restrictions:
10860 // * A list item in a map clause that is specified on a target construct
10861 // must have a base variable or base pointer.
10862 //
10863 // Map clauses on a target construct must either have a base pointer, or a
10864 // base-variable. So, if we don't have a base-pointer, that means that it
10865 // must have a base-variable, i.e. we have a map like `map(s)`, `map(s.x)`
10866 // etc. In such cases, we do not need to handle default map generation
10867 // for `s`.
10868 bool HasEntryWithoutAttachPtr =
10869 llvm::any_of(DeclComponentLists, [&](const auto &MapData) {
10871 Components = std::get<0>(MapData);
10872 return !MEHandler.getAttachPtrExpr(Components);
10873 });
10874
10875 // Generate default map info first if there's no direct map with CV as
10876 // the base-variable, or attach pointer.
10877 if (DeclComponentLists.empty() ||
10878 (!HasEntryWithCVAsAttachPtr && !HasEntryWithoutAttachPtr))
10879 MEHandler.generateDefaultMapInfo(*CI, **RI, *CV, CurInfo);
10880
10881 // If we have any information in the map clause, we use it, otherwise we
10882 // just do a default mapping.
10883 MEHandler.generateInfoForCaptureFromClauseInfo(
10884 DeclComponentLists, CI, *CV, CurInfo, OMPBuilder,
10885 /*OffsetForMemberOfFlag=*/CombinedInfo.BasePointers.size());
10886
10887 if (!CI->capturesThis())
10888 MappedVarSet.insert(CI->getCapturedVar());
10889 else
10890 MappedVarSet.insert(nullptr);
10891
10892 // Generate correct mapping for variables captured by reference in
10893 // lambdas.
10894 if (CI->capturesVariable())
10895 MEHandler.generateInfoForLambdaCaptures(CI->getCapturedVar(), *CV,
10896 CurInfo, LambdaPointers);
10897 }
10898 // We expect to have at least an element of information for this capture.
10899 assert(!CurInfo.BasePointers.empty() &&
10900 "Non-existing map pointer for capture!");
10901 assert(CurInfo.BasePointers.size() == CurInfo.Pointers.size() &&
10902 CurInfo.BasePointers.size() == CurInfo.Sizes.size() &&
10903 CurInfo.BasePointers.size() == CurInfo.Types.size() &&
10904 CurInfo.BasePointers.size() == CurInfo.Mappers.size() &&
10905 "Inconsistent map information sizes!");
10906
10907 // We need to append the results of this capture to what we already have.
10908 CombinedInfo.append(CurInfo);
10909 }
10910 // Adjust MEMBER_OF flags for the lambdas captures.
10911 MEHandler.adjustMemberOfForLambdaCaptures(
10912 OMPBuilder, LambdaPointers, CombinedInfo.BasePointers,
10913 CombinedInfo.Pointers, CombinedInfo.Types);
10914}
10915static void
10916genMapInfo(MappableExprsHandler &MEHandler, CodeGenFunction &CGF,
10917 MappableExprsHandler::MapCombinedInfoTy &CombinedInfo,
10918 llvm::OpenMPIRBuilder &OMPBuilder,
10919 const llvm::DenseSet<CanonicalDeclPtr<const Decl>> &SkippedVarSet =
10920 llvm::DenseSet<CanonicalDeclPtr<const Decl>>()) {
10921
10922 CodeGenModule &CGM = CGF.CGM;
10923 // Map any list items in a map clause that were not captures because they
10924 // weren't referenced within the construct.
10925 MEHandler.generateAllInfo(CombinedInfo, OMPBuilder, SkippedVarSet);
10926
10927 auto FillInfoMap = [&](MappableExprsHandler::MappingExprInfo &MapExpr) {
10928 return emitMappingInformation(CGF, OMPBuilder, MapExpr);
10929 };
10930 if (CGM.getCodeGenOpts().getDebugInfo() !=
10931 llvm::codegenoptions::NoDebugInfo) {
10932 CombinedInfo.Names.resize(CombinedInfo.Exprs.size());
10933 llvm::transform(CombinedInfo.Exprs, CombinedInfo.Names.begin(),
10934 FillInfoMap);
10935 }
10936}
10937
10939 const CapturedStmt &CS,
10941 llvm::OpenMPIRBuilder &OMPBuilder,
10942 MappableExprsHandler::MapCombinedInfoTy &CombinedInfo) {
10943 // Get mappable expression information.
10944 MappableExprsHandler MEHandler(D, CGF);
10945 llvm::DenseSet<CanonicalDeclPtr<const Decl>> MappedVarSet;
10946
10947 genMapInfoForCaptures(MEHandler, CGF, CS, CapturedVars, OMPBuilder,
10948 MappedVarSet, CombinedInfo);
10949 genMapInfo(MEHandler, CGF, CombinedInfo, OMPBuilder, MappedVarSet);
10950}
10951
10952template <typename ClauseTy>
10953static void
10955 const OMPExecutableDirective &D,
10957 const auto *C = D.getSingleClause<ClauseTy>();
10958 assert(!C->varlist_empty() &&
10959 "ompx_bare requires explicit num_teams and thread_limit");
10961 for (auto *E : C->varlist()) {
10962 llvm::Value *V = CGF.EmitScalarExpr(E);
10963 Values.push_back(
10964 CGF.Builder.CreateIntCast(V, CGF.Int32Ty, /*isSigned=*/true));
10965 }
10966}
10967
10969 CGOpenMPRuntime *OMPRuntime, llvm::Function *OutlinedFn,
10970 const OMPExecutableDirective &D,
10971 llvm::SmallVectorImpl<llvm::Value *> &CapturedVars, bool RequiresOuterTask,
10972 const CapturedStmt &CS, bool OffloadingMandatory,
10973 llvm::PointerIntPair<const Expr *, 2, OpenMPDeviceClauseModifier> Device,
10974 llvm::Value *OutlinedFnID, CodeGenFunction::OMPTargetDataInfo &InputInfo,
10975 llvm::Value *&MapTypesArray, llvm::Value *&MapNamesArray,
10976 llvm::function_ref<llvm::Value *(CodeGenFunction &CGF,
10977 const OMPLoopDirective &D)>
10978 SizeEmitter,
10979 CodeGenFunction &CGF, CodeGenModule &CGM) {
10980 llvm::OpenMPIRBuilder &OMPBuilder = OMPRuntime->getOMPBuilder();
10981
10982 // Fill up the arrays with all the captured variables.
10983 MappableExprsHandler::MapCombinedInfoTy CombinedInfo;
10985 genMapInfo(D, CGF, CS, CapturedVars, OMPBuilder, CombinedInfo);
10986
10987 // Append a null entry for the implicit dyn_ptr argument.
10988 using OpenMPOffloadMappingFlags = llvm::omp::OpenMPOffloadMappingFlags;
10989 auto *NullPtr = llvm::Constant::getNullValue(CGF.Builder.getPtrTy());
10990 CombinedInfo.BasePointers.push_back(NullPtr);
10991 CombinedInfo.Pointers.push_back(NullPtr);
10992 CombinedInfo.DevicePointers.push_back(
10993 llvm::OpenMPIRBuilder::DeviceInfoTy::None);
10994 CombinedInfo.Sizes.push_back(CGF.Builder.getInt64(0));
10995 CombinedInfo.Types.push_back(OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM |
10996 OpenMPOffloadMappingFlags::OMP_MAP_LITERAL);
10997 CombinedInfo.HasAttachPtr.push_back(false);
10998 if (!CombinedInfo.Names.empty())
10999 CombinedInfo.Names.push_back(NullPtr);
11000 CombinedInfo.Exprs.push_back(nullptr);
11001 CombinedInfo.Mappers.push_back(nullptr);
11002 CombinedInfo.DevicePtrDecls.push_back(nullptr);
11003
11004 emitOffloadingArraysAndArgs(CGF, CombinedInfo, Info, OMPBuilder,
11005 /*IsNonContiguous=*/true, /*ForEndCall=*/false);
11006
11007 InputInfo.NumberOfTargetItems = Info.NumberOfPtrs;
11008 InputInfo.BasePointersArray = Address(Info.RTArgs.BasePointersArray,
11009 CGF.VoidPtrTy, CGM.getPointerAlign());
11010 InputInfo.PointersArray =
11011 Address(Info.RTArgs.PointersArray, CGF.VoidPtrTy, CGM.getPointerAlign());
11012 InputInfo.SizesArray =
11013 Address(Info.RTArgs.SizesArray, CGF.Int64Ty, CGM.getPointerAlign());
11014 InputInfo.MappersArray =
11015 Address(Info.RTArgs.MappersArray, CGF.VoidPtrTy, CGM.getPointerAlign());
11016 MapTypesArray = Info.RTArgs.MapTypesArray;
11017 MapNamesArray = Info.RTArgs.MapNamesArray;
11018
11019 auto &&ThenGen = [&OMPRuntime, OutlinedFn, &D, &CapturedVars,
11020 RequiresOuterTask, &CS, OffloadingMandatory, Device,
11021 OutlinedFnID, &InputInfo, &MapTypesArray, &MapNamesArray,
11022 SizeEmitter](CodeGenFunction &CGF, PrePostActionTy &) {
11023 bool IsReverseOffloading = Device.getInt() == OMPC_DEVICE_ancestor;
11024
11025 if (IsReverseOffloading) {
11026 // Reverse offloading is not supported, so just execute on the host.
11027 // FIXME: This fallback solution is incorrect since it ignores the
11028 // OMP_TARGET_OFFLOAD environment variable. Instead it would be better to
11029 // assert here and ensure SEMA emits an error.
11030 emitTargetCallFallback(OMPRuntime, OutlinedFn, D, CapturedVars,
11031 RequiresOuterTask, CS, OffloadingMandatory, CGF);
11032 return;
11033 }
11034
11035 bool HasNoWait = D.hasClausesOfKind<OMPNowaitClause>();
11036 unsigned NumTargetItems = InputInfo.NumberOfTargetItems;
11037
11038 llvm::Value *BasePointersArray =
11039 InputInfo.BasePointersArray.emitRawPointer(CGF);
11040 llvm::Value *PointersArray = InputInfo.PointersArray.emitRawPointer(CGF);
11041 llvm::Value *SizesArray = InputInfo.SizesArray.emitRawPointer(CGF);
11042 llvm::Value *MappersArray = InputInfo.MappersArray.emitRawPointer(CGF);
11043
11044 auto &&EmitTargetCallFallbackCB =
11045 [&OMPRuntime, OutlinedFn, &D, &CapturedVars, RequiresOuterTask, &CS,
11046 OffloadingMandatory, &CGF](llvm::OpenMPIRBuilder::InsertPointTy IP)
11047 -> llvm::OpenMPIRBuilder::InsertPointTy {
11048 CGF.Builder.restoreIP(IP);
11049 emitTargetCallFallback(OMPRuntime, OutlinedFn, D, CapturedVars,
11050 RequiresOuterTask, CS, OffloadingMandatory, CGF);
11051 return CGF.Builder.saveIP();
11052 };
11053
11054 bool IsBare = D.hasClausesOfKind<OMPXBareClause>();
11057 if (IsBare) {
11060 NumThreads);
11061 } else {
11062 NumTeams.push_back(OMPRuntime->emitNumTeamsForTargetDirective(CGF, D));
11063 NumThreads.push_back(
11064 OMPRuntime->emitNumThreadsForTargetDirective(CGF, D));
11065 }
11066
11067 llvm::Value *DeviceID = emitDeviceID(Device, CGF);
11068 llvm::Value *RTLoc = OMPRuntime->emitUpdateLocation(CGF, D.getBeginLoc());
11069 llvm::Value *NumIterations =
11070 OMPRuntime->emitTargetNumIterationsCall(CGF, D, SizeEmitter);
11071 auto [DynCGroupMem, DynCGroupMemFallback] = emitDynCGroupMem(D, CGF);
11072 llvm::OpenMPIRBuilder::InsertPointTy AllocaIP(
11073 CGF.AllocaInsertPt->getParent(), CGF.AllocaInsertPt->getIterator());
11074
11075 llvm::OpenMPIRBuilder::TargetDataRTArgs RTArgs(
11076 BasePointersArray, PointersArray, SizesArray, MapTypesArray,
11077 nullptr /* MapTypesArrayEnd */, MappersArray, MapNamesArray);
11078
11079 llvm::OpenMPIRBuilder::TargetKernelArgs Args(
11080 NumTargetItems, RTArgs, NumIterations, NumTeams, NumThreads,
11081 DynCGroupMem, HasNoWait, /*StrictBlocks=*/IsBare,
11082 /*StrictThreads=*/IsBare, DynCGroupMemFallback);
11083
11084 llvm::OpenMPIRBuilder::InsertPointTy AfterIP =
11085 cantFail(OMPRuntime->getOMPBuilder().emitKernelLaunch(
11086 CGF.Builder, OutlinedFnID, EmitTargetCallFallbackCB, Args, DeviceID,
11087 RTLoc, AllocaIP));
11088 CGF.Builder.restoreIP(AfterIP);
11089 };
11090
11091 if (RequiresOuterTask)
11092 CGF.EmitOMPTargetTaskBasedDirective(D, ThenGen, InputInfo);
11093 else
11094 OMPRuntime->emitInlinedDirective(CGF, D.getDirectiveKind(), ThenGen);
11095}
11096
11097static void
11098emitTargetCallElse(CGOpenMPRuntime *OMPRuntime, llvm::Function *OutlinedFn,
11099 const OMPExecutableDirective &D,
11101 bool RequiresOuterTask, const CapturedStmt &CS,
11102 bool OffloadingMandatory, CodeGenFunction &CGF) {
11103
11104 // Notify that the host version must be executed.
11105 auto &&ElseGen =
11106 [&OMPRuntime, OutlinedFn, &D, &CapturedVars, RequiresOuterTask, &CS,
11107 OffloadingMandatory](CodeGenFunction &CGF, PrePostActionTy &) {
11108 emitTargetCallFallback(OMPRuntime, OutlinedFn, D, CapturedVars,
11109 RequiresOuterTask, CS, OffloadingMandatory, CGF);
11110 };
11111
11112 if (RequiresOuterTask) {
11114 CGF.EmitOMPTargetTaskBasedDirective(D, ElseGen, InputInfo);
11115 } else {
11116 OMPRuntime->emitInlinedDirective(CGF, D.getDirectiveKind(), ElseGen);
11117 }
11118}
11119
11122 llvm::Function *OutlinedFn, llvm::Value *OutlinedFnID, const Expr *IfCond,
11123 llvm::PointerIntPair<const Expr *, 2, OpenMPDeviceClauseModifier> Device,
11124 llvm::function_ref<llvm::Value *(CodeGenFunction &CGF,
11125 const OMPLoopDirective &D)>
11126 SizeEmitter) {
11127 if (!CGF.HaveInsertPoint())
11128 return;
11129
11130 const bool OffloadingMandatory = !CGM.getLangOpts().OpenMPIsTargetDevice &&
11131 CGM.getLangOpts().OpenMPOffloadMandatory;
11132
11133 assert((OffloadingMandatory || OutlinedFn) && "Invalid outlined function!");
11134
11135 const bool RequiresOuterTask =
11136 D.hasClausesOfKind<OMPDependClause>() ||
11137 D.hasClausesOfKind<OMPNowaitClause>() ||
11138 D.hasClausesOfKind<OMPInReductionClause>() ||
11139 (CGM.getLangOpts().OpenMP >= 51 &&
11140 needsTaskBasedThreadLimit(D.getDirectiveKind()) &&
11141 D.hasClausesOfKind<OMPThreadLimitClause>());
11143 const CapturedStmt &CS = *D.getCapturedStmt(OMPD_target);
11144 auto &&ArgsCodegen = [&CS, &CapturedVars](CodeGenFunction &CGF,
11145 PrePostActionTy &) {
11146 CGF.GenerateOpenMPCapturedVars(CS, CapturedVars);
11147 };
11148 emitInlinedDirective(CGF, OMPD_unknown, ArgsCodegen);
11149
11151 llvm::Value *MapTypesArray = nullptr;
11152 llvm::Value *MapNamesArray = nullptr;
11153
11154 auto &&TargetThenGen = [this, OutlinedFn, &D, &CapturedVars,
11155 RequiresOuterTask, &CS, OffloadingMandatory, Device,
11156 OutlinedFnID, &InputInfo, &MapTypesArray,
11157 &MapNamesArray, SizeEmitter](CodeGenFunction &CGF,
11158 PrePostActionTy &) {
11159 emitTargetCallKernelLaunch(this, OutlinedFn, D, CapturedVars,
11160 RequiresOuterTask, CS, OffloadingMandatory,
11161 Device, OutlinedFnID, InputInfo, MapTypesArray,
11162 MapNamesArray, SizeEmitter, CGF, CGM);
11163 };
11164
11165 auto &&TargetElseGen =
11166 [this, OutlinedFn, &D, &CapturedVars, RequiresOuterTask, &CS,
11167 OffloadingMandatory](CodeGenFunction &CGF, PrePostActionTy &) {
11168 emitTargetCallElse(this, OutlinedFn, D, CapturedVars, RequiresOuterTask,
11169 CS, OffloadingMandatory, CGF);
11170 };
11171
11172 // If we have a target function ID it means that we need to support
11173 // offloading, otherwise, just execute on the host. We need to execute on host
11174 // regardless of the conditional in the if clause if, e.g., the user do not
11175 // specify target triples.
11176 if (OutlinedFnID) {
11177 if (IfCond) {
11178 emitIfClause(CGF, IfCond, TargetThenGen, TargetElseGen);
11179 } else {
11180 RegionCodeGenTy ThenRCG(TargetThenGen);
11181 ThenRCG(CGF);
11182 }
11183 } else {
11184 RegionCodeGenTy ElseRCG(TargetElseGen);
11185 ElseRCG(CGF);
11186 }
11187}
11188
11190 StringRef ParentName) {
11191 if (!S)
11192 return;
11193
11194 // Register vtable from device for target data and target directives.
11195 // Add this block here since scanForTargetRegionsFunctions ignores
11196 // target data by checking if S is a executable directive (target).
11197 if (auto *E = dyn_cast<OMPExecutableDirective>(S);
11198 E && isOpenMPTargetDataManagementDirective(E->getDirectiveKind())) {
11199 // Don't need to check if it's device compile
11200 // since scanForTargetRegionsFunctions currently only called
11201 // in device compilation.
11202 registerVTable(*E);
11203 }
11204
11205 // Codegen OMP target directives that offload compute to the device.
11206 bool RequiresDeviceCodegen =
11209 cast<OMPExecutableDirective>(S)->getDirectiveKind());
11210
11211 if (RequiresDeviceCodegen) {
11212 const auto &E = *cast<OMPExecutableDirective>(S);
11213
11214 llvm::TargetRegionEntryInfo EntryInfo = getEntryInfoFromPresumedLoc(
11215 CGM, OMPBuilder, E.getBeginLoc(), ParentName);
11216
11217 // Is this a target region that should not be emitted as an entry point? If
11218 // so just signal we are done with this target region.
11219 if (!OMPBuilder.OffloadInfoManager.hasTargetRegionEntryInfo(EntryInfo))
11220 return;
11221
11222 switch (E.getDirectiveKind()) {
11223 case OMPD_target:
11226 break;
11227 case OMPD_target_parallel:
11229 CGM, ParentName, cast<OMPTargetParallelDirective>(E));
11230 break;
11231 case OMPD_target_teams:
11233 CGM, ParentName, cast<OMPTargetTeamsDirective>(E));
11234 break;
11235 case OMPD_target_teams_distribute:
11238 break;
11239 case OMPD_target_teams_distribute_simd:
11242 break;
11243 case OMPD_target_parallel_for:
11246 break;
11247 case OMPD_target_parallel_for_simd:
11250 break;
11251 case OMPD_target_simd:
11253 CGM, ParentName, cast<OMPTargetSimdDirective>(E));
11254 break;
11255 case OMPD_target_teams_distribute_parallel_for:
11257 CGM, ParentName,
11259 break;
11260 case OMPD_target_teams_distribute_parallel_for_simd:
11263 CGM, ParentName,
11265 break;
11266 case OMPD_target_teams_loop:
11269 break;
11270 case OMPD_target_parallel_loop:
11273 break;
11274 case OMPD_parallel:
11275 case OMPD_for:
11276 case OMPD_parallel_for:
11277 case OMPD_parallel_master:
11278 case OMPD_parallel_sections:
11279 case OMPD_for_simd:
11280 case OMPD_parallel_for_simd:
11281 case OMPD_cancel:
11282 case OMPD_cancellation_point:
11283 case OMPD_ordered_standalone:
11284 case OMPD_ordered_blockassoc:
11285 case OMPD_threadprivate:
11286 case OMPD_allocate:
11287 case OMPD_task:
11288 case OMPD_simd:
11289 case OMPD_tile:
11290 case OMPD_unroll:
11291 case OMPD_sections:
11292 case OMPD_section:
11293 case OMPD_single:
11294 case OMPD_master:
11295 case OMPD_critical:
11296 case OMPD_taskyield:
11297 case OMPD_barrier:
11298 case OMPD_taskwait:
11299 case OMPD_taskgroup:
11300 case OMPD_atomic:
11301 case OMPD_flush:
11302 case OMPD_depobj:
11303 case OMPD_scan:
11304 case OMPD_teams:
11305 case OMPD_target_data:
11306 case OMPD_target_exit_data:
11307 case OMPD_target_enter_data:
11308 case OMPD_distribute:
11309 case OMPD_distribute_simd:
11310 case OMPD_distribute_parallel_for:
11311 case OMPD_distribute_parallel_for_simd:
11312 case OMPD_teams_distribute:
11313 case OMPD_teams_distribute_simd:
11314 case OMPD_teams_distribute_parallel_for:
11315 case OMPD_teams_distribute_parallel_for_simd:
11316 case OMPD_target_update:
11317 case OMPD_declare_simd:
11318 case OMPD_declare_variant:
11319 case OMPD_begin_declare_variant:
11320 case OMPD_end_declare_variant:
11321 case OMPD_declare_target:
11322 case OMPD_end_declare_target:
11323 case OMPD_declare_reduction:
11324 case OMPD_declare_mapper:
11325 case OMPD_taskloop:
11326 case OMPD_taskloop_simd:
11327 case OMPD_master_taskloop:
11328 case OMPD_master_taskloop_simd:
11329 case OMPD_parallel_master_taskloop:
11330 case OMPD_parallel_master_taskloop_simd:
11331 case OMPD_requires:
11332 case OMPD_metadirective:
11333 case OMPD_unknown:
11334 default:
11335 llvm_unreachable("Unknown target directive for OpenMP device codegen.");
11336 }
11337 return;
11338 }
11339
11340 if (const auto *E = dyn_cast<OMPExecutableDirective>(S)) {
11341 if (!E->hasAssociatedStmt() || !E->getAssociatedStmt())
11342 return;
11343
11344 scanForTargetRegionsFunctions(E->getRawStmt(), ParentName);
11345 return;
11346 }
11347
11348 // If this is a lambda function, look into its body.
11349 if (const auto *L = dyn_cast<LambdaExpr>(S))
11350 S = L->getBody();
11351
11352 // Keep looking for target regions recursively.
11353 for (const Stmt *II : S->children())
11354 scanForTargetRegionsFunctions(II, ParentName);
11355}
11356
11357static bool isAssumedToBeNotEmitted(const ValueDecl *VD, bool IsDevice) {
11358 std::optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
11359 OMPDeclareTargetDeclAttr::getDeviceType(VD);
11360 if (!DevTy)
11361 return false;
11362 // Do not emit device_type(nohost) functions for the host.
11363 if (!IsDevice && DevTy == OMPDeclareTargetDeclAttr::DT_NoHost)
11364 return true;
11365 // Do not emit device_type(host) functions for the device.
11366 if (IsDevice && DevTy == OMPDeclareTargetDeclAttr::DT_Host)
11367 return true;
11368 return false;
11369}
11370
11372 // If emitting code for the host, we do not process FD here. Instead we do
11373 // the normal code generation.
11374 if (!CGM.getLangOpts().OpenMPIsTargetDevice) {
11375 if (const auto *FD = dyn_cast<FunctionDecl>(GD.getDecl()))
11377 CGM.getLangOpts().OpenMPIsTargetDevice))
11378 return true;
11379 return false;
11380 }
11381
11382 const ValueDecl *VD = cast<ValueDecl>(GD.getDecl());
11383 // Try to detect target regions in the function.
11384 if (const auto *FD = dyn_cast<FunctionDecl>(VD)) {
11385 StringRef Name = CGM.getMangledName(GD);
11388 CGM.getLangOpts().OpenMPIsTargetDevice))
11389 return true;
11390 }
11391
11392 // Do not emit function if it is not marked as declare target.
11393 return !OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD) &&
11394 AlreadyEmittedTargetDecls.count(VD) == 0;
11395}
11396
11399 CGM.getLangOpts().OpenMPIsTargetDevice))
11400 return true;
11401
11402 if (!CGM.getLangOpts().OpenMPIsTargetDevice)
11403 return false;
11404
11405 // Check if there are Ctors/Dtors in this declaration and look for target
11406 // regions in it. We use the complete variant to produce the kernel name
11407 // mangling.
11408 QualType RDTy = cast<VarDecl>(GD.getDecl())->getType();
11409 if (const auto *RD = RDTy->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) {
11410 for (const CXXConstructorDecl *Ctor : RD->ctors()) {
11411 StringRef ParentName =
11412 CGM.getMangledName(GlobalDecl(Ctor, Ctor_Complete));
11413 scanForTargetRegionsFunctions(Ctor->getBody(), ParentName);
11414 }
11415 if (const CXXDestructorDecl *Dtor = RD->getDestructor()) {
11416 StringRef ParentName =
11417 CGM.getMangledName(GlobalDecl(Dtor, Dtor_Complete));
11418 scanForTargetRegionsFunctions(Dtor->getBody(), ParentName);
11419 }
11420 }
11421
11422 // Do not emit variable if it is not marked as declare target.
11423 std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
11424 OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(
11425 cast<VarDecl>(GD.getDecl()));
11426 if (!Res || *Res == OMPDeclareTargetDeclAttr::MT_Link ||
11427 ((*Res == OMPDeclareTargetDeclAttr::MT_To ||
11428 *Res == OMPDeclareTargetDeclAttr::MT_Enter) &&
11431 return true;
11432 }
11433 return false;
11434}
11435
11437 llvm::Constant *Addr) {
11438 if (CGM.getLangOpts().OMPTargetTriples.empty() &&
11439 !CGM.getLangOpts().OpenMPIsTargetDevice)
11440 return;
11441
11442 std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
11443 OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
11444
11445 // If this is an 'extern' declaration we defer to the canonical definition and
11446 // do not emit an offloading entry.
11447 if (Res && *Res != OMPDeclareTargetDeclAttr::MT_Link &&
11448 VD->hasExternalStorage())
11449 return;
11450
11451 // MT_Local variables use direct access with no host-device mapping.
11452 // No offload entry needed — the device global keeps its own initializer.
11453 if (Res && *Res == OMPDeclareTargetDeclAttr::MT_Local)
11454 return;
11455
11456 if (!Res) {
11457 if (CGM.getLangOpts().OpenMPIsTargetDevice) {
11458 // Register non-target variables being emitted in device code (debug info
11459 // may cause this).
11460 StringRef VarName = CGM.getMangledName(VD);
11461 EmittedNonTargetVariables.try_emplace(VarName, Addr);
11462 }
11463 return;
11464 }
11465
11466 auto AddrOfGlobal = [&VD, this]() { return CGM.GetAddrOfGlobal(VD); };
11467 auto LinkageForVariable = [&VD, this]() {
11468 return CGM.getLLVMLinkageVarDefinition(VD);
11469 };
11470
11471 std::vector<llvm::GlobalVariable *> GeneratedRefs;
11472 OMPBuilder.registerTargetGlobalVariable(
11474 VD->hasDefinition(CGM.getContext()) == VarDecl::DeclarationOnly,
11475 VD->isExternallyVisible(),
11477 VD->getCanonicalDecl()->getBeginLoc()),
11478 CGM.getMangledName(VD), GeneratedRefs, CGM.getLangOpts().OpenMPSimd,
11479 CGM.getLangOpts().OMPTargetTriples, AddrOfGlobal, LinkageForVariable,
11480 CGM.getTypes().ConvertTypeForMem(
11481 CGM.getContext().getPointerType(VD->getType())),
11482 Addr);
11483
11484 for (auto *ref : GeneratedRefs)
11485 CGM.addCompilerUsedGlobal(ref);
11486}
11487
11489 if (isa<FunctionDecl>(GD.getDecl()) ||
11491 return emitTargetFunctions(GD);
11492
11493 return emitTargetGlobalVariable(GD);
11494}
11495
11497 for (const VarDecl *VD : DeferredGlobalVariables) {
11498 std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
11499 OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
11500 if (!Res)
11501 continue;
11502 // MT_Local and MT_To/MT_Enter without USM are always emitted.
11503 if (*Res == OMPDeclareTargetDeclAttr::MT_Local ||
11504 ((*Res == OMPDeclareTargetDeclAttr::MT_To ||
11505 *Res == OMPDeclareTargetDeclAttr::MT_Enter) &&
11507 CGM.EmitGlobal(VD);
11508 } else {
11509 assert((*Res == OMPDeclareTargetDeclAttr::MT_Link ||
11510 ((*Res == OMPDeclareTargetDeclAttr::MT_To ||
11511 *Res == OMPDeclareTargetDeclAttr::MT_Enter ||
11512 *Res == OMPDeclareTargetDeclAttr::MT_Local) &&
11514 "Expected link clause or to clause with unified memory.");
11515 (void)CGM.getOpenMPRuntime().getAddrOfDeclareTargetVar(VD);
11516 }
11517 }
11518}
11519
11521 CodeGenFunction &CGF, const OMPExecutableDirective &D) const {
11522 assert(isOpenMPTargetExecutionDirective(D.getDirectiveKind()) &&
11523 " Expected target-based directive.");
11524}
11525
11527 for (const OMPClause *Clause : D->clauselists()) {
11528 if (Clause->getClauseKind() == OMPC_unified_shared_memory) {
11530 OMPBuilder.Config.setHasRequiresUnifiedSharedMemory(true);
11531 } else if (const auto *AC =
11532 dyn_cast<OMPAtomicDefaultMemOrderClause>(Clause)) {
11533 switch (AC->getAtomicDefaultMemOrderKind()) {
11534 case OMPC_ATOMIC_DEFAULT_MEM_ORDER_acq_rel:
11535 RequiresAtomicOrdering = llvm::AtomicOrdering::AcquireRelease;
11536 break;
11537 case OMPC_ATOMIC_DEFAULT_MEM_ORDER_seq_cst:
11538 RequiresAtomicOrdering = llvm::AtomicOrdering::SequentiallyConsistent;
11539 break;
11540 case OMPC_ATOMIC_DEFAULT_MEM_ORDER_relaxed:
11541 RequiresAtomicOrdering = llvm::AtomicOrdering::Monotonic;
11542 break;
11544 break;
11545 }
11546 }
11547 }
11548}
11549
11550llvm::AtomicOrdering CGOpenMPRuntime::getDefaultMemoryOrdering() const {
11552}
11553
11555 LangAS &AS) {
11556 if (!VD || !VD->hasAttr<OMPAllocateDeclAttr>())
11557 return false;
11558 const auto *A = VD->getAttr<OMPAllocateDeclAttr>();
11559 switch(A->getAllocatorType()) {
11560 case OMPAllocateDeclAttr::OMPNullMemAlloc:
11561 case OMPAllocateDeclAttr::OMPDefaultMemAlloc:
11562 // Not supported, fallback to the default mem space.
11563 case OMPAllocateDeclAttr::OMPLargeCapMemAlloc:
11564 case OMPAllocateDeclAttr::OMPCGroupMemAlloc:
11565 case OMPAllocateDeclAttr::OMPHighBWMemAlloc:
11566 case OMPAllocateDeclAttr::OMPLowLatMemAlloc:
11567 case OMPAllocateDeclAttr::OMPThreadMemAlloc:
11568 case OMPAllocateDeclAttr::OMPConstMemAlloc:
11569 case OMPAllocateDeclAttr::OMPPTeamMemAlloc:
11570 AS = LangAS::Default;
11571 return true;
11572 case OMPAllocateDeclAttr::OMPUserDefinedMemAlloc:
11573 llvm_unreachable("Expected predefined allocator for the variables with the "
11574 "static storage.");
11575 }
11576 return false;
11577}
11578
11582
11584 CodeGenModule &CGM)
11585 : CGM(CGM) {
11586 if (CGM.getLangOpts().OpenMPIsTargetDevice) {
11587 SavedShouldMarkAsGlobal = CGM.getOpenMPRuntime().ShouldMarkAsGlobal;
11588 CGM.getOpenMPRuntime().ShouldMarkAsGlobal = false;
11589 }
11590}
11591
11593 if (CGM.getLangOpts().OpenMPIsTargetDevice)
11594 CGM.getOpenMPRuntime().ShouldMarkAsGlobal = SavedShouldMarkAsGlobal;
11595}
11596
11598 if (!CGM.getLangOpts().OpenMPIsTargetDevice || !ShouldMarkAsGlobal)
11599 return true;
11600
11601 const auto *D = cast<FunctionDecl>(GD.getDecl());
11602 // Do not emit function if it is marked as declare target as it was already
11603 // emitted.
11604 if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(D)) {
11605 if (D->hasBody() && AlreadyEmittedTargetDecls.count(D) == 0) {
11606 if (auto *F = dyn_cast_or_null<llvm::Function>(
11607 CGM.GetGlobalValue(CGM.getMangledName(GD))))
11608 return !F->isDeclaration();
11609 return false;
11610 }
11611 return true;
11612 }
11613
11614 return !AlreadyEmittedTargetDecls.insert(D).second;
11615}
11616
11618 const OMPExecutableDirective &D,
11619 SourceLocation Loc,
11620 llvm::Function *OutlinedFn,
11621 ArrayRef<llvm::Value *> CapturedVars) {
11622 if (!CGF.HaveInsertPoint())
11623 return;
11624
11625 llvm::Value *RTLoc = emitUpdateLocation(CGF, Loc);
11627
11628 // Build call __kmpc_fork_teams(loc, n, microtask, var1, .., varn);
11629 llvm::Value *Args[] = {
11630 RTLoc,
11631 CGF.Builder.getInt32(CapturedVars.size()), // Number of captured vars
11632 OutlinedFn};
11634 RealArgs.append(std::begin(Args), std::end(Args));
11635 RealArgs.append(CapturedVars.begin(), CapturedVars.end());
11636
11637 llvm::FunctionCallee RTLFn = OMPBuilder.getOrCreateRuntimeFunction(
11638 CGM.getModule(), OMPRTL___kmpc_fork_teams);
11639 CGF.EmitRuntimeCall(RTLFn, RealArgs);
11640}
11641
11643 const Expr *NumTeams,
11644 const Expr *ThreadLimit,
11645 SourceLocation Loc) {
11646 if (!CGF.HaveInsertPoint())
11647 return;
11648
11649 llvm::Value *RTLoc = emitUpdateLocation(CGF, Loc);
11650
11651 llvm::Value *NumTeamsVal =
11652 NumTeams
11653 ? CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(NumTeams),
11654 CGF.CGM.Int32Ty, /* isSigned = */ true)
11655 : CGF.Builder.getInt32(0);
11656
11657 llvm::Value *ThreadLimitVal =
11658 ThreadLimit
11659 ? CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(ThreadLimit),
11660 CGF.CGM.Int32Ty, /* isSigned = */ true)
11661 : CGF.Builder.getInt32(0);
11662
11663 // Build call __kmpc_push_num_teamss(&loc, global_tid, num_teams, thread_limit)
11664 llvm::Value *PushNumTeamsArgs[] = {RTLoc, getThreadID(CGF, Loc), NumTeamsVal,
11665 ThreadLimitVal};
11666 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
11667 CGM.getModule(), OMPRTL___kmpc_push_num_teams),
11668 PushNumTeamsArgs);
11669}
11670
11672 const Expr *ThreadLimit,
11673 SourceLocation Loc) {
11674 llvm::Value *RTLoc = emitUpdateLocation(CGF, Loc);
11675 llvm::Value *ThreadLimitVal =
11676 ThreadLimit
11677 ? CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(ThreadLimit),
11678 CGF.CGM.Int32Ty, /* isSigned = */ true)
11679 : CGF.Builder.getInt32(0);
11680
11681 // Build call __kmpc_set_thread_limit(&loc, global_tid, thread_limit)
11682 llvm::Value *ThreadLimitArgs[] = {RTLoc, getThreadID(CGF, Loc),
11683 ThreadLimitVal};
11684 CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
11685 CGM.getModule(), OMPRTL___kmpc_set_thread_limit),
11686 ThreadLimitArgs);
11687}
11688
11690 CodeGenFunction &CGF, const OMPExecutableDirective &D, const Expr *IfCond,
11691 const Expr *Device, const RegionCodeGenTy &CodeGen,
11693 if (!CGF.HaveInsertPoint())
11694 return;
11695
11696 // Action used to replace the default codegen action and turn privatization
11697 // off.
11698 PrePostActionTy NoPrivAction;
11699
11700 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
11701
11702 llvm::Value *IfCondVal = nullptr;
11703 if (IfCond)
11704 IfCondVal = CGF.EvaluateExprAsBool(IfCond);
11705
11706 // Emit device ID if any.
11707 llvm::Value *DeviceID = nullptr;
11708 if (Device) {
11709 DeviceID = CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(Device),
11710 CGF.Int64Ty, /*isSigned=*/true);
11711 } else {
11712 DeviceID = CGF.Builder.getInt64(OMP_DEVICEID_UNDEF);
11713 }
11714
11715 // Fill up the arrays with all the mapped variables.
11716 MappableExprsHandler::MapCombinedInfoTy CombinedInfo;
11717 auto GenMapInfoCB =
11718 [&](InsertPointTy CodeGenIP) -> llvm::OpenMPIRBuilder::MapInfosTy & {
11719 CGF.Builder.restoreIP(CodeGenIP);
11720 // Get map clause information.
11721 MappableExprsHandler MEHandler(D, CGF);
11722 MEHandler.generateAllInfo(CombinedInfo, OMPBuilder);
11723
11724 auto FillInfoMap = [&](MappableExprsHandler::MappingExprInfo &MapExpr) {
11725 return emitMappingInformation(CGF, OMPBuilder, MapExpr);
11726 };
11727 if (CGM.getCodeGenOpts().getDebugInfo() !=
11728 llvm::codegenoptions::NoDebugInfo) {
11729 CombinedInfo.Names.resize(CombinedInfo.Exprs.size());
11730 llvm::transform(CombinedInfo.Exprs, CombinedInfo.Names.begin(),
11731 FillInfoMap);
11732 }
11733
11734 return CombinedInfo;
11735 };
11736 using BodyGenTy = llvm::OpenMPIRBuilder::BodyGenTy;
11737 auto BodyCB = [&](InsertPointTy CodeGenIP, BodyGenTy BodyGenType) {
11738 CGF.Builder.restoreIP(CodeGenIP);
11739 switch (BodyGenType) {
11740 case BodyGenTy::Priv:
11741 if (!Info.CaptureDeviceAddrMap.empty())
11742 CodeGen(CGF);
11743 break;
11744 case BodyGenTy::DupNoPriv:
11745 if (!Info.CaptureDeviceAddrMap.empty()) {
11746 CodeGen.setAction(NoPrivAction);
11747 CodeGen(CGF);
11748 }
11749 break;
11750 case BodyGenTy::NoPriv:
11751 if (Info.CaptureDeviceAddrMap.empty()) {
11752 CodeGen.setAction(NoPrivAction);
11753 CodeGen(CGF);
11754 }
11755 break;
11756 }
11757 return InsertPointTy(CGF.Builder.GetInsertBlock(),
11758 CGF.Builder.GetInsertPoint());
11759 };
11760
11761 auto DeviceAddrCB = [&](unsigned int I, llvm::Value *NewDecl) {
11762 if (const ValueDecl *DevVD = CombinedInfo.DevicePtrDecls[I]) {
11763 Info.CaptureDeviceAddrMap.try_emplace(DevVD, NewDecl);
11764 }
11765 };
11766
11767 auto CustomMapperCB = [&](unsigned int I) {
11768 llvm::Function *MFunc = nullptr;
11769 if (CombinedInfo.Mappers[I]) {
11770 Info.HasMapper = true;
11772 cast<OMPDeclareMapperDecl>(CombinedInfo.Mappers[I]));
11773 }
11774 return MFunc;
11775 };
11776
11777 // Source location for the ident struct
11778 llvm::Value *RTLoc = emitUpdateLocation(CGF, D.getBeginLoc());
11779
11780 InsertPointTy AllocaIP(CGF.AllocaInsertPt->getParent(),
11781 CGF.AllocaInsertPt->getIterator());
11782 InsertPointTy CodeGenIP(CGF.Builder.GetInsertBlock(),
11783 CGF.Builder.GetInsertPoint());
11784 llvm::OpenMPIRBuilder::LocationDescription OmpLoc(CodeGenIP);
11785 llvm::OpenMPIRBuilder::InsertPointTy AfterIP =
11786 cantFail(OMPBuilder.createTargetData(
11787 OmpLoc, AllocaIP, CodeGenIP, /*DeallocBlocks=*/{}, DeviceID,
11788 IfCondVal, Info, GenMapInfoCB, CustomMapperCB,
11789 /*MapperFunc=*/nullptr, BodyCB, DeviceAddrCB, RTLoc));
11790 CGF.Builder.restoreIP(AfterIP);
11791}
11792
11794 CodeGenFunction &CGF, const OMPExecutableDirective &D, const Expr *IfCond,
11795 const Expr *Device) {
11796 if (!CGF.HaveInsertPoint())
11797 return;
11798
11802 "Expecting either target enter, exit data, or update directives.");
11803
11805 llvm::Value *MapTypesArray = nullptr;
11806 llvm::Value *MapNamesArray = nullptr;
11807 // Generate the code for the opening of the data environment.
11808 auto &&ThenGen = [this, &D, Device, &InputInfo, &MapTypesArray,
11809 &MapNamesArray](CodeGenFunction &CGF, PrePostActionTy &) {
11810 // Emit device ID if any.
11811 llvm::Value *DeviceID = nullptr;
11812 if (Device) {
11813 DeviceID = CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(Device),
11814 CGF.Int64Ty, /*isSigned=*/true);
11815 } else {
11816 DeviceID = CGF.Builder.getInt64(OMP_DEVICEID_UNDEF);
11817 }
11818
11819 // Emit the number of elements in the offloading arrays.
11820 llvm::Constant *PointerNum =
11821 CGF.Builder.getInt32(InputInfo.NumberOfTargetItems);
11822
11823 // Source location for the ident struct
11824 llvm::Value *RTLoc = emitUpdateLocation(CGF, D.getBeginLoc());
11825
11826 SmallVector<llvm::Value *, 13> OffloadingArgs(
11827 {RTLoc, DeviceID, PointerNum,
11828 InputInfo.BasePointersArray.emitRawPointer(CGF),
11829 InputInfo.PointersArray.emitRawPointer(CGF),
11830 InputInfo.SizesArray.emitRawPointer(CGF), MapTypesArray, MapNamesArray,
11831 InputInfo.MappersArray.emitRawPointer(CGF)});
11832
11833 // Select the right runtime function call for each standalone
11834 // directive.
11835 const bool HasNowait = D.hasClausesOfKind<OMPNowaitClause>();
11836 RuntimeFunction RTLFn;
11837 switch (D.getDirectiveKind()) {
11838 case OMPD_target_enter_data:
11839 RTLFn = HasNowait ? OMPRTL___tgt_target_data_begin_nowait_mapper
11840 : OMPRTL___tgt_target_data_begin_mapper;
11841 break;
11842 case OMPD_target_exit_data:
11843 RTLFn = HasNowait ? OMPRTL___tgt_target_data_end_nowait_mapper
11844 : OMPRTL___tgt_target_data_end_mapper;
11845 break;
11846 case OMPD_target_update:
11847 RTLFn = HasNowait ? OMPRTL___tgt_target_data_update_nowait_mapper
11848 : OMPRTL___tgt_target_data_update_mapper;
11849 break;
11850 case OMPD_parallel:
11851 case OMPD_for:
11852 case OMPD_parallel_for:
11853 case OMPD_parallel_master:
11854 case OMPD_parallel_sections:
11855 case OMPD_for_simd:
11856 case OMPD_parallel_for_simd:
11857 case OMPD_cancel:
11858 case OMPD_cancellation_point:
11859 case OMPD_ordered_standalone:
11860 case OMPD_ordered_blockassoc:
11861 case OMPD_threadprivate:
11862 case OMPD_allocate:
11863 case OMPD_task:
11864 case OMPD_simd:
11865 case OMPD_tile:
11866 case OMPD_unroll:
11867 case OMPD_sections:
11868 case OMPD_section:
11869 case OMPD_single:
11870 case OMPD_master:
11871 case OMPD_critical:
11872 case OMPD_taskyield:
11873 case OMPD_barrier:
11874 case OMPD_taskwait:
11875 case OMPD_taskgroup:
11876 case OMPD_atomic:
11877 case OMPD_flush:
11878 case OMPD_depobj:
11879 case OMPD_scan:
11880 case OMPD_teams:
11881 case OMPD_target_data:
11882 case OMPD_distribute:
11883 case OMPD_distribute_simd:
11884 case OMPD_distribute_parallel_for:
11885 case OMPD_distribute_parallel_for_simd:
11886 case OMPD_teams_distribute:
11887 case OMPD_teams_distribute_simd:
11888 case OMPD_teams_distribute_parallel_for:
11889 case OMPD_teams_distribute_parallel_for_simd:
11890 case OMPD_declare_simd:
11891 case OMPD_declare_variant:
11892 case OMPD_begin_declare_variant:
11893 case OMPD_end_declare_variant:
11894 case OMPD_declare_target:
11895 case OMPD_end_declare_target:
11896 case OMPD_declare_reduction:
11897 case OMPD_declare_mapper:
11898 case OMPD_taskloop:
11899 case OMPD_taskloop_simd:
11900 case OMPD_master_taskloop:
11901 case OMPD_master_taskloop_simd:
11902 case OMPD_parallel_master_taskloop:
11903 case OMPD_parallel_master_taskloop_simd:
11904 case OMPD_target:
11905 case OMPD_target_simd:
11906 case OMPD_target_teams_distribute:
11907 case OMPD_target_teams_distribute_simd:
11908 case OMPD_target_teams_distribute_parallel_for:
11909 case OMPD_target_teams_distribute_parallel_for_simd:
11910 case OMPD_target_teams:
11911 case OMPD_target_parallel:
11912 case OMPD_target_parallel_for:
11913 case OMPD_target_parallel_for_simd:
11914 case OMPD_requires:
11915 case OMPD_metadirective:
11916 case OMPD_unknown:
11917 default:
11918 llvm_unreachable("Unexpected standalone target data directive.");
11919 break;
11920 }
11921 if (HasNowait) {
11922 OffloadingArgs.push_back(llvm::Constant::getNullValue(CGF.Int32Ty));
11923 OffloadingArgs.push_back(llvm::Constant::getNullValue(CGF.VoidPtrTy));
11924 OffloadingArgs.push_back(llvm::Constant::getNullValue(CGF.Int32Ty));
11925 OffloadingArgs.push_back(llvm::Constant::getNullValue(CGF.VoidPtrTy));
11926 }
11927 CGF.EmitRuntimeCall(
11928 OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(), RTLFn),
11929 OffloadingArgs);
11930 };
11931
11932 auto &&TargetThenGen = [this, &ThenGen, &D, &InputInfo, &MapTypesArray,
11933 &MapNamesArray](CodeGenFunction &CGF,
11934 PrePostActionTy &) {
11935 // Fill up the arrays with all the mapped variables.
11936 MappableExprsHandler::MapCombinedInfoTy CombinedInfo;
11938 MappableExprsHandler MEHandler(D, CGF);
11939 genMapInfo(MEHandler, CGF, CombinedInfo, OMPBuilder);
11940 emitOffloadingArraysAndArgs(CGF, CombinedInfo, Info, OMPBuilder,
11941 /*IsNonContiguous=*/true, /*ForEndCall=*/false);
11942
11943 bool RequiresOuterTask = D.hasClausesOfKind<OMPDependClause>() ||
11944 D.hasClausesOfKind<OMPNowaitClause>();
11945
11946 InputInfo.NumberOfTargetItems = Info.NumberOfPtrs;
11947 InputInfo.BasePointersArray = Address(Info.RTArgs.BasePointersArray,
11948 CGF.VoidPtrTy, CGM.getPointerAlign());
11949 InputInfo.PointersArray = Address(Info.RTArgs.PointersArray, CGF.VoidPtrTy,
11950 CGM.getPointerAlign());
11951 InputInfo.SizesArray =
11952 Address(Info.RTArgs.SizesArray, CGF.Int64Ty, CGM.getPointerAlign());
11953 InputInfo.MappersArray =
11954 Address(Info.RTArgs.MappersArray, CGF.VoidPtrTy, CGM.getPointerAlign());
11955 MapTypesArray = Info.RTArgs.MapTypesArray;
11956 MapNamesArray = Info.RTArgs.MapNamesArray;
11957 if (RequiresOuterTask)
11958 CGF.EmitOMPTargetTaskBasedDirective(D, ThenGen, InputInfo);
11959 else
11960 emitInlinedDirective(CGF, D.getDirectiveKind(), ThenGen);
11961 };
11962
11963 if (IfCond) {
11964 emitIfClause(CGF, IfCond, TargetThenGen,
11965 [](CodeGenFunction &CGF, PrePostActionTy &) {});
11966 } else {
11967 RegionCodeGenTy ThenRCG(TargetThenGen);
11968 ThenRCG(CGF);
11969 }
11970}
11971
11972static unsigned
11975 // Every vector variant of a SIMD-enabled function has a vector length (VLEN).
11976 // If OpenMP clause "simdlen" is used, the VLEN is the value of the argument
11977 // of that clause. The VLEN value must be power of 2.
11978 // In other case the notion of the function`s "characteristic data type" (CDT)
11979 // is used to compute the vector length.
11980 // CDT is defined in the following order:
11981 // a) For non-void function, the CDT is the return type.
11982 // b) If the function has any non-uniform, non-linear parameters, then the
11983 // CDT is the type of the first such parameter.
11984 // c) If the CDT determined by a) or b) above is struct, union, or class
11985 // type which is pass-by-value (except for the type that maps to the
11986 // built-in complex data type), the characteristic data type is int.
11987 // d) If none of the above three cases is applicable, the CDT is int.
11988 // The VLEN is then determined based on the CDT and the size of vector
11989 // register of that ISA for which current vector version is generated. The
11990 // VLEN is computed using the formula below:
11991 // VLEN = sizeof(vector_register) / sizeof(CDT),
11992 // where vector register size specified in section 3.2.1 Registers and the
11993 // Stack Frame of original AMD64 ABI document.
11994 QualType RetType = FD->getReturnType();
11995 if (RetType.isNull())
11996 return 0;
11997 ASTContext &C = FD->getASTContext();
11998 QualType CDT;
11999 if (!RetType.isNull() && !RetType->isVoidType()) {
12000 CDT = RetType;
12001 } else {
12002 unsigned Offset = 0;
12003 if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
12004 if (ParamAttrs[Offset].Kind ==
12005 llvm::OpenMPIRBuilder::DeclareSimdKindTy::Vector)
12006 CDT = C.getPointerType(C.getCanonicalTagType(MD->getParent()));
12007 ++Offset;
12008 }
12009 if (CDT.isNull()) {
12010 for (unsigned I = 0, E = FD->getNumParams(); I < E; ++I) {
12011 if (ParamAttrs[I + Offset].Kind ==
12012 llvm::OpenMPIRBuilder::DeclareSimdKindTy::Vector) {
12013 CDT = FD->getParamDecl(I)->getType();
12014 break;
12015 }
12016 }
12017 }
12018 }
12019 if (CDT.isNull())
12020 CDT = C.IntTy;
12021 CDT = CDT->getCanonicalTypeUnqualified();
12022 if (CDT->isRecordType() || CDT->isUnionType())
12023 CDT = C.IntTy;
12024 return C.getTypeSize(CDT);
12025}
12026
12027// This are the Functions that are needed to mangle the name of the
12028// vector functions generated by the compiler, according to the rules
12029// defined in the "Vector Function ABI specifications for AArch64",
12030// available at
12031// https://developer.arm.com/products/software-development-tools/hpc/arm-compiler-for-hpc/vector-function-abi.
12032
12033/// Maps To Vector (MTV), as defined in 4.1.1 of the AAVFABI (2021Q1).
12035 llvm::OpenMPIRBuilder::DeclareSimdKindTy Kind) {
12036 QT = QT.getCanonicalType();
12037
12038 if (QT->isVoidType())
12039 return false;
12040
12041 if (Kind == llvm::OpenMPIRBuilder::DeclareSimdKindTy::Uniform)
12042 return false;
12043
12044 if (Kind == llvm::OpenMPIRBuilder::DeclareSimdKindTy::LinearUVal ||
12045 Kind == llvm::OpenMPIRBuilder::DeclareSimdKindTy::LinearRef)
12046 return false;
12047
12048 if ((Kind == llvm::OpenMPIRBuilder::DeclareSimdKindTy::Linear ||
12049 Kind == llvm::OpenMPIRBuilder::DeclareSimdKindTy::LinearVal) &&
12050 !QT->isReferenceType())
12051 return false;
12052
12053 return true;
12054}
12055
12056/// Pass By Value (PBV), as defined in 3.1.2 of the AAVFABI.
12058 QT = QT.getCanonicalType();
12059 unsigned Size = C.getTypeSize(QT);
12060
12061 // Only scalars and complex within 16 bytes wide set PVB to true.
12062 if (Size != 8 && Size != 16 && Size != 32 && Size != 64 && Size != 128)
12063 return false;
12064
12065 if (QT->isFloatingType())
12066 return true;
12067
12068 if (QT->isIntegerType())
12069 return true;
12070
12071 if (QT->isPointerType())
12072 return true;
12073
12074 // TODO: Add support for complex types (section 3.1.2, item 2).
12075
12076 return false;
12077}
12078
12079/// Computes the lane size (LS) of a return type or of an input parameter,
12080/// as defined by `LS(P)` in 3.2.1 of the AAVFABI.
12081/// TODO: Add support for references, section 3.2.1, item 1.
12082static unsigned getAArch64LS(QualType QT,
12083 llvm::OpenMPIRBuilder::DeclareSimdKindTy Kind,
12084 ASTContext &C) {
12085 if (!getAArch64MTV(QT, Kind) && QT.getCanonicalType()->isPointerType()) {
12087 if (getAArch64PBV(PTy, C))
12088 return C.getTypeSize(PTy);
12089 }
12090 if (getAArch64PBV(QT, C))
12091 return C.getTypeSize(QT);
12092
12093 return C.getTypeSize(C.getUIntPtrType());
12094}
12095
12096// Get Narrowest Data Size (NDS) and Widest Data Size (WDS) from the
12097// signature of the scalar function, as defined in 3.2.2 of the
12098// AAVFABI.
12099static std::tuple<unsigned, unsigned, bool>
12102 QualType RetType = FD->getReturnType().getCanonicalType();
12103
12104 ASTContext &C = FD->getASTContext();
12105
12106 bool OutputBecomesInput = false;
12107
12109 if (!RetType->isVoidType()) {
12110 Sizes.push_back(getAArch64LS(
12111 RetType, llvm::OpenMPIRBuilder::DeclareSimdKindTy::Vector, C));
12112 if (!getAArch64PBV(RetType, C) && getAArch64MTV(RetType, {}))
12113 OutputBecomesInput = true;
12114 }
12115 for (unsigned I = 0, E = FD->getNumParams(); I < E; ++I) {
12117 Sizes.push_back(getAArch64LS(QT, ParamAttrs[I].Kind, C));
12118 }
12119
12120 assert(!Sizes.empty() && "Unable to determine NDS and WDS.");
12121 // The LS of a function parameter / return value can only be a power
12122 // of 2, starting from 8 bits, up to 128.
12123 assert(llvm::all_of(Sizes,
12124 [](unsigned Size) {
12125 return Size == 8 || Size == 16 || Size == 32 ||
12126 Size == 64 || Size == 128;
12127 }) &&
12128 "Invalid size");
12129
12130 return std::make_tuple(*llvm::min_element(Sizes), *llvm::max_element(Sizes),
12131 OutputBecomesInput);
12132}
12133
12134static llvm::OpenMPIRBuilder::DeclareSimdBranch
12135convertDeclareSimdBranch(OMPDeclareSimdDeclAttr::BranchStateTy State) {
12136 switch (State) {
12137 case OMPDeclareSimdDeclAttr::BS_Undefined:
12138 return llvm::OpenMPIRBuilder::DeclareSimdBranch::Undefined;
12139 case OMPDeclareSimdDeclAttr::BS_Inbranch:
12140 return llvm::OpenMPIRBuilder::DeclareSimdBranch::Inbranch;
12141 case OMPDeclareSimdDeclAttr::BS_Notinbranch:
12142 return llvm::OpenMPIRBuilder::DeclareSimdBranch::Notinbranch;
12143 }
12144 llvm_unreachable("unexpected declare simd branch state");
12145}
12146
12147// Check the values provided via `simdlen` by the user.
12149 unsigned UserVLEN, unsigned WDS, char ISA) {
12150 // 1. A `simdlen(1)` doesn't produce vector signatures.
12151 if (UserVLEN == 1) {
12152 CGM.getDiags().Report(SLoc, diag::warn_simdlen_1_no_effect);
12153 return false;
12154 }
12155
12156 // 2. Section 3.3.1, item 1: user input must be a power of 2 for Advanced
12157 // SIMD.
12158 if (ISA == 'n' && UserVLEN && !llvm::isPowerOf2_32(UserVLEN)) {
12159 CGM.getDiags().Report(SLoc, diag::warn_simdlen_requires_power_of_2);
12160 return false;
12161 }
12162
12163 // 3. Section 3.4.1: SVE fixed length must obey the architectural limits.
12164 if (ISA == 's' && UserVLEN != 0 &&
12165 ((UserVLEN * WDS > 2048) || (UserVLEN * WDS % 128 != 0))) {
12166 CGM.getDiags().Report(SLoc, diag::warn_simdlen_must_fit_lanes) << WDS;
12167 return false;
12168 }
12169
12170 return true;
12171}
12172
12174 llvm::Function *Fn) {
12175 ASTContext &C = CGM.getContext();
12176 FD = FD->getMostRecentDecl();
12177 while (FD) {
12178 // Map params to their positions in function decl.
12179 llvm::DenseMap<const Decl *, unsigned> ParamPositions;
12180 if (isa<CXXMethodDecl>(FD))
12181 ParamPositions.try_emplace(FD, 0);
12182 unsigned ParamPos = ParamPositions.size();
12183 for (const ParmVarDecl *P : FD->parameters()) {
12184 ParamPositions.try_emplace(P->getCanonicalDecl(), ParamPos);
12185 ++ParamPos;
12186 }
12187 for (const auto *Attr : FD->specific_attrs<OMPDeclareSimdDeclAttr>()) {
12189 ParamPositions.size());
12190 // Mark uniform parameters.
12191 for (const Expr *E : Attr->uniforms()) {
12192 E = E->IgnoreParenImpCasts();
12193 unsigned Pos;
12194 if (isa<CXXThisExpr>(E)) {
12195 Pos = ParamPositions[FD];
12196 } else {
12197 const auto *PVD = cast<ParmVarDecl>(cast<DeclRefExpr>(E)->getDecl())
12198 ->getCanonicalDecl();
12199 auto It = ParamPositions.find(PVD);
12200 assert(It != ParamPositions.end() && "Function parameter not found");
12201 Pos = It->second;
12202 }
12203 ParamAttrs[Pos].Kind =
12204 llvm::OpenMPIRBuilder::DeclareSimdKindTy::Uniform;
12205 }
12206 // Get alignment info.
12207 auto *NI = Attr->alignments_begin();
12208 for (const Expr *E : Attr->aligneds()) {
12209 E = E->IgnoreParenImpCasts();
12210 unsigned Pos;
12211 QualType ParmTy;
12212 if (isa<CXXThisExpr>(E)) {
12213 Pos = ParamPositions[FD];
12214 ParmTy = E->getType();
12215 } else {
12216 const auto *PVD = cast<ParmVarDecl>(cast<DeclRefExpr>(E)->getDecl())
12217 ->getCanonicalDecl();
12218 auto It = ParamPositions.find(PVD);
12219 assert(It != ParamPositions.end() && "Function parameter not found");
12220 Pos = It->second;
12221 ParmTy = PVD->getType();
12222 }
12223 ParamAttrs[Pos].Alignment =
12224 (*NI)
12225 ? (*NI)->EvaluateKnownConstInt(C)
12226 : llvm::APSInt::getUnsigned(
12227 C.toCharUnitsFromBits(C.getOpenMPDefaultSimdAlign(ParmTy))
12228 .getQuantity());
12229 ++NI;
12230 }
12231 // Mark linear parameters.
12232 auto *SI = Attr->steps_begin();
12233 auto *MI = Attr->modifiers_begin();
12234 for (const Expr *E : Attr->linears()) {
12235 E = E->IgnoreParenImpCasts();
12236 unsigned Pos;
12237 bool IsReferenceType = false;
12238 // Rescaling factor needed to compute the linear parameter
12239 // value in the mangled name.
12240 unsigned PtrRescalingFactor = 1;
12241 if (isa<CXXThisExpr>(E)) {
12242 Pos = ParamPositions[FD];
12243 auto *P = cast<PointerType>(E->getType());
12244 PtrRescalingFactor = CGM.getContext()
12245 .getTypeSizeInChars(P->getPointeeType())
12246 .getQuantity();
12247 } else {
12248 const auto *PVD = cast<ParmVarDecl>(cast<DeclRefExpr>(E)->getDecl())
12249 ->getCanonicalDecl();
12250 auto It = ParamPositions.find(PVD);
12251 assert(It != ParamPositions.end() && "Function parameter not found");
12252 Pos = It->second;
12253 if (auto *P = dyn_cast<PointerType>(PVD->getType()))
12254 PtrRescalingFactor = CGM.getContext()
12255 .getTypeSizeInChars(P->getPointeeType())
12256 .getQuantity();
12257 else if (PVD->getType()->isReferenceType()) {
12258 IsReferenceType = true;
12259 PtrRescalingFactor =
12260 CGM.getContext()
12261 .getTypeSizeInChars(PVD->getType().getNonReferenceType())
12262 .getQuantity();
12263 }
12264 }
12265 llvm::OpenMPIRBuilder::DeclareSimdAttrTy &ParamAttr = ParamAttrs[Pos];
12266 if (*MI == OMPC_LINEAR_ref)
12267 ParamAttr.Kind = llvm::OpenMPIRBuilder::DeclareSimdKindTy::LinearRef;
12268 else if (*MI == OMPC_LINEAR_uval)
12269 ParamAttr.Kind = llvm::OpenMPIRBuilder::DeclareSimdKindTy::LinearUVal;
12270 else if (IsReferenceType)
12271 ParamAttr.Kind = llvm::OpenMPIRBuilder::DeclareSimdKindTy::LinearVal;
12272 else
12273 ParamAttr.Kind = llvm::OpenMPIRBuilder::DeclareSimdKindTy::Linear;
12274 // Assuming a stride of 1, for `linear` without modifiers.
12275 ParamAttr.StrideOrArg = llvm::APSInt::getUnsigned(1);
12276 if (*SI) {
12278 if (!(*SI)->EvaluateAsInt(Result, C, Expr::SE_AllowSideEffects)) {
12279 if (const auto *DRE =
12280 cast<DeclRefExpr>((*SI)->IgnoreParenImpCasts())) {
12281 if (const auto *StridePVD =
12282 dyn_cast<ParmVarDecl>(DRE->getDecl())) {
12283 ParamAttr.HasVarStride = true;
12284 auto It = ParamPositions.find(StridePVD->getCanonicalDecl());
12285 assert(It != ParamPositions.end() &&
12286 "Function parameter not found");
12287 ParamAttr.StrideOrArg = llvm::APSInt::getUnsigned(It->second);
12288 }
12289 }
12290 } else {
12291 ParamAttr.StrideOrArg = Result.Val.getInt();
12292 }
12293 }
12294 // If we are using a linear clause on a pointer, we need to
12295 // rescale the value of linear_step with the byte size of the
12296 // pointee type.
12297 if (!ParamAttr.HasVarStride &&
12298 (ParamAttr.Kind ==
12299 llvm::OpenMPIRBuilder::DeclareSimdKindTy::Linear ||
12300 ParamAttr.Kind ==
12301 llvm::OpenMPIRBuilder::DeclareSimdKindTy::LinearRef))
12302 ParamAttr.StrideOrArg = ParamAttr.StrideOrArg * PtrRescalingFactor;
12303 ++SI;
12304 ++MI;
12305 }
12306 llvm::APSInt VLENVal;
12307 SourceLocation ExprLoc;
12308 const Expr *VLENExpr = Attr->getSimdlen();
12309 if (VLENExpr) {
12310 VLENVal = VLENExpr->EvaluateKnownConstInt(C);
12311 ExprLoc = VLENExpr->getExprLoc();
12312 }
12313 llvm::OpenMPIRBuilder::DeclareSimdBranch State =
12314 convertDeclareSimdBranch(Attr->getBranchState());
12315 if (CGM.getTriple().isX86()) {
12316 unsigned NumElts = evaluateCDTSize(FD, ParamAttrs);
12317 assert(NumElts && "Non-zero simdlen/cdtsize expected");
12318 OMPBuilder.emitX86DeclareSimdFunction(Fn, NumElts, VLENVal, ParamAttrs,
12319 State);
12320 } else if (CGM.getTriple().getArch() == llvm::Triple::aarch64) {
12321 unsigned VLEN = VLENVal.getExtValue();
12322 // Get basic data for building the vector signature.
12323 const auto Data = getNDSWDS(FD, ParamAttrs);
12324 const unsigned NDS = std::get<0>(Data);
12325 const unsigned WDS = std::get<1>(Data);
12326 const bool OutputBecomesInput = std::get<2>(Data);
12327 if (CGM.getTarget().hasFeature("sve")) {
12328 if (validateAArch64Simdlen(CGM, ExprLoc, VLEN, WDS, 's'))
12329 OMPBuilder.emitAArch64DeclareSimdFunction(
12330 Fn, VLEN, ParamAttrs, State, 's', NDS, OutputBecomesInput);
12331 } else if (CGM.getTarget().hasFeature("neon")) {
12332 if (validateAArch64Simdlen(CGM, ExprLoc, VLEN, WDS, 'n'))
12333 OMPBuilder.emitAArch64DeclareSimdFunction(
12334 Fn, VLEN, ParamAttrs, State, 'n', NDS, OutputBecomesInput);
12335 }
12336 }
12337 }
12338 FD = FD->getPreviousDecl();
12339 }
12340}
12341
12342namespace {
12343/// Cleanup action for doacross support.
12344class DoacrossCleanupTy final : public EHScopeStack::Cleanup {
12345public:
12346 static const int DoacrossFinArgs = 2;
12347
12348private:
12349 llvm::FunctionCallee RTLFn;
12350 llvm::Value *Args[DoacrossFinArgs];
12351
12352public:
12353 DoacrossCleanupTy(llvm::FunctionCallee RTLFn,
12354 ArrayRef<llvm::Value *> CallArgs)
12355 : RTLFn(RTLFn) {
12356 assert(CallArgs.size() == DoacrossFinArgs);
12357 std::copy(CallArgs.begin(), CallArgs.end(), std::begin(Args));
12358 }
12359 void Emit(CodeGenFunction &CGF, Flags /*flags*/) override {
12360 if (!CGF.HaveInsertPoint())
12361 return;
12362 CGF.EmitRuntimeCall(RTLFn, Args);
12363 }
12364};
12365} // namespace
12366
12368 const OMPLoopDirective &D,
12369 ArrayRef<Expr *> NumIterations) {
12370 if (!CGF.HaveInsertPoint())
12371 return;
12372
12373 ASTContext &C = CGM.getContext();
12374 QualType Int64Ty = C.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/true);
12375 RecordDecl *RD;
12376 if (KmpDimTy.isNull()) {
12377 // Build struct kmp_dim { // loop bounds info casted to kmp_int64
12378 // kmp_int64 lo; // lower
12379 // kmp_int64 up; // upper
12380 // kmp_int64 st; // stride
12381 // };
12382 RD = C.buildImplicitRecord("kmp_dim");
12383 RD->startDefinition();
12384 addFieldToRecordDecl(C, RD, Int64Ty);
12385 addFieldToRecordDecl(C, RD, Int64Ty);
12386 addFieldToRecordDecl(C, RD, Int64Ty);
12387 RD->completeDefinition();
12388 KmpDimTy = C.getCanonicalTagType(RD);
12389 } else {
12390 RD = KmpDimTy->castAsRecordDecl();
12391 }
12392 llvm::APInt Size(/*numBits=*/32, NumIterations.size());
12393 QualType ArrayTy = C.getConstantArrayType(KmpDimTy, Size, nullptr,
12395
12396 Address DimsAddr = CGF.CreateMemTemp(ArrayTy, "dims");
12397 CGF.EmitNullInitialization(DimsAddr, ArrayTy);
12398 enum { LowerFD = 0, UpperFD, StrideFD };
12399 // Fill dims with data.
12400 for (unsigned I = 0, E = NumIterations.size(); I < E; ++I) {
12401 LValue DimsLVal = CGF.MakeAddrLValue(
12402 CGF.Builder.CreateConstArrayGEP(DimsAddr, I), KmpDimTy);
12403 // dims.upper = num_iterations;
12404 LValue UpperLVal = CGF.EmitLValueForField(
12405 DimsLVal, *std::next(RD->field_begin(), UpperFD));
12406 llvm::Value *NumIterVal = CGF.EmitScalarConversion(
12407 CGF.EmitScalarExpr(NumIterations[I]), NumIterations[I]->getType(),
12408 Int64Ty, NumIterations[I]->getExprLoc());
12409 CGF.EmitStoreOfScalar(NumIterVal, UpperLVal);
12410 // dims.stride = 1;
12411 LValue StrideLVal = CGF.EmitLValueForField(
12412 DimsLVal, *std::next(RD->field_begin(), StrideFD));
12413 CGF.EmitStoreOfScalar(llvm::ConstantInt::getSigned(CGM.Int64Ty, /*V=*/1),
12414 StrideLVal);
12415 }
12416
12417 // Build call void __kmpc_doacross_init(ident_t *loc, kmp_int32 gtid,
12418 // kmp_int32 num_dims, struct kmp_dim * dims);
12419 llvm::Value *Args[] = {
12420 emitUpdateLocation(CGF, D.getBeginLoc()),
12421 getThreadID(CGF, D.getBeginLoc()),
12422 llvm::ConstantInt::getSigned(CGM.Int32Ty, NumIterations.size()),
12424 CGF.Builder.CreateConstArrayGEP(DimsAddr, 0).emitRawPointer(CGF),
12425 CGM.VoidPtrTy)};
12426
12427 llvm::FunctionCallee RTLFn = OMPBuilder.getOrCreateRuntimeFunction(
12428 CGM.getModule(), OMPRTL___kmpc_doacross_init);
12429 CGF.EmitRuntimeCall(RTLFn, Args);
12430 llvm::Value *FiniArgs[DoacrossCleanupTy::DoacrossFinArgs] = {
12431 emitUpdateLocation(CGF, D.getEndLoc()), getThreadID(CGF, D.getEndLoc())};
12432 llvm::FunctionCallee FiniRTLFn = OMPBuilder.getOrCreateRuntimeFunction(
12433 CGM.getModule(), OMPRTL___kmpc_doacross_fini);
12434 CGF.EHStack.pushCleanup<DoacrossCleanupTy>(NormalAndEHCleanup, FiniRTLFn,
12435 llvm::ArrayRef(FiniArgs));
12436}
12437
12438template <typename T>
12440 const T *C, llvm::Value *ULoc,
12441 llvm::Value *ThreadID) {
12442 QualType Int64Ty =
12443 CGM.getContext().getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1);
12444 llvm::APInt Size(/*numBits=*/32, C->getNumLoops());
12446 Int64Ty, Size, nullptr, ArraySizeModifier::Normal, 0);
12447 Address CntAddr = CGF.CreateMemTemp(ArrayTy, ".cnt.addr");
12448 for (unsigned I = 0, E = C->getNumLoops(); I < E; ++I) {
12449 const Expr *CounterVal = C->getLoopData(I);
12450 assert(CounterVal);
12451 llvm::Value *CntVal = CGF.EmitScalarConversion(
12452 CGF.EmitScalarExpr(CounterVal), CounterVal->getType(), Int64Ty,
12453 CounterVal->getExprLoc());
12454 CGF.EmitStoreOfScalar(CntVal, CGF.Builder.CreateConstArrayGEP(CntAddr, I),
12455 /*Volatile=*/false, Int64Ty);
12456 }
12457 llvm::Value *Args[] = {
12458 ULoc, ThreadID,
12459 CGF.Builder.CreateConstArrayGEP(CntAddr, 0).emitRawPointer(CGF)};
12460 llvm::FunctionCallee RTLFn;
12461 llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder();
12462 OMPDoacrossKind<T> ODK;
12463 if (ODK.isSource(C)) {
12464 RTLFn = OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(),
12465 OMPRTL___kmpc_doacross_post);
12466 } else {
12467 assert(ODK.isSink(C) && "Expect sink modifier.");
12468 RTLFn = OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(),
12469 OMPRTL___kmpc_doacross_wait);
12470 }
12471 CGF.EmitRuntimeCall(RTLFn, Args);
12472}
12473
12475 const OMPDependClause *C) {
12477 CGF, CGM, C, emitUpdateLocation(CGF, C->getBeginLoc()),
12478 getThreadID(CGF, C->getBeginLoc()));
12479}
12480
12482 const OMPDoacrossClause *C) {
12484 CGF, CGM, C, emitUpdateLocation(CGF, C->getBeginLoc()),
12485 getThreadID(CGF, C->getBeginLoc()));
12486}
12487
12489 llvm::FunctionCallee Callee,
12490 ArrayRef<llvm::Value *> Args) const {
12491 assert(Loc.isValid() && "Outlined function call location must be valid.");
12493
12494 if (auto *Fn = dyn_cast<llvm::Function>(Callee.getCallee())) {
12495 if (Fn->doesNotThrow()) {
12496 CGF.EmitNounwindRuntimeCall(Fn, Args);
12497 return;
12498 }
12499 }
12500 CGF.EmitRuntimeCall(Callee, Args);
12501}
12502
12504 CodeGenFunction &CGF, SourceLocation Loc, llvm::FunctionCallee OutlinedFn,
12505 ArrayRef<llvm::Value *> Args) const {
12506 emitCall(CGF, Loc, OutlinedFn, Args);
12507}
12508
12510 if (const auto *FD = dyn_cast<FunctionDecl>(D))
12511 if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(FD))
12513}
12514
12516 const VarDecl *NativeParam,
12517 const VarDecl *TargetParam) const {
12518 return CGF.GetAddrOfLocalVar(NativeParam);
12519}
12520
12521/// Return allocator value from expression, or return a null allocator (default
12522/// when no allocator specified).
12523static llvm::Value *getAllocatorVal(CodeGenFunction &CGF,
12524 const Expr *Allocator) {
12525 llvm::Value *AllocVal;
12526 if (Allocator) {
12527 AllocVal = CGF.EmitScalarExpr(Allocator);
12528 // According to the standard, the original allocator type is a enum
12529 // (integer). Convert to pointer type, if required.
12530 AllocVal = CGF.EmitScalarConversion(AllocVal, Allocator->getType(),
12531 CGF.getContext().VoidPtrTy,
12532 Allocator->getExprLoc());
12533 } else {
12534 // If no allocator specified, it defaults to the null allocator.
12535 AllocVal = llvm::Constant::getNullValue(
12537 }
12538 return AllocVal;
12539}
12540
12541/// Return the alignment from an allocate directive if present.
12542static llvm::Value *getAlignmentValue(CodeGenModule &CGM, const VarDecl *VD) {
12543 std::optional<CharUnits> AllocateAlignment = CGM.getOMPAllocateAlignment(VD);
12544
12545 if (!AllocateAlignment)
12546 return nullptr;
12547
12548 return llvm::ConstantInt::get(CGM.SizeTy, AllocateAlignment->getQuantity());
12549}
12550
12552 const VarDecl *VD) {
12553 if (!VD)
12554 return Address::invalid();
12555 Address UntiedAddr = Address::invalid();
12556 Address UntiedRealAddr = Address::invalid();
12557 auto It = FunctionToUntiedTaskStackMap.find(CGF.CurFn);
12558 if (It != FunctionToUntiedTaskStackMap.end()) {
12559 const UntiedLocalVarsAddressesMap &UntiedData =
12560 UntiedLocalVarsStack[It->second];
12561 auto I = UntiedData.find(VD);
12562 if (I != UntiedData.end()) {
12563 UntiedAddr = I->second.first;
12564 UntiedRealAddr = I->second.second;
12565 }
12566 }
12567 const VarDecl *CVD = VD->getCanonicalDecl();
12568 if (CVD->hasAttr<OMPAllocateDeclAttr>()) {
12569 // Use the default allocation.
12570 if (!isAllocatableDecl(VD))
12571 return UntiedAddr;
12572 llvm::Value *Size;
12573 CharUnits Align = CGM.getContext().getDeclAlign(CVD);
12574 if (CVD->getType()->isVariablyModifiedType()) {
12575 Size = CGF.getTypeSize(CVD->getType());
12576 // Align the size: ((size + align - 1) / align) * align
12577 Size = CGF.Builder.CreateNUWAdd(
12578 Size, CGM.getSize(Align - CharUnits::fromQuantity(1)));
12579 Size = CGF.Builder.CreateUDiv(Size, CGM.getSize(Align));
12580 Size = CGF.Builder.CreateNUWMul(Size, CGM.getSize(Align));
12581 } else {
12582 CharUnits Sz = CGM.getContext().getTypeSizeInChars(CVD->getType());
12583 Size = CGM.getSize(Sz.alignTo(Align));
12584 }
12585 llvm::Value *ThreadID = getThreadID(CGF, CVD->getBeginLoc());
12586 const auto *AA = CVD->getAttr<OMPAllocateDeclAttr>();
12587 const Expr *Allocator = AA->getAllocator();
12588 llvm::Value *AllocVal = getAllocatorVal(CGF, Allocator);
12589 llvm::Value *Alignment = getAlignmentValue(CGM, CVD);
12591 Args.push_back(ThreadID);
12592 if (Alignment)
12593 Args.push_back(Alignment);
12594 Args.push_back(Size);
12595 Args.push_back(AllocVal);
12596 llvm::omp::RuntimeFunction FnID =
12597 Alignment ? OMPRTL___kmpc_aligned_alloc : OMPRTL___kmpc_alloc;
12598 llvm::Value *Addr = CGF.EmitRuntimeCall(
12599 OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(), FnID), Args,
12600 getName({CVD->getName(), ".void.addr"}));
12601 llvm::FunctionCallee FiniRTLFn = OMPBuilder.getOrCreateRuntimeFunction(
12602 CGM.getModule(), OMPRTL___kmpc_free);
12603 QualType Ty = CGM.getContext().getPointerType(CVD->getType());
12605 Addr, CGF.ConvertTypeForMem(Ty), getName({CVD->getName(), ".addr"}));
12606 if (UntiedAddr.isValid())
12607 CGF.EmitStoreOfScalar(Addr, UntiedAddr, /*Volatile=*/false, Ty);
12608
12609 // Cleanup action for allocate support.
12610 class OMPAllocateCleanupTy final : public EHScopeStack::Cleanup {
12611 llvm::FunctionCallee RTLFn;
12612 SourceLocation::UIntTy LocEncoding;
12613 Address Addr;
12614 const Expr *AllocExpr;
12615
12616 public:
12617 OMPAllocateCleanupTy(llvm::FunctionCallee RTLFn,
12618 SourceLocation::UIntTy LocEncoding, Address Addr,
12619 const Expr *AllocExpr)
12620 : RTLFn(RTLFn), LocEncoding(LocEncoding), Addr(Addr),
12621 AllocExpr(AllocExpr) {}
12622 void Emit(CodeGenFunction &CGF, Flags /*flags*/) override {
12623 if (!CGF.HaveInsertPoint())
12624 return;
12625 llvm::Value *Args[3];
12626 Args[0] = CGF.CGM.getOpenMPRuntime().getThreadID(
12627 CGF, SourceLocation::getFromRawEncoding(LocEncoding));
12629 Addr.emitRawPointer(CGF), CGF.VoidPtrTy);
12630 llvm::Value *AllocVal = getAllocatorVal(CGF, AllocExpr);
12631 Args[2] = AllocVal;
12632 CGF.EmitRuntimeCall(RTLFn, Args);
12633 }
12634 };
12635 Address VDAddr =
12636 UntiedRealAddr.isValid()
12637 ? UntiedRealAddr
12638 : Address(Addr, CGF.ConvertTypeForMem(CVD->getType()), Align);
12639 CGF.EHStack.pushCleanup<OMPAllocateCleanupTy>(
12640 NormalAndEHCleanup, FiniRTLFn, CVD->getLocation().getRawEncoding(),
12641 VDAddr, Allocator);
12642 if (UntiedRealAddr.isValid())
12643 if (auto *Region =
12644 dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo))
12645 Region->emitUntiedSwitch(CGF);
12646 return VDAddr;
12647 }
12648 return UntiedAddr;
12649}
12650
12652 const VarDecl *VD) const {
12653 auto It = FunctionToUntiedTaskStackMap.find(CGF.CurFn);
12654 if (It == FunctionToUntiedTaskStackMap.end())
12655 return false;
12656 return UntiedLocalVarsStack[It->second].count(VD) > 0;
12657}
12658
12660 CodeGenModule &CGM, const OMPLoopDirective &S)
12661 : CGM(CGM), NeedToPush(S.hasClausesOfKind<OMPNontemporalClause>()) {
12662 assert(CGM.getLangOpts().OpenMP && "Not in OpenMP mode.");
12663 if (!NeedToPush)
12664 return;
12666 CGM.getOpenMPRuntime().NontemporalDeclsStack.emplace_back();
12667 for (const auto *C : S.getClausesOfKind<OMPNontemporalClause>()) {
12668 for (const Stmt *Ref : C->private_refs()) {
12669 const auto *SimpleRefExpr = cast<Expr>(Ref)->IgnoreParenImpCasts();
12670 const ValueDecl *VD;
12671 if (const auto *DRE = dyn_cast<DeclRefExpr>(SimpleRefExpr)) {
12672 VD = DRE->getDecl();
12673 } else {
12674 const auto *ME = cast<MemberExpr>(SimpleRefExpr);
12675 assert((ME->isImplicitCXXThis() ||
12676 isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts())) &&
12677 "Expected member of current class.");
12678 VD = ME->getMemberDecl();
12679 }
12680 DS.insert(VD);
12681 }
12682 }
12683}
12684
12686 if (!NeedToPush)
12687 return;
12688 CGM.getOpenMPRuntime().NontemporalDeclsStack.pop_back();
12689}
12690
12692 CodeGenFunction &CGF,
12693 const llvm::MapVector<CanonicalDeclPtr<const VarDecl>,
12694 std::pair<Address, Address>> &LocalVars)
12695 : CGM(CGF.CGM), NeedToPush(!LocalVars.empty()) {
12696 if (!NeedToPush)
12697 return;
12698 CGM.getOpenMPRuntime().FunctionToUntiedTaskStackMap.try_emplace(
12699 CGF.CurFn, CGM.getOpenMPRuntime().UntiedLocalVarsStack.size());
12700 CGM.getOpenMPRuntime().UntiedLocalVarsStack.push_back(LocalVars);
12701}
12702
12704 if (!NeedToPush)
12705 return;
12706 CGM.getOpenMPRuntime().UntiedLocalVarsStack.pop_back();
12707}
12708
12710 assert(CGM.getLangOpts().OpenMP && "Not in OpenMP mode.");
12711
12712 return llvm::any_of(
12713 CGM.getOpenMPRuntime().NontemporalDeclsStack,
12714 [VD](const NontemporalDeclsSet &Set) { return Set.contains(VD); });
12715}
12716
12717void CGOpenMPRuntime::LastprivateConditionalRAII::tryToDisableInnerAnalysis(
12718 const OMPExecutableDirective &S,
12719 llvm::DenseSet<CanonicalDeclPtr<const Decl>> &NeedToAddForLPCsAsDisabled)
12720 const {
12721 llvm::DenseSet<CanonicalDeclPtr<const Decl>> NeedToCheckForLPCs;
12722 // Vars in target/task regions must be excluded completely.
12723 if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()) ||
12724 isOpenMPTaskingDirective(S.getDirectiveKind())) {
12726 getOpenMPCaptureRegions(CaptureRegions, S.getDirectiveKind());
12727 const CapturedStmt *CS = S.getCapturedStmt(CaptureRegions.front());
12728 for (const CapturedStmt::Capture &Cap : CS->captures()) {
12729 if (Cap.capturesVariable() || Cap.capturesVariableByCopy())
12730 NeedToCheckForLPCs.insert(Cap.getCapturedVar());
12731 }
12732 }
12733 // Exclude vars in private clauses.
12734 for (const auto *C : S.getClausesOfKind<OMPPrivateClause>()) {
12735 for (const Expr *Ref : C->varlist()) {
12736 if (!Ref->getType()->isScalarType())
12737 continue;
12738 const auto *DRE = dyn_cast<DeclRefExpr>(Ref->IgnoreParenImpCasts());
12739 if (!DRE)
12740 continue;
12741 NeedToCheckForLPCs.insert(DRE->getDecl());
12742 }
12743 }
12744 for (const auto *C : S.getClausesOfKind<OMPFirstprivateClause>()) {
12745 for (const Expr *Ref : C->varlist()) {
12746 if (!Ref->getType()->isScalarType())
12747 continue;
12748 const auto *DRE = dyn_cast<DeclRefExpr>(Ref->IgnoreParenImpCasts());
12749 if (!DRE)
12750 continue;
12751 NeedToCheckForLPCs.insert(DRE->getDecl());
12752 }
12753 }
12754 for (const auto *C : S.getClausesOfKind<OMPLastprivateClause>()) {
12755 for (const Expr *Ref : C->varlist()) {
12756 if (!Ref->getType()->isScalarType())
12757 continue;
12758 const auto *DRE = dyn_cast<DeclRefExpr>(Ref->IgnoreParenImpCasts());
12759 if (!DRE)
12760 continue;
12761 NeedToCheckForLPCs.insert(DRE->getDecl());
12762 }
12763 }
12764 for (const auto *C : S.getClausesOfKind<OMPReductionClause>()) {
12765 for (const Expr *Ref : C->varlist()) {
12766 if (!Ref->getType()->isScalarType())
12767 continue;
12768 const auto *DRE = dyn_cast<DeclRefExpr>(Ref->IgnoreParenImpCasts());
12769 if (!DRE)
12770 continue;
12771 NeedToCheckForLPCs.insert(DRE->getDecl());
12772 }
12773 }
12774 for (const auto *C : S.getClausesOfKind<OMPLinearClause>()) {
12775 for (const Expr *Ref : C->varlist()) {
12776 if (!Ref->getType()->isScalarType())
12777 continue;
12778 const auto *DRE = dyn_cast<DeclRefExpr>(Ref->IgnoreParenImpCasts());
12779 if (!DRE)
12780 continue;
12781 NeedToCheckForLPCs.insert(DRE->getDecl());
12782 }
12783 }
12784 for (const Decl *VD : NeedToCheckForLPCs) {
12785 for (const LastprivateConditionalData &Data :
12786 llvm::reverse(CGM.getOpenMPRuntime().LastprivateConditionalStack)) {
12787 if (Data.DeclToUniqueName.count(VD) > 0) {
12788 if (!Data.Disabled)
12789 NeedToAddForLPCsAsDisabled.insert(VD);
12790 break;
12791 }
12792 }
12793 }
12794}
12795
12796CGOpenMPRuntime::LastprivateConditionalRAII::LastprivateConditionalRAII(
12797 CodeGenFunction &CGF, const OMPExecutableDirective &S, LValue IVLVal)
12798 : CGM(CGF.CGM),
12799 Action((CGM.getLangOpts().OpenMP >= 50 &&
12800 llvm::any_of(S.getClausesOfKind<OMPLastprivateClause>(),
12801 [](const OMPLastprivateClause *C) {
12802 return C->getKind() ==
12803 OMPC_LASTPRIVATE_conditional;
12804 }))
12805 ? ActionToDo::PushAsLastprivateConditional
12806 : ActionToDo::DoNotPush) {
12807 assert(CGM.getLangOpts().OpenMP && "Not in OpenMP mode.");
12808 if (CGM.getLangOpts().OpenMP < 50 || Action == ActionToDo::DoNotPush)
12809 return;
12810 assert(Action == ActionToDo::PushAsLastprivateConditional &&
12811 "Expected a push action.");
12813 CGM.getOpenMPRuntime().LastprivateConditionalStack.emplace_back();
12814 for (const auto *C : S.getClausesOfKind<OMPLastprivateClause>()) {
12815 if (C->getKind() != OMPC_LASTPRIVATE_conditional)
12816 continue;
12817
12818 for (const Expr *Ref : C->varlist()) {
12819 Data.DeclToUniqueName.insert(std::make_pair(
12820 cast<DeclRefExpr>(Ref->IgnoreParenImpCasts())->getDecl(),
12821 SmallString<16>(generateUniqueName(CGM, "pl_cond", Ref))));
12822 }
12823 }
12824 Data.IVLVal = IVLVal;
12825 Data.Fn = CGF.CurFn;
12826}
12827
12828CGOpenMPRuntime::LastprivateConditionalRAII::LastprivateConditionalRAII(
12830 : CGM(CGF.CGM), Action(ActionToDo::DoNotPush) {
12831 assert(CGM.getLangOpts().OpenMP && "Not in OpenMP mode.");
12832 if (CGM.getLangOpts().OpenMP < 50)
12833 return;
12834 llvm::DenseSet<CanonicalDeclPtr<const Decl>> NeedToAddForLPCsAsDisabled;
12835 tryToDisableInnerAnalysis(S, NeedToAddForLPCsAsDisabled);
12836 if (!NeedToAddForLPCsAsDisabled.empty()) {
12837 Action = ActionToDo::DisableLastprivateConditional;
12838 LastprivateConditionalData &Data =
12840 for (const Decl *VD : NeedToAddForLPCsAsDisabled)
12841 Data.DeclToUniqueName.try_emplace(VD);
12842 Data.Fn = CGF.CurFn;
12843 Data.Disabled = true;
12844 }
12845}
12846
12847CGOpenMPRuntime::LastprivateConditionalRAII
12849 CodeGenFunction &CGF, const OMPExecutableDirective &S) {
12850 return LastprivateConditionalRAII(CGF, S);
12851}
12852
12854 if (CGM.getLangOpts().OpenMP < 50)
12855 return;
12856 if (Action == ActionToDo::DisableLastprivateConditional) {
12857 assert(CGM.getOpenMPRuntime().LastprivateConditionalStack.back().Disabled &&
12858 "Expected list of disabled private vars.");
12859 CGM.getOpenMPRuntime().LastprivateConditionalStack.pop_back();
12860 }
12861 if (Action == ActionToDo::PushAsLastprivateConditional) {
12862 assert(
12863 !CGM.getOpenMPRuntime().LastprivateConditionalStack.back().Disabled &&
12864 "Expected list of lastprivate conditional vars.");
12865 CGM.getOpenMPRuntime().LastprivateConditionalStack.pop_back();
12866 }
12867}
12868
12870 const VarDecl *VD) {
12871 ASTContext &C = CGM.getContext();
12872 auto I = LastprivateConditionalToTypes.try_emplace(CGF.CurFn).first;
12873 QualType NewType;
12874 const FieldDecl *VDField;
12875 const FieldDecl *FiredField;
12876 LValue BaseLVal;
12877 auto VI = I->getSecond().find(VD);
12878 if (VI == I->getSecond().end()) {
12879 RecordDecl *RD = C.buildImplicitRecord("lasprivate.conditional");
12880 RD->startDefinition();
12881 VDField = addFieldToRecordDecl(C, RD, VD->getType().getNonReferenceType());
12882 FiredField = addFieldToRecordDecl(C, RD, C.CharTy);
12883 RD->completeDefinition();
12884 NewType = C.getCanonicalTagType(RD);
12885 Address Addr = CGF.CreateMemTemp(NewType, C.getDeclAlign(VD), VD->getName());
12886 BaseLVal = CGF.MakeAddrLValue(Addr, NewType, AlignmentSource::Decl);
12887 I->getSecond().try_emplace(VD, NewType, VDField, FiredField, BaseLVal);
12888 } else {
12889 NewType = std::get<0>(VI->getSecond());
12890 VDField = std::get<1>(VI->getSecond());
12891 FiredField = std::get<2>(VI->getSecond());
12892 BaseLVal = std::get<3>(VI->getSecond());
12893 }
12894 LValue FiredLVal =
12895 CGF.EmitLValueForField(BaseLVal, FiredField);
12897 llvm::ConstantInt::getNullValue(CGF.ConvertTypeForMem(C.CharTy)),
12898 FiredLVal);
12899 return CGF.EmitLValueForField(BaseLVal, VDField).getAddress();
12900}
12901
12902namespace {
12903/// Checks if the lastprivate conditional variable is referenced in LHS.
12904class LastprivateConditionalRefChecker final
12905 : public ConstStmtVisitor<LastprivateConditionalRefChecker, bool> {
12907 const Expr *FoundE = nullptr;
12908 const Decl *FoundD = nullptr;
12909 StringRef UniqueDeclName;
12910 LValue IVLVal;
12911 llvm::Function *FoundFn = nullptr;
12912 SourceLocation Loc;
12913
12914public:
12915 bool VisitDeclRefExpr(const DeclRefExpr *E) {
12917 llvm::reverse(LPM)) {
12918 auto It = D.DeclToUniqueName.find(E->getDecl());
12919 if (It == D.DeclToUniqueName.end())
12920 continue;
12921 if (D.Disabled)
12922 return false;
12923 FoundE = E;
12924 FoundD = E->getDecl()->getCanonicalDecl();
12925 UniqueDeclName = It->second;
12926 IVLVal = D.IVLVal;
12927 FoundFn = D.Fn;
12928 break;
12929 }
12930 return FoundE == E;
12931 }
12932 bool VisitMemberExpr(const MemberExpr *E) {
12934 return false;
12936 llvm::reverse(LPM)) {
12937 auto It = D.DeclToUniqueName.find(E->getMemberDecl());
12938 if (It == D.DeclToUniqueName.end())
12939 continue;
12940 if (D.Disabled)
12941 return false;
12942 FoundE = E;
12943 FoundD = E->getMemberDecl()->getCanonicalDecl();
12944 UniqueDeclName = It->second;
12945 IVLVal = D.IVLVal;
12946 FoundFn = D.Fn;
12947 break;
12948 }
12949 return FoundE == E;
12950 }
12951 bool VisitStmt(const Stmt *S) {
12952 for (const Stmt *Child : S->children()) {
12953 if (!Child)
12954 continue;
12955 if (const auto *E = dyn_cast<Expr>(Child))
12956 if (!E->isGLValue())
12957 continue;
12958 if (Visit(Child))
12959 return true;
12960 }
12961 return false;
12962 }
12963 explicit LastprivateConditionalRefChecker(
12964 ArrayRef<CGOpenMPRuntime::LastprivateConditionalData> LPM)
12965 : LPM(LPM) {}
12966 std::tuple<const Expr *, const Decl *, StringRef, LValue, llvm::Function *>
12967 getFoundData() const {
12968 return std::make_tuple(FoundE, FoundD, UniqueDeclName, IVLVal, FoundFn);
12969 }
12970};
12971} // namespace
12972
12974 LValue IVLVal,
12975 StringRef UniqueDeclName,
12976 LValue LVal,
12977 SourceLocation Loc) {
12978 // Last updated loop counter for the lastprivate conditional var.
12979 // int<xx> last_iv = 0;
12980 llvm::Type *LLIVTy = CGF.ConvertTypeForMem(IVLVal.getType());
12981 llvm::Constant *LastIV = OMPBuilder.getOrCreateInternalVariable(
12982 LLIVTy, getName({UniqueDeclName, "iv"}));
12983 cast<llvm::GlobalVariable>(LastIV)->setAlignment(
12984 IVLVal.getAlignment().getAsAlign());
12985 LValue LastIVLVal =
12986 CGF.MakeNaturalAlignRawAddrLValue(LastIV, IVLVal.getType());
12987
12988 // Last value of the lastprivate conditional.
12989 // decltype(priv_a) last_a;
12990 llvm::GlobalVariable *Last = OMPBuilder.getOrCreateInternalVariable(
12991 CGF.ConvertTypeForMem(LVal.getType()), UniqueDeclName);
12992 cast<llvm::GlobalVariable>(Last)->setAlignment(
12993 LVal.getAlignment().getAsAlign());
12994 LValue LastLVal =
12995 CGF.MakeRawAddrLValue(Last, LVal.getType(), LVal.getAlignment());
12996
12997 // Global loop counter. Required to handle inner parallel-for regions.
12998 // iv
12999 llvm::Value *IVVal = CGF.EmitLoadOfScalar(IVLVal, Loc);
13000
13001 // #pragma omp critical(a)
13002 // if (last_iv <= iv) {
13003 // last_iv = iv;
13004 // last_a = priv_a;
13005 // }
13006 auto &&CodeGen = [&LastIVLVal, &IVLVal, IVVal, &LVal, &LastLVal,
13007 Loc](CodeGenFunction &CGF, PrePostActionTy &Action) {
13008 Action.Enter(CGF);
13009 llvm::Value *LastIVVal = CGF.EmitLoadOfScalar(LastIVLVal, Loc);
13010 // (last_iv <= iv) ? Check if the variable is updated and store new
13011 // value in global var.
13012 llvm::Value *CmpRes;
13013 if (IVLVal.getType()->isSignedIntegerType()) {
13014 CmpRes = CGF.Builder.CreateICmpSLE(LastIVVal, IVVal);
13015 } else {
13016 assert(IVLVal.getType()->isUnsignedIntegerType() &&
13017 "Loop iteration variable must be integer.");
13018 CmpRes = CGF.Builder.CreateICmpULE(LastIVVal, IVVal);
13019 }
13020 llvm::BasicBlock *ThenBB = CGF.createBasicBlock("lp_cond_then");
13021 llvm::BasicBlock *ExitBB = CGF.createBasicBlock("lp_cond_exit");
13022 CGF.Builder.CreateCondBr(CmpRes, ThenBB, ExitBB);
13023 // {
13024 CGF.EmitBlock(ThenBB);
13025
13026 // last_iv = iv;
13027 CGF.EmitStoreOfScalar(IVVal, LastIVLVal);
13028
13029 // last_a = priv_a;
13030 switch (CGF.getEvaluationKind(LVal.getType())) {
13031 case TEK_Scalar: {
13032 llvm::Value *PrivVal = CGF.EmitLoadOfScalar(LVal, Loc);
13033 CGF.EmitStoreOfScalar(PrivVal, LastLVal);
13034 break;
13035 }
13036 case TEK_Complex: {
13037 CodeGenFunction::ComplexPairTy PrivVal = CGF.EmitLoadOfComplex(LVal, Loc);
13038 CGF.EmitStoreOfComplex(PrivVal, LastLVal, /*isInit=*/false);
13039 break;
13040 }
13041 case TEK_Aggregate:
13042 llvm_unreachable(
13043 "Aggregates are not supported in lastprivate conditional.");
13044 }
13045 // }
13046 CGF.EmitBranch(ExitBB);
13047 // There is no need to emit line number for unconditional branch.
13049 CGF.EmitBlock(ExitBB, /*IsFinished=*/true);
13050 };
13051
13052 if (CGM.getLangOpts().OpenMPSimd) {
13053 // Do not emit as a critical region as no parallel region could be emitted.
13054 RegionCodeGenTy ThenRCG(CodeGen);
13055 ThenRCG(CGF);
13056 } else {
13057 emitCriticalRegion(CGF, UniqueDeclName, CodeGen, Loc);
13058 }
13059}
13060
13062 const Expr *LHS) {
13063 if (CGF.getLangOpts().OpenMP < 50 || LastprivateConditionalStack.empty())
13064 return;
13065 LastprivateConditionalRefChecker Checker(LastprivateConditionalStack);
13066 if (!Checker.Visit(LHS))
13067 return;
13068 const Expr *FoundE;
13069 const Decl *FoundD;
13070 StringRef UniqueDeclName;
13071 LValue IVLVal;
13072 llvm::Function *FoundFn;
13073 std::tie(FoundE, FoundD, UniqueDeclName, IVLVal, FoundFn) =
13074 Checker.getFoundData();
13075 if (FoundFn != CGF.CurFn) {
13076 // Special codegen for inner parallel regions.
13077 // ((struct.lastprivate.conditional*)&priv_a)->Fired = 1;
13078 auto It = LastprivateConditionalToTypes[FoundFn].find(FoundD);
13079 assert(It != LastprivateConditionalToTypes[FoundFn].end() &&
13080 "Lastprivate conditional is not found in outer region.");
13081 QualType StructTy = std::get<0>(It->getSecond());
13082 const FieldDecl* FiredDecl = std::get<2>(It->getSecond());
13083 LValue PrivLVal = CGF.EmitLValue(FoundE);
13085 PrivLVal.getAddress(),
13086 CGF.ConvertTypeForMem(CGF.getContext().getPointerType(StructTy)),
13087 CGF.ConvertTypeForMem(StructTy));
13088 LValue BaseLVal =
13089 CGF.MakeAddrLValue(StructAddr, StructTy, AlignmentSource::Decl);
13090 LValue FiredLVal = CGF.EmitLValueForField(BaseLVal, FiredDecl);
13091 CGF.EmitAtomicStore(RValue::get(llvm::ConstantInt::get(
13092 CGF.ConvertTypeForMem(FiredDecl->getType()), 1)),
13093 FiredLVal, llvm::AtomicOrdering::Unordered,
13094 /*IsVolatile=*/true, /*isInit=*/false);
13095 return;
13096 }
13097
13098 // Private address of the lastprivate conditional in the current context.
13099 // priv_a
13100 LValue LVal = CGF.EmitLValue(FoundE);
13101 emitLastprivateConditionalUpdate(CGF, IVLVal, UniqueDeclName, LVal,
13102 FoundE->getExprLoc());
13103}
13104
13107 const llvm::DenseSet<CanonicalDeclPtr<const VarDecl>> &IgnoredDecls) {
13108 if (CGF.getLangOpts().OpenMP < 50 || LastprivateConditionalStack.empty())
13109 return;
13110 auto Range = llvm::reverse(LastprivateConditionalStack);
13111 auto It = llvm::find_if(
13112 Range, [](const LastprivateConditionalData &D) { return !D.Disabled; });
13113 if (It == Range.end() || It->Fn != CGF.CurFn)
13114 return;
13115 auto LPCI = LastprivateConditionalToTypes.find(It->Fn);
13116 assert(LPCI != LastprivateConditionalToTypes.end() &&
13117 "Lastprivates must be registered already.");
13119 getOpenMPCaptureRegions(CaptureRegions, D.getDirectiveKind());
13120 const CapturedStmt *CS = D.getCapturedStmt(CaptureRegions.back());
13121 for (const auto &Pair : It->DeclToUniqueName) {
13122 const auto *VD = cast<VarDecl>(Pair.first->getCanonicalDecl());
13123 if (!CS->capturesVariable(VD) || IgnoredDecls.contains(VD))
13124 continue;
13125 auto I = LPCI->getSecond().find(Pair.first);
13126 assert(I != LPCI->getSecond().end() &&
13127 "Lastprivate must be rehistered already.");
13128 // bool Cmp = priv_a.Fired != 0;
13129 LValue BaseLVal = std::get<3>(I->getSecond());
13130 LValue FiredLVal =
13131 CGF.EmitLValueForField(BaseLVal, std::get<2>(I->getSecond()));
13132 llvm::Value *Res = CGF.EmitLoadOfScalar(FiredLVal, D.getBeginLoc());
13133 llvm::Value *Cmp = CGF.Builder.CreateIsNotNull(Res);
13134 llvm::BasicBlock *ThenBB = CGF.createBasicBlock("lpc.then");
13135 llvm::BasicBlock *DoneBB = CGF.createBasicBlock("lpc.done");
13136 // if (Cmp) {
13137 CGF.Builder.CreateCondBr(Cmp, ThenBB, DoneBB);
13138 CGF.EmitBlock(ThenBB);
13139 Address Addr = CGF.GetAddrOfLocalVar(VD);
13140 LValue LVal;
13141 if (VD->getType()->isReferenceType())
13142 LVal = CGF.EmitLoadOfReferenceLValue(Addr, VD->getType(),
13144 else
13145 LVal = CGF.MakeAddrLValue(Addr, VD->getType().getNonReferenceType(),
13147 emitLastprivateConditionalUpdate(CGF, It->IVLVal, Pair.second, LVal,
13148 D.getBeginLoc());
13150 CGF.EmitBlock(DoneBB, /*IsFinal=*/true);
13151 // }
13152 }
13153}
13154
13156 CodeGenFunction &CGF, LValue PrivLVal, const VarDecl *VD,
13157 SourceLocation Loc) {
13158 if (CGF.getLangOpts().OpenMP < 50)
13159 return;
13160 auto It = LastprivateConditionalStack.back().DeclToUniqueName.find(VD);
13161 assert(It != LastprivateConditionalStack.back().DeclToUniqueName.end() &&
13162 "Unknown lastprivate conditional variable.");
13163 StringRef UniqueName = It->second;
13164 llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(UniqueName);
13165 // The variable was not updated in the region - exit.
13166 if (!GV)
13167 return;
13168 LValue LPLVal = CGF.MakeRawAddrLValue(
13169 GV, PrivLVal.getType().getNonReferenceType(), PrivLVal.getAlignment());
13170 llvm::Value *Res = CGF.EmitLoadOfScalar(LPLVal, Loc);
13171 CGF.EmitStoreOfScalar(Res, PrivLVal);
13172}
13173
13176 const VarDecl *ThreadIDVar, OpenMPDirectiveKind InnermostKind,
13177 const RegionCodeGenTy &CodeGen) {
13178 llvm_unreachable("Not supported in SIMD-only mode");
13179}
13180
13183 const VarDecl *ThreadIDVar, OpenMPDirectiveKind InnermostKind,
13184 const RegionCodeGenTy &CodeGen) {
13185 llvm_unreachable("Not supported in SIMD-only mode");
13186}
13187
13189 const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
13190 const VarDecl *PartIDVar, const VarDecl *TaskTVar,
13191 OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen,
13192 bool Tied, unsigned &NumberOfParts) {
13193 llvm_unreachable("Not supported in SIMD-only mode");
13194}
13195
13197 CodeGenFunction &CGF, SourceLocation Loc, llvm::Function *OutlinedFn,
13198 ArrayRef<llvm::Value *> CapturedVars, const Expr *IfCond,
13199 llvm::Value *NumThreads, OpenMPNumThreadsClauseModifier NumThreadsModifier,
13200 OpenMPSeverityClauseKind Severity, const Expr *Message) {
13201 llvm_unreachable("Not supported in SIMD-only mode");
13202}
13203
13205 CodeGenFunction &CGF, StringRef CriticalName,
13206 const RegionCodeGenTy &CriticalOpGen, SourceLocation Loc,
13207 const Expr *Hint) {
13208 llvm_unreachable("Not supported in SIMD-only mode");
13209}
13210
13212 const RegionCodeGenTy &MasterOpGen,
13213 SourceLocation Loc) {
13214 llvm_unreachable("Not supported in SIMD-only mode");
13215}
13216
13218 const RegionCodeGenTy &MasterOpGen,
13219 SourceLocation Loc,
13220 const Expr *Filter) {
13221 llvm_unreachable("Not supported in SIMD-only mode");
13222}
13223
13225 SourceLocation Loc) {
13226 llvm_unreachable("Not supported in SIMD-only mode");
13227}
13228
13230 CodeGenFunction &CGF, const RegionCodeGenTy &TaskgroupOpGen,
13231 SourceLocation Loc) {
13232 llvm_unreachable("Not supported in SIMD-only mode");
13233}
13234
13236 CodeGenFunction &CGF, const RegionCodeGenTy &SingleOpGen,
13237 SourceLocation Loc, ArrayRef<const Expr *> CopyprivateVars,
13239 ArrayRef<const Expr *> AssignmentOps) {
13240 llvm_unreachable("Not supported in SIMD-only mode");
13241}
13242
13244 const RegionCodeGenTy &OrderedOpGen,
13245 SourceLocation Loc,
13246 bool IsThreads) {
13247 llvm_unreachable("Not supported in SIMD-only mode");
13248}
13249
13251 SourceLocation Loc,
13253 bool EmitChecks,
13254 bool ForceSimpleCall) {
13255 llvm_unreachable("Not supported in SIMD-only mode");
13256}
13257
13260 const OpenMPScheduleTy &ScheduleKind, unsigned IVSize, bool IVSigned,
13261 bool Ordered, const DispatchRTInput &DispatchValues) {
13262 llvm_unreachable("Not supported in SIMD-only mode");
13263}
13264
13266 SourceLocation Loc) {
13267 llvm_unreachable("Not supported in SIMD-only mode");
13268}
13269
13272 const OpenMPScheduleTy &ScheduleKind, const StaticRTInput &Values) {
13273 llvm_unreachable("Not supported in SIMD-only mode");
13274}
13275
13278 OpenMPDistScheduleClauseKind SchedKind, const StaticRTInput &Values) {
13279 llvm_unreachable("Not supported in SIMD-only mode");
13280}
13281
13283 SourceLocation Loc,
13284 unsigned IVSize,
13285 bool IVSigned) {
13286 llvm_unreachable("Not supported in SIMD-only mode");
13287}
13288
13290 SourceLocation Loc,
13291 OpenMPDirectiveKind DKind) {
13292 llvm_unreachable("Not supported in SIMD-only mode");
13293}
13294
13296 SourceLocation Loc,
13297 unsigned IVSize, bool IVSigned,
13298 Address IL, Address LB,
13299 Address UB, Address ST) {
13300 llvm_unreachable("Not supported in SIMD-only mode");
13301}
13302
13304 CodeGenFunction &CGF, llvm::Value *NumThreads, SourceLocation Loc,
13306 SourceLocation SeverityLoc, const Expr *Message,
13307 SourceLocation MessageLoc) {
13308 llvm_unreachable("Not supported in SIMD-only mode");
13309}
13310
13312 ProcBindKind ProcBind,
13313 SourceLocation Loc) {
13314 llvm_unreachable("Not supported in SIMD-only mode");
13315}
13316
13318 const VarDecl *VD,
13319 Address VDAddr,
13320 SourceLocation Loc) {
13321 llvm_unreachable("Not supported in SIMD-only mode");
13322}
13323
13325 const VarDecl *VD, Address VDAddr, SourceLocation Loc, bool PerformInit,
13326 CodeGenFunction *CGF) {
13327 llvm_unreachable("Not supported in SIMD-only mode");
13328}
13329
13331 CodeGenFunction &CGF, QualType VarType, StringRef Name) {
13332 llvm_unreachable("Not supported in SIMD-only mode");
13333}
13334
13337 SourceLocation Loc,
13338 llvm::AtomicOrdering AO) {
13339 llvm_unreachable("Not supported in SIMD-only mode");
13340}
13341
13343 const OMPExecutableDirective &D,
13344 llvm::Function *TaskFunction,
13345 QualType SharedsTy, Address Shareds,
13346 const Expr *IfCond,
13347 const OMPTaskDataTy &Data) {
13348 llvm_unreachable("Not supported in SIMD-only mode");
13349}
13350
13353 llvm::Function *TaskFunction, QualType SharedsTy, Address Shareds,
13354 const Expr *IfCond, const OMPTaskDataTy &Data) {
13355 llvm_unreachable("Not supported in SIMD-only mode");
13356}
13357
13361 ArrayRef<const Expr *> ReductionOps, ReductionOptionsTy Options) {
13362 assert(Options.SimpleReduction && "Only simple reduction is expected.");
13363 CGOpenMPRuntime::emitReduction(CGF, Loc, Privates, LHSExprs, RHSExprs,
13364 ReductionOps, Options);
13365}
13366
13369 ArrayRef<const Expr *> RHSExprs, const OMPTaskDataTy &Data) {
13370 llvm_unreachable("Not supported in SIMD-only mode");
13371}
13372
13374 SourceLocation Loc,
13375 bool IsWorksharingReduction) {
13376 llvm_unreachable("Not supported in SIMD-only mode");
13377}
13378
13380 SourceLocation Loc,
13381 ReductionCodeGen &RCG,
13382 unsigned N) {
13383 llvm_unreachable("Not supported in SIMD-only mode");
13384}
13385
13387 SourceLocation Loc,
13388 llvm::Value *ReductionsPtr,
13389 LValue SharedLVal) {
13390 llvm_unreachable("Not supported in SIMD-only mode");
13391}
13392
13394 SourceLocation Loc,
13395 const OMPTaskDataTy &Data) {
13396 llvm_unreachable("Not supported in SIMD-only mode");
13397}
13398
13401 OpenMPDirectiveKind CancelRegion) {
13402 llvm_unreachable("Not supported in SIMD-only mode");
13403}
13404
13406 SourceLocation Loc, const Expr *IfCond,
13407 OpenMPDirectiveKind CancelRegion) {
13408 llvm_unreachable("Not supported in SIMD-only mode");
13409}
13410
13412 const OMPExecutableDirective &D, StringRef ParentName,
13413 llvm::Function *&OutlinedFn, llvm::Constant *&OutlinedFnID,
13414 bool IsOffloadEntry, const RegionCodeGenTy &CodeGen) {
13415 llvm_unreachable("Not supported in SIMD-only mode");
13416}
13417
13420 llvm::Function *OutlinedFn, llvm::Value *OutlinedFnID, const Expr *IfCond,
13421 llvm::PointerIntPair<const Expr *, 2, OpenMPDeviceClauseModifier> Device,
13422 llvm::function_ref<llvm::Value *(CodeGenFunction &CGF,
13423 const OMPLoopDirective &D)>
13424 SizeEmitter) {
13425 llvm_unreachable("Not supported in SIMD-only mode");
13426}
13427
13429 llvm_unreachable("Not supported in SIMD-only mode");
13430}
13431
13433 llvm_unreachable("Not supported in SIMD-only mode");
13434}
13435
13437 return false;
13438}
13439
13441 const OMPExecutableDirective &D,
13442 SourceLocation Loc,
13443 llvm::Function *OutlinedFn,
13444 ArrayRef<llvm::Value *> CapturedVars) {
13445 llvm_unreachable("Not supported in SIMD-only mode");
13446}
13447
13449 const Expr *NumTeams,
13450 const Expr *ThreadLimit,
13451 SourceLocation Loc) {
13452 llvm_unreachable("Not supported in SIMD-only mode");
13453}
13454
13456 CodeGenFunction &CGF, const OMPExecutableDirective &D, const Expr *IfCond,
13457 const Expr *Device, const RegionCodeGenTy &CodeGen,
13459 llvm_unreachable("Not supported in SIMD-only mode");
13460}
13461
13463 CodeGenFunction &CGF, const OMPExecutableDirective &D, const Expr *IfCond,
13464 const Expr *Device) {
13465 llvm_unreachable("Not supported in SIMD-only mode");
13466}
13467
13469 const OMPLoopDirective &D,
13470 ArrayRef<Expr *> NumIterations) {
13471 llvm_unreachable("Not supported in SIMD-only mode");
13472}
13473
13475 const OMPDependClause *C) {
13476 llvm_unreachable("Not supported in SIMD-only mode");
13477}
13478
13480 const OMPDoacrossClause *C) {
13481 llvm_unreachable("Not supported in SIMD-only mode");
13482}
13483
13484const VarDecl *
13486 const VarDecl *NativeParam) const {
13487 llvm_unreachable("Not supported in SIMD-only mode");
13488}
13489
13490Address
13492 const VarDecl *NativeParam,
13493 const VarDecl *TargetParam) const {
13494 llvm_unreachable("Not supported in SIMD-only mode");
13495}
#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:887
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:983
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:5429
Represents an array type, per C99 6.7.5.2 - Array Declarators.
Definition TypeBase.h:3836
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:2641
Represents a C++ destructor within a class.
Definition DeclCXX.h:2906
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Definition DeclCXX.h:2292
QualType getFunctionObjectParameterType() const
Definition DeclCXX.h:2316
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:1027
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:1106
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:3962
bool capturesVariableByCopy() const
Determine whether this capture handles a variable by copy.
Definition Stmt.h:3996
VarDecl * getCapturedVar() const
Retrieve the declaration of the variable being captured.
Definition Stmt.cpp:1391
bool capturesVariableArrayType() const
Determine whether this capture handles a variable-length array type.
Definition Stmt.h:4002
bool capturesThis() const
Determine whether this capture handles the C++ 'this' pointer.
Definition Stmt.h:3990
bool capturesVariable() const
Determine whether this capture handles a variable (by reference).
Definition Stmt.h:3993
This captures a statement into a function.
Definition Stmt.h:3949
const Capture * const_capture_iterator
Definition Stmt.h:4083
capture_iterator capture_end() const
Retrieve an iterator pointing past the end of the sequence of captures.
Definition Stmt.h:4100
const RecordDecl * getCapturedRecordDecl() const
Retrieve the record declaration for captured variables.
Definition Stmt.h:4070
Stmt * getCapturedStmt()
Retrieve the statement being captured.
Definition Stmt.h:4053
bool capturesVariable(const VarDecl *Var) const
True if this variable has been captured.
Definition Stmt.cpp:1517
capture_iterator capture_begin()
Retrieve an iterator pointing to the first capture.
Definition Stmt.h:4095
capture_range captures()
Definition Stmt.h:4087
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:671
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:651
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:2050
const CGFunctionInfo & arrangeBuiltinFunctionDeclaration(QualType resultType, const FunctionArgList &args)
A builtin function is a freestanding function using the default C conventions.
Definition CGCall.cpp:779
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:378
LValue - This represents an lvalue references.
Definition CGValue.h:183
CharUnits getAlignment() const
Definition CGValue.h:355
llvm::Value * getPointer(CodeGenFunction &CGF) const
const Qualifiers & getQuals() const
Definition CGValue.h:350
Address getAddress() const
Definition CGValue.h:373
LValueBaseInfo getBaseInfo() const
Definition CGValue.h:358
QualType getType() const
Definition CGValue.h:303
TBAAAccessInfo getTBAAInfo() const
Definition CGValue.h:347
A basic class for pre|post-action for advanced codegen sequence for OpenMP region.
virtual void Enter(CodeGenFunction &CGF)
RValue - This trivial value class is used to represent the result of an expression that is evaluated.
Definition CGValue.h:42
static RValue get(llvm::Value *V)
Definition CGValue.h:99
static RValue getComplex(llvm::Value *V1, llvm::Value *V2)
Definition CGValue.h:109
llvm::Value * getScalarVal() const
getScalarVal() - Return the Value* of this scalar value.
Definition CGValue.h:72
An abstract representation of an aligned address.
Definition Address.h:42
llvm::Type * getElementType() const
Return the type of the values stored in this address.
Definition Address.h:77
llvm::Value * getPointer() const
Definition Address.h:66
static RawAddress invalid()
Definition Address.h:61
Class intended to support codegen of all kind of the reduction clauses.
LValue getSharedLValue(unsigned N) const
Returns LValue for the reduction item.
const Expr * getRefExpr(unsigned N) const
Returns the base declaration of the reduction item.
LValue getOrigLValue(unsigned N) const
Returns LValue for the original reduction item.
bool needCleanups(unsigned N)
Returns true if the private copy requires cleanups.
void emitAggregateType(CodeGenFunction &CGF, unsigned N)
Emits the code for the variable-modified type, if required.
const VarDecl * getBaseDecl(unsigned N) const
Returns the base declaration of the reduction item.
QualType getPrivateType(unsigned N) const
Return the type of the private item.
bool usesReductionInitializer(unsigned N) const
Returns true if the initialization of the reduction item uses initializer from declare reduction cons...
void emitSharedOrigLValue(CodeGenFunction &CGF, unsigned N)
Emits lvalue for the shared and original reduction item.
void emitInitialization(CodeGenFunction &CGF, unsigned N, Address PrivateAddr, Address SharedAddr, llvm::function_ref< bool(CodeGenFunction &)> DefaultInit)
Performs initialization of the private copy for the reduction item.
std::pair< llvm::Value *, llvm::Value * > getSizes(unsigned N) const
Returns the size of the reduction item (in chars and total number of elements in the item),...
ReductionCodeGen(ArrayRef< const Expr * > Shareds, ArrayRef< const Expr * > Origs, ArrayRef< const Expr * > Privates, ArrayRef< const Expr * > ReductionOps)
void emitCleanups(CodeGenFunction &CGF, unsigned N, Address PrivateAddr)
Emits cleanup code for the reduction item.
Address adjustPrivateAddress(CodeGenFunction &CGF, unsigned N, Address PrivateAddr)
Adjusts PrivatedAddr for using instead of the original variable address in normal operations.
Class provides a way to call simple version of codegen for OpenMP region, or an advanced with possibl...
void operator()(CodeGenFunction &CGF) const
void setAction(PrePostActionTy &Action) const
ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition DeclBase.h:1466
void addDecl(Decl *D)
Add the declaration D into this context.
A reference to a declared variable, function, enum, etc.
Definition Expr.h:1290
ValueDecl * getDecl()
Definition Expr.h:1358
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:113
bool isIntegerConstantExpr(const ASTContext &Ctx) const
bool isGLValue() const
Definition Expr.h:288
Expr * IgnoreParenNoopCasts(const ASTContext &Ctx) LLVM_READONLY
Skip past any parentheses and casts which do not change the value (including ptr->int casts of the sa...
Definition Expr.cpp:3150
@ SE_AllowSideEffects
Allow any unmodeled side effect.
Definition Expr.h:695
@ SE_AllowUndefinedBehavior
Allow UB that we can give a value, but not arbitrary unmodeled side effects.
Definition Expr.h:693
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Definition Expr.cpp:3128
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:3123
bool isEvaluatable(const ASTContext &Ctx, SideEffectsKind AllowSideEffects=SE_NoSideEffects) const
isEvaluatable - Call EvaluateAsRValue to see if this expression can be constant folded without side-e...
bool HasSideEffects(const ASTContext &Ctx, bool IncludePossibleEffects=true) const
HasSideEffects - This routine returns true for all those expressions which have any effect other than...
Definition Expr.cpp:3722
std::optional< llvm::APSInt > getIntegerConstantExpr(const ASTContext &Ctx, bool AllowRelaxedEval=false) const
isIntegerConstantExpr - Return the value if this expression is a valid integer constant expression.
bool EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx, bool InConstantContext=false) const
EvaluateAsBooleanCondition - Return true if this is a constant which we can fold and convert to a boo...
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition Expr.cpp:283
static bool isSameComparisonOperand(const Expr *E1, const Expr *E2)
Checks that the two Expr's will refer to the same value as a comparison operand.
Definition Expr.cpp:4356
QualType getType() const
Definition Expr.h:145
bool hasNonTrivialCall(const ASTContext &Ctx) const
Determine whether this expression involves a call to any function that is not trivial.
Definition Expr.cpp:4092
Represents a member of a struct/union/class.
Definition Decl.h:3294
unsigned getFieldIndex() const
Returns the index of this field within its record, as appropriate for passing to ASTRecordLayout::get...
Definition Decl.h:3379
const RecordDecl * getParent() const
Returns the parent of this field declaration, which is the struct in which this field is defined.
Definition Decl.h:3530
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:4764
Represents a function declaration or definition.
Definition Decl.h:2058
const ParmVarDecl * getParamDecl(unsigned i) const
Definition Decl.h:2927
QualType getReturnType() const
Definition Decl.h:2975
ArrayRef< ParmVarDecl * > parameters() const
Definition Decl.h:2904
FunctionDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
Definition Decl.cpp:3791
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:3870
FunctionDecl * getPreviousDecl()
Return the previous declaration of this declaration or NULL if this is the first declaration.
GlobalDecl - represents a global declaration.
Definition GlobalDecl.h:60
const Decl * getDecl() const
Definition GlobalDecl.h:115
static ImplicitParamDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation IdLoc, const IdentifierInfo *Id, QualType T, ImplicitParamKind ParamKind)
Create implicit parameter.
Definition Decl.cpp:5666
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:3731
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition Expr.h:3408
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
Definition Expr.h:3491
Expr * getBase() const
Definition Expr.h:3485
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:5637
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:1198
Represents a parameter to a function.
Definition Decl.h:1819
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition TypeBase.h:3408
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:8502
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
Definition TypeBase.h:8542
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:8687
QualType getCanonicalType() const
Definition TypeBase.h:8554
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:4459
field_iterator field_end() const
Definition Decl.h:4665
field_range fields() const
Definition Decl.h:4662
virtual void completeDefinition()
Note that the definition of this type is now complete.
Definition Decl.cpp:5355
bool field_empty() const
Definition Decl.h:4670
field_iterator field_begin() const
Definition Decl.cpp:5339
Scope - A scope is a transient data structure that is used while parsing the program.
Definition Scope.h:41
Encodes a location in the source.
static SourceLocation getFromRawEncoding(UIntTy Encoding)
Turn a raw encoding of a SourceLocation object into a real SourceLocation.
bool isValid() const
Return true if this is a valid SourceLocation object.
UIntTy getRawEncoding() const
When a SourceLocation itself cannot be used, this returns an (opaque) 32-bit integer encoding for it.
This class handles loading and caching of source files into memory.
PresumedLoc getPresumedLoc(SourceLocation Loc, bool UseLineDirectives=true) const
Returns the "presumed" location of a SourceLocation specifies.
Stmt - This represents one statement.
Definition Stmt.h:85
child_range children()
Definition Stmt.cpp:304
StmtClass getStmtClass() const
Definition Stmt.h:1505
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:343
Stmt * IgnoreContainers(bool IgnoreCaptured=false)
Skip no-op (attributed, compound) container stmts and skip captured stmt at the top,...
Definition Stmt.cpp:210
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Stmt.cpp:355
void startDefinition()
Starts the definition of this tag declaration.
Definition Decl.cpp:4970
bool isUnion() const
Definition Decl.h:4062
The base class of the type hierarchy.
Definition TypeBase.h:1879
bool isVoidType() const
Definition TypeBase.h:9111
const Type * getPointeeOrArrayElementType() const
If this is a pointer type, return the pointee type.
Definition TypeBase.h:9298
bool isSignedIntegerType() const
Return true if this is an integer type that is signed, according to C99 6.2.5p4 [char,...
Definition Type.cpp:2296
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:8838
bool isPointerType() const
Definition TypeBase.h:8739
CanQualType getCanonicalTypeUnqualified() const
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
Definition TypeBase.h:9155
const T * castAs() const
Member-template castAs<specific type>.
Definition TypeBase.h:9405
bool isReferenceType() const
Definition TypeBase.h:8763
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:8767
bool isAggregateType() const
Determines whether the type is a C++ aggregate type or C aggregate or union type.
Definition Type.cpp:2535
RecordDecl * castAsRecordDecl() const
Definition Type.h:48
QualType getCanonicalTypeInternal() const
Definition TypeBase.h:3196
const Type * getBaseElementTypeUnsafe() const
Get the base element type of this type, potentially discarding type qualifiers.
Definition TypeBase.h:9291
bool isVariablyModifiedType() const
Whether this type is a variably-modified type (C99 6.7.5).
Definition TypeBase.h:2877
const ArrayType * getAsArrayTypeUnsafe() const
A variant of getAs<> for array types which silently discards qualifiers from the outermost type.
Definition TypeBase.h:9391
bool isFloatingType() const
Definition Type.cpp:2421
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:2364
bool isAnyPointerType() const
Definition TypeBase.h:8747
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9338
bool isRecordType() const
Definition TypeBase.h:8866
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:2239
VarDecl * getDefinition(ASTContext &)
Get the real (not just tentative) definition for this declaration.
Definition Decl.cpp:2348
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:2357
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:4080
Expr * getSizeExpr() const
Definition TypeBase.h:4094
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
Top level wrappers for InstallAPI frontend operations.
bool isOpenMPWorksharingDirective(OpenMPDirectiveKind DKind)
Checks if the specified directive is a worksharing directive.
CanQual< Type > CanQualType
Represents a canonical, potentially-qualified type.
bool needsTaskBasedThreadLimit(OpenMPDirectiveKind DKind)
Checks if the specified target directive, combined or not, needs task based thread_limit.
@ Match
This is not an overload because the signature exactly matches an existing declaration.
Definition Sema.h:824
@ Ctor_Complete
Complete object ctor.
Definition ABI.h:25
Privates[]
This class represents the 'transparent' clause in the 'pragma omp task' directive.
bool isa(CodeGen::Address addr)
Definition Address.h:330
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
bool isOpenMPTargetDataManagementDirective(OpenMPDirectiveKind DKind)
Checks if the specified directive is a target data offload directive.
static bool classof(const OMPClause *T)
@ Conditional
A conditional (?:) operator.
Definition Sema.h:663
@ 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:6053
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:558
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:666
Extra information about a function prototype.
Definition TypeBase.h:5506
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.