• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2022 Imagination Technologies Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  */
23 
24 #ifndef ROGUE_UTIL_H
25 #define ROGUE_UTIL_H
26 
27 #include <assert.h>
28 #include <stdbool.h>
29 #include <stddef.h>
30 #include <stdint.h>
31 
32 #include "util/bitscan.h"
33 #include "util/log.h"
34 #include "util/macros.h"
35 
36 /* Input validation helpers. */
37 
38 /**
39  * \brief Returns false if "expr" is not asserted.
40  *
41  * \param[in] expr The expression to check.
42  */
43 #define CHECK(expr)    \
44    do {                \
45       if (!(expr))     \
46          return false; \
47    } while (0)
48 
49 /**
50  * \brief Returns false if "expr" is not asserted,
51  * and logs the provided error message.
52  *
53  * \param[in] expr The expression to check.
54  * \param[in] fmt The error message to print.
55  * \param[in] ... The printf-style varable arguments.
56  */
57 #define CHECKF(expr, fmt, ...)                                  \
58    do {                                                         \
59       if (!(expr)) {                                            \
60          mesa_log(MESA_LOG_ERROR, "ROGUE", fmt, ##__VA_ARGS__); \
61          return false;                                          \
62       }                                                         \
63    } while (0)
64 
65 /**
66  * \brief Asserts if "opcode" is invalid.
67  *
68  * \param[in] opcode The opcode to check.
69  */
70 #define ASSERT_OPCODE_RANGE(opcode) assert((opcode) < ROGUE_OP_COUNT)
71 
72 /**
73  * \brief Asserts if "operand" is invalid.
74  *
75  * \param[in] operand The operand to check.
76  */
77 #define ASSERT_OPERAND_RANGE(operand) \
78    assert((operand) < ROGUE_OPERAND_TYPE_COUNT)
79 
80 /**
81  * \brief Asserts if "operand" is not a register.
82  *
83  * \param[in] operand The operand to check.
84  */
85 #define ASSERT_OPERAND_REG(operand) \
86    assert((operand) <= ROGUE_OPERAND_TYPE_REG_MAX)
87 
88 /**
89  * \brief Asserts if "flag" is invalid.
90  *
91  * \param[in] flag The flag to check.
92  */
93 #define ASSERT_INSTR_FLAG_RANGE(flag) assert((flag) < ROGUE_INSTR_FLAG_COUNT)
94 
95 /**
96  * \brief Asserts if operand index "index" is out of range.
97  *
98  * \param[in] instr The target instruction.
99  * \param[in] index The operand index to check.
100  */
101 #define ASSERT_INSTR_OPERAND_INDEX(instr, index) \
102    assert((index) < (instr)->num_operands)
103 
104 /**
105  * \brief Asserts if "stage" is invalid.
106  *
107  * \param[in] stage The stage to check.
108  */
109 #define ASSERT_SHADER_STAGE_RANGE(stage) assert((stage) < MESA_SHADER_STAGES)
110 
111 /**
112  * \brief Creates a "n"-bit mask starting from bit "b".
113  *
114  * \param[in] b The starting bit.
115  * \param[in] n The number of bits in the mask.
116  */
117 #define BITMASK64_N(b, n) (((~0ULL) << (64 - (n))) >> (63 - (b)))
118 
119 /**
120  * \brief Compile-time rogue_onehot.
121  *
122  * \sa #rogue_onehot()
123  */
124 #define ROH(OFFSET) BITFIELD64_BIT(OFFSET)
125 
126 /* TODO: Consider integrating the following into src/util/{macros,bitscan}.h */
127 
128 /**
129  * \brief Converts a one-hot encoding to an offset encoding.
130  *
131  * E.g. 0b10000 -> 4
132  *
133  * \param[in] onehot The one-hot encoding.
134  * \return The offset encoding.
135  */
rogue_offset(uint64_t onehot)136 static inline uint64_t rogue_offset(uint64_t onehot)
137 {
138    assert(util_bitcount64(onehot) == 1);
139    return ffsll(onehot) - 1;
140 }
141 
142 /**
143  * \brief Converts an offset encoding to a one-hot encoding.
144  *
145  * E.g. 0 -> 0b1
146  *
147  * \param[in] offset The offset encoding.
148  * \return The one-hot encoding.
149  */
rogue_onehot(uint64_t offset)150 static inline uint64_t rogue_onehot(uint64_t offset)
151 {
152    assert(offset < 64ULL);
153    return (1ULL << offset);
154 }
155 
156 /**
157  * \brief Checks whether an input bitfield contains only a valid bitset.
158  *
159  * E.g. rogue_check_bitset(0b00001100, 0b00001111) -> true
160  *      rogue_check_bitset(0b00001100, 0b00000111) -> false
161  *
162  * \param[in] input The input bitfield.
163  * \param[in] valid_bits The valid bitset.
164  * \return true if "input" contains only "valid_bits", false otherwise.
165  */
rogue_check_bitset(uint64_t input,uint64_t valid_bits)166 static inline bool rogue_check_bitset(uint64_t input, uint64_t valid_bits)
167 {
168    input &= ~valid_bits;
169    return !input;
170 }
171 
172 /**
173  * \brief Describes a downward range of bits within an arbitrarily-sized
174  * sequence.
175  *
176  * E.g. for start = 7 and num = 3:
177  *
178  * 76543210
179  * abcdefgh
180  *
181  * the bit range would be: abc.
182  */
183 struct rogue_bitrange {
184    size_t start;
185    size_t num;
186 };
187 
188 /**
189  * \brief Describes a collection of bit-ranges within an arbitrarily-sized
190  * sequence that are meaningful together.
191  *
192  * E.g. an 8-bit value that is encoded within a larger value:
193  *     8-bit value: abcdefgh
194  *     Parent value: 010ab0cdef0010gh
195  *
196  */
197 struct rogue_rangelist {
198    size_t num_ranges;
199    struct rogue_bitrange *ranges;
200 };
201 
202 /**
203  * \brief Counts the total number of bits described in a rangelist.
204  *
205  * \param[in] rangelist The input rangelist.
206  * \return The total number of bits.
207  */
208 static inline size_t
rogue_rangelist_bits(const struct rogue_rangelist * rangelist)209 rogue_rangelist_bits(const struct rogue_rangelist *rangelist)
210 {
211    size_t total_bits = 0U;
212 
213    for (size_t u = 0U; u < rangelist->num_ranges; ++u)
214       total_bits += rangelist->ranges[u].num;
215 
216    return total_bits;
217 }
218 
219 /**
220  * \brief Returns the byte offset of the bitrange moving left from the LSB.
221  *
222  * \param[in] bitrange The input bit-range.
223  * \return The byte offset.
224  */
rogue_byte_num(const struct rogue_bitrange * bitrange)225 static inline size_t rogue_byte_num(const struct rogue_bitrange *bitrange)
226 {
227    /* Make sure there are enough bits. */
228    assert(bitrange->num <= (bitrange->start + 1));
229 
230    return bitrange->start / 8;
231 }
232 
233 /**
234  * \brief Returns the array-indexable byte offset of a bit-range if the sequence
235  * it represents were to be stored in an byte-array containing "num_bytes"
236  * bytes.
237  *
238  * E.g. uint8_t array[2] is a sequence of 16 bits:
239  *     bit(0) is located in array[1].
240  *     bit(15) is located in array[0].
241  *
242  * For uint8_t array[4]:
243  *     bit(0) is located in array[3].
244  *     bit(15) is located in array[2].
245  *
246  * \param[in] bitrange The input bit-range.
247  * \param[in] num_bytes The number of bytes that are used to contain the
248  * bit-range. \return The byte offset.
249  */
rogue_byte_index(const struct rogue_bitrange * bitrange,size_t num_bytes)250 static inline size_t rogue_byte_index(const struct rogue_bitrange *bitrange,
251                                       size_t num_bytes)
252 {
253    /* Make sure there are enough bits. */
254    assert(bitrange->num <= (bitrange->start + 1));
255 
256    return num_bytes - rogue_byte_num(bitrange) - 1;
257 }
258 
259 /**
260  * \brief Returns the bit offset of a bit-range if the sequence it represents is
261  * being accessed in a byte-wise manner.
262  *
263  * E.g. bit 17 has a bit offset of 1.
264  *
265  * \param[in] bitrange The input bit-range.
266  * \return The bit offset.
267  */
rogue_bit_offset(const struct rogue_bitrange * bitrange)268 static inline size_t rogue_bit_offset(const struct rogue_bitrange *bitrange)
269 {
270    /* Make sure there are enough bits. */
271    assert(bitrange->num <= (bitrange->start + 1));
272 
273    return bitrange->start % 8;
274 }
275 
276 /**
277  * \brief Returns the number of additional bytes that the bit-range spills into
278  * (excluding its "starting" byte).
279  *
280  * \param[in] bitrange The input bit-range.
281  * \return The number of bytes spilled.
282  */
rogue_bytes_spilled(const struct rogue_bitrange * bitrange)283 static inline size_t rogue_bytes_spilled(const struct rogue_bitrange *bitrange)
284 {
285    /* Make sure there are enough bits. */
286    assert(bitrange->num <= (bitrange->start + 1));
287 
288    return ((bitrange->num - 1) / 8) +
289           ((bitrange->num % 8) > (rogue_bit_offset(bitrange) + 1));
290 }
291 
292 /**
293  * \brief For a given bit offset, returns the maximum number of bits (including
294  * itself) that are accessible before spilling into the following byte.
295  *
296  * E.g. When trying to insert an 8-bit value offset of 13, a maximum of 6 bits
297  * can be placed; the last 2 bits will need to go into the next byte.
298  *
299  *     8-bit value: abcdefgh
300  *
301  *     array[0]  array[1]
302  *     15      8 7      0
303  *      iiiiiiii jjjjjjjj
304  *        ^
305  *        abcdef gh
306  *
307  * \param[in] The bit offset.
308  * \return The maximum number of accessible bits.
309  */
rogue_max_bits(size_t offset)310 static inline size_t rogue_max_bits(size_t offset)
311 {
312    return (offset % 8) + 1;
313 }
314 
315 bool rogue_distribute_value(uint64_t source,
316                             const struct rogue_rangelist *rangelist,
317                             size_t dest_size,
318                             uint8_t dest_bytes[dest_size]);
319 
320 #endif /* ROGUE_UTIL_H */
321