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