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#include <stdbool.h> 25#include <stddef.h> 26#include <stdint.h> 27 28#include "rogue_instr.h" 29#include "rogue_operand.h" 30#include "rogue_util.h" 31#include "util/ralloc.h" 32 33/** 34 * \file rogue_instr.c 35 * 36 * \brief Contains functions to manipulate Rogue instructions. 37 */ 38 39/* clang-format off */ 40 41static const size_t instr_operand_count[ROGUE_OP_COUNT] = { 42 [ROGUE_OP_NOP] = 0, 43 [ROGUE_OP_END_FRAG] = 0, 44 [ROGUE_OP_END_VERT] = 0, 45 [ROGUE_OP_WDF] = 1, 46 [ROGUE_OP_PIX_ITER_W] = 5, 47 [ROGUE_OP_MAX] = 3, 48 [ROGUE_OP_MIN] = 3, 49 [ROGUE_OP_PACK_U8888] = 2, 50 [ROGUE_OP_MOV] = 2, 51 [ROGUE_OP_MOV_IMM] = 2, 52 [ROGUE_OP_FMA] = 4, 53 [ROGUE_OP_MUL] = 3, 54 [ROGUE_OP_VTXOUT] = 2, 55}; 56 57/* clang-format on */ 58 59/** 60 * \brief Returns the number of operands an instruction takes. 61 * 62 * \param[in] opcode The instruction opcode. 63 * \return The number of operands. 64 */ 65static inline size_t rogue_instr_num_operands(enum rogue_opcode opcode) 66{ 67 ASSERT_OPCODE_RANGE(opcode); 68 69 return instr_operand_count[opcode]; 70} 71 72/** 73 * \brief Allocates and sets up a Rogue instruction. 74 * 75 * \param[in] mem_ctx The memory context for the instruction. 76 * \param[in] opcode The instruction opcode. 77 * \return A rogue_instr* if successful, or NULL if unsuccessful. 78 */ 79struct rogue_instr *rogue_instr_create(void *mem_ctx, enum rogue_opcode opcode) 80{ 81 struct rogue_instr *instr; 82 83 ASSERT_OPCODE_RANGE(opcode); 84 85 instr = rzalloc_size(mem_ctx, sizeof(*instr)); 86 if (!instr) 87 return NULL; 88 89 instr->opcode = opcode; 90 instr->num_operands = rogue_instr_num_operands(opcode); 91 92 /* Allocate space for operand array. */ 93 if (instr->num_operands) { 94 instr->operands = rzalloc_array_size(instr, 95 sizeof(*instr->operands), 96 instr->num_operands); 97 if (!instr->operands) { 98 ralloc_free(instr); 99 return NULL; 100 } 101 } 102 103 return instr; 104} 105 106/** 107 * \brief Sets a Rogue instruction flag. 108 * 109 * \param[in] instr The instruction. 110 * \param[in] flag The flag to set. 111 * \return true if valid, otherwise false. 112 */ 113bool rogue_instr_set_flag(struct rogue_instr *instr, enum rogue_instr_flag flag) 114{ 115 instr->flags = ROH(flag); 116 117 return true; 118} 119 120/** 121 * \brief Sets a Rogue instruction operand to an immediate value. 122 * 123 * \param[in] instr The instruction. 124 * \param[in] index The operand index. 125 * \param[in] value The value to set. 126 * \return true if valid, otherwise false. 127 */ 128bool rogue_instr_set_operand_imm(struct rogue_instr *instr, 129 size_t index, 130 uint64_t value) 131{ 132 ASSERT_INSTR_OPERAND_INDEX(instr, index); 133 134 instr->operands[index].type = ROGUE_OPERAND_TYPE_IMMEDIATE; 135 instr->operands[index].immediate.value = value; 136 137 return true; 138} 139 140/** 141 * \brief Sets a Rogue instruction operand to a DRC number. 142 * 143 * \param[in] instr The instruction. 144 * \param[in] index The operand index. 145 * \param[in] number The DRC number to set. 146 * \return true if valid, otherwise false. 147 */ 148bool rogue_instr_set_operand_drc(struct rogue_instr *instr, 149 size_t index, 150 size_t number) 151{ 152 ASSERT_INSTR_OPERAND_INDEX(instr, index); 153 154 instr->operands[index].type = ROGUE_OPERAND_TYPE_DRC; 155 instr->operands[index].drc.number = number; 156 157 return true; 158} 159 160/** 161 * \brief Sets a Rogue instruction operand to a register. 162 * 163 * \param[in] instr The instruction. 164 * \param[in] index The operand index. 165 * \param[in] type The register type to set. 166 * \param[in] number The register number to set. 167 * \return true if valid, otherwise false. 168 */ 169bool rogue_instr_set_operand_reg(struct rogue_instr *instr, 170 size_t index, 171 enum rogue_operand_type type, 172 size_t number) 173{ 174 ASSERT_INSTR_OPERAND_INDEX(instr, index); 175 ASSERT_OPERAND_REG(type); 176 177 instr->operands[index].type = type; 178 instr->operands[index].reg.number = number; 179 180 return true; 181} 182 183/** 184 * \brief Sets a Rogue instruction operand to a virtual register. 185 * 186 * \param[in] instr The instruction. 187 * \param[in] index The operand index. 188 * \param[in] number The register number to set. 189 * \return true if valid, otherwise false. 190 */ 191bool rogue_instr_set_operand_vreg(struct rogue_instr *instr, 192 size_t index, 193 size_t number) 194{ 195 ASSERT_INSTR_OPERAND_INDEX(instr, index); 196 197 instr->operands[index].type = ROGUE_OPERAND_TYPE_VREG; 198 instr->operands[index].vreg.number = number; 199 instr->operands[index].vreg.is_vector = false; 200 201 return true; 202} 203 204/** 205 * \brief Sets a Rogue instruction operand to a virtual register 206 * that is a vector type. 207 * 208 * \param[in] instr The instruction. 209 * \param[in] index The operand index. 210 * \param[in] component The vector component. 211 * \param[in] number The register number to set. 212 * \return true if valid, otherwise false. 213 */ 214bool rogue_instr_set_operand_vreg_vec(struct rogue_instr *instr, 215 size_t index, 216 size_t component, 217 size_t number) 218{ 219 ASSERT_INSTR_OPERAND_INDEX(instr, index); 220 221 instr->operands[index].type = ROGUE_OPERAND_TYPE_VREG; 222 instr->operands[index].vreg.number = number; 223 instr->operands[index].vreg.is_vector = true; 224 instr->operands[index].vreg.component = component; 225 226 return true; 227} 228