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 */
136static 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 */
150static 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 */
166static 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 */
183struct 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 */
197struct 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 */
208static inline size_t
209rogue_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 */
225static 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 */
250static 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 */
268static 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 */
283static 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 */
310static inline size_t rogue_max_bits(size_t offset)
311{
312   return (offset % 8) + 1;
313}
314
315bool 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