Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / openmp / libomptarget / include / Utilities.h
blob84d38d05911f71274a9e666b1536ed268d594905
1 //===------- Utilities.h - Target independent OpenMP target RTL -- C++ ----===//
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 // Routines and classes used to provide useful functionalities like string
10 // parsing and environment variables.
12 //===----------------------------------------------------------------------===//
14 #ifndef OPENMP_LIBOMPTARGET_INCLUDE_UTILITIES_H
15 #define OPENMP_LIBOMPTARGET_INCLUDE_UTILITIES_H
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/Support/Error.h"
20 #include "Debug.h"
22 #include <algorithm>
23 #include <atomic>
24 #include <cassert>
25 #include <cstddef>
26 #include <cstdint>
27 #include <cstdlib>
28 #include <functional>
29 #include <limits>
30 #include <memory>
31 #include <sstream>
32 #include <string>
34 namespace llvm {
35 namespace omp {
36 namespace target {
38 /// Utility class for parsing strings to other types.
39 struct StringParser {
40 /// Parse a string to another type.
41 template <typename Ty> static bool parse(const char *Value, Ty &Result);
44 /// Class for reading and checking environment variables. Currently working with
45 /// integer, floats, std::string and bool types.
46 template <typename Ty> class Envar {
47 Ty Data;
48 bool IsPresent;
49 bool Initialized;
51 public:
52 /// Auxiliary function to safely create envars. This static function safely
53 /// creates envars using fallible constructors. See the constructors to know
54 /// more details about the creation parameters.
55 template <typename... ArgsTy>
56 static Expected<Envar> create(ArgsTy &&...Args) {
57 Error Err = Error::success();
58 Envar Envar(std::forward<ArgsTy>(Args)..., Err);
59 if (Err)
60 return std::move(Err);
61 return std::move(Envar);
64 /// Create an empty envar. Cannot be consulted. This constructor is merely
65 /// for convenience. This constructor is not fallible.
66 Envar() : Data(Ty()), IsPresent(false), Initialized(false) {}
68 /// Create an envar with a name and an optional default. The Envar object will
69 /// take the value read from the environment variable, or the default if it
70 /// was not set or not correct. This constructor is not fallible.
71 Envar(StringRef Name, Ty Default = Ty())
72 : Data(Default), IsPresent(false), Initialized(true) {
74 if (const char *EnvStr = getenv(Name.data())) {
75 // Check whether the envar is defined and valid.
76 IsPresent = StringParser::parse<Ty>(EnvStr, Data);
78 if (!IsPresent) {
79 DP("Ignoring invalid value %s for envar %s\n", EnvStr, Name.data());
80 Data = Default;
85 Envar<Ty> &operator=(const Ty &V) {
86 Data = V;
87 Initialized = true;
88 return *this;
91 /// Get the definitive value.
92 const Ty &get() const {
93 // Throw a runtime error in case this envar is not initialized.
94 if (!Initialized)
95 FATAL_MESSAGE0(1, "Consulting envar before initialization");
97 return Data;
100 /// Get the definitive value.
101 operator Ty() const { return get(); }
103 /// Indicate whether the environment variable was defined and valid.
104 bool isPresent() const { return IsPresent; }
106 private:
107 /// This constructor should never fail but we provide it for convenience. This
108 /// way, the constructor can be used by the Envar::create() static function
109 /// to safely create this kind of envars.
110 Envar(StringRef Name, Ty Default, Error &Err) : Envar(Name, Default) {
111 ErrorAsOutParameter EAO(&Err);
112 Err = Error::success();
115 /// Create an envar with a name, getter function and a setter function. The
116 /// Envar object will take the value read from the environment variable if
117 /// this value is accepted by the setter function. Otherwise, the getter
118 /// function will be executed to get the default value. The getter should be
119 /// of the form Error GetterFunctionTy(Ty &Value) and the setter should
120 /// be of the form Error SetterFunctionTy(Ty Value). This constructor has a
121 /// private visibility because is a fallible constructor. Please use the
122 /// Envar::create() static function to safely create this object instead.
123 template <typename GetterFunctor, typename SetterFunctor>
124 Envar(StringRef Name, GetterFunctor Getter, SetterFunctor Setter, Error &Err)
125 : Data(Ty()), IsPresent(false), Initialized(true) {
126 ErrorAsOutParameter EAO(&Err);
127 Err = init(Name, Getter, Setter);
130 template <typename GetterFunctor, typename SetterFunctor>
131 Error init(StringRef Name, GetterFunctor Getter, SetterFunctor Setter);
134 /// Define some common envar types.
135 using IntEnvar = Envar<int>;
136 using Int32Envar = Envar<int32_t>;
137 using Int64Envar = Envar<int64_t>;
138 using UInt32Envar = Envar<uint32_t>;
139 using UInt64Envar = Envar<uint64_t>;
140 using StringEnvar = Envar<std::string>;
141 using BoolEnvar = Envar<bool>;
143 /// Utility class for thread-safe reference counting. Any class that needs
144 /// objects' reference counting can inherit from this entity or have it as a
145 /// class data member.
146 template <typename Ty = uint32_t,
147 std::memory_order MemoryOrder = std::memory_order_relaxed>
148 struct RefCountTy {
149 /// Create a refcount object initialized to zero.
150 RefCountTy() : Refs(0) {}
152 ~RefCountTy() { assert(Refs == 0 && "Destroying with non-zero refcount"); }
154 /// Increase the reference count atomically.
155 void increase() { Refs.fetch_add(1, MemoryOrder); }
157 /// Decrease the reference count and return whether it became zero. Decreasing
158 /// the counter in more units than it was previously increased results in
159 /// undefined behavior.
160 bool decrease() {
161 Ty Prev = Refs.fetch_sub(1, MemoryOrder);
162 assert(Prev > 0 && "Invalid refcount");
163 return (Prev == 1);
166 Ty get() const { return Refs.load(MemoryOrder); }
168 private:
169 /// The atomic reference counter.
170 std::atomic<Ty> Refs;
173 template <>
174 inline bool StringParser::parse(const char *ValueStr, bool &Result) {
175 std::string Value(ValueStr);
177 // Convert the string to lowercase.
178 std::transform(Value.begin(), Value.end(), Value.begin(),
179 [](unsigned char c) { return std::tolower(c); });
181 // May be implemented with fancier C++ features, but let's keep it simple.
182 if (Value == "true" || Value == "yes" || Value == "on" || Value == "1")
183 Result = true;
184 else if (Value == "false" || Value == "no" || Value == "off" || Value == "0")
185 Result = false;
186 else
187 return false;
189 // Parsed correctly.
190 return true;
193 template <typename Ty>
194 inline bool StringParser::parse(const char *Value, Ty &Result) {
195 assert(Value && "Parsed value cannot be null");
197 std::istringstream Stream(Value);
198 Stream >> Result;
200 return !Stream.fail();
203 template <typename Ty>
204 template <typename GetterFunctor, typename SetterFunctor>
205 inline Error Envar<Ty>::init(StringRef Name, GetterFunctor Getter,
206 SetterFunctor Setter) {
207 // Get the default value.
208 Ty Default;
209 if (Error Err = Getter(Default))
210 return Err;
212 if (const char *EnvStr = getenv(Name.data())) {
213 IsPresent = StringParser::parse<Ty>(EnvStr, Data);
214 if (IsPresent) {
215 // Check whether the envar value is actually valid.
216 Error Err = Setter(Data);
217 if (Err) {
218 // The setter reported an invalid value. Mark the user-defined value as
219 // not present and reset to the getter value (default).
220 IsPresent = false;
221 Data = Default;
222 DP("Setter of envar %s failed, resetting to %s\n", Name.data(),
223 std::to_string(Data).data());
224 consumeError(std::move(Err));
226 } else {
227 DP("Ignoring invalid value %s for envar %s\n", EnvStr, Name.data());
228 Data = Default;
230 } else {
231 Data = Default;
234 return Error::success();
237 /// Return the difference (in bytes) between \p Begin and \p End.
238 template <typename Ty = char>
239 ptrdiff_t getPtrDiff(const void *End, const void *Begin) {
240 return reinterpret_cast<const Ty *>(End) -
241 reinterpret_cast<const Ty *>(Begin);
244 /// Return \p Ptr advanced by \p Offset bytes.
245 template <typename Ty> Ty *advanceVoidPtr(Ty *Ptr, int64_t Offset) {
246 static_assert(std::is_void<Ty>::value);
247 return const_cast<char *>(reinterpret_cast<const char *>(Ptr) + Offset);
250 /// Return \p Ptr aligned to \p Alignment bytes.
251 template <typename Ty> Ty *alignPtr(Ty *Ptr, int64_t Alignment) {
252 size_t Space = std::numeric_limits<size_t>::max();
253 return std::align(Alignment, sizeof(char), Ptr, Space);
256 /// Round up \p V to a \p Boundary.
257 template <typename Ty> inline Ty roundUp(Ty V, Ty Boundary) {
258 return (V + Boundary - 1) / Boundary * Boundary;
261 } // namespace target
262 } // namespace omp
263 } // namespace llvm
265 #endif // OPENMP_LIBOMPTARGET_INCLUDE_UTILITIES_H