1/* 2 * Copyright © Microsoft Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24#include "dxil_function.h" 25#include "dxil_module.h" 26 27#define MAX_FUNC_PARAMS 17 28 29struct predefined_func_descr { 30 const char *base_name; 31 const char *retval_descr; 32 const char *param_descr; 33 enum dxil_attr_kind attr; 34}; 35 36static struct predefined_func_descr predefined_funcs[] = { 37{"dx.op.atomicBinOp", "O", "i@iiiii", DXIL_ATTR_KIND_READ_NONE}, 38{"dx.op.cbufferLoad", "O", "i@ii", DXIL_ATTR_KIND_READ_ONLY}, 39{"dx.op.cbufferLoadLegacy", "B", "i@i", DXIL_ATTR_KIND_READ_ONLY}, 40{"dx.op.createHandle", "@", "iciib", DXIL_ATTR_KIND_READ_ONLY}, 41{"dx.op.storeOutput", "v", "iiicO", DXIL_ATTR_KIND_NO_UNWIND}, 42{"dx.op.loadInput", "O", "iiici", DXIL_ATTR_KIND_READ_NONE}, 43{"dx.op.tertiary", "O", "iOOO", DXIL_ATTR_KIND_READ_NONE}, 44{"dx.op.quaternary", "O", "iOOOO", DXIL_ATTR_KIND_READ_NONE}, 45{"dx.op.threadId", "i", "ii", DXIL_ATTR_KIND_READ_NONE}, 46{"dx.op.threadIdInGroup", "i", "ii", DXIL_ATTR_KIND_READ_NONE}, 47{"dx.op.flattenedThreadIdInGroup", "i", "i", DXIL_ATTR_KIND_READ_NONE}, 48{"dx.op.groupId", "i", "ii", DXIL_ATTR_KIND_READ_NONE}, 49{"dx.op.unary", "O", "iO", DXIL_ATTR_KIND_READ_NONE}, 50{"dx.op.unaryBits", "i", "iO", DXIL_ATTR_KIND_READ_NONE}, 51{"dx.op.isSpecialFloat", "b", "iO", DXIL_ATTR_KIND_READ_NONE}, 52{"dx.op.binary", "O", "iOO", DXIL_ATTR_KIND_READ_NONE}, 53{"dx.op.bufferStore", "v", "i@iiOOOOc", DXIL_ATTR_KIND_NONE}, 54{"dx.op.bufferLoad", "R", "i@ii", DXIL_ATTR_KIND_READ_ONLY}, 55{"dx.op.attributeAtVertex", "O", "iiicc", DXIL_ATTR_KIND_READ_NONE}, 56{"dx.op.sample", "R", "i@@ffffiiif", DXIL_ATTR_KIND_READ_ONLY}, 57{"dx.op.sampleBias", "R", "i@@ffffiiiff", DXIL_ATTR_KIND_READ_ONLY}, 58{"dx.op.sampleLevel", "R", "i@@ffffiiif", DXIL_ATTR_KIND_READ_ONLY}, 59{"dx.op.sampleGrad", "R", "i@@ffffiiifffffff", DXIL_ATTR_KIND_READ_ONLY}, 60{"dx.op.sampleCmp", "R", "i@@ffffiiiff", DXIL_ATTR_KIND_READ_ONLY}, 61{"dx.op.sampleCmpLevelZero", "R", "i@@ffffiiif", DXIL_ATTR_KIND_READ_ONLY}, 62{"dx.op.textureLoad", "R", "i@iiiiiii", DXIL_ATTR_KIND_READ_ONLY}, 63{"dx.op.textureGather", "R", "i@@ffffiii", DXIL_ATTR_KIND_READ_ONLY}, 64{"dx.op.textureGatherCmp", "R", "i@@ffffiiif", DXIL_ATTR_KIND_READ_ONLY}, 65{"dx.op.discard", "v", "ib", DXIL_ATTR_KIND_NO_UNWIND}, 66{"dx.op.sampleIndex", "i", "i", DXIL_ATTR_KIND_READ_NONE}, 67{"dx.op.emitStream", "v", "ic", DXIL_ATTR_KIND_NONE}, 68{"dx.op.cutStream", "v", "ic", DXIL_ATTR_KIND_NONE}, 69{"dx.op.getDimensions", "D", "i@i", DXIL_ATTR_KIND_READ_ONLY}, 70{"dx.op.calculateLOD", "f", "i@@fffb", DXIL_ATTR_KIND_READ_ONLY}, 71{"dx.op.barrier", "v", "ii", DXIL_ATTR_KIND_NO_DUPLICATE}, 72{"dx.op.atomicCompareExchange", "O", "i@iiiii", DXIL_ATTR_KIND_READ_NONE}, 73{"dx.op.textureStore", "v", "i@iiiOOOOc", DXIL_ATTR_KIND_NONE}, 74{"dx.op.primitiveID", "i", "i", DXIL_ATTR_KIND_READ_NONE}, 75{"dx.op.outputControlPointID", "i", "i", DXIL_ATTR_KIND_READ_NONE}, 76{"dx.op.gsInstanceID", "i", "i", DXIL_ATTR_KIND_READ_NONE}, 77{"dx.op.domainLocation", "f", "ii", DXIL_ATTR_KIND_READ_NONE}, 78{"dx.op.legacyF16ToF32", "f", "ii", DXIL_ATTR_KIND_READ_ONLY}, 79{"dx.op.legacyF32ToF16", "i", "if", DXIL_ATTR_KIND_READ_ONLY}, 80{"dx.op.makeDouble", "g", "iii", DXIL_ATTR_KIND_READ_NONE}, 81{"dx.op.splitDouble", "G", "ig", DXIL_ATTR_KIND_READ_NONE}, 82{"dx.op.texture2DMSGetSamplePosition", "S", "i@i", DXIL_ATTR_KIND_READ_ONLY}, 83{"dx.op.renderTargetGetSamplePosition", "S", "ii", DXIL_ATTR_KIND_READ_ONLY}, 84{"dx.op.evalSnapped", "O", "iiicii", DXIL_ATTR_KIND_READ_NONE}, 85{"dx.op.evalCentroid", "O", "iiic", DXIL_ATTR_KIND_READ_NONE}, 86{"dx.op.evalSampleIndex", "O", "iiici", DXIL_ATTR_KIND_READ_NONE}, 87{"dx.op.coverage", "i", "i", DXIL_ATTR_KIND_READ_NONE}, 88{"dx.op.storePatchConstant", "v", "iiicO", DXIL_ATTR_KIND_NO_UNWIND}, 89{"dx.op.loadPatchConstant", "O", "iiic", DXIL_ATTR_KIND_READ_NONE}, 90{"dx.op.loadOutputControlPoint", "O", "iiici", DXIL_ATTR_KIND_READ_NONE}, 91}; 92 93struct func_descr { 94 const char *name; 95 enum overload_type overload; 96}; 97 98struct func_rb_node { 99 struct rb_node node; 100 const struct dxil_func *func; 101 struct func_descr descr; 102}; 103 104static inline 105const struct func_rb_node * 106func_rb_node(const struct rb_node *n) 107{ 108 return (const struct func_rb_node *)n; 109} 110 111static int 112func_compare_to_name_and_overload(const struct rb_node *node, const void *data) 113{ 114 const struct func_descr *descr = (const struct func_descr *)data; 115 const struct func_rb_node *f = func_rb_node(node); 116 if (f->descr.overload < descr->overload) 117 return -1; 118 if (f->descr.overload > descr->overload) 119 return 1; 120 121 return strcmp(f->descr.name, descr->name); 122} 123 124static const struct dxil_func * 125allocate_function_from_predefined(struct dxil_module *mod, 126 const char *name, 127 enum overload_type overload) 128{ 129 for (unsigned i = 0; i < ARRAY_SIZE(predefined_funcs); ++i) { 130 if (!strcmp(predefined_funcs[i].base_name, name)) { 131 return dxil_alloc_func(mod, name, overload, 132 predefined_funcs[i].retval_descr, 133 predefined_funcs[i].param_descr, 134 predefined_funcs[i].attr); 135 } 136 } 137 unreachable("Invalid function name"); 138} 139 140const struct dxil_func * 141dxil_get_function(struct dxil_module *mod, 142 const char *name, enum overload_type overload) 143{ 144 struct func_descr descr = { name, overload }; 145 const struct rb_node *node = rb_tree_search(mod->functions, &descr, 146 func_compare_to_name_and_overload); 147 if (node) 148 return func_rb_node(node)->func; 149 150 return allocate_function_from_predefined(mod, name, overload); 151} 152 153static int func_compare_name(const struct rb_node *lhs, const struct rb_node *rhs) 154{ 155 const struct func_rb_node *node = func_rb_node(rhs); 156 return func_compare_to_name_and_overload(lhs, &node->descr); 157} 158 159static void 160dxil_add_function(struct rb_tree *functions, const struct dxil_func *func, 161 const char *name, enum overload_type overload) 162{ 163 struct func_rb_node *f = rzalloc(functions, struct func_rb_node); 164 f->func = func; 165 f->descr.name = name; 166 f->descr.overload = overload; 167 rb_tree_insert(functions, &f->node, func_compare_name); 168} 169 170static const struct dxil_type * 171get_type_from_string(struct dxil_module *mod, const char *param_descr, 172 enum overload_type overload, int *idx) 173{ 174 assert(param_descr); 175 char type_id = param_descr[(*idx)++]; 176 assert(*idx <= (int)strlen(param_descr)); 177 178 switch (type_id) { 179 case DXIL_FUNC_PARAM_INT64: return dxil_module_get_int_type(mod, 64); 180 case DXIL_FUNC_PARAM_INT32: return dxil_module_get_int_type(mod, 32); 181 case DXIL_FUNC_PARAM_INT16: return dxil_module_get_int_type(mod, 16); 182 case DXIL_FUNC_PARAM_INT8: return dxil_module_get_int_type(mod, 8); 183 case DXIL_FUNC_PARAM_BOOL: return dxil_module_get_int_type(mod, 1); 184 case DXIL_FUNC_PARAM_FLOAT64: return dxil_module_get_float_type(mod, 64); 185 case DXIL_FUNC_PARAM_FLOAT32: return dxil_module_get_float_type(mod, 32); 186 case DXIL_FUNC_PARAM_FLOAT16: return dxil_module_get_float_type(mod, 16); 187 case DXIL_FUNC_PARAM_HANDLE: return dxil_module_get_handle_type(mod); 188 case DXIL_FUNC_PARAM_VOID: return dxil_module_get_void_type(mod); 189 case DXIL_FUNC_PARAM_FROM_OVERLOAD: return dxil_get_overload_type(mod, overload); 190 case DXIL_FUNC_PARAM_RESRET: return dxil_module_get_resret_type(mod, overload); 191 case DXIL_FUNC_PARAM_DIM: return dxil_module_get_dimret_type(mod); 192 case DXIL_FUNC_PARAM_SAMPLE_POS: return dxil_module_get_samplepos_type(mod); 193 case DXIL_FUNC_PARAM_CBUF_RET: return dxil_module_get_cbuf_ret_type(mod, overload); 194 case DXIL_FUNC_PARAM_SPLIT_DOUBLE: return dxil_module_get_split_double_ret_type(mod); 195 case DXIL_FUNC_PARAM_POINTER: { 196 const struct dxil_type *target = get_type_from_string(mod, param_descr, overload, idx); 197 return dxil_module_get_pointer_type(mod, target); 198 } 199 default: 200 assert(0 && "unknown type identifier"); 201 } 202 return NULL; 203} 204 205const struct dxil_func * 206dxil_alloc_func_with_rettype(struct dxil_module *mod, const char *name, 207 enum overload_type overload, 208 const struct dxil_type *retval_type, 209 const char *param_descr, 210 enum dxil_attr_kind attr) 211{ 212 assert(param_descr); 213 const struct dxil_type *arg_types[MAX_FUNC_PARAMS]; 214 215 int index = 0; 216 unsigned num_params = 0; 217 218 while (param_descr[num_params]) { 219 const struct dxil_type *t = get_type_from_string(mod, param_descr, overload, &index); 220 if (!t) 221 return false; 222 assert(num_params < MAX_FUNC_PARAMS); 223 arg_types[num_params++] = t; 224 } 225 226 const struct dxil_type *func_type = 227 dxil_module_add_function_type(mod, retval_type, 228 arg_types, num_params); 229 if (!func_type) { 230 fprintf(stderr, "%s: Func type allocation failed\n", __func__); 231 return false; 232 } 233 234 char full_name[100]; 235 snprintf(full_name, sizeof (full_name), "%s%s%s", name, 236 overload == DXIL_NONE ? "" : ".", dxil_overload_suffix(overload)); 237 const struct dxil_func *func = dxil_add_function_decl(mod, full_name, func_type, attr); 238 239 if (func) 240 dxil_add_function(mod->functions, func, name, overload); 241 242 return func; 243} 244 245const struct dxil_func * 246dxil_alloc_func(struct dxil_module *mod, const char *name, enum overload_type overload, 247 const char *retval_type_descr, 248 const char *param_descr, enum dxil_attr_kind attr) 249{ 250 251 int index = 0; 252 const struct dxil_type *retval_type = get_type_from_string(mod, retval_type_descr, overload, &index); 253 assert(retval_type_descr[index] == 0); 254 255 return dxil_alloc_func_with_rettype(mod, name, overload, retval_type, 256 param_descr, attr); 257} 258