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 "dxil_function.h"
257ec681f3Smrg#include "dxil_module.h"
267ec681f3Smrg
277ec681f3Smrg#define MAX_FUNC_PARAMS 17
287ec681f3Smrg
297ec681f3Smrgstruct predefined_func_descr {
307ec681f3Smrg   const char *base_name;
317ec681f3Smrg   const char *retval_descr;
327ec681f3Smrg   const char *param_descr;
337ec681f3Smrg   enum dxil_attr_kind attr;
347ec681f3Smrg};
357ec681f3Smrg
367ec681f3Smrgstatic struct  predefined_func_descr predefined_funcs[] = {
377ec681f3Smrg{"dx.op.atomicBinOp", "O", "i@iiiii", DXIL_ATTR_KIND_READ_NONE},
387ec681f3Smrg{"dx.op.cbufferLoad", "O", "i@ii", DXIL_ATTR_KIND_READ_ONLY},
397ec681f3Smrg{"dx.op.cbufferLoadLegacy", "B", "i@i", DXIL_ATTR_KIND_READ_ONLY},
407ec681f3Smrg{"dx.op.createHandle", "@", "iciib", DXIL_ATTR_KIND_READ_ONLY},
417ec681f3Smrg{"dx.op.storeOutput", "v", "iiicO", DXIL_ATTR_KIND_NO_UNWIND},
427ec681f3Smrg{"dx.op.loadInput", "O", "iiici", DXIL_ATTR_KIND_READ_NONE},
437ec681f3Smrg{"dx.op.tertiary", "O", "iOOO", DXIL_ATTR_KIND_READ_NONE},
447ec681f3Smrg{"dx.op.threadId", "i", "ii", DXIL_ATTR_KIND_READ_NONE},
457ec681f3Smrg{"dx.op.threadIdInGroup", "i", "ii", DXIL_ATTR_KIND_READ_NONE},
467ec681f3Smrg{"dx.op.flattenedThreadIdInGroup", "i", "i", DXIL_ATTR_KIND_READ_NONE},
477ec681f3Smrg{"dx.op.groupId", "i", "ii", DXIL_ATTR_KIND_READ_NONE},
487ec681f3Smrg{"dx.op.unary", "O", "iO", DXIL_ATTR_KIND_READ_NONE},
497ec681f3Smrg{"dx.op.unaryBits", "i", "iO", DXIL_ATTR_KIND_READ_NONE},
507ec681f3Smrg{"dx.op.isSpecialFloat", "b", "iO", DXIL_ATTR_KIND_READ_NONE},
517ec681f3Smrg{"dx.op.binary", "O", "iOO", DXIL_ATTR_KIND_READ_NONE},
527ec681f3Smrg{"dx.op.bufferStore", "v", "i@iiOOOOc", DXIL_ATTR_KIND_NONE},
537ec681f3Smrg{"dx.op.bufferLoad", "R", "i@ii", DXIL_ATTR_KIND_READ_ONLY},
547ec681f3Smrg{"dx.op.attributeAtVertex", "O", "iiicc", DXIL_ATTR_KIND_READ_NONE},
557ec681f3Smrg{"dx.op.sample", "R", "i@@ffffiiif", DXIL_ATTR_KIND_READ_ONLY},
567ec681f3Smrg{"dx.op.sampleBias", "R", "i@@ffffiiiff", DXIL_ATTR_KIND_READ_ONLY},
577ec681f3Smrg{"dx.op.sampleLevel", "R", "i@@ffffiiif", DXIL_ATTR_KIND_READ_ONLY},
587ec681f3Smrg{"dx.op.sampleGrad", "R", "i@@ffffiiifffffff", DXIL_ATTR_KIND_READ_ONLY},
597ec681f3Smrg{"dx.op.sampleCmp", "R", "i@@ffffiiiff", DXIL_ATTR_KIND_READ_ONLY},
607ec681f3Smrg{"dx.op.sampleCmpLevelZero", "R", "i@@ffffiiif", DXIL_ATTR_KIND_READ_ONLY},
617ec681f3Smrg{"dx.op.textureLoad", "R", "i@iiiiiii", DXIL_ATTR_KIND_READ_ONLY},
627ec681f3Smrg{"dx.op.discard", "v", "ib", DXIL_ATTR_KIND_READ_NONE},
637ec681f3Smrg{"dx.op.sampleIndex", "i", "i", DXIL_ATTR_KIND_READ_NONE},
647ec681f3Smrg{"dx.op.emitStream", "v", "ic", DXIL_ATTR_KIND_NONE},
657ec681f3Smrg{"dx.op.cutStream", "v", "ic", DXIL_ATTR_KIND_NONE},
667ec681f3Smrg{"dx.op.getDimensions", "D", "i@i", DXIL_ATTR_KIND_READ_ONLY},
677ec681f3Smrg{"dx.op.calculateLOD", "f", "i@@fffb", DXIL_ATTR_KIND_READ_ONLY},
687ec681f3Smrg{"dx.op.barrier", "v", "ii", DXIL_ATTR_KIND_NO_DUPLICATE},
697ec681f3Smrg{"dx.op.atomicCompareExchange", "O", "i@iiiii", DXIL_ATTR_KIND_READ_NONE},
707ec681f3Smrg{"dx.op.textureStore", "v", "i@iiiOOOOc", DXIL_ATTR_KIND_NONE},
717ec681f3Smrg{"dx.op.primitiveID", "i", "i", DXIL_ATTR_KIND_READ_NONE},
727ec681f3Smrg{"dx.op.legacyF16ToF32", "f", "ii", DXIL_ATTR_KIND_READ_ONLY},
737ec681f3Smrg{"dx.op.legacyF32ToF16", "i", "if", DXIL_ATTR_KIND_READ_ONLY},
747ec681f3Smrg{"dx.op.makeDouble", "g", "iii", DXIL_ATTR_KIND_READ_NONE},
757ec681f3Smrg{"dx.op.splitDouble", "G", "ig", DXIL_ATTR_KIND_READ_NONE},
767ec681f3Smrg};
777ec681f3Smrg
787ec681f3Smrgstruct func_descr {
797ec681f3Smrg   const char *name;
807ec681f3Smrg   enum overload_type overload;
817ec681f3Smrg};
827ec681f3Smrg
837ec681f3Smrgstruct func_rb_node {
847ec681f3Smrg   struct rb_node node;
857ec681f3Smrg   const struct dxil_func *func;
867ec681f3Smrg   struct func_descr descr;
877ec681f3Smrg};
887ec681f3Smrg
897ec681f3Smrgstatic inline
907ec681f3Smrgconst struct func_rb_node *
917ec681f3Smrgfunc_rb_node(const struct rb_node *n)
927ec681f3Smrg{
937ec681f3Smrg   return (const struct func_rb_node *)n;
947ec681f3Smrg}
957ec681f3Smrg
967ec681f3Smrgstatic int
977ec681f3Smrgfunc_compare_to_name_and_overload(const struct rb_node *node, const void *data)
987ec681f3Smrg{
997ec681f3Smrg   const struct func_descr *descr = (const struct func_descr *)data;
1007ec681f3Smrg   const struct func_rb_node *f = func_rb_node(node);
1017ec681f3Smrg   if (f->descr.overload < descr->overload)
1027ec681f3Smrg      return -1;
1037ec681f3Smrg   if (f->descr.overload > descr->overload)
1047ec681f3Smrg      return 1;
1057ec681f3Smrg
1067ec681f3Smrg   return strcmp(f->descr.name, descr->name);
1077ec681f3Smrg}
1087ec681f3Smrg
1097ec681f3Smrgstatic const struct dxil_func *
1107ec681f3Smrgallocate_function_from_predefined(struct dxil_module *mod,
1117ec681f3Smrg                                       const char *name,
1127ec681f3Smrg                                       enum overload_type overload)
1137ec681f3Smrg{
1147ec681f3Smrg   for (unsigned i = 0; i < ARRAY_SIZE(predefined_funcs); ++i) {
1157ec681f3Smrg      if (!strcmp(predefined_funcs[i].base_name, name)) {
1167ec681f3Smrg         return dxil_alloc_func(mod, name, overload,
1177ec681f3Smrg                                predefined_funcs[i].retval_descr,
1187ec681f3Smrg                                predefined_funcs[i].param_descr,
1197ec681f3Smrg                                predefined_funcs[i].attr);
1207ec681f3Smrg      }
1217ec681f3Smrg   }
1227ec681f3Smrg   return false;
1237ec681f3Smrg}
1247ec681f3Smrg
1257ec681f3Smrgconst struct dxil_func *
1267ec681f3Smrgdxil_get_function(struct dxil_module *mod,
1277ec681f3Smrg                  const char *name, enum overload_type overload)
1287ec681f3Smrg{
1297ec681f3Smrg   struct func_descr descr = { name, overload };
1307ec681f3Smrg   const struct rb_node *node = rb_tree_search(mod->functions, &descr,
1317ec681f3Smrg                                               func_compare_to_name_and_overload);
1327ec681f3Smrg   if (node)
1337ec681f3Smrg      return func_rb_node(node)->func;
1347ec681f3Smrg
1357ec681f3Smrg   return allocate_function_from_predefined(mod, name, overload);
1367ec681f3Smrg}
1377ec681f3Smrg
1387ec681f3Smrgstatic int func_compare_name(const struct rb_node *lhs, const struct rb_node *rhs)
1397ec681f3Smrg{
1407ec681f3Smrg   const struct func_rb_node *node = func_rb_node(rhs);
1417ec681f3Smrg   return func_compare_to_name_and_overload(lhs, &node->descr);
1427ec681f3Smrg}
1437ec681f3Smrg
1447ec681f3Smrgstatic void
1457ec681f3Smrgdxil_add_function(struct rb_tree *functions, const struct dxil_func *func,
1467ec681f3Smrg                  const char *name, enum overload_type overload)
1477ec681f3Smrg{
1487ec681f3Smrg   struct func_rb_node *f = rzalloc(functions, struct func_rb_node);
1497ec681f3Smrg   f->func = func;
1507ec681f3Smrg   f->descr.name = name;
1517ec681f3Smrg   f->descr.overload = overload;
1527ec681f3Smrg   rb_tree_insert(functions, &f->node, func_compare_name);
1537ec681f3Smrg}
1547ec681f3Smrg
1557ec681f3Smrgstatic const struct dxil_type *
1567ec681f3Smrgget_type_from_string(struct dxil_module *mod, const char *param_descr,
1577ec681f3Smrg                     enum overload_type overload,  int *idx)
1587ec681f3Smrg{
1597ec681f3Smrg   assert(param_descr);
1607ec681f3Smrg   char type_id = param_descr[(*idx)++];
1617ec681f3Smrg   assert(*idx <= (int)strlen(param_descr));
1627ec681f3Smrg
1637ec681f3Smrg   switch (type_id) {
1647ec681f3Smrg   case DXIL_FUNC_PARAM_INT64: return dxil_module_get_int_type(mod, 64);
1657ec681f3Smrg   case DXIL_FUNC_PARAM_INT32: return dxil_module_get_int_type(mod, 32);
1667ec681f3Smrg   case DXIL_FUNC_PARAM_INT16: return dxil_module_get_int_type(mod, 16);
1677ec681f3Smrg   case DXIL_FUNC_PARAM_INT8: return dxil_module_get_int_type(mod, 8);
1687ec681f3Smrg   case DXIL_FUNC_PARAM_BOOL: return dxil_module_get_int_type(mod, 1);
1697ec681f3Smrg   case DXIL_FUNC_PARAM_FLOAT64: return dxil_module_get_float_type(mod, 64);
1707ec681f3Smrg   case DXIL_FUNC_PARAM_FLOAT32: return dxil_module_get_float_type(mod, 32);
1717ec681f3Smrg   case DXIL_FUNC_PARAM_FLOAT16: return dxil_module_get_float_type(mod, 16);
1727ec681f3Smrg   case DXIL_FUNC_PARAM_HANDLE: return dxil_module_get_handle_type(mod);
1737ec681f3Smrg   case DXIL_FUNC_PARAM_VOID: return dxil_module_get_void_type(mod);
1747ec681f3Smrg   case DXIL_FUNC_PARAM_FROM_OVERLOAD:  return dxil_get_overload_type(mod, overload);
1757ec681f3Smrg   case DXIL_FUNC_PARAM_RESRET: return dxil_module_get_resret_type(mod, overload);
1767ec681f3Smrg   case DXIL_FUNC_PARAM_DIM: return dxil_module_get_dimret_type(mod);
1777ec681f3Smrg   case DXIL_FUNC_PARAM_CBUF_RET: return dxil_module_get_cbuf_ret_type(mod, overload);
1787ec681f3Smrg   case DXIL_FUNC_PARAM_SPLIT_DOUBLE: return dxil_module_get_split_double_ret_type(mod);
1797ec681f3Smrg   case DXIL_FUNC_PARAM_POINTER: {
1807ec681f3Smrg         const struct dxil_type *target = get_type_from_string(mod, param_descr, overload, idx);
1817ec681f3Smrg         return dxil_module_get_pointer_type(mod, target);
1827ec681f3Smrg      }
1837ec681f3Smrg   default:
1847ec681f3Smrg      assert(0 && "unknown type identifier");
1857ec681f3Smrg   }
1867ec681f3Smrg   return NULL;
1877ec681f3Smrg}
1887ec681f3Smrg
1897ec681f3Smrgconst struct dxil_func *
1907ec681f3Smrgdxil_alloc_func_with_rettype(struct dxil_module *mod, const char *name,
1917ec681f3Smrg                             enum overload_type overload,
1927ec681f3Smrg                             const struct dxil_type *retval_type,
1937ec681f3Smrg                             const char *param_descr,
1947ec681f3Smrg                             enum dxil_attr_kind attr)
1957ec681f3Smrg{
1967ec681f3Smrg   assert(param_descr);
1977ec681f3Smrg   const struct dxil_type *arg_types[MAX_FUNC_PARAMS];
1987ec681f3Smrg
1997ec681f3Smrg   int index = 0;
2007ec681f3Smrg   unsigned num_params = 0;
2017ec681f3Smrg
2027ec681f3Smrg   while (param_descr[num_params]) {
2037ec681f3Smrg      const struct dxil_type *t = get_type_from_string(mod, param_descr, overload, &index);
2047ec681f3Smrg      if (!t)
2057ec681f3Smrg         return false;
2067ec681f3Smrg      assert(num_params < MAX_FUNC_PARAMS);
2077ec681f3Smrg      arg_types[num_params++] = t;
2087ec681f3Smrg   }
2097ec681f3Smrg
2107ec681f3Smrg   const struct dxil_type *func_type =
2117ec681f3Smrg      dxil_module_add_function_type(mod, retval_type,
2127ec681f3Smrg                                    arg_types, num_params);
2137ec681f3Smrg   if (!func_type) {
2147ec681f3Smrg      fprintf(stderr, "%s: Func type allocation failed\n", __func__);
2157ec681f3Smrg      return false;
2167ec681f3Smrg   }
2177ec681f3Smrg
2187ec681f3Smrg   char full_name[100];
2197ec681f3Smrg   snprintf(full_name, sizeof (full_name), "%s%s%s", name,
2207ec681f3Smrg            overload == DXIL_NONE ? "" : ".", dxil_overload_suffix(overload));
2217ec681f3Smrg   const struct dxil_func *func = dxil_add_function_decl(mod, full_name, func_type, attr);
2227ec681f3Smrg
2237ec681f3Smrg   if (func)
2247ec681f3Smrg      dxil_add_function(mod->functions, func, name, overload);
2257ec681f3Smrg
2267ec681f3Smrg   return func;
2277ec681f3Smrg}
2287ec681f3Smrg
2297ec681f3Smrgconst struct dxil_func *
2307ec681f3Smrgdxil_alloc_func(struct dxil_module *mod, const char *name, enum overload_type overload,
2317ec681f3Smrg                const char *retval_type_descr,
2327ec681f3Smrg                const char *param_descr, enum dxil_attr_kind attr)
2337ec681f3Smrg{
2347ec681f3Smrg
2357ec681f3Smrg   int index = 0;
2367ec681f3Smrg   const struct dxil_type *retval_type = get_type_from_string(mod, retval_type_descr, overload, &index);
2377ec681f3Smrg   assert(retval_type_descr[index] == 0);
2387ec681f3Smrg
2397ec681f3Smrg   return dxil_alloc_func_with_rettype(mod, name, overload, retval_type,
2407ec681f3Smrg                                       param_descr, attr);
2417ec681f3Smrg}
242