#define LONGSTRING __extension__ in imports.h and use it to silence gcc
[mesa.git] / src / mesa / shader / slang / slang_assemble_constructor.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5
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
35 /* _slang_is_swizzle() */
36
37 GLboolean _slang_is_swizzle (const char *field, GLuint rows, slang_swizzle *swz)
38 {
39 GLuint i;
40 GLboolean xyzw = GL_FALSE, rgba = GL_FALSE, stpq = GL_FALSE;
41
42 /* the swizzle can be at most 4-component long */
43 swz->num_components = slang_string_length (field);
44 if (swz->num_components > 4)
45 return GL_FALSE;
46
47 for (i = 0; i < swz->num_components; i++)
48 {
49 /* mark which swizzle group is used */
50 switch (field[i])
51 {
52 case 'x':
53 case 'y':
54 case 'z':
55 case 'w':
56 xyzw = GL_TRUE;
57 break;
58 case 'r':
59 case 'g':
60 case 'b':
61 case 'a':
62 rgba = GL_TRUE;
63 break;
64 case 's':
65 case 't':
66 case 'p':
67 case 'q':
68 stpq = GL_TRUE;
69 break;
70 default:
71 return GL_FALSE;
72 }
73
74 /* collect swizzle component */
75 switch (field[i])
76 {
77 case 'x':
78 case 'r':
79 case 's':
80 swz->swizzle[i] = 0;
81 break;
82 case 'y':
83 case 'g':
84 case 't':
85 swz->swizzle[i] = 1;
86 break;
87 case 'z':
88 case 'b':
89 case 'p':
90 swz->swizzle[i] = 2;
91 break;
92 case 'w':
93 case 'a':
94 case 'q':
95 swz->swizzle[i] = 3;
96 break;
97 }
98
99 /* check if the component is valid for given vector's row count */
100 if (rows <= swz->swizzle[i])
101 return GL_FALSE;
102 }
103
104 /* only one swizzle group can be used */
105 if ((xyzw && rgba) || (xyzw && stpq) || (rgba && stpq))
106 return GL_FALSE;
107
108 return GL_TRUE;
109 }
110
111 /* _slang_is_swizzle_mask() */
112
113 GLboolean _slang_is_swizzle_mask (const slang_swizzle *swz, GLuint rows)
114 {
115 GLuint i, c = 0;
116
117 /* the swizzle may not be longer than the vector dim */
118 if (swz->num_components > rows)
119 return GL_FALSE;
120
121 /* the swizzle components cannot be duplicated */
122 for (i = 0; i < swz->num_components; i++)
123 {
124 if ((c & (1 << swz->swizzle[i])) != 0)
125 return GL_FALSE;
126 c |= 1 << swz->swizzle[i];
127 }
128
129 return GL_TRUE;
130 }
131
132 /* _slang_multiply_swizzles() */
133
134 GLvoid _slang_multiply_swizzles (slang_swizzle *dst, const slang_swizzle *left,
135 const slang_swizzle *right)
136 {
137 GLuint i;
138
139 dst->num_components = right->num_components;
140 for (i = 0; i < right->num_components; i++)
141 dst->swizzle[i] = left->swizzle[right->swizzle[i]];
142 }
143
144 /* _slang_assemble_constructor() */
145
146 static GLboolean
147 sizeof_argument (slang_assemble_ctx *A, GLuint *size, slang_operation *op)
148 {
149 slang_assembly_typeinfo ti;
150 GLboolean result = GL_FALSE;
151 slang_storage_aggregate agg;
152
153 if (!slang_assembly_typeinfo_construct (&ti))
154 return GL_FALSE;
155 if (!_slang_typeof_operation (A, op, &ti))
156 goto end1;
157
158 if (!slang_storage_aggregate_construct (&agg))
159 goto end1;
160 if (!_slang_aggregate_variable (&agg, &ti.spec, 0, A->space.funcs, A->space.structs,
161 A->space.vars, A->mach, A->file, A->atoms))
162 goto end;
163
164 *size = _slang_sizeof_aggregate (&agg);
165 result = GL_TRUE;
166
167 end:
168 slang_storage_aggregate_destruct (&agg);
169 end1:
170 slang_assembly_typeinfo_destruct (&ti);
171 return result;
172 }
173
174 static GLboolean constructor_aggregate (slang_assemble_ctx *A, const slang_storage_aggregate *flat,
175 slang_operation *op, GLuint garbage_size)
176 {
177 slang_assembly_typeinfo ti;
178 GLboolean result = GL_FALSE;
179 slang_storage_aggregate agg, flat_agg;
180
181 if (!slang_assembly_typeinfo_construct (&ti))
182 return GL_FALSE;
183 if (!_slang_typeof_operation (A, op, &ti))
184 goto end1;
185
186 if (!slang_storage_aggregate_construct (&agg))
187 goto end1;
188 if (!_slang_aggregate_variable (&agg, &ti.spec, 0, A->space.funcs, A->space.structs,
189 A->space.vars, A->mach, A->file, A->atoms))
190 goto end2;
191
192 if (!slang_storage_aggregate_construct (&flat_agg))
193 goto end2;
194 if (!_slang_flatten_aggregate (&flat_agg, &agg))
195 goto end;
196
197 if (!_slang_assemble_operation (A, op, slang_ref_forbid))
198 goto end;
199
200 /* TODO: convert (generic) elements */
201
202 /* free the garbage */
203 if (garbage_size != 0)
204 {
205 GLuint i;
206
207 /* move the non-garbage part to the end of the argument */
208 if (!slang_assembly_file_push_label (A->file, slang_asm_addr_push, 0))
209 goto end;
210 for (i = flat_agg.count * 4 - garbage_size; i > 0; i -= 4)
211 {
212 if (!slang_assembly_file_push_label2 (A->file, slang_asm_float_move,
213 garbage_size + i, i))
214 {
215 goto end;
216 }
217 }
218 if (!slang_assembly_file_push_label (A->file, slang_asm_local_free, garbage_size + 4))
219 goto end;
220 }
221
222 result = GL_TRUE;
223 end:
224 slang_storage_aggregate_destruct (&flat_agg);
225 end2:
226 slang_storage_aggregate_destruct (&agg);
227 end1:
228 slang_assembly_typeinfo_destruct (&ti);
229 return result;
230 }
231
232 GLboolean _slang_assemble_constructor (slang_assemble_ctx *A, slang_operation *op)
233 {
234 slang_assembly_typeinfo ti;
235 GLboolean result = GL_FALSE;
236 slang_storage_aggregate agg, flat;
237 GLuint size, i;
238 GLuint arg_sums[2];
239
240 /* get typeinfo of the constructor (the result of constructor expression) */
241 if (!slang_assembly_typeinfo_construct (&ti))
242 return GL_FALSE;
243 if (!_slang_typeof_operation (A, op, &ti))
244 goto end1;
245
246 /* create an aggregate of the constructor */
247 if (!slang_storage_aggregate_construct (&agg))
248 goto end1;
249 if (!_slang_aggregate_variable (&agg, &ti.spec, 0, A->space.funcs, A->space.structs,
250 A->space.vars, A->mach, A->file, A->atoms))
251 goto end2;
252
253 /* calculate size of the constructor */
254 size = _slang_sizeof_aggregate (&agg);
255
256 /* flatten the constructor */
257 if (!slang_storage_aggregate_construct (&flat))
258 goto end2;
259 if (!_slang_flatten_aggregate (&flat, &agg))
260 goto end;
261
262 /* collect the last two constructor's argument size sums */
263 arg_sums[0] = 0; /* will hold all but the last argument's size sum */
264 arg_sums[1] = 0; /* will hold all argument's size sum */
265 for (i = 0; i < op->num_children; i++)
266 {
267 GLuint arg_size = 0;
268
269 if (!sizeof_argument (A, &arg_size, &op->children[i]))
270 goto end;
271 if (i > 0)
272 arg_sums[0] = arg_sums[1];
273 arg_sums[1] += arg_size;
274 }
275
276 /* check if there are too many arguments */
277 if (arg_sums[0] >= size)
278 {
279 /* TODO: info log: too many arguments in constructor list */
280 goto end;
281 }
282
283 /* check if there are too few arguments */
284 if (arg_sums[1] < size)
285 {
286 /* TODO: info log: too few arguments in constructor list */
287 goto end;
288 }
289
290 /* traverse the children that form the constructor expression */
291 for (i = op->num_children; i > 0; i--)
292 {
293 GLuint garbage_size;
294
295 /* the last argument may be too big - calculate the unnecessary data size */
296 if (i == op->num_children)
297 garbage_size = arg_sums[1] - size;
298 else
299 garbage_size = 0;
300
301 if (!constructor_aggregate (A, &flat, &op->children[i - 1], garbage_size))
302 goto end;
303 }
304
305 result = GL_TRUE;
306 end:
307 slang_storage_aggregate_destruct (&flat);
308 end2:
309 slang_storage_aggregate_destruct (&agg);
310 end1:
311 slang_assembly_typeinfo_destruct (&ti);
312 return result;
313 }
314
315 /* _slang_assemble_constructor_from_swizzle() */
316
317 GLboolean _slang_assemble_constructor_from_swizzle (slang_assemble_ctx *A, const slang_swizzle *swz,
318 slang_type_specifier *spec, slang_type_specifier *master_spec)
319 {
320 GLuint master_rows, i;
321
322 master_rows = _slang_type_dim (master_spec->type);
323 for (i = 0; i < master_rows; i++)
324 {
325 switch (_slang_type_base (master_spec->type))
326 {
327 case slang_spec_bool:
328 if (!slang_assembly_file_push_label2 (A->file, slang_asm_bool_copy,
329 (master_rows - i) * 4, i * 4))
330 return GL_FALSE;
331 break;
332 case slang_spec_int:
333 if (!slang_assembly_file_push_label2 (A->file, slang_asm_int_copy,
334 (master_rows - i) * 4, i * 4))
335 return GL_FALSE;
336 break;
337 case slang_spec_float:
338 if (!slang_assembly_file_push_label2 (A->file, slang_asm_float_copy,
339 (master_rows - i) * 4, i * 4))
340 return GL_FALSE;
341 break;
342 default:
343 break;
344 }
345 }
346 if (!slang_assembly_file_push_label (A->file, slang_asm_local_free, 4))
347 return GL_FALSE;
348 for (i = swz->num_components; i > 0; i--)
349 {
350 GLuint n = i - 1;
351
352 if (!slang_assembly_file_push_label2 (A->file, slang_asm_local_addr, A->local.swizzle_tmp, 16))
353 return GL_FALSE;
354 if (!slang_assembly_file_push_label (A->file, slang_asm_addr_push, swz->swizzle[n] * 4))
355 return GL_FALSE;
356 if (!slang_assembly_file_push (A->file, slang_asm_addr_add))
357 return GL_FALSE;
358 switch (_slang_type_base (master_spec->type))
359 {
360 case slang_spec_bool:
361 if (!slang_assembly_file_push (A->file, slang_asm_bool_deref))
362 return GL_FALSE;
363 break;
364 case slang_spec_int:
365 if (!slang_assembly_file_push (A->file, slang_asm_int_deref))
366 return GL_FALSE;
367 break;
368 case slang_spec_float:
369 if (!slang_assembly_file_push (A->file, slang_asm_float_deref))
370 return GL_FALSE;
371 break;
372 default:
373 break;
374 }
375 }
376
377 return GL_TRUE;
378 }
379