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 18
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.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.rawBufferStore", "v", "i@iiOOOOci", DXIL_ATTR_KIND_NONE},
55 {"dx.op.bufferLoad", "R", "i@ii", DXIL_ATTR_KIND_READ_ONLY},
56 {"dx.op.rawBufferLoad", "R", "i@iici", DXIL_ATTR_KIND_READ_ONLY},
57 {"dx.op.attributeAtVertex", "O", "iiicc", DXIL_ATTR_KIND_READ_NONE},
58 {"dx.op.sample", "R", "i@@ffffiiif", DXIL_ATTR_KIND_READ_ONLY},
59 {"dx.op.sampleBias", "R", "i@@ffffiiiff", DXIL_ATTR_KIND_READ_ONLY},
60 {"dx.op.sampleLevel", "R", "i@@ffffiiif", DXIL_ATTR_KIND_READ_ONLY},
61 {"dx.op.sampleGrad", "R", "i@@ffffiiifffffff", DXIL_ATTR_KIND_READ_ONLY},
62 {"dx.op.sampleCmp", "R", "i@@ffffiiiff", DXIL_ATTR_KIND_READ_ONLY},
63 {"dx.op.sampleCmpLevel", "R", "i@@ffffiiiff", DXIL_ATTR_KIND_READ_ONLY},
64 {"dx.op.sampleCmpLevelZero", "R", "i@@ffffiiif", DXIL_ATTR_KIND_READ_ONLY},
65 {"dx.op.sampleCmpBias", "R", "i@@ffffiiifff", DXIL_ATTR_KIND_READ_ONLY},
66 {"dx.op.sampleCmpGrad", "R", "i@@ffffiiiffffffff", DXIL_ATTR_KIND_READ_ONLY},
67 {"dx.op.textureLoad", "R", "i@iiiiiii", DXIL_ATTR_KIND_READ_ONLY},
68 {"dx.op.textureGather", "R", "i@@ffffiii", DXIL_ATTR_KIND_READ_ONLY},
69 {"dx.op.textureGatherCmp", "R", "i@@ffffiiif", DXIL_ATTR_KIND_READ_ONLY},
70 {"dx.op.discard", "v", "ib", DXIL_ATTR_KIND_NO_UNWIND},
71 {"dx.op.sampleIndex", "i", "i", DXIL_ATTR_KIND_READ_NONE},
72 {"dx.op.emitStream", "v", "ic", DXIL_ATTR_KIND_NONE},
73 {"dx.op.cutStream", "v", "ic", DXIL_ATTR_KIND_NONE},
74 {"dx.op.getDimensions", "D", "i@i", DXIL_ATTR_KIND_READ_ONLY},
75 {"dx.op.calculateLOD", "f", "i@@fffb", DXIL_ATTR_KIND_READ_ONLY},
76 {"dx.op.barrier", "v", "ii", DXIL_ATTR_KIND_NO_DUPLICATE},
77 {"dx.op.atomicCompareExchange", "O", "i@iiiii", DXIL_ATTR_KIND_READ_NONE},
78 {"dx.op.textureStore", "v", "i@iiiOOOOc", DXIL_ATTR_KIND_NONE},
79 {"dx.op.primitiveID", "i", "i", DXIL_ATTR_KIND_READ_NONE},
80 {"dx.op.outputControlPointID", "i", "i", DXIL_ATTR_KIND_READ_NONE},
81 {"dx.op.gsInstanceID", "i", "i", DXIL_ATTR_KIND_READ_NONE},
82 {"dx.op.viewID", "i", "i", DXIL_ATTR_KIND_READ_NONE},
83 {"dx.op.domainLocation", "f", "ii", DXIL_ATTR_KIND_READ_NONE},
84 {"dx.op.legacyF16ToF32", "f", "ii", DXIL_ATTR_KIND_READ_ONLY},
85 {"dx.op.legacyF32ToF16", "i", "if", DXIL_ATTR_KIND_READ_ONLY},
86 {"dx.op.makeDouble", "g", "iii", DXIL_ATTR_KIND_READ_NONE},
87 {"dx.op.splitDouble", "G", "ig", DXIL_ATTR_KIND_READ_NONE},
88 {"dx.op.texture2DMSGetSamplePosition", "S", "i@i", DXIL_ATTR_KIND_READ_ONLY},
89 {"dx.op.renderTargetGetSamplePosition", "S", "ii", DXIL_ATTR_KIND_READ_ONLY},
90 {"dx.op.evalSnapped", "O", "iiicii", DXIL_ATTR_KIND_READ_NONE},
91 {"dx.op.evalCentroid", "O", "iiic", DXIL_ATTR_KIND_READ_NONE},
92 {"dx.op.evalSampleIndex", "O", "iiici", DXIL_ATTR_KIND_READ_NONE},
93 {"dx.op.coverage", "i", "i", DXIL_ATTR_KIND_READ_NONE},
94 {"dx.op.storePatchConstant", "v", "iiicO", DXIL_ATTR_KIND_NO_UNWIND},
95 {"dx.op.loadPatchConstant", "O", "iiic", DXIL_ATTR_KIND_READ_NONE},
96 {"dx.op.loadOutputControlPoint", "O", "iiici", DXIL_ATTR_KIND_READ_NONE},
97 {"dx.op.createHandleFromBinding", "@", "i#ib", DXIL_ATTR_KIND_READ_NONE},
98 {"dx.op.createHandleFromHeap", "@", "iibb", DXIL_ATTR_KIND_READ_NONE},
99 {"dx.op.annotateHandle", "@", "i@P", DXIL_ATTR_KIND_READ_NONE},
100 {"dx.op.isHelperLane", "b", "i", DXIL_ATTR_KIND_READ_ONLY},
101 {"dx.op.waveIsFirstLane", "b", "i", DXIL_ATTR_KIND_NO_UNWIND},
102 {"dx.op.waveGetLaneIndex", "i", "i", DXIL_ATTR_KIND_READ_NONE},
103 {"dx.op.waveGetLaneCount", "i", "i", DXIL_ATTR_KIND_READ_NONE},
104 {"dx.op.waveReadLaneFirst", "O", "iO", DXIL_ATTR_KIND_NO_UNWIND},
105 {"dx.op.waveReadLaneAt", "O", "iOi", DXIL_ATTR_KIND_NO_UNWIND},
106 {"dx.op.waveAnyTrue", "b", "ib", DXIL_ATTR_KIND_NO_UNWIND},
107 {"dx.op.waveAllTrue", "b", "ib", DXIL_ATTR_KIND_NO_UNWIND},
108 {"dx.op.waveActiveAllEqual", "b", "iO", DXIL_ATTR_KIND_NO_UNWIND},
109 {"dx.op.waveActiveBallot", "F", "ib", DXIL_ATTR_KIND_NO_UNWIND},
110 {"dx.op.waveActiveOp", "O", "iOcc", DXIL_ATTR_KIND_NO_UNWIND},
111 {"dx.op.waveActiveBit", "O", "iOc", DXIL_ATTR_KIND_NO_UNWIND},
112 {"dx.op.wavePrefixOp", "O", "iOcc", DXIL_ATTR_KIND_NO_UNWIND},
113 {"dx.op.quadReadLaneAt", "O", "iOi", DXIL_ATTR_KIND_NO_UNWIND},
114 {"dx.op.quadOp", "O", "iOc", DXIL_ATTR_KIND_NO_UNWIND},
115 {"dx.op.dot4AddPacked", "i", "iiii", DXIL_ATTR_KIND_READ_NONE},
116 };
117
118 struct func_descr {
119 const char *name;
120 enum overload_type overload;
121 };
122
123 struct func_rb_node {
124 struct rb_node node;
125 const struct dxil_func *func;
126 struct func_descr descr;
127 };
128
129 static inline
130 const struct func_rb_node *
func_rb_node(const struct rb_node * n)131 func_rb_node(const struct rb_node *n)
132 {
133 return (const struct func_rb_node *)n;
134 }
135
136 static int
func_compare_to_name_and_overload(const struct rb_node * node,const void * data)137 func_compare_to_name_and_overload(const struct rb_node *node, const void *data)
138 {
139 const struct func_descr *descr = (const struct func_descr *)data;
140 const struct func_rb_node *f = func_rb_node(node);
141 if (f->descr.overload < descr->overload)
142 return -1;
143 if (f->descr.overload > descr->overload)
144 return 1;
145
146 return strcmp(f->descr.name, descr->name);
147 }
148
149 static const struct dxil_func *
allocate_function_from_predefined(struct dxil_module * mod,const char * name,enum overload_type overload)150 allocate_function_from_predefined(struct dxil_module *mod,
151 const char *name,
152 enum overload_type overload)
153 {
154 for (unsigned i = 0; i < ARRAY_SIZE(predefined_funcs); ++i) {
155 if (!strcmp(predefined_funcs[i].base_name, name)) {
156 return dxil_alloc_func(mod, name, overload,
157 predefined_funcs[i].retval_descr,
158 predefined_funcs[i].param_descr,
159 predefined_funcs[i].attr);
160 }
161 }
162 unreachable("Invalid function name");
163 }
164
165 const struct dxil_func *
dxil_get_function(struct dxil_module * mod,const char * name,enum overload_type overload)166 dxil_get_function(struct dxil_module *mod,
167 const char *name, enum overload_type overload)
168 {
169 struct func_descr descr = { name, overload };
170 const struct rb_node *node = rb_tree_search(mod->functions, &descr,
171 func_compare_to_name_and_overload);
172 if (node)
173 return func_rb_node(node)->func;
174
175 return allocate_function_from_predefined(mod, name, overload);
176 }
177
func_compare_name(const struct rb_node * lhs,const struct rb_node * rhs)178 static int func_compare_name(const struct rb_node *lhs, const struct rb_node *rhs)
179 {
180 const struct func_rb_node *node = func_rb_node(rhs);
181 return func_compare_to_name_and_overload(lhs, &node->descr);
182 }
183
184 static void
dxil_add_function(struct rb_tree * functions,const struct dxil_func * func,const char * name,enum overload_type overload)185 dxil_add_function(struct rb_tree *functions, const struct dxil_func *func,
186 const char *name, enum overload_type overload)
187 {
188 struct func_rb_node *f = rzalloc(functions, struct func_rb_node);
189 f->func = func;
190 f->descr.name = name;
191 f->descr.overload = overload;
192 rb_tree_insert(functions, &f->node, func_compare_name);
193 }
194
195 static const struct dxil_type *
get_type_from_string(struct dxil_module * mod,const char * param_descr,enum overload_type overload,int * idx)196 get_type_from_string(struct dxil_module *mod, const char *param_descr,
197 enum overload_type overload, int *idx)
198 {
199 assert(param_descr);
200 char type_id = param_descr[(*idx)++];
201 assert(*idx <= (int)strlen(param_descr));
202
203 switch (type_id) {
204 case DXIL_FUNC_PARAM_INT64: return dxil_module_get_int_type(mod, 64);
205 case DXIL_FUNC_PARAM_INT32: return dxil_module_get_int_type(mod, 32);
206 case DXIL_FUNC_PARAM_INT16: return dxil_module_get_int_type(mod, 16);
207 case DXIL_FUNC_PARAM_INT8: return dxil_module_get_int_type(mod, 8);
208 case DXIL_FUNC_PARAM_BOOL: return dxil_module_get_int_type(mod, 1);
209 case DXIL_FUNC_PARAM_FLOAT64: return dxil_module_get_float_type(mod, 64);
210 case DXIL_FUNC_PARAM_FLOAT32: return dxil_module_get_float_type(mod, 32);
211 case DXIL_FUNC_PARAM_FLOAT16: return dxil_module_get_float_type(mod, 16);
212 case DXIL_FUNC_PARAM_HANDLE: return dxil_module_get_handle_type(mod);
213 case DXIL_FUNC_PARAM_VOID: return dxil_module_get_void_type(mod);
214 case DXIL_FUNC_PARAM_FROM_OVERLOAD: return dxil_get_overload_type(mod, overload);
215 case DXIL_FUNC_PARAM_RESRET: return dxil_module_get_resret_type(mod, overload);
216 case DXIL_FUNC_PARAM_DIM: return dxil_module_get_dimret_type(mod);
217 case DXIL_FUNC_PARAM_SAMPLE_POS: return dxil_module_get_samplepos_type(mod);
218 case DXIL_FUNC_PARAM_CBUF_RET: return dxil_module_get_cbuf_ret_type(mod, overload);
219 case DXIL_FUNC_PARAM_SPLIT_DOUBLE: return dxil_module_get_split_double_ret_type(mod);
220 case DXIL_FUNC_PARAM_RES_BIND: return dxil_module_get_res_bind_type(mod);
221 case DXIL_FUNC_PARAM_RES_PROPS: return dxil_module_get_res_props_type(mod);
222 case DXIL_FUNC_PARAM_POINTER: {
223 const struct dxil_type *target = get_type_from_string(mod, param_descr, overload, idx);
224 return dxil_module_get_pointer_type(mod, target);
225 }
226 case DXIL_FUNC_PARAM_FOURI32: return dxil_module_get_fouri32_type(mod);
227 default:
228 assert(0 && "unknown type identifier");
229 }
230 return NULL;
231 }
232
233 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)234 dxil_alloc_func_with_rettype(struct dxil_module *mod, const char *name,
235 enum overload_type overload,
236 const struct dxil_type *retval_type,
237 const char *param_descr,
238 enum dxil_attr_kind attr)
239 {
240 assert(param_descr);
241 const struct dxil_type *arg_types[MAX_FUNC_PARAMS];
242
243 int index = 0;
244 unsigned num_params = 0;
245
246 while (param_descr[num_params]) {
247 const struct dxil_type *t = get_type_from_string(mod, param_descr, overload, &index);
248 if (!t)
249 return false;
250 assert(num_params < MAX_FUNC_PARAMS);
251 arg_types[num_params++] = t;
252 }
253
254 const struct dxil_type *func_type =
255 dxil_module_add_function_type(mod, retval_type,
256 arg_types, num_params);
257 if (!func_type) {
258 fprintf(stderr, "%s: Func type allocation failed\n", __func__);
259 return false;
260 }
261
262 char full_name[100];
263 snprintf(full_name, sizeof (full_name), "%s%s%s", name,
264 overload == DXIL_NONE ? "" : ".", dxil_overload_suffix(overload));
265 const struct dxil_func *func = dxil_add_function_decl(mod, full_name, func_type, attr);
266
267 if (func)
268 dxil_add_function(mod->functions, func, name, overload);
269
270 return func;
271 }
272
273 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)274 dxil_alloc_func(struct dxil_module *mod, const char *name, enum overload_type overload,
275 const char *retval_type_descr,
276 const char *param_descr, enum dxil_attr_kind attr)
277 {
278
279 int index = 0;
280 const struct dxil_type *retval_type = get_type_from_string(mod, retval_type_descr, overload, &index);
281 assert(retval_type_descr[index] == 0);
282
283 return dxil_alloc_func_with_rettype(mod, name, overload, retval_type,
284 param_descr, attr);
285 }
286