2 * Mesa 3-D graphics library
5 * Copyright (C) 2005-2006 Brian Paul All Rights Reserved.
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:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
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.
26 * \file slang_assemble_constructor.c
27 * slang constructor and vector swizzle assembler
32 #include "slang_assemble.h"
33 #include "slang_storage.h"
34 #include "prog_instruction.h"
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.
44 _slang_is_swizzle(const char *field
, GLuint rows
, slang_swizzle
* swz
)
47 GLboolean xyzw
= GL_FALSE
, rgba
= GL_FALSE
, stpq
= GL_FALSE
;
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".
55 for (i
= 0; i
< 4; i
++)
56 swz
->swizzle
[i
] = SWIZZLE_NIL
;
58 /* the swizzle can be at most 4-component long */
59 swz
->num_components
= slang_string_length(field
);
60 if (swz
->num_components
> 4)
63 for (i
= 0; i
< swz
->num_components
; i
++) {
64 /* mark which swizzle group is used */
88 /* collect swizzle component */
112 /* check if the component is valid for given vector's row count */
113 if (rows
<= swz
->swizzle
[i
])
117 /* only one swizzle group can be used */
118 if ((xyzw
&& rgba
) || (xyzw
&& stpq
) || (rgba
&& stpq
))
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
132 _slang_is_swizzle_mask(const slang_swizzle
* swz
, GLuint rows
)
136 /* the swizzle may not be longer than the vector dim */
137 if (swz
->num_components
> rows
)
140 /* the swizzle components cannot be duplicated */
141 for (i
= 0; i
< swz
->num_components
; i
++) {
142 if ((c
& (1 << swz
->swizzle
[i
])) != 0)
144 c
|= 1 << swz
->swizzle
[i
];
153 * Combines (multiplies) two swizzles to form single swizzle.
154 * Example: "vec.wzyx.yx" --> "vec.zw".
157 _slang_multiply_swizzles(slang_swizzle
* dst
, const slang_swizzle
* left
,
158 const slang_swizzle
* right
)
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
]];
170 sizeof_argument(slang_assemble_ctx
* A
, GLuint
* size
, slang_operation
* op
)
172 slang_assembly_typeinfo ti
;
173 GLboolean result
= GL_FALSE
;
174 slang_storage_aggregate agg
;
176 if (!slang_assembly_typeinfo_construct(&ti
))
178 if (!_slang_typeof_operation(A
, op
, &ti
))
181 if (!slang_storage_aggregate_construct(&agg
))
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
))
188 *size
= _slang_sizeof_aggregate(&agg
);
192 slang_storage_aggregate_destruct(&agg
);
194 slang_assembly_typeinfo_destruct(&ti
);
200 constructor_aggregate(slang_assemble_ctx
* A
,
201 const slang_storage_aggregate
* flat
,
202 slang_operation
* op
, GLuint garbage_size
)
204 slang_assembly_typeinfo ti
;
205 GLboolean result
= GL_FALSE
;
206 slang_storage_aggregate agg
, flat_agg
;
208 if (!slang_assembly_typeinfo_construct(&ti
))
210 if (!_slang_typeof_operation(A
, op
, &ti
))
213 if (!slang_storage_aggregate_construct(&agg
))
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
))
220 if (!slang_storage_aggregate_construct(&flat_agg
))
222 if (!_slang_flatten_aggregate(&flat_agg
, &agg
))
225 if (!_slang_assemble_operation(A
, op
, slang_ref_forbid
))
228 /* TODO: convert (generic) elements */
230 /* free the garbage */
231 if (garbage_size
!= 0) {
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))
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
)) {
243 if (!slang_assembly_file_push_label
244 (A
->file
, slang_asm_local_free
, garbage_size
+ 4))
250 slang_storage_aggregate_destruct(&flat_agg
);
252 slang_storage_aggregate_destruct(&agg
);
254 slang_assembly_typeinfo_destruct(&ti
);
260 _slang_assemble_constructor(slang_assemble_ctx
* A
, const slang_operation
* op
)
262 slang_assembly_typeinfo ti
;
263 GLboolean result
= GL_FALSE
;
264 slang_storage_aggregate agg
, flat
;
268 /* get typeinfo of the constructor (the result of constructor expression) */
269 if (!slang_assembly_typeinfo_construct(&ti
))
271 if (!_slang_typeof_operation(A
, op
, &ti
))
274 /* create an aggregate of the constructor */
275 if (!slang_storage_aggregate_construct(&agg
))
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
))
282 /* calculate size of the constructor */
283 size
= _slang_sizeof_aggregate(&agg
);
285 /* flatten the constructor */
286 if (!slang_storage_aggregate_construct(&flat
))
288 if (!_slang_flatten_aggregate(&flat
, &agg
))
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
++) {
297 if (!sizeof_argument(A
, &arg_size
, &op
->children
[i
]))
300 arg_sums
[0] = arg_sums
[1];
301 arg_sums
[1] += arg_size
;
304 /* check if there are too many arguments */
305 if (arg_sums
[0] >= size
) {
306 /* TODO: info log: too many arguments in constructor list */
310 /* check if there are too few arguments */
311 if (arg_sums
[1] < size
) {
312 /* TODO: info log: too few arguments in constructor list */
315 if (!slang_storage_aggregate_construct(&agg
))
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
))
322 /* calculate size of the constructor */
323 size
= _slang_sizeof_aggregate(&agg
);
328 /* traverse the children that form the constructor expression */
329 for (i
= op
->num_children
; i
> 0; i
--) {
332 /* the last argument may be too big - calculate the unnecessary
335 if (i
== op
->num_children
)
336 garbage_size
= arg_sums
[1] - size
;
340 if (!constructor_aggregate(A
, &flat
, &op
->children
[i
- 1], garbage_size
))
346 slang_storage_aggregate_destruct(&flat
);
348 slang_storage_aggregate_destruct(&agg
);
350 slang_assembly_typeinfo_destruct(&ti
);
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
)
362 const GLuint master_rows
= _slang_type_dim(master_spec
->type
);
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))
373 if (!slang_assembly_file_push_label2(A
->file
, slang_asm_int_copy
,
374 (master_rows
- i
) * 4, i
* 4))
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))
387 if (!slang_assembly_file_push_label(A
->file
, slang_asm_local_free
, 4))
390 for (i
= swz
->num_components
; i
> 0; i
--) {
391 const GLuint n
= i
- 1;
393 if (!slang_assembly_file_push_label2(A
->file
, slang_asm_local_addr
,
394 A
->local
.swizzle_tmp
, 16))
396 if (!slang_assembly_file_push_label(A
->file
, slang_asm_addr_push
,
397 swz
->swizzle
[n
] * 4))
399 if (!slang_assembly_file_push(A
->file
, slang_asm_addr_add
))
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
))
408 if (!slang_assembly_file_push(A
->file
, slang_asm_int_deref
))
411 case slang_spec_float
:
412 if (!slang_assembly_file_push(A
->file
, slang_asm_float_deref
))