Add functions to generate constructors for built-in types.
[mesa.git] / hir_field_selection.cpp
1 /*
2 * Copyright © 2010 Intel 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
21 * DEALINGS IN THE SOFTWARE.
22 */
23 #include <stdio.h>
24 #include "main/imports.h"
25 #include "symbol_table.h"
26 #include "glsl_parser_extras.h"
27 #include "ast.h"
28 #include "glsl_types.h"
29 #include "ir.h"
30
31 #define X 1
32 #define R 5
33 #define S 9
34 #define I 13
35
36 static bool
37 generate_swizzle(const char *str, ir_dereference *deref,
38 unsigned vector_length)
39 {
40 /* For each possible swizzle character, this table encodes the value in
41 * \c idx_map that represents the 0th element of the vector. For invalid
42 * swizzle characters (e.g., 'k'), a special value is used that will allow
43 * detection of errors.
44 */
45 static const unsigned char base_idx[26] = {
46 /* a b c d e f g h i j k l m */
47 R, R, I, I, I, I, R, I, I, I, I, I, I,
48 /* n o p q r s t u v w x y z */
49 I, I, S, S, R, S, S, I, I, X, X, X, X
50 };
51
52 /* Each valid swizzle character has an entry in the previous table. This
53 * table encodes the base index encoded in the previous table plus the actual
54 * index of the swizzle character. When processing swizzles, the first
55 * character in the string is indexed in the previous table. Each character
56 * in the string is indexed in this table, and the value found there has the
57 * value form the first table subtracted. The result must be on the range
58 * [0,3].
59 *
60 * For example, the string "wzyx" will get X from the first table. Each of
61 * the charcaters will get X+3, X+2, X+1, and X+0 from this table. After
62 * subtraction, the swizzle values are { 3, 2, 1, 0 }.
63 *
64 * The string "wzrg" will get X from the first table. Each of the characters
65 * will get X+3, X+2, R+0, and R+1 from this table. After subtraction, the
66 * swizzle values are { 3, 2, 4, 5 }. Since 4 and 5 are outside the range
67 * [0,3], the error is detected.
68 */
69 static const unsigned char idx_map[26] = {
70 /* a b c d e f g h i j k l m */
71 R+3, R+2, 0, 0, 0, 0, R+1, 0, 0, 0, 0, 0, 0,
72 /* n o p q r s t u v w x y z */
73 0, 0, S+2, S+3, R+0, S+0, S+1, 0, 0, X+3, X+0, X+1, X+2
74 };
75
76 int swiz_idx[4] = { 0, 0, 0, 0 };
77 unsigned i;
78
79
80 /* Validate the first character in the swizzle string and look up the base
81 * index value as described above.
82 */
83 if ((str[0] < 'a') || (str[0] > 'z'))
84 return false;
85
86 const unsigned base = base_idx[str[0] - 'a'];
87
88
89 for (i = 0; (i < 4) && (str[i] != '\0'); i++) {
90 /* Validate the next character, and, as described above, convert it to a
91 * swizzle index.
92 */
93 if ((str[i] < 'a') || (str[i] > 'z'))
94 return false;
95
96 swiz_idx[i] = idx_map[str[i] - 'a'] - base;
97 if ((swiz_idx[i] < 0) || (swiz_idx[i] >= (int) vector_length))
98 return false;
99 }
100
101 if (str[i] != '\0')
102 return false;
103
104 deref->set_swizzle(swiz_idx[0], swiz_idx[1], swiz_idx[2], swiz_idx[3], i);
105 return true;
106 }
107
108
109 struct ir_instruction *
110 _mesa_ast_field_selection_to_hir(const ast_expression *expr,
111 exec_list *instructions,
112 struct _mesa_glsl_parse_state *state)
113 {
114 ir_instruction *op;
115 ir_dereference *deref;
116 YYLTYPE loc;
117
118
119 op = expr->subexpressions[0]->hir(instructions, state);
120 deref = new ir_dereference(op);
121
122 /* Initially assume that the resulting type of the field selection is an
123 * error. This make the error paths below a bit easier to follow.
124 */
125 deref->type = glsl_error_type;
126
127 /* If processing the thing being dereferenced generated an error, bail out
128 * now. Doing so prevents spurious error messages from being logged below.
129 */
130 if (is_error_type(op->type))
131 return (struct ir_instruction *) deref;
132
133 /* There are two kinds of field selection. There is the selection of a
134 * specific field from a structure, and there is the selection of a
135 * swizzle / mask from a vector. Which is which is determined entirely
136 * by the base type of the thing to which the field selection operator is
137 * being applied.
138 */
139 loc = expr->get_location();
140 if (op->type->is_vector()) {
141 if (generate_swizzle(expr->primary_expression.identifier,
142 deref, op->type->vector_elements)) {
143 /* Based on the number of elements in the swizzle and the base type
144 * (i.e., float, int, unsigned, or bool) of the vector being swizzled,
145 * generate the type of the resulting value.
146 */
147 deref->type =
148 glsl_type::get_instance(op->type->base_type,
149 deref->selector.swizzle.num_components,
150 1);
151 } else {
152 /* FINISHME: Logging of error messages should be moved into
153 * FINISHME: generate_swizzle. This allows the generation of more
154 * FINISHME: specific error messages.
155 */
156 _mesa_glsl_error(& loc, state, "Invalid swizzle / mask `%s'",
157 expr->primary_expression.identifier);
158 }
159 } else if (op->type->base_type == GLSL_TYPE_STRUCT) {
160 /* FINISHME: Handle field selection from structures. */
161 } else {
162 _mesa_glsl_error(& loc, state, "Cannot access field `%s' of "
163 "non-structure / non-vector.",
164 expr->primary_expression.identifier);
165 }
166
167 return (struct ir_instruction *) deref;
168 }