Make AST->HIR conversion a method of ast_node, re-enable
[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, struct ir_swizzle_mask *swiz,
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 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 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 base;
78 unsigned dup_mask = 0;
79 unsigned seen_mask = 0;
80 unsigned i;
81
82
83 /* Validate the first character in the swizzle string and look up the base
84 * index value as described above.
85 */
86 if ((str[0] < 'a') || (str[0] > 'z'))
87 return false;
88
89 base = base_idx[str[0] - 'a'];
90
91
92 for (i = 0; (i < 4) && (str[i] != '\0'); i++) {
93 unsigned bit;
94
95 /* Validate the next character, and, as described above, convert it to a
96 * swizzle index.
97 */
98 if ((str[i] < 'a') || (str[i] > 'z'))
99 return false;
100
101 swiz_idx[i] = idx_map[str[0] - 'a'] - base;
102 if ((swiz_idx[i] < 0) || (swiz_idx[i] >= (int) vector_length))
103 return false;
104
105
106 /* Track a bit-mask of the swizzle index values that have been seen. If
107 * a value is seen more than once, set the "duplicate" flag.
108 */
109 bit = (1U << swiz_idx[i]);
110 dup_mask |= seen_mask & bit;
111 seen_mask |= bit;
112 }
113
114 if (str[i] != '\0')
115 return false;
116
117 swiz->x = swiz_idx[0];
118 swiz->y = swiz_idx[1];
119 swiz->z = swiz_idx[2];
120 swiz->w = swiz_idx[3];
121 swiz->num_components = i;
122 swiz->has_duplicates = (dup_mask != 0);
123
124 return true;
125 }
126
127
128 struct ir_instruction *
129 _mesa_ast_field_selection_to_hir(const ast_expression *expr,
130 simple_node *instructions,
131 struct _mesa_glsl_parse_state *state)
132 {
133 ir_instruction *op;
134 ir_dereference *deref;
135 YYLTYPE loc;
136
137
138 op = expr->subexpressions[0]->hir(instructions, state);
139 deref = new ir_dereference(op);
140
141 /* Initially assume that the resulting type of the field selection is an
142 * error. This make the error paths below a bit easier to follow.
143 */
144 deref->type = glsl_error_type;
145
146 /* If processing the thing being dereferenced generated an error, bail out
147 * now. Doing so prevents spurious error messages from being logged below.
148 */
149 if (is_error_type(op->type))
150 return (struct ir_instruction *) deref;
151
152 /* There are two kinds of field selection. There is the selection of a
153 * specific field from a structure, and there is the selection of a
154 * swizzle / mask from a vector. Which is which is determined entirely
155 * by the base type of the thing to which the field selection operator is
156 * being applied.
157 */
158 loc = expr->get_location();
159 if (is_glsl_type_vector(op->type)) {
160 if (generate_swizzle(expr->primary_expression.identifier,
161 & deref->selector.swizzle,
162 op->type->vector_elements)) {
163 /* Based on the number of elements in the swizzle and the base type
164 * (i.e., float, int, unsigned, or bool) of the vector being swizzled,
165 * generate the type of the resulting value.
166 */
167 deref->type =
168 _mesa_glsl_get_vector_type(op->type->base_type,
169 deref->selector.swizzle.num_components);
170 } else {
171 /* FINISHME: Logging of error messages should be moved into
172 * FINISHME: generate_swizzle. This allows the generation of more
173 * FINISHME: specific error messages.
174 */
175 _mesa_glsl_error(& loc, state, "Invalid swizzle / mask `%s'",
176 expr->primary_expression.identifier);
177 }
178 } else if (op->type->base_type == GLSL_TYPE_STRUCT) {
179 /* FINISHME: Handle field selection from structures. */
180 } else {
181 _mesa_glsl_error(& loc, state, "Cannot access field `%s' of "
182 "non-structure / non-vector.",
183 expr->primary_expression.identifier);
184 }
185
186 return (struct ir_instruction *) deref;
187 }