• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
29 struct 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 
36 static 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.threadId", "i", "ii", DXIL_ATTR_KIND_READ_NONE},
45 {"dx.op.threadIdInGroup", "i", "ii", DXIL_ATTR_KIND_READ_NONE},
46 {"dx.op.flattenedThreadIdInGroup", "i", "i", DXIL_ATTR_KIND_READ_NONE},
47 {"dx.op.groupId", "i", "ii", DXIL_ATTR_KIND_READ_NONE},
48 {"dx.op.unary", "O", "iO", DXIL_ATTR_KIND_READ_NONE},
49 {"dx.op.unaryBits", "i", "iO", DXIL_ATTR_KIND_READ_NONE},
50 {"dx.op.isSpecialFloat", "b", "iO", DXIL_ATTR_KIND_READ_NONE},
51 {"dx.op.binary", "O", "iOO", DXIL_ATTR_KIND_READ_NONE},
52 {"dx.op.bufferStore", "v", "i@iiOOOOc", DXIL_ATTR_KIND_NONE},
53 {"dx.op.bufferLoad", "R", "i@ii", DXIL_ATTR_KIND_READ_ONLY},
54 {"dx.op.attributeAtVertex", "O", "iiicc", DXIL_ATTR_KIND_READ_NONE},
55 {"dx.op.sample", "R", "i@@ffffiiif", DXIL_ATTR_KIND_READ_ONLY},
56 {"dx.op.sampleBias", "R", "i@@ffffiiiff", DXIL_ATTR_KIND_READ_ONLY},
57 {"dx.op.sampleLevel", "R", "i@@ffffiiif", DXIL_ATTR_KIND_READ_ONLY},
58 {"dx.op.sampleGrad", "R", "i@@ffffiiifffffff", DXIL_ATTR_KIND_READ_ONLY},
59 {"dx.op.sampleCmp", "R", "i@@ffffiiiff", DXIL_ATTR_KIND_READ_ONLY},
60 {"dx.op.sampleCmpLevelZero", "R", "i@@ffffiiif", DXIL_ATTR_KIND_READ_ONLY},
61 {"dx.op.textureLoad", "R", "i@iiiiiii", DXIL_ATTR_KIND_READ_ONLY},
62 {"dx.op.discard", "v", "ib", DXIL_ATTR_KIND_READ_NONE},
63 {"dx.op.sampleIndex", "i", "i", DXIL_ATTR_KIND_READ_NONE},
64 {"dx.op.emitStream", "v", "ic", DXIL_ATTR_KIND_NONE},
65 {"dx.op.cutStream", "v", "ic", DXIL_ATTR_KIND_NONE},
66 {"dx.op.getDimensions", "D", "i@i", DXIL_ATTR_KIND_READ_ONLY},
67 {"dx.op.calculateLOD", "f", "i@@fffb", DXIL_ATTR_KIND_READ_ONLY},
68 {"dx.op.barrier", "v", "ii", DXIL_ATTR_KIND_NO_DUPLICATE},
69 {"dx.op.atomicCompareExchange", "O", "i@iiiii", DXIL_ATTR_KIND_READ_NONE},
70 {"dx.op.textureStore", "v", "i@iiiOOOOc", DXIL_ATTR_KIND_NONE},
71 {"dx.op.primitiveID", "i", "i", DXIL_ATTR_KIND_READ_NONE},
72 {"dx.op.legacyF16ToF32", "f", "ii", DXIL_ATTR_KIND_READ_ONLY},
73 {"dx.op.legacyF32ToF16", "i", "if", DXIL_ATTR_KIND_READ_ONLY},
74 {"dx.op.makeDouble", "g", "iii", DXIL_ATTR_KIND_READ_NONE},
75 {"dx.op.splitDouble", "G", "ig", DXIL_ATTR_KIND_READ_NONE},
76 };
77 
78 struct func_descr {
79    const char *name;
80    enum overload_type overload;
81 };
82 
83 struct func_rb_node {
84    struct rb_node node;
85    const struct dxil_func *func;
86    struct func_descr descr;
87 };
88 
89 static inline
90 const struct func_rb_node *
func_rb_node(const struct rb_node * n)91 func_rb_node(const struct rb_node *n)
92 {
93    return (const struct func_rb_node *)n;
94 }
95 
96 static int
func_compare_to_name_and_overload(const struct rb_node * node,const void * data)97 func_compare_to_name_and_overload(const struct rb_node *node, const void *data)
98 {
99    const struct func_descr *descr = (const struct func_descr *)data;
100    const struct func_rb_node *f = func_rb_node(node);
101    if (f->descr.overload < descr->overload)
102       return -1;
103    if (f->descr.overload > descr->overload)
104       return 1;
105 
106    return strcmp(f->descr.name, descr->name);
107 }
108 
109 static const struct dxil_func *
allocate_function_from_predefined(struct dxil_module * mod,const char * name,enum overload_type overload)110 allocate_function_from_predefined(struct dxil_module *mod,
111                                        const char *name,
112                                        enum overload_type overload)
113 {
114    for (unsigned i = 0; i < ARRAY_SIZE(predefined_funcs); ++i) {
115       if (!strcmp(predefined_funcs[i].base_name, name)) {
116          return dxil_alloc_func(mod, name, overload,
117                                 predefined_funcs[i].retval_descr,
118                                 predefined_funcs[i].param_descr,
119                                 predefined_funcs[i].attr);
120       }
121    }
122    return false;
123 }
124 
125 const struct dxil_func *
dxil_get_function(struct dxil_module * mod,const char * name,enum overload_type overload)126 dxil_get_function(struct dxil_module *mod,
127                   const char *name, enum overload_type overload)
128 {
129    struct func_descr descr = { name, overload };
130    const struct rb_node *node = rb_tree_search(mod->functions, &descr,
131                                                func_compare_to_name_and_overload);
132    if (node)
133       return func_rb_node(node)->func;
134 
135    return allocate_function_from_predefined(mod, name, overload);
136 }
137 
func_compare_name(const struct rb_node * lhs,const struct rb_node * rhs)138 static int func_compare_name(const struct rb_node *lhs, const struct rb_node *rhs)
139 {
140    const struct func_rb_node *node = func_rb_node(rhs);
141    return func_compare_to_name_and_overload(lhs, &node->descr);
142 }
143 
144 static void
dxil_add_function(struct rb_tree * functions,const struct dxil_func * func,const char * name,enum overload_type overload)145 dxil_add_function(struct rb_tree *functions, const struct dxil_func *func,
146                   const char *name, enum overload_type overload)
147 {
148    struct func_rb_node *f = rzalloc(functions, struct func_rb_node);
149    f->func = func;
150    f->descr.name = name;
151    f->descr.overload = overload;
152    rb_tree_insert(functions, &f->node, func_compare_name);
153 }
154 
155 static const struct dxil_type *
get_type_from_string(struct dxil_module * mod,const char * param_descr,enum overload_type overload,int * idx)156 get_type_from_string(struct dxil_module *mod, const char *param_descr,
157                      enum overload_type overload,  int *idx)
158 {
159    assert(param_descr);
160    char type_id = param_descr[(*idx)++];
161    assert(*idx <= (int)strlen(param_descr));
162 
163    switch (type_id) {
164    case DXIL_FUNC_PARAM_INT64: return dxil_module_get_int_type(mod, 64);
165    case DXIL_FUNC_PARAM_INT32: return dxil_module_get_int_type(mod, 32);
166    case DXIL_FUNC_PARAM_INT16: return dxil_module_get_int_type(mod, 16);
167    case DXIL_FUNC_PARAM_INT8: return dxil_module_get_int_type(mod, 8);
168    case DXIL_FUNC_PARAM_BOOL: return dxil_module_get_int_type(mod, 1);
169    case DXIL_FUNC_PARAM_FLOAT64: return dxil_module_get_float_type(mod, 64);
170    case DXIL_FUNC_PARAM_FLOAT32: return dxil_module_get_float_type(mod, 32);
171    case DXIL_FUNC_PARAM_FLOAT16: return dxil_module_get_float_type(mod, 16);
172    case DXIL_FUNC_PARAM_HANDLE: return dxil_module_get_handle_type(mod);
173    case DXIL_FUNC_PARAM_VOID: return dxil_module_get_void_type(mod);
174    case DXIL_FUNC_PARAM_FROM_OVERLOAD:  return dxil_get_overload_type(mod, overload);
175    case DXIL_FUNC_PARAM_RESRET: return dxil_module_get_resret_type(mod, overload);
176    case DXIL_FUNC_PARAM_DIM: return dxil_module_get_dimret_type(mod);
177    case DXIL_FUNC_PARAM_CBUF_RET: return dxil_module_get_cbuf_ret_type(mod, overload);
178    case DXIL_FUNC_PARAM_SPLIT_DOUBLE: return dxil_module_get_split_double_ret_type(mod);
179    case DXIL_FUNC_PARAM_POINTER: {
180          const struct dxil_type *target = get_type_from_string(mod, param_descr, overload, idx);
181          return dxil_module_get_pointer_type(mod, target);
182       }
183    default:
184       assert(0 && "unknown type identifier");
185    }
186    return NULL;
187 }
188 
189 const struct dxil_func *
dxil_alloc_func_with_rettype(struct dxil_module * mod,const char * name,enum overload_type overload,const struct dxil_type * retval_type,const char * param_descr,enum dxil_attr_kind attr)190 dxil_alloc_func_with_rettype(struct dxil_module *mod, const char *name,
191                              enum overload_type overload,
192                              const struct dxil_type *retval_type,
193                              const char *param_descr,
194                              enum dxil_attr_kind attr)
195 {
196    assert(param_descr);
197    const struct dxil_type *arg_types[MAX_FUNC_PARAMS];
198 
199    int index = 0;
200    unsigned num_params = 0;
201 
202    while (param_descr[num_params]) {
203       const struct dxil_type *t = get_type_from_string(mod, param_descr, overload, &index);
204       if (!t)
205          return false;
206       assert(num_params < MAX_FUNC_PARAMS);
207       arg_types[num_params++] = t;
208    }
209 
210    const struct dxil_type *func_type =
211       dxil_module_add_function_type(mod, retval_type,
212                                     arg_types, num_params);
213    if (!func_type) {
214       fprintf(stderr, "%s: Func type allocation failed\n", __func__);
215       return false;
216    }
217 
218    char full_name[100];
219    snprintf(full_name, sizeof (full_name), "%s%s%s", name,
220             overload == DXIL_NONE ? "" : ".", dxil_overload_suffix(overload));
221    const struct dxil_func *func = dxil_add_function_decl(mod, full_name, func_type, attr);
222 
223    if (func)
224       dxil_add_function(mod->functions, func, name, overload);
225 
226    return func;
227 }
228 
229 const struct dxil_func *
dxil_alloc_func(struct dxil_module * mod,const char * name,enum overload_type overload,const char * retval_type_descr,const char * param_descr,enum dxil_attr_kind attr)230 dxil_alloc_func(struct dxil_module *mod, const char *name, enum overload_type overload,
231                 const char *retval_type_descr,
232                 const char *param_descr, enum dxil_attr_kind attr)
233 {
234 
235    int index = 0;
236    const struct dxil_type *retval_type = get_type_from_string(mod, retval_type_descr, overload, &index);
237    assert(retval_type_descr[index] == 0);
238 
239    return dxil_alloc_func_with_rettype(mod, name, overload, retval_type,
240                                        param_descr, attr);
241 }
242