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