Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5564 | serge | 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 | |||
24 | #include "ir_reader.h" |
||
25 | #include "glsl_parser_extras.h" |
||
26 | #include "glsl_types.h" |
||
27 | #include "s_expression.h" |
||
28 | |||
29 | const static bool debug = false; |
||
30 | |||
31 | namespace { |
||
32 | |||
33 | class ir_reader { |
||
34 | public: |
||
35 | ir_reader(_mesa_glsl_parse_state *); |
||
36 | |||
37 | void read(exec_list *instructions, const char *src, bool scan_for_protos); |
||
38 | |||
39 | private: |
||
40 | void *mem_ctx; |
||
41 | _mesa_glsl_parse_state *state; |
||
42 | |||
43 | void ir_read_error(s_expression *, const char *fmt, ...); |
||
44 | |||
45 | const glsl_type *read_type(s_expression *); |
||
46 | |||
47 | void scan_for_prototypes(exec_list *, s_expression *); |
||
48 | ir_function *read_function(s_expression *, bool skip_body); |
||
49 | void read_function_sig(ir_function *, s_expression *, bool skip_body); |
||
50 | |||
51 | void read_instructions(exec_list *, s_expression *, ir_loop *); |
||
52 | ir_instruction *read_instruction(s_expression *, ir_loop *); |
||
53 | ir_variable *read_declaration(s_expression *); |
||
54 | ir_if *read_if(s_expression *, ir_loop *); |
||
55 | ir_loop *read_loop(s_expression *); |
||
56 | ir_call *read_call(s_expression *); |
||
57 | ir_return *read_return(s_expression *); |
||
58 | ir_rvalue *read_rvalue(s_expression *); |
||
59 | ir_assignment *read_assignment(s_expression *); |
||
60 | ir_expression *read_expression(s_expression *); |
||
61 | ir_swizzle *read_swizzle(s_expression *); |
||
62 | ir_constant *read_constant(s_expression *); |
||
63 | ir_texture *read_texture(s_expression *); |
||
64 | ir_emit_vertex *read_emit_vertex(s_expression *); |
||
65 | ir_end_primitive *read_end_primitive(s_expression *); |
||
66 | |||
67 | ir_dereference *read_dereference(s_expression *); |
||
68 | ir_dereference_variable *read_var_ref(s_expression *); |
||
69 | }; |
||
70 | |||
71 | } /* anonymous namespace */ |
||
72 | |||
73 | ir_reader::ir_reader(_mesa_glsl_parse_state *state) : state(state) |
||
74 | { |
||
75 | this->mem_ctx = state; |
||
76 | } |
||
77 | |||
78 | void |
||
79 | _mesa_glsl_read_ir(_mesa_glsl_parse_state *state, exec_list *instructions, |
||
80 | const char *src, bool scan_for_protos) |
||
81 | { |
||
82 | ir_reader r(state); |
||
83 | r.read(instructions, src, scan_for_protos); |
||
84 | } |
||
85 | |||
86 | void |
||
87 | ir_reader::read(exec_list *instructions, const char *src, bool scan_for_protos) |
||
88 | { |
||
89 | void *sx_mem_ctx = ralloc_context(NULL); |
||
90 | s_expression *expr = s_expression::read_expression(sx_mem_ctx, src); |
||
91 | if (expr == NULL) { |
||
92 | ir_read_error(NULL, "couldn't parse S-Expression."); |
||
93 | return; |
||
94 | } |
||
95 | |||
96 | if (scan_for_protos) { |
||
97 | scan_for_prototypes(instructions, expr); |
||
98 | if (state->error) |
||
99 | return; |
||
100 | } |
||
101 | |||
102 | read_instructions(instructions, expr, NULL); |
||
103 | ralloc_free(sx_mem_ctx); |
||
104 | |||
105 | if (debug) |
||
106 | validate_ir_tree(instructions); |
||
107 | } |
||
108 | |||
109 | void |
||
110 | ir_reader::ir_read_error(s_expression *expr, const char *fmt, ...) |
||
111 | { |
||
112 | va_list ap; |
||
113 | |||
114 | state->error = true; |
||
115 | |||
116 | if (state->current_function != NULL) |
||
117 | ralloc_asprintf_append(&state->info_log, "In function %s:\n", |
||
118 | state->current_function->function_name()); |
||
119 | ralloc_strcat(&state->info_log, "error: "); |
||
120 | |||
121 | va_start(ap, fmt); |
||
122 | ralloc_vasprintf_append(&state->info_log, fmt, ap); |
||
123 | va_end(ap); |
||
124 | ralloc_strcat(&state->info_log, "\n"); |
||
125 | |||
126 | if (expr != NULL) { |
||
127 | ralloc_strcat(&state->info_log, "...in this context:\n "); |
||
128 | expr->print(); |
||
129 | ralloc_strcat(&state->info_log, "\n\n"); |
||
130 | } |
||
131 | } |
||
132 | |||
133 | const glsl_type * |
||
134 | ir_reader::read_type(s_expression *expr) |
||
135 | { |
||
136 | s_expression *s_base_type; |
||
137 | s_int *s_size; |
||
138 | |||
139 | s_pattern pat[] = { "array", s_base_type, s_size }; |
||
140 | if (MATCH(expr, pat)) { |
||
141 | const glsl_type *base_type = read_type(s_base_type); |
||
142 | if (base_type == NULL) { |
||
143 | ir_read_error(NULL, "when reading base type of array type"); |
||
144 | return NULL; |
||
145 | } |
||
146 | |||
147 | return glsl_type::get_array_instance(base_type, s_size->value()); |
||
148 | } |
||
149 | |||
150 | s_symbol *type_sym = SX_AS_SYMBOL(expr); |
||
151 | if (type_sym == NULL) { |
||
152 | ir_read_error(expr, "expected |
||
153 | return NULL; |
||
154 | } |
||
155 | |||
156 | const glsl_type *type = state->symbols->get_type(type_sym->value()); |
||
157 | if (type == NULL) |
||
158 | ir_read_error(expr, "invalid type: %s", type_sym->value()); |
||
159 | |||
160 | return type; |
||
161 | } |
||
162 | |||
163 | |||
164 | void |
||
165 | ir_reader::scan_for_prototypes(exec_list *instructions, s_expression *expr) |
||
166 | { |
||
167 | s_list *list = SX_AS_LIST(expr); |
||
168 | if (list == NULL) { |
||
169 | ir_read_error(expr, "Expected ( |
||
170 | return; |
||
171 | } |
||
172 | |||
173 | foreach_in_list(s_list, sub, &list->subexpressions) { |
||
174 | if (!sub->is_list()) |
||
175 | continue; // not a (function ...); ignore it. |
||
176 | |||
177 | s_symbol *tag = SX_AS_SYMBOL(sub->subexpressions.get_head()); |
||
178 | if (tag == NULL || strcmp(tag->value(), "function") != 0) |
||
179 | continue; // not a (function ...); ignore it. |
||
180 | |||
181 | ir_function *f = read_function(sub, true); |
||
182 | if (f == NULL) |
||
183 | return; |
||
184 | instructions->push_tail(f); |
||
185 | } |
||
186 | } |
||
187 | |||
188 | ir_function * |
||
189 | ir_reader::read_function(s_expression *expr, bool skip_body) |
||
190 | { |
||
191 | bool added = false; |
||
192 | s_symbol *name; |
||
193 | |||
194 | s_pattern pat[] = { "function", name }; |
||
195 | if (!PARTIAL_MATCH(expr, pat)) { |
||
196 | ir_read_error(expr, "Expected (function |
||
197 | return NULL; |
||
198 | } |
||
199 | |||
200 | ir_function *f = state->symbols->get_function(name->value()); |
||
201 | if (f == NULL) { |
||
202 | f = new(mem_ctx) ir_function(name->value()); |
||
203 | added = state->symbols->add_function(f); |
||
204 | assert(added); |
||
205 | } |
||
206 | |||
207 | /* Skip over "function" tag and function name (which are guaranteed to be |
||
208 | * present by the above PARTIAL_MATCH call). |
||
209 | */ |
||
210 | exec_node *node = ((s_list *) expr)->subexpressions.head->next->next; |
||
211 | for (/* nothing */; !node->is_tail_sentinel(); node = node->next) { |
||
212 | s_expression *s_sig = (s_expression *) node; |
||
213 | read_function_sig(f, s_sig, skip_body); |
||
214 | } |
||
215 | return added ? f : NULL; |
||
216 | } |
||
217 | |||
218 | static bool |
||
219 | always_available(const _mesa_glsl_parse_state *) |
||
220 | { |
||
221 | return true; |
||
222 | } |
||
223 | |||
224 | void |
||
225 | ir_reader::read_function_sig(ir_function *f, s_expression *expr, bool skip_body) |
||
226 | { |
||
227 | s_expression *type_expr; |
||
228 | s_list *paramlist; |
||
229 | s_list *body_list; |
||
230 | |||
231 | s_pattern pat[] = { "signature", type_expr, paramlist, body_list }; |
||
232 | if (!MATCH(expr, pat)) { |
||
233 | ir_read_error(expr, "Expected (signature |
||
234 | "( |
||
235 | return; |
||
236 | } |
||
237 | |||
238 | const glsl_type *return_type = read_type(type_expr); |
||
239 | if (return_type == NULL) |
||
240 | return; |
||
241 | |||
242 | s_symbol *paramtag = SX_AS_SYMBOL(paramlist->subexpressions.get_head()); |
||
243 | if (paramtag == NULL || strcmp(paramtag->value(), "parameters") != 0) { |
||
244 | ir_read_error(paramlist, "Expected (parameters ...)"); |
||
245 | return; |
||
246 | } |
||
247 | |||
248 | // Read the parameters list into a temporary place. |
||
249 | exec_list hir_parameters; |
||
250 | state->symbols->push_scope(); |
||
251 | |||
252 | /* Skip over the "parameters" tag. */ |
||
253 | exec_node *node = paramlist->subexpressions.head->next; |
||
254 | for (/* nothing */; !node->is_tail_sentinel(); node = node->next) { |
||
255 | ir_variable *var = read_declaration((s_expression *) node); |
||
256 | if (var == NULL) |
||
257 | return; |
||
258 | |||
259 | hir_parameters.push_tail(var); |
||
260 | } |
||
261 | |||
262 | ir_function_signature *sig = |
||
263 | f->exact_matching_signature(state, &hir_parameters); |
||
264 | if (sig == NULL && skip_body) { |
||
265 | /* If scanning for prototypes, generate a new signature. */ |
||
266 | /* ir_reader doesn't know what languages support a given built-in, so |
||
267 | * just say that they're always available. For now, other mechanisms |
||
268 | * guarantee the right built-ins are available. |
||
269 | */ |
||
270 | sig = new(mem_ctx) ir_function_signature(return_type, always_available); |
||
271 | f->add_signature(sig); |
||
272 | } else if (sig != NULL) { |
||
273 | const char *badvar = sig->qualifiers_match(&hir_parameters); |
||
274 | if (badvar != NULL) { |
||
275 | ir_read_error(expr, "function `%s' parameter `%s' qualifiers " |
||
276 | "don't match prototype", f->name, badvar); |
||
277 | return; |
||
278 | } |
||
279 | |||
280 | if (sig->return_type != return_type) { |
||
281 | ir_read_error(expr, "function `%s' return type doesn't " |
||
282 | "match prototype", f->name); |
||
283 | return; |
||
284 | } |
||
285 | } else { |
||
286 | /* No prototype for this body exists - skip it. */ |
||
287 | state->symbols->pop_scope(); |
||
288 | return; |
||
289 | } |
||
290 | assert(sig != NULL); |
||
291 | |||
292 | sig->replace_parameters(&hir_parameters); |
||
293 | |||
294 | if (!skip_body && !body_list->subexpressions.is_empty()) { |
||
295 | if (sig->is_defined) { |
||
296 | ir_read_error(expr, "function %s redefined", f->name); |
||
297 | return; |
||
298 | } |
||
299 | state->current_function = sig; |
||
300 | read_instructions(&sig->body, body_list, NULL); |
||
301 | state->current_function = NULL; |
||
302 | sig->is_defined = true; |
||
303 | } |
||
304 | |||
305 | state->symbols->pop_scope(); |
||
306 | } |
||
307 | |||
308 | void |
||
309 | ir_reader::read_instructions(exec_list *instructions, s_expression *expr, |
||
310 | ir_loop *loop_ctx) |
||
311 | { |
||
312 | // Read in a list of instructions |
||
313 | s_list *list = SX_AS_LIST(expr); |
||
314 | if (list == NULL) { |
||
315 | ir_read_error(expr, "Expected ( |
||
316 | return; |
||
317 | } |
||
318 | |||
319 | foreach_in_list(s_expression, sub, &list->subexpressions) { |
||
320 | ir_instruction *ir = read_instruction(sub, loop_ctx); |
||
321 | if (ir != NULL) { |
||
322 | /* Global variable declarations should be moved to the top, before |
||
323 | * any functions that might use them. Functions are added to the |
||
324 | * instruction stream when scanning for prototypes, so without this |
||
325 | * hack, they always appear before variable declarations. |
||
326 | */ |
||
327 | if (state->current_function == NULL && ir->as_variable() != NULL) |
||
328 | instructions->push_head(ir); |
||
329 | else |
||
330 | instructions->push_tail(ir); |
||
331 | } |
||
332 | } |
||
333 | } |
||
334 | |||
335 | |||
336 | ir_instruction * |
||
337 | ir_reader::read_instruction(s_expression *expr, ir_loop *loop_ctx) |
||
338 | { |
||
339 | s_symbol *symbol = SX_AS_SYMBOL(expr); |
||
340 | if (symbol != NULL) { |
||
341 | if (strcmp(symbol->value(), "break") == 0 && loop_ctx != NULL) |
||
342 | return new(mem_ctx) ir_loop_jump(ir_loop_jump::jump_break); |
||
343 | if (strcmp(symbol->value(), "continue") == 0 && loop_ctx != NULL) |
||
344 | return new(mem_ctx) ir_loop_jump(ir_loop_jump::jump_continue); |
||
345 | } |
||
346 | |||
347 | s_list *list = SX_AS_LIST(expr); |
||
348 | if (list == NULL || list->subexpressions.is_empty()) { |
||
349 | ir_read_error(expr, "Invalid instruction.\n"); |
||
350 | return NULL; |
||
351 | } |
||
352 | |||
353 | s_symbol *tag = SX_AS_SYMBOL(list->subexpressions.get_head()); |
||
354 | if (tag == NULL) { |
||
355 | ir_read_error(expr, "expected instruction tag"); |
||
356 | return NULL; |
||
357 | } |
||
358 | |||
359 | ir_instruction *inst = NULL; |
||
360 | if (strcmp(tag->value(), "declare") == 0) { |
||
361 | inst = read_declaration(list); |
||
362 | } else if (strcmp(tag->value(), "assign") == 0) { |
||
363 | inst = read_assignment(list); |
||
364 | } else if (strcmp(tag->value(), "if") == 0) { |
||
365 | inst = read_if(list, loop_ctx); |
||
366 | } else if (strcmp(tag->value(), "loop") == 0) { |
||
367 | inst = read_loop(list); |
||
368 | } else if (strcmp(tag->value(), "call") == 0) { |
||
369 | inst = read_call(list); |
||
370 | } else if (strcmp(tag->value(), "return") == 0) { |
||
371 | inst = read_return(list); |
||
372 | } else if (strcmp(tag->value(), "function") == 0) { |
||
373 | inst = read_function(list, false); |
||
374 | } else if (strcmp(tag->value(), "emit-vertex") == 0) { |
||
375 | inst = read_emit_vertex(list); |
||
376 | } else if (strcmp(tag->value(), "end-primitive") == 0) { |
||
377 | inst = read_end_primitive(list); |
||
378 | } else { |
||
379 | inst = read_rvalue(list); |
||
380 | if (inst == NULL) |
||
381 | ir_read_error(NULL, "when reading instruction"); |
||
382 | } |
||
383 | return inst; |
||
384 | } |
||
385 | |||
386 | ir_variable * |
||
387 | ir_reader::read_declaration(s_expression *expr) |
||
388 | { |
||
389 | s_list *s_quals; |
||
390 | s_expression *s_type; |
||
391 | s_symbol *s_name; |
||
392 | |||
393 | s_pattern pat[] = { "declare", s_quals, s_type, s_name }; |
||
394 | if (!MATCH(expr, pat)) { |
||
395 | ir_read_error(expr, "expected (declare ( |
||
396 | return NULL; |
||
397 | } |
||
398 | |||
399 | const glsl_type *type = read_type(s_type); |
||
400 | if (type == NULL) |
||
401 | return NULL; |
||
402 | |||
403 | ir_variable *var = new(mem_ctx) ir_variable(type, s_name->value(), |
||
404 | ir_var_auto); |
||
405 | |||
406 | foreach_in_list(s_symbol, qualifier, &s_quals->subexpressions) { |
||
407 | if (!qualifier->is_symbol()) { |
||
408 | ir_read_error(expr, "qualifier list must contain only symbols"); |
||
409 | return NULL; |
||
410 | } |
||
411 | |||
412 | // FINISHME: Check for duplicate/conflicting qualifiers. |
||
413 | if (strcmp(qualifier->value(), "centroid") == 0) { |
||
414 | var->data.centroid = 1; |
||
415 | } else if (strcmp(qualifier->value(), "sample") == 0) { |
||
416 | var->data.sample = 1; |
||
417 | } else if (strcmp(qualifier->value(), "invariant") == 0) { |
||
418 | var->data.invariant = 1; |
||
419 | } else if (strcmp(qualifier->value(), "uniform") == 0) { |
||
420 | var->data.mode = ir_var_uniform; |
||
421 | } else if (strcmp(qualifier->value(), "auto") == 0) { |
||
422 | var->data.mode = ir_var_auto; |
||
423 | } else if (strcmp(qualifier->value(), "in") == 0) { |
||
424 | var->data.mode = ir_var_function_in; |
||
425 | } else if (strcmp(qualifier->value(), "shader_in") == 0) { |
||
426 | var->data.mode = ir_var_shader_in; |
||
427 | } else if (strcmp(qualifier->value(), "const_in") == 0) { |
||
428 | var->data.mode = ir_var_const_in; |
||
429 | } else if (strcmp(qualifier->value(), "out") == 0) { |
||
430 | var->data.mode = ir_var_function_out; |
||
431 | } else if (strcmp(qualifier->value(), "shader_out") == 0) { |
||
432 | var->data.mode = ir_var_shader_out; |
||
433 | } else if (strcmp(qualifier->value(), "inout") == 0) { |
||
434 | var->data.mode = ir_var_function_inout; |
||
435 | } else if (strcmp(qualifier->value(), "temporary") == 0) { |
||
436 | var->data.mode = ir_var_temporary; |
||
437 | } else if (strcmp(qualifier->value(), "stream1") == 0) { |
||
438 | var->data.stream = 1; |
||
439 | } else if (strcmp(qualifier->value(), "stream2") == 0) { |
||
440 | var->data.stream = 2; |
||
441 | } else if (strcmp(qualifier->value(), "stream3") == 0) { |
||
442 | var->data.stream = 3; |
||
443 | } else if (strcmp(qualifier->value(), "smooth") == 0) { |
||
444 | var->data.interpolation = INTERP_QUALIFIER_SMOOTH; |
||
445 | } else if (strcmp(qualifier->value(), "flat") == 0) { |
||
446 | var->data.interpolation = INTERP_QUALIFIER_FLAT; |
||
447 | } else if (strcmp(qualifier->value(), "noperspective") == 0) { |
||
448 | var->data.interpolation = INTERP_QUALIFIER_NOPERSPECTIVE; |
||
449 | } else { |
||
450 | ir_read_error(expr, "unknown qualifier: %s", qualifier->value()); |
||
451 | return NULL; |
||
452 | } |
||
453 | } |
||
454 | |||
455 | // Add the variable to the symbol table |
||
456 | state->symbols->add_variable(var); |
||
457 | |||
458 | return var; |
||
459 | } |
||
460 | |||
461 | |||
462 | ir_if * |
||
463 | ir_reader::read_if(s_expression *expr, ir_loop *loop_ctx) |
||
464 | { |
||
465 | s_expression *s_cond; |
||
466 | s_expression *s_then; |
||
467 | s_expression *s_else; |
||
468 | |||
469 | s_pattern pat[] = { "if", s_cond, s_then, s_else }; |
||
470 | if (!MATCH(expr, pat)) { |
||
471 | ir_read_error(expr, "expected (if |
||
472 | return NULL; |
||
473 | } |
||
474 | |||
475 | ir_rvalue *condition = read_rvalue(s_cond); |
||
476 | if (condition == NULL) { |
||
477 | ir_read_error(NULL, "when reading condition of (if ...)"); |
||
478 | return NULL; |
||
479 | } |
||
480 | |||
481 | ir_if *iff = new(mem_ctx) ir_if(condition); |
||
482 | |||
483 | read_instructions(&iff->then_instructions, s_then, loop_ctx); |
||
484 | read_instructions(&iff->else_instructions, s_else, loop_ctx); |
||
485 | if (state->error) { |
||
486 | delete iff; |
||
487 | iff = NULL; |
||
488 | } |
||
489 | return iff; |
||
490 | } |
||
491 | |||
492 | |||
493 | ir_loop * |
||
494 | ir_reader::read_loop(s_expression *expr) |
||
495 | { |
||
496 | s_expression *s_body; |
||
497 | |||
498 | s_pattern loop_pat[] = { "loop", s_body }; |
||
499 | if (!MATCH(expr, loop_pat)) { |
||
500 | ir_read_error(expr, "expected (loop )"); |
||
501 | return NULL; |
||
502 | } |
||
503 | |||
504 | ir_loop *loop = new(mem_ctx) ir_loop; |
||
505 | |||
506 | read_instructions(&loop->body_instructions, s_body, loop); |
||
507 | if (state->error) { |
||
508 | delete loop; |
||
509 | loop = NULL; |
||
510 | } |
||
511 | return loop; |
||
512 | } |
||
513 | |||
514 | |||
515 | ir_return * |
||
516 | ir_reader::read_return(s_expression *expr) |
||
517 | { |
||
518 | s_expression *s_retval; |
||
519 | |||
520 | s_pattern return_value_pat[] = { "return", s_retval}; |
||
521 | s_pattern return_void_pat[] = { "return" }; |
||
522 | if (MATCH(expr, return_value_pat)) { |
||
523 | ir_rvalue *retval = read_rvalue(s_retval); |
||
524 | if (retval == NULL) { |
||
525 | ir_read_error(NULL, "when reading return value"); |
||
526 | return NULL; |
||
527 | } |
||
528 | return new(mem_ctx) ir_return(retval); |
||
529 | } else if (MATCH(expr, return_void_pat)) { |
||
530 | return new(mem_ctx) ir_return; |
||
531 | } else { |
||
532 | ir_read_error(expr, "expected (return |
||
533 | return NULL; |
||
534 | } |
||
535 | } |
||
536 | |||
537 | |||
538 | ir_rvalue * |
||
539 | ir_reader::read_rvalue(s_expression *expr) |
||
540 | { |
||
541 | s_list *list = SX_AS_LIST(expr); |
||
542 | if (list == NULL || list->subexpressions.is_empty()) |
||
543 | return NULL; |
||
544 | |||
545 | s_symbol *tag = SX_AS_SYMBOL(list->subexpressions.get_head()); |
||
546 | if (tag == NULL) { |
||
547 | ir_read_error(expr, "expected rvalue tag"); |
||
548 | return NULL; |
||
549 | } |
||
550 | |||
551 | ir_rvalue *rvalue = read_dereference(list); |
||
552 | if (rvalue != NULL || state->error) |
||
553 | return rvalue; |
||
554 | else if (strcmp(tag->value(), "swiz") == 0) { |
||
555 | rvalue = read_swizzle(list); |
||
556 | } else if (strcmp(tag->value(), "expression") == 0) { |
||
557 | rvalue = read_expression(list); |
||
558 | } else if (strcmp(tag->value(), "constant") == 0) { |
||
559 | rvalue = read_constant(list); |
||
560 | } else { |
||
561 | rvalue = read_texture(list); |
||
562 | if (rvalue == NULL && !state->error) |
||
563 | ir_read_error(expr, "unrecognized rvalue tag: %s", tag->value()); |
||
564 | } |
||
565 | |||
566 | return rvalue; |
||
567 | } |
||
568 | |||
569 | ir_assignment * |
||
570 | ir_reader::read_assignment(s_expression *expr) |
||
571 | { |
||
572 | s_expression *cond_expr = NULL; |
||
573 | s_expression *lhs_expr, *rhs_expr; |
||
574 | s_list *mask_list; |
||
575 | |||
576 | s_pattern pat4[] = { "assign", mask_list, lhs_expr, rhs_expr }; |
||
577 | s_pattern pat5[] = { "assign", cond_expr, mask_list, lhs_expr, rhs_expr }; |
||
578 | if (!MATCH(expr, pat4) && !MATCH(expr, pat5)) { |
||
579 | ir_read_error(expr, "expected (assign [ |
||
580 | " |
||
581 | return NULL; |
||
582 | } |
||
583 | |||
584 | ir_rvalue *condition = NULL; |
||
585 | if (cond_expr != NULL) { |
||
586 | condition = read_rvalue(cond_expr); |
||
587 | if (condition == NULL) { |
||
588 | ir_read_error(NULL, "when reading condition of assignment"); |
||
589 | return NULL; |
||
590 | } |
||
591 | } |
||
592 | |||
593 | unsigned mask = 0; |
||
594 | |||
595 | s_symbol *mask_symbol; |
||
596 | s_pattern mask_pat[] = { mask_symbol }; |
||
597 | if (MATCH(mask_list, mask_pat)) { |
||
598 | const char *mask_str = mask_symbol->value(); |
||
599 | unsigned mask_length = strlen(mask_str); |
||
600 | if (mask_length > 4) { |
||
601 | ir_read_error(expr, "invalid write mask: %s", mask_str); |
||
602 | return NULL; |
||
603 | } |
||
604 | |||
605 | const unsigned idx_map[] = { 3, 0, 1, 2 }; /* w=bit 3, x=0, y=1, z=2 */ |
||
606 | |||
607 | for (unsigned i = 0; i < mask_length; i++) { |
||
608 | if (mask_str[i] < 'w' || mask_str[i] > 'z') { |
||
609 | ir_read_error(expr, "write mask contains invalid character: %c", |
||
610 | mask_str[i]); |
||
611 | return NULL; |
||
612 | } |
||
613 | mask |= 1 << idx_map[mask_str[i] - 'w']; |
||
614 | } |
||
615 | } else if (!mask_list->subexpressions.is_empty()) { |
||
616 | ir_read_error(mask_list, "expected () or ( |
||
617 | return NULL; |
||
618 | } |
||
619 | |||
620 | ir_dereference *lhs = read_dereference(lhs_expr); |
||
621 | if (lhs == NULL) { |
||
622 | ir_read_error(NULL, "when reading left-hand side of assignment"); |
||
623 | return NULL; |
||
624 | } |
||
625 | |||
626 | ir_rvalue *rhs = read_rvalue(rhs_expr); |
||
627 | if (rhs == NULL) { |
||
628 | ir_read_error(NULL, "when reading right-hand side of assignment"); |
||
629 | return NULL; |
||
630 | } |
||
631 | |||
632 | if (mask == 0 && (lhs->type->is_vector() || lhs->type->is_scalar())) { |
||
633 | ir_read_error(expr, "non-zero write mask required."); |
||
634 | return NULL; |
||
635 | } |
||
636 | |||
637 | return new(mem_ctx) ir_assignment(lhs, rhs, condition, mask); |
||
638 | } |
||
639 | |||
640 | ir_call * |
||
641 | ir_reader::read_call(s_expression *expr) |
||
642 | { |
||
643 | s_symbol *name; |
||
644 | s_list *params; |
||
645 | s_list *s_return = NULL; |
||
646 | |||
647 | ir_dereference_variable *return_deref = NULL; |
||
648 | |||
649 | s_pattern void_pat[] = { "call", name, params }; |
||
650 | s_pattern non_void_pat[] = { "call", name, s_return, params }; |
||
651 | if (MATCH(expr, non_void_pat)) { |
||
652 | return_deref = read_var_ref(s_return); |
||
653 | if (return_deref == NULL) { |
||
654 | ir_read_error(s_return, "when reading a call's return storage"); |
||
655 | return NULL; |
||
656 | } |
||
657 | } else if (!MATCH(expr, void_pat)) { |
||
658 | ir_read_error(expr, "expected (call |
||
659 | return NULL; |
||
660 | } |
||
661 | |||
662 | exec_list parameters; |
||
663 | |||
664 | foreach_in_list(s_expression, e, ¶ms->subexpressions) { |
||
665 | ir_rvalue *param = read_rvalue(e); |
||
666 | if (param == NULL) { |
||
667 | ir_read_error(e, "when reading parameter to function call"); |
||
668 | return NULL; |
||
669 | } |
||
670 | parameters.push_tail(param); |
||
671 | } |
||
672 | |||
673 | ir_function *f = state->symbols->get_function(name->value()); |
||
674 | if (f == NULL) { |
||
675 | ir_read_error(expr, "found call to undefined function %s", |
||
676 | name->value()); |
||
677 | return NULL; |
||
678 | } |
||
679 | |||
680 | ir_function_signature *callee = |
||
681 | f->matching_signature(state, ¶meters, true); |
||
682 | if (callee == NULL) { |
||
683 | ir_read_error(expr, "couldn't find matching signature for function " |
||
684 | "%s", name->value()); |
||
685 | return NULL; |
||
686 | } |
||
687 | |||
688 | if (callee->return_type == glsl_type::void_type && return_deref) { |
||
689 | ir_read_error(expr, "call has return value storage but void type"); |
||
690 | return NULL; |
||
691 | } else if (callee->return_type != glsl_type::void_type && !return_deref) { |
||
692 | ir_read_error(expr, "call has non-void type but no return value storage"); |
||
693 | return NULL; |
||
694 | } |
||
695 | |||
696 | return new(mem_ctx) ir_call(callee, return_deref, ¶meters); |
||
697 | } |
||
698 | |||
699 | ir_expression * |
||
700 | ir_reader::read_expression(s_expression *expr) |
||
701 | { |
||
702 | s_expression *s_type; |
||
703 | s_symbol *s_op; |
||
704 | s_expression *s_arg[4] = {NULL}; |
||
705 | |||
706 | s_pattern pat[] = { "expression", s_type, s_op, s_arg[0] }; |
||
707 | if (!PARTIAL_MATCH(expr, pat)) { |
||
708 | ir_read_error(expr, "expected (expression |
||
709 | " |
||
710 | return NULL; |
||
711 | } |
||
712 | s_arg[1] = (s_expression *) s_arg[0]->next; // may be tail sentinel |
||
713 | s_arg[2] = (s_expression *) s_arg[1]->next; // may be tail sentinel or NULL |
||
714 | if (s_arg[2]) |
||
715 | s_arg[3] = (s_expression *) s_arg[2]->next; // may be tail sentinel or NULL |
||
716 | |||
717 | const glsl_type *type = read_type(s_type); |
||
718 | if (type == NULL) |
||
719 | return NULL; |
||
720 | |||
721 | /* Read the operator */ |
||
722 | ir_expression_operation op = ir_expression::get_operator(s_op->value()); |
||
723 | if (op == (ir_expression_operation) -1) { |
||
724 | ir_read_error(expr, "invalid operator: %s", s_op->value()); |
||
725 | return NULL; |
||
726 | } |
||
727 | |||
728 | /* Skip "expression" |
||
729 | int num_operands = (int) ((s_list *) expr)->subexpressions.length() - 3; |
||
730 | |||
731 | int expected_operands = ir_expression::get_num_operands(op); |
||
732 | if (num_operands != expected_operands) { |
||
733 | ir_read_error(expr, "found %d expression operands, expected %d", |
||
734 | num_operands, expected_operands); |
||
735 | return NULL; |
||
736 | } |
||
737 | |||
738 | ir_rvalue *arg[4] = {NULL}; |
||
739 | for (int i = 0; i < num_operands; i++) { |
||
740 | arg[i] = read_rvalue(s_arg[i]); |
||
741 | if (arg[i] == NULL) { |
||
742 | ir_read_error(NULL, "when reading operand #%d of %s", i, s_op->value()); |
||
743 | return NULL; |
||
744 | } |
||
745 | } |
||
746 | |||
747 | return new(mem_ctx) ir_expression(op, type, arg[0], arg[1], arg[2], arg[3]); |
||
748 | } |
||
749 | |||
750 | ir_swizzle * |
||
751 | ir_reader::read_swizzle(s_expression *expr) |
||
752 | { |
||
753 | s_symbol *swiz; |
||
754 | s_expression *sub; |
||
755 | |||
756 | s_pattern pat[] = { "swiz", swiz, sub }; |
||
757 | if (!MATCH(expr, pat)) { |
||
758 | ir_read_error(expr, "expected (swiz |
||
759 | return NULL; |
||
760 | } |
||
761 | |||
762 | if (strlen(swiz->value()) > 4) { |
||
763 | ir_read_error(expr, "expected a valid swizzle; found %s", swiz->value()); |
||
764 | return NULL; |
||
765 | } |
||
766 | |||
767 | ir_rvalue *rvalue = read_rvalue(sub); |
||
768 | if (rvalue == NULL) |
||
769 | return NULL; |
||
770 | |||
771 | ir_swizzle *ir = ir_swizzle::create(rvalue, swiz->value(), |
||
772 | rvalue->type->vector_elements); |
||
773 | if (ir == NULL) |
||
774 | ir_read_error(expr, "invalid swizzle"); |
||
775 | |||
776 | return ir; |
||
777 | } |
||
778 | |||
779 | ir_constant * |
||
780 | ir_reader::read_constant(s_expression *expr) |
||
781 | { |
||
782 | s_expression *type_expr; |
||
783 | s_list *values; |
||
784 | |||
785 | s_pattern pat[] = { "constant", type_expr, values }; |
||
786 | if (!MATCH(expr, pat)) { |
||
787 | ir_read_error(expr, "expected (constant |
||
788 | return NULL; |
||
789 | } |
||
790 | |||
791 | const glsl_type *type = read_type(type_expr); |
||
792 | if (type == NULL) |
||
793 | return NULL; |
||
794 | |||
795 | if (values == NULL) { |
||
796 | ir_read_error(expr, "expected (constant |
||
797 | return NULL; |
||
798 | } |
||
799 | |||
800 | if (type->is_array()) { |
||
801 | unsigned elements_supplied = 0; |
||
802 | exec_list elements; |
||
803 | foreach_in_list(s_expression, elt, &values->subexpressions) { |
||
804 | ir_constant *ir_elt = read_constant(elt); |
||
805 | if (ir_elt == NULL) |
||
806 | return NULL; |
||
807 | elements.push_tail(ir_elt); |
||
808 | elements_supplied++; |
||
809 | } |
||
810 | |||
811 | if (elements_supplied != type->length) { |
||
812 | ir_read_error(values, "expected exactly %u array elements, " |
||
813 | "given %u", type->length, elements_supplied); |
||
814 | return NULL; |
||
815 | } |
||
816 | return new(mem_ctx) ir_constant(type, &elements); |
||
817 | } |
||
818 | |||
819 | ir_constant_data data = { { 0 } }; |
||
820 | |||
821 | // Read in list of values (at most 16). |
||
822 | unsigned k = 0; |
||
823 | foreach_in_list(s_expression, expr, &values->subexpressions) { |
||
824 | if (k >= 16) { |
||
825 | ir_read_error(values, "expected at most 16 numbers"); |
||
826 | return NULL; |
||
827 | } |
||
828 | |||
829 | if (type->base_type == GLSL_TYPE_FLOAT) { |
||
830 | s_number *value = SX_AS_NUMBER(expr); |
||
831 | if (value == NULL) { |
||
832 | ir_read_error(values, "expected numbers"); |
||
833 | return NULL; |
||
834 | } |
||
835 | data.f[k] = value->fvalue(); |
||
836 | } else { |
||
837 | s_int *value = SX_AS_INT(expr); |
||
838 | if (value == NULL) { |
||
839 | ir_read_error(values, "expected integers"); |
||
840 | return NULL; |
||
841 | } |
||
842 | |||
843 | switch (type->base_type) { |
||
844 | case GLSL_TYPE_UINT: { |
||
845 | data.u[k] = value->value(); |
||
846 | break; |
||
847 | } |
||
848 | case GLSL_TYPE_INT: { |
||
849 | data.i[k] = value->value(); |
||
850 | break; |
||
851 | } |
||
852 | case GLSL_TYPE_BOOL: { |
||
853 | data.b[k] = value->value(); |
||
854 | break; |
||
855 | } |
||
856 | default: |
||
857 | ir_read_error(values, "unsupported constant type"); |
||
858 | return NULL; |
||
859 | } |
||
860 | } |
||
861 | ++k; |
||
862 | } |
||
863 | if (k != type->components()) { |
||
864 | ir_read_error(values, "expected %u constant values, found %u", |
||
865 | type->components(), k); |
||
866 | return NULL; |
||
867 | } |
||
868 | |||
869 | return new(mem_ctx) ir_constant(type, &data); |
||
870 | } |
||
871 | |||
872 | ir_dereference_variable * |
||
873 | ir_reader::read_var_ref(s_expression *expr) |
||
874 | { |
||
875 | s_symbol *s_var; |
||
876 | s_pattern var_pat[] = { "var_ref", s_var }; |
||
877 | |||
878 | if (MATCH(expr, var_pat)) { |
||
879 | ir_variable *var = state->symbols->get_variable(s_var->value()); |
||
880 | if (var == NULL) { |
||
881 | ir_read_error(expr, "undeclared variable: %s", s_var->value()); |
||
882 | return NULL; |
||
883 | } |
||
884 | return new(mem_ctx) ir_dereference_variable(var); |
||
885 | } |
||
886 | return NULL; |
||
887 | } |
||
888 | |||
889 | ir_dereference * |
||
890 | ir_reader::read_dereference(s_expression *expr) |
||
891 | { |
||
892 | s_expression *s_subject; |
||
893 | s_expression *s_index; |
||
894 | s_symbol *s_field; |
||
895 | |||
896 | s_pattern array_pat[] = { "array_ref", s_subject, s_index }; |
||
897 | s_pattern record_pat[] = { "record_ref", s_subject, s_field }; |
||
898 | |||
899 | ir_dereference_variable *var_ref = read_var_ref(expr); |
||
900 | if (var_ref != NULL) { |
||
901 | return var_ref; |
||
902 | } else if (MATCH(expr, array_pat)) { |
||
903 | ir_rvalue *subject = read_rvalue(s_subject); |
||
904 | if (subject == NULL) { |
||
905 | ir_read_error(NULL, "when reading the subject of an array_ref"); |
||
906 | return NULL; |
||
907 | } |
||
908 | |||
909 | ir_rvalue *idx = read_rvalue(s_index); |
||
910 | if (idx == NULL) { |
||
911 | ir_read_error(NULL, "when reading the index of an array_ref"); |
||
912 | return NULL; |
||
913 | } |
||
914 | return new(mem_ctx) ir_dereference_array(subject, idx); |
||
915 | } else if (MATCH(expr, record_pat)) { |
||
916 | ir_rvalue *subject = read_rvalue(s_subject); |
||
917 | if (subject == NULL) { |
||
918 | ir_read_error(NULL, "when reading the subject of a record_ref"); |
||
919 | return NULL; |
||
920 | } |
||
921 | return new(mem_ctx) ir_dereference_record(subject, s_field->value()); |
||
922 | } |
||
923 | return NULL; |
||
924 | } |
||
925 | |||
926 | ir_texture * |
||
927 | ir_reader::read_texture(s_expression *expr) |
||
928 | { |
||
929 | s_symbol *tag = NULL; |
||
930 | s_expression *s_type = NULL; |
||
931 | s_expression *s_sampler = NULL; |
||
932 | s_expression *s_coord = NULL; |
||
933 | s_expression *s_offset = NULL; |
||
934 | s_expression *s_proj = NULL; |
||
935 | s_list *s_shadow = NULL; |
||
936 | s_expression *s_lod = NULL; |
||
937 | s_expression *s_sample_index = NULL; |
||
938 | s_expression *s_component = NULL; |
||
939 | |||
940 | ir_texture_opcode op = ir_tex; /* silence warning */ |
||
941 | |||
942 | s_pattern tex_pattern[] = |
||
943 | { "tex", s_type, s_sampler, s_coord, s_offset, s_proj, s_shadow }; |
||
944 | s_pattern lod_pattern[] = |
||
945 | { "lod", s_type, s_sampler, s_coord }; |
||
946 | s_pattern txf_pattern[] = |
||
947 | { "txf", s_type, s_sampler, s_coord, s_offset, s_lod }; |
||
948 | s_pattern txf_ms_pattern[] = |
||
949 | { "txf_ms", s_type, s_sampler, s_coord, s_sample_index }; |
||
950 | s_pattern txs_pattern[] = |
||
951 | { "txs", s_type, s_sampler, s_lod }; |
||
952 | s_pattern tg4_pattern[] = |
||
953 | { "tg4", s_type, s_sampler, s_coord, s_offset, s_component }; |
||
954 | s_pattern query_levels_pattern[] = |
||
955 | { "query_levels", s_type, s_sampler }; |
||
956 | s_pattern other_pattern[] = |
||
957 | { tag, s_type, s_sampler, s_coord, s_offset, s_proj, s_shadow, s_lod }; |
||
958 | |||
959 | if (MATCH(expr, lod_pattern)) { |
||
960 | op = ir_lod; |
||
961 | } else if (MATCH(expr, tex_pattern)) { |
||
962 | op = ir_tex; |
||
963 | } else if (MATCH(expr, txf_pattern)) { |
||
964 | op = ir_txf; |
||
965 | } else if (MATCH(expr, txf_ms_pattern)) { |
||
966 | op = ir_txf_ms; |
||
967 | } else if (MATCH(expr, txs_pattern)) { |
||
968 | op = ir_txs; |
||
969 | } else if (MATCH(expr, tg4_pattern)) { |
||
970 | op = ir_tg4; |
||
971 | } else if (MATCH(expr, query_levels_pattern)) { |
||
972 | op = ir_query_levels; |
||
973 | } else if (MATCH(expr, other_pattern)) { |
||
974 | op = ir_texture::get_opcode(tag->value()); |
||
975 | if (op == (ir_texture_opcode) -1) |
||
976 | return NULL; |
||
977 | } else { |
||
978 | ir_read_error(NULL, "unexpected texture pattern %s", tag->value()); |
||
979 | return NULL; |
||
980 | } |
||
981 | |||
982 | ir_texture *tex = new(mem_ctx) ir_texture(op); |
||
983 | |||
984 | // Read return type |
||
985 | const glsl_type *type = read_type(s_type); |
||
986 | if (type == NULL) { |
||
987 | ir_read_error(NULL, "when reading type in (%s ...)", |
||
988 | tex->opcode_string()); |
||
989 | return NULL; |
||
990 | } |
||
991 | |||
992 | // Read sampler (must be a deref) |
||
993 | ir_dereference *sampler = read_dereference(s_sampler); |
||
994 | if (sampler == NULL) { |
||
995 | ir_read_error(NULL, "when reading sampler in (%s ...)", |
||
996 | tex->opcode_string()); |
||
997 | return NULL; |
||
998 | } |
||
999 | tex->set_sampler(sampler, type); |
||
1000 | |||
1001 | if (op != ir_txs) { |
||
1002 | // Read coordinate (any rvalue) |
||
1003 | tex->coordinate = read_rvalue(s_coord); |
||
1004 | if (tex->coordinate == NULL) { |
||
1005 | ir_read_error(NULL, "when reading coordinate in (%s ...)", |
||
1006 | tex->opcode_string()); |
||
1007 | return NULL; |
||
1008 | } |
||
1009 | |||
1010 | if (op != ir_txf_ms && op != ir_lod) { |
||
1011 | // Read texel offset - either 0 or an rvalue. |
||
1012 | s_int *si_offset = SX_AS_INT(s_offset); |
||
1013 | if (si_offset == NULL || si_offset->value() != 0) { |
||
1014 | tex->offset = read_rvalue(s_offset); |
||
1015 | if (tex->offset == NULL) { |
||
1016 | ir_read_error(s_offset, "expected 0 or an expression"); |
||
1017 | return NULL; |
||
1018 | } |
||
1019 | } |
||
1020 | } |
||
1021 | } |
||
1022 | |||
1023 | if (op != ir_txf && op != ir_txf_ms && |
||
1024 | op != ir_txs && op != ir_lod && op != ir_tg4 && |
||
1025 | op != ir_query_levels) { |
||
1026 | s_int *proj_as_int = SX_AS_INT(s_proj); |
||
1027 | if (proj_as_int && proj_as_int->value() == 1) { |
||
1028 | tex->projector = NULL; |
||
1029 | } else { |
||
1030 | tex->projector = read_rvalue(s_proj); |
||
1031 | if (tex->projector == NULL) { |
||
1032 | ir_read_error(NULL, "when reading projective divide in (%s ..)", |
||
1033 | tex->opcode_string()); |
||
1034 | return NULL; |
||
1035 | } |
||
1036 | } |
||
1037 | |||
1038 | if (s_shadow->subexpressions.is_empty()) { |
||
1039 | tex->shadow_comparitor = NULL; |
||
1040 | } else { |
||
1041 | tex->shadow_comparitor = read_rvalue(s_shadow); |
||
1042 | if (tex->shadow_comparitor == NULL) { |
||
1043 | ir_read_error(NULL, "when reading shadow comparitor in (%s ..)", |
||
1044 | tex->opcode_string()); |
||
1045 | return NULL; |
||
1046 | } |
||
1047 | } |
||
1048 | } |
||
1049 | |||
1050 | switch (op) { |
||
1051 | case ir_txb: |
||
1052 | tex->lod_info.bias = read_rvalue(s_lod); |
||
1053 | if (tex->lod_info.bias == NULL) { |
||
1054 | ir_read_error(NULL, "when reading LOD bias in (txb ...)"); |
||
1055 | return NULL; |
||
1056 | } |
||
1057 | break; |
||
1058 | case ir_txl: |
||
1059 | case ir_txf: |
||
1060 | case ir_txs: |
||
1061 | tex->lod_info.lod = read_rvalue(s_lod); |
||
1062 | if (tex->lod_info.lod == NULL) { |
||
1063 | ir_read_error(NULL, "when reading LOD in (%s ...)", |
||
1064 | tex->opcode_string()); |
||
1065 | return NULL; |
||
1066 | } |
||
1067 | break; |
||
1068 | case ir_txf_ms: |
||
1069 | tex->lod_info.sample_index = read_rvalue(s_sample_index); |
||
1070 | if (tex->lod_info.sample_index == NULL) { |
||
1071 | ir_read_error(NULL, "when reading sample_index in (txf_ms ...)"); |
||
1072 | return NULL; |
||
1073 | } |
||
1074 | break; |
||
1075 | case ir_txd: { |
||
1076 | s_expression *s_dx, *s_dy; |
||
1077 | s_pattern dxdy_pat[] = { s_dx, s_dy }; |
||
1078 | if (!MATCH(s_lod, dxdy_pat)) { |
||
1079 | ir_read_error(s_lod, "expected (dPdx dPdy) in (txd ...)"); |
||
1080 | return NULL; |
||
1081 | } |
||
1082 | tex->lod_info.grad.dPdx = read_rvalue(s_dx); |
||
1083 | if (tex->lod_info.grad.dPdx == NULL) { |
||
1084 | ir_read_error(NULL, "when reading dPdx in (txd ...)"); |
||
1085 | return NULL; |
||
1086 | } |
||
1087 | tex->lod_info.grad.dPdy = read_rvalue(s_dy); |
||
1088 | if (tex->lod_info.grad.dPdy == NULL) { |
||
1089 | ir_read_error(NULL, "when reading dPdy in (txd ...)"); |
||
1090 | return NULL; |
||
1091 | } |
||
1092 | break; |
||
1093 | } |
||
1094 | case ir_tg4: |
||
1095 | tex->lod_info.component = read_rvalue(s_component); |
||
1096 | if (tex->lod_info.component == NULL) { |
||
1097 | ir_read_error(NULL, "when reading component in (tg4 ...)"); |
||
1098 | return NULL; |
||
1099 | } |
||
1100 | break; |
||
1101 | default: |
||
1102 | // tex and lod don't have any extra parameters. |
||
1103 | break; |
||
1104 | }; |
||
1105 | return tex; |
||
1106 | } |
||
1107 | |||
1108 | ir_emit_vertex * |
||
1109 | ir_reader::read_emit_vertex(s_expression *expr) |
||
1110 | { |
||
1111 | s_expression *s_stream = NULL; |
||
1112 | |||
1113 | s_pattern pat[] = { "emit-vertex", s_stream }; |
||
1114 | |||
1115 | if (MATCH(expr, pat)) { |
||
1116 | ir_rvalue *stream = read_dereference(s_stream); |
||
1117 | if (stream == NULL) { |
||
1118 | ir_read_error(NULL, "when reading stream info in emit-vertex"); |
||
1119 | return NULL; |
||
1120 | } |
||
1121 | return new(mem_ctx) ir_emit_vertex(stream); |
||
1122 | } |
||
1123 | ir_read_error(NULL, "when reading emit-vertex"); |
||
1124 | return NULL; |
||
1125 | } |
||
1126 | |||
1127 | ir_end_primitive * |
||
1128 | ir_reader::read_end_primitive(s_expression *expr) |
||
1129 | { |
||
1130 | s_expression *s_stream = NULL; |
||
1131 | |||
1132 | s_pattern pat[] = { "end-primitive", s_stream }; |
||
1133 | |||
1134 | if (MATCH(expr, pat)) { |
||
1135 | ir_rvalue *stream = read_dereference(s_stream); |
||
1136 | if (stream == NULL) { |
||
1137 | ir_read_error(NULL, "when reading stream info in end-primitive"); |
||
1138 | return NULL; |
||
1139 | } |
||
1140 | return new(mem_ctx) ir_end_primitive(stream); |
||
1141 | } |
||
1142 | ir_read_error(NULL, "when reading end-primitive"); |
||
1143 | return NULL; |
||
1144 | }>><>>> |