1 /*========================== begin_copyright_notice ============================
2 
3 Copyright (C) 2017-2021 Intel Corporation
4 
5 SPDX-License-Identifier: MIT
6 
7 ============================= end_copyright_notice ===========================*/
8 
9 #ifndef IGC_COMMON_TYPES_H
10 #define IGC_COMMON_TYPES_H
11 
12 #include "IGC/common/StringMacros.hpp"
13 #include "3d/common/iStdLib/types.h"
14 
15 #include "AdaptorCommon/API/igc.h"
16 #include "common/debug/Debug.hpp"
17 
18 #include "IGC/common/LLVMWarningsPush.hpp"
19 #include "llvm/Config/llvm-config.h"
20 #if LLVM_VERSION_MAJOR >= 10
21 #include "llvm/Support/TypeSize.h"
22 #endif
23 #include "IGC/common/LLVMWarningsPop.hpp"
24 #include "Probe/Assertion.h"
25 #include "IGC/common/shaderHash.hpp"
26 #include "EmUtils.h"
27 
28 namespace USC
29 {
30     struct ShaderD3D;
31 }
32 
33 namespace IGC
34 {
35     enum PrecisionType : uint8_t
36     {
37         PRECISION_UNUSED, U8, U4, U2, S8, S4, S2,
38         BF16, FP16
39     };
40 
getPrecisionInBits(PrecisionType P)41     inline uint32_t getPrecisionInBits(PrecisionType P)
42     {
43         switch (P)
44         {
45         default:
46             break;
47         case BF16:
48         case FP16:
49             return 16;
50         case U8:
51         case S8:
52             return 8;
53         case U4:
54         case S4:
55             return 4;
56         case U2:
57         case S2:
58             return 2;
59         }
60         return 0;
61     }
62 }
63 
64 enum class SIMDMode : unsigned char
65 {
66     UNKNOWN,
67     SIMD1,
68     SIMD2,
69     SIMD4,
70     SIMD8,
71     SIMD16,
72     SIMD32,
73     END,
74     BEGIN = 0
75 };
76 
77 enum class SIMDStatus : unsigned char
78 {
79     SIMD_BEGIN = 0,
80     SIMD_PASS,
81     SIMD_FUNC_FAIL,
82     SIMD_PERF_FAIL,
83     SIMD_END
84 };
85 
numLanes(SIMDMode width)86 inline uint16_t numLanes(SIMDMode width)
87 {
88     switch(width)
89     {
90     case SIMDMode::SIMD1   : return 1;
91     case SIMDMode::SIMD2   : return 2;
92     case SIMDMode::SIMD4   : return 4;
93     case SIMDMode::SIMD8   : return 8;
94     case SIMDMode::SIMD16  : return 16;
95     case SIMDMode::SIMD32  : return 32;
96     case SIMDMode::UNKNOWN :
97     default:
98         IGC_ASSERT_MESSAGE(0, "unreachable");
99         return 1;
100     }
101 }
102 
lanesToSIMDMode(unsigned lanes)103 inline SIMDMode lanesToSIMDMode(unsigned lanes) {
104     switch (lanes) {
105     case  1: return SIMDMode::SIMD1;
106     case  2: return SIMDMode::SIMD2;
107     case  4: return SIMDMode::SIMD4;
108     case  8: return SIMDMode::SIMD8;
109     case 16: return SIMDMode::SIMD16;
110     case 32: return SIMDMode::SIMD32;
111     default:
112         IGC_ASSERT_MESSAGE(0, "Unexpected number of lanes!");
113         return SIMDMode::UNKNOWN;
114     }
115 }
116 
117 enum class ShaderType
118 {
119     UNKNOWN,
120     VERTEX_SHADER,
121     HULL_SHADER,
122     DOMAIN_SHADER,
123     GEOMETRY_SHADER,
124     PIXEL_SHADER,
125     COMPUTE_SHADER,
126     OPENCL_SHADER,
127     END,
128     BEGIN = 0
129 };
130 
131 enum class ShaderDispatchMode
132 {
133     NOT_APPLICABLE,
134     SINGLE_PATCH,
135     DUAL_PATCH,
136     EIGHT_PATCH,
137     END,
138     BEGIN = 0
139 };
140 
141 static const char *ShaderTypeString[] = {
142     "ERROR",
143     "VS",
144     "HS",
145     "DS",
146     "GS",
147     "PS",
148     "CS",
149     "OCL",
150     "ERROR"
151 };
152 
153 static_assert(sizeof(ShaderTypeString) / sizeof(*ShaderTypeString) == static_cast<size_t>(ShaderType::END) + 1,
154     "Update the array");
155 
156 template <typename TIter>
157 class RangeWrapper
158 {
159 public:
begin()160     TIter& begin() { return m_first; }
end()161     TIter& end() { return m_last; }
162 
163 private:
RangeWrapper(TIter first,TIter last)164     RangeWrapper( TIter first, TIter last )
165         : m_first(first)
166         , m_last(last)
167     { }
168 
169     TIter m_first;
170     TIter m_last;
171 
172     template <typename T>
173     friend inline RangeWrapper<T> range( const T& first, const T& last );
174 };
175 
176 /**
177  * \brief Create a proxy to iterate over a container's nonstandard iterator pairs via c++11 range-for
178  *
179  * This is to be used for containers that provide multiple sets of iterators
180  * such as llvm::Function, which has begin()/end() and arg_begin()/arg_end().
181  * In the latter case, range-for cannot be used without such a proxy.
182  *
183  * \example
184  *     for ( auto arg : range( pFunc->arg_begin(), pFunc->arg_end() ) )
185  *     {
186  *         ...
187  *     }
188  */
189 template <typename TIter>
range(const TIter & first,const TIter & last)190 inline RangeWrapper<TIter> range( const TIter& first, const TIter& last )
191 {
192     return RangeWrapper<TIter>(first, last);
193 }
194 
195 template <typename TEnum>
196 class EnumIter
197 {
198 public:
operator ++()199     EnumIter operator++(/* prefix */)
200     {
201         increment_me();
202         return *this;
203     }
operator ++(int)204     EnumIter operator++(int /* postfix */)
205     {
206         TEnum old(m_val);
207         increment_me();
208         return old;
209     }
operator *() const210     TEnum operator*() const
211     {
212         return m_val;
213     }
operator !=(EnumIter const & other) const214     bool operator!=(EnumIter const& other) const
215     {
216         return !is_equal(other);
217     }
operator ==(EnumIter const & other) const218     bool operator==(EnumIter const& other) const
219     {
220         return is_equal(other);
221     }
222 private:
EnumIter(TEnum init)223     EnumIter(TEnum init)
224         : m_val(init)
225     {}
is_equal(EnumIter const & other) const226     bool is_equal(EnumIter const& other) const
227     {
228         return m_val == other.m_val;
229     }
increment_me()230     void increment_me()
231     {
232          m_val = static_cast<TEnum>( static_cast<unsigned int>(m_val) + 1 );
233     }
234 
235     template <typename T>
236     friend inline RangeWrapper<EnumIter<T>> eRange(T, T);
237 
238     TEnum m_val;
239 };
240 
241 /**
242  * \brief Create a proxy to iterate over every element of an enumeration
243  *
244  * Assumes that TEnum follows this pattern, with no gaps between the enumerated values:
245  * enum class EFoo {
246  *     E1,
247  *     E2,
248  *     END,
249  *     BEGIN = 0
250  * };
251  */
252 template <typename TEnum>
eRange(TEnum begin=TEnum::BEGIN,TEnum end=TEnum::END)253 inline RangeWrapper<EnumIter<TEnum>> eRange( TEnum begin = TEnum::BEGIN, TEnum end = TEnum::END)
254 {
255     return range( EnumIter<TEnum>(begin), EnumIter<TEnum>(end) );
256 }
257 
258 /// Template that should be used when a static_cast of a larger integer
259 /// type to a smaller one is required.
260 /// In debug, this will check if the source argument doesn't exceed the target type range.
261 /// In release, it is just static_cast with no check.
262 ///
263 /// Note that the cases where one needs to typecast integer types should be infrequent.
264 /// Could be necessary when dealing with other interfaces, otherwise think twice before
265 /// using it - maybe changing types or modifying the code design would be better.
266 template <typename TDst, typename TSrc>
267 inline typename std::enable_if<
268     std::is_signed<TDst>::value && std::is_signed<TSrc>::value,
int_cast(TSrc value)269     TDst>::type int_cast(TSrc value)
270 {
271     static_assert(std::is_integral<TDst>::value && std::is_integral<TSrc>::value,
272         "int_cast<>() should be used only for conversions between integer types.");
273 
274     IGC_ASSERT(std::numeric_limits<TDst>::min() <= value);
275     IGC_ASSERT(value <= std::numeric_limits<TDst>::max());
276 
277     return static_cast<TDst>(value);
278 }
279 
280 template <typename TDst, typename TSrc>
281 inline typename std::enable_if<
282     std::is_signed<TDst>::value && std::is_unsigned<TSrc>::value,
int_cast(TSrc value)283     TDst>::type int_cast(TSrc value)
284 {
285     static_assert(std::is_integral<TDst>::value && std::is_integral<TSrc>::value,
286         "int_cast<>() should be used only for conversions between integer types.");
287 
288     IGC_ASSERT(value <= static_cast<typename std::make_unsigned<TDst>::type>(std::numeric_limits<TDst>::max()));
289 
290     return static_cast<TDst>(value);
291 }
292 
293 template <typename TDst, typename TSrc>
294 inline typename std::enable_if<
295     std::is_unsigned<TDst>::value && std::is_signed<TSrc>::value,
int_cast(TSrc value)296     TDst>::type int_cast(TSrc value)
297 {
298     static_assert(std::is_integral<TDst>::value && std::is_integral<TSrc>::value,
299         "int_cast<>() should be used only for conversions between integer types.");
300 
301     IGC_ASSERT(0 <= value);
302     IGC_ASSERT(static_cast<typename std::make_unsigned<TSrc>::type>(value) <= std::numeric_limits<TDst>::max());
303 
304     return static_cast<TDst>(value);
305 }
306 
307 template <typename TDst, typename TSrc>
308 inline typename std::enable_if<
309     std::is_unsigned<TDst>::value && std::is_unsigned<TSrc>::value,
int_cast(TSrc value)310     TDst>::type int_cast(TSrc value)
311 {
312     static_assert(std::is_integral<TDst>::value && std::is_integral<TSrc>::value,
313         "int_cast<>() should be used only for conversions between integer types.");
314 
315     IGC_ASSERT(value <= std::numeric_limits<TDst>::max());
316     return static_cast<TDst>(value);
317 }
318 
319 #if LLVM_VERSION_MAJOR >= 10
320 template <typename TDst>
321 inline typename std::enable_if<
322     std::is_unsigned<TDst>::value,
int_cast(llvm::TypeSize value)323     TDst>::type int_cast(llvm::TypeSize value)
324 {
325     static_assert(std::is_integral<TDst>::value,
326         "int_cast<>() should be used only for conversions between integer types.");
327 
328     IGC_ASSERT(value.getFixedSize() <= std::numeric_limits<TDst>::max());
329     return static_cast<TDst>(value.getFixedSize());
330 }
331 
332 template <typename TDst>
333 inline typename std::enable_if<
334     std::is_signed<TDst>::value,
int_cast(llvm::TypeSize value)335     TDst>::type int_cast(llvm::TypeSize value)
336 {
337     static_assert(std::is_integral<TDst>::value,
338         "int_cast<>() should be used only for conversions between integer types.");
339 
340     IGC_ASSERT(value.getFixedSize() <= static_cast<typename std::make_unsigned<TDst>::type>(std::numeric_limits<TDst>::max()));
341     return static_cast<TDst>(value.getFixedSize());
342 }
343 
344 #endif
345 
346 #endif //IGC_COMMON_TYPES_H
347