blob: 8beea55573add74f5ff6bfbb0ba79cd6eba3f7cc [file] [log] [blame]
Ian Romanicka87ac252010-02-22 13:19:34 -08001/*
2 * Copyright © 2008, 2009 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 <stdarg.h>
25#include <stdlib.h>
26#include <string.h>
27#include <assert.h>
28
29#include <sys/types.h>
30#include <sys/stat.h>
31#include <fcntl.h>
32#include <unistd.h>
33
34#include "ast.h"
35#include "glsl_parser_extras.h"
Ian Romanickd59673c2010-02-25 17:17:23 -080036#include "glsl_parser.h"
Eric Anholt62735692010-04-05 15:24:28 -070037#include "ir_constant_folding.h"
Ian Romanick1c4156f2010-03-10 09:27:03 -080038#include "ir_print_visitor.h"
Ian Romanicka87ac252010-02-22 13:19:34 -080039
Ian Romanick5bfe30a2010-04-07 16:44:30 -070040const char *
41_mesa_glsl_shader_target_name(enum _mesa_glsl_parser_targets target)
42{
43 switch (target) {
44 case vertex_shader: return "vertex";
45 case fragment_shader: return "fragment";
46 case geometry_shader: return "geometry";
47 }
48
49 assert(!"Should not get here.");
50}
51
52
Ian Romanicka87ac252010-02-22 13:19:34 -080053void
Ian Romanick1f585182010-03-11 14:08:33 -080054_mesa_glsl_error(YYLTYPE *locp, _mesa_glsl_parse_state *state,
55 const char *fmt, ...)
Ian Romanicka87ac252010-02-22 13:19:34 -080056{
57 char buf[1024];
58 int len;
59 va_list ap;
60
Ian Romanick71d0bbf2010-03-23 13:21:19 -070061 state->error = true;
Ian Romanick1f585182010-03-11 14:08:33 -080062
Ian Romanicka87ac252010-02-22 13:19:34 -080063 len = snprintf(buf, sizeof(buf), "%u:%u(%u): error: ",
64 locp->source, locp->first_line, locp->first_column);
65
66 va_start(ap, fmt);
67 vsnprintf(buf + len, sizeof(buf) - len, fmt, ap);
68 va_end(ap);
69
70 printf("%s\n", buf);
71}
72
73
Ian Romanick56b8b212010-04-07 14:47:46 -070074void
75_mesa_glsl_warning(const YYLTYPE *locp, const _mesa_glsl_parse_state *state,
76 const char *fmt, ...)
77{
78 char buf[1024];
79 int len;
80 va_list ap;
81
82 len = snprintf(buf, sizeof(buf), "%u:%u(%u): warning: ",
83 locp->source, locp->first_line, locp->first_column);
84
85 va_start(ap, fmt);
86 vsnprintf(buf + len, sizeof(buf) - len, fmt, ap);
87 va_end(ap);
88
89 printf("%s\n", buf);
90}
91
92
Ian Romanicke7017612010-04-07 16:46:25 -070093bool
94_mesa_glsl_process_extension(const char *name, YYLTYPE *name_locp,
95 const char *behavior, YYLTYPE *behavior_locp,
96 _mesa_glsl_parse_state *state)
97{
98 enum {
99 extension_disable,
100 extension_enable,
101 extension_require,
102 extension_warn
103 } ext_mode;
104 bool error = false;
105
106 if (strcmp(behavior, "warn") == 0) {
107 ext_mode = extension_warn;
108 } else if (strcmp(behavior, "require") == 0) {
109 ext_mode = extension_require;
110 } else if (strcmp(behavior, "enable") == 0) {
111 ext_mode = extension_enable;
112 } else if (strcmp(behavior, "disable") == 0) {
113 ext_mode = extension_disable;
114 } else {
115 _mesa_glsl_error(behavior_locp, state,
116 "Unknown extension behavior `%s'",
117 behavior);
118 return false;
119 }
120
121 if (strcmp(name, "all") == 0) {
122 if ((ext_mode == extension_enable) || (ext_mode == extension_require)) {
123 _mesa_glsl_error(name_locp, state, "Cannot %s all extensions",
124 (ext_mode == extension_enable)
125 ? "enable" : "require");
126 return false;
127 }
128 } else {
129 if (ext_mode == extension_require) {
130 _mesa_glsl_error(name_locp, state, "Unknown extension `%s'",
131 name);
132 return false;
Ian Romanick1799a0c2010-04-07 14:50:36 -0700133 } else {
134 _mesa_glsl_warning(name_locp, state, "Unknown extension `%s'",
135 name);
Ian Romanicke7017612010-04-07 16:46:25 -0700136 }
137 }
138
139 return true;
140}
141
142
Ian Romanicka87ac252010-02-22 13:19:34 -0800143ast_node::~ast_node()
144{
145 /* empty */
146}
147
148
149void
150_mesa_ast_type_qualifier_print(const struct ast_type_qualifier *q)
151{
152 if (q->constant)
153 printf("const ");
154
155 if (q->invariant)
156 printf("invariant ");
157
158 if (q->attribute)
159 printf("attribute ");
160
161 if (q->varying)
162 printf("varying ");
163
164 if (q->in && q->out)
165 printf("inout ");
166 else {
167 if (q->in)
168 printf("in ");
169
170 if (q->out)
171 printf("out ");
172 }
173
174 if (q->centroid)
175 printf("centroid ");
176 if (q->uniform)
177 printf("uniform ");
178 if (q->smooth)
179 printf("smooth ");
180 if (q->flat)
181 printf("flat ");
182 if (q->noperspective)
183 printf("noperspective ");
184}
185
186
187void
188ast_node::print(void) const
189{
Ian Romanick03d3f3a2010-04-02 11:03:47 -0700190 printf("unhandled node ");
Ian Romanicka87ac252010-02-22 13:19:34 -0800191}
192
193
194ast_node::ast_node(void)
195{
Ian Romanick53d27742010-02-22 13:22:10 -0800196 make_empty_list(this);
Ian Romanicka87ac252010-02-22 13:19:34 -0800197}
198
Ian Romanicka87ac252010-02-22 13:19:34 -0800199
200static void
201ast_opt_array_size_print(bool is_array, const ast_expression *array_size)
202{
203 if (is_array) {
204 printf("[ ");
205
206 if (array_size)
207 array_size->print();
208
209 printf("] ");
210 }
211}
212
213
Ian Romanicka87ac252010-02-22 13:19:34 -0800214void
215ast_compound_statement::print(void) const
216{
217 const struct simple_node *ptr;
218
219 printf("{\n");
220
221 foreach(ptr, & statements) {
Ian Romanicke41a1cd2010-02-25 12:49:55 -0800222 ((ast_node *)ptr)->print();
Ian Romanicka87ac252010-02-22 13:19:34 -0800223 }
224
225 printf("}\n");
226}
227
228
229ast_compound_statement::ast_compound_statement(int new_scope,
230 ast_node *statements)
231{
232 this->new_scope = new_scope;
233 make_empty_list(& this->statements);
234
235 if (statements != NULL) {
236 /* This seems odd, but it works. The simple_list is,
237 * basically, a circular list. insert_at_tail adds
238 * the specified node to the list before the current
239 * head.
240 */
241 insert_at_tail((struct simple_node *) statements,
242 & this->statements);
243 }
244}
245
246
247void
248ast_expression::print(void) const
249{
Ian Romanicka87ac252010-02-22 13:19:34 -0800250 switch (oper) {
251 case ast_assign:
Ian Romanicka87ac252010-02-22 13:19:34 -0800252 case ast_mul_assign:
253 case ast_div_assign:
254 case ast_mod_assign:
255 case ast_add_assign:
256 case ast_sub_assign:
257 case ast_ls_assign:
258 case ast_rs_assign:
259 case ast_and_assign:
260 case ast_xor_assign:
261 case ast_or_assign:
262 subexpressions[0]->print();
Ian Romanick88349b22010-02-22 19:10:25 -0800263 printf("%s ", operator_string(oper));
Ian Romanicka87ac252010-02-22 13:19:34 -0800264 subexpressions[1]->print();
265 break;
266
267 case ast_field_selection:
268 subexpressions[0]->print();
269 printf(". %s ", primary_expression.identifier);
270 break;
271
272 case ast_plus:
273 case ast_neg:
274 case ast_bit_not:
275 case ast_logic_not:
276 case ast_pre_inc:
277 case ast_pre_dec:
Ian Romanick88349b22010-02-22 19:10:25 -0800278 printf("%s ", operator_string(oper));
Ian Romanicka87ac252010-02-22 13:19:34 -0800279 subexpressions[0]->print();
280 break;
281
282 case ast_post_inc:
283 case ast_post_dec:
284 subexpressions[0]->print();
Ian Romanick88349b22010-02-22 19:10:25 -0800285 printf("%s ", operator_string(oper));
Ian Romanicka87ac252010-02-22 13:19:34 -0800286 break;
287
288 case ast_conditional:
289 subexpressions[0]->print();
290 printf("? ");
291 subexpressions[1]->print();
292 printf(": ");
293 subexpressions[1]->print();
294 break;
295
296 case ast_array_index:
297 subexpressions[0]->print();
298 printf("[ ");
299 subexpressions[1]->print();
300 printf("] ");
301 break;
302
303 case ast_function_call: {
304 ast_expression *parameters = subexpressions[1];
305
306 subexpressions[0]->print();
307 printf("( ");
308
309 if (parameters != NULL) {
310 struct simple_node *ptr;
311
312 parameters->print();
313 foreach (ptr, (struct simple_node *) parameters) {
314 printf(", ");
Ian Romanicke41a1cd2010-02-25 12:49:55 -0800315 ((ast_node *)ptr)->print();
Ian Romanicka87ac252010-02-22 13:19:34 -0800316 }
317 }
318
319 printf(") ");
320 break;
321 }
322
323 case ast_identifier:
324 printf("%s ", primary_expression.identifier);
325 break;
326
327 case ast_int_constant:
328 printf("%d ", primary_expression.int_constant);
329 break;
330
331 case ast_uint_constant:
332 printf("%u ", primary_expression.uint_constant);
333 break;
334
335 case ast_float_constant:
336 printf("%f ", primary_expression.float_constant);
337 break;
338
339 case ast_bool_constant:
340 printf("%s ",
341 primary_expression.bool_constant
342 ? "true" : "false");
343 break;
344
345 case ast_sequence: {
346 struct simple_node *ptr;
347 struct simple_node *const head = first_elem(& expressions);
348
349 printf("( ");
350 foreach (ptr, & expressions) {
351 if (ptr != head)
352 printf(", ");
353
Ian Romanicke41a1cd2010-02-25 12:49:55 -0800354 ((ast_node *)ptr)->print();
Ian Romanicka87ac252010-02-22 13:19:34 -0800355 }
356 printf(") ");
357 break;
358 }
Ian Romanick88349b22010-02-22 19:10:25 -0800359
360 default:
361 assert(0);
362 break;
Ian Romanicka87ac252010-02-22 13:19:34 -0800363 }
364}
365
366ast_expression::ast_expression(int oper,
367 ast_expression *ex0,
368 ast_expression *ex1,
369 ast_expression *ex2)
370{
371 this->oper = ast_operators(oper);
372 this->subexpressions[0] = ex0;
373 this->subexpressions[1] = ex1;
374 this->subexpressions[2] = ex2;
375 make_empty_list(& expressions);
376}
377
378
379void
380ast_expression_statement::print(void) const
381{
382 if (expression)
383 expression->print();
384
385 printf("; ");
386}
387
388
389ast_expression_statement::ast_expression_statement(ast_expression *ex) :
390 expression(ex)
391{
392 /* empty */
393}
394
395
396void
397ast_function::print(void) const
398{
399 struct simple_node *ptr;
400
401 return_type->print();
402 printf(" %s (", identifier);
403
404 foreach(ptr, & parameters) {
Ian Romanicke41a1cd2010-02-25 12:49:55 -0800405 ((ast_node *)ptr)->print();
Ian Romanicka87ac252010-02-22 13:19:34 -0800406 }
407
408 printf(")");
409}
410
411
412ast_function::ast_function(void)
Ian Romanick92318a92010-03-31 18:23:21 -0700413 : is_definition(false), signature(NULL)
Ian Romanicka87ac252010-02-22 13:19:34 -0800414{
415 make_empty_list(& parameters);
416}
417
418
419void
420ast_fully_specified_type::print(void) const
421{
422 _mesa_ast_type_qualifier_print(& qualifier);
423 specifier->print();
424}
425
426
427void
428ast_parameter_declarator::print(void) const
429{
430 type->print();
431 if (identifier)
432 printf("%s ", identifier);
433 ast_opt_array_size_print(is_array, array_size);
434}
435
436
437void
438ast_function_definition::print(void) const
439{
440 prototype->print();
441 body->print();
442}
443
444
445void
446ast_declaration::print(void) const
447{
448 printf("%s ", identifier);
449 ast_opt_array_size_print(is_array, array_size);
450
451 if (initializer) {
452 printf("= ");
453 initializer->print();
454 }
455}
456
457
458ast_declaration::ast_declaration(char *identifier, int is_array,
459 ast_expression *array_size,
460 ast_expression *initializer)
461{
462 this->identifier = identifier;
463 this->is_array = is_array;
464 this->array_size = array_size;
465 this->initializer = initializer;
466}
467
468
469void
470ast_declarator_list::print(void) const
471{
472 struct simple_node *head;
473 struct simple_node *ptr;
474
475 assert(type || invariant);
476
477 if (type)
478 type->print();
479 else
480 printf("invariant ");
481
482 head = first_elem(& declarations);
483 foreach (ptr, & declarations) {
484 if (ptr != head)
485 printf(", ");
486
Ian Romanicke41a1cd2010-02-25 12:49:55 -0800487 ((ast_node *)ptr)->print();
Ian Romanicka87ac252010-02-22 13:19:34 -0800488 }
489
490 printf("; ");
491}
492
493
494ast_declarator_list::ast_declarator_list(ast_fully_specified_type *type)
495{
496 this->type = type;
497 make_empty_list(& this->declarations);
498}
499
500void
501ast_jump_statement::print(void) const
502{
503 switch (mode) {
504 case ast_continue:
505 printf("continue; ");
506 break;
507 case ast_break:
508 printf("break; ");
509 break;
510 case ast_return:
511 printf("return ");
512 if (opt_return_value)
513 opt_return_value->print();
514
515 printf("; ");
516 break;
517 case ast_discard:
518 printf("discard; ");
519 break;
520 }
521}
522
523
524ast_jump_statement::ast_jump_statement(int mode, ast_expression *return_value)
525{
526 this->mode = ast_jump_modes(mode);
527
528 if (mode == ast_return)
529 opt_return_value = return_value;
530}
531
532
533void
534ast_selection_statement::print(void) const
535{
536 printf("if ( ");
537 condition->print();
538 printf(") ");
539
540 then_statement->print();
541
542 if (else_statement) {
543 printf("else ");
544 else_statement->print();
545 }
546
547}
548
549
550ast_selection_statement::ast_selection_statement(ast_expression *condition,
551 ast_node *then_statement,
552 ast_node *else_statement)
553{
554 this->condition = condition;
555 this->then_statement = then_statement;
556 this->else_statement = else_statement;
557}
558
559
560void
561ast_iteration_statement::print(void) const
562{
563 switch (mode) {
564 case ast_for:
565 printf("for( ");
566 if (init_statement)
567 init_statement->print();
568 printf("; ");
569
570 if (condition)
571 condition->print();
572 printf("; ");
573
574 if (rest_expression)
575 rest_expression->print();
576 printf(") ");
577
578 body->print();
579 break;
580
581 case ast_while:
582 printf("while ( ");
583 if (condition)
584 condition->print();
585 printf(") ");
586 body->print();
587 break;
588
589 case ast_do_while:
590 printf("do ");
591 body->print();
592 printf("while ( ");
593 if (condition)
594 condition->print();
595 printf("); ");
596 break;
597 }
598}
599
600
601ast_iteration_statement::ast_iteration_statement(int mode,
602 ast_node *init,
603 ast_node *condition,
604 ast_expression *rest_expression,
605 ast_node *body)
606{
607 this->mode = ast_iteration_modes(mode);
608 this->init_statement = init;
609 this->condition = condition;
610 this->rest_expression = rest_expression;
611 this->body = body;
612}
613
614
615void
616ast_struct_specifier::print(void) const
617{
618 struct simple_node *ptr;
619
620 printf("struct %s { ", name);
621 foreach (ptr, & declarations) {
Ian Romanicke41a1cd2010-02-25 12:49:55 -0800622 ((ast_node *)ptr)->print();
Ian Romanicka87ac252010-02-22 13:19:34 -0800623 }
624 printf("} ");
625}
626
627
628ast_struct_specifier::ast_struct_specifier(char *identifier,
629 ast_node *declarator_list)
630{
631 name = identifier;
632
633 /* This seems odd, but it works. The simple_list is,
634 * basically, a circular list. insert_at_tail adds
635 * the specified node to the list before the current
636 * head.
637 */
638 insert_at_tail((struct simple_node *) declarator_list,
639 & declarations);
640}
641
642
643static char *
644load_text_file(const char *file_name, size_t *size)
645{
646 char *text = NULL;
647 struct stat st;
648 ssize_t total_read = 0;
649 int fd = open(file_name, O_RDONLY);
650
651 *size = 0;
652 if (fd < 0) {
653 return NULL;
654 }
655
656 if (fstat(fd, & st) == 0) {
657 text = (char *) malloc(st.st_size + 1);
658 if (text != NULL) {
659 do {
660 ssize_t bytes = read(fd, text + total_read,
661 st.st_size - total_read);
662 if (bytes < 0) {
663 free(text);
664 text = NULL;
665 break;
666 }
667
668 if (bytes == 0) {
669 break;
670 }
671
672 total_read += bytes;
673 } while (total_read < st.st_size);
674
675 text[total_read] = '\0';
676 *size = total_read;
677 }
678 }
679
680 close(fd);
681
682 return text;
683}
684
685
686int
687main(int argc, char **argv)
688{
689 struct _mesa_glsl_parse_state state;
690 char *shader;
691 size_t shader_len;
692 struct simple_node *ptr;
Ian Romanick0044e7e2010-03-08 23:44:00 -0800693 exec_list instructions;
Ian Romanicka87ac252010-02-22 13:19:34 -0800694
Ian Romanick8e6cd3b2010-03-10 09:31:30 -0800695 if (argc < 3) {
696 printf("Usage: %s [v|g|f] <shader_file>\n", argv[0]);
697 return EXIT_FAILURE;
698 }
699
700 switch (argv[1][0]) {
701 case 'v':
702 state.target = vertex_shader;
703 break;
704 case 'g':
705 state.target = geometry_shader;
706 break;
707 case 'f':
708 state.target = fragment_shader;
709 break;
710 default:
711 printf("Usage: %s [v|g|f] <shader_file>\n", argv[0]);
712 return EXIT_FAILURE;
713 }
714
715 shader = load_text_file(argv[2], & shader_len);
Ian Romanicka87ac252010-02-22 13:19:34 -0800716
717 state.scanner = NULL;
718 make_empty_list(& state.translation_unit);
Ian Romanick8bde4ce2010-03-19 11:57:24 -0700719 state.symbols = new glsl_symbol_table;
Ian Romanick1f585182010-03-11 14:08:33 -0800720 state.error = false;
Ian Romanick5185a5f2010-03-29 15:20:42 -0700721 state.temp_index = 0;
Ian Romanicke9d0f262010-04-05 17:01:53 -0700722 state.loop_or_switch_nesting = NULL;
Ian Romanicka87ac252010-02-22 13:19:34 -0800723
724 _mesa_glsl_lexer_ctor(& state, shader, shader_len);
725 _mesa_glsl_parse(& state);
726 _mesa_glsl_lexer_dtor(& state);
727
728 foreach (ptr, & state.translation_unit) {
Ian Romanicke41a1cd2010-02-25 12:49:55 -0800729 ((ast_node *)ptr)->print();
Ian Romanicka87ac252010-02-22 13:19:34 -0800730 }
731
Ian Romanickd949a9a2010-03-10 09:55:22 -0800732 _mesa_ast_to_hir(&instructions, &state);
Ian Romanicka87ac252010-02-22 13:19:34 -0800733
Eric Anholt62735692010-04-05 15:24:28 -0700734 /* Optimization passes */
735 if (!state.error) {
736 /* Constant folding */
Eric Anholt70b74922010-04-06 11:52:09 -0700737 ir_constant_folding_visitor constant_folding;
738 visit_exec_list(&instructions, &constant_folding);
Eric Anholt62735692010-04-05 15:24:28 -0700739 }
740
741 /* Print out the resulting IR */
Ian Romanick1c4156f2010-03-10 09:27:03 -0800742 printf("\n\n");
Ian Romanick1c4156f2010-03-10 09:27:03 -0800743
Ian Romanick1f585182010-03-11 14:08:33 -0800744 if (!state.error) {
745 foreach_iter(exec_list_iterator, iter, instructions) {
746 ir_print_visitor v;
747
748 ((ir_instruction *)iter.get())->accept(& v);
Ian Romanickd1464272010-03-25 18:29:25 -0700749 printf("\n");
Ian Romanick1f585182010-03-11 14:08:33 -0800750 }
Ian Romanick1c4156f2010-03-10 09:27:03 -0800751 }
752
Ian Romanick8bde4ce2010-03-19 11:57:24 -0700753 delete state.symbols;
Ian Romanicka87ac252010-02-22 13:19:34 -0800754
Eric Anholt7c15bb22010-03-25 14:37:25 -0700755 return state.error != 0;
Ian Romanicka87ac252010-02-22 13:19:34 -0800756}