17ec681f3Smrg/*
27ec681f3Smrg * Copyright © Microsoft Corporation
37ec681f3Smrg *
47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
57ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
67ec681f3Smrg * to deal in the Software without restriction, including without limitation
77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
97ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
107ec681f3Smrg *
117ec681f3Smrg * The above copyright notice and this permission notice (including the next
127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
137ec681f3Smrg * Software.
147ec681f3Smrg *
157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
207ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
217ec681f3Smrg * IN THE SOFTWARE.
227ec681f3Smrg */
237ec681f3Smrg
247ec681f3Smrg#include "nir_to_dxil.h"
257ec681f3Smrg
267ec681f3Smrg#include "dxil_container.h"
277ec681f3Smrg#include "dxil_dump.h"
287ec681f3Smrg#include "dxil_enums.h"
297ec681f3Smrg#include "dxil_function.h"
307ec681f3Smrg#include "dxil_module.h"
317ec681f3Smrg#include "dxil_nir.h"
327ec681f3Smrg#include "dxil_signature.h"
337ec681f3Smrg
347ec681f3Smrg#include "nir/nir_builder.h"
357ec681f3Smrg#include "util/u_debug.h"
367ec681f3Smrg#include "util/u_dynarray.h"
377ec681f3Smrg#include "util/u_math.h"
387ec681f3Smrg
397ec681f3Smrg#include "git_sha1.h"
407ec681f3Smrg
417ec681f3Smrg#include "vulkan/vulkan_core.h"
427ec681f3Smrg
437ec681f3Smrg#include <stdint.h>
447ec681f3Smrg
457ec681f3Smrgint debug_dxil = 0;
467ec681f3Smrg
477ec681f3Smrgstatic const struct debug_named_value
487ec681f3Smrgdxil_debug_options[] = {
497ec681f3Smrg   { "verbose", DXIL_DEBUG_VERBOSE, NULL },
507ec681f3Smrg   { "dump_blob",  DXIL_DEBUG_DUMP_BLOB , "Write shader blobs" },
517ec681f3Smrg   { "trace",  DXIL_DEBUG_TRACE , "Trace instruction conversion" },
527ec681f3Smrg   { "dump_module", DXIL_DEBUG_DUMP_MODULE, "dump module tree to stderr"},
537ec681f3Smrg   DEBUG_NAMED_VALUE_END
547ec681f3Smrg};
557ec681f3Smrg
567ec681f3SmrgDEBUG_GET_ONCE_FLAGS_OPTION(debug_dxil, "DXIL_DEBUG", dxil_debug_options, 0)
577ec681f3Smrg
587ec681f3Smrg#define NIR_INSTR_UNSUPPORTED(instr) \
597ec681f3Smrg   if (debug_dxil & DXIL_DEBUG_VERBOSE) \
607ec681f3Smrg   do { \
617ec681f3Smrg      fprintf(stderr, "Unsupported instruction:"); \
627ec681f3Smrg      nir_print_instr(instr, stderr); \
637ec681f3Smrg      fprintf(stderr, "\n"); \
647ec681f3Smrg   } while (0)
657ec681f3Smrg
667ec681f3Smrg#define TRACE_CONVERSION(instr) \
677ec681f3Smrg   if (debug_dxil & DXIL_DEBUG_TRACE) \
687ec681f3Smrg      do { \
697ec681f3Smrg         fprintf(stderr, "Convert '"); \
707ec681f3Smrg         nir_print_instr(instr, stderr); \
717ec681f3Smrg         fprintf(stderr, "'\n"); \
727ec681f3Smrg      } while (0)
737ec681f3Smrg
747ec681f3Smrgstatic const nir_shader_compiler_options
757ec681f3Smrgnir_options = {
767ec681f3Smrg   .lower_ineg = true,
777ec681f3Smrg   .lower_fneg = true,
787ec681f3Smrg   .lower_ffma16 = true,
797ec681f3Smrg   .lower_ffma32 = true,
807ec681f3Smrg   .lower_isign = true,
817ec681f3Smrg   .lower_fsign = true,
827ec681f3Smrg   .lower_iabs = true,
837ec681f3Smrg   .lower_fmod = true,
847ec681f3Smrg   .lower_fpow = true,
857ec681f3Smrg   .lower_scmp = true,
867ec681f3Smrg   .lower_ldexp = true,
877ec681f3Smrg   .lower_flrp16 = true,
887ec681f3Smrg   .lower_flrp32 = true,
897ec681f3Smrg   .lower_flrp64 = true,
907ec681f3Smrg   .lower_bitfield_extract_to_shifts = true,
917ec681f3Smrg   .lower_extract_word = true,
927ec681f3Smrg   .lower_extract_byte = true,
937ec681f3Smrg   .lower_insert_word = true,
947ec681f3Smrg   .lower_insert_byte = true,
957ec681f3Smrg   .lower_all_io_to_elements = true,
967ec681f3Smrg   .lower_all_io_to_temps = true,
977ec681f3Smrg   .lower_hadd = true,
987ec681f3Smrg   .lower_uadd_sat = true,
997ec681f3Smrg   .lower_iadd_sat = true,
1007ec681f3Smrg   .lower_uadd_carry = true,
1017ec681f3Smrg   .lower_mul_high = true,
1027ec681f3Smrg   .lower_rotate = true,
1037ec681f3Smrg   .lower_pack_64_2x32_split = true,
1047ec681f3Smrg   .lower_pack_32_2x16_split = true,
1057ec681f3Smrg   .lower_unpack_64_2x32_split = true,
1067ec681f3Smrg   .lower_unpack_32_2x16_split = true,
1077ec681f3Smrg   .has_fsub = true,
1087ec681f3Smrg   .has_isub = true,
1097ec681f3Smrg   .use_scoped_barrier = true,
1107ec681f3Smrg   .vertex_id_zero_based = true,
1117ec681f3Smrg   .lower_base_vertex = true,
1127ec681f3Smrg   .has_cs_global_id = true,
1137ec681f3Smrg   .has_txs = true,
1147ec681f3Smrg};
1157ec681f3Smrg
1167ec681f3Smrgconst nir_shader_compiler_options*
1177ec681f3Smrgdxil_get_nir_compiler_options(void)
1187ec681f3Smrg{
1197ec681f3Smrg   return &nir_options;
1207ec681f3Smrg}
1217ec681f3Smrg
1227ec681f3Smrgstatic bool
1237ec681f3Smrgemit_llvm_ident(struct dxil_module *m)
1247ec681f3Smrg{
1257ec681f3Smrg   const struct dxil_mdnode *compiler = dxil_get_metadata_string(m, "Mesa version " PACKAGE_VERSION MESA_GIT_SHA1);
1267ec681f3Smrg   if (!compiler)
1277ec681f3Smrg      return false;
1287ec681f3Smrg
1297ec681f3Smrg   const struct dxil_mdnode *llvm_ident = dxil_get_metadata_node(m, &compiler, 1);
1307ec681f3Smrg   return llvm_ident &&
1317ec681f3Smrg          dxil_add_metadata_named_node(m, "llvm.ident", &llvm_ident, 1);
1327ec681f3Smrg}
1337ec681f3Smrg
1347ec681f3Smrgstatic bool
1357ec681f3Smrgemit_named_version(struct dxil_module *m, const char *name,
1367ec681f3Smrg                   int major, int minor)
1377ec681f3Smrg{
1387ec681f3Smrg   const struct dxil_mdnode *major_node = dxil_get_metadata_int32(m, major);
1397ec681f3Smrg   const struct dxil_mdnode *minor_node = dxil_get_metadata_int32(m, minor);
1407ec681f3Smrg   const struct dxil_mdnode *version_nodes[] = { major_node, minor_node };
1417ec681f3Smrg   const struct dxil_mdnode *version = dxil_get_metadata_node(m, version_nodes,
1427ec681f3Smrg                                                     ARRAY_SIZE(version_nodes));
1437ec681f3Smrg   return dxil_add_metadata_named_node(m, name, &version, 1);
1447ec681f3Smrg}
1457ec681f3Smrg
1467ec681f3Smrgstatic const char *
1477ec681f3Smrgget_shader_kind_str(enum dxil_shader_kind kind)
1487ec681f3Smrg{
1497ec681f3Smrg   switch (kind) {
1507ec681f3Smrg   case DXIL_PIXEL_SHADER:
1517ec681f3Smrg      return "ps";
1527ec681f3Smrg   case DXIL_VERTEX_SHADER:
1537ec681f3Smrg      return "vs";
1547ec681f3Smrg   case DXIL_GEOMETRY_SHADER:
1557ec681f3Smrg      return "gs";
1567ec681f3Smrg   case DXIL_HULL_SHADER:
1577ec681f3Smrg      return "hs";
1587ec681f3Smrg   case DXIL_DOMAIN_SHADER:
1597ec681f3Smrg      return "ds";
1607ec681f3Smrg   case DXIL_COMPUTE_SHADER:
1617ec681f3Smrg      return "cs";
1627ec681f3Smrg   default:
1637ec681f3Smrg      unreachable("invalid shader kind");
1647ec681f3Smrg   }
1657ec681f3Smrg}
1667ec681f3Smrg
1677ec681f3Smrgstatic bool
1687ec681f3Smrgemit_dx_shader_model(struct dxil_module *m)
1697ec681f3Smrg{
1707ec681f3Smrg   const struct dxil_mdnode *type_node = dxil_get_metadata_string(m, get_shader_kind_str(m->shader_kind));
1717ec681f3Smrg   const struct dxil_mdnode *major_node = dxil_get_metadata_int32(m, m->major_version);
1727ec681f3Smrg   const struct dxil_mdnode *minor_node = dxil_get_metadata_int32(m, m->minor_version);
1737ec681f3Smrg   const struct dxil_mdnode *shader_model[] = { type_node, major_node,
1747ec681f3Smrg                                                minor_node };
1757ec681f3Smrg   const struct dxil_mdnode *dx_shader_model = dxil_get_metadata_node(m, shader_model, ARRAY_SIZE(shader_model));
1767ec681f3Smrg
1777ec681f3Smrg   return dxil_add_metadata_named_node(m, "dx.shaderModel",
1787ec681f3Smrg                                       &dx_shader_model, 1);
1797ec681f3Smrg}
1807ec681f3Smrg
1817ec681f3Smrgenum {
1827ec681f3Smrg   DXIL_TYPED_BUFFER_ELEMENT_TYPE_TAG = 0,
1837ec681f3Smrg   DXIL_STRUCTURED_BUFFER_ELEMENT_STRIDE_TAG = 1
1847ec681f3Smrg};
1857ec681f3Smrg
1867ec681f3Smrgenum dxil_intr {
1877ec681f3Smrg   DXIL_INTR_LOAD_INPUT = 4,
1887ec681f3Smrg   DXIL_INTR_STORE_OUTPUT = 5,
1897ec681f3Smrg   DXIL_INTR_FABS = 6,
1907ec681f3Smrg   DXIL_INTR_SATURATE = 7,
1917ec681f3Smrg
1927ec681f3Smrg   DXIL_INTR_ISFINITE = 10,
1937ec681f3Smrg   DXIL_INTR_ISNORMAL = 11,
1947ec681f3Smrg
1957ec681f3Smrg   DXIL_INTR_FCOS = 12,
1967ec681f3Smrg   DXIL_INTR_FSIN = 13,
1977ec681f3Smrg
1987ec681f3Smrg   DXIL_INTR_FEXP2 = 21,
1997ec681f3Smrg   DXIL_INTR_FRC = 22,
2007ec681f3Smrg   DXIL_INTR_FLOG2 = 23,
2017ec681f3Smrg
2027ec681f3Smrg   DXIL_INTR_SQRT = 24,
2037ec681f3Smrg   DXIL_INTR_RSQRT = 25,
2047ec681f3Smrg   DXIL_INTR_ROUND_NE = 26,
2057ec681f3Smrg   DXIL_INTR_ROUND_NI = 27,
2067ec681f3Smrg   DXIL_INTR_ROUND_PI = 28,
2077ec681f3Smrg   DXIL_INTR_ROUND_Z = 29,
2087ec681f3Smrg
2097ec681f3Smrg   DXIL_INTR_COUNTBITS = 31,
2107ec681f3Smrg   DXIL_INTR_FIRSTBIT_HI = 33,
2117ec681f3Smrg
2127ec681f3Smrg   DXIL_INTR_FMAX = 35,
2137ec681f3Smrg   DXIL_INTR_FMIN = 36,
2147ec681f3Smrg   DXIL_INTR_IMAX = 37,
2157ec681f3Smrg   DXIL_INTR_IMIN = 38,
2167ec681f3Smrg   DXIL_INTR_UMAX = 39,
2177ec681f3Smrg   DXIL_INTR_UMIN = 40,
2187ec681f3Smrg
2197ec681f3Smrg   DXIL_INTR_FMA = 47,
2207ec681f3Smrg
2217ec681f3Smrg   DXIL_INTR_CREATE_HANDLE = 57,
2227ec681f3Smrg   DXIL_INTR_CBUFFER_LOAD_LEGACY = 59,
2237ec681f3Smrg
2247ec681f3Smrg   DXIL_INTR_SAMPLE = 60,
2257ec681f3Smrg   DXIL_INTR_SAMPLE_BIAS = 61,
2267ec681f3Smrg   DXIL_INTR_SAMPLE_LEVEL = 62,
2277ec681f3Smrg   DXIL_INTR_SAMPLE_GRAD = 63,
2287ec681f3Smrg   DXIL_INTR_SAMPLE_CMP = 64,
2297ec681f3Smrg   DXIL_INTR_SAMPLE_CMP_LVL_ZERO = 65,
2307ec681f3Smrg
2317ec681f3Smrg   DXIL_INTR_TEXTURE_LOAD = 66,
2327ec681f3Smrg   DXIL_INTR_TEXTURE_STORE = 67,
2337ec681f3Smrg
2347ec681f3Smrg   DXIL_INTR_BUFFER_LOAD = 68,
2357ec681f3Smrg   DXIL_INTR_BUFFER_STORE = 69,
2367ec681f3Smrg
2377ec681f3Smrg   DXIL_INTR_TEXTURE_SIZE = 72,
2387ec681f3Smrg
2397ec681f3Smrg   DXIL_INTR_ATOMIC_BINOP = 78,
2407ec681f3Smrg   DXIL_INTR_ATOMIC_CMPXCHG = 79,
2417ec681f3Smrg   DXIL_INTR_BARRIER = 80,
2427ec681f3Smrg   DXIL_INTR_TEXTURE_LOD = 81,
2437ec681f3Smrg
2447ec681f3Smrg   DXIL_INTR_DISCARD = 82,
2457ec681f3Smrg   DXIL_INTR_DDX_COARSE = 83,
2467ec681f3Smrg   DXIL_INTR_DDY_COARSE = 84,
2477ec681f3Smrg   DXIL_INTR_DDX_FINE = 85,
2487ec681f3Smrg   DXIL_INTR_DDY_FINE = 86,
2497ec681f3Smrg
2507ec681f3Smrg   DXIL_INTR_SAMPLE_INDEX = 90,
2517ec681f3Smrg
2527ec681f3Smrg   DXIL_INTR_THREAD_ID = 93,
2537ec681f3Smrg   DXIL_INTR_GROUP_ID = 94,
2547ec681f3Smrg   DXIL_INTR_THREAD_ID_IN_GROUP = 95,
2557ec681f3Smrg   DXIL_INTR_FLATTENED_THREAD_ID_IN_GROUP = 96,
2567ec681f3Smrg
2577ec681f3Smrg   DXIL_INTR_EMIT_STREAM = 97,
2587ec681f3Smrg   DXIL_INTR_CUT_STREAM = 98,
2597ec681f3Smrg
2607ec681f3Smrg   DXIL_INTR_MAKE_DOUBLE = 101,
2617ec681f3Smrg   DXIL_INTR_SPLIT_DOUBLE = 102,
2627ec681f3Smrg
2637ec681f3Smrg   DXIL_INTR_PRIMITIVE_ID = 108,
2647ec681f3Smrg
2657ec681f3Smrg   DXIL_INTR_LEGACY_F32TOF16 = 130,
2667ec681f3Smrg   DXIL_INTR_LEGACY_F16TOF32 = 131,
2677ec681f3Smrg
2687ec681f3Smrg   DXIL_INTR_ATTRIBUTE_AT_VERTEX = 137,
2697ec681f3Smrg};
2707ec681f3Smrg
2717ec681f3Smrgenum dxil_atomic_op {
2727ec681f3Smrg   DXIL_ATOMIC_ADD = 0,
2737ec681f3Smrg   DXIL_ATOMIC_AND = 1,
2747ec681f3Smrg   DXIL_ATOMIC_OR = 2,
2757ec681f3Smrg   DXIL_ATOMIC_XOR = 3,
2767ec681f3Smrg   DXIL_ATOMIC_IMIN = 4,
2777ec681f3Smrg   DXIL_ATOMIC_IMAX = 5,
2787ec681f3Smrg   DXIL_ATOMIC_UMIN = 6,
2797ec681f3Smrg   DXIL_ATOMIC_UMAX = 7,
2807ec681f3Smrg   DXIL_ATOMIC_EXCHANGE = 8,
2817ec681f3Smrg};
2827ec681f3Smrg
2837ec681f3Smrgtypedef struct {
2847ec681f3Smrg   unsigned id;
2857ec681f3Smrg   unsigned binding;
2867ec681f3Smrg   unsigned size;
2877ec681f3Smrg   unsigned space;
2887ec681f3Smrg} resource_array_layout;
2897ec681f3Smrg
2907ec681f3Smrgstatic void
2917ec681f3Smrgfill_resource_metadata(struct dxil_module *m, const struct dxil_mdnode **fields,
2927ec681f3Smrg                       const struct dxil_type *struct_type,
2937ec681f3Smrg                       const char *name, const resource_array_layout *layout)
2947ec681f3Smrg{
2957ec681f3Smrg   const struct dxil_type *pointer_type = dxil_module_get_pointer_type(m, struct_type);
2967ec681f3Smrg   const struct dxil_value *pointer_undef = dxil_module_get_undef(m, pointer_type);
2977ec681f3Smrg
2987ec681f3Smrg   fields[0] = dxil_get_metadata_int32(m, layout->id); // resource ID
2997ec681f3Smrg   fields[1] = dxil_get_metadata_value(m, pointer_type, pointer_undef); // global constant symbol
3007ec681f3Smrg   fields[2] = dxil_get_metadata_string(m, name ? name : ""); // name
3017ec681f3Smrg   fields[3] = dxil_get_metadata_int32(m, layout->space); // space ID
3027ec681f3Smrg   fields[4] = dxil_get_metadata_int32(m, layout->binding); // lower bound
3037ec681f3Smrg   fields[5] = dxil_get_metadata_int32(m, layout->size); // range size
3047ec681f3Smrg}
3057ec681f3Smrg
3067ec681f3Smrgstatic const struct dxil_mdnode *
3077ec681f3Smrgemit_srv_metadata(struct dxil_module *m, const struct dxil_type *elem_type,
3087ec681f3Smrg                  const char *name, const resource_array_layout *layout,
3097ec681f3Smrg                  enum dxil_component_type comp_type,
3107ec681f3Smrg                  enum dxil_resource_kind res_kind)
3117ec681f3Smrg{
3127ec681f3Smrg   const struct dxil_mdnode *fields[9];
3137ec681f3Smrg
3147ec681f3Smrg   const struct dxil_mdnode *metadata_tag_nodes[2];
3157ec681f3Smrg
3167ec681f3Smrg   fill_resource_metadata(m, fields, elem_type, name, layout);
3177ec681f3Smrg   fields[6] = dxil_get_metadata_int32(m, res_kind); // resource shape
3187ec681f3Smrg   fields[7] = dxil_get_metadata_int1(m, 0); // sample count
3197ec681f3Smrg   if (res_kind != DXIL_RESOURCE_KIND_RAW_BUFFER &&
3207ec681f3Smrg       res_kind != DXIL_RESOURCE_KIND_STRUCTURED_BUFFER) {
3217ec681f3Smrg      metadata_tag_nodes[0] = dxil_get_metadata_int32(m, DXIL_TYPED_BUFFER_ELEMENT_TYPE_TAG);
3227ec681f3Smrg      metadata_tag_nodes[1] = dxil_get_metadata_int32(m, comp_type);
3237ec681f3Smrg      fields[8] = dxil_get_metadata_node(m, metadata_tag_nodes, ARRAY_SIZE(metadata_tag_nodes)); // metadata
3247ec681f3Smrg   } else if (res_kind == DXIL_RESOURCE_KIND_RAW_BUFFER)
3257ec681f3Smrg      fields[8] = NULL;
3267ec681f3Smrg   else
3277ec681f3Smrg      unreachable("Structured buffers not supported yet");
3287ec681f3Smrg
3297ec681f3Smrg   return dxil_get_metadata_node(m, fields, ARRAY_SIZE(fields));
3307ec681f3Smrg}
3317ec681f3Smrg
3327ec681f3Smrgstatic const struct dxil_mdnode *
3337ec681f3Smrgemit_uav_metadata(struct dxil_module *m, const struct dxil_type *struct_type,
3347ec681f3Smrg                  const char *name, const resource_array_layout *layout,
3357ec681f3Smrg                  enum dxil_component_type comp_type,
3367ec681f3Smrg                  enum dxil_resource_kind res_kind)
3377ec681f3Smrg{
3387ec681f3Smrg   const struct dxil_mdnode *fields[11];
3397ec681f3Smrg
3407ec681f3Smrg   const struct dxil_mdnode *metadata_tag_nodes[2];
3417ec681f3Smrg
3427ec681f3Smrg   fill_resource_metadata(m, fields, struct_type, name, layout);
3437ec681f3Smrg   fields[6] = dxil_get_metadata_int32(m, res_kind); // resource shape
3447ec681f3Smrg   fields[7] = dxil_get_metadata_int1(m, false); // globally-coherent
3457ec681f3Smrg   fields[8] = dxil_get_metadata_int1(m, false); // has counter
3467ec681f3Smrg   fields[9] = dxil_get_metadata_int1(m, false); // is ROV
3477ec681f3Smrg   if (res_kind != DXIL_RESOURCE_KIND_RAW_BUFFER &&
3487ec681f3Smrg       res_kind != DXIL_RESOURCE_KIND_STRUCTURED_BUFFER) {
3497ec681f3Smrg      metadata_tag_nodes[0] = dxil_get_metadata_int32(m, DXIL_TYPED_BUFFER_ELEMENT_TYPE_TAG);
3507ec681f3Smrg      metadata_tag_nodes[1] = dxil_get_metadata_int32(m, comp_type);
3517ec681f3Smrg      fields[10] = dxil_get_metadata_node(m, metadata_tag_nodes, ARRAY_SIZE(metadata_tag_nodes)); // metadata
3527ec681f3Smrg   } else if (res_kind == DXIL_RESOURCE_KIND_RAW_BUFFER)
3537ec681f3Smrg      fields[10] = NULL;
3547ec681f3Smrg   else
3557ec681f3Smrg      unreachable("Structured buffers not supported yet");
3567ec681f3Smrg
3577ec681f3Smrg   return dxil_get_metadata_node(m, fields, ARRAY_SIZE(fields));
3587ec681f3Smrg}
3597ec681f3Smrg
3607ec681f3Smrgstatic const struct dxil_mdnode *
3617ec681f3Smrgemit_cbv_metadata(struct dxil_module *m, const struct dxil_type *struct_type,
3627ec681f3Smrg                  const char *name, const resource_array_layout *layout,
3637ec681f3Smrg                  unsigned size)
3647ec681f3Smrg{
3657ec681f3Smrg   const struct dxil_mdnode *fields[8];
3667ec681f3Smrg
3677ec681f3Smrg   fill_resource_metadata(m, fields, struct_type, name, layout);
3687ec681f3Smrg   fields[6] = dxil_get_metadata_int32(m, size); // constant buffer size
3697ec681f3Smrg   fields[7] = NULL; // metadata
3707ec681f3Smrg
3717ec681f3Smrg   return dxil_get_metadata_node(m, fields, ARRAY_SIZE(fields));
3727ec681f3Smrg}
3737ec681f3Smrg
3747ec681f3Smrgstatic const struct dxil_mdnode *
3757ec681f3Smrgemit_sampler_metadata(struct dxil_module *m, const struct dxil_type *struct_type,
3767ec681f3Smrg                      nir_variable *var, const resource_array_layout *layout)
3777ec681f3Smrg{
3787ec681f3Smrg   const struct dxil_mdnode *fields[8];
3797ec681f3Smrg   const struct glsl_type *type = glsl_without_array(var->type);
3807ec681f3Smrg
3817ec681f3Smrg   fill_resource_metadata(m, fields, struct_type, var->name, layout);
3827ec681f3Smrg   fields[6] = dxil_get_metadata_int32(m, DXIL_SAMPLER_KIND_DEFAULT); // sampler kind
3837ec681f3Smrg   enum dxil_sampler_kind sampler_kind = glsl_sampler_type_is_shadow(type) ?
3847ec681f3Smrg          DXIL_SAMPLER_KIND_COMPARISON : DXIL_SAMPLER_KIND_DEFAULT;
3857ec681f3Smrg   fields[6] = dxil_get_metadata_int32(m, sampler_kind); // sampler kind
3867ec681f3Smrg   fields[7] = NULL; // metadata
3877ec681f3Smrg
3887ec681f3Smrg   return dxil_get_metadata_node(m, fields, ARRAY_SIZE(fields));
3897ec681f3Smrg}
3907ec681f3Smrg
3917ec681f3Smrg
3927ec681f3Smrg#define MAX_SRVS 128
3937ec681f3Smrg#define MAX_UAVS 64
3947ec681f3Smrg#define MAX_CBVS 64 // ??
3957ec681f3Smrg#define MAX_SAMPLERS 64 // ??
3967ec681f3Smrg
3977ec681f3Smrgstruct dxil_def {
3987ec681f3Smrg   const struct dxil_value *chans[NIR_MAX_VEC_COMPONENTS];
3997ec681f3Smrg};
4007ec681f3Smrg
4017ec681f3Smrgstruct ntd_context {
4027ec681f3Smrg   void *ralloc_ctx;
4037ec681f3Smrg   const struct nir_to_dxil_options *opts;
4047ec681f3Smrg   struct nir_shader *shader;
4057ec681f3Smrg
4067ec681f3Smrg   struct dxil_module mod;
4077ec681f3Smrg
4087ec681f3Smrg   struct util_dynarray srv_metadata_nodes;
4097ec681f3Smrg   const struct dxil_value *srv_handles[MAX_SRVS];
4107ec681f3Smrg
4117ec681f3Smrg   struct util_dynarray uav_metadata_nodes;
4127ec681f3Smrg   const struct dxil_value *uav_handles[MAX_UAVS];
4137ec681f3Smrg
4147ec681f3Smrg   struct util_dynarray cbv_metadata_nodes;
4157ec681f3Smrg   const struct dxil_value *cbv_handles[MAX_CBVS];
4167ec681f3Smrg
4177ec681f3Smrg   struct util_dynarray sampler_metadata_nodes;
4187ec681f3Smrg   const struct dxil_value *sampler_handles[MAX_SAMPLERS];
4197ec681f3Smrg
4207ec681f3Smrg   struct util_dynarray resources;
4217ec681f3Smrg
4227ec681f3Smrg   const struct dxil_mdnode *shader_property_nodes[6];
4237ec681f3Smrg   size_t num_shader_property_nodes;
4247ec681f3Smrg
4257ec681f3Smrg   struct dxil_def *defs;
4267ec681f3Smrg   unsigned num_defs;
4277ec681f3Smrg   struct hash_table *phis;
4287ec681f3Smrg
4297ec681f3Smrg   const struct dxil_value *sharedvars;
4307ec681f3Smrg   const struct dxil_value *scratchvars;
4317ec681f3Smrg   struct hash_table *consts;
4327ec681f3Smrg
4337ec681f3Smrg   nir_variable *ps_front_face;
4347ec681f3Smrg   nir_variable *system_value[SYSTEM_VALUE_MAX];
4357ec681f3Smrg};
4367ec681f3Smrg
4377ec681f3Smrgstatic const char*
4387ec681f3Smrgunary_func_name(enum dxil_intr intr)
4397ec681f3Smrg{
4407ec681f3Smrg   switch (intr) {
4417ec681f3Smrg   case DXIL_INTR_COUNTBITS:
4427ec681f3Smrg   case DXIL_INTR_FIRSTBIT_HI:
4437ec681f3Smrg      return "dx.op.unaryBits";
4447ec681f3Smrg   case DXIL_INTR_ISFINITE:
4457ec681f3Smrg   case DXIL_INTR_ISNORMAL:
4467ec681f3Smrg      return "dx.op.isSpecialFloat";
4477ec681f3Smrg   default:
4487ec681f3Smrg      return "dx.op.unary";
4497ec681f3Smrg   }
4507ec681f3Smrg}
4517ec681f3Smrg
4527ec681f3Smrgstatic const struct dxil_value *
4537ec681f3Smrgemit_unary_call(struct ntd_context *ctx, enum overload_type overload,
4547ec681f3Smrg                enum dxil_intr intr,
4557ec681f3Smrg                const struct dxil_value *op0)
4567ec681f3Smrg{
4577ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod,
4587ec681f3Smrg                                                    unary_func_name(intr),
4597ec681f3Smrg                                                    overload);
4607ec681f3Smrg   if (!func)
4617ec681f3Smrg      return NULL;
4627ec681f3Smrg
4637ec681f3Smrg   const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, intr);
4647ec681f3Smrg   if (!opcode)
4657ec681f3Smrg      return NULL;
4667ec681f3Smrg
4677ec681f3Smrg   const struct dxil_value *args[] = {
4687ec681f3Smrg     opcode,
4697ec681f3Smrg     op0
4707ec681f3Smrg   };
4717ec681f3Smrg
4727ec681f3Smrg   return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args));
4737ec681f3Smrg}
4747ec681f3Smrg
4757ec681f3Smrgstatic const struct dxil_value *
4767ec681f3Smrgemit_binary_call(struct ntd_context *ctx, enum overload_type overload,
4777ec681f3Smrg                 enum dxil_intr intr,
4787ec681f3Smrg                 const struct dxil_value *op0, const struct dxil_value *op1)
4797ec681f3Smrg{
4807ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.binary", overload);
4817ec681f3Smrg   if (!func)
4827ec681f3Smrg      return NULL;
4837ec681f3Smrg
4847ec681f3Smrg   const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, intr);
4857ec681f3Smrg   if (!opcode)
4867ec681f3Smrg      return NULL;
4877ec681f3Smrg
4887ec681f3Smrg   const struct dxil_value *args[] = {
4897ec681f3Smrg     opcode,
4907ec681f3Smrg     op0,
4917ec681f3Smrg     op1
4927ec681f3Smrg   };
4937ec681f3Smrg
4947ec681f3Smrg   return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args));
4957ec681f3Smrg}
4967ec681f3Smrg
4977ec681f3Smrgstatic const struct dxil_value *
4987ec681f3Smrgemit_tertiary_call(struct ntd_context *ctx, enum overload_type overload,
4997ec681f3Smrg                   enum dxil_intr intr,
5007ec681f3Smrg                   const struct dxil_value *op0,
5017ec681f3Smrg                   const struct dxil_value *op1,
5027ec681f3Smrg                   const struct dxil_value *op2)
5037ec681f3Smrg{
5047ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.tertiary", overload);
5057ec681f3Smrg   if (!func)
5067ec681f3Smrg      return NULL;
5077ec681f3Smrg
5087ec681f3Smrg   const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, intr);
5097ec681f3Smrg   if (!opcode)
5107ec681f3Smrg      return NULL;
5117ec681f3Smrg
5127ec681f3Smrg   const struct dxil_value *args[] = {
5137ec681f3Smrg     opcode,
5147ec681f3Smrg     op0,
5157ec681f3Smrg     op1,
5167ec681f3Smrg     op2
5177ec681f3Smrg   };
5187ec681f3Smrg
5197ec681f3Smrg   return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args));
5207ec681f3Smrg}
5217ec681f3Smrg
5227ec681f3Smrgstatic const struct dxil_value *
5237ec681f3Smrgemit_threadid_call(struct ntd_context *ctx, const struct dxil_value *comp)
5247ec681f3Smrg{
5257ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.threadId", DXIL_I32);
5267ec681f3Smrg   if (!func)
5277ec681f3Smrg      return NULL;
5287ec681f3Smrg
5297ec681f3Smrg   const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod,
5307ec681f3Smrg       DXIL_INTR_THREAD_ID);
5317ec681f3Smrg   if (!opcode)
5327ec681f3Smrg      return NULL;
5337ec681f3Smrg
5347ec681f3Smrg   const struct dxil_value *args[] = {
5357ec681f3Smrg     opcode,
5367ec681f3Smrg     comp
5377ec681f3Smrg   };
5387ec681f3Smrg
5397ec681f3Smrg   return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args));
5407ec681f3Smrg}
5417ec681f3Smrg
5427ec681f3Smrgstatic const struct dxil_value *
5437ec681f3Smrgemit_threadidingroup_call(struct ntd_context *ctx,
5447ec681f3Smrg                          const struct dxil_value *comp)
5457ec681f3Smrg{
5467ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.threadIdInGroup", DXIL_I32);
5477ec681f3Smrg
5487ec681f3Smrg   if (!func)
5497ec681f3Smrg      return NULL;
5507ec681f3Smrg
5517ec681f3Smrg   const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod,
5527ec681f3Smrg       DXIL_INTR_THREAD_ID_IN_GROUP);
5537ec681f3Smrg   if (!opcode)
5547ec681f3Smrg      return NULL;
5557ec681f3Smrg
5567ec681f3Smrg   const struct dxil_value *args[] = {
5577ec681f3Smrg     opcode,
5587ec681f3Smrg     comp
5597ec681f3Smrg   };
5607ec681f3Smrg
5617ec681f3Smrg   return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args));
5627ec681f3Smrg}
5637ec681f3Smrg
5647ec681f3Smrgstatic const struct dxil_value *
5657ec681f3Smrgemit_flattenedthreadidingroup_call(struct ntd_context *ctx)
5667ec681f3Smrg{
5677ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.flattenedThreadIdInGroup", DXIL_I32);
5687ec681f3Smrg
5697ec681f3Smrg   if (!func)
5707ec681f3Smrg      return NULL;
5717ec681f3Smrg
5727ec681f3Smrg   const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod,
5737ec681f3Smrg      DXIL_INTR_FLATTENED_THREAD_ID_IN_GROUP);
5747ec681f3Smrg   if (!opcode)
5757ec681f3Smrg      return NULL;
5767ec681f3Smrg
5777ec681f3Smrg   const struct dxil_value *args[] = {
5787ec681f3Smrg     opcode
5797ec681f3Smrg   };
5807ec681f3Smrg
5817ec681f3Smrg   return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args));
5827ec681f3Smrg}
5837ec681f3Smrg
5847ec681f3Smrgstatic const struct dxil_value *
5857ec681f3Smrgemit_groupid_call(struct ntd_context *ctx, const struct dxil_value *comp)
5867ec681f3Smrg{
5877ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.groupId", DXIL_I32);
5887ec681f3Smrg
5897ec681f3Smrg   if (!func)
5907ec681f3Smrg      return NULL;
5917ec681f3Smrg
5927ec681f3Smrg   const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod,
5937ec681f3Smrg       DXIL_INTR_GROUP_ID);
5947ec681f3Smrg   if (!opcode)
5957ec681f3Smrg      return NULL;
5967ec681f3Smrg
5977ec681f3Smrg   const struct dxil_value *args[] = {
5987ec681f3Smrg     opcode,
5997ec681f3Smrg     comp
6007ec681f3Smrg   };
6017ec681f3Smrg
6027ec681f3Smrg   return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args));
6037ec681f3Smrg}
6047ec681f3Smrg
6057ec681f3Smrgstatic const struct dxil_value *
6067ec681f3Smrgemit_bufferload_call(struct ntd_context *ctx,
6077ec681f3Smrg                     const struct dxil_value *handle,
6087ec681f3Smrg                     const struct dxil_value *coord[2],
6097ec681f3Smrg                     enum overload_type overload)
6107ec681f3Smrg{
6117ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.bufferLoad", overload);
6127ec681f3Smrg   if (!func)
6137ec681f3Smrg      return NULL;
6147ec681f3Smrg
6157ec681f3Smrg   const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod,
6167ec681f3Smrg      DXIL_INTR_BUFFER_LOAD);
6177ec681f3Smrg   const struct dxil_value *args[] = { opcode, handle, coord[0], coord[1] };
6187ec681f3Smrg
6197ec681f3Smrg   return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args));
6207ec681f3Smrg}
6217ec681f3Smrg
6227ec681f3Smrgstatic bool
6237ec681f3Smrgemit_bufferstore_call(struct ntd_context *ctx,
6247ec681f3Smrg                      const struct dxil_value *handle,
6257ec681f3Smrg                      const struct dxil_value *coord[2],
6267ec681f3Smrg                      const struct dxil_value *value[4],
6277ec681f3Smrg                      const struct dxil_value *write_mask,
6287ec681f3Smrg                      enum overload_type overload)
6297ec681f3Smrg{
6307ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.bufferStore", overload);
6317ec681f3Smrg
6327ec681f3Smrg   if (!func)
6337ec681f3Smrg      return false;
6347ec681f3Smrg
6357ec681f3Smrg   const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod,
6367ec681f3Smrg      DXIL_INTR_BUFFER_STORE);
6377ec681f3Smrg   const struct dxil_value *args[] = {
6387ec681f3Smrg      opcode, handle, coord[0], coord[1],
6397ec681f3Smrg      value[0], value[1], value[2], value[3],
6407ec681f3Smrg      write_mask
6417ec681f3Smrg   };
6427ec681f3Smrg
6437ec681f3Smrg   return dxil_emit_call_void(&ctx->mod, func,
6447ec681f3Smrg                              args, ARRAY_SIZE(args));
6457ec681f3Smrg}
6467ec681f3Smrg
6477ec681f3Smrgstatic const struct dxil_value *
6487ec681f3Smrgemit_textureload_call(struct ntd_context *ctx,
6497ec681f3Smrg                      const struct dxil_value *handle,
6507ec681f3Smrg                      const struct dxil_value *coord[3],
6517ec681f3Smrg                      enum overload_type overload)
6527ec681f3Smrg{
6537ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.textureLoad", overload);
6547ec681f3Smrg   if (!func)
6557ec681f3Smrg      return NULL;
6567ec681f3Smrg   const struct dxil_type *int_type = dxil_module_get_int_type(&ctx->mod, 32);
6577ec681f3Smrg   const struct dxil_value *int_undef = dxil_module_get_undef(&ctx->mod, int_type);
6587ec681f3Smrg
6597ec681f3Smrg   const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod,
6607ec681f3Smrg      DXIL_INTR_TEXTURE_LOAD);
6617ec681f3Smrg   const struct dxil_value *args[] = { opcode, handle,
6627ec681f3Smrg      /*lod_or_sample*/ int_undef,
6637ec681f3Smrg      coord[0], coord[1], coord[2],
6647ec681f3Smrg      /* offsets */ int_undef, int_undef, int_undef};
6657ec681f3Smrg
6667ec681f3Smrg   return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args));
6677ec681f3Smrg}
6687ec681f3Smrg
6697ec681f3Smrgstatic bool
6707ec681f3Smrgemit_texturestore_call(struct ntd_context *ctx,
6717ec681f3Smrg                       const struct dxil_value *handle,
6727ec681f3Smrg                       const struct dxil_value *coord[3],
6737ec681f3Smrg                       const struct dxil_value *value[4],
6747ec681f3Smrg                       const struct dxil_value *write_mask,
6757ec681f3Smrg                       enum overload_type overload)
6767ec681f3Smrg{
6777ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.textureStore", overload);
6787ec681f3Smrg
6797ec681f3Smrg   if (!func)
6807ec681f3Smrg      return false;
6817ec681f3Smrg
6827ec681f3Smrg   const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod,
6837ec681f3Smrg      DXIL_INTR_TEXTURE_STORE);
6847ec681f3Smrg   const struct dxil_value *args[] = {
6857ec681f3Smrg      opcode, handle, coord[0], coord[1], coord[2],
6867ec681f3Smrg      value[0], value[1], value[2], value[3],
6877ec681f3Smrg      write_mask
6887ec681f3Smrg   };
6897ec681f3Smrg
6907ec681f3Smrg   return dxil_emit_call_void(&ctx->mod, func,
6917ec681f3Smrg                              args, ARRAY_SIZE(args));
6927ec681f3Smrg}
6937ec681f3Smrg
6947ec681f3Smrgstatic const struct dxil_value *
6957ec681f3Smrgemit_atomic_binop(struct ntd_context *ctx,
6967ec681f3Smrg                  const struct dxil_value *handle,
6977ec681f3Smrg                  enum dxil_atomic_op atomic_op,
6987ec681f3Smrg                  const struct dxil_value *coord[3],
6997ec681f3Smrg                  const struct dxil_value *value)
7007ec681f3Smrg{
7017ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.atomicBinOp", DXIL_I32);
7027ec681f3Smrg
7037ec681f3Smrg   if (!func)
7047ec681f3Smrg      return false;
7057ec681f3Smrg
7067ec681f3Smrg   const struct dxil_value *opcode =
7077ec681f3Smrg      dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_ATOMIC_BINOP);
7087ec681f3Smrg   const struct dxil_value *atomic_op_value =
7097ec681f3Smrg      dxil_module_get_int32_const(&ctx->mod, atomic_op);
7107ec681f3Smrg   const struct dxil_value *args[] = {
7117ec681f3Smrg      opcode, handle, atomic_op_value,
7127ec681f3Smrg      coord[0], coord[1], coord[2], value
7137ec681f3Smrg   };
7147ec681f3Smrg
7157ec681f3Smrg   return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args));
7167ec681f3Smrg}
7177ec681f3Smrg
7187ec681f3Smrgstatic const struct dxil_value *
7197ec681f3Smrgemit_atomic_cmpxchg(struct ntd_context *ctx,
7207ec681f3Smrg                    const struct dxil_value *handle,
7217ec681f3Smrg                    const struct dxil_value *coord[3],
7227ec681f3Smrg                    const struct dxil_value *cmpval,
7237ec681f3Smrg                    const struct dxil_value *newval)
7247ec681f3Smrg{
7257ec681f3Smrg   const struct dxil_func *func =
7267ec681f3Smrg      dxil_get_function(&ctx->mod, "dx.op.atomicCompareExchange", DXIL_I32);
7277ec681f3Smrg
7287ec681f3Smrg   if (!func)
7297ec681f3Smrg      return false;
7307ec681f3Smrg
7317ec681f3Smrg   const struct dxil_value *opcode =
7327ec681f3Smrg      dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_ATOMIC_CMPXCHG);
7337ec681f3Smrg   const struct dxil_value *args[] = {
7347ec681f3Smrg      opcode, handle, coord[0], coord[1], coord[2], cmpval, newval
7357ec681f3Smrg   };
7367ec681f3Smrg
7377ec681f3Smrg   return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args));
7387ec681f3Smrg}
7397ec681f3Smrg
7407ec681f3Smrgstatic const struct dxil_value *
7417ec681f3Smrgemit_createhandle_call(struct ntd_context *ctx,
7427ec681f3Smrg                       enum dxil_resource_class resource_class,
7437ec681f3Smrg                       unsigned resource_range_id,
7447ec681f3Smrg                       const struct dxil_value *resource_range_index,
7457ec681f3Smrg                       bool non_uniform_resource_index)
7467ec681f3Smrg{
7477ec681f3Smrg   const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_CREATE_HANDLE);
7487ec681f3Smrg   const struct dxil_value *resource_class_value = dxil_module_get_int8_const(&ctx->mod, resource_class);
7497ec681f3Smrg   const struct dxil_value *resource_range_id_value = dxil_module_get_int32_const(&ctx->mod, resource_range_id);
7507ec681f3Smrg   const struct dxil_value *non_uniform_resource_index_value = dxil_module_get_int1_const(&ctx->mod, non_uniform_resource_index);
7517ec681f3Smrg   if (!opcode || !resource_class_value || !resource_range_id_value ||
7527ec681f3Smrg       !non_uniform_resource_index_value)
7537ec681f3Smrg      return NULL;
7547ec681f3Smrg
7557ec681f3Smrg   const struct dxil_value *args[] = {
7567ec681f3Smrg      opcode,
7577ec681f3Smrg      resource_class_value,
7587ec681f3Smrg      resource_range_id_value,
7597ec681f3Smrg      resource_range_index,
7607ec681f3Smrg      non_uniform_resource_index_value
7617ec681f3Smrg   };
7627ec681f3Smrg
7637ec681f3Smrg   const struct dxil_func *func =
7647ec681f3Smrg         dxil_get_function(&ctx->mod, "dx.op.createHandle", DXIL_NONE);
7657ec681f3Smrg
7667ec681f3Smrg   if (!func)
7677ec681f3Smrg         return NULL;
7687ec681f3Smrg
7697ec681f3Smrg   return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args));
7707ec681f3Smrg}
7717ec681f3Smrg
7727ec681f3Smrgstatic const struct dxil_value *
7737ec681f3Smrgemit_createhandle_call_const_index(struct ntd_context *ctx,
7747ec681f3Smrg                                   enum dxil_resource_class resource_class,
7757ec681f3Smrg                                   unsigned resource_range_id,
7767ec681f3Smrg                                   unsigned resource_range_index,
7777ec681f3Smrg                                   bool non_uniform_resource_index)
7787ec681f3Smrg{
7797ec681f3Smrg
7807ec681f3Smrg   const struct dxil_value *resource_range_index_value = dxil_module_get_int32_const(&ctx->mod, resource_range_index);
7817ec681f3Smrg   if (!resource_range_index_value)
7827ec681f3Smrg      return NULL;
7837ec681f3Smrg
7847ec681f3Smrg   return emit_createhandle_call(ctx, resource_class, resource_range_id,
7857ec681f3Smrg                                 resource_range_index_value,
7867ec681f3Smrg                                 non_uniform_resource_index);
7877ec681f3Smrg}
7887ec681f3Smrg
7897ec681f3Smrgstatic void
7907ec681f3Smrgadd_resource(struct ntd_context *ctx, enum dxil_resource_type type,
7917ec681f3Smrg             const resource_array_layout *layout)
7927ec681f3Smrg{
7937ec681f3Smrg   struct dxil_resource *resource = util_dynarray_grow(&ctx->resources, struct dxil_resource, 1);
7947ec681f3Smrg   resource->resource_type = type;
7957ec681f3Smrg   resource->space = layout->space;
7967ec681f3Smrg   resource->lower_bound = layout->binding;
7977ec681f3Smrg   if (layout->size == 0 || (uint64_t)layout->size + layout->binding >= UINT_MAX)
7987ec681f3Smrg      resource->upper_bound = UINT_MAX;
7997ec681f3Smrg   else
8007ec681f3Smrg      resource->upper_bound = layout->binding + layout->size - 1;
8017ec681f3Smrg}
8027ec681f3Smrg
8037ec681f3Smrgstatic unsigned
8047ec681f3Smrgget_resource_id(struct ntd_context *ctx, enum dxil_resource_class class,
8057ec681f3Smrg                unsigned space, unsigned binding)
8067ec681f3Smrg{
8077ec681f3Smrg   unsigned offset = 0;
8087ec681f3Smrg   unsigned count = 0;
8097ec681f3Smrg
8107ec681f3Smrg   unsigned num_srvs = util_dynarray_num_elements(&ctx->srv_metadata_nodes, const struct dxil_mdnode *);
8117ec681f3Smrg   unsigned num_uavs = util_dynarray_num_elements(&ctx->uav_metadata_nodes, const struct dxil_mdnode *);
8127ec681f3Smrg   unsigned num_cbvs = util_dynarray_num_elements(&ctx->cbv_metadata_nodes, const struct dxil_mdnode *);
8137ec681f3Smrg   unsigned num_samplers = util_dynarray_num_elements(&ctx->sampler_metadata_nodes, const struct dxil_mdnode *);
8147ec681f3Smrg
8157ec681f3Smrg   switch (class) {
8167ec681f3Smrg   case DXIL_RESOURCE_CLASS_UAV:
8177ec681f3Smrg      offset = num_srvs + num_samplers + num_cbvs;
8187ec681f3Smrg      count = num_uavs;
8197ec681f3Smrg      break;
8207ec681f3Smrg   case DXIL_RESOURCE_CLASS_SRV:
8217ec681f3Smrg      offset = num_samplers + num_cbvs;
8227ec681f3Smrg      count = num_srvs;
8237ec681f3Smrg      break;
8247ec681f3Smrg   case DXIL_RESOURCE_CLASS_SAMPLER:
8257ec681f3Smrg      offset = num_cbvs;
8267ec681f3Smrg      count = num_samplers;
8277ec681f3Smrg      break;
8287ec681f3Smrg   case DXIL_RESOURCE_CLASS_CBV:
8297ec681f3Smrg      offset = 0;
8307ec681f3Smrg      count = num_cbvs;
8317ec681f3Smrg      break;
8327ec681f3Smrg   }
8337ec681f3Smrg
8347ec681f3Smrg   assert(offset + count <= util_dynarray_num_elements(&ctx->resources, struct dxil_resource));
8357ec681f3Smrg   for (unsigned i = offset; i < offset + count; ++i) {
8367ec681f3Smrg      const struct dxil_resource *resource = util_dynarray_element(&ctx->resources, struct dxil_resource, i);
8377ec681f3Smrg      if (resource->space == space &&
8387ec681f3Smrg          resource->lower_bound <= binding &&
8397ec681f3Smrg          resource->upper_bound >= binding) {
8407ec681f3Smrg         return i - offset;
8417ec681f3Smrg      }
8427ec681f3Smrg   }
8437ec681f3Smrg
8447ec681f3Smrg   unreachable("Resource access for undeclared range");
8457ec681f3Smrg   return 0;
8467ec681f3Smrg}
8477ec681f3Smrg
8487ec681f3Smrgstatic bool
8497ec681f3Smrgemit_srv(struct ntd_context *ctx, nir_variable *var, unsigned count)
8507ec681f3Smrg{
8517ec681f3Smrg   unsigned id = util_dynarray_num_elements(&ctx->srv_metadata_nodes, const struct dxil_mdnode *);
8527ec681f3Smrg   unsigned binding = var->data.binding;
8537ec681f3Smrg   resource_array_layout layout = {id, binding, count, var->data.descriptor_set};
8547ec681f3Smrg
8557ec681f3Smrg   enum dxil_component_type comp_type;
8567ec681f3Smrg   enum dxil_resource_kind res_kind;
8577ec681f3Smrg   enum dxil_resource_type res_type;
8587ec681f3Smrg   if (var->data.mode == nir_var_mem_ssbo) {
8597ec681f3Smrg      comp_type = DXIL_COMP_TYPE_INVALID;
8607ec681f3Smrg      res_kind = DXIL_RESOURCE_KIND_RAW_BUFFER;
8617ec681f3Smrg      res_type = DXIL_RES_SRV_RAW;
8627ec681f3Smrg   } else {
8637ec681f3Smrg      comp_type = dxil_get_comp_type(var->type);
8647ec681f3Smrg      res_kind = dxil_get_resource_kind(var->type);
8657ec681f3Smrg      res_type = DXIL_RES_SRV_TYPED;
8667ec681f3Smrg   }
8677ec681f3Smrg   const struct dxil_type *res_type_as_type = dxil_module_get_res_type(&ctx->mod, res_kind, comp_type, false /* readwrite */);
8687ec681f3Smrg   const struct dxil_mdnode *srv_meta = emit_srv_metadata(&ctx->mod, res_type_as_type, var->name,
8697ec681f3Smrg                                                          &layout, comp_type, res_kind);
8707ec681f3Smrg
8717ec681f3Smrg   if (!srv_meta)
8727ec681f3Smrg      return false;
8737ec681f3Smrg
8747ec681f3Smrg   util_dynarray_append(&ctx->srv_metadata_nodes, const struct dxil_mdnode *, srv_meta);
8757ec681f3Smrg   add_resource(ctx, res_type, &layout);
8767ec681f3Smrg   if (res_type == DXIL_RES_SRV_RAW)
8777ec681f3Smrg      ctx->mod.raw_and_structured_buffers = true;
8787ec681f3Smrg
8797ec681f3Smrg   if (!ctx->opts->vulkan_environment) {
8807ec681f3Smrg      for (unsigned i = 0; i < count; ++i) {
8817ec681f3Smrg         const struct dxil_value *handle =
8827ec681f3Smrg            emit_createhandle_call_const_index(ctx, DXIL_RESOURCE_CLASS_SRV,
8837ec681f3Smrg                                               id, binding + i, false);
8847ec681f3Smrg         if (!handle)
8857ec681f3Smrg            return false;
8867ec681f3Smrg
8877ec681f3Smrg         int idx = var->data.binding + i;
8887ec681f3Smrg         ctx->srv_handles[idx] = handle;
8897ec681f3Smrg      }
8907ec681f3Smrg   }
8917ec681f3Smrg
8927ec681f3Smrg   return true;
8937ec681f3Smrg}
8947ec681f3Smrg
8957ec681f3Smrgstatic bool
8967ec681f3Smrgemit_globals(struct ntd_context *ctx, unsigned size)
8977ec681f3Smrg{
8987ec681f3Smrg   nir_foreach_variable_with_modes(var, ctx->shader, nir_var_mem_ssbo)
8997ec681f3Smrg      size++;
9007ec681f3Smrg
9017ec681f3Smrg   if (!size)
9027ec681f3Smrg      return true;
9037ec681f3Smrg
9047ec681f3Smrg   const struct dxil_type *struct_type = dxil_module_get_res_type(&ctx->mod,
9057ec681f3Smrg      DXIL_RESOURCE_KIND_RAW_BUFFER, DXIL_COMP_TYPE_INVALID, true /* readwrite */);
9067ec681f3Smrg   if (!struct_type)
9077ec681f3Smrg      return false;
9087ec681f3Smrg
9097ec681f3Smrg   const struct dxil_type *array_type =
9107ec681f3Smrg      dxil_module_get_array_type(&ctx->mod, struct_type, size);
9117ec681f3Smrg   if (!array_type)
9127ec681f3Smrg      return false;
9137ec681f3Smrg
9147ec681f3Smrg   resource_array_layout layout = {0, 0, size, 0};
9157ec681f3Smrg   const struct dxil_mdnode *uav_meta =
9167ec681f3Smrg      emit_uav_metadata(&ctx->mod, array_type,
9177ec681f3Smrg                                   "globals", &layout,
9187ec681f3Smrg                                   DXIL_COMP_TYPE_INVALID,
9197ec681f3Smrg                                   DXIL_RESOURCE_KIND_RAW_BUFFER);
9207ec681f3Smrg   if (!uav_meta)
9217ec681f3Smrg      return false;
9227ec681f3Smrg
9237ec681f3Smrg   util_dynarray_append(&ctx->uav_metadata_nodes, const struct dxil_mdnode *, uav_meta);
9247ec681f3Smrg   if (util_dynarray_num_elements(&ctx->uav_metadata_nodes, const struct dxil_mdnode *) > 8)
9257ec681f3Smrg      ctx->mod.feats.use_64uavs = 1;
9267ec681f3Smrg   /* Handles to UAVs used for kernel globals are created on-demand */
9277ec681f3Smrg   add_resource(ctx, DXIL_RES_UAV_RAW, &layout);
9287ec681f3Smrg   ctx->mod.raw_and_structured_buffers = true;
9297ec681f3Smrg   return true;
9307ec681f3Smrg}
9317ec681f3Smrg
9327ec681f3Smrgstatic bool
9337ec681f3Smrgemit_uav(struct ntd_context *ctx, unsigned binding, unsigned space, unsigned count,
9347ec681f3Smrg         enum dxil_component_type comp_type, enum dxil_resource_kind res_kind, const char *name)
9357ec681f3Smrg{
9367ec681f3Smrg   unsigned id = util_dynarray_num_elements(&ctx->uav_metadata_nodes, const struct dxil_mdnode *);
9377ec681f3Smrg   resource_array_layout layout = { id, binding, count, space };
9387ec681f3Smrg
9397ec681f3Smrg   const struct dxil_type *res_type = dxil_module_get_res_type(&ctx->mod, res_kind, comp_type, true /* readwrite */);
9407ec681f3Smrg   const struct dxil_mdnode *uav_meta = emit_uav_metadata(&ctx->mod, res_type, name,
9417ec681f3Smrg                                                          &layout, comp_type, res_kind);
9427ec681f3Smrg
9437ec681f3Smrg   if (!uav_meta)
9447ec681f3Smrg      return false;
9457ec681f3Smrg
9467ec681f3Smrg   util_dynarray_append(&ctx->uav_metadata_nodes, const struct dxil_mdnode *, uav_meta);
9477ec681f3Smrg   if (util_dynarray_num_elements(&ctx->uav_metadata_nodes, const struct dxil_mdnode *) > 8)
9487ec681f3Smrg      ctx->mod.feats.use_64uavs = 1;
9497ec681f3Smrg
9507ec681f3Smrg   add_resource(ctx, res_kind == DXIL_RESOURCE_KIND_RAW_BUFFER ? DXIL_RES_UAV_RAW : DXIL_RES_UAV_TYPED, &layout);
9517ec681f3Smrg   if (res_kind == DXIL_RESOURCE_KIND_RAW_BUFFER)
9527ec681f3Smrg      ctx->mod.raw_and_structured_buffers = true;
9537ec681f3Smrg
9547ec681f3Smrg   if (!ctx->opts->vulkan_environment) {
9557ec681f3Smrg      for (unsigned i = 0; i < count; ++i) {
9567ec681f3Smrg         const struct dxil_value *handle = emit_createhandle_call_const_index(ctx, DXIL_RESOURCE_CLASS_UAV,
9577ec681f3Smrg                                                                              id, binding + i, false);
9587ec681f3Smrg         if (!handle)
9597ec681f3Smrg            return false;
9607ec681f3Smrg
9617ec681f3Smrg         ctx->uav_handles[binding + i] = handle;
9627ec681f3Smrg      }
9637ec681f3Smrg   }
9647ec681f3Smrg
9657ec681f3Smrg   return true;
9667ec681f3Smrg}
9677ec681f3Smrg
9687ec681f3Smrgstatic bool
9697ec681f3Smrgemit_uav_var(struct ntd_context *ctx, nir_variable *var, unsigned count)
9707ec681f3Smrg{
9717ec681f3Smrg   unsigned binding = var->data.binding;
9727ec681f3Smrg   unsigned space = var->data.descriptor_set;
9737ec681f3Smrg   enum dxil_component_type comp_type = dxil_get_comp_type(var->type);
9747ec681f3Smrg   enum dxil_resource_kind res_kind = dxil_get_resource_kind(var->type);
9757ec681f3Smrg   const char *name = var->name;
9767ec681f3Smrg
9777ec681f3Smrg   return emit_uav(ctx, binding, space, count, comp_type, res_kind, name);
9787ec681f3Smrg}
9797ec681f3Smrg
9807ec681f3Smrgstatic unsigned get_dword_size(const struct glsl_type *type)
9817ec681f3Smrg{
9827ec681f3Smrg   if (glsl_type_is_array(type)) {
9837ec681f3Smrg      type = glsl_without_array(type);
9847ec681f3Smrg   }
9857ec681f3Smrg   assert(glsl_type_is_struct(type) || glsl_type_is_interface(type));
9867ec681f3Smrg   return glsl_get_explicit_size(type, false);
9877ec681f3Smrg}
9887ec681f3Smrg
9897ec681f3Smrgstatic void
9907ec681f3Smrgvar_fill_const_array_with_vector_or_scalar(struct ntd_context *ctx,
9917ec681f3Smrg                                           const struct nir_constant *c,
9927ec681f3Smrg                                           const struct glsl_type *type,
9937ec681f3Smrg                                           void *const_vals,
9947ec681f3Smrg                                           unsigned int offset)
9957ec681f3Smrg{
9967ec681f3Smrg   assert(glsl_type_is_vector_or_scalar(type));
9977ec681f3Smrg   unsigned int components = glsl_get_vector_elements(type);
9987ec681f3Smrg   unsigned bit_size = glsl_get_bit_size(type);
9997ec681f3Smrg   unsigned int increment = bit_size / 8;
10007ec681f3Smrg
10017ec681f3Smrg   for (unsigned int comp = 0; comp < components; comp++) {
10027ec681f3Smrg      uint8_t *dst = (uint8_t *)const_vals + offset;
10037ec681f3Smrg
10047ec681f3Smrg      switch (bit_size) {
10057ec681f3Smrg      case 64:
10067ec681f3Smrg         memcpy(dst, &c->values[comp].u64, sizeof(c->values[0].u64));
10077ec681f3Smrg         break;
10087ec681f3Smrg      case 32:
10097ec681f3Smrg         memcpy(dst, &c->values[comp].u32, sizeof(c->values[0].u32));
10107ec681f3Smrg         break;
10117ec681f3Smrg      case 16:
10127ec681f3Smrg         memcpy(dst, &c->values[comp].u16, sizeof(c->values[0].u16));
10137ec681f3Smrg         break;
10147ec681f3Smrg      case 8:
10157ec681f3Smrg         assert(glsl_base_type_is_integer(glsl_get_base_type(type)));
10167ec681f3Smrg         memcpy(dst, &c->values[comp].u8, sizeof(c->values[0].u8));
10177ec681f3Smrg         break;
10187ec681f3Smrg      default:
10197ec681f3Smrg         unreachable("unexpeted bit-size");
10207ec681f3Smrg      }
10217ec681f3Smrg
10227ec681f3Smrg      offset += increment;
10237ec681f3Smrg   }
10247ec681f3Smrg}
10257ec681f3Smrg
10267ec681f3Smrgstatic void
10277ec681f3Smrgvar_fill_const_array(struct ntd_context *ctx, const struct nir_constant *c,
10287ec681f3Smrg                     const struct glsl_type *type, void *const_vals,
10297ec681f3Smrg                     unsigned int offset)
10307ec681f3Smrg{
10317ec681f3Smrg   assert(!glsl_type_is_interface(type));
10327ec681f3Smrg
10337ec681f3Smrg   if (glsl_type_is_vector_or_scalar(type)) {
10347ec681f3Smrg      var_fill_const_array_with_vector_or_scalar(ctx, c, type,
10357ec681f3Smrg                                                 const_vals,
10367ec681f3Smrg                                                 offset);
10377ec681f3Smrg   } else if (glsl_type_is_array(type)) {
10387ec681f3Smrg      assert(!glsl_type_is_unsized_array(type));
10397ec681f3Smrg      const struct glsl_type *without = glsl_without_array(type);
10407ec681f3Smrg      unsigned stride = glsl_get_explicit_stride(without);
10417ec681f3Smrg
10427ec681f3Smrg      for (unsigned elt = 0; elt < glsl_get_length(type); elt++) {
10437ec681f3Smrg         var_fill_const_array(ctx, c->elements[elt], without,
10447ec681f3Smrg                              const_vals, offset + (elt * stride));
10457ec681f3Smrg         offset += glsl_get_cl_size(without);
10467ec681f3Smrg      }
10477ec681f3Smrg   } else if (glsl_type_is_struct(type)) {
10487ec681f3Smrg      for (unsigned int elt = 0; elt < glsl_get_length(type); elt++) {
10497ec681f3Smrg         const struct glsl_type *elt_type = glsl_get_struct_field(type, elt);
10507ec681f3Smrg         unsigned field_offset = glsl_get_struct_field_offset(type, elt);
10517ec681f3Smrg
10527ec681f3Smrg         var_fill_const_array(ctx, c->elements[elt],
10537ec681f3Smrg                              elt_type, const_vals,
10547ec681f3Smrg                              offset + field_offset);
10557ec681f3Smrg      }
10567ec681f3Smrg   } else
10577ec681f3Smrg      unreachable("unknown GLSL type in var_fill_const_array");
10587ec681f3Smrg}
10597ec681f3Smrg
10607ec681f3Smrgstatic bool
10617ec681f3Smrgemit_global_consts(struct ntd_context *ctx)
10627ec681f3Smrg{
10637ec681f3Smrg   nir_foreach_variable_with_modes(var, ctx->shader, nir_var_shader_temp) {
10647ec681f3Smrg      assert(var->constant_initializer);
10657ec681f3Smrg
10667ec681f3Smrg      unsigned int num_members = DIV_ROUND_UP(glsl_get_cl_size(var->type), 4);
10677ec681f3Smrg      uint32_t *const_ints = ralloc_array(ctx->ralloc_ctx, uint32_t, num_members);
10687ec681f3Smrg      var_fill_const_array(ctx, var->constant_initializer, var->type,
10697ec681f3Smrg                                 const_ints, 0);
10707ec681f3Smrg      const struct dxil_value **const_vals =
10717ec681f3Smrg         ralloc_array(ctx->ralloc_ctx, const struct dxil_value *, num_members);
10727ec681f3Smrg      if (!const_vals)
10737ec681f3Smrg         return false;
10747ec681f3Smrg      for (int i = 0; i < num_members; i++)
10757ec681f3Smrg         const_vals[i] = dxil_module_get_int32_const(&ctx->mod, const_ints[i]);
10767ec681f3Smrg
10777ec681f3Smrg      const struct dxil_type *elt_type = dxil_module_get_int_type(&ctx->mod, 32);
10787ec681f3Smrg      if (!elt_type)
10797ec681f3Smrg         return false;
10807ec681f3Smrg      const struct dxil_type *type =
10817ec681f3Smrg         dxil_module_get_array_type(&ctx->mod, elt_type, num_members);
10827ec681f3Smrg      if (!type)
10837ec681f3Smrg         return false;
10847ec681f3Smrg      const struct dxil_value *agg_vals =
10857ec681f3Smrg         dxil_module_get_array_const(&ctx->mod, type, const_vals);
10867ec681f3Smrg      if (!agg_vals)
10877ec681f3Smrg         return false;
10887ec681f3Smrg
10897ec681f3Smrg      const struct dxil_value *gvar = dxil_add_global_ptr_var(&ctx->mod, var->name, type,
10907ec681f3Smrg                                                              DXIL_AS_DEFAULT, 4,
10917ec681f3Smrg                                                              agg_vals);
10927ec681f3Smrg      if (!gvar)
10937ec681f3Smrg         return false;
10947ec681f3Smrg
10957ec681f3Smrg      if (!_mesa_hash_table_insert(ctx->consts, var, (void *)gvar))
10967ec681f3Smrg         return false;
10977ec681f3Smrg   }
10987ec681f3Smrg
10997ec681f3Smrg   return true;
11007ec681f3Smrg}
11017ec681f3Smrg
11027ec681f3Smrgstatic bool
11037ec681f3Smrgemit_cbv(struct ntd_context *ctx, unsigned binding, unsigned space,
11047ec681f3Smrg         unsigned size, unsigned count, char *name)
11057ec681f3Smrg{
11067ec681f3Smrg   unsigned idx = util_dynarray_num_elements(&ctx->cbv_metadata_nodes, const struct dxil_mdnode *);
11077ec681f3Smrg
11087ec681f3Smrg   const struct dxil_type *float32 = dxil_module_get_float_type(&ctx->mod, 32);
11097ec681f3Smrg   const struct dxil_type *array_type = dxil_module_get_array_type(&ctx->mod, float32, size);
11107ec681f3Smrg   const struct dxil_type *buffer_type = dxil_module_get_struct_type(&ctx->mod, name,
11117ec681f3Smrg                                                                     &array_type, 1);
11127ec681f3Smrg   const struct dxil_type *final_type = count != 1 ? dxil_module_get_array_type(&ctx->mod, buffer_type, count) : buffer_type;
11137ec681f3Smrg   resource_array_layout layout = {idx, binding, count, space};
11147ec681f3Smrg   const struct dxil_mdnode *cbv_meta = emit_cbv_metadata(&ctx->mod, final_type,
11157ec681f3Smrg                                                          name, &layout, 4 * size);
11167ec681f3Smrg
11177ec681f3Smrg   if (!cbv_meta)
11187ec681f3Smrg      return false;
11197ec681f3Smrg
11207ec681f3Smrg   util_dynarray_append(&ctx->cbv_metadata_nodes, const struct dxil_mdnode *, cbv_meta);
11217ec681f3Smrg   add_resource(ctx, DXIL_RES_CBV, &layout);
11227ec681f3Smrg
11237ec681f3Smrg   if (!ctx->opts->vulkan_environment) {
11247ec681f3Smrg      for (unsigned i = 0; i < count; ++i) {
11257ec681f3Smrg         const struct dxil_value *handle = emit_createhandle_call_const_index(ctx, DXIL_RESOURCE_CLASS_CBV,
11267ec681f3Smrg                                                                              idx, binding + i, false);
11277ec681f3Smrg         if (!handle)
11287ec681f3Smrg            return false;
11297ec681f3Smrg
11307ec681f3Smrg         assert(!ctx->cbv_handles[binding + i]);
11317ec681f3Smrg         ctx->cbv_handles[binding + i] = handle;
11327ec681f3Smrg      }
11337ec681f3Smrg   }
11347ec681f3Smrg
11357ec681f3Smrg   return true;
11367ec681f3Smrg}
11377ec681f3Smrg
11387ec681f3Smrgstatic bool
11397ec681f3Smrgemit_ubo_var(struct ntd_context *ctx, nir_variable *var)
11407ec681f3Smrg{
11417ec681f3Smrg   unsigned count = 1;
11427ec681f3Smrg   if (glsl_type_is_array(var->type))
11437ec681f3Smrg      count = glsl_get_length(var->type);
11447ec681f3Smrg   return emit_cbv(ctx, var->data.binding, var->data.descriptor_set, get_dword_size(var->type), count, var->name);
11457ec681f3Smrg}
11467ec681f3Smrg
11477ec681f3Smrgstatic bool
11487ec681f3Smrgemit_sampler(struct ntd_context *ctx, nir_variable *var, unsigned count)
11497ec681f3Smrg{
11507ec681f3Smrg   unsigned id = util_dynarray_num_elements(&ctx->sampler_metadata_nodes, const struct dxil_mdnode *);
11517ec681f3Smrg   unsigned binding = var->data.binding;
11527ec681f3Smrg   resource_array_layout layout = {id, binding, count, var->data.descriptor_set};
11537ec681f3Smrg   const struct dxil_type *int32_type = dxil_module_get_int_type(&ctx->mod, 32);
11547ec681f3Smrg   const struct dxil_type *sampler_type = dxil_module_get_struct_type(&ctx->mod, "struct.SamplerState", &int32_type, 1);
11557ec681f3Smrg   const struct dxil_mdnode *sampler_meta = emit_sampler_metadata(&ctx->mod, sampler_type, var, &layout);
11567ec681f3Smrg
11577ec681f3Smrg   if (!sampler_meta)
11587ec681f3Smrg      return false;
11597ec681f3Smrg
11607ec681f3Smrg   util_dynarray_append(&ctx->sampler_metadata_nodes, const struct dxil_mdnode *, sampler_meta);
11617ec681f3Smrg   add_resource(ctx, DXIL_RES_SAMPLER, &layout);
11627ec681f3Smrg
11637ec681f3Smrg   if (!ctx->opts->vulkan_environment) {
11647ec681f3Smrg      for (unsigned i = 0; i < count; ++i) {
11657ec681f3Smrg         const struct dxil_value *handle =
11667ec681f3Smrg            emit_createhandle_call_const_index(ctx, DXIL_RESOURCE_CLASS_SAMPLER,
11677ec681f3Smrg                                               id, binding + i, false);
11687ec681f3Smrg         if (!handle)
11697ec681f3Smrg            return false;
11707ec681f3Smrg
11717ec681f3Smrg         unsigned idx = var->data.binding + i;
11727ec681f3Smrg         ctx->sampler_handles[idx] = handle;
11737ec681f3Smrg      }
11747ec681f3Smrg   }
11757ec681f3Smrg
11767ec681f3Smrg   return true;
11777ec681f3Smrg}
11787ec681f3Smrg
11797ec681f3Smrgstatic const struct dxil_mdnode *
11807ec681f3Smrgemit_gs_state(struct ntd_context *ctx)
11817ec681f3Smrg{
11827ec681f3Smrg   const struct dxil_mdnode *gs_state_nodes[5];
11837ec681f3Smrg   const nir_shader *s = ctx->shader;
11847ec681f3Smrg
11857ec681f3Smrg   gs_state_nodes[0] = dxil_get_metadata_int32(&ctx->mod, dxil_get_input_primitive(s->info.gs.input_primitive));
11867ec681f3Smrg   gs_state_nodes[1] = dxil_get_metadata_int32(&ctx->mod, s->info.gs.vertices_out);
11877ec681f3Smrg   gs_state_nodes[2] = dxil_get_metadata_int32(&ctx->mod, s->info.gs.active_stream_mask);
11887ec681f3Smrg   gs_state_nodes[3] = dxil_get_metadata_int32(&ctx->mod, dxil_get_primitive_topology(s->info.gs.output_primitive));
11897ec681f3Smrg   gs_state_nodes[4] = dxil_get_metadata_int32(&ctx->mod, s->info.gs.invocations);
11907ec681f3Smrg
11917ec681f3Smrg   for (unsigned i = 0; i < ARRAY_SIZE(gs_state_nodes); ++i) {
11927ec681f3Smrg      if (!gs_state_nodes[i])
11937ec681f3Smrg         return NULL;
11947ec681f3Smrg   }
11957ec681f3Smrg
11967ec681f3Smrg   return dxil_get_metadata_node(&ctx->mod, gs_state_nodes, ARRAY_SIZE(gs_state_nodes));
11977ec681f3Smrg}
11987ec681f3Smrg
11997ec681f3Smrgstatic const struct dxil_mdnode *
12007ec681f3Smrgemit_threads(struct ntd_context *ctx)
12017ec681f3Smrg{
12027ec681f3Smrg   const nir_shader *s = ctx->shader;
12037ec681f3Smrg   const struct dxil_mdnode *threads_x = dxil_get_metadata_int32(&ctx->mod, MAX2(s->info.workgroup_size[0], 1));
12047ec681f3Smrg   const struct dxil_mdnode *threads_y = dxil_get_metadata_int32(&ctx->mod, MAX2(s->info.workgroup_size[1], 1));
12057ec681f3Smrg   const struct dxil_mdnode *threads_z = dxil_get_metadata_int32(&ctx->mod, MAX2(s->info.workgroup_size[2], 1));
12067ec681f3Smrg   if (!threads_x || !threads_y || !threads_z)
12077ec681f3Smrg      return false;
12087ec681f3Smrg
12097ec681f3Smrg   const struct dxil_mdnode *threads_nodes[] = { threads_x, threads_y, threads_z };
12107ec681f3Smrg   return dxil_get_metadata_node(&ctx->mod, threads_nodes, ARRAY_SIZE(threads_nodes));
12117ec681f3Smrg}
12127ec681f3Smrg
12137ec681f3Smrgstatic int64_t
12147ec681f3Smrgget_module_flags(struct ntd_context *ctx)
12157ec681f3Smrg{
12167ec681f3Smrg   /* See the DXIL documentation for the definition of these flags:
12177ec681f3Smrg    *
12187ec681f3Smrg    * https://github.com/Microsoft/DirectXShaderCompiler/blob/master/docs/DXIL.rst#shader-flags
12197ec681f3Smrg    */
12207ec681f3Smrg
12217ec681f3Smrg   uint64_t flags = 0;
12227ec681f3Smrg   if (ctx->mod.feats.doubles)
12237ec681f3Smrg      flags |= (1 << 2);
12247ec681f3Smrg   if (ctx->mod.raw_and_structured_buffers)
12257ec681f3Smrg      flags |= (1 << 4);
12267ec681f3Smrg   if (ctx->mod.feats.min_precision)
12277ec681f3Smrg      flags |= (1 << 5);
12287ec681f3Smrg   if (ctx->mod.feats.dx11_1_double_extensions)
12297ec681f3Smrg      flags |= (1 << 6);
12307ec681f3Smrg   if (ctx->mod.feats.inner_coverage)
12317ec681f3Smrg      flags |= (1 << 10);
12327ec681f3Smrg   if (ctx->mod.feats.typed_uav_load_additional_formats)
12337ec681f3Smrg      flags |= (1 << 13);
12347ec681f3Smrg   if (ctx->mod.feats.use_64uavs)
12357ec681f3Smrg      flags |= (1 << 15);
12367ec681f3Smrg   if (ctx->mod.feats.cs_4x_raw_sb)
12377ec681f3Smrg      flags |= (1 << 17);
12387ec681f3Smrg   if (ctx->mod.feats.wave_ops)
12397ec681f3Smrg      flags |= (1 << 19);
12407ec681f3Smrg   if (ctx->mod.feats.int64_ops)
12417ec681f3Smrg      flags |= (1 << 20);
12427ec681f3Smrg   if (ctx->mod.feats.stencil_ref)
12437ec681f3Smrg      flags |= (1 << 11);
12447ec681f3Smrg   if (ctx->mod.feats.native_low_precision)
12457ec681f3Smrg      flags |= (1 << 23) | (1 << 5);
12467ec681f3Smrg
12477ec681f3Smrg   if (ctx->opts->disable_math_refactoring)
12487ec681f3Smrg      flags |= (1 << 1);
12497ec681f3Smrg
12507ec681f3Smrg   return flags;
12517ec681f3Smrg}
12527ec681f3Smrg
12537ec681f3Smrgstatic const struct dxil_mdnode *
12547ec681f3Smrgemit_entrypoint(struct ntd_context *ctx,
12557ec681f3Smrg                const struct dxil_func *func, const char *name,
12567ec681f3Smrg                const struct dxil_mdnode *signatures,
12577ec681f3Smrg                const struct dxil_mdnode *resources,
12587ec681f3Smrg                const struct dxil_mdnode *shader_props)
12597ec681f3Smrg{
12607ec681f3Smrg   const struct dxil_mdnode *func_md = dxil_get_metadata_func(&ctx->mod, func);
12617ec681f3Smrg   const struct dxil_mdnode *name_md = dxil_get_metadata_string(&ctx->mod, name);
12627ec681f3Smrg   const struct dxil_mdnode *nodes[] = {
12637ec681f3Smrg      func_md,
12647ec681f3Smrg      name_md,
12657ec681f3Smrg      signatures,
12667ec681f3Smrg      resources,
12677ec681f3Smrg      shader_props
12687ec681f3Smrg   };
12697ec681f3Smrg   return dxil_get_metadata_node(&ctx->mod, nodes,
12707ec681f3Smrg                                 ARRAY_SIZE(nodes));
12717ec681f3Smrg}
12727ec681f3Smrg
12737ec681f3Smrgstatic const struct dxil_mdnode *
12747ec681f3Smrgemit_resources(struct ntd_context *ctx)
12757ec681f3Smrg{
12767ec681f3Smrg   bool emit_resources = false;
12777ec681f3Smrg   const struct dxil_mdnode *resources_nodes[] = {
12787ec681f3Smrg      NULL, NULL, NULL, NULL
12797ec681f3Smrg   };
12807ec681f3Smrg
12817ec681f3Smrg#define ARRAY_AND_SIZE(arr) arr.data, util_dynarray_num_elements(&arr, const struct dxil_mdnode *)
12827ec681f3Smrg
12837ec681f3Smrg   if (ctx->srv_metadata_nodes.size) {
12847ec681f3Smrg      resources_nodes[0] = dxil_get_metadata_node(&ctx->mod, ARRAY_AND_SIZE(ctx->srv_metadata_nodes));
12857ec681f3Smrg      emit_resources = true;
12867ec681f3Smrg   }
12877ec681f3Smrg
12887ec681f3Smrg   if (ctx->uav_metadata_nodes.size) {
12897ec681f3Smrg      resources_nodes[1] = dxil_get_metadata_node(&ctx->mod, ARRAY_AND_SIZE(ctx->uav_metadata_nodes));
12907ec681f3Smrg      emit_resources = true;
12917ec681f3Smrg   }
12927ec681f3Smrg
12937ec681f3Smrg   if (ctx->cbv_metadata_nodes.size) {
12947ec681f3Smrg      resources_nodes[2] = dxil_get_metadata_node(&ctx->mod, ARRAY_AND_SIZE(ctx->cbv_metadata_nodes));
12957ec681f3Smrg      emit_resources = true;
12967ec681f3Smrg   }
12977ec681f3Smrg
12987ec681f3Smrg   if (ctx->sampler_metadata_nodes.size) {
12997ec681f3Smrg      resources_nodes[3] = dxil_get_metadata_node(&ctx->mod, ARRAY_AND_SIZE(ctx->sampler_metadata_nodes));
13007ec681f3Smrg      emit_resources = true;
13017ec681f3Smrg   }
13027ec681f3Smrg
13037ec681f3Smrg#undef ARRAY_AND_SIZE
13047ec681f3Smrg
13057ec681f3Smrg   return emit_resources ?
13067ec681f3Smrg      dxil_get_metadata_node(&ctx->mod, resources_nodes, ARRAY_SIZE(resources_nodes)): NULL;
13077ec681f3Smrg}
13087ec681f3Smrg
13097ec681f3Smrgstatic boolean
13107ec681f3Smrgemit_tag(struct ntd_context *ctx, enum dxil_shader_tag tag,
13117ec681f3Smrg         const struct dxil_mdnode *value_node)
13127ec681f3Smrg{
13137ec681f3Smrg   const struct dxil_mdnode *tag_node = dxil_get_metadata_int32(&ctx->mod, tag);
13147ec681f3Smrg   if (!tag_node || !value_node)
13157ec681f3Smrg      return false;
13167ec681f3Smrg   assert(ctx->num_shader_property_nodes <= ARRAY_SIZE(ctx->shader_property_nodes) - 2);
13177ec681f3Smrg   ctx->shader_property_nodes[ctx->num_shader_property_nodes++] = tag_node;
13187ec681f3Smrg   ctx->shader_property_nodes[ctx->num_shader_property_nodes++] = value_node;
13197ec681f3Smrg
13207ec681f3Smrg   return true;
13217ec681f3Smrg}
13227ec681f3Smrg
13237ec681f3Smrgstatic bool
13247ec681f3Smrgemit_metadata(struct ntd_context *ctx)
13257ec681f3Smrg{
13267ec681f3Smrg   unsigned dxilMinor = ctx->mod.minor_version;
13277ec681f3Smrg   if (!emit_llvm_ident(&ctx->mod) ||
13287ec681f3Smrg       !emit_named_version(&ctx->mod, "dx.version", 1, dxilMinor) ||
13297ec681f3Smrg       !emit_named_version(&ctx->mod, "dx.valver", 1, 4) ||
13307ec681f3Smrg       !emit_dx_shader_model(&ctx->mod))
13317ec681f3Smrg      return false;
13327ec681f3Smrg
13337ec681f3Smrg   const struct dxil_type *void_type = dxil_module_get_void_type(&ctx->mod);
13347ec681f3Smrg   const struct dxil_type *main_func_type = dxil_module_add_function_type(&ctx->mod, void_type, NULL, 0);
13357ec681f3Smrg   const struct dxil_func *main_func = dxil_add_function_def(&ctx->mod, "main", main_func_type);
13367ec681f3Smrg   if (!main_func)
13377ec681f3Smrg      return false;
13387ec681f3Smrg
13397ec681f3Smrg   const struct dxil_mdnode *resources_node = emit_resources(ctx);
13407ec681f3Smrg
13417ec681f3Smrg   const struct dxil_mdnode *main_entrypoint = dxil_get_metadata_func(&ctx->mod, main_func);
13427ec681f3Smrg   const struct dxil_mdnode *node27 = dxil_get_metadata_node(&ctx->mod, NULL, 0);
13437ec681f3Smrg
13447ec681f3Smrg   const struct dxil_mdnode *node4 = dxil_get_metadata_int32(&ctx->mod, 0);
13457ec681f3Smrg   const struct dxil_mdnode *nodes_4_27_27[] = {
13467ec681f3Smrg      node4, node27, node27
13477ec681f3Smrg   };
13487ec681f3Smrg   const struct dxil_mdnode *node28 = dxil_get_metadata_node(&ctx->mod, nodes_4_27_27,
13497ec681f3Smrg                                                      ARRAY_SIZE(nodes_4_27_27));
13507ec681f3Smrg
13517ec681f3Smrg   const struct dxil_mdnode *node29 = dxil_get_metadata_node(&ctx->mod, &node28, 1);
13527ec681f3Smrg
13537ec681f3Smrg   const struct dxil_mdnode *node3 = dxil_get_metadata_int32(&ctx->mod, 1);
13547ec681f3Smrg   const struct dxil_mdnode *main_type_annotation_nodes[] = {
13557ec681f3Smrg      node3, main_entrypoint, node29
13567ec681f3Smrg   };
13577ec681f3Smrg   const struct dxil_mdnode *main_type_annotation = dxil_get_metadata_node(&ctx->mod, main_type_annotation_nodes,
13587ec681f3Smrg                                                                           ARRAY_SIZE(main_type_annotation_nodes));
13597ec681f3Smrg
13607ec681f3Smrg   if (ctx->mod.shader_kind == DXIL_GEOMETRY_SHADER) {
13617ec681f3Smrg      if (!emit_tag(ctx, DXIL_SHADER_TAG_GS_STATE, emit_gs_state(ctx)))
13627ec681f3Smrg         return false;
13637ec681f3Smrg   } else if (ctx->mod.shader_kind == DXIL_COMPUTE_SHADER) {
13647ec681f3Smrg      if (!emit_tag(ctx, DXIL_SHADER_TAG_NUM_THREADS, emit_threads(ctx)))
13657ec681f3Smrg         return false;
13667ec681f3Smrg   }
13677ec681f3Smrg
13687ec681f3Smrg   uint64_t flags = get_module_flags(ctx);
13697ec681f3Smrg   if (flags != 0) {
13707ec681f3Smrg      if (!emit_tag(ctx, DXIL_SHADER_TAG_FLAGS, dxil_get_metadata_int64(&ctx->mod, flags)))
13717ec681f3Smrg         return false;
13727ec681f3Smrg   }
13737ec681f3Smrg   const struct dxil_mdnode *shader_properties = NULL;
13747ec681f3Smrg   if (ctx->num_shader_property_nodes > 0) {
13757ec681f3Smrg      shader_properties = dxil_get_metadata_node(&ctx->mod, ctx->shader_property_nodes,
13767ec681f3Smrg                                                 ctx->num_shader_property_nodes);
13777ec681f3Smrg      if (!shader_properties)
13787ec681f3Smrg         return false;
13797ec681f3Smrg   }
13807ec681f3Smrg
13817ec681f3Smrg   const struct dxil_mdnode *signatures = get_signatures(&ctx->mod, ctx->shader,
13827ec681f3Smrg                                                         ctx->opts->vulkan_environment);
13837ec681f3Smrg
13847ec681f3Smrg   const struct dxil_mdnode *dx_entry_point = emit_entrypoint(ctx, main_func,
13857ec681f3Smrg       "main", signatures, resources_node, shader_properties);
13867ec681f3Smrg   if (!dx_entry_point)
13877ec681f3Smrg      return false;
13887ec681f3Smrg
13897ec681f3Smrg   if (resources_node) {
13907ec681f3Smrg      const struct dxil_mdnode *dx_resources = resources_node;
13917ec681f3Smrg      dxil_add_metadata_named_node(&ctx->mod, "dx.resources",
13927ec681f3Smrg                                       &dx_resources, 1);
13937ec681f3Smrg   }
13947ec681f3Smrg
13957ec681f3Smrg   const struct dxil_mdnode *dx_type_annotations[] = { main_type_annotation };
13967ec681f3Smrg   return dxil_add_metadata_named_node(&ctx->mod, "dx.typeAnnotations",
13977ec681f3Smrg                                       dx_type_annotations,
13987ec681f3Smrg                                       ARRAY_SIZE(dx_type_annotations)) &&
13997ec681f3Smrg          dxil_add_metadata_named_node(&ctx->mod, "dx.entryPoints",
14007ec681f3Smrg                                       &dx_entry_point, 1);
14017ec681f3Smrg}
14027ec681f3Smrg
14037ec681f3Smrgstatic const struct dxil_value *
14047ec681f3Smrgbitcast_to_int(struct ntd_context *ctx, unsigned bit_size,
14057ec681f3Smrg               const struct dxil_value *value)
14067ec681f3Smrg{
14077ec681f3Smrg   const struct dxil_type *type = dxil_module_get_int_type(&ctx->mod, bit_size);
14087ec681f3Smrg   if (!type)
14097ec681f3Smrg      return NULL;
14107ec681f3Smrg
14117ec681f3Smrg   return dxil_emit_cast(&ctx->mod, DXIL_CAST_BITCAST, type, value);
14127ec681f3Smrg}
14137ec681f3Smrg
14147ec681f3Smrgstatic const struct dxil_value *
14157ec681f3Smrgbitcast_to_float(struct ntd_context *ctx, unsigned bit_size,
14167ec681f3Smrg                 const struct dxil_value *value)
14177ec681f3Smrg{
14187ec681f3Smrg   const struct dxil_type *type = dxil_module_get_float_type(&ctx->mod, bit_size);
14197ec681f3Smrg   if (!type)
14207ec681f3Smrg      return NULL;
14217ec681f3Smrg
14227ec681f3Smrg   return dxil_emit_cast(&ctx->mod, DXIL_CAST_BITCAST, type, value);
14237ec681f3Smrg}
14247ec681f3Smrg
14257ec681f3Smrgstatic void
14267ec681f3Smrgstore_ssa_def(struct ntd_context *ctx, nir_ssa_def *ssa, unsigned chan,
14277ec681f3Smrg              const struct dxil_value *value)
14287ec681f3Smrg{
14297ec681f3Smrg   assert(ssa->index < ctx->num_defs);
14307ec681f3Smrg   assert(chan < ssa->num_components);
14317ec681f3Smrg   /* We pre-defined the dest value because of a phi node, so bitcast while storing if the
14327ec681f3Smrg    * base type differs */
14337ec681f3Smrg   if (ctx->defs[ssa->index].chans[chan]) {
14347ec681f3Smrg      const struct dxil_type *expect_type = dxil_value_get_type(ctx->defs[ssa->index].chans[chan]);
14357ec681f3Smrg      const struct dxil_type *value_type = dxil_value_get_type(value);
14367ec681f3Smrg      if (dxil_type_to_nir_type(expect_type) != dxil_type_to_nir_type(value_type))
14377ec681f3Smrg         value = dxil_emit_cast(&ctx->mod, DXIL_CAST_BITCAST, expect_type, value);
14387ec681f3Smrg   }
14397ec681f3Smrg   ctx->defs[ssa->index].chans[chan] = value;
14407ec681f3Smrg}
14417ec681f3Smrg
14427ec681f3Smrgstatic void
14437ec681f3Smrgstore_dest_value(struct ntd_context *ctx, nir_dest *dest, unsigned chan,
14447ec681f3Smrg                 const struct dxil_value *value)
14457ec681f3Smrg{
14467ec681f3Smrg   assert(dest->is_ssa);
14477ec681f3Smrg   assert(value);
14487ec681f3Smrg   store_ssa_def(ctx, &dest->ssa, chan, value);
14497ec681f3Smrg}
14507ec681f3Smrg
14517ec681f3Smrgstatic void
14527ec681f3Smrgstore_dest(struct ntd_context *ctx, nir_dest *dest, unsigned chan,
14537ec681f3Smrg           const struct dxil_value *value, nir_alu_type type)
14547ec681f3Smrg{
14557ec681f3Smrg   switch (nir_alu_type_get_base_type(type)) {
14567ec681f3Smrg   case nir_type_float:
14577ec681f3Smrg      if (nir_dest_bit_size(*dest) == 64)
14587ec681f3Smrg         ctx->mod.feats.doubles = true;
14597ec681f3Smrg      FALLTHROUGH;
14607ec681f3Smrg   case nir_type_uint:
14617ec681f3Smrg   case nir_type_int:
14627ec681f3Smrg      if (nir_dest_bit_size(*dest) == 16)
14637ec681f3Smrg         ctx->mod.feats.native_low_precision = true;
14647ec681f3Smrg      if (nir_dest_bit_size(*dest) == 64)
14657ec681f3Smrg         ctx->mod.feats.int64_ops = true;
14667ec681f3Smrg      FALLTHROUGH;
14677ec681f3Smrg   case nir_type_bool:
14687ec681f3Smrg      store_dest_value(ctx, dest, chan, value);
14697ec681f3Smrg      break;
14707ec681f3Smrg   default:
14717ec681f3Smrg      unreachable("unexpected nir_alu_type");
14727ec681f3Smrg   }
14737ec681f3Smrg}
14747ec681f3Smrg
14757ec681f3Smrgstatic void
14767ec681f3Smrgstore_alu_dest(struct ntd_context *ctx, nir_alu_instr *alu, unsigned chan,
14777ec681f3Smrg               const struct dxil_value *value)
14787ec681f3Smrg{
14797ec681f3Smrg   assert(!alu->dest.saturate);
14807ec681f3Smrg   store_dest(ctx, &alu->dest.dest, chan, value,
14817ec681f3Smrg              nir_op_infos[alu->op].output_type);
14827ec681f3Smrg}
14837ec681f3Smrg
14847ec681f3Smrgstatic const struct dxil_value *
14857ec681f3Smrgget_src_ssa(struct ntd_context *ctx, const nir_ssa_def *ssa, unsigned chan)
14867ec681f3Smrg{
14877ec681f3Smrg   assert(ssa->index < ctx->num_defs);
14887ec681f3Smrg   assert(chan < ssa->num_components);
14897ec681f3Smrg   assert(ctx->defs[ssa->index].chans[chan]);
14907ec681f3Smrg   return ctx->defs[ssa->index].chans[chan];
14917ec681f3Smrg}
14927ec681f3Smrg
14937ec681f3Smrgstatic const struct dxil_value *
14947ec681f3Smrgget_src(struct ntd_context *ctx, nir_src *src, unsigned chan,
14957ec681f3Smrg        nir_alu_type type)
14967ec681f3Smrg{
14977ec681f3Smrg   assert(src->is_ssa);
14987ec681f3Smrg   const struct dxil_value *value = get_src_ssa(ctx, src->ssa, chan);
14997ec681f3Smrg
15007ec681f3Smrg   const int bit_size = nir_src_bit_size(*src);
15017ec681f3Smrg
15027ec681f3Smrg   switch (nir_alu_type_get_base_type(type)) {
15037ec681f3Smrg   case nir_type_int:
15047ec681f3Smrg   case nir_type_uint: {
15057ec681f3Smrg      assert(bit_size != 64 || ctx->mod.feats.int64_ops);
15067ec681f3Smrg      const struct dxil_type *expect_type =  dxil_module_get_int_type(&ctx->mod, bit_size);
15077ec681f3Smrg      /* nohing to do */
15087ec681f3Smrg      if (dxil_value_type_equal_to(value, expect_type))
15097ec681f3Smrg         return value;
15107ec681f3Smrg      assert(dxil_value_type_bitsize_equal_to(value, bit_size));
15117ec681f3Smrg      return bitcast_to_int(ctx,  bit_size, value);
15127ec681f3Smrg      }
15137ec681f3Smrg
15147ec681f3Smrg   case nir_type_float:
15157ec681f3Smrg      assert(nir_src_bit_size(*src) >= 16);
15167ec681f3Smrg      assert(nir_src_bit_size(*src) != 64 || (ctx->mod.feats.doubles &&
15177ec681f3Smrg                                              ctx->mod.feats.int64_ops));
15187ec681f3Smrg      if (dxil_value_type_equal_to(value, dxil_module_get_float_type(&ctx->mod, bit_size)))
15197ec681f3Smrg         return value;
15207ec681f3Smrg      assert(dxil_value_type_bitsize_equal_to(value, bit_size));
15217ec681f3Smrg      return bitcast_to_float(ctx, bit_size, value);
15227ec681f3Smrg
15237ec681f3Smrg   case nir_type_bool:
15247ec681f3Smrg      if (!dxil_value_type_bitsize_equal_to(value, 1)) {
15257ec681f3Smrg         return dxil_emit_cast(&ctx->mod, DXIL_CAST_TRUNC,
15267ec681f3Smrg                               dxil_module_get_int_type(&ctx->mod, 1), value);
15277ec681f3Smrg      }
15287ec681f3Smrg      return value;
15297ec681f3Smrg
15307ec681f3Smrg   default:
15317ec681f3Smrg      unreachable("unexpected nir_alu_type");
15327ec681f3Smrg   }
15337ec681f3Smrg}
15347ec681f3Smrg
15357ec681f3Smrgstatic const struct dxil_type *
15367ec681f3Smrgget_alu_src_type(struct ntd_context *ctx, nir_alu_instr *alu, unsigned src)
15377ec681f3Smrg{
15387ec681f3Smrg   assert(!alu->src[src].abs);
15397ec681f3Smrg   assert(!alu->src[src].negate);
15407ec681f3Smrg   nir_ssa_def *ssa_src = alu->src[src].src.ssa;
15417ec681f3Smrg   unsigned chan = alu->src[src].swizzle[0];
15427ec681f3Smrg   const struct dxil_value *value = get_src_ssa(ctx, ssa_src, chan);
15437ec681f3Smrg   return dxil_value_get_type(value);
15447ec681f3Smrg}
15457ec681f3Smrg
15467ec681f3Smrgstatic const struct dxil_value *
15477ec681f3Smrgget_alu_src(struct ntd_context *ctx, nir_alu_instr *alu, unsigned src)
15487ec681f3Smrg{
15497ec681f3Smrg   assert(!alu->src[src].abs);
15507ec681f3Smrg   assert(!alu->src[src].negate);
15517ec681f3Smrg
15527ec681f3Smrg   unsigned chan = alu->src[src].swizzle[0];
15537ec681f3Smrg   return get_src(ctx, &alu->src[src].src, chan,
15547ec681f3Smrg                  nir_op_infos[alu->op].input_types[src]);
15557ec681f3Smrg}
15567ec681f3Smrg
15577ec681f3Smrgstatic bool
15587ec681f3Smrgemit_binop(struct ntd_context *ctx, nir_alu_instr *alu,
15597ec681f3Smrg           enum dxil_bin_opcode opcode,
15607ec681f3Smrg           const struct dxil_value *op0, const struct dxil_value *op1)
15617ec681f3Smrg{
15627ec681f3Smrg   bool is_float_op = nir_alu_type_get_base_type(nir_op_infos[alu->op].output_type) == nir_type_float;
15637ec681f3Smrg
15647ec681f3Smrg   enum dxil_opt_flags flags = 0;
15657ec681f3Smrg   if (is_float_op && !alu->exact)
15667ec681f3Smrg      flags |= DXIL_UNSAFE_ALGEBRA;
15677ec681f3Smrg
15687ec681f3Smrg   const struct dxil_value *v = dxil_emit_binop(&ctx->mod, opcode, op0, op1, flags);
15697ec681f3Smrg   if (!v)
15707ec681f3Smrg      return false;
15717ec681f3Smrg   store_alu_dest(ctx, alu, 0, v);
15727ec681f3Smrg   return true;
15737ec681f3Smrg}
15747ec681f3Smrg
15757ec681f3Smrgstatic bool
15767ec681f3Smrgemit_shift(struct ntd_context *ctx, nir_alu_instr *alu,
15777ec681f3Smrg           enum dxil_bin_opcode opcode,
15787ec681f3Smrg           const struct dxil_value *op0, const struct dxil_value *op1)
15797ec681f3Smrg{
15807ec681f3Smrg   unsigned op0_bit_size = nir_src_bit_size(alu->src[0].src);
15817ec681f3Smrg   unsigned op1_bit_size = nir_src_bit_size(alu->src[1].src);
15827ec681f3Smrg   if (op0_bit_size != op1_bit_size) {
15837ec681f3Smrg      const struct dxil_type *type =
15847ec681f3Smrg         dxil_module_get_int_type(&ctx->mod, op0_bit_size);
15857ec681f3Smrg      enum dxil_cast_opcode cast_op =
15867ec681f3Smrg         op1_bit_size < op0_bit_size ? DXIL_CAST_ZEXT : DXIL_CAST_TRUNC;
15877ec681f3Smrg      op1 = dxil_emit_cast(&ctx->mod, cast_op, type, op1);
15887ec681f3Smrg   }
15897ec681f3Smrg
15907ec681f3Smrg   const struct dxil_value *v =
15917ec681f3Smrg      dxil_emit_binop(&ctx->mod, opcode, op0, op1, 0);
15927ec681f3Smrg   if (!v)
15937ec681f3Smrg      return false;
15947ec681f3Smrg   store_alu_dest(ctx, alu, 0, v);
15957ec681f3Smrg   return true;
15967ec681f3Smrg}
15977ec681f3Smrg
15987ec681f3Smrgstatic bool
15997ec681f3Smrgemit_cmp(struct ntd_context *ctx, nir_alu_instr *alu,
16007ec681f3Smrg         enum dxil_cmp_pred pred,
16017ec681f3Smrg         const struct dxil_value *op0, const struct dxil_value *op1)
16027ec681f3Smrg{
16037ec681f3Smrg   const struct dxil_value *v = dxil_emit_cmp(&ctx->mod, pred, op0, op1);
16047ec681f3Smrg   if (!v)
16057ec681f3Smrg      return false;
16067ec681f3Smrg   store_alu_dest(ctx, alu, 0, v);
16077ec681f3Smrg   return true;
16087ec681f3Smrg}
16097ec681f3Smrg
16107ec681f3Smrgstatic enum dxil_cast_opcode
16117ec681f3Smrgget_cast_op(nir_alu_instr *alu)
16127ec681f3Smrg{
16137ec681f3Smrg   unsigned dst_bits = nir_dest_bit_size(alu->dest.dest);
16147ec681f3Smrg   unsigned src_bits = nir_src_bit_size(alu->src[0].src);
16157ec681f3Smrg
16167ec681f3Smrg   switch (alu->op) {
16177ec681f3Smrg   /* bool -> int */
16187ec681f3Smrg   case nir_op_b2i16:
16197ec681f3Smrg   case nir_op_b2i32:
16207ec681f3Smrg   case nir_op_b2i64:
16217ec681f3Smrg      return DXIL_CAST_ZEXT;
16227ec681f3Smrg
16237ec681f3Smrg   /* float -> float */
16247ec681f3Smrg   case nir_op_f2f16_rtz:
16257ec681f3Smrg   case nir_op_f2f32:
16267ec681f3Smrg   case nir_op_f2f64:
16277ec681f3Smrg      assert(dst_bits != src_bits);
16287ec681f3Smrg      if (dst_bits < src_bits)
16297ec681f3Smrg         return DXIL_CAST_FPTRUNC;
16307ec681f3Smrg      else
16317ec681f3Smrg         return DXIL_CAST_FPEXT;
16327ec681f3Smrg
16337ec681f3Smrg   /* int -> int */
16347ec681f3Smrg   case nir_op_i2i16:
16357ec681f3Smrg   case nir_op_i2i32:
16367ec681f3Smrg   case nir_op_i2i64:
16377ec681f3Smrg      assert(dst_bits != src_bits);
16387ec681f3Smrg      if (dst_bits < src_bits)
16397ec681f3Smrg         return DXIL_CAST_TRUNC;
16407ec681f3Smrg      else
16417ec681f3Smrg         return DXIL_CAST_SEXT;
16427ec681f3Smrg
16437ec681f3Smrg   /* uint -> uint */
16447ec681f3Smrg   case nir_op_u2u16:
16457ec681f3Smrg   case nir_op_u2u32:
16467ec681f3Smrg   case nir_op_u2u64:
16477ec681f3Smrg      assert(dst_bits != src_bits);
16487ec681f3Smrg      if (dst_bits < src_bits)
16497ec681f3Smrg         return DXIL_CAST_TRUNC;
16507ec681f3Smrg      else
16517ec681f3Smrg         return DXIL_CAST_ZEXT;
16527ec681f3Smrg
16537ec681f3Smrg   /* float -> int */
16547ec681f3Smrg   case nir_op_f2i16:
16557ec681f3Smrg   case nir_op_f2i32:
16567ec681f3Smrg   case nir_op_f2i64:
16577ec681f3Smrg      return DXIL_CAST_FPTOSI;
16587ec681f3Smrg
16597ec681f3Smrg   /* float -> uint */
16607ec681f3Smrg   case nir_op_f2u16:
16617ec681f3Smrg   case nir_op_f2u32:
16627ec681f3Smrg   case nir_op_f2u64:
16637ec681f3Smrg      return DXIL_CAST_FPTOUI;
16647ec681f3Smrg
16657ec681f3Smrg   /* int -> float */
16667ec681f3Smrg   case nir_op_i2f16:
16677ec681f3Smrg   case nir_op_i2f32:
16687ec681f3Smrg   case nir_op_i2f64:
16697ec681f3Smrg      return DXIL_CAST_SITOFP;
16707ec681f3Smrg
16717ec681f3Smrg   /* uint -> float */
16727ec681f3Smrg   case nir_op_u2f16:
16737ec681f3Smrg   case nir_op_u2f32:
16747ec681f3Smrg   case nir_op_u2f64:
16757ec681f3Smrg      return DXIL_CAST_UITOFP;
16767ec681f3Smrg
16777ec681f3Smrg   default:
16787ec681f3Smrg      unreachable("unexpected cast op");
16797ec681f3Smrg   }
16807ec681f3Smrg}
16817ec681f3Smrg
16827ec681f3Smrgstatic const struct dxil_type *
16837ec681f3Smrgget_cast_dest_type(struct ntd_context *ctx, nir_alu_instr *alu)
16847ec681f3Smrg{
16857ec681f3Smrg   unsigned dst_bits = nir_dest_bit_size(alu->dest.dest);
16867ec681f3Smrg   switch (nir_alu_type_get_base_type(nir_op_infos[alu->op].output_type)) {
16877ec681f3Smrg   case nir_type_bool:
16887ec681f3Smrg      assert(dst_bits == 1);
16897ec681f3Smrg      FALLTHROUGH;
16907ec681f3Smrg   case nir_type_int:
16917ec681f3Smrg   case nir_type_uint:
16927ec681f3Smrg      return dxil_module_get_int_type(&ctx->mod, dst_bits);
16937ec681f3Smrg
16947ec681f3Smrg   case nir_type_float:
16957ec681f3Smrg      return dxil_module_get_float_type(&ctx->mod, dst_bits);
16967ec681f3Smrg
16977ec681f3Smrg   default:
16987ec681f3Smrg      unreachable("unknown nir_alu_type");
16997ec681f3Smrg   }
17007ec681f3Smrg}
17017ec681f3Smrg
17027ec681f3Smrgstatic bool
17037ec681f3Smrgis_double(nir_alu_type alu_type, unsigned bit_size)
17047ec681f3Smrg{
17057ec681f3Smrg   return nir_alu_type_get_base_type(alu_type) == nir_type_float &&
17067ec681f3Smrg          bit_size == 64;
17077ec681f3Smrg}
17087ec681f3Smrg
17097ec681f3Smrgstatic bool
17107ec681f3Smrgemit_cast(struct ntd_context *ctx, nir_alu_instr *alu,
17117ec681f3Smrg          const struct dxil_value *value)
17127ec681f3Smrg{
17137ec681f3Smrg   enum dxil_cast_opcode opcode = get_cast_op(alu);
17147ec681f3Smrg   const struct dxil_type *type = get_cast_dest_type(ctx, alu);
17157ec681f3Smrg   if (!type)
17167ec681f3Smrg      return false;
17177ec681f3Smrg
17187ec681f3Smrg   const nir_op_info *info = &nir_op_infos[alu->op];
17197ec681f3Smrg   switch (opcode) {
17207ec681f3Smrg   case DXIL_CAST_UITOFP:
17217ec681f3Smrg   case DXIL_CAST_SITOFP:
17227ec681f3Smrg      if (is_double(info->output_type, nir_dest_bit_size(alu->dest.dest)))
17237ec681f3Smrg         ctx->mod.feats.dx11_1_double_extensions = true;
17247ec681f3Smrg      break;
17257ec681f3Smrg   case DXIL_CAST_FPTOUI:
17267ec681f3Smrg   case DXIL_CAST_FPTOSI:
17277ec681f3Smrg      if (is_double(info->input_types[0], nir_src_bit_size(alu->src[0].src)))
17287ec681f3Smrg         ctx->mod.feats.dx11_1_double_extensions = true;
17297ec681f3Smrg      break;
17307ec681f3Smrg   default:
17317ec681f3Smrg      break;
17327ec681f3Smrg   }
17337ec681f3Smrg
17347ec681f3Smrg   const struct dxil_value *v = dxil_emit_cast(&ctx->mod, opcode, type,
17357ec681f3Smrg                                               value);
17367ec681f3Smrg   if (!v)
17377ec681f3Smrg      return false;
17387ec681f3Smrg   store_alu_dest(ctx, alu, 0, v);
17397ec681f3Smrg   return true;
17407ec681f3Smrg}
17417ec681f3Smrg
17427ec681f3Smrgstatic enum overload_type
17437ec681f3Smrgget_overload(nir_alu_type alu_type, unsigned bit_size)
17447ec681f3Smrg{
17457ec681f3Smrg   switch (nir_alu_type_get_base_type(alu_type)) {
17467ec681f3Smrg   case nir_type_int:
17477ec681f3Smrg   case nir_type_uint:
17487ec681f3Smrg      switch (bit_size) {
17497ec681f3Smrg      case 16: return DXIL_I16;
17507ec681f3Smrg      case 32: return DXIL_I32;
17517ec681f3Smrg      case 64: return DXIL_I64;
17527ec681f3Smrg      default:
17537ec681f3Smrg         unreachable("unexpected bit_size");
17547ec681f3Smrg      }
17557ec681f3Smrg   case nir_type_float:
17567ec681f3Smrg      switch (bit_size) {
17577ec681f3Smrg      case 16: return DXIL_F16;
17587ec681f3Smrg      case 32: return DXIL_F32;
17597ec681f3Smrg      case 64: return DXIL_F64;
17607ec681f3Smrg      default:
17617ec681f3Smrg         unreachable("unexpected bit_size");
17627ec681f3Smrg      }
17637ec681f3Smrg   default:
17647ec681f3Smrg      unreachable("unexpected output type");
17657ec681f3Smrg   }
17667ec681f3Smrg}
17677ec681f3Smrg
17687ec681f3Smrgstatic bool
17697ec681f3Smrgemit_unary_intin(struct ntd_context *ctx, nir_alu_instr *alu,
17707ec681f3Smrg                 enum dxil_intr intr, const struct dxil_value *op)
17717ec681f3Smrg{
17727ec681f3Smrg   const nir_op_info *info = &nir_op_infos[alu->op];
17737ec681f3Smrg   unsigned src_bits = nir_src_bit_size(alu->src[0].src);
17747ec681f3Smrg   enum overload_type overload = get_overload(info->input_types[0], src_bits);
17757ec681f3Smrg
17767ec681f3Smrg   const struct dxil_value *v = emit_unary_call(ctx, overload, intr, op);
17777ec681f3Smrg   if (!v)
17787ec681f3Smrg      return false;
17797ec681f3Smrg   store_alu_dest(ctx, alu, 0, v);
17807ec681f3Smrg   return true;
17817ec681f3Smrg}
17827ec681f3Smrg
17837ec681f3Smrgstatic bool
17847ec681f3Smrgemit_binary_intin(struct ntd_context *ctx, nir_alu_instr *alu,
17857ec681f3Smrg                  enum dxil_intr intr,
17867ec681f3Smrg                  const struct dxil_value *op0, const struct dxil_value *op1)
17877ec681f3Smrg{
17887ec681f3Smrg   const nir_op_info *info = &nir_op_infos[alu->op];
17897ec681f3Smrg   assert(info->output_type == info->input_types[0]);
17907ec681f3Smrg   assert(info->output_type == info->input_types[1]);
17917ec681f3Smrg   unsigned dst_bits = nir_dest_bit_size(alu->dest.dest);
17927ec681f3Smrg   assert(nir_src_bit_size(alu->src[0].src) == dst_bits);
17937ec681f3Smrg   assert(nir_src_bit_size(alu->src[1].src) == dst_bits);
17947ec681f3Smrg   enum overload_type overload = get_overload(info->output_type, dst_bits);
17957ec681f3Smrg
17967ec681f3Smrg   const struct dxil_value *v = emit_binary_call(ctx, overload, intr,
17977ec681f3Smrg                                                 op0, op1);
17987ec681f3Smrg   if (!v)
17997ec681f3Smrg      return false;
18007ec681f3Smrg   store_alu_dest(ctx, alu, 0, v);
18017ec681f3Smrg   return true;
18027ec681f3Smrg}
18037ec681f3Smrg
18047ec681f3Smrgstatic bool
18057ec681f3Smrgemit_tertiary_intin(struct ntd_context *ctx, nir_alu_instr *alu,
18067ec681f3Smrg                    enum dxil_intr intr,
18077ec681f3Smrg                    const struct dxil_value *op0,
18087ec681f3Smrg                    const struct dxil_value *op1,
18097ec681f3Smrg                    const struct dxil_value *op2)
18107ec681f3Smrg{
18117ec681f3Smrg   const nir_op_info *info = &nir_op_infos[alu->op];
18127ec681f3Smrg   assert(info->output_type == info->input_types[0]);
18137ec681f3Smrg   assert(info->output_type == info->input_types[1]);
18147ec681f3Smrg   assert(info->output_type == info->input_types[2]);
18157ec681f3Smrg
18167ec681f3Smrg   unsigned dst_bits = nir_dest_bit_size(alu->dest.dest);
18177ec681f3Smrg   assert(nir_src_bit_size(alu->src[0].src) == dst_bits);
18187ec681f3Smrg   assert(nir_src_bit_size(alu->src[1].src) == dst_bits);
18197ec681f3Smrg   assert(nir_src_bit_size(alu->src[2].src) == dst_bits);
18207ec681f3Smrg
18217ec681f3Smrg   enum overload_type overload = get_overload(info->output_type, dst_bits);
18227ec681f3Smrg
18237ec681f3Smrg   const struct dxil_value *v = emit_tertiary_call(ctx, overload, intr,
18247ec681f3Smrg                                                   op0, op1, op2);
18257ec681f3Smrg   if (!v)
18267ec681f3Smrg      return false;
18277ec681f3Smrg   store_alu_dest(ctx, alu, 0, v);
18287ec681f3Smrg   return true;
18297ec681f3Smrg}
18307ec681f3Smrg
18317ec681f3Smrgstatic bool emit_select(struct ntd_context *ctx, nir_alu_instr *alu,
18327ec681f3Smrg                        const struct dxil_value *sel,
18337ec681f3Smrg                        const struct dxil_value *val_true,
18347ec681f3Smrg                        const struct dxil_value *val_false)
18357ec681f3Smrg{
18367ec681f3Smrg   assert(sel);
18377ec681f3Smrg   assert(val_true);
18387ec681f3Smrg   assert(val_false);
18397ec681f3Smrg
18407ec681f3Smrg   const struct dxil_value *v = dxil_emit_select(&ctx->mod, sel, val_true, val_false);
18417ec681f3Smrg   if (!v)
18427ec681f3Smrg      return false;
18437ec681f3Smrg
18447ec681f3Smrg   store_alu_dest(ctx, alu, 0, v);
18457ec681f3Smrg   return true;
18467ec681f3Smrg}
18477ec681f3Smrg
18487ec681f3Smrgstatic bool
18497ec681f3Smrgemit_b2f16(struct ntd_context *ctx, nir_alu_instr *alu, const struct dxil_value *val)
18507ec681f3Smrg{
18517ec681f3Smrg   assert(val);
18527ec681f3Smrg
18537ec681f3Smrg   struct dxil_module *m = &ctx->mod;
18547ec681f3Smrg
18557ec681f3Smrg   const struct dxil_value *c1 = dxil_module_get_float16_const(m, 0x3C00);
18567ec681f3Smrg   const struct dxil_value *c0 = dxil_module_get_float16_const(m, 0);
18577ec681f3Smrg
18587ec681f3Smrg   if (!c0 || !c1)
18597ec681f3Smrg      return false;
18607ec681f3Smrg
18617ec681f3Smrg   return emit_select(ctx, alu, val, c1, c0);
18627ec681f3Smrg}
18637ec681f3Smrg
18647ec681f3Smrgstatic bool
18657ec681f3Smrgemit_b2f32(struct ntd_context *ctx, nir_alu_instr *alu, const struct dxil_value *val)
18667ec681f3Smrg{
18677ec681f3Smrg   assert(val);
18687ec681f3Smrg
18697ec681f3Smrg   struct dxil_module *m = &ctx->mod;
18707ec681f3Smrg
18717ec681f3Smrg   const struct dxil_value *c1 = dxil_module_get_float_const(m, 1.0f);
18727ec681f3Smrg   const struct dxil_value *c0 = dxil_module_get_float_const(m, 0.0f);
18737ec681f3Smrg
18747ec681f3Smrg   if (!c0 || !c1)
18757ec681f3Smrg      return false;
18767ec681f3Smrg
18777ec681f3Smrg   return emit_select(ctx, alu, val, c1, c0);
18787ec681f3Smrg}
18797ec681f3Smrg
18807ec681f3Smrgstatic bool
18817ec681f3Smrgemit_f2b32(struct ntd_context *ctx, nir_alu_instr *alu, const struct dxil_value *val)
18827ec681f3Smrg{
18837ec681f3Smrg   assert(val);
18847ec681f3Smrg
18857ec681f3Smrg   const struct dxil_value *zero = dxil_module_get_float_const(&ctx->mod, 0.0f);
18867ec681f3Smrg   return emit_cmp(ctx, alu, DXIL_FCMP_UNE, val, zero);
18877ec681f3Smrg}
18887ec681f3Smrg
18897ec681f3Smrgstatic bool
18907ec681f3Smrgemit_ufind_msb(struct ntd_context *ctx, nir_alu_instr *alu,
18917ec681f3Smrg               const struct dxil_value *val)
18927ec681f3Smrg{
18937ec681f3Smrg   const nir_op_info *info = &nir_op_infos[alu->op];
18947ec681f3Smrg   unsigned dst_bits = nir_dest_bit_size(alu->dest.dest);
18957ec681f3Smrg   unsigned src_bits = nir_src_bit_size(alu->src[0].src);
18967ec681f3Smrg   enum overload_type overload = get_overload(info->output_type, src_bits);
18977ec681f3Smrg
18987ec681f3Smrg   const struct dxil_value *v = emit_unary_call(ctx, overload,
18997ec681f3Smrg                                                DXIL_INTR_FIRSTBIT_HI, val);
19007ec681f3Smrg   if (!v)
19017ec681f3Smrg      return false;
19027ec681f3Smrg
19037ec681f3Smrg   const struct dxil_value *size = dxil_module_get_int32_const(&ctx->mod,
19047ec681f3Smrg      src_bits - 1);
19057ec681f3Smrg   const struct dxil_value *zero = dxil_module_get_int_const(&ctx->mod, 0,
19067ec681f3Smrg                                                             src_bits);
19077ec681f3Smrg   if (!size || !zero)
19087ec681f3Smrg      return false;
19097ec681f3Smrg
19107ec681f3Smrg   v = dxil_emit_binop(&ctx->mod, DXIL_BINOP_SUB, size, v, 0);
19117ec681f3Smrg   const struct dxil_value *cnd = dxil_emit_cmp(&ctx->mod, DXIL_ICMP_NE,
19127ec681f3Smrg                                                val, zero);
19137ec681f3Smrg   if (!v || !cnd)
19147ec681f3Smrg      return false;
19157ec681f3Smrg
19167ec681f3Smrg   const struct dxil_value *minus_one =
19177ec681f3Smrg      dxil_module_get_int_const(&ctx->mod, -1, dst_bits);
19187ec681f3Smrg   if (!minus_one)
19197ec681f3Smrg      return false;
19207ec681f3Smrg
19217ec681f3Smrg   v = dxil_emit_select(&ctx->mod, cnd, v, minus_one);
19227ec681f3Smrg   if (!v)
19237ec681f3Smrg      return false;
19247ec681f3Smrg
19257ec681f3Smrg   store_alu_dest(ctx, alu, 0, v);
19267ec681f3Smrg   return true;
19277ec681f3Smrg}
19287ec681f3Smrg
19297ec681f3Smrgstatic bool
19307ec681f3Smrgemit_f16tof32(struct ntd_context *ctx, nir_alu_instr *alu, const struct dxil_value *val)
19317ec681f3Smrg{
19327ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod,
19337ec681f3Smrg                                                    "dx.op.legacyF16ToF32",
19347ec681f3Smrg                                                    DXIL_NONE);
19357ec681f3Smrg   if (!func)
19367ec681f3Smrg      return false;
19377ec681f3Smrg
19387ec681f3Smrg   const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_LEGACY_F16TOF32);
19397ec681f3Smrg   if (!opcode)
19407ec681f3Smrg      return false;
19417ec681f3Smrg
19427ec681f3Smrg   const struct dxil_value *args[] = {
19437ec681f3Smrg     opcode,
19447ec681f3Smrg     val
19457ec681f3Smrg   };
19467ec681f3Smrg
19477ec681f3Smrg   const struct dxil_value *v = dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args));
19487ec681f3Smrg   if (!v)
19497ec681f3Smrg      return false;
19507ec681f3Smrg   store_alu_dest(ctx, alu, 0, v);
19517ec681f3Smrg   return true;
19527ec681f3Smrg}
19537ec681f3Smrg
19547ec681f3Smrgstatic bool
19557ec681f3Smrgemit_f32tof16(struct ntd_context *ctx, nir_alu_instr *alu, const struct dxil_value *val)
19567ec681f3Smrg{
19577ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod,
19587ec681f3Smrg                                                    "dx.op.legacyF32ToF16",
19597ec681f3Smrg                                                    DXIL_NONE);
19607ec681f3Smrg   if (!func)
19617ec681f3Smrg      return false;
19627ec681f3Smrg
19637ec681f3Smrg   const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_LEGACY_F32TOF16);
19647ec681f3Smrg   if (!opcode)
19657ec681f3Smrg      return false;
19667ec681f3Smrg
19677ec681f3Smrg   const struct dxil_value *args[] = {
19687ec681f3Smrg     opcode,
19697ec681f3Smrg     val
19707ec681f3Smrg   };
19717ec681f3Smrg
19727ec681f3Smrg   const struct dxil_value *v = dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args));
19737ec681f3Smrg   if (!v)
19747ec681f3Smrg      return false;
19757ec681f3Smrg   store_alu_dest(ctx, alu, 0, v);
19767ec681f3Smrg   return true;
19777ec681f3Smrg}
19787ec681f3Smrg
19797ec681f3Smrgstatic bool
19807ec681f3Smrgemit_vec(struct ntd_context *ctx, nir_alu_instr *alu, unsigned num_inputs)
19817ec681f3Smrg{
19827ec681f3Smrg   const struct dxil_type *type = get_alu_src_type(ctx, alu, 0);
19837ec681f3Smrg   nir_alu_type t = dxil_type_to_nir_type(type);
19847ec681f3Smrg
19857ec681f3Smrg   for (unsigned i = 0; i < num_inputs; i++) {
19867ec681f3Smrg      const struct dxil_value *src =
19877ec681f3Smrg         get_src(ctx, &alu->src[i].src, alu->src[i].swizzle[0], t);
19887ec681f3Smrg      if (!src)
19897ec681f3Smrg         return false;
19907ec681f3Smrg
19917ec681f3Smrg      store_alu_dest(ctx, alu, i, src);
19927ec681f3Smrg   }
19937ec681f3Smrg   return true;
19947ec681f3Smrg}
19957ec681f3Smrg
19967ec681f3Smrgstatic bool
19977ec681f3Smrgemit_make_double(struct ntd_context *ctx, nir_alu_instr *alu)
19987ec681f3Smrg{
19997ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.makeDouble", DXIL_F64);
20007ec681f3Smrg   if (!func)
20017ec681f3Smrg      return false;
20027ec681f3Smrg
20037ec681f3Smrg   const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_MAKE_DOUBLE);
20047ec681f3Smrg   if (!opcode)
20057ec681f3Smrg      return false;
20067ec681f3Smrg
20077ec681f3Smrg   const struct dxil_value *args[3] = {
20087ec681f3Smrg      opcode,
20097ec681f3Smrg      get_src(ctx, &alu->src[0].src, 0, nir_type_uint32),
20107ec681f3Smrg      get_src(ctx, &alu->src[0].src, 1, nir_type_uint32),
20117ec681f3Smrg   };
20127ec681f3Smrg   if (!args[1] || !args[2])
20137ec681f3Smrg      return false;
20147ec681f3Smrg
20157ec681f3Smrg   const struct dxil_value *v = dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args));
20167ec681f3Smrg   if (!v)
20177ec681f3Smrg      return false;
20187ec681f3Smrg   store_dest(ctx, &alu->dest.dest, 0, v, nir_type_float64);
20197ec681f3Smrg   return true;
20207ec681f3Smrg}
20217ec681f3Smrg
20227ec681f3Smrgstatic bool
20237ec681f3Smrgemit_split_double(struct ntd_context *ctx, nir_alu_instr *alu)
20247ec681f3Smrg{
20257ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.splitDouble", DXIL_F64);
20267ec681f3Smrg   if (!func)
20277ec681f3Smrg      return false;
20287ec681f3Smrg
20297ec681f3Smrg   const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_SPLIT_DOUBLE);
20307ec681f3Smrg   if (!opcode)
20317ec681f3Smrg      return false;
20327ec681f3Smrg
20337ec681f3Smrg   const struct dxil_value *args[] = {
20347ec681f3Smrg      opcode,
20357ec681f3Smrg      get_src(ctx, &alu->src[0].src, 0, nir_type_float64)
20367ec681f3Smrg   };
20377ec681f3Smrg   if (!args[1])
20387ec681f3Smrg      return false;
20397ec681f3Smrg
20407ec681f3Smrg   const struct dxil_value *v = dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args));
20417ec681f3Smrg   if (!v)
20427ec681f3Smrg      return false;
20437ec681f3Smrg
20447ec681f3Smrg   const struct dxil_value *hi = dxil_emit_extractval(&ctx->mod, v, 0);
20457ec681f3Smrg   const struct dxil_value *lo = dxil_emit_extractval(&ctx->mod, v, 1);
20467ec681f3Smrg   if (!hi || !lo)
20477ec681f3Smrg      return false;
20487ec681f3Smrg
20497ec681f3Smrg   store_dest_value(ctx, &alu->dest.dest, 0, hi);
20507ec681f3Smrg   store_dest_value(ctx, &alu->dest.dest, 1, lo);
20517ec681f3Smrg   return true;
20527ec681f3Smrg}
20537ec681f3Smrg
20547ec681f3Smrgstatic bool
20557ec681f3Smrgemit_alu(struct ntd_context *ctx, nir_alu_instr *alu)
20567ec681f3Smrg{
20577ec681f3Smrg   /* handle vec-instructions first; they are the only ones that produce
20587ec681f3Smrg    * vector results.
20597ec681f3Smrg    */
20607ec681f3Smrg   switch (alu->op) {
20617ec681f3Smrg   case nir_op_vec2:
20627ec681f3Smrg   case nir_op_vec3:
20637ec681f3Smrg   case nir_op_vec4:
20647ec681f3Smrg   case nir_op_vec8:
20657ec681f3Smrg   case nir_op_vec16:
20667ec681f3Smrg      return emit_vec(ctx, alu, nir_op_infos[alu->op].num_inputs);
20677ec681f3Smrg   case nir_op_mov: {
20687ec681f3Smrg         assert(nir_dest_num_components(alu->dest.dest) == 1);
20697ec681f3Smrg         store_ssa_def(ctx, &alu->dest.dest.ssa, 0, get_src_ssa(ctx,
20707ec681f3Smrg                        alu->src->src.ssa, alu->src->swizzle[0]));
20717ec681f3Smrg         return true;
20727ec681f3Smrg      }
20737ec681f3Smrg   case nir_op_pack_double_2x32_dxil:
20747ec681f3Smrg      return emit_make_double(ctx, alu);
20757ec681f3Smrg   case nir_op_unpack_double_2x32_dxil:
20767ec681f3Smrg      return emit_split_double(ctx, alu);
20777ec681f3Smrg   default:
20787ec681f3Smrg      /* silence warnings */
20797ec681f3Smrg      ;
20807ec681f3Smrg   }
20817ec681f3Smrg
20827ec681f3Smrg   /* other ops should be scalar */
20837ec681f3Smrg   assert(alu->dest.write_mask == 1);
20847ec681f3Smrg   const struct dxil_value *src[4];
20857ec681f3Smrg   assert(nir_op_infos[alu->op].num_inputs <= 4);
20867ec681f3Smrg   for (unsigned i = 0; i < nir_op_infos[alu->op].num_inputs; i++) {
20877ec681f3Smrg      src[i] = get_alu_src(ctx, alu, i);
20887ec681f3Smrg      if (!src[i])
20897ec681f3Smrg         return false;
20907ec681f3Smrg   }
20917ec681f3Smrg
20927ec681f3Smrg   switch (alu->op) {
20937ec681f3Smrg   case nir_op_iadd:
20947ec681f3Smrg   case nir_op_fadd: return emit_binop(ctx, alu, DXIL_BINOP_ADD, src[0], src[1]);
20957ec681f3Smrg
20967ec681f3Smrg   case nir_op_isub:
20977ec681f3Smrg   case nir_op_fsub: return emit_binop(ctx, alu, DXIL_BINOP_SUB, src[0], src[1]);
20987ec681f3Smrg
20997ec681f3Smrg   case nir_op_imul:
21007ec681f3Smrg   case nir_op_fmul: return emit_binop(ctx, alu, DXIL_BINOP_MUL, src[0], src[1]);
21017ec681f3Smrg
21027ec681f3Smrg   case nir_op_idiv:
21037ec681f3Smrg   case nir_op_fdiv: return emit_binop(ctx, alu, DXIL_BINOP_SDIV, src[0], src[1]);
21047ec681f3Smrg
21057ec681f3Smrg   case nir_op_udiv: return emit_binop(ctx, alu, DXIL_BINOP_UDIV, src[0], src[1]);
21067ec681f3Smrg   case nir_op_irem: return emit_binop(ctx, alu, DXIL_BINOP_SREM, src[0], src[1]);
21077ec681f3Smrg   case nir_op_imod: return emit_binop(ctx, alu, DXIL_BINOP_UREM, src[0], src[1]);
21087ec681f3Smrg   case nir_op_umod: return emit_binop(ctx, alu, DXIL_BINOP_UREM, src[0], src[1]);
21097ec681f3Smrg   case nir_op_ishl: return emit_shift(ctx, alu, DXIL_BINOP_SHL, src[0], src[1]);
21107ec681f3Smrg   case nir_op_ishr: return emit_shift(ctx, alu, DXIL_BINOP_ASHR, src[0], src[1]);
21117ec681f3Smrg   case nir_op_ushr: return emit_shift(ctx, alu, DXIL_BINOP_LSHR, src[0], src[1]);
21127ec681f3Smrg   case nir_op_iand: return emit_binop(ctx, alu, DXIL_BINOP_AND, src[0], src[1]);
21137ec681f3Smrg   case nir_op_ior:  return emit_binop(ctx, alu, DXIL_BINOP_OR, src[0], src[1]);
21147ec681f3Smrg   case nir_op_ixor: return emit_binop(ctx, alu, DXIL_BINOP_XOR, src[0], src[1]);
21157ec681f3Smrg   case nir_op_inot: {
21167ec681f3Smrg      unsigned bit_size = alu->dest.dest.ssa.bit_size;
21177ec681f3Smrg      intmax_t val = bit_size == 1 ? 1 : -1;
21187ec681f3Smrg      const struct dxil_value *negative_one = dxil_module_get_int_const(&ctx->mod, val, bit_size);
21197ec681f3Smrg      return emit_binop(ctx, alu, DXIL_BINOP_XOR, src[0], negative_one);
21207ec681f3Smrg   }
21217ec681f3Smrg   case nir_op_ieq:  return emit_cmp(ctx, alu, DXIL_ICMP_EQ, src[0], src[1]);
21227ec681f3Smrg   case nir_op_ine:  return emit_cmp(ctx, alu, DXIL_ICMP_NE, src[0], src[1]);
21237ec681f3Smrg   case nir_op_ige:  return emit_cmp(ctx, alu, DXIL_ICMP_SGE, src[0], src[1]);
21247ec681f3Smrg   case nir_op_uge:  return emit_cmp(ctx, alu, DXIL_ICMP_UGE, src[0], src[1]);
21257ec681f3Smrg   case nir_op_ilt:  return emit_cmp(ctx, alu, DXIL_ICMP_SLT, src[0], src[1]);
21267ec681f3Smrg   case nir_op_ult:  return emit_cmp(ctx, alu, DXIL_ICMP_ULT, src[0], src[1]);
21277ec681f3Smrg   case nir_op_feq:  return emit_cmp(ctx, alu, DXIL_FCMP_OEQ, src[0], src[1]);
21287ec681f3Smrg   case nir_op_fneu: return emit_cmp(ctx, alu, DXIL_FCMP_UNE, src[0], src[1]);
21297ec681f3Smrg   case nir_op_flt:  return emit_cmp(ctx, alu, DXIL_FCMP_OLT, src[0], src[1]);
21307ec681f3Smrg   case nir_op_fge:  return emit_cmp(ctx, alu, DXIL_FCMP_OGE, src[0], src[1]);
21317ec681f3Smrg   case nir_op_bcsel: return emit_select(ctx, alu, src[0], src[1], src[2]);
21327ec681f3Smrg   case nir_op_ftrunc: return emit_unary_intin(ctx, alu, DXIL_INTR_ROUND_Z, src[0]);
21337ec681f3Smrg   case nir_op_fabs: return emit_unary_intin(ctx, alu, DXIL_INTR_FABS, src[0]);
21347ec681f3Smrg   case nir_op_fcos: return emit_unary_intin(ctx, alu, DXIL_INTR_FCOS, src[0]);
21357ec681f3Smrg   case nir_op_fsin: return emit_unary_intin(ctx, alu, DXIL_INTR_FSIN, src[0]);
21367ec681f3Smrg   case nir_op_fceil: return emit_unary_intin(ctx, alu, DXIL_INTR_ROUND_PI, src[0]);
21377ec681f3Smrg   case nir_op_fexp2: return emit_unary_intin(ctx, alu, DXIL_INTR_FEXP2, src[0]);
21387ec681f3Smrg   case nir_op_flog2: return emit_unary_intin(ctx, alu, DXIL_INTR_FLOG2, src[0]);
21397ec681f3Smrg   case nir_op_ffloor: return emit_unary_intin(ctx, alu, DXIL_INTR_ROUND_NI, src[0]);
21407ec681f3Smrg   case nir_op_ffract: return emit_unary_intin(ctx, alu, DXIL_INTR_FRC, src[0]);
21417ec681f3Smrg   case nir_op_fisnormal: return emit_unary_intin(ctx, alu, DXIL_INTR_ISNORMAL, src[0]);
21427ec681f3Smrg   case nir_op_fisfinite: return emit_unary_intin(ctx, alu, DXIL_INTR_ISFINITE, src[0]);
21437ec681f3Smrg
21447ec681f3Smrg   case nir_op_fddx:
21457ec681f3Smrg   case nir_op_fddx_coarse: return emit_unary_intin(ctx, alu, DXIL_INTR_DDX_COARSE, src[0]);
21467ec681f3Smrg   case nir_op_fddx_fine: return emit_unary_intin(ctx, alu, DXIL_INTR_DDX_FINE, src[0]);
21477ec681f3Smrg   case nir_op_fddy:
21487ec681f3Smrg   case nir_op_fddy_coarse: return emit_unary_intin(ctx, alu, DXIL_INTR_DDY_COARSE, src[0]);
21497ec681f3Smrg   case nir_op_fddy_fine: return emit_unary_intin(ctx, alu, DXIL_INTR_DDY_FINE, src[0]);
21507ec681f3Smrg
21517ec681f3Smrg   case nir_op_fround_even: return emit_unary_intin(ctx, alu, DXIL_INTR_ROUND_NE, src[0]);
21527ec681f3Smrg   case nir_op_frcp: {
21537ec681f3Smrg         const struct dxil_value *one = dxil_module_get_float_const(&ctx->mod, 1.0f);
21547ec681f3Smrg         return emit_binop(ctx, alu, DXIL_BINOP_SDIV, one, src[0]);
21557ec681f3Smrg      }
21567ec681f3Smrg   case nir_op_fsat: return emit_unary_intin(ctx, alu, DXIL_INTR_SATURATE, src[0]);
21577ec681f3Smrg   case nir_op_bit_count: return emit_unary_intin(ctx, alu, DXIL_INTR_COUNTBITS, src[0]);
21587ec681f3Smrg   case nir_op_ufind_msb: return emit_ufind_msb(ctx, alu, src[0]);
21597ec681f3Smrg   case nir_op_imax: return emit_binary_intin(ctx, alu, DXIL_INTR_IMAX, src[0], src[1]);
21607ec681f3Smrg   case nir_op_imin: return emit_binary_intin(ctx, alu, DXIL_INTR_IMIN, src[0], src[1]);
21617ec681f3Smrg   case nir_op_umax: return emit_binary_intin(ctx, alu, DXIL_INTR_UMAX, src[0], src[1]);
21627ec681f3Smrg   case nir_op_umin: return emit_binary_intin(ctx, alu, DXIL_INTR_UMIN, src[0], src[1]);
21637ec681f3Smrg   case nir_op_frsq: return emit_unary_intin(ctx, alu, DXIL_INTR_RSQRT, src[0]);
21647ec681f3Smrg   case nir_op_fsqrt: return emit_unary_intin(ctx, alu, DXIL_INTR_SQRT, src[0]);
21657ec681f3Smrg   case nir_op_fmax: return emit_binary_intin(ctx, alu, DXIL_INTR_FMAX, src[0], src[1]);
21667ec681f3Smrg   case nir_op_fmin: return emit_binary_intin(ctx, alu, DXIL_INTR_FMIN, src[0], src[1]);
21677ec681f3Smrg   case nir_op_ffma: return emit_tertiary_intin(ctx, alu, DXIL_INTR_FMA, src[0], src[1], src[2]);
21687ec681f3Smrg
21697ec681f3Smrg   case nir_op_unpack_half_2x16_split_x: return emit_f16tof32(ctx, alu, src[0]);
21707ec681f3Smrg   case nir_op_pack_half_2x16_split: return emit_f32tof16(ctx, alu, src[0]);
21717ec681f3Smrg
21727ec681f3Smrg   case nir_op_b2i16:
21737ec681f3Smrg   case nir_op_i2i16:
21747ec681f3Smrg   case nir_op_f2i16:
21757ec681f3Smrg   case nir_op_f2u16:
21767ec681f3Smrg   case nir_op_u2u16:
21777ec681f3Smrg   case nir_op_u2f16:
21787ec681f3Smrg   case nir_op_i2f16:
21797ec681f3Smrg   case nir_op_f2f16_rtz:
21807ec681f3Smrg   case nir_op_b2i32:
21817ec681f3Smrg   case nir_op_f2f32:
21827ec681f3Smrg   case nir_op_f2i32:
21837ec681f3Smrg   case nir_op_f2u32:
21847ec681f3Smrg   case nir_op_i2f32:
21857ec681f3Smrg   case nir_op_i2i32:
21867ec681f3Smrg   case nir_op_u2f32:
21877ec681f3Smrg   case nir_op_u2u32:
21887ec681f3Smrg   case nir_op_b2i64:
21897ec681f3Smrg   case nir_op_f2f64:
21907ec681f3Smrg   case nir_op_f2i64:
21917ec681f3Smrg   case nir_op_f2u64:
21927ec681f3Smrg   case nir_op_i2f64:
21937ec681f3Smrg   case nir_op_i2i64:
21947ec681f3Smrg   case nir_op_u2f64:
21957ec681f3Smrg   case nir_op_u2u64:
21967ec681f3Smrg      return emit_cast(ctx, alu, src[0]);
21977ec681f3Smrg
21987ec681f3Smrg   case nir_op_f2b32: return emit_f2b32(ctx, alu, src[0]);
21997ec681f3Smrg   case nir_op_b2f16: return emit_b2f16(ctx, alu, src[0]);
22007ec681f3Smrg   case nir_op_b2f32: return emit_b2f32(ctx, alu, src[0]);
22017ec681f3Smrg   default:
22027ec681f3Smrg      NIR_INSTR_UNSUPPORTED(&alu->instr);
22037ec681f3Smrg      assert("Unimplemented ALU instruction");
22047ec681f3Smrg      return false;
22057ec681f3Smrg   }
22067ec681f3Smrg}
22077ec681f3Smrg
22087ec681f3Smrgstatic const struct dxil_value *
22097ec681f3Smrgload_ubo(struct ntd_context *ctx, const struct dxil_value *handle,
22107ec681f3Smrg         const struct dxil_value *offset, enum overload_type overload)
22117ec681f3Smrg{
22127ec681f3Smrg   assert(handle && offset);
22137ec681f3Smrg
22147ec681f3Smrg   const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_CBUFFER_LOAD_LEGACY);
22157ec681f3Smrg   if (!opcode)
22167ec681f3Smrg      return NULL;
22177ec681f3Smrg
22187ec681f3Smrg   const struct dxil_value *args[] = {
22197ec681f3Smrg      opcode, handle, offset
22207ec681f3Smrg   };
22217ec681f3Smrg
22227ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.cbufferLoadLegacy", overload);
22237ec681f3Smrg   if (!func)
22247ec681f3Smrg      return NULL;
22257ec681f3Smrg   return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args));
22267ec681f3Smrg}
22277ec681f3Smrg
22287ec681f3Smrgstatic bool
22297ec681f3Smrgemit_barrier(struct ntd_context *ctx, nir_intrinsic_instr *intr)
22307ec681f3Smrg{
22317ec681f3Smrg   const struct dxil_value *opcode, *mode;
22327ec681f3Smrg   const struct dxil_func *func;
22337ec681f3Smrg   uint32_t flags = 0;
22347ec681f3Smrg
22357ec681f3Smrg   if (nir_intrinsic_execution_scope(intr) == NIR_SCOPE_WORKGROUP)
22367ec681f3Smrg      flags |= DXIL_BARRIER_MODE_SYNC_THREAD_GROUP;
22377ec681f3Smrg
22387ec681f3Smrg   nir_variable_mode modes = nir_intrinsic_memory_modes(intr);
22397ec681f3Smrg   nir_scope mem_scope = nir_intrinsic_memory_scope(intr);
22407ec681f3Smrg
22417ec681f3Smrg   /* Currently vtn uses uniform to indicate image memory, which DXIL considers global */
22427ec681f3Smrg   if (modes & nir_var_uniform)
22437ec681f3Smrg      modes |= nir_var_mem_global;
22447ec681f3Smrg
22457ec681f3Smrg   if (modes & (nir_var_mem_ssbo | nir_var_mem_global)) {
22467ec681f3Smrg      if (mem_scope > NIR_SCOPE_WORKGROUP)
22477ec681f3Smrg         flags |= DXIL_BARRIER_MODE_UAV_FENCE_GLOBAL;
22487ec681f3Smrg      else
22497ec681f3Smrg         flags |= DXIL_BARRIER_MODE_UAV_FENCE_THREAD_GROUP;
22507ec681f3Smrg   }
22517ec681f3Smrg
22527ec681f3Smrg   if (modes & nir_var_mem_shared)
22537ec681f3Smrg      flags |= DXIL_BARRIER_MODE_GROUPSHARED_MEM_FENCE;
22547ec681f3Smrg
22557ec681f3Smrg   func = dxil_get_function(&ctx->mod, "dx.op.barrier", DXIL_NONE);
22567ec681f3Smrg   if (!func)
22577ec681f3Smrg      return false;
22587ec681f3Smrg
22597ec681f3Smrg   opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_BARRIER);
22607ec681f3Smrg   if (!opcode)
22617ec681f3Smrg      return false;
22627ec681f3Smrg
22637ec681f3Smrg   mode = dxil_module_get_int32_const(&ctx->mod, flags);
22647ec681f3Smrg   if (!mode)
22657ec681f3Smrg      return false;
22667ec681f3Smrg
22677ec681f3Smrg   const struct dxil_value *args[] = { opcode, mode };
22687ec681f3Smrg
22697ec681f3Smrg   return dxil_emit_call_void(&ctx->mod, func,
22707ec681f3Smrg                              args, ARRAY_SIZE(args));
22717ec681f3Smrg}
22727ec681f3Smrg
22737ec681f3Smrgstatic bool
22747ec681f3Smrgemit_load_global_invocation_id(struct ntd_context *ctx,
22757ec681f3Smrg                                    nir_intrinsic_instr *intr)
22767ec681f3Smrg{
22777ec681f3Smrg   assert(intr->dest.is_ssa);
22787ec681f3Smrg   nir_component_mask_t comps = nir_ssa_def_components_read(&intr->dest.ssa);
22797ec681f3Smrg
22807ec681f3Smrg   for (int i = 0; i < nir_intrinsic_dest_components(intr); i++) {
22817ec681f3Smrg      if (comps & (1 << i)) {
22827ec681f3Smrg         const struct dxil_value *idx = dxil_module_get_int32_const(&ctx->mod, i);
22837ec681f3Smrg         if (!idx)
22847ec681f3Smrg            return false;
22857ec681f3Smrg         const struct dxil_value *globalid = emit_threadid_call(ctx, idx);
22867ec681f3Smrg
22877ec681f3Smrg         if (!globalid)
22887ec681f3Smrg            return false;
22897ec681f3Smrg
22907ec681f3Smrg         store_dest_value(ctx, &intr->dest, i, globalid);
22917ec681f3Smrg      }
22927ec681f3Smrg   }
22937ec681f3Smrg   return true;
22947ec681f3Smrg}
22957ec681f3Smrg
22967ec681f3Smrgstatic bool
22977ec681f3Smrgemit_load_local_invocation_id(struct ntd_context *ctx,
22987ec681f3Smrg                              nir_intrinsic_instr *intr)
22997ec681f3Smrg{
23007ec681f3Smrg   assert(intr->dest.is_ssa);
23017ec681f3Smrg   nir_component_mask_t comps = nir_ssa_def_components_read(&intr->dest.ssa);
23027ec681f3Smrg
23037ec681f3Smrg   for (int i = 0; i < nir_intrinsic_dest_components(intr); i++) {
23047ec681f3Smrg      if (comps & (1 << i)) {
23057ec681f3Smrg         const struct dxil_value
23067ec681f3Smrg            *idx = dxil_module_get_int32_const(&ctx->mod, i);
23077ec681f3Smrg         if (!idx)
23087ec681f3Smrg            return false;
23097ec681f3Smrg         const struct dxil_value
23107ec681f3Smrg            *threadidingroup = emit_threadidingroup_call(ctx, idx);
23117ec681f3Smrg         if (!threadidingroup)
23127ec681f3Smrg            return false;
23137ec681f3Smrg         store_dest_value(ctx, &intr->dest, i, threadidingroup);
23147ec681f3Smrg      }
23157ec681f3Smrg   }
23167ec681f3Smrg   return true;
23177ec681f3Smrg}
23187ec681f3Smrg
23197ec681f3Smrgstatic bool
23207ec681f3Smrgemit_load_local_invocation_index(struct ntd_context *ctx,
23217ec681f3Smrg                                 nir_intrinsic_instr *intr)
23227ec681f3Smrg{
23237ec681f3Smrg   assert(intr->dest.is_ssa);
23247ec681f3Smrg
23257ec681f3Smrg   const struct dxil_value
23267ec681f3Smrg      *flattenedthreadidingroup = emit_flattenedthreadidingroup_call(ctx);
23277ec681f3Smrg   if (!flattenedthreadidingroup)
23287ec681f3Smrg      return false;
23297ec681f3Smrg   store_dest_value(ctx, &intr->dest, 0, flattenedthreadidingroup);
23307ec681f3Smrg
23317ec681f3Smrg   return true;
23327ec681f3Smrg}
23337ec681f3Smrg
23347ec681f3Smrgstatic bool
23357ec681f3Smrgemit_load_local_workgroup_id(struct ntd_context *ctx,
23367ec681f3Smrg                              nir_intrinsic_instr *intr)
23377ec681f3Smrg{
23387ec681f3Smrg   assert(intr->dest.is_ssa);
23397ec681f3Smrg   nir_component_mask_t comps = nir_ssa_def_components_read(&intr->dest.ssa);
23407ec681f3Smrg
23417ec681f3Smrg   for (int i = 0; i < nir_intrinsic_dest_components(intr); i++) {
23427ec681f3Smrg      if (comps & (1 << i)) {
23437ec681f3Smrg         const struct dxil_value *idx = dxil_module_get_int32_const(&ctx->mod, i);
23447ec681f3Smrg         if (!idx)
23457ec681f3Smrg            return false;
23467ec681f3Smrg         const struct dxil_value *groupid = emit_groupid_call(ctx, idx);
23477ec681f3Smrg         if (!groupid)
23487ec681f3Smrg            return false;
23497ec681f3Smrg         store_dest_value(ctx, &intr->dest, i, groupid);
23507ec681f3Smrg      }
23517ec681f3Smrg   }
23527ec681f3Smrg   return true;
23537ec681f3Smrg}
23547ec681f3Smrg
23557ec681f3Smrgstatic bool
23567ec681f3Smrgemit_load_unary_external_function(struct ntd_context *ctx,
23577ec681f3Smrg                                  nir_intrinsic_instr *intr, const char *name,
23587ec681f3Smrg                                  int32_t dxil_intr)
23597ec681f3Smrg{
23607ec681f3Smrg   const struct dxil_func *func =
23617ec681f3Smrg      dxil_get_function(&ctx->mod, name, DXIL_I32);
23627ec681f3Smrg   if (!func)
23637ec681f3Smrg      return false;
23647ec681f3Smrg
23657ec681f3Smrg   const struct dxil_value *opcode =
23667ec681f3Smrg      dxil_module_get_int32_const(&ctx->mod, dxil_intr);
23677ec681f3Smrg   if (!opcode)
23687ec681f3Smrg      return false;
23697ec681f3Smrg
23707ec681f3Smrg   const struct dxil_value *args[] = {opcode};
23717ec681f3Smrg
23727ec681f3Smrg   const struct dxil_value *value =
23737ec681f3Smrg      dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args));
23747ec681f3Smrg   store_dest_value(ctx, &intr->dest, 0, value);
23757ec681f3Smrg
23767ec681f3Smrg   return true;
23777ec681f3Smrg}
23787ec681f3Smrg
23797ec681f3Smrgstatic const struct dxil_value *
23807ec681f3Smrgget_int32_undef(struct dxil_module *m)
23817ec681f3Smrg{
23827ec681f3Smrg   const struct dxil_type *int32_type =
23837ec681f3Smrg      dxil_module_get_int_type(m, 32);
23847ec681f3Smrg   if (!int32_type)
23857ec681f3Smrg      return NULL;
23867ec681f3Smrg
23877ec681f3Smrg   return dxil_module_get_undef(m, int32_type);
23887ec681f3Smrg}
23897ec681f3Smrg
23907ec681f3Smrgstatic const struct dxil_value *
23917ec681f3Smrgemit_gep_for_index(struct ntd_context *ctx, const nir_variable *var,
23927ec681f3Smrg                   const struct dxil_value *index)
23937ec681f3Smrg{
23947ec681f3Smrg   assert(var->data.mode == nir_var_shader_temp);
23957ec681f3Smrg
23967ec681f3Smrg   struct hash_entry *he = _mesa_hash_table_search(ctx->consts, var);
23977ec681f3Smrg   assert(he != NULL);
23987ec681f3Smrg   const struct dxil_value *ptr = he->data;
23997ec681f3Smrg
24007ec681f3Smrg   const struct dxil_value *zero = dxil_module_get_int32_const(&ctx->mod, 0);
24017ec681f3Smrg   if (!zero)
24027ec681f3Smrg      return NULL;
24037ec681f3Smrg
24047ec681f3Smrg   const struct dxil_value *ops[] = { ptr, zero, index };
24057ec681f3Smrg   return dxil_emit_gep_inbounds(&ctx->mod, ops, ARRAY_SIZE(ops));
24067ec681f3Smrg}
24077ec681f3Smrg
24087ec681f3Smrgstatic const struct dxil_value *
24097ec681f3Smrgget_ubo_ssbo_handle(struct ntd_context *ctx, nir_src *src, enum dxil_resource_class class, unsigned base_binding)
24107ec681f3Smrg{
24117ec681f3Smrg   /* This source might be one of:
24127ec681f3Smrg    * 1. Constant resource index - just look it up in precomputed handle arrays
24137ec681f3Smrg    *    If it's null in that array, create a handle, and store the result
24147ec681f3Smrg    * 2. A handle from load_vulkan_descriptor - just get the stored SSA value
24157ec681f3Smrg    * 3. Dynamic resource index - create a handle for it here
24167ec681f3Smrg    */
24177ec681f3Smrg   assert(src->ssa->num_components == 1 && src->ssa->bit_size == 32);
24187ec681f3Smrg   nir_const_value *const_block_index = nir_src_as_const_value(*src);
24197ec681f3Smrg   const struct dxil_value **handle_entry = NULL;
24207ec681f3Smrg   if (const_block_index) {
24217ec681f3Smrg      assert(!ctx->opts->vulkan_environment);
24227ec681f3Smrg      switch (class) {
24237ec681f3Smrg      case DXIL_RESOURCE_CLASS_CBV:
24247ec681f3Smrg         handle_entry = &ctx->cbv_handles[const_block_index->u32];
24257ec681f3Smrg         break;
24267ec681f3Smrg      case DXIL_RESOURCE_CLASS_UAV:
24277ec681f3Smrg         handle_entry = &ctx->uav_handles[const_block_index->u32];
24287ec681f3Smrg         break;
24297ec681f3Smrg      case DXIL_RESOURCE_CLASS_SRV:
24307ec681f3Smrg         handle_entry = &ctx->srv_handles[const_block_index->u32];
24317ec681f3Smrg         break;
24327ec681f3Smrg      default:
24337ec681f3Smrg         unreachable("Unexpected resource class");
24347ec681f3Smrg      }
24357ec681f3Smrg   }
24367ec681f3Smrg
24377ec681f3Smrg   if (handle_entry && *handle_entry)
24387ec681f3Smrg      return *handle_entry;
24397ec681f3Smrg
24407ec681f3Smrg   const struct dxil_value *value = get_src_ssa(ctx, src->ssa, 0);
24417ec681f3Smrg   if (ctx->opts->vulkan_environment) {
24427ec681f3Smrg      return value;
24437ec681f3Smrg   }
24447ec681f3Smrg
24457ec681f3Smrg   const struct dxil_value *handle = emit_createhandle_call(ctx, class,
24467ec681f3Smrg      get_resource_id(ctx, class, 0, base_binding), value, !const_block_index);
24477ec681f3Smrg   if (handle_entry)
24487ec681f3Smrg      *handle_entry = handle;
24497ec681f3Smrg
24507ec681f3Smrg   return handle;
24517ec681f3Smrg}
24527ec681f3Smrg
24537ec681f3Smrgstatic bool
24547ec681f3Smrgemit_load_ssbo(struct ntd_context *ctx, nir_intrinsic_instr *intr)
24557ec681f3Smrg{
24567ec681f3Smrg   const struct dxil_value *int32_undef = get_int32_undef(&ctx->mod);
24577ec681f3Smrg
24587ec681f3Smrg   nir_variable *var = nir_get_binding_variable(ctx->shader, nir_chase_binding(intr->src[0]));
24597ec681f3Smrg   enum dxil_resource_class class = DXIL_RESOURCE_CLASS_UAV;
24607ec681f3Smrg   if (var && var->data.access & ACCESS_NON_WRITEABLE)
24617ec681f3Smrg      class = DXIL_RESOURCE_CLASS_SRV;
24627ec681f3Smrg
24637ec681f3Smrg   const struct dxil_value *handle = get_ubo_ssbo_handle(ctx, &intr->src[0], class, 0);
24647ec681f3Smrg   const struct dxil_value *offset =
24657ec681f3Smrg      get_src(ctx, &intr->src[1], 0, nir_type_uint);
24667ec681f3Smrg   if (!int32_undef || !handle || !offset)
24677ec681f3Smrg      return false;
24687ec681f3Smrg
24697ec681f3Smrg   assert(nir_src_bit_size(intr->src[0]) == 32);
24707ec681f3Smrg   assert(nir_intrinsic_dest_components(intr) <= 4);
24717ec681f3Smrg
24727ec681f3Smrg   const struct dxil_value *coord[2] = {
24737ec681f3Smrg      offset,
24747ec681f3Smrg      int32_undef
24757ec681f3Smrg   };
24767ec681f3Smrg
24777ec681f3Smrg   const struct dxil_value *load = emit_bufferload_call(ctx, handle, coord, DXIL_I32);
24787ec681f3Smrg   if (!load)
24797ec681f3Smrg      return false;
24807ec681f3Smrg
24817ec681f3Smrg   for (int i = 0; i < nir_intrinsic_dest_components(intr); i++) {
24827ec681f3Smrg      const struct dxil_value *val =
24837ec681f3Smrg         dxil_emit_extractval(&ctx->mod, load, i);
24847ec681f3Smrg      if (!val)
24857ec681f3Smrg         return false;
24867ec681f3Smrg      store_dest_value(ctx, &intr->dest, i, val);
24877ec681f3Smrg   }
24887ec681f3Smrg   return true;
24897ec681f3Smrg}
24907ec681f3Smrg
24917ec681f3Smrgstatic bool
24927ec681f3Smrgemit_store_ssbo(struct ntd_context *ctx, nir_intrinsic_instr *intr)
24937ec681f3Smrg{
24947ec681f3Smrg   const struct dxil_value* handle = get_ubo_ssbo_handle(ctx, &intr->src[1], DXIL_RESOURCE_CLASS_UAV, 0);
24957ec681f3Smrg   const struct dxil_value *offset =
24967ec681f3Smrg      get_src(ctx, &intr->src[2], 0, nir_type_uint);
24977ec681f3Smrg   if (!handle || !offset)
24987ec681f3Smrg      return false;
24997ec681f3Smrg
25007ec681f3Smrg   assert(nir_src_bit_size(intr->src[0]) == 32);
25017ec681f3Smrg   unsigned num_components = nir_src_num_components(intr->src[0]);
25027ec681f3Smrg   assert(num_components <= 4);
25037ec681f3Smrg   const struct dxil_value *value[4];
25047ec681f3Smrg   for (unsigned i = 0; i < num_components; ++i) {
25057ec681f3Smrg      value[i] = get_src(ctx, &intr->src[0], i, nir_type_uint);
25067ec681f3Smrg      if (!value[i])
25077ec681f3Smrg         return false;
25087ec681f3Smrg   }
25097ec681f3Smrg
25107ec681f3Smrg   const struct dxil_value *int32_undef = get_int32_undef(&ctx->mod);
25117ec681f3Smrg   if (!int32_undef)
25127ec681f3Smrg      return false;
25137ec681f3Smrg
25147ec681f3Smrg   const struct dxil_value *coord[2] = {
25157ec681f3Smrg      offset,
25167ec681f3Smrg      int32_undef
25177ec681f3Smrg   };
25187ec681f3Smrg
25197ec681f3Smrg   for (int i = num_components; i < 4; ++i)
25207ec681f3Smrg      value[i] = int32_undef;
25217ec681f3Smrg
25227ec681f3Smrg   const struct dxil_value *write_mask =
25237ec681f3Smrg      dxil_module_get_int8_const(&ctx->mod, (1u << num_components) - 1);
25247ec681f3Smrg   if (!write_mask)
25257ec681f3Smrg      return false;
25267ec681f3Smrg
25277ec681f3Smrg   return emit_bufferstore_call(ctx, handle, coord, value, write_mask, DXIL_I32);
25287ec681f3Smrg}
25297ec681f3Smrg
25307ec681f3Smrgstatic bool
25317ec681f3Smrgemit_store_ssbo_masked(struct ntd_context *ctx, nir_intrinsic_instr *intr)
25327ec681f3Smrg{
25337ec681f3Smrg   const struct dxil_value *value =
25347ec681f3Smrg      get_src(ctx, &intr->src[0], 0, nir_type_uint);
25357ec681f3Smrg   const struct dxil_value *mask =
25367ec681f3Smrg      get_src(ctx, &intr->src[1], 0, nir_type_uint);
25377ec681f3Smrg   const struct dxil_value* handle = get_ubo_ssbo_handle(ctx, &intr->src[2], DXIL_RESOURCE_CLASS_UAV, 0);
25387ec681f3Smrg   const struct dxil_value *offset =
25397ec681f3Smrg      get_src(ctx, &intr->src[3], 0, nir_type_uint);
25407ec681f3Smrg   if (!value || !mask || !handle || !offset)
25417ec681f3Smrg      return false;
25427ec681f3Smrg
25437ec681f3Smrg   const struct dxil_value *int32_undef = get_int32_undef(&ctx->mod);
25447ec681f3Smrg   if (!int32_undef)
25457ec681f3Smrg      return false;
25467ec681f3Smrg
25477ec681f3Smrg   const struct dxil_value *coord[3] = {
25487ec681f3Smrg      offset, int32_undef, int32_undef
25497ec681f3Smrg   };
25507ec681f3Smrg
25517ec681f3Smrg   return
25527ec681f3Smrg      emit_atomic_binop(ctx, handle, DXIL_ATOMIC_AND, coord, mask) != NULL &&
25537ec681f3Smrg      emit_atomic_binop(ctx, handle, DXIL_ATOMIC_OR, coord, value) != NULL;
25547ec681f3Smrg}
25557ec681f3Smrg
25567ec681f3Smrgstatic bool
25577ec681f3Smrgemit_store_shared(struct ntd_context *ctx, nir_intrinsic_instr *intr)
25587ec681f3Smrg{
25597ec681f3Smrg   const struct dxil_value *zero, *index;
25607ec681f3Smrg
25617ec681f3Smrg   /* All shared mem accesses should have been lowered to scalar 32bit
25627ec681f3Smrg    * accesses.
25637ec681f3Smrg    */
25647ec681f3Smrg   assert(nir_src_bit_size(intr->src[0]) == 32);
25657ec681f3Smrg   assert(nir_src_num_components(intr->src[0]) == 1);
25667ec681f3Smrg
25677ec681f3Smrg   zero = dxil_module_get_int32_const(&ctx->mod, 0);
25687ec681f3Smrg   if (!zero)
25697ec681f3Smrg      return false;
25707ec681f3Smrg
25717ec681f3Smrg   if (intr->intrinsic == nir_intrinsic_store_shared_dxil)
25727ec681f3Smrg      index = get_src(ctx, &intr->src[1], 0, nir_type_uint);
25737ec681f3Smrg   else
25747ec681f3Smrg      index = get_src(ctx, &intr->src[2], 0, nir_type_uint);
25757ec681f3Smrg   if (!index)
25767ec681f3Smrg      return false;
25777ec681f3Smrg
25787ec681f3Smrg   const struct dxil_value *ops[] = { ctx->sharedvars, zero, index };
25797ec681f3Smrg   const struct dxil_value *ptr, *value;
25807ec681f3Smrg
25817ec681f3Smrg   ptr = dxil_emit_gep_inbounds(&ctx->mod, ops, ARRAY_SIZE(ops));
25827ec681f3Smrg   if (!ptr)
25837ec681f3Smrg      return false;
25847ec681f3Smrg
25857ec681f3Smrg   value = get_src(ctx, &intr->src[0], 0, nir_type_uint);
25867ec681f3Smrg   if (!value)
25877ec681f3Smrg      return false;
25887ec681f3Smrg
25897ec681f3Smrg   if (intr->intrinsic == nir_intrinsic_store_shared_dxil)
25907ec681f3Smrg      return dxil_emit_store(&ctx->mod, value, ptr, 4, false);
25917ec681f3Smrg
25927ec681f3Smrg   const struct dxil_value *mask = get_src(ctx, &intr->src[1], 0, nir_type_uint);
25937ec681f3Smrg   if (!mask)
25947ec681f3Smrg      return false;
25957ec681f3Smrg
25967ec681f3Smrg   if (!dxil_emit_atomicrmw(&ctx->mod, mask, ptr, DXIL_RMWOP_AND, false,
25977ec681f3Smrg                            DXIL_ATOMIC_ORDERING_ACQREL,
25987ec681f3Smrg                            DXIL_SYNC_SCOPE_CROSSTHREAD))
25997ec681f3Smrg      return false;
26007ec681f3Smrg
26017ec681f3Smrg   if (!dxil_emit_atomicrmw(&ctx->mod, value, ptr, DXIL_RMWOP_OR, false,
26027ec681f3Smrg                            DXIL_ATOMIC_ORDERING_ACQREL,
26037ec681f3Smrg                            DXIL_SYNC_SCOPE_CROSSTHREAD))
26047ec681f3Smrg      return false;
26057ec681f3Smrg
26067ec681f3Smrg   return true;
26077ec681f3Smrg}
26087ec681f3Smrg
26097ec681f3Smrgstatic bool
26107ec681f3Smrgemit_store_scratch(struct ntd_context *ctx, nir_intrinsic_instr *intr)
26117ec681f3Smrg{
26127ec681f3Smrg   const struct dxil_value *zero, *index;
26137ec681f3Smrg
26147ec681f3Smrg   /* All scratch mem accesses should have been lowered to scalar 32bit
26157ec681f3Smrg    * accesses.
26167ec681f3Smrg    */
26177ec681f3Smrg   assert(nir_src_bit_size(intr->src[0]) == 32);
26187ec681f3Smrg   assert(nir_src_num_components(intr->src[0]) == 1);
26197ec681f3Smrg
26207ec681f3Smrg   zero = dxil_module_get_int32_const(&ctx->mod, 0);
26217ec681f3Smrg   if (!zero)
26227ec681f3Smrg      return false;
26237ec681f3Smrg
26247ec681f3Smrg   index = get_src(ctx, &intr->src[1], 0, nir_type_uint);
26257ec681f3Smrg   if (!index)
26267ec681f3Smrg      return false;
26277ec681f3Smrg
26287ec681f3Smrg   const struct dxil_value *ops[] = { ctx->scratchvars, zero, index };
26297ec681f3Smrg   const struct dxil_value *ptr, *value;
26307ec681f3Smrg
26317ec681f3Smrg   ptr = dxil_emit_gep_inbounds(&ctx->mod, ops, ARRAY_SIZE(ops));
26327ec681f3Smrg   if (!ptr)
26337ec681f3Smrg      return false;
26347ec681f3Smrg
26357ec681f3Smrg   value = get_src(ctx, &intr->src[0], 0, nir_type_uint);
26367ec681f3Smrg   if (!value)
26377ec681f3Smrg      return false;
26387ec681f3Smrg
26397ec681f3Smrg   return dxil_emit_store(&ctx->mod, value, ptr, 4, false);
26407ec681f3Smrg}
26417ec681f3Smrg
26427ec681f3Smrgstatic bool
26437ec681f3Smrgemit_load_ubo(struct ntd_context *ctx, nir_intrinsic_instr *intr)
26447ec681f3Smrg{
26457ec681f3Smrg   const struct dxil_value* handle = get_ubo_ssbo_handle(ctx, &intr->src[0], DXIL_RESOURCE_CLASS_CBV, 0);
26467ec681f3Smrg   if (!handle)
26477ec681f3Smrg      return false;
26487ec681f3Smrg
26497ec681f3Smrg   const struct dxil_value *offset;
26507ec681f3Smrg   nir_const_value *const_offset = nir_src_as_const_value(intr->src[1]);
26517ec681f3Smrg   if (const_offset) {
26527ec681f3Smrg      offset = dxil_module_get_int32_const(&ctx->mod, const_offset->i32 >> 4);
26537ec681f3Smrg   } else {
26547ec681f3Smrg      const struct dxil_value *offset_src = get_src(ctx, &intr->src[1], 0, nir_type_uint);
26557ec681f3Smrg      const struct dxil_value *c4 = dxil_module_get_int32_const(&ctx->mod, 4);
26567ec681f3Smrg      if (!offset_src || !c4)
26577ec681f3Smrg         return false;
26587ec681f3Smrg
26597ec681f3Smrg      offset = dxil_emit_binop(&ctx->mod, DXIL_BINOP_ASHR, offset_src, c4, 0);
26607ec681f3Smrg   }
26617ec681f3Smrg
26627ec681f3Smrg   const struct dxil_value *agg = load_ubo(ctx, handle, offset, DXIL_F32);
26637ec681f3Smrg
26647ec681f3Smrg   if (!agg)
26657ec681f3Smrg      return false;
26667ec681f3Smrg
26677ec681f3Smrg   for (unsigned i = 0; i < nir_dest_num_components(intr->dest); ++i) {
26687ec681f3Smrg      const struct dxil_value *retval = dxil_emit_extractval(&ctx->mod, agg, i);
26697ec681f3Smrg      store_dest(ctx, &intr->dest, i, retval,
26707ec681f3Smrg                 nir_dest_bit_size(intr->dest) > 1 ? nir_type_float : nir_type_bool);
26717ec681f3Smrg   }
26727ec681f3Smrg   return true;
26737ec681f3Smrg}
26747ec681f3Smrg
26757ec681f3Smrgstatic bool
26767ec681f3Smrgemit_load_ubo_dxil(struct ntd_context *ctx, nir_intrinsic_instr *intr)
26777ec681f3Smrg{
26787ec681f3Smrg   assert(nir_dest_num_components(intr->dest) <= 4);
26797ec681f3Smrg   assert(nir_dest_bit_size(intr->dest) == 32);
26807ec681f3Smrg
26817ec681f3Smrg   const struct dxil_value* handle = get_ubo_ssbo_handle(ctx, &intr->src[0], DXIL_RESOURCE_CLASS_CBV, 0);
26827ec681f3Smrg   const struct dxil_value *offset =
26837ec681f3Smrg      get_src(ctx, &intr->src[1], 0, nir_type_uint);
26847ec681f3Smrg
26857ec681f3Smrg   if (!handle || !offset)
26867ec681f3Smrg      return false;
26877ec681f3Smrg
26887ec681f3Smrg   const struct dxil_value *agg = load_ubo(ctx, handle, offset, DXIL_I32);
26897ec681f3Smrg   if (!agg)
26907ec681f3Smrg      return false;
26917ec681f3Smrg
26927ec681f3Smrg   for (unsigned i = 0; i < nir_dest_num_components(intr->dest); i++)
26937ec681f3Smrg      store_dest_value(ctx, &intr->dest, i,
26947ec681f3Smrg                       dxil_emit_extractval(&ctx->mod, agg, i));
26957ec681f3Smrg
26967ec681f3Smrg   return true;
26977ec681f3Smrg}
26987ec681f3Smrg
26997ec681f3Smrgstatic bool
27007ec681f3Smrgemit_store_output(struct ntd_context *ctx, nir_intrinsic_instr *intr,
27017ec681f3Smrg                  nir_variable *output)
27027ec681f3Smrg{
27037ec681f3Smrg   nir_alu_type out_type = nir_get_nir_type_for_glsl_base_type(glsl_get_base_type(output->type));
27047ec681f3Smrg   enum overload_type overload = DXIL_F32;
27057ec681f3Smrg   if (output->data.compact)
27067ec681f3Smrg      out_type = nir_type_float;
27077ec681f3Smrg   else
27087ec681f3Smrg      overload = get_overload(out_type, glsl_get_bit_size(output->type));
27097ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.storeOutput", overload);
27107ec681f3Smrg
27117ec681f3Smrg   if (!func)
27127ec681f3Smrg      return false;
27137ec681f3Smrg
27147ec681f3Smrg   const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_STORE_OUTPUT);
27157ec681f3Smrg   const struct dxil_value *output_id = dxil_module_get_int32_const(&ctx->mod, (int)output->data.driver_location);
27167ec681f3Smrg   const struct dxil_value *row = dxil_module_get_int32_const(&ctx->mod, 0);
27177ec681f3Smrg
27187ec681f3Smrg   bool success = true;
27197ec681f3Smrg   if (output->data.compact) {
27207ec681f3Smrg      nir_deref_instr *array_deref = nir_instr_as_deref(intr->src[0].ssa->parent_instr);
27217ec681f3Smrg      unsigned array_index = nir_src_as_uint(array_deref->arr.index);
27227ec681f3Smrg
27237ec681f3Smrg      const struct dxil_value *col = dxil_module_get_int8_const(&ctx->mod, array_index);
27247ec681f3Smrg      const struct dxil_value *value = get_src(ctx, &intr->src[1], 0, out_type);
27257ec681f3Smrg      if (!col || !value)
27267ec681f3Smrg         return false;
27277ec681f3Smrg
27287ec681f3Smrg      const struct dxil_value *args[] = {
27297ec681f3Smrg         opcode, output_id, row, col, value
27307ec681f3Smrg      };
27317ec681f3Smrg      success = dxil_emit_call_void(&ctx->mod, func, args, ARRAY_SIZE(args));
27327ec681f3Smrg   } else {
27337ec681f3Smrg      uint32_t writemask = nir_intrinsic_write_mask(intr);
27347ec681f3Smrg      for (unsigned i = 0; i < nir_src_num_components(intr->src[1]) && success; ++i) {
27357ec681f3Smrg         if (writemask & (1 << i)) {
27367ec681f3Smrg            const struct dxil_value *col = dxil_module_get_int8_const(&ctx->mod, i);
27377ec681f3Smrg            const struct dxil_value *value = get_src(ctx, &intr->src[1], i, out_type);
27387ec681f3Smrg            if (!col || !value)
27397ec681f3Smrg               return false;
27407ec681f3Smrg
27417ec681f3Smrg            const struct dxil_value *args[] = {
27427ec681f3Smrg               opcode, output_id, row, col, value
27437ec681f3Smrg            };
27447ec681f3Smrg            success &= dxil_emit_call_void(&ctx->mod, func, args, ARRAY_SIZE(args));
27457ec681f3Smrg         }
27467ec681f3Smrg      }
27477ec681f3Smrg   }
27487ec681f3Smrg   return success;
27497ec681f3Smrg}
27507ec681f3Smrg
27517ec681f3Smrgstatic bool
27527ec681f3Smrgemit_store_deref(struct ntd_context *ctx, nir_intrinsic_instr *intr)
27537ec681f3Smrg{
27547ec681f3Smrg   nir_deref_instr *deref = nir_src_as_deref(intr->src[0]);
27557ec681f3Smrg   nir_variable *var = nir_deref_instr_get_variable(deref);
27567ec681f3Smrg
27577ec681f3Smrg   switch (var->data.mode) {
27587ec681f3Smrg   case nir_var_shader_out:
27597ec681f3Smrg      return emit_store_output(ctx, intr, var);
27607ec681f3Smrg
27617ec681f3Smrg   default:
27627ec681f3Smrg      unreachable("unsupported nir_variable_mode");
27637ec681f3Smrg   }
27647ec681f3Smrg}
27657ec681f3Smrg
27667ec681f3Smrgstatic bool
27677ec681f3Smrgemit_load_input_array(struct ntd_context *ctx, nir_intrinsic_instr *intr, nir_variable *var, nir_src *index)
27687ec681f3Smrg{
27697ec681f3Smrg   assert(var);
27707ec681f3Smrg   const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_LOAD_INPUT);
27717ec681f3Smrg   const struct dxil_value *input_id = dxil_module_get_int32_const(&ctx->mod, var->data.driver_location);
27727ec681f3Smrg   const struct dxil_value *vertex_id;
27737ec681f3Smrg   const struct dxil_value *row;
27747ec681f3Smrg
27757ec681f3Smrg   if (ctx->mod.shader_kind == DXIL_GEOMETRY_SHADER) {
27767ec681f3Smrg      vertex_id = get_src(ctx, index, 0, nir_type_int);
27777ec681f3Smrg      row = dxil_module_get_int32_const(&ctx->mod, 0);
27787ec681f3Smrg   } else {
27797ec681f3Smrg      const struct dxil_type *int32_type = dxil_module_get_int_type(&ctx->mod, 32);
27807ec681f3Smrg      vertex_id = dxil_module_get_undef(&ctx->mod, int32_type);
27817ec681f3Smrg      row = get_src(ctx, index, 0, nir_type_int);
27827ec681f3Smrg   }
27837ec681f3Smrg
27847ec681f3Smrg   if (!opcode || !input_id || !vertex_id || !row)
27857ec681f3Smrg      return false;
27867ec681f3Smrg
27877ec681f3Smrg   nir_alu_type out_type = nir_get_nir_type_for_glsl_base_type(glsl_get_base_type(glsl_get_array_element(var->type)));
27887ec681f3Smrg   enum overload_type overload = get_overload(out_type, glsl_get_bit_size(glsl_get_array_element(var->type)));
27897ec681f3Smrg
27907ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.loadInput", overload);
27917ec681f3Smrg
27927ec681f3Smrg   if (!func)
27937ec681f3Smrg      return false;
27947ec681f3Smrg
27957ec681f3Smrg   for (unsigned i = 0; i < nir_dest_num_components(intr->dest); ++i) {
27967ec681f3Smrg      const struct dxil_value *comp = dxil_module_get_int8_const(&ctx->mod, i);
27977ec681f3Smrg      if (!comp)
27987ec681f3Smrg         return false;
27997ec681f3Smrg
28007ec681f3Smrg      const struct dxil_value *args[] = {
28017ec681f3Smrg         opcode, input_id, row, comp, vertex_id
28027ec681f3Smrg      };
28037ec681f3Smrg
28047ec681f3Smrg      const struct dxil_value *retval = dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args));
28057ec681f3Smrg      if (!retval)
28067ec681f3Smrg         return false;
28077ec681f3Smrg      store_dest(ctx, &intr->dest, i, retval, out_type);
28087ec681f3Smrg   }
28097ec681f3Smrg   return true;
28107ec681f3Smrg}
28117ec681f3Smrg
28127ec681f3Smrgstatic bool
28137ec681f3Smrgemit_load_compact_input_array(struct ntd_context *ctx, nir_intrinsic_instr *intr, nir_variable *var, nir_deref_instr *deref)
28147ec681f3Smrg{
28157ec681f3Smrg   assert(var);
28167ec681f3Smrg   const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_LOAD_INPUT);
28177ec681f3Smrg   const struct dxil_value *input_id = dxil_module_get_int32_const(&ctx->mod, var->data.driver_location);
28187ec681f3Smrg   const struct dxil_value *row = dxil_module_get_int32_const(&ctx->mod, 0);
28197ec681f3Smrg   const struct dxil_value *vertex_id;
28207ec681f3Smrg
28217ec681f3Smrg   nir_src *col = &deref->arr.index;
28227ec681f3Smrg   nir_src_is_const(*col);
28237ec681f3Smrg
28247ec681f3Smrg   if (ctx->mod.shader_kind == DXIL_GEOMETRY_SHADER) {
28257ec681f3Smrg      nir_deref_instr *deref_parent = nir_deref_instr_parent(deref);
28267ec681f3Smrg      assert(deref_parent->deref_type == nir_deref_type_array);
28277ec681f3Smrg
28287ec681f3Smrg      vertex_id = get_src(ctx, &deref_parent->arr.index, 0, nir_type_int);
28297ec681f3Smrg   } else {
28307ec681f3Smrg      const struct dxil_type *int32_type = dxil_module_get_int_type(&ctx->mod, 32);
28317ec681f3Smrg      vertex_id = dxil_module_get_undef(&ctx->mod, int32_type);
28327ec681f3Smrg   }
28337ec681f3Smrg
28347ec681f3Smrg   if (!opcode || !input_id || !row || !vertex_id)
28357ec681f3Smrg      return false;
28367ec681f3Smrg
28377ec681f3Smrg   nir_alu_type out_type = nir_type_float;
28387ec681f3Smrg   enum overload_type overload = get_overload(out_type, 32);
28397ec681f3Smrg
28407ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.loadInput", overload);
28417ec681f3Smrg
28427ec681f3Smrg   if (!func)
28437ec681f3Smrg      return false;
28447ec681f3Smrg
28457ec681f3Smrg   const struct dxil_value *comp = dxil_module_get_int8_const(&ctx->mod, nir_src_as_int(*col));
28467ec681f3Smrg   if (!comp)
28477ec681f3Smrg      return false;
28487ec681f3Smrg
28497ec681f3Smrg   const struct dxil_value *args[] = {
28507ec681f3Smrg      opcode, input_id, row, comp, vertex_id
28517ec681f3Smrg   };
28527ec681f3Smrg
28537ec681f3Smrg   const struct dxil_value *retval = dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args));
28547ec681f3Smrg   if (!retval)
28557ec681f3Smrg      return false;
28567ec681f3Smrg   store_dest(ctx, &intr->dest, 0, retval, out_type);
28577ec681f3Smrg   return true;
28587ec681f3Smrg}
28597ec681f3Smrg
28607ec681f3Smrgstatic bool
28617ec681f3Smrgemit_load_input_interpolated(struct ntd_context *ctx, nir_intrinsic_instr *intr, nir_variable *var)
28627ec681f3Smrg{
28637ec681f3Smrg   assert(var);
28647ec681f3Smrg   const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_LOAD_INPUT);
28657ec681f3Smrg   const struct dxil_value *input_id = dxil_module_get_int32_const(&ctx->mod, var->data.driver_location);
28667ec681f3Smrg   const struct dxil_value *row = dxil_module_get_int32_const(&ctx->mod, 0);
28677ec681f3Smrg   const struct dxil_type *int32_type = dxil_module_get_int_type(&ctx->mod, 32);
28687ec681f3Smrg   const struct dxil_value *vertex_id = dxil_module_get_undef(&ctx->mod, int32_type);
28697ec681f3Smrg
28707ec681f3Smrg   if (!opcode || !input_id || !row || !int32_type || !vertex_id)
28717ec681f3Smrg      return false;
28727ec681f3Smrg
28737ec681f3Smrg   nir_alu_type out_type = nir_get_nir_type_for_glsl_base_type(glsl_get_base_type(var->type));
28747ec681f3Smrg   enum overload_type overload = get_overload(out_type, glsl_get_bit_size(var->type));
28757ec681f3Smrg
28767ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.loadInput", overload);
28777ec681f3Smrg
28787ec681f3Smrg   if (!func)
28797ec681f3Smrg      return false;
28807ec681f3Smrg
28817ec681f3Smrg   for (unsigned i = 0; i < nir_dest_num_components(intr->dest); ++i) {
28827ec681f3Smrg      const struct dxil_value *comp = dxil_module_get_int8_const(&ctx->mod, i);
28837ec681f3Smrg
28847ec681f3Smrg      const struct dxil_value *args[] = {
28857ec681f3Smrg         opcode, input_id, row, comp, vertex_id
28867ec681f3Smrg      };
28877ec681f3Smrg
28887ec681f3Smrg      const struct dxil_value *retval = dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args));
28897ec681f3Smrg      if (!retval)
28907ec681f3Smrg         return false;
28917ec681f3Smrg      store_dest(ctx, &intr->dest, i, retval, out_type);
28927ec681f3Smrg   }
28937ec681f3Smrg   return true;
28947ec681f3Smrg}
28957ec681f3Smrg
28967ec681f3Smrgstatic bool
28977ec681f3Smrgemit_load_input_flat(struct ntd_context *ctx, nir_intrinsic_instr *intr, nir_variable* var)
28987ec681f3Smrg{
28997ec681f3Smrg   const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_ATTRIBUTE_AT_VERTEX);
29007ec681f3Smrg   const struct dxil_value *input_id = dxil_module_get_int32_const(&ctx->mod, (int)var->data.driver_location);
29017ec681f3Smrg   const struct dxil_value *row = dxil_module_get_int32_const(&ctx->mod, 0);
29027ec681f3Smrg   const struct dxil_value *vertex_id = dxil_module_get_int8_const(&ctx->mod, ctx->opts->provoking_vertex);
29037ec681f3Smrg
29047ec681f3Smrg   nir_alu_type out_type = nir_get_nir_type_for_glsl_base_type(glsl_get_base_type(var->type));
29057ec681f3Smrg   enum overload_type overload = get_overload(out_type, glsl_get_bit_size(var->type));
29067ec681f3Smrg
29077ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.attributeAtVertex", overload);
29087ec681f3Smrg   if (!func)
29097ec681f3Smrg      return false;
29107ec681f3Smrg
29117ec681f3Smrg   for (unsigned i = 0; i < nir_dest_num_components(intr->dest); ++i) {
29127ec681f3Smrg      const struct dxil_value *comp = dxil_module_get_int8_const(&ctx->mod, i);
29137ec681f3Smrg      const struct dxil_value *args[] = {
29147ec681f3Smrg         opcode, input_id, row, comp, vertex_id
29157ec681f3Smrg      };
29167ec681f3Smrg
29177ec681f3Smrg      const struct dxil_value *retval = dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args));
29187ec681f3Smrg      if (!retval)
29197ec681f3Smrg         return false;
29207ec681f3Smrg
29217ec681f3Smrg      store_dest(ctx, &intr->dest, i, retval, out_type);
29227ec681f3Smrg   }
29237ec681f3Smrg   return true;
29247ec681f3Smrg}
29257ec681f3Smrg
29267ec681f3Smrgstatic bool
29277ec681f3Smrgemit_load_input(struct ntd_context *ctx, nir_intrinsic_instr *intr,
29287ec681f3Smrg                nir_variable *input)
29297ec681f3Smrg{
29307ec681f3Smrg   if (ctx->mod.shader_kind != DXIL_PIXEL_SHADER ||
29317ec681f3Smrg       input->data.interpolation != INTERP_MODE_FLAT ||
29327ec681f3Smrg       !ctx->opts->interpolate_at_vertex ||
29337ec681f3Smrg       ctx->opts->provoking_vertex == 0 ||
29347ec681f3Smrg       glsl_type_is_integer(input->type))
29357ec681f3Smrg      return emit_load_input_interpolated(ctx, intr, input);
29367ec681f3Smrg   else
29377ec681f3Smrg      return emit_load_input_flat(ctx, intr, input);
29387ec681f3Smrg}
29397ec681f3Smrg
29407ec681f3Smrgstatic bool
29417ec681f3Smrgemit_load_ptr(struct ntd_context *ctx, nir_intrinsic_instr *intr)
29427ec681f3Smrg{
29437ec681f3Smrg   struct nir_variable *var =
29447ec681f3Smrg      nir_deref_instr_get_variable(nir_src_as_deref(intr->src[0]));
29457ec681f3Smrg
29467ec681f3Smrg   const struct dxil_value *index =
29477ec681f3Smrg      get_src(ctx, &intr->src[1], 0, nir_type_uint);
29487ec681f3Smrg   if (!index)
29497ec681f3Smrg      return false;
29507ec681f3Smrg
29517ec681f3Smrg   const struct dxil_value *ptr = emit_gep_for_index(ctx, var, index);
29527ec681f3Smrg   if (!ptr)
29537ec681f3Smrg      return false;
29547ec681f3Smrg
29557ec681f3Smrg   const struct dxil_value *retval =
29567ec681f3Smrg      dxil_emit_load(&ctx->mod, ptr, 4, false);
29577ec681f3Smrg   if (!retval)
29587ec681f3Smrg      return false;
29597ec681f3Smrg
29607ec681f3Smrg   store_dest(ctx, &intr->dest, 0, retval, nir_type_uint);
29617ec681f3Smrg   return true;
29627ec681f3Smrg}
29637ec681f3Smrg
29647ec681f3Smrgstatic bool
29657ec681f3Smrgemit_load_shared(struct ntd_context *ctx, nir_intrinsic_instr *intr)
29667ec681f3Smrg{
29677ec681f3Smrg   const struct dxil_value *zero, *index;
29687ec681f3Smrg   unsigned bit_size = nir_dest_bit_size(intr->dest);
29697ec681f3Smrg   unsigned align = bit_size / 8;
29707ec681f3Smrg
29717ec681f3Smrg   /* All shared mem accesses should have been lowered to scalar 32bit
29727ec681f3Smrg    * accesses.
29737ec681f3Smrg    */
29747ec681f3Smrg   assert(bit_size == 32);
29757ec681f3Smrg   assert(nir_dest_num_components(intr->dest) == 1);
29767ec681f3Smrg
29777ec681f3Smrg   zero = dxil_module_get_int32_const(&ctx->mod, 0);
29787ec681f3Smrg   if (!zero)
29797ec681f3Smrg      return false;
29807ec681f3Smrg
29817ec681f3Smrg   index = get_src(ctx, &intr->src[0], 0, nir_type_uint);
29827ec681f3Smrg   if (!index)
29837ec681f3Smrg      return false;
29847ec681f3Smrg
29857ec681f3Smrg   const struct dxil_value *ops[] = { ctx->sharedvars, zero, index };
29867ec681f3Smrg   const struct dxil_value *ptr, *retval;
29877ec681f3Smrg
29887ec681f3Smrg   ptr = dxil_emit_gep_inbounds(&ctx->mod, ops, ARRAY_SIZE(ops));
29897ec681f3Smrg   if (!ptr)
29907ec681f3Smrg      return false;
29917ec681f3Smrg
29927ec681f3Smrg   retval = dxil_emit_load(&ctx->mod, ptr, align, false);
29937ec681f3Smrg   if (!retval)
29947ec681f3Smrg      return false;
29957ec681f3Smrg
29967ec681f3Smrg   store_dest(ctx, &intr->dest, 0, retval, nir_type_uint);
29977ec681f3Smrg   return true;
29987ec681f3Smrg}
29997ec681f3Smrg
30007ec681f3Smrgstatic bool
30017ec681f3Smrgemit_load_scratch(struct ntd_context *ctx, nir_intrinsic_instr *intr)
30027ec681f3Smrg{
30037ec681f3Smrg   const struct dxil_value *zero, *index;
30047ec681f3Smrg   unsigned bit_size = nir_dest_bit_size(intr->dest);
30057ec681f3Smrg   unsigned align = bit_size / 8;
30067ec681f3Smrg
30077ec681f3Smrg   /* All scratch mem accesses should have been lowered to scalar 32bit
30087ec681f3Smrg    * accesses.
30097ec681f3Smrg    */
30107ec681f3Smrg   assert(bit_size == 32);
30117ec681f3Smrg   assert(nir_dest_num_components(intr->dest) == 1);
30127ec681f3Smrg
30137ec681f3Smrg   zero = dxil_module_get_int32_const(&ctx->mod, 0);
30147ec681f3Smrg   if (!zero)
30157ec681f3Smrg      return false;
30167ec681f3Smrg
30177ec681f3Smrg   index = get_src(ctx, &intr->src[0], 0, nir_type_uint);
30187ec681f3Smrg   if (!index)
30197ec681f3Smrg      return false;
30207ec681f3Smrg
30217ec681f3Smrg   const struct dxil_value *ops[] = { ctx->scratchvars, zero, index };
30227ec681f3Smrg   const struct dxil_value *ptr, *retval;
30237ec681f3Smrg
30247ec681f3Smrg   ptr = dxil_emit_gep_inbounds(&ctx->mod, ops, ARRAY_SIZE(ops));
30257ec681f3Smrg   if (!ptr)
30267ec681f3Smrg      return false;
30277ec681f3Smrg
30287ec681f3Smrg   retval = dxil_emit_load(&ctx->mod, ptr, align, false);
30297ec681f3Smrg   if (!retval)
30307ec681f3Smrg      return false;
30317ec681f3Smrg
30327ec681f3Smrg   store_dest(ctx, &intr->dest, 0, retval, nir_type_uint);
30337ec681f3Smrg   return true;
30347ec681f3Smrg}
30357ec681f3Smrg
30367ec681f3Smrgstatic bool
30377ec681f3Smrgemit_load_deref(struct ntd_context *ctx, nir_intrinsic_instr *intr)
30387ec681f3Smrg{
30397ec681f3Smrg   assert(intr->src[0].is_ssa);
30407ec681f3Smrg   nir_deref_instr *deref = nir_instr_as_deref(intr->src[0].ssa->parent_instr);
30417ec681f3Smrg   nir_variable *var = nir_deref_instr_get_variable(deref);
30427ec681f3Smrg
30437ec681f3Smrg   switch (var->data.mode) {
30447ec681f3Smrg   case nir_var_shader_in:
30457ec681f3Smrg      if (glsl_type_is_array(var->type)) {
30467ec681f3Smrg         if (var->data.compact)
30477ec681f3Smrg            return emit_load_compact_input_array(ctx, intr, var, deref);
30487ec681f3Smrg         else
30497ec681f3Smrg            return emit_load_input_array(ctx, intr, var, &deref->arr.index);
30507ec681f3Smrg      }
30517ec681f3Smrg      return emit_load_input(ctx, intr, var);
30527ec681f3Smrg
30537ec681f3Smrg   default:
30547ec681f3Smrg      unreachable("unsupported nir_variable_mode");
30557ec681f3Smrg   }
30567ec681f3Smrg}
30577ec681f3Smrg
30587ec681f3Smrgstatic bool
30597ec681f3Smrgemit_discard_if_with_value(struct ntd_context *ctx, const struct dxil_value *value)
30607ec681f3Smrg{
30617ec681f3Smrg   const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_DISCARD);
30627ec681f3Smrg   if (!opcode)
30637ec681f3Smrg      return false;
30647ec681f3Smrg
30657ec681f3Smrg   const struct dxil_value *args[] = {
30667ec681f3Smrg     opcode,
30677ec681f3Smrg     value
30687ec681f3Smrg   };
30697ec681f3Smrg
30707ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.discard", DXIL_NONE);
30717ec681f3Smrg   if (!func)
30727ec681f3Smrg      return false;
30737ec681f3Smrg
30747ec681f3Smrg   return dxil_emit_call_void(&ctx->mod, func, args, ARRAY_SIZE(args));
30757ec681f3Smrg}
30767ec681f3Smrg
30777ec681f3Smrgstatic bool
30787ec681f3Smrgemit_discard_if(struct ntd_context *ctx, nir_intrinsic_instr *intr)
30797ec681f3Smrg{
30807ec681f3Smrg   const struct dxil_value *value = get_src(ctx, &intr->src[0], 0, nir_type_bool);
30817ec681f3Smrg   if (!value)
30827ec681f3Smrg      return false;
30837ec681f3Smrg
30847ec681f3Smrg   return emit_discard_if_with_value(ctx, value);
30857ec681f3Smrg}
30867ec681f3Smrg
30877ec681f3Smrgstatic bool
30887ec681f3Smrgemit_discard(struct ntd_context *ctx)
30897ec681f3Smrg{
30907ec681f3Smrg   const struct dxil_value *value = dxil_module_get_int1_const(&ctx->mod, true);
30917ec681f3Smrg   return emit_discard_if_with_value(ctx, value);
30927ec681f3Smrg}
30937ec681f3Smrg
30947ec681f3Smrgstatic bool
30957ec681f3Smrgemit_emit_vertex(struct ntd_context *ctx, nir_intrinsic_instr *intr)
30967ec681f3Smrg{
30977ec681f3Smrg   const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_EMIT_STREAM);
30987ec681f3Smrg   const struct dxil_value *stream_id = dxil_module_get_int8_const(&ctx->mod, nir_intrinsic_stream_id(intr));
30997ec681f3Smrg   if (!opcode || !stream_id)
31007ec681f3Smrg      return false;
31017ec681f3Smrg
31027ec681f3Smrg   const struct dxil_value *args[] = {
31037ec681f3Smrg     opcode,
31047ec681f3Smrg     stream_id
31057ec681f3Smrg   };
31067ec681f3Smrg
31077ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.emitStream", DXIL_NONE);
31087ec681f3Smrg   if (!func)
31097ec681f3Smrg      return false;
31107ec681f3Smrg
31117ec681f3Smrg   return dxil_emit_call_void(&ctx->mod, func, args, ARRAY_SIZE(args));
31127ec681f3Smrg}
31137ec681f3Smrg
31147ec681f3Smrgstatic bool
31157ec681f3Smrgemit_end_primitive(struct ntd_context *ctx, nir_intrinsic_instr *intr)
31167ec681f3Smrg{
31177ec681f3Smrg   const struct dxil_value *opcode = dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_CUT_STREAM);
31187ec681f3Smrg   const struct dxil_value *stream_id = dxil_module_get_int8_const(&ctx->mod, nir_intrinsic_stream_id(intr));
31197ec681f3Smrg   if (!opcode || !stream_id)
31207ec681f3Smrg      return false;
31217ec681f3Smrg
31227ec681f3Smrg   const struct dxil_value *args[] = {
31237ec681f3Smrg     opcode,
31247ec681f3Smrg     stream_id
31257ec681f3Smrg   };
31267ec681f3Smrg
31277ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.cutStream", DXIL_NONE);
31287ec681f3Smrg   if (!func)
31297ec681f3Smrg      return false;
31307ec681f3Smrg
31317ec681f3Smrg   return dxil_emit_call_void(&ctx->mod, func, args, ARRAY_SIZE(args));
31327ec681f3Smrg}
31337ec681f3Smrg
31347ec681f3Smrgstatic bool
31357ec681f3Smrgemit_image_store(struct ntd_context *ctx, nir_intrinsic_instr *intr)
31367ec681f3Smrg{
31377ec681f3Smrg   const struct dxil_value *handle;
31387ec681f3Smrg   bool is_array = false;
31397ec681f3Smrg   if (ctx->opts->vulkan_environment) {
31407ec681f3Smrg      assert(intr->intrinsic == nir_intrinsic_image_deref_store);
31417ec681f3Smrg      handle = get_src_ssa(ctx, intr->src[0].ssa, 0);
31427ec681f3Smrg      is_array = glsl_sampler_type_is_array(nir_src_as_deref(intr->src[0])->type);
31437ec681f3Smrg   } else {
31447ec681f3Smrg      assert(intr->intrinsic == nir_intrinsic_image_store);
31457ec681f3Smrg      int binding = nir_src_as_int(intr->src[0]);
31467ec681f3Smrg      is_array = nir_intrinsic_image_array(intr);
31477ec681f3Smrg      handle = ctx->uav_handles[binding];
31487ec681f3Smrg   }
31497ec681f3Smrg   if (!handle)
31507ec681f3Smrg      return false;
31517ec681f3Smrg
31527ec681f3Smrg   const struct dxil_value *int32_undef = get_int32_undef(&ctx->mod);
31537ec681f3Smrg   if (!int32_undef)
31547ec681f3Smrg      return false;
31557ec681f3Smrg
31567ec681f3Smrg   const struct dxil_value *coord[3] = { int32_undef, int32_undef, int32_undef };
31577ec681f3Smrg   enum glsl_sampler_dim image_dim = intr->intrinsic == nir_intrinsic_image_store ?
31587ec681f3Smrg      nir_intrinsic_image_dim(intr) :
31597ec681f3Smrg      glsl_get_sampler_dim(nir_src_as_deref(intr->src[0])->type);
31607ec681f3Smrg   unsigned num_coords = glsl_get_sampler_dim_coordinate_components(image_dim);
31617ec681f3Smrg   if (is_array)
31627ec681f3Smrg      ++num_coords;
31637ec681f3Smrg
31647ec681f3Smrg   assert(num_coords <= nir_src_num_components(intr->src[1]));
31657ec681f3Smrg   for (unsigned i = 0; i < num_coords; ++i) {
31667ec681f3Smrg      coord[i] = get_src(ctx, &intr->src[1], i, nir_type_uint);
31677ec681f3Smrg      if (!coord[i])
31687ec681f3Smrg         return false;
31697ec681f3Smrg   }
31707ec681f3Smrg
31717ec681f3Smrg   nir_alu_type in_type = nir_intrinsic_src_type(intr);
31727ec681f3Smrg   enum overload_type overload = get_overload(in_type, 32);
31737ec681f3Smrg
31747ec681f3Smrg   assert(nir_src_bit_size(intr->src[3]) == 32);
31757ec681f3Smrg   unsigned num_components = nir_src_num_components(intr->src[3]);
31767ec681f3Smrg   assert(num_components <= 4);
31777ec681f3Smrg   const struct dxil_value *value[4];
31787ec681f3Smrg   for (unsigned i = 0; i < num_components; ++i) {
31797ec681f3Smrg      value[i] = get_src(ctx, &intr->src[3], i, in_type);
31807ec681f3Smrg      if (!value[i])
31817ec681f3Smrg         return false;
31827ec681f3Smrg   }
31837ec681f3Smrg
31847ec681f3Smrg   for (int i = num_components; i < 4; ++i)
31857ec681f3Smrg      value[i] = int32_undef;
31867ec681f3Smrg
31877ec681f3Smrg   const struct dxil_value *write_mask =
31887ec681f3Smrg      dxil_module_get_int8_const(&ctx->mod, (1u << num_components) - 1);
31897ec681f3Smrg   if (!write_mask)
31907ec681f3Smrg      return false;
31917ec681f3Smrg
31927ec681f3Smrg   if (image_dim == GLSL_SAMPLER_DIM_BUF) {
31937ec681f3Smrg      coord[1] = int32_undef;
31947ec681f3Smrg      return emit_bufferstore_call(ctx, handle, coord, value, write_mask, overload);
31957ec681f3Smrg   } else
31967ec681f3Smrg      return emit_texturestore_call(ctx, handle, coord, value, write_mask, overload);
31977ec681f3Smrg}
31987ec681f3Smrg
31997ec681f3Smrgstatic bool
32007ec681f3Smrgemit_image_load(struct ntd_context *ctx, nir_intrinsic_instr *intr)
32017ec681f3Smrg{
32027ec681f3Smrg   const struct dxil_value *handle;
32037ec681f3Smrg   bool is_array = false;
32047ec681f3Smrg   if (ctx->opts->vulkan_environment) {
32057ec681f3Smrg      assert(intr->intrinsic == nir_intrinsic_image_deref_load);
32067ec681f3Smrg      handle = get_src_ssa(ctx, intr->src[0].ssa, 0);
32077ec681f3Smrg      is_array = glsl_sampler_type_is_array(nir_src_as_deref(intr->src[0])->type);
32087ec681f3Smrg   } else {
32097ec681f3Smrg      assert(intr->intrinsic == nir_intrinsic_image_load);
32107ec681f3Smrg      int binding = nir_src_as_int(intr->src[0]);
32117ec681f3Smrg      is_array = nir_intrinsic_image_array(intr);
32127ec681f3Smrg      handle = ctx->uav_handles[binding];
32137ec681f3Smrg   }
32147ec681f3Smrg   if (!handle)
32157ec681f3Smrg      return false;
32167ec681f3Smrg
32177ec681f3Smrg   const struct dxil_value *int32_undef = get_int32_undef(&ctx->mod);
32187ec681f3Smrg   if (!int32_undef)
32197ec681f3Smrg      return false;
32207ec681f3Smrg
32217ec681f3Smrg   const struct dxil_value *coord[3] = { int32_undef, int32_undef, int32_undef };
32227ec681f3Smrg   enum glsl_sampler_dim image_dim = intr->intrinsic == nir_intrinsic_image_load ?
32237ec681f3Smrg      nir_intrinsic_image_dim(intr) :
32247ec681f3Smrg      glsl_get_sampler_dim(nir_src_as_deref(intr->src[0])->type);
32257ec681f3Smrg   unsigned num_coords = glsl_get_sampler_dim_coordinate_components(image_dim);
32267ec681f3Smrg   if (is_array)
32277ec681f3Smrg      ++num_coords;
32287ec681f3Smrg
32297ec681f3Smrg   assert(num_coords <= nir_src_num_components(intr->src[1]));
32307ec681f3Smrg   for (unsigned i = 0; i < num_coords; ++i) {
32317ec681f3Smrg      coord[i] = get_src(ctx, &intr->src[1], i, nir_type_uint);
32327ec681f3Smrg      if (!coord[i])
32337ec681f3Smrg         return false;
32347ec681f3Smrg   }
32357ec681f3Smrg
32367ec681f3Smrg   nir_alu_type out_type = nir_intrinsic_dest_type(intr);
32377ec681f3Smrg   enum overload_type overload = get_overload(out_type, 32);
32387ec681f3Smrg
32397ec681f3Smrg   const struct dxil_value *load_result;
32407ec681f3Smrg   if (image_dim == GLSL_SAMPLER_DIM_BUF) {
32417ec681f3Smrg      coord[1] = int32_undef;
32427ec681f3Smrg      load_result = emit_bufferload_call(ctx, handle, coord, overload);
32437ec681f3Smrg   } else
32447ec681f3Smrg      load_result = emit_textureload_call(ctx, handle, coord, overload);
32457ec681f3Smrg
32467ec681f3Smrg   if (!load_result)
32477ec681f3Smrg      return false;
32487ec681f3Smrg
32497ec681f3Smrg   assert(nir_dest_bit_size(intr->dest) == 32);
32507ec681f3Smrg   unsigned num_components = nir_dest_num_components(intr->dest);
32517ec681f3Smrg   assert(num_components <= 4);
32527ec681f3Smrg   for (unsigned i = 0; i < num_components; ++i) {
32537ec681f3Smrg      const struct dxil_value *component = dxil_emit_extractval(&ctx->mod, load_result, i);
32547ec681f3Smrg      if (!component)
32557ec681f3Smrg         return false;
32567ec681f3Smrg      store_dest(ctx, &intr->dest, i, component, out_type);
32577ec681f3Smrg   }
32587ec681f3Smrg
32597ec681f3Smrg   if (num_components > 1)
32607ec681f3Smrg      ctx->mod.feats.typed_uav_load_additional_formats = true;
32617ec681f3Smrg
32627ec681f3Smrg   return true;
32637ec681f3Smrg}
32647ec681f3Smrg
32657ec681f3Smrgstruct texop_parameters {
32667ec681f3Smrg   const struct dxil_value *tex;
32677ec681f3Smrg   const struct dxil_value *sampler;
32687ec681f3Smrg   const struct dxil_value *bias, *lod_or_sample, *min_lod;
32697ec681f3Smrg   const struct dxil_value *coord[4], *offset[3], *dx[3], *dy[3];
32707ec681f3Smrg   const struct dxil_value *cmp;
32717ec681f3Smrg   enum overload_type overload;
32727ec681f3Smrg};
32737ec681f3Smrg
32747ec681f3Smrgstatic const struct dxil_value *
32757ec681f3Smrgemit_texture_size(struct ntd_context *ctx, struct texop_parameters *params)
32767ec681f3Smrg{
32777ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.getDimensions", DXIL_NONE);
32787ec681f3Smrg   if (!func)
32797ec681f3Smrg      return false;
32807ec681f3Smrg
32817ec681f3Smrg   const struct dxil_value *args[] = {
32827ec681f3Smrg      dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_TEXTURE_SIZE),
32837ec681f3Smrg      params->tex,
32847ec681f3Smrg      params->lod_or_sample
32857ec681f3Smrg   };
32867ec681f3Smrg
32877ec681f3Smrg   return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args));
32887ec681f3Smrg}
32897ec681f3Smrg
32907ec681f3Smrgstatic bool
32917ec681f3Smrgemit_image_size(struct ntd_context *ctx, nir_intrinsic_instr *intr)
32927ec681f3Smrg{
32937ec681f3Smrg   const struct dxil_value *handle;
32947ec681f3Smrg   if (ctx->opts->vulkan_environment) {
32957ec681f3Smrg      assert(intr->intrinsic == nir_intrinsic_image_deref_size);
32967ec681f3Smrg      handle = get_src_ssa(ctx, intr->src[0].ssa, 0);
32977ec681f3Smrg   }
32987ec681f3Smrg   else {
32997ec681f3Smrg      assert(intr->intrinsic == nir_intrinsic_image_size);
33007ec681f3Smrg      int binding = nir_src_as_int(intr->src[0]);
33017ec681f3Smrg      handle = ctx->uav_handles[binding];
33027ec681f3Smrg   }
33037ec681f3Smrg   if (!handle)
33047ec681f3Smrg      return false;
33057ec681f3Smrg
33067ec681f3Smrg   const struct dxil_value *lod = get_src(ctx, &intr->src[1], 0, nir_type_uint);
33077ec681f3Smrg   if (!lod)
33087ec681f3Smrg      return false;
33097ec681f3Smrg
33107ec681f3Smrg   struct texop_parameters params = {
33117ec681f3Smrg      .tex = handle,
33127ec681f3Smrg      .lod_or_sample = lod
33137ec681f3Smrg   };
33147ec681f3Smrg   const struct dxil_value *dimensions = emit_texture_size(ctx, &params);
33157ec681f3Smrg   if (!dimensions)
33167ec681f3Smrg      return false;
33177ec681f3Smrg
33187ec681f3Smrg   for (unsigned i = 0; i < nir_dest_num_components(intr->dest); ++i) {
33197ec681f3Smrg      const struct dxil_value *retval = dxil_emit_extractval(&ctx->mod, dimensions, i);
33207ec681f3Smrg      store_dest(ctx, &intr->dest, i, retval, nir_type_uint);
33217ec681f3Smrg   }
33227ec681f3Smrg
33237ec681f3Smrg   return true;
33247ec681f3Smrg}
33257ec681f3Smrg
33267ec681f3Smrgstatic bool
33277ec681f3Smrgemit_get_ssbo_size(struct ntd_context *ctx, nir_intrinsic_instr *intr)
33287ec681f3Smrg{
33297ec681f3Smrg   const struct dxil_value* handle = NULL;
33307ec681f3Smrg   if (ctx->opts->vulkan_environment) {
33317ec681f3Smrg      handle = get_src_ssa(ctx, intr->src[0].ssa, 0);
33327ec681f3Smrg   } else {
33337ec681f3Smrg      int binding = nir_src_as_int(intr->src[0]);
33347ec681f3Smrg      handle = ctx->uav_handles[binding];
33357ec681f3Smrg   }
33367ec681f3Smrg
33377ec681f3Smrg   if (!handle)
33387ec681f3Smrg     return false;
33397ec681f3Smrg
33407ec681f3Smrg   struct texop_parameters params = {
33417ec681f3Smrg      .tex = handle,
33427ec681f3Smrg      .lod_or_sample = dxil_module_get_undef(
33437ec681f3Smrg                        &ctx->mod, dxil_module_get_int_type(&ctx->mod, 32))
33447ec681f3Smrg   };
33457ec681f3Smrg
33467ec681f3Smrg   const struct dxil_value *dimensions = emit_texture_size(ctx, &params);
33477ec681f3Smrg   if (!dimensions)
33487ec681f3Smrg      return false;
33497ec681f3Smrg
33507ec681f3Smrg   const struct dxil_value *retval = dxil_emit_extractval(&ctx->mod, dimensions, 0);
33517ec681f3Smrg   store_dest(ctx, &intr->dest, 0, retval, nir_type_uint);
33527ec681f3Smrg
33537ec681f3Smrg   return true;
33547ec681f3Smrg}
33557ec681f3Smrg
33567ec681f3Smrgstatic bool
33577ec681f3Smrgemit_ssbo_atomic(struct ntd_context *ctx, nir_intrinsic_instr *intr,
33587ec681f3Smrg                   enum dxil_atomic_op op, nir_alu_type type)
33597ec681f3Smrg{
33607ec681f3Smrg   const struct dxil_value* handle = get_ubo_ssbo_handle(ctx, &intr->src[0], DXIL_RESOURCE_CLASS_UAV, 0);
33617ec681f3Smrg   const struct dxil_value *offset =
33627ec681f3Smrg      get_src(ctx, &intr->src[1], 0, nir_type_uint);
33637ec681f3Smrg   const struct dxil_value *value =
33647ec681f3Smrg      get_src(ctx, &intr->src[2], 0, type);
33657ec681f3Smrg
33667ec681f3Smrg   if (!value || !handle || !offset)
33677ec681f3Smrg      return false;
33687ec681f3Smrg
33697ec681f3Smrg   const struct dxil_value *int32_undef = get_int32_undef(&ctx->mod);
33707ec681f3Smrg   if (!int32_undef)
33717ec681f3Smrg      return false;
33727ec681f3Smrg
33737ec681f3Smrg   const struct dxil_value *coord[3] = {
33747ec681f3Smrg      offset, int32_undef, int32_undef
33757ec681f3Smrg   };
33767ec681f3Smrg
33777ec681f3Smrg   const struct dxil_value *retval =
33787ec681f3Smrg      emit_atomic_binop(ctx, handle, op, coord, value);
33797ec681f3Smrg
33807ec681f3Smrg   if (!retval)
33817ec681f3Smrg      return false;
33827ec681f3Smrg
33837ec681f3Smrg   store_dest(ctx, &intr->dest, 0, retval, type);
33847ec681f3Smrg   return true;
33857ec681f3Smrg}
33867ec681f3Smrg
33877ec681f3Smrgstatic bool
33887ec681f3Smrgemit_ssbo_atomic_comp_swap(struct ntd_context *ctx, nir_intrinsic_instr *intr)
33897ec681f3Smrg{
33907ec681f3Smrg   const struct dxil_value* handle = get_ubo_ssbo_handle(ctx, &intr->src[0], DXIL_RESOURCE_CLASS_UAV, 0);
33917ec681f3Smrg   const struct dxil_value *offset =
33927ec681f3Smrg      get_src(ctx, &intr->src[1], 0, nir_type_uint);
33937ec681f3Smrg   const struct dxil_value *cmpval =
33947ec681f3Smrg      get_src(ctx, &intr->src[2], 0, nir_type_int);
33957ec681f3Smrg   const struct dxil_value *newval =
33967ec681f3Smrg      get_src(ctx, &intr->src[3], 0, nir_type_int);
33977ec681f3Smrg
33987ec681f3Smrg   if (!cmpval || !newval || !handle || !offset)
33997ec681f3Smrg      return false;
34007ec681f3Smrg
34017ec681f3Smrg   const struct dxil_value *int32_undef = get_int32_undef(&ctx->mod);
34027ec681f3Smrg   if (!int32_undef)
34037ec681f3Smrg      return false;
34047ec681f3Smrg
34057ec681f3Smrg   const struct dxil_value *coord[3] = {
34067ec681f3Smrg      offset, int32_undef, int32_undef
34077ec681f3Smrg   };
34087ec681f3Smrg
34097ec681f3Smrg   const struct dxil_value *retval =
34107ec681f3Smrg      emit_atomic_cmpxchg(ctx, handle, coord, cmpval, newval);
34117ec681f3Smrg
34127ec681f3Smrg   if (!retval)
34137ec681f3Smrg      return false;
34147ec681f3Smrg
34157ec681f3Smrg   store_dest(ctx, &intr->dest, 0, retval, nir_type_int);
34167ec681f3Smrg   return true;
34177ec681f3Smrg}
34187ec681f3Smrg
34197ec681f3Smrgstatic bool
34207ec681f3Smrgemit_shared_atomic(struct ntd_context *ctx, nir_intrinsic_instr *intr,
34217ec681f3Smrg                   enum dxil_rmw_op op, nir_alu_type type)
34227ec681f3Smrg{
34237ec681f3Smrg   const struct dxil_value *zero, *index;
34247ec681f3Smrg
34257ec681f3Smrg   assert(nir_src_bit_size(intr->src[1]) == 32);
34267ec681f3Smrg
34277ec681f3Smrg   zero = dxil_module_get_int32_const(&ctx->mod, 0);
34287ec681f3Smrg   if (!zero)
34297ec681f3Smrg      return false;
34307ec681f3Smrg
34317ec681f3Smrg   index = get_src(ctx, &intr->src[0], 0, nir_type_uint);
34327ec681f3Smrg   if (!index)
34337ec681f3Smrg      return false;
34347ec681f3Smrg
34357ec681f3Smrg   const struct dxil_value *ops[] = { ctx->sharedvars, zero, index };
34367ec681f3Smrg   const struct dxil_value *ptr, *value, *retval;
34377ec681f3Smrg
34387ec681f3Smrg   ptr = dxil_emit_gep_inbounds(&ctx->mod, ops, ARRAY_SIZE(ops));
34397ec681f3Smrg   if (!ptr)
34407ec681f3Smrg      return false;
34417ec681f3Smrg
34427ec681f3Smrg   value = get_src(ctx, &intr->src[1], 0, type);
34437ec681f3Smrg   if (!value)
34447ec681f3Smrg      return false;
34457ec681f3Smrg
34467ec681f3Smrg   retval = dxil_emit_atomicrmw(&ctx->mod, value, ptr, op, false,
34477ec681f3Smrg                                DXIL_ATOMIC_ORDERING_ACQREL,
34487ec681f3Smrg                                DXIL_SYNC_SCOPE_CROSSTHREAD);
34497ec681f3Smrg   if (!retval)
34507ec681f3Smrg      return false;
34517ec681f3Smrg
34527ec681f3Smrg   store_dest(ctx, &intr->dest, 0, retval, type);
34537ec681f3Smrg   return true;
34547ec681f3Smrg}
34557ec681f3Smrg
34567ec681f3Smrgstatic bool
34577ec681f3Smrgemit_shared_atomic_comp_swap(struct ntd_context *ctx, nir_intrinsic_instr *intr)
34587ec681f3Smrg{
34597ec681f3Smrg   const struct dxil_value *zero, *index;
34607ec681f3Smrg
34617ec681f3Smrg   assert(nir_src_bit_size(intr->src[1]) == 32);
34627ec681f3Smrg
34637ec681f3Smrg   zero = dxil_module_get_int32_const(&ctx->mod, 0);
34647ec681f3Smrg   if (!zero)
34657ec681f3Smrg      return false;
34667ec681f3Smrg
34677ec681f3Smrg   index = get_src(ctx, &intr->src[0], 0, nir_type_uint);
34687ec681f3Smrg   if (!index)
34697ec681f3Smrg      return false;
34707ec681f3Smrg
34717ec681f3Smrg   const struct dxil_value *ops[] = { ctx->sharedvars, zero, index };
34727ec681f3Smrg   const struct dxil_value *ptr, *cmpval, *newval, *retval;
34737ec681f3Smrg
34747ec681f3Smrg   ptr = dxil_emit_gep_inbounds(&ctx->mod, ops, ARRAY_SIZE(ops));
34757ec681f3Smrg   if (!ptr)
34767ec681f3Smrg      return false;
34777ec681f3Smrg
34787ec681f3Smrg   cmpval = get_src(ctx, &intr->src[1], 0, nir_type_uint);
34797ec681f3Smrg   newval = get_src(ctx, &intr->src[2], 0, nir_type_uint);
34807ec681f3Smrg   if (!cmpval || !newval)
34817ec681f3Smrg      return false;
34827ec681f3Smrg
34837ec681f3Smrg   retval = dxil_emit_cmpxchg(&ctx->mod, cmpval, newval, ptr, false,
34847ec681f3Smrg                              DXIL_ATOMIC_ORDERING_ACQREL,
34857ec681f3Smrg                              DXIL_SYNC_SCOPE_CROSSTHREAD);
34867ec681f3Smrg   if (!retval)
34877ec681f3Smrg      return false;
34887ec681f3Smrg
34897ec681f3Smrg   store_dest(ctx, &intr->dest, 0, retval, nir_type_uint);
34907ec681f3Smrg   return true;
34917ec681f3Smrg}
34927ec681f3Smrg
34937ec681f3Smrgstatic bool
34947ec681f3Smrgemit_vulkan_resource_index(struct ntd_context *ctx, nir_intrinsic_instr *intr)
34957ec681f3Smrg{
34967ec681f3Smrg   unsigned int binding = nir_intrinsic_binding(intr);
34977ec681f3Smrg
34987ec681f3Smrg   bool const_index = nir_src_is_const(intr->src[0]);
34997ec681f3Smrg   if (const_index) {
35007ec681f3Smrg      binding += nir_src_as_const_value(intr->src[0])->u32;
35017ec681f3Smrg   }
35027ec681f3Smrg
35037ec681f3Smrg   const struct dxil_value *index_value = dxil_module_get_int32_const(&ctx->mod, binding);
35047ec681f3Smrg   if (!index_value)
35057ec681f3Smrg      return false;
35067ec681f3Smrg
35077ec681f3Smrg   if (!const_index) {
35087ec681f3Smrg      const struct dxil_value *offset = get_src(ctx, &intr->src[0], 0, nir_type_uint32);
35097ec681f3Smrg      if (!offset)
35107ec681f3Smrg         return false;
35117ec681f3Smrg
35127ec681f3Smrg      index_value = dxil_emit_binop(&ctx->mod, DXIL_BINOP_ADD, index_value, offset, 0);
35137ec681f3Smrg      if (!index_value)
35147ec681f3Smrg         return false;
35157ec681f3Smrg   }
35167ec681f3Smrg
35177ec681f3Smrg   store_dest(ctx, &intr->dest, 0, index_value, nir_type_uint32);
35187ec681f3Smrg   store_dest(ctx, &intr->dest, 1, dxil_module_get_int32_const(&ctx->mod, 0), nir_type_uint32);
35197ec681f3Smrg   return true;
35207ec681f3Smrg}
35217ec681f3Smrg
35227ec681f3Smrgstatic bool
35237ec681f3Smrgemit_load_vulkan_descriptor(struct ntd_context *ctx, nir_intrinsic_instr *intr)
35247ec681f3Smrg{
35257ec681f3Smrg   nir_intrinsic_instr* index = nir_src_as_intrinsic(intr->src[0]);
35267ec681f3Smrg   /* We currently do not support reindex */
35277ec681f3Smrg   assert(index && index->intrinsic == nir_intrinsic_vulkan_resource_index);
35287ec681f3Smrg
35297ec681f3Smrg   unsigned binding = nir_intrinsic_binding(index);
35307ec681f3Smrg   unsigned space = nir_intrinsic_desc_set(index);
35317ec681f3Smrg
35327ec681f3Smrg   /* The descriptor_set field for variables is only 5 bits. We shouldn't have intrinsics trying to go beyond that. */
35337ec681f3Smrg   assert(space < 32);
35347ec681f3Smrg
35357ec681f3Smrg   nir_variable *var = nir_get_binding_variable(ctx->shader, nir_chase_binding(intr->src[0]));
35367ec681f3Smrg
35377ec681f3Smrg   const struct dxil_value *handle = NULL;
35387ec681f3Smrg   enum dxil_resource_class resource_class;
35397ec681f3Smrg
35407ec681f3Smrg   switch (nir_intrinsic_desc_type(intr)) {
35417ec681f3Smrg   case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
35427ec681f3Smrg      resource_class = DXIL_RESOURCE_CLASS_CBV;
35437ec681f3Smrg      break;
35447ec681f3Smrg   case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
35457ec681f3Smrg      if (var->data.access & ACCESS_NON_WRITEABLE)
35467ec681f3Smrg         resource_class = DXIL_RESOURCE_CLASS_SRV;
35477ec681f3Smrg      else
35487ec681f3Smrg         resource_class = DXIL_RESOURCE_CLASS_UAV;
35497ec681f3Smrg      break;
35507ec681f3Smrg   default:
35517ec681f3Smrg      unreachable("unknown descriptor type");
35527ec681f3Smrg      return false;
35537ec681f3Smrg   }
35547ec681f3Smrg
35557ec681f3Smrg   const struct dxil_value *index_value = get_src(ctx, &intr->src[0], 0, nir_type_uint32);
35567ec681f3Smrg   if (!index_value)
35577ec681f3Smrg      return false;
35587ec681f3Smrg
35597ec681f3Smrg   handle = emit_createhandle_call(ctx, resource_class,
35607ec681f3Smrg      get_resource_id(ctx, resource_class, space, binding),
35617ec681f3Smrg      index_value, false);
35627ec681f3Smrg
35637ec681f3Smrg   store_dest_value(ctx, &intr->dest, 0, handle);
35647ec681f3Smrg   store_dest(ctx, &intr->dest, 1, get_src(ctx, &intr->src[0], 1, nir_type_uint32), nir_type_uint32);
35657ec681f3Smrg
35667ec681f3Smrg   return true;
35677ec681f3Smrg}
35687ec681f3Smrg
35697ec681f3Smrgstatic bool
35707ec681f3Smrgemit_intrinsic(struct ntd_context *ctx, nir_intrinsic_instr *intr)
35717ec681f3Smrg{
35727ec681f3Smrg   switch (intr->intrinsic) {
35737ec681f3Smrg   case nir_intrinsic_load_global_invocation_id:
35747ec681f3Smrg   case nir_intrinsic_load_global_invocation_id_zero_base:
35757ec681f3Smrg      return emit_load_global_invocation_id(ctx, intr);
35767ec681f3Smrg   case nir_intrinsic_load_local_invocation_id:
35777ec681f3Smrg      return emit_load_local_invocation_id(ctx, intr);
35787ec681f3Smrg   case nir_intrinsic_load_local_invocation_index:
35797ec681f3Smrg      return emit_load_local_invocation_index(ctx, intr);
35807ec681f3Smrg   case nir_intrinsic_load_workgroup_id:
35817ec681f3Smrg   case nir_intrinsic_load_workgroup_id_zero_base:
35827ec681f3Smrg      return emit_load_local_workgroup_id(ctx, intr);
35837ec681f3Smrg   case nir_intrinsic_load_ssbo:
35847ec681f3Smrg      return emit_load_ssbo(ctx, intr);
35857ec681f3Smrg   case nir_intrinsic_store_ssbo:
35867ec681f3Smrg      return emit_store_ssbo(ctx, intr);
35877ec681f3Smrg   case nir_intrinsic_store_ssbo_masked_dxil:
35887ec681f3Smrg      return emit_store_ssbo_masked(ctx, intr);
35897ec681f3Smrg   case nir_intrinsic_store_deref:
35907ec681f3Smrg      return emit_store_deref(ctx, intr);
35917ec681f3Smrg   case nir_intrinsic_store_shared_dxil:
35927ec681f3Smrg   case nir_intrinsic_store_shared_masked_dxil:
35937ec681f3Smrg      return emit_store_shared(ctx, intr);
35947ec681f3Smrg   case nir_intrinsic_store_scratch_dxil:
35957ec681f3Smrg      return emit_store_scratch(ctx, intr);
35967ec681f3Smrg   case nir_intrinsic_load_deref:
35977ec681f3Smrg      return emit_load_deref(ctx, intr);
35987ec681f3Smrg   case nir_intrinsic_load_ptr_dxil:
35997ec681f3Smrg      return emit_load_ptr(ctx, intr);
36007ec681f3Smrg   case nir_intrinsic_load_ubo:
36017ec681f3Smrg      return emit_load_ubo(ctx, intr);
36027ec681f3Smrg   case nir_intrinsic_load_ubo_dxil:
36037ec681f3Smrg      return emit_load_ubo_dxil(ctx, intr);
36047ec681f3Smrg   case nir_intrinsic_load_front_face:
36057ec681f3Smrg      return emit_load_input_interpolated(ctx, intr,
36067ec681f3Smrg                                          ctx->system_value[SYSTEM_VALUE_FRONT_FACE]);
36077ec681f3Smrg   case nir_intrinsic_load_vertex_id_zero_base:
36087ec681f3Smrg      return emit_load_input_interpolated(ctx, intr,
36097ec681f3Smrg                                          ctx->system_value[SYSTEM_VALUE_VERTEX_ID_ZERO_BASE]);
36107ec681f3Smrg   case nir_intrinsic_load_instance_id:
36117ec681f3Smrg      return emit_load_input_interpolated(ctx, intr,
36127ec681f3Smrg                                          ctx->system_value[SYSTEM_VALUE_INSTANCE_ID]);
36137ec681f3Smrg   case nir_intrinsic_load_primitive_id:
36147ec681f3Smrg      return emit_load_unary_external_function(ctx, intr, "dx.op.primitiveID",
36157ec681f3Smrg                                               DXIL_INTR_PRIMITIVE_ID);
36167ec681f3Smrg   case nir_intrinsic_load_sample_id:
36177ec681f3Smrg      return emit_load_unary_external_function(ctx, intr, "dx.op.sampleIndex",
36187ec681f3Smrg                                               DXIL_INTR_SAMPLE_INDEX);
36197ec681f3Smrg   case nir_intrinsic_load_shared_dxil:
36207ec681f3Smrg      return emit_load_shared(ctx, intr);
36217ec681f3Smrg   case nir_intrinsic_load_scratch_dxil:
36227ec681f3Smrg      return emit_load_scratch(ctx, intr);
36237ec681f3Smrg   case nir_intrinsic_discard_if:
36247ec681f3Smrg      return emit_discard_if(ctx, intr);
36257ec681f3Smrg   case nir_intrinsic_discard:
36267ec681f3Smrg      return emit_discard(ctx);
36277ec681f3Smrg   case nir_intrinsic_emit_vertex:
36287ec681f3Smrg      return emit_emit_vertex(ctx, intr);
36297ec681f3Smrg   case nir_intrinsic_end_primitive:
36307ec681f3Smrg      return emit_end_primitive(ctx, intr);
36317ec681f3Smrg   case nir_intrinsic_scoped_barrier:
36327ec681f3Smrg      return emit_barrier(ctx, intr);
36337ec681f3Smrg   case nir_intrinsic_ssbo_atomic_add:
36347ec681f3Smrg      return emit_ssbo_atomic(ctx, intr, DXIL_ATOMIC_ADD, nir_type_int);
36357ec681f3Smrg   case nir_intrinsic_ssbo_atomic_imin:
36367ec681f3Smrg      return emit_ssbo_atomic(ctx, intr, DXIL_ATOMIC_IMIN, nir_type_int);
36377ec681f3Smrg   case nir_intrinsic_ssbo_atomic_umin:
36387ec681f3Smrg      return emit_ssbo_atomic(ctx, intr, DXIL_ATOMIC_UMIN, nir_type_uint);
36397ec681f3Smrg   case nir_intrinsic_ssbo_atomic_imax:
36407ec681f3Smrg      return emit_ssbo_atomic(ctx, intr, DXIL_ATOMIC_IMAX, nir_type_int);
36417ec681f3Smrg   case nir_intrinsic_ssbo_atomic_umax:
36427ec681f3Smrg      return emit_ssbo_atomic(ctx, intr, DXIL_ATOMIC_UMAX, nir_type_uint);
36437ec681f3Smrg   case nir_intrinsic_ssbo_atomic_and:
36447ec681f3Smrg      return emit_ssbo_atomic(ctx, intr, DXIL_ATOMIC_AND, nir_type_uint);
36457ec681f3Smrg   case nir_intrinsic_ssbo_atomic_or:
36467ec681f3Smrg      return emit_ssbo_atomic(ctx, intr, DXIL_ATOMIC_OR, nir_type_uint);
36477ec681f3Smrg   case nir_intrinsic_ssbo_atomic_xor:
36487ec681f3Smrg      return emit_ssbo_atomic(ctx, intr, DXIL_ATOMIC_XOR, nir_type_uint);
36497ec681f3Smrg   case nir_intrinsic_ssbo_atomic_exchange:
36507ec681f3Smrg      return emit_ssbo_atomic(ctx, intr, DXIL_ATOMIC_EXCHANGE, nir_type_int);
36517ec681f3Smrg   case nir_intrinsic_ssbo_atomic_comp_swap:
36527ec681f3Smrg      return emit_ssbo_atomic_comp_swap(ctx, intr);
36537ec681f3Smrg   case nir_intrinsic_shared_atomic_add_dxil:
36547ec681f3Smrg      return emit_shared_atomic(ctx, intr, DXIL_RMWOP_ADD, nir_type_int);
36557ec681f3Smrg   case nir_intrinsic_shared_atomic_imin_dxil:
36567ec681f3Smrg      return emit_shared_atomic(ctx, intr, DXIL_RMWOP_MIN, nir_type_int);
36577ec681f3Smrg   case nir_intrinsic_shared_atomic_umin_dxil:
36587ec681f3Smrg      return emit_shared_atomic(ctx, intr, DXIL_RMWOP_UMIN, nir_type_uint);
36597ec681f3Smrg   case nir_intrinsic_shared_atomic_imax_dxil:
36607ec681f3Smrg      return emit_shared_atomic(ctx, intr, DXIL_RMWOP_MAX, nir_type_int);
36617ec681f3Smrg   case nir_intrinsic_shared_atomic_umax_dxil:
36627ec681f3Smrg      return emit_shared_atomic(ctx, intr, DXIL_RMWOP_UMAX, nir_type_uint);
36637ec681f3Smrg   case nir_intrinsic_shared_atomic_and_dxil:
36647ec681f3Smrg      return emit_shared_atomic(ctx, intr, DXIL_RMWOP_AND, nir_type_uint);
36657ec681f3Smrg   case nir_intrinsic_shared_atomic_or_dxil:
36667ec681f3Smrg      return emit_shared_atomic(ctx, intr, DXIL_RMWOP_OR, nir_type_uint);
36677ec681f3Smrg   case nir_intrinsic_shared_atomic_xor_dxil:
36687ec681f3Smrg      return emit_shared_atomic(ctx, intr, DXIL_RMWOP_XOR, nir_type_uint);
36697ec681f3Smrg   case nir_intrinsic_shared_atomic_exchange_dxil:
36707ec681f3Smrg      return emit_shared_atomic(ctx, intr, DXIL_RMWOP_XCHG, nir_type_int);
36717ec681f3Smrg   case nir_intrinsic_shared_atomic_comp_swap_dxil:
36727ec681f3Smrg      return emit_shared_atomic_comp_swap(ctx, intr);
36737ec681f3Smrg   case nir_intrinsic_image_store:
36747ec681f3Smrg   case nir_intrinsic_image_deref_store:
36757ec681f3Smrg      return emit_image_store(ctx, intr);
36767ec681f3Smrg   case nir_intrinsic_image_load:
36777ec681f3Smrg   case nir_intrinsic_image_deref_load:
36787ec681f3Smrg      return emit_image_load(ctx, intr);
36797ec681f3Smrg   case nir_intrinsic_image_size:
36807ec681f3Smrg   case nir_intrinsic_image_deref_size:
36817ec681f3Smrg      return emit_image_size(ctx, intr);
36827ec681f3Smrg   case nir_intrinsic_get_ssbo_size:
36837ec681f3Smrg      return emit_get_ssbo_size(ctx, intr);
36847ec681f3Smrg
36857ec681f3Smrg   case nir_intrinsic_vulkan_resource_index:
36867ec681f3Smrg      return emit_vulkan_resource_index(ctx, intr);
36877ec681f3Smrg   case nir_intrinsic_load_vulkan_descriptor:
36887ec681f3Smrg      return emit_load_vulkan_descriptor(ctx, intr);
36897ec681f3Smrg
36907ec681f3Smrg   case nir_intrinsic_load_num_workgroups:
36917ec681f3Smrg   case nir_intrinsic_load_workgroup_size:
36927ec681f3Smrg   default:
36937ec681f3Smrg      NIR_INSTR_UNSUPPORTED(&intr->instr);
36947ec681f3Smrg      assert("Unimplemented intrinsic instruction");
36957ec681f3Smrg      return false;
36967ec681f3Smrg   }
36977ec681f3Smrg}
36987ec681f3Smrg
36997ec681f3Smrgstatic bool
37007ec681f3Smrgemit_load_const(struct ntd_context *ctx, nir_load_const_instr *load_const)
37017ec681f3Smrg{
37027ec681f3Smrg   for (int i = 0; i < load_const->def.num_components; ++i) {
37037ec681f3Smrg      const struct dxil_value *value;
37047ec681f3Smrg      switch (load_const->def.bit_size) {
37057ec681f3Smrg      case 1:
37067ec681f3Smrg         value = dxil_module_get_int1_const(&ctx->mod,
37077ec681f3Smrg                                            load_const->value[i].b);
37087ec681f3Smrg         break;
37097ec681f3Smrg      case 16:
37107ec681f3Smrg         ctx->mod.feats.native_low_precision = true;
37117ec681f3Smrg         value = dxil_module_get_int16_const(&ctx->mod,
37127ec681f3Smrg                                             load_const->value[i].u16);
37137ec681f3Smrg         break;
37147ec681f3Smrg      case 32:
37157ec681f3Smrg         value = dxil_module_get_int32_const(&ctx->mod,
37167ec681f3Smrg                                             load_const->value[i].u32);
37177ec681f3Smrg         break;
37187ec681f3Smrg      case 64:
37197ec681f3Smrg         ctx->mod.feats.int64_ops = true;
37207ec681f3Smrg         value = dxil_module_get_int64_const(&ctx->mod,
37217ec681f3Smrg                                             load_const->value[i].u64);
37227ec681f3Smrg         break;
37237ec681f3Smrg      default:
37247ec681f3Smrg         unreachable("unexpected bit_size");
37257ec681f3Smrg      }
37267ec681f3Smrg      if (!value)
37277ec681f3Smrg         return false;
37287ec681f3Smrg
37297ec681f3Smrg      store_ssa_def(ctx, &load_const->def, i, value);
37307ec681f3Smrg   }
37317ec681f3Smrg   return true;
37327ec681f3Smrg}
37337ec681f3Smrg
37347ec681f3Smrgstatic bool
37357ec681f3Smrgemit_deref(struct ntd_context* ctx, nir_deref_instr* instr)
37367ec681f3Smrg{
37377ec681f3Smrg   assert(instr->deref_type == nir_deref_type_var ||
37387ec681f3Smrg          instr->deref_type == nir_deref_type_array);
37397ec681f3Smrg
37407ec681f3Smrg   /* In the non-Vulkan environment, there's nothing to emit. Any references to
37417ec681f3Smrg    * derefs will emit the necessary logic to handle scratch/shared GEP addressing
37427ec681f3Smrg    */
37437ec681f3Smrg   if (!ctx->opts->vulkan_environment)
37447ec681f3Smrg      return true;
37457ec681f3Smrg
37467ec681f3Smrg   /* In the Vulkan environment, we don't have cached handles for textures or
37477ec681f3Smrg    * samplers, so let's use the opportunity of walking through the derefs to
37487ec681f3Smrg    * emit those.
37497ec681f3Smrg    */
37507ec681f3Smrg   nir_variable *var = nir_deref_instr_get_variable(instr);
37517ec681f3Smrg   assert(var);
37527ec681f3Smrg
37537ec681f3Smrg   if (!glsl_type_is_sampler(glsl_without_array(var->type)) &&
37547ec681f3Smrg       !glsl_type_is_image(glsl_without_array(var->type)))
37557ec681f3Smrg      return true;
37567ec681f3Smrg
37577ec681f3Smrg   const struct glsl_type *type = instr->type;
37587ec681f3Smrg   const struct dxil_value *binding;
37597ec681f3Smrg
37607ec681f3Smrg   if (instr->deref_type == nir_deref_type_var) {
37617ec681f3Smrg      binding = dxil_module_get_int32_const(&ctx->mod, var->data.binding);
37627ec681f3Smrg   } else {
37637ec681f3Smrg      const struct dxil_value *base = get_src(ctx, &instr->parent, 0, nir_type_uint32);
37647ec681f3Smrg      const struct dxil_value *offset = get_src(ctx, &instr->arr.index, 0, nir_type_uint32);
37657ec681f3Smrg      if (!base || !offset)
37667ec681f3Smrg         return false;
37677ec681f3Smrg
37687ec681f3Smrg      binding = dxil_emit_binop(&ctx->mod, DXIL_BINOP_ADD, base, offset, 0);
37697ec681f3Smrg   }
37707ec681f3Smrg
37717ec681f3Smrg   if (!binding)
37727ec681f3Smrg      return false;
37737ec681f3Smrg
37747ec681f3Smrg   /* Haven't finished chasing the deref chain yet, just store the value */
37757ec681f3Smrg   if (glsl_type_is_array(type)) {
37767ec681f3Smrg      store_dest(ctx, &instr->dest, 0, binding, nir_type_uint32);
37777ec681f3Smrg      return true;
37787ec681f3Smrg   }
37797ec681f3Smrg
37807ec681f3Smrg   assert(glsl_type_is_sampler(type) || glsl_type_is_image(type));
37817ec681f3Smrg   enum dxil_resource_class res_class;
37827ec681f3Smrg   if (glsl_type_is_image(type))
37837ec681f3Smrg      res_class = DXIL_RESOURCE_CLASS_UAV;
37847ec681f3Smrg   else if (glsl_get_sampler_result_type(type) == GLSL_TYPE_VOID)
37857ec681f3Smrg      res_class = DXIL_RESOURCE_CLASS_SAMPLER;
37867ec681f3Smrg   else
37877ec681f3Smrg      res_class = DXIL_RESOURCE_CLASS_SRV;
37887ec681f3Smrg
37897ec681f3Smrg   const struct dxil_value *handle = emit_createhandle_call(ctx, res_class,
37907ec681f3Smrg      get_resource_id(ctx, res_class, var->data.descriptor_set, var->data.binding), binding, false);
37917ec681f3Smrg   if (!handle)
37927ec681f3Smrg      return false;
37937ec681f3Smrg
37947ec681f3Smrg   store_dest_value(ctx, &instr->dest, 0, handle);
37957ec681f3Smrg   return true;
37967ec681f3Smrg}
37977ec681f3Smrg
37987ec681f3Smrgstatic bool
37997ec681f3Smrgemit_cond_branch(struct ntd_context *ctx, const struct dxil_value *cond,
38007ec681f3Smrg                 int true_block, int false_block)
38017ec681f3Smrg{
38027ec681f3Smrg   assert(cond);
38037ec681f3Smrg   assert(true_block >= 0);
38047ec681f3Smrg   assert(false_block >= 0);
38057ec681f3Smrg   return dxil_emit_branch(&ctx->mod, cond, true_block, false_block);
38067ec681f3Smrg}
38077ec681f3Smrg
38087ec681f3Smrgstatic bool
38097ec681f3Smrgemit_branch(struct ntd_context *ctx, int block)
38107ec681f3Smrg{
38117ec681f3Smrg   assert(block >= 0);
38127ec681f3Smrg   return dxil_emit_branch(&ctx->mod, NULL, block, -1);
38137ec681f3Smrg}
38147ec681f3Smrg
38157ec681f3Smrgstatic bool
38167ec681f3Smrgemit_jump(struct ntd_context *ctx, nir_jump_instr *instr)
38177ec681f3Smrg{
38187ec681f3Smrg   switch (instr->type) {
38197ec681f3Smrg   case nir_jump_break:
38207ec681f3Smrg   case nir_jump_continue:
38217ec681f3Smrg      assert(instr->instr.block->successors[0]);
38227ec681f3Smrg      assert(!instr->instr.block->successors[1]);
38237ec681f3Smrg      return emit_branch(ctx, instr->instr.block->successors[0]->index);
38247ec681f3Smrg
38257ec681f3Smrg   default:
38267ec681f3Smrg      unreachable("Unsupported jump type\n");
38277ec681f3Smrg   }
38287ec681f3Smrg}
38297ec681f3Smrg
38307ec681f3Smrgstruct phi_block {
38317ec681f3Smrg   unsigned num_components;
38327ec681f3Smrg   struct dxil_instr *comp[NIR_MAX_VEC_COMPONENTS];
38337ec681f3Smrg};
38347ec681f3Smrg
38357ec681f3Smrgstatic bool
38367ec681f3Smrgemit_phi(struct ntd_context *ctx, nir_phi_instr *instr)
38377ec681f3Smrg{
38387ec681f3Smrg   unsigned bit_size = nir_dest_bit_size(instr->dest);
38397ec681f3Smrg   const struct dxil_type *type = dxil_module_get_int_type(&ctx->mod,
38407ec681f3Smrg                                                           bit_size);
38417ec681f3Smrg
38427ec681f3Smrg   struct phi_block *vphi = ralloc(ctx->phis, struct phi_block);
38437ec681f3Smrg   vphi->num_components = nir_dest_num_components(instr->dest);
38447ec681f3Smrg
38457ec681f3Smrg   for (unsigned i = 0; i < vphi->num_components; ++i) {
38467ec681f3Smrg      struct dxil_instr *phi = vphi->comp[i] = dxil_emit_phi(&ctx->mod, type);
38477ec681f3Smrg      if (!phi)
38487ec681f3Smrg         return false;
38497ec681f3Smrg      store_dest_value(ctx, &instr->dest, i, dxil_instr_get_return_value(phi));
38507ec681f3Smrg   }
38517ec681f3Smrg   _mesa_hash_table_insert(ctx->phis, instr, vphi);
38527ec681f3Smrg   return true;
38537ec681f3Smrg}
38547ec681f3Smrg
38557ec681f3Smrgstatic void
38567ec681f3Smrgfixup_phi(struct ntd_context *ctx, nir_phi_instr *instr,
38577ec681f3Smrg          struct phi_block *vphi)
38587ec681f3Smrg{
38597ec681f3Smrg   const struct dxil_value *values[128];
38607ec681f3Smrg   unsigned blocks[128];
38617ec681f3Smrg   for (unsigned i = 0; i < vphi->num_components; ++i) {
38627ec681f3Smrg      size_t num_incoming = 0;
38637ec681f3Smrg      nir_foreach_phi_src(src, instr) {
38647ec681f3Smrg         assert(src->src.is_ssa);
38657ec681f3Smrg         const struct dxil_value *val = get_src_ssa(ctx, src->src.ssa, i);
38667ec681f3Smrg         assert(num_incoming < ARRAY_SIZE(values));
38677ec681f3Smrg         values[num_incoming] = val;
38687ec681f3Smrg         assert(num_incoming < ARRAY_SIZE(blocks));
38697ec681f3Smrg         blocks[num_incoming] = src->pred->index;
38707ec681f3Smrg         ++num_incoming;
38717ec681f3Smrg      }
38727ec681f3Smrg      dxil_phi_set_incoming(vphi->comp[i], values, blocks, num_incoming);
38737ec681f3Smrg   }
38747ec681f3Smrg}
38757ec681f3Smrg
38767ec681f3Smrgstatic unsigned
38777ec681f3Smrgget_n_src(struct ntd_context *ctx, const struct dxil_value **values,
38787ec681f3Smrg          unsigned max_components, nir_tex_src *src, nir_alu_type type)
38797ec681f3Smrg{
38807ec681f3Smrg   unsigned num_components = nir_src_num_components(src->src);
38817ec681f3Smrg   unsigned i = 0;
38827ec681f3Smrg
38837ec681f3Smrg   assert(num_components <= max_components);
38847ec681f3Smrg
38857ec681f3Smrg   for (i = 0; i < num_components; ++i) {
38867ec681f3Smrg      values[i] = get_src(ctx, &src->src, i, type);
38877ec681f3Smrg      if (!values[i])
38887ec681f3Smrg         return 0;
38897ec681f3Smrg   }
38907ec681f3Smrg
38917ec681f3Smrg   return num_components;
38927ec681f3Smrg}
38937ec681f3Smrg
38947ec681f3Smrg#define PAD_SRC(ctx, array, components, undef) \
38957ec681f3Smrg   for (unsigned i = components; i < ARRAY_SIZE(array); ++i) { \
38967ec681f3Smrg      array[i] = undef; \
38977ec681f3Smrg   }
38987ec681f3Smrg
38997ec681f3Smrgstatic const struct dxil_value *
39007ec681f3Smrgemit_sample(struct ntd_context *ctx, struct texop_parameters *params)
39017ec681f3Smrg{
39027ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.sample", params->overload);
39037ec681f3Smrg   if (!func)
39047ec681f3Smrg      return NULL;
39057ec681f3Smrg
39067ec681f3Smrg   const struct dxil_value *args[11] = {
39077ec681f3Smrg      dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_SAMPLE),
39087ec681f3Smrg      params->tex, params->sampler,
39097ec681f3Smrg      params->coord[0], params->coord[1], params->coord[2], params->coord[3],
39107ec681f3Smrg      params->offset[0], params->offset[1], params->offset[2],
39117ec681f3Smrg      params->min_lod
39127ec681f3Smrg   };
39137ec681f3Smrg
39147ec681f3Smrg   return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args));
39157ec681f3Smrg}
39167ec681f3Smrg
39177ec681f3Smrgstatic const struct dxil_value *
39187ec681f3Smrgemit_sample_bias(struct ntd_context *ctx, struct texop_parameters *params)
39197ec681f3Smrg{
39207ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.sampleBias", params->overload);
39217ec681f3Smrg   if (!func)
39227ec681f3Smrg      return NULL;
39237ec681f3Smrg
39247ec681f3Smrg   assert(params->bias != NULL);
39257ec681f3Smrg
39267ec681f3Smrg   const struct dxil_value *args[12] = {
39277ec681f3Smrg      dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_SAMPLE_BIAS),
39287ec681f3Smrg      params->tex, params->sampler,
39297ec681f3Smrg      params->coord[0], params->coord[1], params->coord[2], params->coord[3],
39307ec681f3Smrg      params->offset[0], params->offset[1], params->offset[2],
39317ec681f3Smrg      params->bias, params->min_lod
39327ec681f3Smrg   };
39337ec681f3Smrg
39347ec681f3Smrg   return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args));
39357ec681f3Smrg}
39367ec681f3Smrg
39377ec681f3Smrgstatic const struct dxil_value *
39387ec681f3Smrgemit_sample_level(struct ntd_context *ctx, struct texop_parameters *params)
39397ec681f3Smrg{
39407ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.sampleLevel", params->overload);
39417ec681f3Smrg   if (!func)
39427ec681f3Smrg      return NULL;
39437ec681f3Smrg
39447ec681f3Smrg   assert(params->lod_or_sample != NULL);
39457ec681f3Smrg
39467ec681f3Smrg   const struct dxil_value *args[11] = {
39477ec681f3Smrg      dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_SAMPLE_LEVEL),
39487ec681f3Smrg      params->tex, params->sampler,
39497ec681f3Smrg      params->coord[0], params->coord[1], params->coord[2], params->coord[3],
39507ec681f3Smrg      params->offset[0], params->offset[1], params->offset[2],
39517ec681f3Smrg      params->lod_or_sample
39527ec681f3Smrg   };
39537ec681f3Smrg
39547ec681f3Smrg   return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args));
39557ec681f3Smrg}
39567ec681f3Smrg
39577ec681f3Smrgstatic const struct dxil_value *
39587ec681f3Smrgemit_sample_cmp(struct ntd_context *ctx, struct texop_parameters *params)
39597ec681f3Smrg{
39607ec681f3Smrg   const struct dxil_func *func;
39617ec681f3Smrg   enum dxil_intr opcode;
39627ec681f3Smrg   int numparam;
39637ec681f3Smrg
39647ec681f3Smrg   if (ctx->mod.shader_kind == DXIL_PIXEL_SHADER)  {
39657ec681f3Smrg      func = dxil_get_function(&ctx->mod, "dx.op.sampleCmp", DXIL_F32);
39667ec681f3Smrg      opcode = DXIL_INTR_SAMPLE_CMP;
39677ec681f3Smrg      numparam = 12;
39687ec681f3Smrg   } else {
39697ec681f3Smrg      func = dxil_get_function(&ctx->mod, "dx.op.sampleCmpLevelZero", DXIL_F32);
39707ec681f3Smrg      opcode = DXIL_INTR_SAMPLE_CMP_LVL_ZERO;
39717ec681f3Smrg      numparam = 11;
39727ec681f3Smrg   }
39737ec681f3Smrg
39747ec681f3Smrg   if (!func)
39757ec681f3Smrg      return NULL;
39767ec681f3Smrg
39777ec681f3Smrg   const struct dxil_value *args[12] = {
39787ec681f3Smrg      dxil_module_get_int32_const(&ctx->mod, opcode),
39797ec681f3Smrg      params->tex, params->sampler,
39807ec681f3Smrg      params->coord[0], params->coord[1], params->coord[2], params->coord[3],
39817ec681f3Smrg      params->offset[0], params->offset[1], params->offset[2],
39827ec681f3Smrg      params->cmp, params->min_lod
39837ec681f3Smrg   };
39847ec681f3Smrg
39857ec681f3Smrg   return dxil_emit_call(&ctx->mod, func, args, numparam);
39867ec681f3Smrg}
39877ec681f3Smrg
39887ec681f3Smrgstatic const struct dxil_value *
39897ec681f3Smrgemit_sample_grad(struct ntd_context *ctx, struct texop_parameters *params)
39907ec681f3Smrg{
39917ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.sampleGrad", params->overload);
39927ec681f3Smrg   if (!func)
39937ec681f3Smrg      return false;
39947ec681f3Smrg
39957ec681f3Smrg   const struct dxil_value *args[17] = {
39967ec681f3Smrg      dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_SAMPLE_GRAD),
39977ec681f3Smrg      params->tex, params->sampler,
39987ec681f3Smrg      params->coord[0], params->coord[1], params->coord[2], params->coord[3],
39997ec681f3Smrg      params->offset[0], params->offset[1], params->offset[2],
40007ec681f3Smrg      params->dx[0], params->dx[1], params->dx[2],
40017ec681f3Smrg      params->dy[0], params->dy[1], params->dy[2],
40027ec681f3Smrg      params->min_lod
40037ec681f3Smrg   };
40047ec681f3Smrg
40057ec681f3Smrg   return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args));
40067ec681f3Smrg}
40077ec681f3Smrg
40087ec681f3Smrgstatic const struct dxil_value *
40097ec681f3Smrgemit_texel_fetch(struct ntd_context *ctx, struct texop_parameters *params)
40107ec681f3Smrg{
40117ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.textureLoad", params->overload);
40127ec681f3Smrg   if (!func)
40137ec681f3Smrg      return false;
40147ec681f3Smrg
40157ec681f3Smrg   if (!params->lod_or_sample)
40167ec681f3Smrg      params->lod_or_sample = dxil_module_get_undef(&ctx->mod, dxil_module_get_int_type(&ctx->mod, 32));
40177ec681f3Smrg
40187ec681f3Smrg   const struct dxil_value *args[] = {
40197ec681f3Smrg      dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_TEXTURE_LOAD),
40207ec681f3Smrg      params->tex,
40217ec681f3Smrg      params->lod_or_sample, params->coord[0], params->coord[1], params->coord[2],
40227ec681f3Smrg      params->offset[0], params->offset[1], params->offset[2]
40237ec681f3Smrg   };
40247ec681f3Smrg
40257ec681f3Smrg   return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args));
40267ec681f3Smrg}
40277ec681f3Smrg
40287ec681f3Smrgstatic const struct dxil_value *
40297ec681f3Smrgemit_texture_lod(struct ntd_context *ctx, struct texop_parameters *params)
40307ec681f3Smrg{
40317ec681f3Smrg   const struct dxil_func *func = dxil_get_function(&ctx->mod, "dx.op.calculateLOD", DXIL_F32);
40327ec681f3Smrg   if (!func)
40337ec681f3Smrg      return false;
40347ec681f3Smrg
40357ec681f3Smrg   const struct dxil_value *args[] = {
40367ec681f3Smrg      dxil_module_get_int32_const(&ctx->mod, DXIL_INTR_TEXTURE_LOD),
40377ec681f3Smrg      params->tex,
40387ec681f3Smrg      params->sampler,
40397ec681f3Smrg      params->coord[0],
40407ec681f3Smrg      params->coord[1],
40417ec681f3Smrg      params->coord[2],
40427ec681f3Smrg      dxil_module_get_int1_const(&ctx->mod, 1)
40437ec681f3Smrg   };
40447ec681f3Smrg
40457ec681f3Smrg   return dxil_emit_call(&ctx->mod, func, args, ARRAY_SIZE(args));
40467ec681f3Smrg}
40477ec681f3Smrg
40487ec681f3Smrgstatic bool
40497ec681f3Smrgemit_tex(struct ntd_context *ctx, nir_tex_instr *instr)
40507ec681f3Smrg{
40517ec681f3Smrg   struct texop_parameters params;
40527ec681f3Smrg   memset(&params, 0, sizeof(struct texop_parameters));
40537ec681f3Smrg   if (!ctx->opts->vulkan_environment) {
40547ec681f3Smrg      params.tex = ctx->srv_handles[instr->texture_index];
40557ec681f3Smrg      params.sampler = ctx->sampler_handles[instr->sampler_index];
40567ec681f3Smrg   }
40577ec681f3Smrg
40587ec681f3Smrg   const struct dxil_type *int_type = dxil_module_get_int_type(&ctx->mod, 32);
40597ec681f3Smrg   const struct dxil_type *float_type = dxil_module_get_float_type(&ctx->mod, 32);
40607ec681f3Smrg   const struct dxil_value *int_undef = dxil_module_get_undef(&ctx->mod, int_type);
40617ec681f3Smrg   const struct dxil_value *float_undef = dxil_module_get_undef(&ctx->mod, float_type);
40627ec681f3Smrg
40637ec681f3Smrg   unsigned coord_components = 0, offset_components = 0, dx_components = 0, dy_components = 0;
40647ec681f3Smrg   params.overload = get_overload(instr->dest_type, 32);
40657ec681f3Smrg
40667ec681f3Smrg   for (unsigned i = 0; i < instr->num_srcs; i++) {
40677ec681f3Smrg      nir_alu_type type = nir_tex_instr_src_type(instr, i);
40687ec681f3Smrg
40697ec681f3Smrg      switch (instr->src[i].src_type) {
40707ec681f3Smrg      case nir_tex_src_coord:
40717ec681f3Smrg         coord_components = get_n_src(ctx, params.coord, ARRAY_SIZE(params.coord),
40727ec681f3Smrg                                      &instr->src[i], type);
40737ec681f3Smrg         if (!coord_components)
40747ec681f3Smrg            return false;
40757ec681f3Smrg         break;
40767ec681f3Smrg
40777ec681f3Smrg      case nir_tex_src_offset:
40787ec681f3Smrg         offset_components = get_n_src(ctx, params.offset, ARRAY_SIZE(params.offset),
40797ec681f3Smrg                                       &instr->src[i],  nir_type_int);
40807ec681f3Smrg         if (!offset_components)
40817ec681f3Smrg            return false;
40827ec681f3Smrg         break;
40837ec681f3Smrg
40847ec681f3Smrg      case nir_tex_src_bias:
40857ec681f3Smrg         assert(instr->op == nir_texop_txb);
40867ec681f3Smrg         assert(nir_src_num_components(instr->src[i].src) == 1);
40877ec681f3Smrg         params.bias = get_src(ctx, &instr->src[i].src, 0, nir_type_float);
40887ec681f3Smrg         if (!params.bias)
40897ec681f3Smrg            return false;
40907ec681f3Smrg         break;
40917ec681f3Smrg
40927ec681f3Smrg      case nir_tex_src_lod:
40937ec681f3Smrg         assert(nir_src_num_components(instr->src[i].src) == 1);
40947ec681f3Smrg         /* Buffers don't have a LOD */
40957ec681f3Smrg         if (instr->sampler_dim != GLSL_SAMPLER_DIM_BUF)
40967ec681f3Smrg            params.lod_or_sample = get_src(ctx, &instr->src[i].src, 0, type);
40977ec681f3Smrg         else
40987ec681f3Smrg            params.lod_or_sample = int_undef;
40997ec681f3Smrg         if (!params.lod_or_sample)
41007ec681f3Smrg            return false;
41017ec681f3Smrg         break;
41027ec681f3Smrg
41037ec681f3Smrg      case nir_tex_src_min_lod:
41047ec681f3Smrg         assert(nir_src_num_components(instr->src[i].src) == 1);
41057ec681f3Smrg         params.min_lod = get_src(ctx, &instr->src[i].src, 0, type);
41067ec681f3Smrg         if (!params.min_lod)
41077ec681f3Smrg            return false;
41087ec681f3Smrg         break;
41097ec681f3Smrg
41107ec681f3Smrg      case nir_tex_src_comparator:
41117ec681f3Smrg         assert(nir_src_num_components(instr->src[i].src) == 1);
41127ec681f3Smrg         params.cmp = get_src(ctx, &instr->src[i].src, 0, nir_type_float);
41137ec681f3Smrg         if (!params.cmp)
41147ec681f3Smrg            return false;
41157ec681f3Smrg         break;
41167ec681f3Smrg
41177ec681f3Smrg      case nir_tex_src_ddx:
41187ec681f3Smrg         dx_components = get_n_src(ctx, params.dx, ARRAY_SIZE(params.dx),
41197ec681f3Smrg                                   &instr->src[i], nir_type_float);
41207ec681f3Smrg         if (!dx_components)
41217ec681f3Smrg            return false;
41227ec681f3Smrg         break;
41237ec681f3Smrg
41247ec681f3Smrg      case nir_tex_src_ddy:
41257ec681f3Smrg         dy_components = get_n_src(ctx, params.dy, ARRAY_SIZE(params.dy),
41267ec681f3Smrg                                   &instr->src[i], nir_type_float);
41277ec681f3Smrg         if (!dy_components)
41287ec681f3Smrg            return false;
41297ec681f3Smrg         break;
41307ec681f3Smrg
41317ec681f3Smrg      case nir_tex_src_ms_index:
41327ec681f3Smrg         params.lod_or_sample = get_src(ctx, &instr->src[i].src, 0, nir_type_int);
41337ec681f3Smrg         if (!params.lod_or_sample)
41347ec681f3Smrg            return false;
41357ec681f3Smrg         break;
41367ec681f3Smrg
41377ec681f3Smrg      case nir_tex_src_texture_deref:
41387ec681f3Smrg         assert(ctx->opts->vulkan_environment);
41397ec681f3Smrg         params.tex = get_src_ssa(ctx, instr->src[i].src.ssa, 0);
41407ec681f3Smrg         break;
41417ec681f3Smrg
41427ec681f3Smrg      case nir_tex_src_sampler_deref:
41437ec681f3Smrg         assert(ctx->opts->vulkan_environment);
41447ec681f3Smrg         params.sampler = get_src_ssa(ctx, instr->src[i].src.ssa, 0);
41457ec681f3Smrg         break;
41467ec681f3Smrg
41477ec681f3Smrg      case nir_tex_src_projector:
41487ec681f3Smrg         unreachable("Texture projector should have been lowered");
41497ec681f3Smrg
41507ec681f3Smrg      default:
41517ec681f3Smrg         fprintf(stderr, "texture source: %d\n", instr->src[i].src_type);
41527ec681f3Smrg         unreachable("unknown texture source");
41537ec681f3Smrg      }
41547ec681f3Smrg   }
41557ec681f3Smrg
41567ec681f3Smrg   assert(params.tex != NULL);
41577ec681f3Smrg   assert(instr->op == nir_texop_txf ||
41587ec681f3Smrg          instr->op == nir_texop_txf_ms ||
41597ec681f3Smrg          nir_tex_instr_is_query(instr) ||
41607ec681f3Smrg          params.sampler != NULL);
41617ec681f3Smrg
41627ec681f3Smrg   PAD_SRC(ctx, params.coord, coord_components, float_undef);
41637ec681f3Smrg   PAD_SRC(ctx, params.offset, offset_components, int_undef);
41647ec681f3Smrg   if (!params.min_lod) params.min_lod = float_undef;
41657ec681f3Smrg
41667ec681f3Smrg   const struct dxil_value *sample = NULL;
41677ec681f3Smrg   switch (instr->op) {
41687ec681f3Smrg   case nir_texop_txb:
41697ec681f3Smrg      sample = emit_sample_bias(ctx, &params);
41707ec681f3Smrg      break;
41717ec681f3Smrg
41727ec681f3Smrg   case nir_texop_tex:
41737ec681f3Smrg      if (params.cmp != NULL) {
41747ec681f3Smrg         sample = emit_sample_cmp(ctx, &params);
41757ec681f3Smrg         break;
41767ec681f3Smrg      } else if (ctx->mod.shader_kind == DXIL_PIXEL_SHADER) {
41777ec681f3Smrg         sample = emit_sample(ctx, &params);
41787ec681f3Smrg         break;
41797ec681f3Smrg      }
41807ec681f3Smrg      params.lod_or_sample = dxil_module_get_float_const(&ctx->mod, 0);
41817ec681f3Smrg      FALLTHROUGH;
41827ec681f3Smrg   case nir_texop_txl:
41837ec681f3Smrg      sample = emit_sample_level(ctx, &params);
41847ec681f3Smrg      break;
41857ec681f3Smrg
41867ec681f3Smrg   case nir_texop_txd:
41877ec681f3Smrg      PAD_SRC(ctx, params.dx, dx_components, float_undef);
41887ec681f3Smrg      PAD_SRC(ctx, params.dy, dy_components,float_undef);
41897ec681f3Smrg      sample = emit_sample_grad(ctx, &params);
41907ec681f3Smrg      break;
41917ec681f3Smrg
41927ec681f3Smrg   case nir_texop_txf:
41937ec681f3Smrg   case nir_texop_txf_ms:
41947ec681f3Smrg      if (instr->sampler_dim == GLSL_SAMPLER_DIM_BUF) {
41957ec681f3Smrg         params.coord[1] = int_undef;
41967ec681f3Smrg         sample = emit_bufferload_call(ctx, params.tex, params.coord, params.overload);
41977ec681f3Smrg      } else {
41987ec681f3Smrg         PAD_SRC(ctx, params.coord, coord_components, int_undef);
41997ec681f3Smrg         sample = emit_texel_fetch(ctx, &params);
42007ec681f3Smrg      }
42017ec681f3Smrg      break;
42027ec681f3Smrg
42037ec681f3Smrg   case nir_texop_txs:
42047ec681f3Smrg      sample = emit_texture_size(ctx, &params);
42057ec681f3Smrg      break;
42067ec681f3Smrg
42077ec681f3Smrg   case nir_texop_lod:
42087ec681f3Smrg      sample = emit_texture_lod(ctx, &params);
42097ec681f3Smrg      store_dest(ctx, &instr->dest, 0, sample, nir_alu_type_get_base_type(instr->dest_type));
42107ec681f3Smrg      return true;
42117ec681f3Smrg
42127ec681f3Smrg   case nir_texop_query_levels:
42137ec681f3Smrg      params.lod_or_sample = dxil_module_get_int_const(&ctx->mod, 0, 32);
42147ec681f3Smrg      sample = emit_texture_size(ctx, &params);
42157ec681f3Smrg      const struct dxil_value *retval = dxil_emit_extractval(&ctx->mod, sample, 3);
42167ec681f3Smrg      store_dest(ctx, &instr->dest, 0, retval, nir_alu_type_get_base_type(instr->dest_type));
42177ec681f3Smrg      return true;
42187ec681f3Smrg
42197ec681f3Smrg   default:
42207ec681f3Smrg      fprintf(stderr, "texture op: %d\n", instr->op);
42217ec681f3Smrg      unreachable("unknown texture op");
42227ec681f3Smrg   }
42237ec681f3Smrg
42247ec681f3Smrg   if (!sample)
42257ec681f3Smrg      return false;
42267ec681f3Smrg
42277ec681f3Smrg   for (unsigned i = 0; i < nir_dest_num_components(instr->dest); ++i) {
42287ec681f3Smrg      const struct dxil_value *retval = dxil_emit_extractval(&ctx->mod, sample, i);
42297ec681f3Smrg      store_dest(ctx, &instr->dest, i, retval, nir_alu_type_get_base_type(instr->dest_type));
42307ec681f3Smrg   }
42317ec681f3Smrg
42327ec681f3Smrg   return true;
42337ec681f3Smrg}
42347ec681f3Smrg
42357ec681f3Smrgstatic bool
42367ec681f3Smrgemit_undefined(struct ntd_context *ctx, nir_ssa_undef_instr *undef)
42377ec681f3Smrg{
42387ec681f3Smrg   for (unsigned i = 0; i < undef->def.num_components; ++i)
42397ec681f3Smrg      store_ssa_def(ctx, &undef->def, i, dxil_module_get_int32_const(&ctx->mod, 0));
42407ec681f3Smrg   return true;
42417ec681f3Smrg}
42427ec681f3Smrg
42437ec681f3Smrgstatic bool emit_instr(struct ntd_context *ctx, struct nir_instr* instr)
42447ec681f3Smrg{
42457ec681f3Smrg   switch (instr->type) {
42467ec681f3Smrg   case nir_instr_type_alu:
42477ec681f3Smrg      return emit_alu(ctx, nir_instr_as_alu(instr));
42487ec681f3Smrg   case nir_instr_type_intrinsic:
42497ec681f3Smrg      return emit_intrinsic(ctx, nir_instr_as_intrinsic(instr));
42507ec681f3Smrg   case nir_instr_type_load_const:
42517ec681f3Smrg      return emit_load_const(ctx, nir_instr_as_load_const(instr));
42527ec681f3Smrg   case nir_instr_type_deref:
42537ec681f3Smrg      return emit_deref(ctx, nir_instr_as_deref(instr));
42547ec681f3Smrg   case nir_instr_type_jump:
42557ec681f3Smrg      return emit_jump(ctx, nir_instr_as_jump(instr));
42567ec681f3Smrg   case nir_instr_type_phi:
42577ec681f3Smrg      return emit_phi(ctx, nir_instr_as_phi(instr));
42587ec681f3Smrg   case nir_instr_type_tex:
42597ec681f3Smrg      return emit_tex(ctx, nir_instr_as_tex(instr));
42607ec681f3Smrg   case nir_instr_type_ssa_undef:
42617ec681f3Smrg      return emit_undefined(ctx, nir_instr_as_ssa_undef(instr));
42627ec681f3Smrg   default:
42637ec681f3Smrg      NIR_INSTR_UNSUPPORTED(instr);
42647ec681f3Smrg      unreachable("Unimplemented instruction type");
42657ec681f3Smrg      return false;
42667ec681f3Smrg   }
42677ec681f3Smrg}
42687ec681f3Smrg
42697ec681f3Smrg
42707ec681f3Smrgstatic bool
42717ec681f3Smrgemit_block(struct ntd_context *ctx, struct nir_block *block)
42727ec681f3Smrg{
42737ec681f3Smrg   assert(block->index < ctx->mod.num_basic_block_ids);
42747ec681f3Smrg   ctx->mod.basic_block_ids[block->index] = ctx->mod.curr_block;
42757ec681f3Smrg
42767ec681f3Smrg   nir_foreach_instr(instr, block) {
42777ec681f3Smrg      TRACE_CONVERSION(instr);
42787ec681f3Smrg
42797ec681f3Smrg      if (!emit_instr(ctx, instr))  {
42807ec681f3Smrg         return false;
42817ec681f3Smrg      }
42827ec681f3Smrg   }
42837ec681f3Smrg   return true;
42847ec681f3Smrg}
42857ec681f3Smrg
42867ec681f3Smrgstatic bool
42877ec681f3Smrgemit_cf_list(struct ntd_context *ctx, struct exec_list *list);
42887ec681f3Smrg
42897ec681f3Smrgstatic bool
42907ec681f3Smrgemit_if(struct ntd_context *ctx, struct nir_if *if_stmt)
42917ec681f3Smrg{
42927ec681f3Smrg   assert(nir_src_num_components(if_stmt->condition) == 1);
42937ec681f3Smrg   const struct dxil_value *cond = get_src(ctx, &if_stmt->condition, 0,
42947ec681f3Smrg                                           nir_type_bool);
42957ec681f3Smrg   if (!cond)
42967ec681f3Smrg      return false;
42977ec681f3Smrg
42987ec681f3Smrg   /* prepare blocks */
42997ec681f3Smrg   nir_block *then_block = nir_if_first_then_block(if_stmt);
43007ec681f3Smrg   assert(nir_if_last_then_block(if_stmt)->successors[0]);
43017ec681f3Smrg   assert(!nir_if_last_then_block(if_stmt)->successors[1]);
43027ec681f3Smrg   int then_succ = nir_if_last_then_block(if_stmt)->successors[0]->index;
43037ec681f3Smrg
43047ec681f3Smrg   nir_block *else_block = NULL;
43057ec681f3Smrg   int else_succ = -1;
43067ec681f3Smrg   if (!exec_list_is_empty(&if_stmt->else_list)) {
43077ec681f3Smrg      else_block = nir_if_first_else_block(if_stmt);
43087ec681f3Smrg      assert(nir_if_last_else_block(if_stmt)->successors[0]);
43097ec681f3Smrg      assert(!nir_if_last_else_block(if_stmt)->successors[1]);
43107ec681f3Smrg      else_succ = nir_if_last_else_block(if_stmt)->successors[0]->index;
43117ec681f3Smrg   }
43127ec681f3Smrg
43137ec681f3Smrg   if (!emit_cond_branch(ctx, cond, then_block->index,
43147ec681f3Smrg                         else_block ? else_block->index : then_succ))
43157ec681f3Smrg      return false;
43167ec681f3Smrg
43177ec681f3Smrg   /* handle then-block */
43187ec681f3Smrg   if (!emit_cf_list(ctx, &if_stmt->then_list) ||
43197ec681f3Smrg       (!nir_block_ends_in_jump(nir_if_last_then_block(if_stmt)) &&
43207ec681f3Smrg        !emit_branch(ctx, then_succ)))
43217ec681f3Smrg      return false;
43227ec681f3Smrg
43237ec681f3Smrg   if (else_block) {
43247ec681f3Smrg      /* handle else-block */
43257ec681f3Smrg      if (!emit_cf_list(ctx, &if_stmt->else_list) ||
43267ec681f3Smrg          (!nir_block_ends_in_jump(nir_if_last_else_block(if_stmt)) &&
43277ec681f3Smrg           !emit_branch(ctx, else_succ)))
43287ec681f3Smrg         return false;
43297ec681f3Smrg   }
43307ec681f3Smrg
43317ec681f3Smrg   return true;
43327ec681f3Smrg}
43337ec681f3Smrg
43347ec681f3Smrgstatic bool
43357ec681f3Smrgemit_loop(struct ntd_context *ctx, nir_loop *loop)
43367ec681f3Smrg{
43377ec681f3Smrg   nir_block *first_block = nir_loop_first_block(loop);
43387ec681f3Smrg
43397ec681f3Smrg   assert(nir_loop_last_block(loop)->successors[0]);
43407ec681f3Smrg   assert(!nir_loop_last_block(loop)->successors[1]);
43417ec681f3Smrg
43427ec681f3Smrg   if (!emit_branch(ctx, first_block->index))
43437ec681f3Smrg      return false;
43447ec681f3Smrg
43457ec681f3Smrg   if (!emit_cf_list(ctx, &loop->body))
43467ec681f3Smrg      return false;
43477ec681f3Smrg
43487ec681f3Smrg   if (!emit_branch(ctx, first_block->index))
43497ec681f3Smrg      return false;
43507ec681f3Smrg
43517ec681f3Smrg   return true;
43527ec681f3Smrg}
43537ec681f3Smrg
43547ec681f3Smrgstatic bool
43557ec681f3Smrgemit_cf_list(struct ntd_context *ctx, struct exec_list *list)
43567ec681f3Smrg{
43577ec681f3Smrg   foreach_list_typed(nir_cf_node, node, node, list) {
43587ec681f3Smrg      switch (node->type) {
43597ec681f3Smrg      case nir_cf_node_block:
43607ec681f3Smrg         if (!emit_block(ctx, nir_cf_node_as_block(node)))
43617ec681f3Smrg            return false;
43627ec681f3Smrg         break;
43637ec681f3Smrg
43647ec681f3Smrg      case nir_cf_node_if:
43657ec681f3Smrg         if (!emit_if(ctx, nir_cf_node_as_if(node)))
43667ec681f3Smrg            return false;
43677ec681f3Smrg         break;
43687ec681f3Smrg
43697ec681f3Smrg      case nir_cf_node_loop:
43707ec681f3Smrg         if (!emit_loop(ctx, nir_cf_node_as_loop(node)))
43717ec681f3Smrg            return false;
43727ec681f3Smrg         break;
43737ec681f3Smrg
43747ec681f3Smrg      default:
43757ec681f3Smrg         unreachable("unsupported cf-list node");
43767ec681f3Smrg         break;
43777ec681f3Smrg      }
43787ec681f3Smrg   }
43797ec681f3Smrg   return true;
43807ec681f3Smrg}
43817ec681f3Smrg
43827ec681f3Smrgstatic void
43837ec681f3Smrginsert_sorted_by_binding(struct exec_list *var_list, nir_variable *new_var)
43847ec681f3Smrg{
43857ec681f3Smrg   nir_foreach_variable_in_list(var, var_list) {
43867ec681f3Smrg      if (var->data.binding > new_var->data.binding) {
43877ec681f3Smrg         exec_node_insert_node_before(&var->node, &new_var->node);
43887ec681f3Smrg         return;
43897ec681f3Smrg      }
43907ec681f3Smrg   }
43917ec681f3Smrg   exec_list_push_tail(var_list, &new_var->node);
43927ec681f3Smrg}
43937ec681f3Smrg
43947ec681f3Smrg
43957ec681f3Smrgstatic void
43967ec681f3Smrgsort_uniforms_by_binding_and_remove_structs(nir_shader *s)
43977ec681f3Smrg{
43987ec681f3Smrg   struct exec_list new_list;
43997ec681f3Smrg   exec_list_make_empty(&new_list);
44007ec681f3Smrg
44017ec681f3Smrg   nir_foreach_variable_with_modes_safe(var, s, nir_var_uniform) {
44027ec681f3Smrg      exec_node_remove(&var->node);
44037ec681f3Smrg      const struct glsl_type *type = glsl_without_array(var->type);
44047ec681f3Smrg      if (!glsl_type_is_struct(type))
44057ec681f3Smrg         insert_sorted_by_binding(&new_list, var);
44067ec681f3Smrg   }
44077ec681f3Smrg   exec_list_append(&s->variables, &new_list);
44087ec681f3Smrg}
44097ec681f3Smrg
44107ec681f3Smrgstatic void
44117ec681f3Smrgprepare_phi_values(struct ntd_context *ctx)
44127ec681f3Smrg{
44137ec681f3Smrg   /* PHI nodes are difficult to get right when tracking the types:
44147ec681f3Smrg    * Since the incoming sources are linked to blocks, we can't bitcast
44157ec681f3Smrg    * on the fly while loading. So scan the shader and insert a typed dummy
44167ec681f3Smrg    * value for each phi source, and when storing we convert if the incoming
44177ec681f3Smrg    * value has a different type then the one expected by the phi node.
44187ec681f3Smrg    * We choose int as default, because it supports more bit sizes.
44197ec681f3Smrg    */
44207ec681f3Smrg   nir_foreach_function(function, ctx->shader) {
44217ec681f3Smrg      if (function->impl) {
44227ec681f3Smrg         nir_foreach_block(block, function->impl) {
44237ec681f3Smrg            nir_foreach_instr(instr, block) {
44247ec681f3Smrg               if (instr->type == nir_instr_type_phi) {
44257ec681f3Smrg                  nir_phi_instr *ir = nir_instr_as_phi(instr);
44267ec681f3Smrg                  unsigned bitsize = nir_dest_bit_size(ir->dest);
44277ec681f3Smrg                  const struct dxil_value *dummy = dxil_module_get_int_const(&ctx->mod, 0, bitsize);
44287ec681f3Smrg                  nir_foreach_phi_src(src, ir) {
44297ec681f3Smrg                     for(unsigned int i = 0; i < ir->dest.ssa.num_components; ++i)
44307ec681f3Smrg                        store_ssa_def(ctx, src->src.ssa, i, dummy);
44317ec681f3Smrg                  }
44327ec681f3Smrg               }
44337ec681f3Smrg            }
44347ec681f3Smrg         }
44357ec681f3Smrg      }
44367ec681f3Smrg   }
44377ec681f3Smrg}
44387ec681f3Smrg
44397ec681f3Smrgstatic bool
44407ec681f3Smrgemit_cbvs(struct ntd_context *ctx)
44417ec681f3Smrg{
44427ec681f3Smrg   if (ctx->shader->info.stage == MESA_SHADER_KERNEL || ctx->opts->vulkan_environment) {
44437ec681f3Smrg      nir_foreach_variable_with_modes(var, ctx->shader, nir_var_mem_ubo) {
44447ec681f3Smrg         if (!emit_ubo_var(ctx, var))
44457ec681f3Smrg            return false;
44467ec681f3Smrg      }
44477ec681f3Smrg   } else {
44487ec681f3Smrg      for (int i = ctx->opts->ubo_binding_offset; i < ctx->shader->info.num_ubos; ++i) {
44497ec681f3Smrg         char name[64];
44507ec681f3Smrg         snprintf(name, sizeof(name), "__ubo%d", i);
44517ec681f3Smrg         if (!emit_cbv(ctx, i, 0, 16384 /*4096 vec4's*/, 1, name))
44527ec681f3Smrg            return false;
44537ec681f3Smrg      }
44547ec681f3Smrg   }
44557ec681f3Smrg
44567ec681f3Smrg   return true;
44577ec681f3Smrg}
44587ec681f3Smrg
44597ec681f3Smrgstatic bool
44607ec681f3Smrgemit_scratch(struct ntd_context *ctx)
44617ec681f3Smrg{
44627ec681f3Smrg   if (ctx->shader->scratch_size) {
44637ec681f3Smrg      /*
44647ec681f3Smrg       * We always allocate an u32 array, no matter the actual variable types.
44657ec681f3Smrg       * According to the DXIL spec, the minimum load/store granularity is
44667ec681f3Smrg       * 32-bit, anything smaller requires using a read-extract/read-write-modify
44677ec681f3Smrg       * approach.
44687ec681f3Smrg       */
44697ec681f3Smrg      unsigned size = ALIGN_POT(ctx->shader->scratch_size, sizeof(uint32_t));
44707ec681f3Smrg      const struct dxil_type *int32 = dxil_module_get_int_type(&ctx->mod, 32);
44717ec681f3Smrg      const struct dxil_value *array_length = dxil_module_get_int32_const(&ctx->mod, size / sizeof(uint32_t));
44727ec681f3Smrg      if (!int32 || !array_length)
44737ec681f3Smrg         return false;
44747ec681f3Smrg
44757ec681f3Smrg      const struct dxil_type *type = dxil_module_get_array_type(
44767ec681f3Smrg         &ctx->mod, int32, size / sizeof(uint32_t));
44777ec681f3Smrg      if (!type)
44787ec681f3Smrg         return false;
44797ec681f3Smrg
44807ec681f3Smrg      ctx->scratchvars = dxil_emit_alloca(&ctx->mod, type, int32, array_length, 4);
44817ec681f3Smrg      if (!ctx->scratchvars)
44827ec681f3Smrg         return false;
44837ec681f3Smrg   }
44847ec681f3Smrg
44857ec681f3Smrg   return true;
44867ec681f3Smrg}
44877ec681f3Smrg
44887ec681f3Smrg/* The validator complains if we don't have ops that reference a global variable. */
44897ec681f3Smrgstatic bool
44907ec681f3Smrgshader_has_shared_ops(struct nir_shader *s)
44917ec681f3Smrg{
44927ec681f3Smrg   nir_foreach_function(func, s) {
44937ec681f3Smrg      if (!func->impl)
44947ec681f3Smrg         continue;
44957ec681f3Smrg      nir_foreach_block(block, func->impl) {
44967ec681f3Smrg         nir_foreach_instr(instr, block) {
44977ec681f3Smrg            if (instr->type != nir_instr_type_intrinsic)
44987ec681f3Smrg               continue;
44997ec681f3Smrg            nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
45007ec681f3Smrg            switch (intrin->intrinsic) {
45017ec681f3Smrg            case nir_intrinsic_load_shared_dxil:
45027ec681f3Smrg            case nir_intrinsic_store_shared_dxil:
45037ec681f3Smrg            case nir_intrinsic_shared_atomic_add_dxil:
45047ec681f3Smrg            case nir_intrinsic_shared_atomic_and_dxil:
45057ec681f3Smrg            case nir_intrinsic_shared_atomic_comp_swap_dxil:
45067ec681f3Smrg            case nir_intrinsic_shared_atomic_exchange_dxil:
45077ec681f3Smrg            case nir_intrinsic_shared_atomic_imax_dxil:
45087ec681f3Smrg            case nir_intrinsic_shared_atomic_imin_dxil:
45097ec681f3Smrg            case nir_intrinsic_shared_atomic_or_dxil:
45107ec681f3Smrg            case nir_intrinsic_shared_atomic_umax_dxil:
45117ec681f3Smrg            case nir_intrinsic_shared_atomic_umin_dxil:
45127ec681f3Smrg            case nir_intrinsic_shared_atomic_xor_dxil:
45137ec681f3Smrg               return true;
45147ec681f3Smrg            default: break;
45157ec681f3Smrg            }
45167ec681f3Smrg         }
45177ec681f3Smrg      }
45187ec681f3Smrg   }
45197ec681f3Smrg   return false;
45207ec681f3Smrg}
45217ec681f3Smrg
45227ec681f3Smrgstatic bool
45237ec681f3Smrgemit_module(struct ntd_context *ctx, const struct nir_to_dxil_options *opts)
45247ec681f3Smrg{
45257ec681f3Smrg   /* The validator forces us to emit resources in a specific order:
45267ec681f3Smrg    * CBVs, Samplers, SRVs, UAVs. While we are at it also remove
45277ec681f3Smrg    * stale struct uniforms, they are lowered but might not have been removed */
45287ec681f3Smrg   sort_uniforms_by_binding_and_remove_structs(ctx->shader);
45297ec681f3Smrg
45307ec681f3Smrg   /* CBVs */
45317ec681f3Smrg   if (!emit_cbvs(ctx))
45327ec681f3Smrg      return false;
45337ec681f3Smrg
45347ec681f3Smrg   /* Samplers */
45357ec681f3Smrg   nir_foreach_variable_with_modes(var, ctx->shader, nir_var_uniform) {
45367ec681f3Smrg      unsigned count = glsl_type_get_sampler_count(var->type);
45377ec681f3Smrg      const struct glsl_type *without_array = glsl_without_array(var->type);
45387ec681f3Smrg      if (var->data.mode == nir_var_uniform && glsl_type_is_sampler(without_array) &&
45397ec681f3Smrg          glsl_get_sampler_result_type(without_array) == GLSL_TYPE_VOID) {
45407ec681f3Smrg         if (!emit_sampler(ctx, var, count))
45417ec681f3Smrg            return false;
45427ec681f3Smrg      }
45437ec681f3Smrg   }
45447ec681f3Smrg
45457ec681f3Smrg   /* SRVs */
45467ec681f3Smrg   nir_foreach_variable_with_modes(var, ctx->shader, nir_var_uniform) {
45477ec681f3Smrg      unsigned count = glsl_type_get_sampler_count(var->type);
45487ec681f3Smrg      const struct glsl_type *without_array = glsl_without_array(var->type);
45497ec681f3Smrg      if (var->data.mode == nir_var_uniform && glsl_type_is_sampler(without_array) &&
45507ec681f3Smrg          glsl_get_sampler_result_type(without_array) != GLSL_TYPE_VOID) {
45517ec681f3Smrg         if (!emit_srv(ctx, var, count))
45527ec681f3Smrg            return false;
45537ec681f3Smrg      }
45547ec681f3Smrg   }
45557ec681f3Smrg   /* Handle read-only SSBOs as SRVs */
45567ec681f3Smrg   nir_foreach_variable_with_modes(var, ctx->shader, nir_var_mem_ssbo) {
45577ec681f3Smrg      if ((var->data.access & ACCESS_NON_WRITEABLE) != 0) {
45587ec681f3Smrg         unsigned count = 1;
45597ec681f3Smrg         if (glsl_type_is_array(var->type))
45607ec681f3Smrg            count = glsl_get_length(var->type);
45617ec681f3Smrg         if (!emit_srv(ctx, var, count))
45627ec681f3Smrg            return false;
45637ec681f3Smrg      }
45647ec681f3Smrg   }
45657ec681f3Smrg
45667ec681f3Smrg   if (ctx->shader->info.shared_size && shader_has_shared_ops(ctx->shader)) {
45677ec681f3Smrg      const struct dxil_type *type;
45687ec681f3Smrg      unsigned size;
45697ec681f3Smrg
45707ec681f3Smrg     /*
45717ec681f3Smrg      * We always allocate an u32 array, no matter the actual variable types.
45727ec681f3Smrg      * According to the DXIL spec, the minimum load/store granularity is
45737ec681f3Smrg      * 32-bit, anything smaller requires using a read-extract/read-write-modify
45747ec681f3Smrg      * approach. Non-atomic 64-bit accesses are allowed, but the
45757ec681f3Smrg      * GEP(cast(gvar, u64[] *), offset) and cast(GEP(gvar, offset), u64 *))
45767ec681f3Smrg      * sequences don't seem to be accepted by the DXIL validator when the
45777ec681f3Smrg      * pointer is in the groupshared address space, making the 32-bit -> 64-bit
45787ec681f3Smrg      * pointer cast impossible.
45797ec681f3Smrg      */
45807ec681f3Smrg      size = ALIGN_POT(ctx->shader->info.shared_size, sizeof(uint32_t));
45817ec681f3Smrg      type = dxil_module_get_array_type(&ctx->mod,
45827ec681f3Smrg                                        dxil_module_get_int_type(&ctx->mod, 32),
45837ec681f3Smrg                                        size / sizeof(uint32_t));
45847ec681f3Smrg      ctx->sharedvars = dxil_add_global_ptr_var(&ctx->mod, "shared", type,
45857ec681f3Smrg                                                DXIL_AS_GROUPSHARED,
45867ec681f3Smrg                                                ffs(sizeof(uint64_t)),
45877ec681f3Smrg                                                NULL);
45887ec681f3Smrg   }
45897ec681f3Smrg
45907ec681f3Smrg   if (!emit_scratch(ctx))
45917ec681f3Smrg      return false;
45927ec681f3Smrg
45937ec681f3Smrg   /* UAVs */
45947ec681f3Smrg   if (ctx->shader->info.stage == MESA_SHADER_KERNEL) {
45957ec681f3Smrg      if (!emit_globals(ctx, opts->num_kernel_globals))
45967ec681f3Smrg         return false;
45977ec681f3Smrg
45987ec681f3Smrg      ctx->consts = _mesa_pointer_hash_table_create(ctx->ralloc_ctx);
45997ec681f3Smrg      if (!ctx->consts)
46007ec681f3Smrg         return false;
46017ec681f3Smrg      if (!emit_global_consts(ctx))
46027ec681f3Smrg         return false;
46037ec681f3Smrg   } else {
46047ec681f3Smrg      /* Handle read/write SSBOs as UAVs */
46057ec681f3Smrg      nir_foreach_variable_with_modes(var, ctx->shader, nir_var_mem_ssbo) {
46067ec681f3Smrg         if ((var->data.access & ACCESS_NON_WRITEABLE) == 0) {
46077ec681f3Smrg            unsigned count = 1;
46087ec681f3Smrg            if (glsl_type_is_array(var->type))
46097ec681f3Smrg               count = glsl_get_length(var->type);
46107ec681f3Smrg            if (!emit_uav(ctx, var->data.binding, var->data.descriptor_set,
46117ec681f3Smrg                        count, DXIL_COMP_TYPE_INVALID,
46127ec681f3Smrg                        DXIL_RESOURCE_KIND_RAW_BUFFER, var->name))
46137ec681f3Smrg               return false;
46147ec681f3Smrg
46157ec681f3Smrg         }
46167ec681f3Smrg      }
46177ec681f3Smrg   }
46187ec681f3Smrg
46197ec681f3Smrg   nir_foreach_variable_with_modes(var, ctx->shader, nir_var_uniform) {
46207ec681f3Smrg      if (var->data.mode == nir_var_uniform && glsl_type_is_image(glsl_without_array(var->type))) {
46217ec681f3Smrg         if (!emit_uav_var(ctx, var, glsl_type_get_image_count(var->type)))
46227ec681f3Smrg            return false;
46237ec681f3Smrg      }
46247ec681f3Smrg   }
46257ec681f3Smrg
46267ec681f3Smrg   nir_function_impl *entry = nir_shader_get_entrypoint(ctx->shader);
46277ec681f3Smrg   nir_metadata_require(entry, nir_metadata_block_index);
46287ec681f3Smrg
46297ec681f3Smrg   assert(entry->num_blocks > 0);
46307ec681f3Smrg   ctx->mod.basic_block_ids = rzalloc_array(ctx->ralloc_ctx, int,
46317ec681f3Smrg                                            entry->num_blocks);
46327ec681f3Smrg   if (!ctx->mod.basic_block_ids)
46337ec681f3Smrg      return false;
46347ec681f3Smrg
46357ec681f3Smrg   for (int i = 0; i < entry->num_blocks; ++i)
46367ec681f3Smrg      ctx->mod.basic_block_ids[i] = -1;
46377ec681f3Smrg   ctx->mod.num_basic_block_ids = entry->num_blocks;
46387ec681f3Smrg
46397ec681f3Smrg   ctx->defs = rzalloc_array(ctx->ralloc_ctx, struct dxil_def,
46407ec681f3Smrg                             entry->ssa_alloc);
46417ec681f3Smrg   if (!ctx->defs)
46427ec681f3Smrg      return false;
46437ec681f3Smrg   ctx->num_defs = entry->ssa_alloc;
46447ec681f3Smrg
46457ec681f3Smrg   ctx->phis = _mesa_pointer_hash_table_create(ctx->ralloc_ctx);
46467ec681f3Smrg   if (!ctx->phis)
46477ec681f3Smrg      return false;
46487ec681f3Smrg
46497ec681f3Smrg   prepare_phi_values(ctx);
46507ec681f3Smrg
46517ec681f3Smrg   if (!emit_cf_list(ctx, &entry->body))
46527ec681f3Smrg      return false;
46537ec681f3Smrg
46547ec681f3Smrg   hash_table_foreach(ctx->phis, entry) {
46557ec681f3Smrg      fixup_phi(ctx, (nir_phi_instr *)entry->key,
46567ec681f3Smrg                (struct phi_block *)entry->data);
46577ec681f3Smrg   }
46587ec681f3Smrg
46597ec681f3Smrg   if (!dxil_emit_ret_void(&ctx->mod))
46607ec681f3Smrg      return false;
46617ec681f3Smrg
46627ec681f3Smrg   if (ctx->shader->info.stage == MESA_SHADER_FRAGMENT) {
46637ec681f3Smrg      nir_foreach_variable_with_modes(var, ctx->shader, nir_var_shader_out) {
46647ec681f3Smrg         if (var->data.location == FRAG_RESULT_STENCIL) {
46657ec681f3Smrg            ctx->mod.feats.stencil_ref = true;
46667ec681f3Smrg         }
46677ec681f3Smrg      }
46687ec681f3Smrg   }
46697ec681f3Smrg
46707ec681f3Smrg   if (ctx->mod.feats.native_low_precision)
46717ec681f3Smrg      ctx->mod.minor_version = MAX2(ctx->mod.minor_version, 2);
46727ec681f3Smrg
46737ec681f3Smrg   return emit_metadata(ctx) &&
46747ec681f3Smrg          dxil_emit_module(&ctx->mod);
46757ec681f3Smrg}
46767ec681f3Smrg
46777ec681f3Smrgstatic unsigned int
46787ec681f3Smrgget_dxil_shader_kind(struct nir_shader *s)
46797ec681f3Smrg{
46807ec681f3Smrg   switch (s->info.stage) {
46817ec681f3Smrg   case MESA_SHADER_VERTEX:
46827ec681f3Smrg      return DXIL_VERTEX_SHADER;
46837ec681f3Smrg   case MESA_SHADER_GEOMETRY:
46847ec681f3Smrg      return DXIL_GEOMETRY_SHADER;
46857ec681f3Smrg   case MESA_SHADER_FRAGMENT:
46867ec681f3Smrg      return DXIL_PIXEL_SHADER;
46877ec681f3Smrg   case MESA_SHADER_KERNEL:
46887ec681f3Smrg   case MESA_SHADER_COMPUTE:
46897ec681f3Smrg      return DXIL_COMPUTE_SHADER;
46907ec681f3Smrg   default:
46917ec681f3Smrg      unreachable("unknown shader stage in nir_to_dxil");
46927ec681f3Smrg      return DXIL_COMPUTE_SHADER;
46937ec681f3Smrg   }
46947ec681f3Smrg}
46957ec681f3Smrg
46967ec681f3Smrgstatic unsigned
46977ec681f3Smrglower_bit_size_callback(const nir_instr* instr, void *data)
46987ec681f3Smrg{
46997ec681f3Smrg   if (instr->type != nir_instr_type_alu)
47007ec681f3Smrg      return 0;
47017ec681f3Smrg   const nir_alu_instr *alu = nir_instr_as_alu(instr);
47027ec681f3Smrg
47037ec681f3Smrg   if (nir_op_infos[alu->op].is_conversion)
47047ec681f3Smrg      return 0;
47057ec681f3Smrg
47067ec681f3Smrg   unsigned num_inputs = nir_op_infos[alu->op].num_inputs;
47077ec681f3Smrg   const struct nir_to_dxil_options *opts = (const struct nir_to_dxil_options*)data;
47087ec681f3Smrg   unsigned min_bit_size = opts->lower_int16 ? 32 : 16;
47097ec681f3Smrg
47107ec681f3Smrg   unsigned ret = 0;
47117ec681f3Smrg   for (unsigned i = 0; i < num_inputs; i++) {
47127ec681f3Smrg      unsigned bit_size = nir_src_bit_size(alu->src[i].src);
47137ec681f3Smrg      if (bit_size != 1 && bit_size < min_bit_size)
47147ec681f3Smrg         ret = min_bit_size;
47157ec681f3Smrg   }
47167ec681f3Smrg
47177ec681f3Smrg   return ret;
47187ec681f3Smrg}
47197ec681f3Smrg
47207ec681f3Smrgstatic void
47217ec681f3Smrgoptimize_nir(struct nir_shader *s, const struct nir_to_dxil_options *opts)
47227ec681f3Smrg{
47237ec681f3Smrg   bool progress;
47247ec681f3Smrg   do {
47257ec681f3Smrg      progress = false;
47267ec681f3Smrg      NIR_PASS_V(s, nir_lower_vars_to_ssa);
47277ec681f3Smrg      NIR_PASS(progress, s, nir_lower_indirect_derefs, nir_var_function_temp, UINT32_MAX);
47287ec681f3Smrg      NIR_PASS(progress, s, nir_lower_alu_to_scalar, NULL, NULL);
47297ec681f3Smrg      NIR_PASS(progress, s, nir_copy_prop);
47307ec681f3Smrg      NIR_PASS(progress, s, nir_opt_copy_prop_vars);
47317ec681f3Smrg      NIR_PASS(progress, s, nir_lower_bit_size, lower_bit_size_callback, (void*)opts);
47327ec681f3Smrg      NIR_PASS(progress, s, dxil_nir_lower_8bit_conv);
47337ec681f3Smrg      if (opts->lower_int16)
47347ec681f3Smrg         NIR_PASS(progress, s, dxil_nir_lower_16bit_conv);
47357ec681f3Smrg      NIR_PASS(progress, s, nir_opt_remove_phis);
47367ec681f3Smrg      NIR_PASS(progress, s, nir_opt_dce);
47377ec681f3Smrg      NIR_PASS(progress, s, nir_opt_if, true);
47387ec681f3Smrg      NIR_PASS(progress, s, nir_opt_dead_cf);
47397ec681f3Smrg      NIR_PASS(progress, s, nir_opt_cse);
47407ec681f3Smrg      NIR_PASS(progress, s, nir_opt_peephole_select, 8, true, true);
47417ec681f3Smrg      NIR_PASS(progress, s, nir_opt_algebraic);
47427ec681f3Smrg      NIR_PASS(progress, s, dxil_nir_lower_x2b);
47437ec681f3Smrg      if (s->options->lower_int64_options)
47447ec681f3Smrg         NIR_PASS(progress, s, nir_lower_int64);
47457ec681f3Smrg      NIR_PASS(progress, s, nir_lower_alu);
47467ec681f3Smrg      NIR_PASS(progress, s, dxil_nir_lower_inot);
47477ec681f3Smrg      NIR_PASS(progress, s, nir_opt_constant_folding);
47487ec681f3Smrg      NIR_PASS(progress, s, nir_opt_undef);
47497ec681f3Smrg      NIR_PASS(progress, s, nir_lower_undef_to_zero);
47507ec681f3Smrg      NIR_PASS(progress, s, nir_opt_deref);
47517ec681f3Smrg      NIR_PASS(progress, s, dxil_nir_lower_upcast_phis, opts->lower_int16 ? 32 : 16);
47527ec681f3Smrg      NIR_PASS(progress, s, nir_lower_64bit_phis);
47537ec681f3Smrg      NIR_PASS_V(s, nir_lower_system_values);
47547ec681f3Smrg   } while (progress);
47557ec681f3Smrg
47567ec681f3Smrg   do {
47577ec681f3Smrg      progress = false;
47587ec681f3Smrg      NIR_PASS(progress, s, nir_opt_algebraic_late);
47597ec681f3Smrg   } while (progress);
47607ec681f3Smrg}
47617ec681f3Smrg
47627ec681f3Smrgstatic
47637ec681f3Smrgvoid dxil_fill_validation_state(struct ntd_context *ctx,
47647ec681f3Smrg                                struct dxil_validation_state *state)
47657ec681f3Smrg{
47667ec681f3Smrg   state->num_resources = util_dynarray_num_elements(&ctx->resources, struct dxil_resource);
47677ec681f3Smrg   state->resources = (struct dxil_resource*)ctx->resources.data;
47687ec681f3Smrg   state->state.psv0.max_expected_wave_lane_count = UINT_MAX;
47697ec681f3Smrg   state->state.shader_stage = (uint8_t)ctx->mod.shader_kind;
47707ec681f3Smrg   state->state.sig_input_elements = (uint8_t)ctx->mod.num_sig_inputs;
47717ec681f3Smrg   state->state.sig_output_elements = (uint8_t)ctx->mod.num_sig_outputs;
47727ec681f3Smrg   //state->state.sig_patch_const_or_prim_elements = 0;
47737ec681f3Smrg
47747ec681f3Smrg   switch (ctx->mod.shader_kind) {
47757ec681f3Smrg   case DXIL_VERTEX_SHADER:
47767ec681f3Smrg      state->state.psv0.vs.output_position_present = ctx->mod.info.has_out_position;
47777ec681f3Smrg      break;
47787ec681f3Smrg   case DXIL_PIXEL_SHADER:
47797ec681f3Smrg      /* TODO: handle depth outputs */
47807ec681f3Smrg      state->state.psv0.ps.depth_output = ctx->mod.info.has_out_depth;
47817ec681f3Smrg      state->state.psv0.ps.sample_frequency =
47827ec681f3Smrg         ctx->mod.info.has_per_sample_input;
47837ec681f3Smrg      break;
47847ec681f3Smrg   case DXIL_COMPUTE_SHADER:
47857ec681f3Smrg      break;
47867ec681f3Smrg   case DXIL_GEOMETRY_SHADER:
47877ec681f3Smrg      state->state.max_vertex_count = ctx->shader->info.gs.vertices_out;
47887ec681f3Smrg      state->state.psv0.gs.input_primitive = dxil_get_input_primitive(ctx->shader->info.gs.input_primitive);
47897ec681f3Smrg      state->state.psv0.gs.output_toplology = dxil_get_primitive_topology(ctx->shader->info.gs.output_primitive);
47907ec681f3Smrg      state->state.psv0.gs.output_stream_mask = ctx->shader->info.gs.active_stream_mask;
47917ec681f3Smrg      state->state.psv0.gs.output_position_present = ctx->mod.info.has_out_position;
47927ec681f3Smrg      break;
47937ec681f3Smrg   default:
47947ec681f3Smrg      assert(0 && "Shader type not (yet) supported");
47957ec681f3Smrg   }
47967ec681f3Smrg}
47977ec681f3Smrg
47987ec681f3Smrgstatic nir_variable *
47997ec681f3Smrgadd_sysvalue(struct ntd_context *ctx,
48007ec681f3Smrg              uint8_t value, char *name,
48017ec681f3Smrg              int driver_location)
48027ec681f3Smrg{
48037ec681f3Smrg
48047ec681f3Smrg   nir_variable *var = rzalloc(ctx->shader, nir_variable);
48057ec681f3Smrg   if (!var)
48067ec681f3Smrg      return NULL;
48077ec681f3Smrg   var->data.driver_location = driver_location;
48087ec681f3Smrg   var->data.location = value;
48097ec681f3Smrg   var->type = glsl_uint_type();
48107ec681f3Smrg   var->name = name;
48117ec681f3Smrg   var->data.mode = nir_var_system_value;
48127ec681f3Smrg   var->data.interpolation = INTERP_MODE_FLAT;
48137ec681f3Smrg   return var;
48147ec681f3Smrg}
48157ec681f3Smrg
48167ec681f3Smrgstatic bool
48177ec681f3Smrgappend_input_or_sysvalue(struct ntd_context *ctx,
48187ec681f3Smrg                         int input_loc,  int sv_slot,
48197ec681f3Smrg                         char *name, int driver_location)
48207ec681f3Smrg{
48217ec681f3Smrg   if (input_loc >= 0) {
48227ec681f3Smrg      /* Check inputs whether a variable is available the corresponds
48237ec681f3Smrg       * to the sysvalue */
48247ec681f3Smrg      nir_foreach_variable_with_modes(var, ctx->shader, nir_var_shader_in) {
48257ec681f3Smrg         if (var->data.location == input_loc) {
48267ec681f3Smrg            ctx->system_value[sv_slot] = var;
48277ec681f3Smrg            return true;
48287ec681f3Smrg         }
48297ec681f3Smrg      }
48307ec681f3Smrg   }
48317ec681f3Smrg
48327ec681f3Smrg   ctx->system_value[sv_slot] = add_sysvalue(ctx, sv_slot, name, driver_location);
48337ec681f3Smrg   if (!ctx->system_value[sv_slot])
48347ec681f3Smrg      return false;
48357ec681f3Smrg
48367ec681f3Smrg   nir_shader_add_variable(ctx->shader, ctx->system_value[sv_slot]);
48377ec681f3Smrg   return true;
48387ec681f3Smrg}
48397ec681f3Smrg
48407ec681f3Smrgstruct sysvalue_name {
48417ec681f3Smrg   gl_system_value value;
48427ec681f3Smrg   int slot;
48437ec681f3Smrg   char *name;
48447ec681f3Smrg} possible_sysvalues[] = {
48457ec681f3Smrg   {SYSTEM_VALUE_VERTEX_ID_ZERO_BASE, -1, "SV_VertexID"},
48467ec681f3Smrg   {SYSTEM_VALUE_INSTANCE_ID, -1, "SV_InstanceID"},
48477ec681f3Smrg   {SYSTEM_VALUE_FRONT_FACE, VARYING_SLOT_FACE, "SV_IsFrontFace"},
48487ec681f3Smrg   {SYSTEM_VALUE_PRIMITIVE_ID, VARYING_SLOT_PRIMITIVE_ID, "SV_PrimitiveID"},
48497ec681f3Smrg   {SYSTEM_VALUE_SAMPLE_ID, -1, "SV_SampleIndex"},
48507ec681f3Smrg};
48517ec681f3Smrg
48527ec681f3Smrgstatic bool
48537ec681f3Smrgallocate_sysvalues(struct ntd_context *ctx)
48547ec681f3Smrg{
48557ec681f3Smrg   unsigned driver_location = 0;
48567ec681f3Smrg   nir_foreach_variable_with_modes(var, ctx->shader, nir_var_shader_in)
48577ec681f3Smrg      driver_location++;
48587ec681f3Smrg   nir_foreach_variable_with_modes(var, ctx->shader, nir_var_system_value)
48597ec681f3Smrg      driver_location++;
48607ec681f3Smrg
48617ec681f3Smrg   for (unsigned i = 0; i < ARRAY_SIZE(possible_sysvalues); ++i) {
48627ec681f3Smrg      struct sysvalue_name *info = &possible_sysvalues[i];
48637ec681f3Smrg      if (BITSET_TEST(ctx->shader->info.system_values_read, info->value)) {
48647ec681f3Smrg         if (!append_input_or_sysvalue(ctx, info->slot,
48657ec681f3Smrg                                       info->value, info->name,
48667ec681f3Smrg                                       driver_location++))
48677ec681f3Smrg            return false;
48687ec681f3Smrg      }
48697ec681f3Smrg   }
48707ec681f3Smrg   return true;
48717ec681f3Smrg}
48727ec681f3Smrg
48737ec681f3Smrgbool
48747ec681f3Smrgnir_to_dxil(struct nir_shader *s, const struct nir_to_dxil_options *opts,
48757ec681f3Smrg            struct blob *blob)
48767ec681f3Smrg{
48777ec681f3Smrg   assert(opts);
48787ec681f3Smrg   bool retval = true;
48797ec681f3Smrg   debug_dxil = (int)debug_get_option_debug_dxil();
48807ec681f3Smrg   blob_init(blob);
48817ec681f3Smrg
48827ec681f3Smrg   struct ntd_context *ctx = calloc(1, sizeof(*ctx));
48837ec681f3Smrg   if (!ctx)
48847ec681f3Smrg      return false;
48857ec681f3Smrg
48867ec681f3Smrg   ctx->opts = opts;
48877ec681f3Smrg   ctx->shader = s;
48887ec681f3Smrg
48897ec681f3Smrg   ctx->ralloc_ctx = ralloc_context(NULL);
48907ec681f3Smrg   if (!ctx->ralloc_ctx) {
48917ec681f3Smrg      retval = false;
48927ec681f3Smrg      goto out;
48937ec681f3Smrg   }
48947ec681f3Smrg
48957ec681f3Smrg   util_dynarray_init(&ctx->srv_metadata_nodes, ctx->ralloc_ctx);
48967ec681f3Smrg   util_dynarray_init(&ctx->uav_metadata_nodes, ctx->ralloc_ctx);
48977ec681f3Smrg   util_dynarray_init(&ctx->cbv_metadata_nodes, ctx->ralloc_ctx);
48987ec681f3Smrg   util_dynarray_init(&ctx->sampler_metadata_nodes, ctx->ralloc_ctx);
48997ec681f3Smrg   util_dynarray_init(&ctx->resources, ctx->ralloc_ctx);
49007ec681f3Smrg   dxil_module_init(&ctx->mod, ctx->ralloc_ctx);
49017ec681f3Smrg   ctx->mod.shader_kind = get_dxil_shader_kind(s);
49027ec681f3Smrg   ctx->mod.major_version = 6;
49037ec681f3Smrg   ctx->mod.minor_version = 1;
49047ec681f3Smrg
49057ec681f3Smrg   NIR_PASS_V(s, nir_lower_pack);
49067ec681f3Smrg   NIR_PASS_V(s, nir_lower_frexp);
49077ec681f3Smrg   NIR_PASS_V(s, nir_lower_flrp, 16 | 32 | 64, true);
49087ec681f3Smrg
49097ec681f3Smrg   optimize_nir(s, opts);
49107ec681f3Smrg
49117ec681f3Smrg   NIR_PASS_V(s, nir_remove_dead_variables,
49127ec681f3Smrg              nir_var_function_temp | nir_var_shader_temp, NULL);
49137ec681f3Smrg
49147ec681f3Smrg   if (!allocate_sysvalues(ctx))
49157ec681f3Smrg      return false;
49167ec681f3Smrg
49177ec681f3Smrg   if (debug_dxil & DXIL_DEBUG_VERBOSE)
49187ec681f3Smrg      nir_print_shader(s, stderr);
49197ec681f3Smrg
49207ec681f3Smrg   if (!emit_module(ctx, opts)) {
49217ec681f3Smrg      debug_printf("D3D12: dxil_container_add_module failed\n");
49227ec681f3Smrg      retval = false;
49237ec681f3Smrg      goto out;
49247ec681f3Smrg   }
49257ec681f3Smrg
49267ec681f3Smrg   if (debug_dxil & DXIL_DEBUG_DUMP_MODULE) {
49277ec681f3Smrg      struct dxil_dumper *dumper = dxil_dump_create();
49287ec681f3Smrg      dxil_dump_module(dumper, &ctx->mod);
49297ec681f3Smrg      fprintf(stderr, "\n");
49307ec681f3Smrg      dxil_dump_buf_to_file(dumper, stderr);
49317ec681f3Smrg      fprintf(stderr, "\n\n");
49327ec681f3Smrg      dxil_dump_free(dumper);
49337ec681f3Smrg   }
49347ec681f3Smrg
49357ec681f3Smrg   struct dxil_container container;
49367ec681f3Smrg   dxil_container_init(&container);
49377ec681f3Smrg   if (!dxil_container_add_features(&container, &ctx->mod.feats)) {
49387ec681f3Smrg      debug_printf("D3D12: dxil_container_add_features failed\n");
49397ec681f3Smrg      retval = false;
49407ec681f3Smrg      goto out;
49417ec681f3Smrg   }
49427ec681f3Smrg
49437ec681f3Smrg   if (!dxil_container_add_io_signature(&container,
49447ec681f3Smrg                                        DXIL_ISG1,
49457ec681f3Smrg                                        ctx->mod.num_sig_inputs,
49467ec681f3Smrg                                        ctx->mod.inputs)) {
49477ec681f3Smrg      debug_printf("D3D12: failed to write input signature\n");
49487ec681f3Smrg      retval = false;
49497ec681f3Smrg      goto out;
49507ec681f3Smrg   }
49517ec681f3Smrg
49527ec681f3Smrg   if (!dxil_container_add_io_signature(&container,
49537ec681f3Smrg                                        DXIL_OSG1,
49547ec681f3Smrg                                        ctx->mod.num_sig_outputs,
49557ec681f3Smrg                                        ctx->mod.outputs)) {
49567ec681f3Smrg      debug_printf("D3D12: failed to write output signature\n");
49577ec681f3Smrg      retval = false;
49587ec681f3Smrg      goto out;
49597ec681f3Smrg   }
49607ec681f3Smrg
49617ec681f3Smrg   struct dxil_validation_state validation_state;
49627ec681f3Smrg   memset(&validation_state, 0, sizeof(validation_state));
49637ec681f3Smrg   dxil_fill_validation_state(ctx, &validation_state);
49647ec681f3Smrg
49657ec681f3Smrg   if (!dxil_container_add_state_validation(&container,&ctx->mod,
49667ec681f3Smrg                                            &validation_state)) {
49677ec681f3Smrg      debug_printf("D3D12: failed to write state-validation\n");
49687ec681f3Smrg      retval = false;
49697ec681f3Smrg      goto out;
49707ec681f3Smrg   }
49717ec681f3Smrg
49727ec681f3Smrg   if (!dxil_container_add_module(&container, &ctx->mod)) {
49737ec681f3Smrg      debug_printf("D3D12: failed to write module\n");
49747ec681f3Smrg      retval = false;
49757ec681f3Smrg      goto out;
49767ec681f3Smrg   }
49777ec681f3Smrg
49787ec681f3Smrg   if (!dxil_container_write(&container, blob)) {
49797ec681f3Smrg      debug_printf("D3D12: dxil_container_write failed\n");
49807ec681f3Smrg      retval = false;
49817ec681f3Smrg      goto out;
49827ec681f3Smrg   }
49837ec681f3Smrg   dxil_container_finish(&container);
49847ec681f3Smrg
49857ec681f3Smrg   if (debug_dxil & DXIL_DEBUG_DUMP_BLOB) {
49867ec681f3Smrg      static int shader_id = 0;
49877ec681f3Smrg      char buffer[64];
49887ec681f3Smrg      snprintf(buffer, sizeof(buffer), "shader_%s_%d.blob",
49897ec681f3Smrg               get_shader_kind_str(ctx->mod.shader_kind), shader_id++);
49907ec681f3Smrg      debug_printf("Try to write blob to %s\n", buffer);
49917ec681f3Smrg      FILE *f = fopen(buffer, "wb");
49927ec681f3Smrg      if (f) {
49937ec681f3Smrg         fwrite(blob->data, 1, blob->size, f);
49947ec681f3Smrg         fclose(f);
49957ec681f3Smrg      }
49967ec681f3Smrg   }
49977ec681f3Smrg
49987ec681f3Smrgout:
49997ec681f3Smrg   dxil_module_release(&ctx->mod);
50007ec681f3Smrg   ralloc_free(ctx->ralloc_ctx);
50017ec681f3Smrg   free(ctx);
50027ec681f3Smrg   return retval;
50037ec681f3Smrg}
50047ec681f3Smrg
50057ec681f3Smrgenum dxil_sysvalue_type
50067ec681f3Smrgnir_var_to_dxil_sysvalue_type(nir_variable *var, uint64_t other_stage_mask)
50077ec681f3Smrg{
50087ec681f3Smrg   switch (var->data.location) {
50097ec681f3Smrg   case VARYING_SLOT_FACE:
50107ec681f3Smrg      return DXIL_GENERATED_SYSVALUE;
50117ec681f3Smrg   case VARYING_SLOT_POS:
50127ec681f3Smrg   case VARYING_SLOT_PRIMITIVE_ID:
50137ec681f3Smrg   case VARYING_SLOT_CLIP_DIST0:
50147ec681f3Smrg   case VARYING_SLOT_CLIP_DIST1:
50157ec681f3Smrg   case VARYING_SLOT_PSIZ:
50167ec681f3Smrg      if (!((1ull << var->data.location) & other_stage_mask))
50177ec681f3Smrg         return DXIL_SYSVALUE;
50187ec681f3Smrg      FALLTHROUGH;
50197ec681f3Smrg   default:
50207ec681f3Smrg      return DXIL_NO_SYSVALUE;
50217ec681f3Smrg   }
50227ec681f3Smrg}
5023