123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784 |
- /*
- * Copyright © 2008, 2009 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
- #include <stdio.h>
- #include <stdarg.h>
- #include <stdlib.h>
- #include <string.h>
- #include <assert.h>
-
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <unistd.h>
-
- #include "ast.h"
- #include "glsl_parser_extras.h"
- #include "glsl_parser.h"
- #include "ir_constant_folding.h"
- #include "ir_function_inlining.h"
- #include "ir_print_visitor.h"
-
- const char *
- _mesa_glsl_shader_target_name(enum _mesa_glsl_parser_targets target)
- {
- switch (target) {
- case vertex_shader: return "vertex";
- case fragment_shader: return "fragment";
- case geometry_shader: return "geometry";
- }
-
- assert(!"Should not get here.");
- }
-
-
- void
- _mesa_glsl_error(YYLTYPE *locp, _mesa_glsl_parse_state *state,
- const char *fmt, ...)
- {
- char buf[1024];
- int len;
- va_list ap;
-
- state->error = true;
-
- len = snprintf(buf, sizeof(buf), "%u:%u(%u): error: ",
- locp->source, locp->first_line, locp->first_column);
-
- va_start(ap, fmt);
- vsnprintf(buf + len, sizeof(buf) - len, fmt, ap);
- va_end(ap);
-
- printf("%s\n", buf);
- }
-
-
- void
- _mesa_glsl_warning(const YYLTYPE *locp, const _mesa_glsl_parse_state *state,
- const char *fmt, ...)
- {
- char buf[1024];
- int len;
- va_list ap;
-
- len = snprintf(buf, sizeof(buf), "%u:%u(%u): warning: ",
- locp->source, locp->first_line, locp->first_column);
-
- va_start(ap, fmt);
- vsnprintf(buf + len, sizeof(buf) - len, fmt, ap);
- va_end(ap);
-
- printf("%s\n", buf);
- }
-
-
- bool
- _mesa_glsl_process_extension(const char *name, YYLTYPE *name_locp,
- const char *behavior, YYLTYPE *behavior_locp,
- _mesa_glsl_parse_state *state)
- {
- enum {
- extension_disable,
- extension_enable,
- extension_require,
- extension_warn
- } ext_mode;
-
- if (strcmp(behavior, "warn") == 0) {
- ext_mode = extension_warn;
- } else if (strcmp(behavior, "require") == 0) {
- ext_mode = extension_require;
- } else if (strcmp(behavior, "enable") == 0) {
- ext_mode = extension_enable;
- } else if (strcmp(behavior, "disable") == 0) {
- ext_mode = extension_disable;
- } else {
- _mesa_glsl_error(behavior_locp, state,
- "Unknown extension behavior `%s'",
- behavior);
- return false;
- }
-
- bool unsupported = false;
-
- if (strcmp(name, "all") == 0) {
- if ((ext_mode == extension_enable) || (ext_mode == extension_require)) {
- _mesa_glsl_error(name_locp, state, "Cannot %s all extensions",
- (ext_mode == extension_enable)
- ? "enable" : "require");
- return false;
- }
- } if (strcmp(name, "GL_ARB_draw_buffers") == 0) {
- /* This extension is only supported in fragment shaders.
- */
- if (state->target != fragment_shader) {
- unsupported = true;
- } else {
- state->ARB_draw_buffers_enable = (ext_mode != extension_disable);
- state->ARB_draw_buffers_warn = (ext_mode == extension_warn);
- }
- } if (strcmp(name, "GL_ARB_texture_rectangle") == 0) {
- state->ARB_texture_rectangle_enable = (ext_mode != extension_disable);
- state->ARB_texture_rectangle_warn = (ext_mode == extension_warn);
- } else {
- unsupported = true;
- }
-
- if (unsupported) {
- static const char *const fmt = "extension `%s' unsupported in %s shader";
-
- if (ext_mode == extension_require) {
- _mesa_glsl_error(name_locp, state, fmt,
- name, _mesa_glsl_shader_target_name(state->target));
- return false;
- } else {
- _mesa_glsl_warning(name_locp, state, fmt,
- name, _mesa_glsl_shader_target_name(state->target));
- }
- }
-
- return true;
- }
-
-
- ast_node::~ast_node()
- {
- /* empty */
- }
-
-
- void
- _mesa_ast_type_qualifier_print(const struct ast_type_qualifier *q)
- {
- if (q->constant)
- printf("const ");
-
- if (q->invariant)
- printf("invariant ");
-
- if (q->attribute)
- printf("attribute ");
-
- if (q->varying)
- printf("varying ");
-
- if (q->in && q->out)
- printf("inout ");
- else {
- if (q->in)
- printf("in ");
-
- if (q->out)
- printf("out ");
- }
-
- if (q->centroid)
- printf("centroid ");
- if (q->uniform)
- printf("uniform ");
- if (q->smooth)
- printf("smooth ");
- if (q->flat)
- printf("flat ");
- if (q->noperspective)
- printf("noperspective ");
- }
-
-
- void
- ast_node::print(void) const
- {
- printf("unhandled node ");
- }
-
-
- ast_node::ast_node(void)
- {
- make_empty_list(this);
- }
-
-
- static void
- ast_opt_array_size_print(bool is_array, const ast_expression *array_size)
- {
- if (is_array) {
- printf("[ ");
-
- if (array_size)
- array_size->print();
-
- printf("] ");
- }
- }
-
-
- void
- ast_compound_statement::print(void) const
- {
- const struct simple_node *ptr;
-
- printf("{\n");
-
- foreach(ptr, & statements) {
- ((ast_node *)ptr)->print();
- }
-
- printf("}\n");
- }
-
-
- ast_compound_statement::ast_compound_statement(int new_scope,
- ast_node *statements)
- {
- this->new_scope = new_scope;
- make_empty_list(& this->statements);
-
- if (statements != NULL) {
- /* This seems odd, but it works. The simple_list is,
- * basically, a circular list. insert_at_tail adds
- * the specified node to the list before the current
- * head.
- */
- insert_at_tail((struct simple_node *) statements,
- & this->statements);
- }
- }
-
-
- void
- ast_expression::print(void) const
- {
- switch (oper) {
- case ast_assign:
- case ast_mul_assign:
- case ast_div_assign:
- case ast_mod_assign:
- case ast_add_assign:
- case ast_sub_assign:
- case ast_ls_assign:
- case ast_rs_assign:
- case ast_and_assign:
- case ast_xor_assign:
- case ast_or_assign:
- subexpressions[0]->print();
- printf("%s ", operator_string(oper));
- subexpressions[1]->print();
- break;
-
- case ast_field_selection:
- subexpressions[0]->print();
- printf(". %s ", primary_expression.identifier);
- break;
-
- case ast_plus:
- case ast_neg:
- case ast_bit_not:
- case ast_logic_not:
- case ast_pre_inc:
- case ast_pre_dec:
- printf("%s ", operator_string(oper));
- subexpressions[0]->print();
- break;
-
- case ast_post_inc:
- case ast_post_dec:
- subexpressions[0]->print();
- printf("%s ", operator_string(oper));
- break;
-
- case ast_conditional:
- subexpressions[0]->print();
- printf("? ");
- subexpressions[1]->print();
- printf(": ");
- subexpressions[1]->print();
- break;
-
- case ast_array_index:
- subexpressions[0]->print();
- printf("[ ");
- subexpressions[1]->print();
- printf("] ");
- break;
-
- case ast_function_call: {
- ast_expression *parameters = subexpressions[1];
-
- subexpressions[0]->print();
- printf("( ");
-
- if (parameters != NULL) {
- struct simple_node *ptr;
-
- parameters->print();
- foreach (ptr, (struct simple_node *) parameters) {
- printf(", ");
- ((ast_node *)ptr)->print();
- }
- }
-
- printf(") ");
- break;
- }
-
- case ast_identifier:
- printf("%s ", primary_expression.identifier);
- break;
-
- case ast_int_constant:
- printf("%d ", primary_expression.int_constant);
- break;
-
- case ast_uint_constant:
- printf("%u ", primary_expression.uint_constant);
- break;
-
- case ast_float_constant:
- printf("%f ", primary_expression.float_constant);
- break;
-
- case ast_bool_constant:
- printf("%s ",
- primary_expression.bool_constant
- ? "true" : "false");
- break;
-
- case ast_sequence: {
- struct simple_node *ptr;
- struct simple_node *const head = first_elem(& expressions);
-
- printf("( ");
- foreach (ptr, & expressions) {
- if (ptr != head)
- printf(", ");
-
- ((ast_node *)ptr)->print();
- }
- printf(") ");
- break;
- }
-
- default:
- assert(0);
- break;
- }
- }
-
- ast_expression::ast_expression(int oper,
- ast_expression *ex0,
- ast_expression *ex1,
- ast_expression *ex2)
- {
- this->oper = ast_operators(oper);
- this->subexpressions[0] = ex0;
- this->subexpressions[1] = ex1;
- this->subexpressions[2] = ex2;
- make_empty_list(& expressions);
- }
-
-
- void
- ast_expression_statement::print(void) const
- {
- if (expression)
- expression->print();
-
- printf("; ");
- }
-
-
- ast_expression_statement::ast_expression_statement(ast_expression *ex) :
- expression(ex)
- {
- /* empty */
- }
-
-
- void
- ast_function::print(void) const
- {
- struct simple_node *ptr;
-
- return_type->print();
- printf(" %s (", identifier);
-
- foreach(ptr, & parameters) {
- ((ast_node *)ptr)->print();
- }
-
- printf(")");
- }
-
-
- ast_function::ast_function(void)
- : is_definition(false), signature(NULL)
- {
- make_empty_list(& parameters);
- }
-
-
- void
- ast_fully_specified_type::print(void) const
- {
- _mesa_ast_type_qualifier_print(& qualifier);
- specifier->print();
- }
-
-
- void
- ast_parameter_declarator::print(void) const
- {
- type->print();
- if (identifier)
- printf("%s ", identifier);
- ast_opt_array_size_print(is_array, array_size);
- }
-
-
- void
- ast_function_definition::print(void) const
- {
- prototype->print();
- body->print();
- }
-
-
- void
- ast_declaration::print(void) const
- {
- printf("%s ", identifier);
- ast_opt_array_size_print(is_array, array_size);
-
- if (initializer) {
- printf("= ");
- initializer->print();
- }
- }
-
-
- ast_declaration::ast_declaration(char *identifier, int is_array,
- ast_expression *array_size,
- ast_expression *initializer)
- {
- this->identifier = identifier;
- this->is_array = is_array;
- this->array_size = array_size;
- this->initializer = initializer;
- }
-
-
- void
- ast_declarator_list::print(void) const
- {
- struct simple_node *head;
- struct simple_node *ptr;
-
- assert(type || invariant);
-
- if (type)
- type->print();
- else
- printf("invariant ");
-
- head = first_elem(& declarations);
- foreach (ptr, & declarations) {
- if (ptr != head)
- printf(", ");
-
- ((ast_node *)ptr)->print();
- }
-
- printf("; ");
- }
-
-
- ast_declarator_list::ast_declarator_list(ast_fully_specified_type *type)
- {
- this->type = type;
- make_empty_list(& this->declarations);
- }
-
- void
- ast_jump_statement::print(void) const
- {
- switch (mode) {
- case ast_continue:
- printf("continue; ");
- break;
- case ast_break:
- printf("break; ");
- break;
- case ast_return:
- printf("return ");
- if (opt_return_value)
- opt_return_value->print();
-
- printf("; ");
- break;
- case ast_discard:
- printf("discard; ");
- break;
- }
- }
-
-
- ast_jump_statement::ast_jump_statement(int mode, ast_expression *return_value)
- {
- this->mode = ast_jump_modes(mode);
-
- if (mode == ast_return)
- opt_return_value = return_value;
- }
-
-
- void
- ast_selection_statement::print(void) const
- {
- printf("if ( ");
- condition->print();
- printf(") ");
-
- then_statement->print();
-
- if (else_statement) {
- printf("else ");
- else_statement->print();
- }
-
- }
-
-
- ast_selection_statement::ast_selection_statement(ast_expression *condition,
- ast_node *then_statement,
- ast_node *else_statement)
- {
- this->condition = condition;
- this->then_statement = then_statement;
- this->else_statement = else_statement;
- }
-
-
- void
- ast_iteration_statement::print(void) const
- {
- switch (mode) {
- case ast_for:
- printf("for( ");
- if (init_statement)
- init_statement->print();
- printf("; ");
-
- if (condition)
- condition->print();
- printf("; ");
-
- if (rest_expression)
- rest_expression->print();
- printf(") ");
-
- body->print();
- break;
-
- case ast_while:
- printf("while ( ");
- if (condition)
- condition->print();
- printf(") ");
- body->print();
- break;
-
- case ast_do_while:
- printf("do ");
- body->print();
- printf("while ( ");
- if (condition)
- condition->print();
- printf("); ");
- break;
- }
- }
-
-
- ast_iteration_statement::ast_iteration_statement(int mode,
- ast_node *init,
- ast_node *condition,
- ast_expression *rest_expression,
- ast_node *body)
- {
- this->mode = ast_iteration_modes(mode);
- this->init_statement = init;
- this->condition = condition;
- this->rest_expression = rest_expression;
- this->body = body;
- }
-
-
- void
- ast_struct_specifier::print(void) const
- {
- struct simple_node *ptr;
-
- printf("struct %s { ", name);
- foreach (ptr, & declarations) {
- ((ast_node *)ptr)->print();
- }
- printf("} ");
- }
-
-
- ast_struct_specifier::ast_struct_specifier(char *identifier,
- ast_node *declarator_list)
- {
- name = identifier;
-
- /* This seems odd, but it works. The simple_list is,
- * basically, a circular list. insert_at_tail adds
- * the specified node to the list before the current
- * head.
- */
- insert_at_tail((struct simple_node *) declarator_list,
- & declarations);
- }
-
-
- static char *
- load_text_file(const char *file_name, size_t *size)
- {
- char *text = NULL;
- struct stat st;
- ssize_t total_read = 0;
- int fd = open(file_name, O_RDONLY);
-
- *size = 0;
- if (fd < 0) {
- return NULL;
- }
-
- if (fstat(fd, & st) == 0) {
- text = (char *) malloc(st.st_size + 1);
- if (text != NULL) {
- do {
- ssize_t bytes = read(fd, text + total_read,
- st.st_size - total_read);
- if (bytes < 0) {
- free(text);
- text = NULL;
- break;
- }
-
- if (bytes == 0) {
- break;
- }
-
- total_read += bytes;
- } while (total_read < st.st_size);
-
- text[total_read] = '\0';
- *size = total_read;
- }
- }
-
- close(fd);
-
- return text;
- }
-
-
- int
- main(int argc, char **argv)
- {
- struct _mesa_glsl_parse_state state;
- char *shader;
- size_t shader_len;
- struct simple_node *ptr;
- exec_list instructions;
-
- if (argc < 3) {
- printf("Usage: %s [v|g|f] <shader_file>\n", argv[0]);
- return EXIT_FAILURE;
- }
-
- switch (argv[1][0]) {
- case 'v':
- state.target = vertex_shader;
- break;
- case 'g':
- state.target = geometry_shader;
- break;
- case 'f':
- state.target = fragment_shader;
- break;
- default:
- printf("Usage: %s [v|g|f] <shader_file>\n", argv[0]);
- return EXIT_FAILURE;
- }
-
- shader = load_text_file(argv[2], & shader_len);
-
- state.scanner = NULL;
- make_empty_list(& state.translation_unit);
- state.symbols = new glsl_symbol_table;
- state.error = false;
- state.temp_index = 0;
- state.loop_or_switch_nesting = NULL;
- state.ARB_texture_rectangle_enable = true;
-
- _mesa_glsl_lexer_ctor(& state, shader, shader_len);
- _mesa_glsl_parse(& state);
- _mesa_glsl_lexer_dtor(& state);
-
- foreach (ptr, & state.translation_unit) {
- ((ast_node *)ptr)->print();
- }
-
- _mesa_ast_to_hir(&instructions, &state);
-
- /* Optimization passes */
- if (!state.error) {
- bool progress;
- do {
- progress = false;
-
- progress = do_function_inlining(&instructions) || progress;
-
- /* Constant folding */
- ir_constant_folding_visitor constant_folding;
- visit_exec_list(&instructions, &constant_folding);
- } while (progress);
- }
-
- /* Print out the resulting IR */
- printf("\n\n");
-
- if (!state.error) {
- foreach_iter(exec_list_iterator, iter, instructions) {
- ir_print_visitor v;
-
- ((ir_instruction *)iter.get())->accept(& v);
- printf("\n");
- }
- }
-
- delete state.symbols;
-
- return state.error != 0;
- }
|