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#include <stdbool.h>
25bf215546Sopenharmony_ci#include <stddef.h>
26bf215546Sopenharmony_ci#include <stdint.h>
27bf215546Sopenharmony_ci#include <stdio.h>
28bf215546Sopenharmony_ci
29bf215546Sopenharmony_ci#include "compiler/shader_enums.h"
30bf215546Sopenharmony_ci#include "compiler/spirv/nir_spirv.h"
31bf215546Sopenharmony_ci#include "nir/nir.h"
32bf215546Sopenharmony_ci#include "rogue.h"
33bf215546Sopenharmony_ci#include "rogue_build_data.h"
34bf215546Sopenharmony_ci#include "rogue_compiler.h"
35bf215546Sopenharmony_ci#include "rogue_constreg.h"
36bf215546Sopenharmony_ci#include "rogue_encode.h"
37bf215546Sopenharmony_ci#include "rogue_nir.h"
38bf215546Sopenharmony_ci#include "rogue_nir_helpers.h"
39bf215546Sopenharmony_ci#include "rogue_operand.h"
40bf215546Sopenharmony_ci#include "rogue_regalloc.h"
41bf215546Sopenharmony_ci#include "rogue_shader.h"
42bf215546Sopenharmony_ci#include "rogue_validate.h"
43bf215546Sopenharmony_ci#include "util/macros.h"
44bf215546Sopenharmony_ci#include "util/memstream.h"
45bf215546Sopenharmony_ci#include "util/ralloc.h"
46bf215546Sopenharmony_ci
47bf215546Sopenharmony_ci/**
48bf215546Sopenharmony_ci * \file rogue.c
49bf215546Sopenharmony_ci *
50bf215546Sopenharmony_ci * \brief Contains the top-level Rogue compiler interface for Vulkan driver and
51bf215546Sopenharmony_ci * the offline compiler.
52bf215546Sopenharmony_ci */
53bf215546Sopenharmony_ci
54bf215546Sopenharmony_ci/**
55bf215546Sopenharmony_ci * \brief Converts a SPIR-V shader to NIR.
56bf215546Sopenharmony_ci *
57bf215546Sopenharmony_ci * \param[in] ctx Shared multi-stage build context.
58bf215546Sopenharmony_ci * \param[in] stage Shader stage.
59bf215546Sopenharmony_ci * \param[in] spirv_size SPIR-V data length in DWORDs.
60bf215546Sopenharmony_ci * \param[in] spirv_data SPIR-V data.
61bf215546Sopenharmony_ci * \param[in] num_spec Number of SPIR-V specializations.
62bf215546Sopenharmony_ci * \param[in] spec SPIR-V specializations.
63bf215546Sopenharmony_ci * \return A nir_shader* if successful, or NULL if unsuccessful.
64bf215546Sopenharmony_ci */
65bf215546Sopenharmony_cinir_shader *rogue_spirv_to_nir(struct rogue_build_ctx *ctx,
66bf215546Sopenharmony_ci                               gl_shader_stage stage,
67bf215546Sopenharmony_ci                               const char *entry,
68bf215546Sopenharmony_ci                               size_t spirv_size,
69bf215546Sopenharmony_ci                               const uint32_t *spirv_data,
70bf215546Sopenharmony_ci                               unsigned num_spec,
71bf215546Sopenharmony_ci                               struct nir_spirv_specialization *spec)
72bf215546Sopenharmony_ci{
73bf215546Sopenharmony_ci   nir_shader *nir;
74bf215546Sopenharmony_ci
75bf215546Sopenharmony_ci   nir = spirv_to_nir(spirv_data,
76bf215546Sopenharmony_ci                      spirv_size,
77bf215546Sopenharmony_ci                      spec,
78bf215546Sopenharmony_ci                      num_spec,
79bf215546Sopenharmony_ci                      stage,
80bf215546Sopenharmony_ci                      entry,
81bf215546Sopenharmony_ci                      rogue_get_spirv_options(ctx->compiler),
82bf215546Sopenharmony_ci                      rogue_get_compiler_options(ctx->compiler));
83bf215546Sopenharmony_ci   if (!nir)
84bf215546Sopenharmony_ci      return NULL;
85bf215546Sopenharmony_ci
86bf215546Sopenharmony_ci   ralloc_steal(ctx, nir);
87bf215546Sopenharmony_ci
88bf215546Sopenharmony_ci   /* Apply passes. */
89bf215546Sopenharmony_ci   if (!rogue_nir_passes(ctx, nir, stage)) {
90bf215546Sopenharmony_ci      ralloc_free(nir);
91bf215546Sopenharmony_ci      return NULL;
92bf215546Sopenharmony_ci   }
93bf215546Sopenharmony_ci
94bf215546Sopenharmony_ci   /* Collect I/O data to pass back to the driver. */
95bf215546Sopenharmony_ci   if (!rogue_collect_io_data(ctx, nir)) {
96bf215546Sopenharmony_ci      ralloc_free(nir);
97bf215546Sopenharmony_ci      return NULL;
98bf215546Sopenharmony_ci   }
99bf215546Sopenharmony_ci
100bf215546Sopenharmony_ci   return nir;
101bf215546Sopenharmony_ci}
102bf215546Sopenharmony_ci
103bf215546Sopenharmony_ci/**
104bf215546Sopenharmony_ci * \brief Converts a Rogue shader to binary.
105bf215546Sopenharmony_ci *
106bf215546Sopenharmony_ci * \param[in] ctx Shared multi-stage build context.
107bf215546Sopenharmony_ci * \param[in] shader Rogue shader.
108bf215546Sopenharmony_ci * \return A rogue_shader_binary* if successful, or NULL if unsuccessful.
109bf215546Sopenharmony_ci */
110bf215546Sopenharmony_cistruct rogue_shader_binary *rogue_to_binary(struct rogue_build_ctx *ctx,
111bf215546Sopenharmony_ci                                            const struct rogue_shader *shader)
112bf215546Sopenharmony_ci{
113bf215546Sopenharmony_ci   struct rogue_shader_binary *binary;
114bf215546Sopenharmony_ci   struct u_memstream mem;
115bf215546Sopenharmony_ci   size_t buf_size;
116bf215546Sopenharmony_ci   char *buf;
117bf215546Sopenharmony_ci
118bf215546Sopenharmony_ci   if (!rogue_validate_shader(shader))
119bf215546Sopenharmony_ci      return NULL;
120bf215546Sopenharmony_ci
121bf215546Sopenharmony_ci   if (!u_memstream_open(&mem, &buf, &buf_size))
122bf215546Sopenharmony_ci      return NULL;
123bf215546Sopenharmony_ci
124bf215546Sopenharmony_ci   if (!rogue_encode_shader(shader, u_memstream_get(&mem))) {
125bf215546Sopenharmony_ci      u_memstream_close(&mem);
126bf215546Sopenharmony_ci      free(buf);
127bf215546Sopenharmony_ci      return NULL;
128bf215546Sopenharmony_ci   }
129bf215546Sopenharmony_ci
130bf215546Sopenharmony_ci   u_memstream_close(&mem);
131bf215546Sopenharmony_ci
132bf215546Sopenharmony_ci   binary = rzalloc_size(ctx, sizeof(*binary) + buf_size);
133bf215546Sopenharmony_ci   if (!binary) {
134bf215546Sopenharmony_ci      free(buf);
135bf215546Sopenharmony_ci      return NULL;
136bf215546Sopenharmony_ci   }
137bf215546Sopenharmony_ci
138bf215546Sopenharmony_ci   binary->size = buf_size;
139bf215546Sopenharmony_ci   memcpy(binary->data, buf, buf_size);
140bf215546Sopenharmony_ci
141bf215546Sopenharmony_ci   free(buf);
142bf215546Sopenharmony_ci
143bf215546Sopenharmony_ci   return binary;
144bf215546Sopenharmony_ci}
145bf215546Sopenharmony_ci
146bf215546Sopenharmony_cistatic bool
147bf215546Sopenharmony_cisetup_alu_dest(struct rogue_instr *instr, size_t dest_index, nir_alu_instr *alu)
148bf215546Sopenharmony_ci{
149bf215546Sopenharmony_ci   assert(dest_index == 0);
150bf215546Sopenharmony_ci
151bf215546Sopenharmony_ci   /* Dest validation. */
152bf215546Sopenharmony_ci   assert(nir_dest_num_components(alu->dest.dest) == 1 ||
153bf215546Sopenharmony_ci          nir_dest_num_components(alu->dest.dest) == 4);
154bf215546Sopenharmony_ci   assert(nir_dest_bit_size(alu->dest.dest) == 32);
155bf215546Sopenharmony_ci
156bf215546Sopenharmony_ci   size_t nir_dest_reg = nir_alu_dest_regindex(alu);
157bf215546Sopenharmony_ci
158bf215546Sopenharmony_ci   if (nir_dest_num_components(alu->dest.dest) == 1) {
159bf215546Sopenharmony_ci      CHECK(rogue_instr_set_operand_vreg(instr, dest_index, nir_dest_reg));
160bf215546Sopenharmony_ci   } else {
161bf215546Sopenharmony_ci      size_t comp = nir_alu_dest_comp(alu);
162bf215546Sopenharmony_ci      CHECK(rogue_instr_set_operand_vreg_vec(instr,
163bf215546Sopenharmony_ci                                             dest_index,
164bf215546Sopenharmony_ci                                             comp,
165bf215546Sopenharmony_ci                                             nir_dest_reg));
166bf215546Sopenharmony_ci   }
167bf215546Sopenharmony_ci
168bf215546Sopenharmony_ci   return true;
169bf215546Sopenharmony_ci}
170bf215546Sopenharmony_ci
171bf215546Sopenharmony_cistatic bool trans_constreg_operand(struct rogue_instr *instr,
172bf215546Sopenharmony_ci                                   size_t operand_index,
173bf215546Sopenharmony_ci                                   uint32_t const_value)
174bf215546Sopenharmony_ci{
175bf215546Sopenharmony_ci   size_t const_reg = rogue_constreg_lookup(const_value);
176bf215546Sopenharmony_ci
177bf215546Sopenharmony_ci   /* Only values that can be sourced from const regs should be left from the
178bf215546Sopenharmony_ci    * rogue_nir_constreg pass.
179bf215546Sopenharmony_ci    */
180bf215546Sopenharmony_ci   assert(const_reg != ROGUE_NO_CONST_REG);
181bf215546Sopenharmony_ci
182bf215546Sopenharmony_ci   CHECK(rogue_instr_set_operand_reg(instr,
183bf215546Sopenharmony_ci                                     operand_index,
184bf215546Sopenharmony_ci                                     ROGUE_OPERAND_TYPE_REG_CONST,
185bf215546Sopenharmony_ci                                     const_reg));
186bf215546Sopenharmony_ci
187bf215546Sopenharmony_ci   return true;
188bf215546Sopenharmony_ci}
189bf215546Sopenharmony_ci
190bf215546Sopenharmony_cistatic bool trans_nir_alu_fmax(struct rogue_shader *shader, nir_alu_instr *alu)
191bf215546Sopenharmony_ci{
192bf215546Sopenharmony_ci   /* Src validation. */
193bf215546Sopenharmony_ci   assert(nir_src_num_components(alu->src[0].src) == 1);
194bf215546Sopenharmony_ci   assert(nir_src_bit_size(alu->src[0].src) == 32);
195bf215546Sopenharmony_ci
196bf215546Sopenharmony_ci   assert(nir_src_num_components(alu->src[1].src) == 1);
197bf215546Sopenharmony_ci   assert(nir_src_bit_size(alu->src[1].src) == 32);
198bf215546Sopenharmony_ci
199bf215546Sopenharmony_ci   struct rogue_instr *instr = rogue_shader_insert(shader, ROGUE_OP_MAX);
200bf215546Sopenharmony_ci
201bf215546Sopenharmony_ci   CHECK(setup_alu_dest(instr, 0, alu));
202bf215546Sopenharmony_ci
203bf215546Sopenharmony_ci   for (size_t u = 0; u < nir_op_infos[nir_op_fmax].num_inputs; ++u) {
204bf215546Sopenharmony_ci      /* Handle values that can be pulled from const regs. */
205bf215546Sopenharmony_ci      if (nir_alu_src_is_const(alu, u)) {
206bf215546Sopenharmony_ci         CHECK(trans_constreg_operand(instr, u + 1, nir_alu_src_const(alu, u)));
207bf215546Sopenharmony_ci         continue;
208bf215546Sopenharmony_ci      }
209bf215546Sopenharmony_ci
210bf215546Sopenharmony_ci      size_t nir_src_reg = nir_alu_src_regindex(alu, u);
211bf215546Sopenharmony_ci
212bf215546Sopenharmony_ci      CHECK(rogue_instr_set_operand_vreg(instr, u + 1, nir_src_reg));
213bf215546Sopenharmony_ci   }
214bf215546Sopenharmony_ci
215bf215546Sopenharmony_ci   return true;
216bf215546Sopenharmony_ci}
217bf215546Sopenharmony_ci
218bf215546Sopenharmony_cistatic bool trans_nir_alu_fmin(struct rogue_shader *shader, nir_alu_instr *alu)
219bf215546Sopenharmony_ci{
220bf215546Sopenharmony_ci   /* Src validation. */
221bf215546Sopenharmony_ci   assert(nir_src_num_components(alu->src[0].src) == 1);
222bf215546Sopenharmony_ci   assert(nir_src_bit_size(alu->src[0].src) == 32);
223bf215546Sopenharmony_ci
224bf215546Sopenharmony_ci   assert(nir_src_num_components(alu->src[1].src) == 1);
225bf215546Sopenharmony_ci   assert(nir_src_bit_size(alu->src[1].src) == 32);
226bf215546Sopenharmony_ci
227bf215546Sopenharmony_ci   struct rogue_instr *instr = rogue_shader_insert(shader, ROGUE_OP_MIN);
228bf215546Sopenharmony_ci
229bf215546Sopenharmony_ci   CHECK(setup_alu_dest(instr, 0, alu));
230bf215546Sopenharmony_ci
231bf215546Sopenharmony_ci   for (size_t u = 0; u < nir_op_infos[nir_op_fmin].num_inputs; ++u) {
232bf215546Sopenharmony_ci      /* Handle values that can be pulled from const regs. */
233bf215546Sopenharmony_ci      if (nir_alu_src_is_const(alu, u)) {
234bf215546Sopenharmony_ci         CHECK(trans_constreg_operand(instr, u + 1, nir_alu_src_const(alu, u)));
235bf215546Sopenharmony_ci         continue;
236bf215546Sopenharmony_ci      }
237bf215546Sopenharmony_ci
238bf215546Sopenharmony_ci      size_t nir_src_reg = nir_alu_src_regindex(alu, u);
239bf215546Sopenharmony_ci
240bf215546Sopenharmony_ci      CHECK(rogue_instr_set_operand_vreg(instr, u + 1, nir_src_reg));
241bf215546Sopenharmony_ci   }
242bf215546Sopenharmony_ci
243bf215546Sopenharmony_ci   return true;
244bf215546Sopenharmony_ci}
245bf215546Sopenharmony_ci
246bf215546Sopenharmony_cistatic bool trans_nir_alu_mov_imm(struct rogue_shader *shader,
247bf215546Sopenharmony_ci                                  nir_alu_instr *alu)
248bf215546Sopenharmony_ci{
249bf215546Sopenharmony_ci   /* Src validation. */
250bf215546Sopenharmony_ci   assert(nir_src_num_components(alu->src[0].src) == 1);
251bf215546Sopenharmony_ci   assert(nir_src_bit_size(alu->src[0].src) == 32);
252bf215546Sopenharmony_ci
253bf215546Sopenharmony_ci   uint32_t value = nir_alu_src_const(alu, 0);
254bf215546Sopenharmony_ci
255bf215546Sopenharmony_ci   struct rogue_instr *instr = rogue_shader_insert(shader, ROGUE_OP_MOV_IMM);
256bf215546Sopenharmony_ci
257bf215546Sopenharmony_ci   CHECK(setup_alu_dest(instr, 0, alu));
258bf215546Sopenharmony_ci   CHECK(rogue_instr_set_operand_imm(instr, 1, value));
259bf215546Sopenharmony_ci
260bf215546Sopenharmony_ci   return true;
261bf215546Sopenharmony_ci}
262bf215546Sopenharmony_ci
263bf215546Sopenharmony_cistatic bool trans_nir_alu_mov(struct rogue_shader *shader, nir_alu_instr *alu)
264bf215546Sopenharmony_ci{
265bf215546Sopenharmony_ci   /* Constant value that isn't in constregs. */
266bf215546Sopenharmony_ci   if (nir_alu_src_is_const(alu, 0) &&
267bf215546Sopenharmony_ci       nir_dest_num_components(alu->dest.dest) == 1)
268bf215546Sopenharmony_ci      return trans_nir_alu_mov_imm(shader, alu);
269bf215546Sopenharmony_ci
270bf215546Sopenharmony_ci   /* Src validation. */
271bf215546Sopenharmony_ci   assert(nir_src_num_components(alu->src[0].src) == 1);
272bf215546Sopenharmony_ci   assert(nir_src_bit_size(alu->src[0].src) == 32);
273bf215546Sopenharmony_ci
274bf215546Sopenharmony_ci   struct rogue_instr *instr = rogue_shader_insert(shader, ROGUE_OP_MOV);
275bf215546Sopenharmony_ci
276bf215546Sopenharmony_ci   CHECK(setup_alu_dest(instr, 0, alu));
277bf215546Sopenharmony_ci
278bf215546Sopenharmony_ci   /* Handle values that can be pulled from const regs. */
279bf215546Sopenharmony_ci   if (nir_alu_src_is_const(alu, 0)) {
280bf215546Sopenharmony_ci      return trans_constreg_operand(instr, 1, nir_alu_src_const(alu, 0));
281bf215546Sopenharmony_ci   }
282bf215546Sopenharmony_ci
283bf215546Sopenharmony_ci   size_t nir_src_reg = nir_alu_src_regindex(alu, 0);
284bf215546Sopenharmony_ci   CHECK(rogue_instr_set_operand_vreg(instr, 1, nir_src_reg));
285bf215546Sopenharmony_ci
286bf215546Sopenharmony_ci   return true;
287bf215546Sopenharmony_ci}
288bf215546Sopenharmony_ci
289bf215546Sopenharmony_cistatic bool trans_nir_alu_pack_unorm_4x8(struct rogue_shader *shader,
290bf215546Sopenharmony_ci                                         nir_alu_instr *alu)
291bf215546Sopenharmony_ci{
292bf215546Sopenharmony_ci   /* Src/dest validation. */
293bf215546Sopenharmony_ci   assert(nir_dest_num_components(alu->dest.dest) == 1);
294bf215546Sopenharmony_ci   assert(nir_dest_bit_size(alu->dest.dest) == 32);
295bf215546Sopenharmony_ci
296bf215546Sopenharmony_ci   assert(nir_src_num_components(alu->src[0].src) == 4);
297bf215546Sopenharmony_ci   assert(nir_src_bit_size(alu->src[0].src) == 32);
298bf215546Sopenharmony_ci
299bf215546Sopenharmony_ci   size_t nir_src_reg = nir_alu_src_regindex(alu, 0);
300bf215546Sopenharmony_ci   size_t nir_dest_reg = nir_alu_dest_regindex(alu);
301bf215546Sopenharmony_ci
302bf215546Sopenharmony_ci   struct rogue_instr *instr = rogue_shader_insert(shader, ROGUE_OP_PACK_U8888);
303bf215546Sopenharmony_ci
304bf215546Sopenharmony_ci   CHECK(rogue_instr_set_operand_vreg(instr, 0, nir_dest_reg));
305bf215546Sopenharmony_ci
306bf215546Sopenharmony_ci   /* Ensure all 4 components are being sourced in order. */
307bf215546Sopenharmony_ci   for (size_t u = 0; u < nir_src_num_components(alu->src[0].src); ++u)
308bf215546Sopenharmony_ci      assert(alu->src->swizzle[u] == u);
309bf215546Sopenharmony_ci
310bf215546Sopenharmony_ci   CHECK(rogue_instr_set_operand_vreg_vec(instr,
311bf215546Sopenharmony_ci                                          1,
312bf215546Sopenharmony_ci                                          ROGUE_COMPONENT_ALL,
313bf215546Sopenharmony_ci                                          nir_src_reg));
314bf215546Sopenharmony_ci
315bf215546Sopenharmony_ci   return true;
316bf215546Sopenharmony_ci}
317bf215546Sopenharmony_ci
318bf215546Sopenharmony_cistatic bool trans_nir_alu_fmul(struct rogue_shader *shader, nir_alu_instr *alu)
319bf215546Sopenharmony_ci{
320bf215546Sopenharmony_ci   /* Src validation. */
321bf215546Sopenharmony_ci   assert(nir_src_num_components(alu->src[0].src) == 1);
322bf215546Sopenharmony_ci   assert(nir_src_bit_size(alu->src[0].src) == 32);
323bf215546Sopenharmony_ci
324bf215546Sopenharmony_ci   assert(nir_src_num_components(alu->src[1].src) == 1);
325bf215546Sopenharmony_ci   assert(nir_src_bit_size(alu->src[1].src) == 32);
326bf215546Sopenharmony_ci
327bf215546Sopenharmony_ci   size_t nir_in_reg_a = nir_alu_src_regindex(alu, 0);
328bf215546Sopenharmony_ci   size_t nir_in_reg_b = nir_alu_src_regindex(alu, 1);
329bf215546Sopenharmony_ci
330bf215546Sopenharmony_ci   struct rogue_instr *instr = rogue_shader_insert(shader, ROGUE_OP_MUL);
331bf215546Sopenharmony_ci
332bf215546Sopenharmony_ci   CHECK(setup_alu_dest(instr, 0, alu));
333bf215546Sopenharmony_ci   CHECK(rogue_instr_set_operand_vreg(instr, 1, nir_in_reg_a));
334bf215546Sopenharmony_ci   CHECK(rogue_instr_set_operand_vreg(instr, 2, nir_in_reg_b));
335bf215546Sopenharmony_ci
336bf215546Sopenharmony_ci   return true;
337bf215546Sopenharmony_ci}
338bf215546Sopenharmony_ci
339bf215546Sopenharmony_cistatic bool trans_nir_alu_ffma(struct rogue_shader *shader, nir_alu_instr *alu)
340bf215546Sopenharmony_ci{
341bf215546Sopenharmony_ci   /* Src validation. */
342bf215546Sopenharmony_ci   assert(nir_src_num_components(alu->src[0].src) == 1);
343bf215546Sopenharmony_ci   assert(nir_src_bit_size(alu->src[0].src) == 32);
344bf215546Sopenharmony_ci
345bf215546Sopenharmony_ci   assert(nir_src_num_components(alu->src[1].src) == 1);
346bf215546Sopenharmony_ci   assert(nir_src_bit_size(alu->src[1].src) == 32);
347bf215546Sopenharmony_ci
348bf215546Sopenharmony_ci   assert(nir_src_num_components(alu->src[2].src) == 1);
349bf215546Sopenharmony_ci   assert(nir_src_bit_size(alu->src[2].src) == 32);
350bf215546Sopenharmony_ci
351bf215546Sopenharmony_ci   size_t nir_in_reg_a = nir_alu_src_regindex(alu, 0);
352bf215546Sopenharmony_ci   size_t nir_in_reg_b = nir_alu_src_regindex(alu, 1);
353bf215546Sopenharmony_ci   size_t nir_in_reg_c = nir_alu_src_regindex(alu, 2);
354bf215546Sopenharmony_ci
355bf215546Sopenharmony_ci   struct rogue_instr *instr = rogue_shader_insert(shader, ROGUE_OP_FMA);
356bf215546Sopenharmony_ci
357bf215546Sopenharmony_ci   CHECK(setup_alu_dest(instr, 0, alu));
358bf215546Sopenharmony_ci   CHECK(rogue_instr_set_operand_vreg(instr, 1, nir_in_reg_a));
359bf215546Sopenharmony_ci   CHECK(rogue_instr_set_operand_vreg(instr, 2, nir_in_reg_b));
360bf215546Sopenharmony_ci   CHECK(rogue_instr_set_operand_vreg(instr, 3, nir_in_reg_c));
361bf215546Sopenharmony_ci
362bf215546Sopenharmony_ci   return true;
363bf215546Sopenharmony_ci}
364bf215546Sopenharmony_ci
365bf215546Sopenharmony_cistatic bool trans_nir_alu(struct rogue_shader *shader, nir_alu_instr *alu)
366bf215546Sopenharmony_ci{
367bf215546Sopenharmony_ci   switch (alu->op) {
368bf215546Sopenharmony_ci   case nir_op_fmax:
369bf215546Sopenharmony_ci      return trans_nir_alu_fmax(shader, alu);
370bf215546Sopenharmony_ci
371bf215546Sopenharmony_ci   case nir_op_fmin:
372bf215546Sopenharmony_ci      return trans_nir_alu_fmin(shader, alu);
373bf215546Sopenharmony_ci
374bf215546Sopenharmony_ci   case nir_op_pack_unorm_4x8:
375bf215546Sopenharmony_ci      return trans_nir_alu_pack_unorm_4x8(shader, alu);
376bf215546Sopenharmony_ci
377bf215546Sopenharmony_ci   case nir_op_mov:
378bf215546Sopenharmony_ci      return trans_nir_alu_mov(shader, alu);
379bf215546Sopenharmony_ci
380bf215546Sopenharmony_ci   case nir_op_fmul:
381bf215546Sopenharmony_ci      return trans_nir_alu_fmul(shader, alu);
382bf215546Sopenharmony_ci
383bf215546Sopenharmony_ci   case nir_op_ffma:
384bf215546Sopenharmony_ci      return trans_nir_alu_ffma(shader, alu);
385bf215546Sopenharmony_ci
386bf215546Sopenharmony_ci   default:
387bf215546Sopenharmony_ci      break;
388bf215546Sopenharmony_ci   }
389bf215546Sopenharmony_ci
390bf215546Sopenharmony_ci   unreachable("Unimplemented NIR ALU instruction.");
391bf215546Sopenharmony_ci}
392bf215546Sopenharmony_ci
393bf215546Sopenharmony_cistatic bool trans_nir_intrinsic_load_input_fs(struct rogue_shader *shader,
394bf215546Sopenharmony_ci                                              nir_intrinsic_instr *intr)
395bf215546Sopenharmony_ci{
396bf215546Sopenharmony_ci   struct rogue_fs_build_data *fs_data = &shader->ctx->stage_data.fs;
397bf215546Sopenharmony_ci
398bf215546Sopenharmony_ci   /* Src/dest validation. */
399bf215546Sopenharmony_ci   assert(nir_dest_num_components(intr->dest) == 1);
400bf215546Sopenharmony_ci   assert(nir_dest_bit_size(intr->dest) == 32);
401bf215546Sopenharmony_ci
402bf215546Sopenharmony_ci   assert(nir_src_num_components(intr->src[0]) == 1);
403bf215546Sopenharmony_ci   assert(nir_src_bit_size(intr->src[0]) == 32);
404bf215546Sopenharmony_ci   assert(nir_intr_src_is_const(intr, 0));
405bf215546Sopenharmony_ci
406bf215546Sopenharmony_ci   /* Intrinsic index validation. */
407bf215546Sopenharmony_ci   assert(nir_intrinsic_dest_type(intr) == nir_type_float32);
408bf215546Sopenharmony_ci
409bf215546Sopenharmony_ci   struct nir_io_semantics io_semantics = nir_intrinsic_io_semantics(intr);
410bf215546Sopenharmony_ci   size_t component = nir_intrinsic_component(intr);
411bf215546Sopenharmony_ci   size_t coeff_index = rogue_coeff_index_fs(&fs_data->iterator_args,
412bf215546Sopenharmony_ci                                             io_semantics.location,
413bf215546Sopenharmony_ci                                             component);
414bf215546Sopenharmony_ci   size_t wcoeff_index = rogue_coeff_index_fs(&fs_data->iterator_args, ~0, 0);
415bf215546Sopenharmony_ci   size_t drc_num = rogue_acquire_drc(shader);
416bf215546Sopenharmony_ci   uint64_t source_count = nir_dest_num_components(intr->dest);
417bf215546Sopenharmony_ci
418bf215546Sopenharmony_ci   size_t nir_dest_reg = nir_intr_dest_regindex(intr);
419bf215546Sopenharmony_ci
420bf215546Sopenharmony_ci   /* pixiter.w instruction. */
421bf215546Sopenharmony_ci   struct rogue_instr *instr = rogue_shader_insert(shader, ROGUE_OP_PIX_ITER_W);
422bf215546Sopenharmony_ci
423bf215546Sopenharmony_ci   CHECK(rogue_instr_set_operand_vreg(instr, 0, nir_dest_reg));
424bf215546Sopenharmony_ci   CHECK(rogue_instr_set_operand_drc(instr, 1, drc_num));
425bf215546Sopenharmony_ci   CHECK(rogue_instr_set_operand_reg(instr,
426bf215546Sopenharmony_ci                                     2,
427bf215546Sopenharmony_ci                                     ROGUE_OPERAND_TYPE_REG_COEFF,
428bf215546Sopenharmony_ci                                     coeff_index));
429bf215546Sopenharmony_ci   CHECK(rogue_instr_set_operand_reg(instr,
430bf215546Sopenharmony_ci                                     3,
431bf215546Sopenharmony_ci                                     ROGUE_OPERAND_TYPE_REG_COEFF,
432bf215546Sopenharmony_ci                                     wcoeff_index));
433bf215546Sopenharmony_ci   CHECK(rogue_instr_set_operand_imm(instr, 4, source_count));
434bf215546Sopenharmony_ci
435bf215546Sopenharmony_ci   /* wdf instruction must follow the pixiter.w. */
436bf215546Sopenharmony_ci   instr = rogue_shader_insert(shader, ROGUE_OP_WDF);
437bf215546Sopenharmony_ci
438bf215546Sopenharmony_ci   CHECK(rogue_instr_set_operand_drc(instr, 0, drc_num));
439bf215546Sopenharmony_ci   rogue_release_drc(shader, drc_num);
440bf215546Sopenharmony_ci
441bf215546Sopenharmony_ci   return true;
442bf215546Sopenharmony_ci}
443bf215546Sopenharmony_ci
444bf215546Sopenharmony_cistatic bool trans_nir_intrinsic_load_input_vs(struct rogue_shader *shader,
445bf215546Sopenharmony_ci                                              nir_intrinsic_instr *intr)
446bf215546Sopenharmony_ci{
447bf215546Sopenharmony_ci   /* Src/dest validation. */
448bf215546Sopenharmony_ci   assert(nir_dest_num_components(intr->dest) == 1);
449bf215546Sopenharmony_ci   assert(nir_dest_bit_size(intr->dest) == 32);
450bf215546Sopenharmony_ci
451bf215546Sopenharmony_ci   assert(nir_src_num_components(intr->src[0]) == 1);
452bf215546Sopenharmony_ci   assert(nir_src_bit_size(intr->src[0]) == 32);
453bf215546Sopenharmony_ci   assert(nir_intr_src_is_const(intr, 0));
454bf215546Sopenharmony_ci
455bf215546Sopenharmony_ci   /* Intrinsic index validation. */
456bf215546Sopenharmony_ci   assert(nir_intrinsic_dest_type(intr) == nir_type_float32);
457bf215546Sopenharmony_ci
458bf215546Sopenharmony_ci   size_t component = nir_intrinsic_component(intr);
459bf215546Sopenharmony_ci   struct nir_io_semantics io_semantics = nir_intrinsic_io_semantics(intr);
460bf215546Sopenharmony_ci   size_t vi_reg_index = ((io_semantics.location - VERT_ATTRIB_GENERIC0) * 3) +
461bf215546Sopenharmony_ci                         component; /* TODO: get these properly with the
462bf215546Sopenharmony_ci                                     * intrinsic index (ssa argument)
463bf215546Sopenharmony_ci                                     */
464bf215546Sopenharmony_ci
465bf215546Sopenharmony_ci   size_t nir_dest_reg = nir_intr_dest_regindex(intr);
466bf215546Sopenharmony_ci
467bf215546Sopenharmony_ci   struct rogue_instr *instr = rogue_shader_insert(shader, ROGUE_OP_MOV);
468bf215546Sopenharmony_ci
469bf215546Sopenharmony_ci   CHECK(rogue_instr_set_operand_vreg(instr, 0, nir_dest_reg));
470bf215546Sopenharmony_ci   CHECK(rogue_instr_set_operand_reg(instr,
471bf215546Sopenharmony_ci                                     1,
472bf215546Sopenharmony_ci                                     ROGUE_OPERAND_TYPE_REG_VERTEX_IN,
473bf215546Sopenharmony_ci                                     vi_reg_index));
474bf215546Sopenharmony_ci
475bf215546Sopenharmony_ci   return true;
476bf215546Sopenharmony_ci}
477bf215546Sopenharmony_ci
478bf215546Sopenharmony_cistatic bool trans_nir_intrinsic_load_input(struct rogue_shader *shader,
479bf215546Sopenharmony_ci                                           nir_intrinsic_instr *intr)
480bf215546Sopenharmony_ci{
481bf215546Sopenharmony_ci   switch (shader->stage) {
482bf215546Sopenharmony_ci   case MESA_SHADER_FRAGMENT:
483bf215546Sopenharmony_ci      return trans_nir_intrinsic_load_input_fs(shader, intr);
484bf215546Sopenharmony_ci
485bf215546Sopenharmony_ci   case MESA_SHADER_VERTEX:
486bf215546Sopenharmony_ci      return trans_nir_intrinsic_load_input_vs(shader, intr);
487bf215546Sopenharmony_ci
488bf215546Sopenharmony_ci   default:
489bf215546Sopenharmony_ci      break;
490bf215546Sopenharmony_ci   }
491bf215546Sopenharmony_ci
492bf215546Sopenharmony_ci   unreachable("Unimplemented NIR load_input variant.");
493bf215546Sopenharmony_ci}
494bf215546Sopenharmony_ci
495bf215546Sopenharmony_cistatic bool trans_nir_intrinsic_store_output_fs(struct rogue_shader *shader,
496bf215546Sopenharmony_ci                                                nir_intrinsic_instr *intr)
497bf215546Sopenharmony_ci{
498bf215546Sopenharmony_ci   /* Src/dest validation. */
499bf215546Sopenharmony_ci   assert(nir_src_num_components(intr->src[0]) == 1);
500bf215546Sopenharmony_ci   assert(nir_src_bit_size(intr->src[0]) == 32);
501bf215546Sopenharmony_ci   assert(!nir_intr_src_is_const(intr, 0));
502bf215546Sopenharmony_ci
503bf215546Sopenharmony_ci   assert(nir_src_num_components(intr->src[1]) == 1);
504bf215546Sopenharmony_ci   assert(nir_src_bit_size(intr->src[1]) == 32);
505bf215546Sopenharmony_ci   assert(nir_intr_src_is_const(intr, 1));
506bf215546Sopenharmony_ci
507bf215546Sopenharmony_ci   /* Intrinsic index validation. */
508bf215546Sopenharmony_ci   assert(nir_intrinsic_src_type(intr) == nir_type_uint32);
509bf215546Sopenharmony_ci
510bf215546Sopenharmony_ci   /* Fetch the output offset. */
511bf215546Sopenharmony_ci   /* TODO: Is this really the right value to use for pixel out reg. num? */
512bf215546Sopenharmony_ci   size_t offset = nir_intr_src_const(intr, 1);
513bf215546Sopenharmony_ci
514bf215546Sopenharmony_ci   /* Fetch the components. */
515bf215546Sopenharmony_ci   size_t src_reg = nir_intr_src_regindex(intr, 0);
516bf215546Sopenharmony_ci
517bf215546Sopenharmony_ci   /* mov.olchk instruction. */
518bf215546Sopenharmony_ci   struct rogue_instr *instr = rogue_shader_insert(shader, ROGUE_OP_MOV);
519bf215546Sopenharmony_ci
520bf215546Sopenharmony_ci   CHECK(rogue_instr_set_operand_reg(instr,
521bf215546Sopenharmony_ci                                     0,
522bf215546Sopenharmony_ci                                     ROGUE_OPERAND_TYPE_REG_PIXEL_OUT,
523bf215546Sopenharmony_ci                                     offset));
524bf215546Sopenharmony_ci   CHECK(rogue_instr_set_operand_vreg(instr, 1, src_reg));
525bf215546Sopenharmony_ci   CHECK(rogue_instr_set_flag(instr, ROGUE_INSTR_FLAG_OLCHK));
526bf215546Sopenharmony_ci
527bf215546Sopenharmony_ci   return true;
528bf215546Sopenharmony_ci}
529bf215546Sopenharmony_ci
530bf215546Sopenharmony_cistatic bool trans_nir_intrinsic_store_output_vs(struct rogue_shader *shader,
531bf215546Sopenharmony_ci                                                nir_intrinsic_instr *intr)
532bf215546Sopenharmony_ci{
533bf215546Sopenharmony_ci   struct rogue_vs_build_data *vs_data = &shader->ctx->stage_data.vs;
534bf215546Sopenharmony_ci
535bf215546Sopenharmony_ci   /* Src/dest validation. */
536bf215546Sopenharmony_ci   assert(nir_src_num_components(intr->src[0]) == 1);
537bf215546Sopenharmony_ci   assert(nir_src_bit_size(intr->src[0]) == 32);
538bf215546Sopenharmony_ci   assert(!nir_intr_src_is_const(intr, 0));
539bf215546Sopenharmony_ci
540bf215546Sopenharmony_ci   assert(nir_src_num_components(intr->src[1]) == 1);
541bf215546Sopenharmony_ci   assert(nir_src_bit_size(intr->src[1]) == 32);
542bf215546Sopenharmony_ci   assert(nir_intr_src_is_const(intr, 1));
543bf215546Sopenharmony_ci
544bf215546Sopenharmony_ci   /* Intrinsic index validation. */
545bf215546Sopenharmony_ci   assert(nir_intrinsic_src_type(intr) == nir_type_float32);
546bf215546Sopenharmony_ci   assert(util_bitcount(nir_intrinsic_write_mask(intr)) == 1);
547bf215546Sopenharmony_ci
548bf215546Sopenharmony_ci   struct nir_io_semantics io_semantics = nir_intrinsic_io_semantics(intr);
549bf215546Sopenharmony_ci   size_t component = nir_intrinsic_component(intr);
550bf215546Sopenharmony_ci   size_t vo_index = rogue_output_index_vs(&vs_data->outputs,
551bf215546Sopenharmony_ci                                           io_semantics.location,
552bf215546Sopenharmony_ci                                           component);
553bf215546Sopenharmony_ci
554bf215546Sopenharmony_ci   size_t src_reg = nir_intr_src_regindex(intr, 0);
555bf215546Sopenharmony_ci
556bf215546Sopenharmony_ci   struct rogue_instr *instr = rogue_shader_insert(shader, ROGUE_OP_VTXOUT);
557bf215546Sopenharmony_ci
558bf215546Sopenharmony_ci   CHECK(rogue_instr_set_operand_imm(instr, 0, vo_index));
559bf215546Sopenharmony_ci   CHECK(rogue_instr_set_operand_vreg(instr, 1, src_reg));
560bf215546Sopenharmony_ci
561bf215546Sopenharmony_ci   return true;
562bf215546Sopenharmony_ci}
563bf215546Sopenharmony_ci
564bf215546Sopenharmony_cistatic bool trans_nir_intrinsic_store_output(struct rogue_shader *shader,
565bf215546Sopenharmony_ci                                             nir_intrinsic_instr *intr)
566bf215546Sopenharmony_ci{
567bf215546Sopenharmony_ci   switch (shader->stage) {
568bf215546Sopenharmony_ci   case MESA_SHADER_FRAGMENT:
569bf215546Sopenharmony_ci      return trans_nir_intrinsic_store_output_fs(shader, intr);
570bf215546Sopenharmony_ci
571bf215546Sopenharmony_ci   case MESA_SHADER_VERTEX:
572bf215546Sopenharmony_ci      return trans_nir_intrinsic_store_output_vs(shader, intr);
573bf215546Sopenharmony_ci
574bf215546Sopenharmony_ci   default:
575bf215546Sopenharmony_ci      break;
576bf215546Sopenharmony_ci   }
577bf215546Sopenharmony_ci
578bf215546Sopenharmony_ci   unreachable("Unimplemented NIR store_output variant.");
579bf215546Sopenharmony_ci}
580bf215546Sopenharmony_ci
581bf215546Sopenharmony_cistatic bool trans_nir_intrinsic_load_ubo(struct rogue_shader *shader,
582bf215546Sopenharmony_ci                                         nir_intrinsic_instr *intr)
583bf215546Sopenharmony_ci{
584bf215546Sopenharmony_ci   struct rogue_ubo_data *ubo_data =
585bf215546Sopenharmony_ci      &shader->ctx->common_data[shader->stage].ubo_data;
586bf215546Sopenharmony_ci
587bf215546Sopenharmony_ci   /* Src/dest validation. */
588bf215546Sopenharmony_ci   assert(nir_dest_num_components(intr->dest) == 1);
589bf215546Sopenharmony_ci   assert(nir_dest_bit_size(intr->dest) == 32);
590bf215546Sopenharmony_ci
591bf215546Sopenharmony_ci   assert(nir_src_num_components(intr->src[0]) == 2);
592bf215546Sopenharmony_ci   assert(nir_src_bit_size(intr->src[0]) == 32);
593bf215546Sopenharmony_ci   assert(nir_intr_src_is_const(intr, 0));
594bf215546Sopenharmony_ci
595bf215546Sopenharmony_ci   assert(nir_src_num_components(intr->src[1]) == 1);
596bf215546Sopenharmony_ci   assert(nir_src_bit_size(intr->src[1]) == 32);
597bf215546Sopenharmony_ci   assert(nir_intr_src_is_const(intr, 1));
598bf215546Sopenharmony_ci
599bf215546Sopenharmony_ci   /* Intrinsic index validation. */
600bf215546Sopenharmony_ci   assert((nir_intrinsic_range_base(intr) % ROGUE_REG_SIZE_BYTES) == 0);
601bf215546Sopenharmony_ci   assert(nir_intrinsic_range(intr) == ROGUE_REG_SIZE_BYTES);
602bf215546Sopenharmony_ci
603bf215546Sopenharmony_ci   size_t nir_dest_reg = nir_intr_dest_regindex(intr);
604bf215546Sopenharmony_ci
605bf215546Sopenharmony_ci   size_t desc_set = nir_intr_src_comp_const(intr, 0, 0);
606bf215546Sopenharmony_ci   size_t binding = nir_intr_src_comp_const(intr, 0, 1);
607bf215546Sopenharmony_ci   size_t offset = nir_intrinsic_range_base(intr);
608bf215546Sopenharmony_ci
609bf215546Sopenharmony_ci   size_t sh_num = rogue_ubo_reg(ubo_data, desc_set, binding, offset);
610bf215546Sopenharmony_ci
611bf215546Sopenharmony_ci   struct rogue_instr *instr = rogue_shader_insert(shader, ROGUE_OP_MOV);
612bf215546Sopenharmony_ci
613bf215546Sopenharmony_ci   CHECK(rogue_instr_set_operand_vreg(instr, 0, nir_dest_reg));
614bf215546Sopenharmony_ci   CHECK(rogue_instr_set_operand_reg(instr,
615bf215546Sopenharmony_ci                                     1,
616bf215546Sopenharmony_ci                                     ROGUE_OPERAND_TYPE_REG_SHARED,
617bf215546Sopenharmony_ci                                     sh_num));
618bf215546Sopenharmony_ci   return true;
619bf215546Sopenharmony_ci}
620bf215546Sopenharmony_ci
621bf215546Sopenharmony_cistatic bool trans_nir_intrinsic(struct rogue_shader *shader,
622bf215546Sopenharmony_ci                                nir_intrinsic_instr *intr)
623bf215546Sopenharmony_ci{
624bf215546Sopenharmony_ci   switch (intr->intrinsic) {
625bf215546Sopenharmony_ci   case nir_intrinsic_load_input:
626bf215546Sopenharmony_ci      return trans_nir_intrinsic_load_input(shader, intr);
627bf215546Sopenharmony_ci
628bf215546Sopenharmony_ci   case nir_intrinsic_store_output:
629bf215546Sopenharmony_ci      return trans_nir_intrinsic_store_output(shader, intr);
630bf215546Sopenharmony_ci
631bf215546Sopenharmony_ci   case nir_intrinsic_load_ubo:
632bf215546Sopenharmony_ci      return trans_nir_intrinsic_load_ubo(shader, intr);
633bf215546Sopenharmony_ci
634bf215546Sopenharmony_ci   default:
635bf215546Sopenharmony_ci      break;
636bf215546Sopenharmony_ci   }
637bf215546Sopenharmony_ci
638bf215546Sopenharmony_ci   unreachable("Unimplemented NIR intrinsic instruction.");
639bf215546Sopenharmony_ci}
640bf215546Sopenharmony_ci
641bf215546Sopenharmony_cistatic bool trans_nir_load_const(struct rogue_shader *shader,
642bf215546Sopenharmony_ci                                 nir_load_const_instr *load_const)
643bf215546Sopenharmony_ci{
644bf215546Sopenharmony_ci   /* Src/dest validation. */
645bf215546Sopenharmony_ci   assert(load_const->def.bit_size == 32);
646bf215546Sopenharmony_ci
647bf215546Sopenharmony_ci   /* Ensure that two-component load_consts are used only by load_ubos. */
648bf215546Sopenharmony_ci   if (load_const->def.num_components == 2) {
649bf215546Sopenharmony_ci      nir_foreach_use (use_src, &load_const->def) {
650bf215546Sopenharmony_ci         nir_instr *instr = use_src->parent_instr;
651bf215546Sopenharmony_ci         assert(instr->type == nir_instr_type_intrinsic);
652bf215546Sopenharmony_ci
653bf215546Sopenharmony_ci         ASSERTED nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
654bf215546Sopenharmony_ci         assert(intr->intrinsic == nir_intrinsic_load_ubo);
655bf215546Sopenharmony_ci      }
656bf215546Sopenharmony_ci   } else {
657bf215546Sopenharmony_ci      assert(load_const->def.num_components == 1);
658bf215546Sopenharmony_ci   }
659bf215546Sopenharmony_ci
660bf215546Sopenharmony_ci   /* TODO: This is currently done in MOV_IMM, but instead now would be the
661bf215546Sopenharmony_ci    * time to lookup the constant value, see if it lives in const regs, or if
662bf215546Sopenharmony_ci    * it needs to generate a MOV_IMM (or be constant calc-ed).
663bf215546Sopenharmony_ci    */
664bf215546Sopenharmony_ci   return true;
665bf215546Sopenharmony_ci}
666bf215546Sopenharmony_ci
667bf215546Sopenharmony_cistatic bool trans_nir_jump_return(struct rogue_shader *shader,
668bf215546Sopenharmony_ci                                  nir_jump_instr *jump)
669bf215546Sopenharmony_ci{
670bf215546Sopenharmony_ci   enum rogue_opcode return_op;
671bf215546Sopenharmony_ci
672bf215546Sopenharmony_ci   switch (shader->stage) {
673bf215546Sopenharmony_ci   case MESA_SHADER_FRAGMENT:
674bf215546Sopenharmony_ci      return_op = ROGUE_OP_END_FRAG;
675bf215546Sopenharmony_ci      break;
676bf215546Sopenharmony_ci
677bf215546Sopenharmony_ci   case MESA_SHADER_VERTEX:
678bf215546Sopenharmony_ci      return_op = ROGUE_OP_END_VERT;
679bf215546Sopenharmony_ci      break;
680bf215546Sopenharmony_ci
681bf215546Sopenharmony_ci   default:
682bf215546Sopenharmony_ci      unreachable("Unimplemented NIR return instruction type.");
683bf215546Sopenharmony_ci   }
684bf215546Sopenharmony_ci
685bf215546Sopenharmony_ci   rogue_shader_insert(shader, return_op);
686bf215546Sopenharmony_ci
687bf215546Sopenharmony_ci   return true;
688bf215546Sopenharmony_ci}
689bf215546Sopenharmony_ci
690bf215546Sopenharmony_cistatic bool trans_nir_jump(struct rogue_shader *shader, nir_jump_instr *jump)
691bf215546Sopenharmony_ci{
692bf215546Sopenharmony_ci   switch (jump->type) {
693bf215546Sopenharmony_ci   case nir_jump_return:
694bf215546Sopenharmony_ci      return trans_nir_jump_return(shader, jump);
695bf215546Sopenharmony_ci
696bf215546Sopenharmony_ci   default:
697bf215546Sopenharmony_ci      break;
698bf215546Sopenharmony_ci   }
699bf215546Sopenharmony_ci
700bf215546Sopenharmony_ci   unreachable("Unimplemented NIR jump instruction type.");
701bf215546Sopenharmony_ci}
702bf215546Sopenharmony_ci
703bf215546Sopenharmony_ci/**
704bf215546Sopenharmony_ci * \brief Converts a NIR shader to Rogue.
705bf215546Sopenharmony_ci *
706bf215546Sopenharmony_ci * \param[in] ctx Shared multi-stage build context.
707bf215546Sopenharmony_ci * \param[in] nir NIR shader.
708bf215546Sopenharmony_ci * \return A rogue_shader* if successful, or NULL if unsuccessful.
709bf215546Sopenharmony_ci */
710bf215546Sopenharmony_cistruct rogue_shader *rogue_nir_to_rogue(struct rogue_build_ctx *ctx,
711bf215546Sopenharmony_ci                                        const nir_shader *nir)
712bf215546Sopenharmony_ci{
713bf215546Sopenharmony_ci   gl_shader_stage stage = nir->info.stage;
714bf215546Sopenharmony_ci   struct rogue_shader *shader = rogue_shader_create(ctx, stage);
715bf215546Sopenharmony_ci   if (!shader)
716bf215546Sopenharmony_ci      return NULL;
717bf215546Sopenharmony_ci
718bf215546Sopenharmony_ci   /* Make sure we only have a single function. */
719bf215546Sopenharmony_ci   assert(exec_list_length(&nir->functions) == 1);
720bf215546Sopenharmony_ci
721bf215546Sopenharmony_ci   /* Translate shader entrypoint. */
722bf215546Sopenharmony_ci   nir_function_impl *entry = nir_shader_get_entrypoint((nir_shader *)nir);
723bf215546Sopenharmony_ci   nir_foreach_block (block, entry) {
724bf215546Sopenharmony_ci      nir_foreach_instr (instr, block) {
725bf215546Sopenharmony_ci         switch (instr->type) {
726bf215546Sopenharmony_ci         case nir_instr_type_alu:
727bf215546Sopenharmony_ci            /* TODO: Cleanup on failure. */
728bf215546Sopenharmony_ci            CHECKF(trans_nir_alu(shader, nir_instr_as_alu(instr)),
729bf215546Sopenharmony_ci                   "Failed to translate NIR ALU instruction.");
730bf215546Sopenharmony_ci            break;
731bf215546Sopenharmony_ci
732bf215546Sopenharmony_ci         case nir_instr_type_intrinsic:
733bf215546Sopenharmony_ci            CHECKF(trans_nir_intrinsic(shader, nir_instr_as_intrinsic(instr)),
734bf215546Sopenharmony_ci                   "Failed to translate NIR intrinsic instruction.");
735bf215546Sopenharmony_ci            break;
736bf215546Sopenharmony_ci
737bf215546Sopenharmony_ci         case nir_instr_type_load_const:
738bf215546Sopenharmony_ci            CHECKF(trans_nir_load_const(shader, nir_instr_as_load_const(instr)),
739bf215546Sopenharmony_ci                   "Failed to translate NIR load_const instruction.");
740bf215546Sopenharmony_ci            break;
741bf215546Sopenharmony_ci
742bf215546Sopenharmony_ci         case nir_instr_type_jump:
743bf215546Sopenharmony_ci            CHECKF(trans_nir_jump(shader, nir_instr_as_jump(instr)),
744bf215546Sopenharmony_ci                   "Failed to translate NIR jump instruction.");
745bf215546Sopenharmony_ci            break;
746bf215546Sopenharmony_ci
747bf215546Sopenharmony_ci         default:
748bf215546Sopenharmony_ci            unreachable("Unimplemented NIR instruction type.");
749bf215546Sopenharmony_ci         }
750bf215546Sopenharmony_ci      }
751bf215546Sopenharmony_ci   }
752bf215546Sopenharmony_ci
753bf215546Sopenharmony_ci   /* Perform register allocation. */
754bf215546Sopenharmony_ci   /* TODO: handle failure. */
755bf215546Sopenharmony_ci   if (!rogue_ra_alloc(&shader->instr_list,
756bf215546Sopenharmony_ci                       shader->ra,
757bf215546Sopenharmony_ci                       &ctx->common_data[stage].temps,
758bf215546Sopenharmony_ci                       &ctx->common_data[stage].internals))
759bf215546Sopenharmony_ci      return NULL;
760bf215546Sopenharmony_ci
761bf215546Sopenharmony_ci   return shader;
762bf215546Sopenharmony_ci}
763bf215546Sopenharmony_ci
764bf215546Sopenharmony_ci/**
765bf215546Sopenharmony_ci * \brief Creates and sets up a shared multi-stage build context.
766bf215546Sopenharmony_ci *
767bf215546Sopenharmony_ci * \param[in] compiler The compiler context.
768bf215546Sopenharmony_ci * \return A pointer to the new build context, or NULL on failure.
769bf215546Sopenharmony_ci */
770bf215546Sopenharmony_cistruct rogue_build_ctx *
771bf215546Sopenharmony_cirogue_create_build_context(struct rogue_compiler *compiler)
772bf215546Sopenharmony_ci{
773bf215546Sopenharmony_ci   struct rogue_build_ctx *ctx;
774bf215546Sopenharmony_ci
775bf215546Sopenharmony_ci   ctx = rzalloc_size(compiler, sizeof(*ctx));
776bf215546Sopenharmony_ci   if (!ctx)
777bf215546Sopenharmony_ci      return NULL;
778bf215546Sopenharmony_ci
779bf215546Sopenharmony_ci   ctx->compiler = compiler;
780bf215546Sopenharmony_ci
781bf215546Sopenharmony_ci   /* nir/rogue/binary shaders need to be default-zeroed;
782bf215546Sopenharmony_ci    * this is taken care of by rzalloc_size.
783bf215546Sopenharmony_ci    */
784bf215546Sopenharmony_ci
785bf215546Sopenharmony_ci   /* Setup non-zero defaults. */
786bf215546Sopenharmony_ci   ctx->stage_data.fs.msaa_mode = ROGUE_MSAA_MODE_PIXEL;
787bf215546Sopenharmony_ci
788bf215546Sopenharmony_ci   return ctx;
789bf215546Sopenharmony_ci}
790