_slang_evaluate_int() no longer used
[mesa.git] / src / mesa / shader / slang / slang_assemble_constructor.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5.2
4 *
5 * Copyright (C) 2005-2006 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 /**
26 * \file slang_assemble_constructor.c
27 * slang constructor and vector swizzle assembler
28 * \author Michal Krol
29 */
30
31 #include "imports.h"
32 #include "slang_assemble.h"
33 #include "slang_storage.h"
34 #include "prog_instruction.h"
35
36
37 /**
38 * Checks if a field selector is a general swizzle (an r-value swizzle
39 * with replicated components or an l-value swizzle mask) for a
40 * vector. Returns GL_TRUE if this is the case, <swz> is filled with
41 * swizzle information. Returns GL_FALSE otherwise.
42 */
43 GLboolean
44 _slang_is_swizzle(const char *field, GLuint rows, slang_swizzle * swz)
45 {
46 GLuint i;
47 GLboolean xyzw = GL_FALSE, rgba = GL_FALSE, stpq = GL_FALSE;
48
49 /* init to undefined.
50 * We rely on undefined/nil values to distinguish between
51 * regular swizzles and writemasks.
52 * For example, the swizzle ".xNNN" is the writemask ".x".
53 * That's different than the swizzle ".xxxx".
54 */
55 for (i = 0; i < 4; i++)
56 swz->swizzle[i] = SWIZZLE_NIL;
57
58 /* the swizzle can be at most 4-component long */
59 swz->num_components = slang_string_length(field);
60 if (swz->num_components > 4)
61 return GL_FALSE;
62
63 for (i = 0; i < swz->num_components; i++) {
64 /* mark which swizzle group is used */
65 switch (field[i]) {
66 case 'x':
67 case 'y':
68 case 'z':
69 case 'w':
70 xyzw = GL_TRUE;
71 break;
72 case 'r':
73 case 'g':
74 case 'b':
75 case 'a':
76 rgba = GL_TRUE;
77 break;
78 case 's':
79 case 't':
80 case 'p':
81 case 'q':
82 stpq = GL_TRUE;
83 break;
84 default:
85 return GL_FALSE;
86 }
87
88 /* collect swizzle component */
89 switch (field[i]) {
90 case 'x':
91 case 'r':
92 case 's':
93 swz->swizzle[i] = 0;
94 break;
95 case 'y':
96 case 'g':
97 case 't':
98 swz->swizzle[i] = 1;
99 break;
100 case 'z':
101 case 'b':
102 case 'p':
103 swz->swizzle[i] = 2;
104 break;
105 case 'w':
106 case 'a':
107 case 'q':
108 swz->swizzle[i] = 3;
109 break;
110 }
111
112 /* check if the component is valid for given vector's row count */
113 if (rows <= swz->swizzle[i])
114 return GL_FALSE;
115 }
116
117 /* only one swizzle group can be used */
118 if ((xyzw && rgba) || (xyzw && stpq) || (rgba && stpq))
119 return GL_FALSE;
120
121 return GL_TRUE;
122 }
123
124
125
126 /**
127 * Checks if a general swizzle is an l-value swizzle - these swizzles
128 * do not have duplicated fields. Returns GL_TRUE if this is a
129 * swizzle mask. Returns GL_FALSE otherwise
130 */
131 GLboolean
132 _slang_is_swizzle_mask(const slang_swizzle * swz, GLuint rows)
133 {
134 GLuint i, c = 0;
135
136 /* the swizzle may not be longer than the vector dim */
137 if (swz->num_components > rows)
138 return GL_FALSE;
139
140 /* the swizzle components cannot be duplicated */
141 for (i = 0; i < swz->num_components; i++) {
142 if ((c & (1 << swz->swizzle[i])) != 0)
143 return GL_FALSE;
144 c |= 1 << swz->swizzle[i];
145 }
146
147 return GL_TRUE;
148 }
149
150
151
152 /**
153 * Combines (multiplies) two swizzles to form single swizzle.
154 * Example: "vec.wzyx.yx" --> "vec.zw".
155 */
156 GLvoid
157 _slang_multiply_swizzles(slang_swizzle * dst, const slang_swizzle * left,
158 const slang_swizzle * right)
159 {
160 GLuint i;
161
162 dst->num_components = right->num_components;
163 for (i = 0; i < right->num_components; i++)
164 dst->swizzle[i] = left->swizzle[right->swizzle[i]];
165 }
166
167
168
169 static GLboolean
170 sizeof_argument(slang_assemble_ctx * A, GLuint * size, slang_operation * op)
171 {
172 slang_assembly_typeinfo ti;
173 GLboolean result = GL_FALSE;
174 slang_storage_aggregate agg;
175
176 if (!slang_assembly_typeinfo_construct(&ti))
177 return GL_FALSE;
178 if (!_slang_typeof_operation(A, op, &ti))
179 goto end1;
180
181 if (!slang_storage_aggregate_construct(&agg))
182 goto end1;
183 if (!_slang_aggregate_variable(&agg, &ti.spec, 0, A->space.funcs,
184 A->space.structs, A->space.vars,
185 A->mach, A->file, A->atoms))
186 goto end;
187
188 *size = _slang_sizeof_aggregate(&agg);
189 result = GL_TRUE;
190
191 end:
192 slang_storage_aggregate_destruct(&agg);
193 end1:
194 slang_assembly_typeinfo_destruct(&ti);
195 return result;
196 }
197
198
199 static GLboolean
200 constructor_aggregate(slang_assemble_ctx * A,
201 const slang_storage_aggregate * flat,
202 slang_operation * op, GLuint garbage_size)
203 {
204 slang_assembly_typeinfo ti;
205 GLboolean result = GL_FALSE;
206 slang_storage_aggregate agg, flat_agg;
207
208 if (!slang_assembly_typeinfo_construct(&ti))
209 return GL_FALSE;
210 if (!_slang_typeof_operation(A, op, &ti))
211 goto end1;
212
213 if (!slang_storage_aggregate_construct(&agg))
214 goto end1;
215 if (!_slang_aggregate_variable(&agg, &ti.spec, 0, A->space.funcs,
216 A->space.structs, A->space.vars,
217 A->mach, A->file, A->atoms))
218 goto end2;
219
220 if (!slang_storage_aggregate_construct(&flat_agg))
221 goto end2;
222 if (!_slang_flatten_aggregate(&flat_agg, &agg))
223 goto end;
224
225 if (!_slang_assemble_operation(A, op, slang_ref_forbid))
226 goto end;
227
228 /* TODO: convert (generic) elements */
229
230 /* free the garbage */
231 if (garbage_size != 0) {
232 GLuint i;
233
234 /* move the non-garbage part to the end of the argument */
235 if (!slang_assembly_file_push_label(A->file, slang_asm_addr_push, 0))
236 goto end;
237 for (i = flat_agg.count * 4 - garbage_size; i > 0; i -= 4) {
238 if (!slang_assembly_file_push_label2(A->file, slang_asm_float_move,
239 garbage_size + i, i)) {
240 goto end;
241 }
242 }
243 if (!slang_assembly_file_push_label
244 (A->file, slang_asm_local_free, garbage_size + 4))
245 goto end;
246 }
247
248 result = GL_TRUE;
249 end:
250 slang_storage_aggregate_destruct(&flat_agg);
251 end2:
252 slang_storage_aggregate_destruct(&agg);
253 end1:
254 slang_assembly_typeinfo_destruct(&ti);
255 return result;
256 }
257
258
259 GLboolean
260 _slang_assemble_constructor(slang_assemble_ctx * A, const slang_operation * op)
261 {
262 slang_assembly_typeinfo ti;
263 GLboolean result = GL_FALSE;
264 slang_storage_aggregate agg, flat;
265 GLuint size, i;
266 GLuint arg_sums[2];
267
268 /* get typeinfo of the constructor (the result of constructor expression) */
269 if (!slang_assembly_typeinfo_construct(&ti))
270 return GL_FALSE;
271 if (!_slang_typeof_operation(A, op, &ti))
272 goto end1;
273
274 /* create an aggregate of the constructor */
275 if (!slang_storage_aggregate_construct(&agg))
276 goto end1;
277 if (!_slang_aggregate_variable(&agg, &ti.spec, 0, A->space.funcs,
278 A->space.structs, A->space.vars,
279 A->mach, A->file, A->atoms))
280 goto end2;
281
282 /* calculate size of the constructor */
283 size = _slang_sizeof_aggregate(&agg);
284
285 /* flatten the constructor */
286 if (!slang_storage_aggregate_construct(&flat))
287 goto end2;
288 if (!_slang_flatten_aggregate(&flat, &agg))
289 goto end;
290
291 /* collect the last two constructor's argument size sums */
292 arg_sums[0] = 0; /* will hold all but the last argument's size sum */
293 arg_sums[1] = 0; /* will hold all argument's size sum */
294 for (i = 0; i < op->num_children; i++) {
295 GLuint arg_size = 0;
296
297 if (!sizeof_argument(A, &arg_size, &op->children[i]))
298 goto end;
299 if (i > 0)
300 arg_sums[0] = arg_sums[1];
301 arg_sums[1] += arg_size;
302 }
303
304 /* check if there are too many arguments */
305 if (arg_sums[0] >= size) {
306 /* TODO: info log: too many arguments in constructor list */
307 goto end;
308 }
309
310 /* check if there are too few arguments */
311 if (arg_sums[1] < size) {
312 /* TODO: info log: too few arguments in constructor list */
313 /* DEBUG */
314 {
315 if (!slang_storage_aggregate_construct(&agg))
316 goto end1;
317 if (!_slang_aggregate_variable(&agg, &ti.spec, 0, A->space.funcs,
318 A->space.structs, A->space.vars,
319 A->mach, A->file, A->atoms))
320 goto end2;
321
322 /* calculate size of the constructor */
323 size = _slang_sizeof_aggregate(&agg);
324 }
325 goto end;
326 }
327
328 /* traverse the children that form the constructor expression */
329 for (i = op->num_children; i > 0; i--) {
330 GLuint garbage_size;
331
332 /* the last argument may be too big - calculate the unnecessary
333 * data size
334 */
335 if (i == op->num_children)
336 garbage_size = arg_sums[1] - size;
337 else
338 garbage_size = 0;
339
340 if (!constructor_aggregate(A, &flat, &op->children[i - 1], garbage_size))
341 goto end;
342 }
343
344 result = GL_TRUE;
345 end:
346 slang_storage_aggregate_destruct(&flat);
347 end2:
348 slang_storage_aggregate_destruct(&agg);
349 end1:
350 slang_assembly_typeinfo_destruct(&ti);
351 return result;
352 }
353
354
355
356 GLboolean
357 _slang_assemble_constructor_from_swizzle(slang_assemble_ctx * A,
358 const slang_swizzle * swz,
359 const slang_type_specifier * spec,
360 const slang_type_specifier * master_spec)
361 {
362 const GLuint master_rows = _slang_type_dim(master_spec->type);
363 GLuint i;
364
365 for (i = 0; i < master_rows; i++) {
366 switch (_slang_type_base(master_spec->type)) {
367 case slang_spec_bool:
368 if (!slang_assembly_file_push_label2(A->file, slang_asm_bool_copy,
369 (master_rows - i) * 4, i * 4))
370 return GL_FALSE;
371 break;
372 case slang_spec_int:
373 if (!slang_assembly_file_push_label2(A->file, slang_asm_int_copy,
374 (master_rows - i) * 4, i * 4))
375 return GL_FALSE;
376 break;
377 case slang_spec_float:
378 if (!slang_assembly_file_push_label2(A->file, slang_asm_float_copy,
379 (master_rows - i) * 4, i * 4))
380 return GL_FALSE;
381 break;
382 default:
383 break;
384 }
385 }
386
387 if (!slang_assembly_file_push_label(A->file, slang_asm_local_free, 4))
388 return GL_FALSE;
389
390 for (i = swz->num_components; i > 0; i--) {
391 const GLuint n = i - 1;
392
393 if (!slang_assembly_file_push_label2(A->file, slang_asm_local_addr,
394 A->local.swizzle_tmp, 16))
395 return GL_FALSE;
396 if (!slang_assembly_file_push_label(A->file, slang_asm_addr_push,
397 swz->swizzle[n] * 4))
398 return GL_FALSE;
399 if (!slang_assembly_file_push(A->file, slang_asm_addr_add))
400 return GL_FALSE;
401
402 switch (_slang_type_base(master_spec->type)) {
403 case slang_spec_bool:
404 if (!slang_assembly_file_push(A->file, slang_asm_bool_deref))
405 return GL_FALSE;
406 break;
407 case slang_spec_int:
408 if (!slang_assembly_file_push(A->file, slang_asm_int_deref))
409 return GL_FALSE;
410 break;
411 case slang_spec_float:
412 if (!slang_assembly_file_push(A->file, slang_asm_float_deref))
413 return GL_FALSE;
414 break;
415 default:
416 break;
417 }
418 }
419
420 return GL_TRUE;
421 }