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