//===-------- State.h - OpenMP State & ICV interface ------------- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // //===----------------------------------------------------------------------===// #ifndef OMPTARGET_STATE_H #define OMPTARGET_STATE_H #include "Debug.h" #include "Types.h" #pragma omp declare target namespace _OMP { namespace state { inline constexpr uint32_t SharedScratchpadSize = SHARED_SCRATCHPAD_SIZE; /// Initialize the state machinery. Must be called by all threads. void init(bool IsSPMD); /// TODO enum ValueKind { VK_NThreads, VK_Level, VK_ActiveLevel, VK_MaxActiveLevels, VK_RunSched, // --- VK_RunSchedChunk, VK_ParallelRegionFn, VK_ParallelTeamSize, }; /// TODO void enterDataEnvironment(IdentTy *Ident); /// TODO void exitDataEnvironment(); /// TODO struct DateEnvironmentRAII { DateEnvironmentRAII(IdentTy *Ident) { enterDataEnvironment(Ident); } ~DateEnvironmentRAII() { exitDataEnvironment(); } }; /// TODO void resetStateForThread(uint32_t TId); uint32_t &lookup32(ValueKind VK, bool IsReadonly, IdentTy *Ident); void *&lookupPtr(ValueKind VK, bool IsReadonly); /// A class without actual state used to provide a nice interface to lookup and /// update ICV values we can declare in global scope. template struct Value { __attribute__((flatten, always_inline)) operator Ty() { return lookup(/* IsReadonly */ true, /* IdentTy */ nullptr); } __attribute__((flatten, always_inline)) Value &operator=(const Ty &Other) { set(Other, /* IdentTy */ nullptr); return *this; } __attribute__((flatten, always_inline)) Value &operator++() { inc(1, /* IdentTy */ nullptr); return *this; } __attribute__((flatten, always_inline)) Value &operator--() { inc(-1, /* IdentTy */ nullptr); return *this; } private: __attribute__((flatten, always_inline)) Ty &lookup(bool IsReadonly, IdentTy *Ident) { Ty &t = lookup32(Kind, IsReadonly, Ident); return t; } __attribute__((flatten, always_inline)) Ty &inc(int UpdateVal, IdentTy *Ident) { return (lookup(/* IsReadonly */ false, Ident) += UpdateVal); } __attribute__((flatten, always_inline)) Ty &set(Ty UpdateVal, IdentTy *Ident) { return (lookup(/* IsReadonly */ false, Ident) = UpdateVal); } template friend struct ValueRAII; }; /// A mookup class without actual state used to provide /// a nice interface to lookup and update ICV values /// we can declare in global scope. template struct PtrValue { __attribute__((flatten, always_inline)) operator Ty() { return lookup(/* IsReadonly */ true, /* IdentTy */ nullptr); } __attribute__((flatten, always_inline)) PtrValue &operator=(const Ty Other) { set(Other); return *this; } private: Ty &lookup(bool IsReadonly, IdentTy *) { return lookupPtr(Kind, IsReadonly); } Ty &set(Ty UpdateVal) { return (lookup(/* IsReadonly */ false, /* IdentTy */ nullptr) = UpdateVal); } template friend struct ValueRAII; }; template struct ValueRAII { ValueRAII(VTy &V, Ty NewValue, Ty OldValue, bool Active, IdentTy *Ident) : Ptr(Active ? &V.lookup(/* IsReadonly */ false, Ident) : nullptr), Val(OldValue), Active(Active) { if (!Active) return; ASSERT(*Ptr == OldValue && "ValueRAII initialization with wrong old value!"); *Ptr = NewValue; } ~ValueRAII() { if (Active) *Ptr = Val; } private: Ty *Ptr; Ty Val; bool Active; }; /// TODO inline state::Value RunSchedChunk; /// TODO inline state::Value ParallelTeamSize; /// TODO inline state::PtrValue ParallelRegionFn; void runAndCheckState(void(Func(void))); void assumeInitialState(bool IsSPMD); } // namespace state namespace icv { /// TODO inline state::Value NThreads; /// TODO inline state::Value Level; /// The `active-level` describes which of the parallel level counted with the /// `level-var` is active. There can only be one. /// /// active-level-var is 1, if ActiveLevelVar is not 0, otherweise it is 0. inline state::Value ActiveLevel; /// TODO inline state::Value MaxActiveLevels; /// TODO inline state::Value RunSched; } // namespace icv namespace memory { /// Alloca \p Size bytes in shared memory, if possible, for \p Reason. /// /// Note: See the restrictions on __kmpc_alloc_shared for proper usage. void *allocShared(uint64_t Size, const char *Reason); /// Free \p Ptr, alloated via allocShared, for \p Reason. /// /// Note: See the restrictions on __kmpc_free_shared for proper usage. void freeShared(void *Ptr, uint64_t Bytes, const char *Reason); /// Alloca \p Size bytes in global memory, if possible, for \p Reason. void *allocGlobal(uint64_t Size, const char *Reason); /// Return a pointer to the dynamic shared memory buffer. void *getDynamicBuffer(); /// Free \p Ptr, alloated via allocGlobal, for \p Reason. void freeGlobal(void *Ptr, const char *Reason); } // namespace memory } // namespace _OMP #pragma omp end declare target #endif