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