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/** 25bf215546Sopenharmony_ci * \file rogue_validate.c 26bf215546Sopenharmony_ci * 27bf215546Sopenharmony_ci * \brief Contains rules and functions for validating Rogue data structures. 28bf215546Sopenharmony_ci */ 29bf215546Sopenharmony_ci 30bf215546Sopenharmony_ci#include <stdbool.h> 31bf215546Sopenharmony_ci 32bf215546Sopenharmony_ci#include "rogue_operand.h" 33bf215546Sopenharmony_ci#include "rogue_shader.h" 34bf215546Sopenharmony_ci#include "rogue_util.h" 35bf215546Sopenharmony_ci#include "rogue_validate.h" 36bf215546Sopenharmony_ci#include "util/list.h" 37bf215546Sopenharmony_ci#include "util/macros.h" 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_ci/** 40bf215546Sopenharmony_ci * \brief Register operand rules. 41bf215546Sopenharmony_ci */ 42bf215546Sopenharmony_ci#define REG_RULE(OPERAND, ACCESS, MAX, MODIFIERS) \ 43bf215546Sopenharmony_ci [ROGUE_OPERAND_TYPE_REG_##OPERAND] = { \ 44bf215546Sopenharmony_ci .access = ROGUE_REG_ACCESS_##ACCESS, \ 45bf215546Sopenharmony_ci .max = MAX, \ 46bf215546Sopenharmony_ci .modifiers = ROGUE_REG_MOD_##MODIFIERS, \ 47bf215546Sopenharmony_ci } 48bf215546Sopenharmony_ci 49bf215546Sopenharmony_ci/* TODO: Support register indexing > ROGUE_MAX_REG_TEMP. */ 50bf215546Sopenharmony_cistatic const struct rogue_register_rule reg_rules[ROGUE_NUM_REG_TYPES] = { 51bf215546Sopenharmony_ci REG_RULE(TEMP, RW, MIN2(ROGUE_MAX_REG_INDEX, ROGUE_MAX_REG_TEMP), ALL), 52bf215546Sopenharmony_ci REG_RULE(COEFF, RW, MIN2(ROGUE_MAX_REG_INDEX, ROGUE_MAX_REG_COEFF), ALL), 53bf215546Sopenharmony_ci REG_RULE(CONST, RW, MIN2(ROGUE_MAX_REG_INDEX, ROGUE_MAX_REG_CONST), NONE), 54bf215546Sopenharmony_ci REG_RULE(SHARED, RW, MIN2(ROGUE_MAX_REG_INDEX, ROGUE_MAX_REG_SHARED), ALL), 55bf215546Sopenharmony_ci REG_RULE(PIXEL_OUT, 56bf215546Sopenharmony_ci RW, 57bf215546Sopenharmony_ci MIN2(ROGUE_MAX_REG_INDEX, ROGUE_MAX_REG_PIXEL_OUT), 58bf215546Sopenharmony_ci NONE), 59bf215546Sopenharmony_ci REG_RULE(VERTEX_IN, 60bf215546Sopenharmony_ci RW, 61bf215546Sopenharmony_ci MIN2(ROGUE_MAX_REG_INDEX, ROGUE_MAX_REG_VERTEX_IN), 62bf215546Sopenharmony_ci ALL), 63bf215546Sopenharmony_ci REG_RULE(INTERNAL, 64bf215546Sopenharmony_ci RW, 65bf215546Sopenharmony_ci MIN2(ROGUE_MAX_REG_INDEX, ROGUE_MAX_REG_INTERNAL), 66bf215546Sopenharmony_ci NONE), 67bf215546Sopenharmony_ci}; 68bf215546Sopenharmony_ci#undef REG_RULE 69bf215546Sopenharmony_ci 70bf215546Sopenharmony_ci/** 71bf215546Sopenharmony_ci * \brief Instruction rules. 72bf215546Sopenharmony_ci */ 73bf215546Sopenharmony_ci/* TODO: Common up register classes to prevent long lines. */ 74bf215546Sopenharmony_cistatic const struct rogue_instr_rule instr_rules[ROGUE_OP_COUNT] = { 75bf215546Sopenharmony_ci [ROGUE_OP_NOP] = { .flags = 0, .num_operands = 0, .operand_rules = NULL, }, 76bf215546Sopenharmony_ci [ROGUE_OP_END_FRAG] = { .flags = 0, .num_operands = 0, .operand_rules = NULL, }, 77bf215546Sopenharmony_ci [ROGUE_OP_END_VERT] = { .flags = 0, .num_operands = 0, .operand_rules = NULL, }, 78bf215546Sopenharmony_ci [ROGUE_OP_WDF] = { .flags = 0, 79bf215546Sopenharmony_ci .num_operands = 1, .operand_rules = (struct rogue_instr_operand_rule[]){ 80bf215546Sopenharmony_ci [0] = { .mask = ROH(ROGUE_OPERAND_TYPE_DRC), .min = -1, .max = -1, .align = -1, }, 81bf215546Sopenharmony_ci }, 82bf215546Sopenharmony_ci }, 83bf215546Sopenharmony_ci [ROGUE_OP_PIX_ITER_W] = { .flags = ROH(ROGUE_INSTR_FLAG_SAT), 84bf215546Sopenharmony_ci .num_operands = 5, .operand_rules = (struct rogue_instr_operand_rule[]){ 85bf215546Sopenharmony_ci [0] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, }, 86bf215546Sopenharmony_ci [1] = { .mask = ROH(ROGUE_OPERAND_TYPE_DRC), .min = -1, .max = -1, .align = -1, }, 87bf215546Sopenharmony_ci [2] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_COEFF), .min = -1, .max = -1, .align = ROGUE_COEFF_ALIGN, }, 88bf215546Sopenharmony_ci [3] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_COEFF), .min = -1, .max = -1, .align = ROGUE_COEFF_ALIGN, }, 89bf215546Sopenharmony_ci [4] = { .mask = ROH(ROGUE_OPERAND_TYPE_IMMEDIATE), .min = 1, .max = 16, .align = -1, }, 90bf215546Sopenharmony_ci }, 91bf215546Sopenharmony_ci }, 92bf215546Sopenharmony_ci [ROGUE_OP_MAX] = { .flags = 0, 93bf215546Sopenharmony_ci .num_operands = 3, .operand_rules = (struct rogue_instr_operand_rule[]){ 94bf215546Sopenharmony_ci [0] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, }, 95bf215546Sopenharmony_ci [1] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, }, 96bf215546Sopenharmony_ci [2] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_CONST) | ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, }, 97bf215546Sopenharmony_ci }, 98bf215546Sopenharmony_ci }, 99bf215546Sopenharmony_ci [ROGUE_OP_MIN] = { .flags = 0, 100bf215546Sopenharmony_ci .num_operands = 3, .operand_rules = (struct rogue_instr_operand_rule[]){ 101bf215546Sopenharmony_ci [0] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP) | ROH(ROGUE_OPERAND_TYPE_REG_INTERNAL), .min = -1, .max = -1, .align = -1, }, 102bf215546Sopenharmony_ci [1] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, }, 103bf215546Sopenharmony_ci [2] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_CONST) | ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, }, 104bf215546Sopenharmony_ci }, 105bf215546Sopenharmony_ci }, 106bf215546Sopenharmony_ci /* TODO: Add representation for 4 sequential registers. */ 107bf215546Sopenharmony_ci [ROGUE_OP_PACK_U8888] = { .flags = 0, 108bf215546Sopenharmony_ci .num_operands = 2, .operand_rules = (struct rogue_instr_operand_rule[]){ 109bf215546Sopenharmony_ci [0] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, }, 110bf215546Sopenharmony_ci [1] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_INTERNAL), .min = -1, .max = -1, .align = -1, }, 111bf215546Sopenharmony_ci }, 112bf215546Sopenharmony_ci }, 113bf215546Sopenharmony_ci [ROGUE_OP_MOV] = { .flags = ROH(ROGUE_INSTR_FLAG_OLCHK), 114bf215546Sopenharmony_ci .num_operands = 2, .operand_rules = (struct rogue_instr_operand_rule[]){ 115bf215546Sopenharmony_ci [0] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP) | ROH(ROGUE_OPERAND_TYPE_REG_INTERNAL) | ROH(ROGUE_OPERAND_TYPE_REG_PIXEL_OUT), .min = -1, .max = -1, .align = -1, }, 116bf215546Sopenharmony_ci [1] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_CONST) | ROH(ROGUE_OPERAND_TYPE_REG_TEMP) | ROH(ROGUE_OPERAND_TYPE_REG_SHARED) | ROH(ROGUE_OPERAND_TYPE_REG_VERTEX_IN), .min = -1, .max = -1, .align = -1, }, 117bf215546Sopenharmony_ci }, 118bf215546Sopenharmony_ci }, 119bf215546Sopenharmony_ci [ROGUE_OP_MOV_IMM] = { .flags = 0, 120bf215546Sopenharmony_ci .num_operands = 2, .operand_rules = (struct rogue_instr_operand_rule[]){ 121bf215546Sopenharmony_ci [0] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, }, 122bf215546Sopenharmony_ci [1] = { .mask = ROH(ROGUE_OPERAND_TYPE_IMMEDIATE), .min = 0, .max = UINT32_MAX, .align = -1, }, 123bf215546Sopenharmony_ci }, 124bf215546Sopenharmony_ci }, 125bf215546Sopenharmony_ci [ROGUE_OP_FMA] = { .flags = ROH(ROGUE_INSTR_FLAG_SAT) | ROH(ROGUE_INSTR_FLAG_LP), 126bf215546Sopenharmony_ci .num_operands = 4, .operand_rules = (struct rogue_instr_operand_rule[]){ 127bf215546Sopenharmony_ci [0] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, }, 128bf215546Sopenharmony_ci [1] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, }, 129bf215546Sopenharmony_ci [2] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, }, 130bf215546Sopenharmony_ci [3] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, }, 131bf215546Sopenharmony_ci }, 132bf215546Sopenharmony_ci }, 133bf215546Sopenharmony_ci [ROGUE_OP_MUL] = { .flags = ROH(ROGUE_INSTR_FLAG_SAT) | ROH(ROGUE_INSTR_FLAG_LP), 134bf215546Sopenharmony_ci .num_operands = 3, .operand_rules = (struct rogue_instr_operand_rule[]){ 135bf215546Sopenharmony_ci [0] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, }, 136bf215546Sopenharmony_ci [1] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, }, 137bf215546Sopenharmony_ci [2] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, }, 138bf215546Sopenharmony_ci }, 139bf215546Sopenharmony_ci }, 140bf215546Sopenharmony_ci [ROGUE_OP_VTXOUT] = { .flags = 0, 141bf215546Sopenharmony_ci .num_operands = 2, .operand_rules = (struct rogue_instr_operand_rule[]){ 142bf215546Sopenharmony_ci [0] = { .mask = ROH(ROGUE_OPERAND_TYPE_IMMEDIATE), .min = 0, .max = ROGUE_MAX_VERTEX_OUTPUTS, .align = -1, }, 143bf215546Sopenharmony_ci [1] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, }, 144bf215546Sopenharmony_ci }, 145bf215546Sopenharmony_ci }, 146bf215546Sopenharmony_ci}; 147bf215546Sopenharmony_ci 148bf215546Sopenharmony_ci/** 149bf215546Sopenharmony_ci * \brief Validates an operand. 150bf215546Sopenharmony_ci * 151bf215546Sopenharmony_ci * \param[in] operand The operand. 152bf215546Sopenharmony_ci * \return true if valid, otherwise false. 153bf215546Sopenharmony_ci */ 154bf215546Sopenharmony_cibool rogue_validate_operand(const struct rogue_operand *operand) 155bf215546Sopenharmony_ci{ 156bf215546Sopenharmony_ci ASSERT_OPERAND_RANGE(operand->type); 157bf215546Sopenharmony_ci 158bf215546Sopenharmony_ci switch (operand->type) { 159bf215546Sopenharmony_ci case ROGUE_OPERAND_TYPE_IMMEDIATE: 160bf215546Sopenharmony_ci return true; 161bf215546Sopenharmony_ci 162bf215546Sopenharmony_ci case ROGUE_OPERAND_TYPE_DRC: 163bf215546Sopenharmony_ci CHECKF(operand->drc.number < ROGUE_NUM_DRCS, 164bf215546Sopenharmony_ci "Invalid DRC number '%zu'.", 165bf215546Sopenharmony_ci operand->drc.number); 166bf215546Sopenharmony_ci return true; 167bf215546Sopenharmony_ci 168bf215546Sopenharmony_ci case ROGUE_OPERAND_TYPE_REG_TEMP: 169bf215546Sopenharmony_ci case ROGUE_OPERAND_TYPE_REG_COEFF: 170bf215546Sopenharmony_ci case ROGUE_OPERAND_TYPE_REG_CONST: 171bf215546Sopenharmony_ci case ROGUE_OPERAND_TYPE_REG_SHARED: 172bf215546Sopenharmony_ci case ROGUE_OPERAND_TYPE_REG_PIXEL_OUT: 173bf215546Sopenharmony_ci case ROGUE_OPERAND_TYPE_REG_VERTEX_IN: 174bf215546Sopenharmony_ci case ROGUE_OPERAND_TYPE_REG_INTERNAL: 175bf215546Sopenharmony_ci CHECKF(operand->reg.number < reg_rules[operand->type].max, 176bf215546Sopenharmony_ci "Register number '%zu' out of range.", 177bf215546Sopenharmony_ci operand->reg.number); 178bf215546Sopenharmony_ci return true; 179bf215546Sopenharmony_ci 180bf215546Sopenharmony_ci default: 181bf215546Sopenharmony_ci break; 182bf215546Sopenharmony_ci } 183bf215546Sopenharmony_ci 184bf215546Sopenharmony_ci return false; 185bf215546Sopenharmony_ci} 186bf215546Sopenharmony_ci 187bf215546Sopenharmony_ci/** 188bf215546Sopenharmony_ci * \brief Validates an instruction. 189bf215546Sopenharmony_ci * 190bf215546Sopenharmony_ci * \param[in] instr The instruction. 191bf215546Sopenharmony_ci * \return true if valid, otherwise false. 192bf215546Sopenharmony_ci */ 193bf215546Sopenharmony_cibool rogue_validate_instr(const struct rogue_instr *instr) 194bf215546Sopenharmony_ci{ 195bf215546Sopenharmony_ci const struct rogue_instr_rule *rule; 196bf215546Sopenharmony_ci 197bf215546Sopenharmony_ci ASSERT_OPCODE_RANGE(instr->opcode); 198bf215546Sopenharmony_ci 199bf215546Sopenharmony_ci rule = &instr_rules[instr->opcode]; 200bf215546Sopenharmony_ci 201bf215546Sopenharmony_ci /* Validate flags. */ 202bf215546Sopenharmony_ci CHECKF(rogue_check_bitset(instr->flags, rule->flags), 203bf215546Sopenharmony_ci "Invalid instruction flags specified."); 204bf215546Sopenharmony_ci 205bf215546Sopenharmony_ci /* Validate number of operands. */ 206bf215546Sopenharmony_ci CHECKF(instr->num_operands == rule->num_operands, 207bf215546Sopenharmony_ci "Invalid number of operands specified."); 208bf215546Sopenharmony_ci 209bf215546Sopenharmony_ci CHECK(!rule->num_operands || instr->operands); 210bf215546Sopenharmony_ci for (size_t u = 0U; u < instr->num_operands; ++u) { 211bf215546Sopenharmony_ci /* Validate operand types. */ 212bf215546Sopenharmony_ci CHECKF(rogue_check_bitset(rogue_onehot(instr->operands[u].type), 213bf215546Sopenharmony_ci rule->operand_rules[u].mask), 214bf215546Sopenharmony_ci "Invalid type for operand %zu.", 215bf215546Sopenharmony_ci u); 216bf215546Sopenharmony_ci 217bf215546Sopenharmony_ci /* Validate immediate ranges. */ 218bf215546Sopenharmony_ci if (rogue_check_bitset(rogue_onehot(instr->operands[u].type), 219bf215546Sopenharmony_ci ROH(ROGUE_OPERAND_TYPE_IMMEDIATE)) && 220bf215546Sopenharmony_ci rule->operand_rules[u].min != -1 && 221bf215546Sopenharmony_ci rule->operand_rules[u].max != -1) { 222bf215546Sopenharmony_ci CHECKF( 223bf215546Sopenharmony_ci instr->operands[u].immediate.value >= rule->operand_rules[u].min && 224bf215546Sopenharmony_ci instr->operands[u].immediate.value <= rule->operand_rules[u].max, 225bf215546Sopenharmony_ci "Immediate value out of range for operand %zu.", 226bf215546Sopenharmony_ci u); 227bf215546Sopenharmony_ci } 228bf215546Sopenharmony_ci 229bf215546Sopenharmony_ci /* Validate register alignment. */ 230bf215546Sopenharmony_ci if (rogue_check_bitset(rogue_onehot(instr->operands[u].type), 231bf215546Sopenharmony_ci ROGUE_MASK_ANY_REG) && 232bf215546Sopenharmony_ci rule->operand_rules[u].align != -1) { 233bf215546Sopenharmony_ci CHECKF(!(instr->operands[u].reg.number % rule->operand_rules[u].align), 234bf215546Sopenharmony_ci "Invalid register alignment in operand %zu.", 235bf215546Sopenharmony_ci u); 236bf215546Sopenharmony_ci } 237bf215546Sopenharmony_ci 238bf215546Sopenharmony_ci /* Validate each operand. */ 239bf215546Sopenharmony_ci CHECKF(rogue_validate_operand(&instr->operands[u]), 240bf215546Sopenharmony_ci "Failed to validate operand."); 241bf215546Sopenharmony_ci } 242bf215546Sopenharmony_ci 243bf215546Sopenharmony_ci return true; 244bf215546Sopenharmony_ci} 245bf215546Sopenharmony_ci 246bf215546Sopenharmony_ci/** 247bf215546Sopenharmony_ci * \brief Validates a shader. 248bf215546Sopenharmony_ci * 249bf215546Sopenharmony_ci * \param[in] shader The shader. 250bf215546Sopenharmony_ci * \return true if valid, otherwise false. 251bf215546Sopenharmony_ci */ 252bf215546Sopenharmony_cibool rogue_validate_shader(const struct rogue_shader *shader) 253bf215546Sopenharmony_ci{ 254bf215546Sopenharmony_ci CHECK(!list_is_empty(&shader->instr_list)); 255bf215546Sopenharmony_ci ASSERT_SHADER_STAGE_RANGE(shader->stage); 256bf215546Sopenharmony_ci 257bf215546Sopenharmony_ci /* Shader stage-specific validation. */ 258bf215546Sopenharmony_ci switch (shader->stage) { 259bf215546Sopenharmony_ci case MESA_SHADER_VERTEX: 260bf215546Sopenharmony_ci /* Make sure there is (only) one end vertex shader instruction. */ 261bf215546Sopenharmony_ci CHECKF(rogue_shader_instr_count_type(shader, ROGUE_OP_END_VERT) == 1, 262bf215546Sopenharmony_ci "Shader must contain a single end.vert instruction."); 263bf215546Sopenharmony_ci 264bf215546Sopenharmony_ci /* Make sure the end vertex shader instruction is the last one. */ 265bf215546Sopenharmony_ci CHECKF(instr_last_entry(&shader->instr_list)->opcode == ROGUE_OP_END_VERT, 266bf215546Sopenharmony_ci "end.vert not last instruction."); 267bf215546Sopenharmony_ci break; 268bf215546Sopenharmony_ci 269bf215546Sopenharmony_ci case MESA_SHADER_FRAGMENT: 270bf215546Sopenharmony_ci /* Make sure there is (only) one end fragment shader instruction. */ 271bf215546Sopenharmony_ci CHECKF(rogue_shader_instr_count_type(shader, ROGUE_OP_END_FRAG) == 1, 272bf215546Sopenharmony_ci "Shader must contain a single end.frag instruction."); 273bf215546Sopenharmony_ci 274bf215546Sopenharmony_ci /* Make sure the end fragment shader instruction is the last one. */ 275bf215546Sopenharmony_ci CHECKF(instr_last_entry(&shader->instr_list)->opcode == ROGUE_OP_END_FRAG, 276bf215546Sopenharmony_ci "end.frag not last instruction."); 277bf215546Sopenharmony_ci break; 278bf215546Sopenharmony_ci 279bf215546Sopenharmony_ci default: 280bf215546Sopenharmony_ci return false; 281bf215546Sopenharmony_ci } 282bf215546Sopenharmony_ci 283bf215546Sopenharmony_ci /* Validate each instruction. */ 284bf215546Sopenharmony_ci foreach_instr (instr, &shader->instr_list) 285bf215546Sopenharmony_ci CHECKF(rogue_validate_instr(instr), "Failed to validate instruction."); 286bf215546Sopenharmony_ci 287bf215546Sopenharmony_ci return true; 288bf215546Sopenharmony_ci} 289