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