2010-02-22 13:19:34 -08:00
|
|
|
/*
|
|
|
|
|
* 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 <string.h>
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
2010-06-17 15:15:35 -07:00
|
|
|
extern "C" {
|
2010-10-12 12:26:10 -04:00
|
|
|
#include "main/core.h" /* for struct gl_context */
|
2010-06-17 15:15:35 -07:00
|
|
|
}
|
|
|
|
|
|
2011-01-21 14:32:31 -08:00
|
|
|
#include "ralloc.h"
|
2010-02-22 13:19:34 -08:00
|
|
|
#include "ast.h"
|
|
|
|
|
#include "glsl_parser_extras.h"
|
2010-02-25 17:17:23 -08:00
|
|
|
#include "glsl_parser.h"
|
2010-08-10 13:06:49 -07:00
|
|
|
#include "ir_optimization.h"
|
2010-08-26 16:45:22 -07:00
|
|
|
#include "loop_analysis.h"
|
2010-02-22 13:19:34 -08:00
|
|
|
|
2010-10-12 12:26:10 -04:00
|
|
|
_mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *ctx,
|
2010-07-18 15:59:43 -07:00
|
|
|
GLenum target, void *mem_ctx)
|
|
|
|
|
{
|
|
|
|
|
switch (target) {
|
|
|
|
|
case GL_VERTEX_SHADER: this->target = vertex_shader; break;
|
|
|
|
|
case GL_FRAGMENT_SHADER: this->target = fragment_shader; break;
|
|
|
|
|
case GL_GEOMETRY_SHADER: this->target = geometry_shader; break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->scanner = NULL;
|
|
|
|
|
this->translation_unit.make_empty();
|
|
|
|
|
this->symbols = new(mem_ctx) glsl_symbol_table;
|
2011-01-21 14:32:31 -08:00
|
|
|
this->info_log = ralloc_strdup(mem_ctx, "");
|
2010-07-18 15:59:43 -07:00
|
|
|
this->error = false;
|
|
|
|
|
this->loop_or_switch_nesting = NULL;
|
2010-09-05 00:31:28 -07:00
|
|
|
|
|
|
|
|
/* Set default language version and extensions */
|
|
|
|
|
this->language_version = 110;
|
2010-08-16 12:34:53 -07:00
|
|
|
this->es_shader = false;
|
2010-07-18 15:59:43 -07:00
|
|
|
this->ARB_texture_rectangle_enable = true;
|
|
|
|
|
|
2010-09-08 18:48:12 +08:00
|
|
|
/* OpenGL ES 2.0 has different defaults from desktop GL. */
|
|
|
|
|
if (ctx->API == API_OPENGLES2) {
|
|
|
|
|
this->language_version = 100;
|
|
|
|
|
this->es_shader = true;
|
|
|
|
|
this->ARB_texture_rectangle_enable = false;
|
2010-07-18 15:59:43 -07:00
|
|
|
}
|
2010-09-08 18:48:12 +08:00
|
|
|
|
|
|
|
|
this->extensions = &ctx->Extensions;
|
|
|
|
|
|
|
|
|
|
this->Const.MaxLights = ctx->Const.MaxLights;
|
|
|
|
|
this->Const.MaxClipPlanes = ctx->Const.MaxClipPlanes;
|
|
|
|
|
this->Const.MaxTextureUnits = ctx->Const.MaxTextureUnits;
|
|
|
|
|
this->Const.MaxTextureCoords = ctx->Const.MaxTextureCoordUnits;
|
|
|
|
|
this->Const.MaxVertexAttribs = ctx->Const.VertexProgram.MaxAttribs;
|
|
|
|
|
this->Const.MaxVertexUniformComponents = ctx->Const.VertexProgram.MaxUniformComponents;
|
|
|
|
|
this->Const.MaxVaryingFloats = ctx->Const.MaxVarying * 4;
|
|
|
|
|
this->Const.MaxVertexTextureImageUnits = ctx->Const.MaxVertexTextureImageUnits;
|
|
|
|
|
this->Const.MaxCombinedTextureImageUnits = ctx->Const.MaxCombinedTextureImageUnits;
|
|
|
|
|
this->Const.MaxTextureImageUnits = ctx->Const.MaxTextureImageUnits;
|
|
|
|
|
this->Const.MaxFragmentUniformComponents = ctx->Const.FragmentProgram.MaxUniformComponents;
|
|
|
|
|
|
|
|
|
|
this->Const.MaxDrawBuffers = ctx->Const.MaxDrawBuffers;
|
2011-01-31 15:02:24 -08:00
|
|
|
|
|
|
|
|
/* Note: Once the OpenGL 3.0 'forward compatible' context or the OpenGL 3.2
|
|
|
|
|
* Core context is supported, this logic will need change. Older versions of
|
|
|
|
|
* GLSL are no longer supported outside the compatibility contexts of 3.x.
|
|
|
|
|
*/
|
|
|
|
|
this->Const.GLSL_100ES = (ctx->API == API_OPENGLES2)
|
|
|
|
|
|| ctx->Extensions.ARB_ES2_compatibility;
|
|
|
|
|
this->Const.GLSL_110 = (ctx->API == API_OPENGL);
|
|
|
|
|
this->Const.GLSL_120 = (ctx->API == API_OPENGL)
|
|
|
|
|
&& (ctx->Const.GLSLVersion >= 120);
|
|
|
|
|
this->Const.GLSL_130 = (ctx->API == API_OPENGL)
|
|
|
|
|
&& (ctx->Const.GLSLVersion >= 130);
|
|
|
|
|
|
|
|
|
|
const unsigned lowest_version =
|
|
|
|
|
(ctx->API == API_OPENGLES2) || ctx->Extensions.ARB_ES2_compatibility
|
|
|
|
|
? 100 : 110;
|
|
|
|
|
const unsigned highest_version =
|
|
|
|
|
(ctx->API == API_OPENGL) ? ctx->Const.GLSLVersion : 100;
|
2011-02-01 00:20:01 -08:00
|
|
|
char *supported = ralloc_strdup(this, "");
|
2011-01-31 15:02:24 -08:00
|
|
|
|
|
|
|
|
for (unsigned ver = lowest_version; ver <= highest_version; ver += 10) {
|
|
|
|
|
const char *const prefix = (ver == lowest_version)
|
|
|
|
|
? ""
|
|
|
|
|
: ((ver == highest_version) ? ", and " : ", ");
|
|
|
|
|
|
|
|
|
|
ralloc_asprintf_append(& supported, "%s%d.%02d%s",
|
|
|
|
|
prefix,
|
|
|
|
|
ver / 100, ver % 100,
|
|
|
|
|
(ver == 100) ? " ES" : "");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->supported_version_string = supported;
|
2010-07-18 15:59:43 -07:00
|
|
|
}
|
|
|
|
|
|
2010-04-07 16:44:30 -07:00
|
|
|
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.");
|
2010-07-18 17:47:15 -07:00
|
|
|
return "unknown";
|
2010-04-07 16:44:30 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-02-22 13:19:34 -08:00
|
|
|
void
|
2010-03-11 14:08:33 -08:00
|
|
|
_mesa_glsl_error(YYLTYPE *locp, _mesa_glsl_parse_state *state,
|
|
|
|
|
const char *fmt, ...)
|
2010-02-22 13:19:34 -08:00
|
|
|
{
|
|
|
|
|
va_list ap;
|
|
|
|
|
|
2010-03-23 13:21:19 -07:00
|
|
|
state->error = true;
|
2010-03-11 14:08:33 -08:00
|
|
|
|
2010-06-17 15:15:35 -07:00
|
|
|
assert(state->info_log != NULL);
|
2011-01-21 14:32:31 -08:00
|
|
|
ralloc_asprintf_append(&state->info_log, "%u:%u(%u): error: ",
|
2010-06-17 15:15:35 -07:00
|
|
|
locp->source,
|
|
|
|
|
locp->first_line,
|
|
|
|
|
locp->first_column);
|
2010-02-22 13:19:34 -08:00
|
|
|
va_start(ap, fmt);
|
2011-01-21 14:32:31 -08:00
|
|
|
ralloc_vasprintf_append(&state->info_log, fmt, ap);
|
2010-02-22 13:19:34 -08:00
|
|
|
va_end(ap);
|
2011-01-21 14:32:31 -08:00
|
|
|
ralloc_strcat(&state->info_log, "\n");
|
2010-02-22 13:19:34 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-04-07 14:47:46 -07:00
|
|
|
void
|
2010-04-29 18:00:33 -07:00
|
|
|
_mesa_glsl_warning(const YYLTYPE *locp, _mesa_glsl_parse_state *state,
|
2010-04-07 14:47:46 -07:00
|
|
|
const char *fmt, ...)
|
|
|
|
|
{
|
|
|
|
|
va_list ap;
|
|
|
|
|
|
2010-06-17 15:15:35 -07:00
|
|
|
assert(state->info_log != NULL);
|
2011-01-21 14:32:31 -08:00
|
|
|
ralloc_asprintf_append(&state->info_log, "%u:%u(%u): warning: ",
|
2010-06-17 15:15:35 -07:00
|
|
|
locp->source,
|
|
|
|
|
locp->first_line,
|
|
|
|
|
locp->first_column);
|
2010-04-07 14:47:46 -07:00
|
|
|
va_start(ap, fmt);
|
2011-01-21 14:32:31 -08:00
|
|
|
ralloc_vasprintf_append(&state->info_log, fmt, ap);
|
2010-04-07 14:47:46 -07:00
|
|
|
va_end(ap);
|
2011-01-21 14:32:31 -08:00
|
|
|
ralloc_strcat(&state->info_log, "\n");
|
2010-04-07 14:47:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-04-07 16:46:25 -07:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-07 16:57:56 -07:00
|
|
|
bool unsupported = false;
|
|
|
|
|
|
2010-04-07 16:46:25 -07:00
|
|
|
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;
|
|
|
|
|
}
|
2010-04-23 13:32:23 -07:00
|
|
|
} else if (strcmp(name, "GL_ARB_draw_buffers") == 0) {
|
2010-04-07 16:59:46 -07:00
|
|
|
/* 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);
|
|
|
|
|
}
|
2010-12-08 18:25:38 -07:00
|
|
|
} else if (strcmp(name, "GL_ARB_draw_instanced") == 0) {
|
2011-04-08 12:41:42 -07:00
|
|
|
state->ARB_draw_instanced_enable = (ext_mode != extension_disable);
|
|
|
|
|
state->ARB_draw_instanced_warn = (ext_mode == extension_warn);
|
|
|
|
|
|
2010-12-08 18:25:38 -07:00
|
|
|
/* This extension is only supported in vertex shaders.
|
|
|
|
|
*/
|
2011-04-08 12:41:42 -07:00
|
|
|
unsupported = (state->target != vertex_shader)
|
|
|
|
|
|| !state->extensions->ARB_draw_instanced;
|
2010-10-05 17:00:31 -07:00
|
|
|
} else if (strcmp(name, "GL_ARB_explicit_attrib_location") == 0) {
|
|
|
|
|
state->ARB_explicit_attrib_location_enable =
|
|
|
|
|
(ext_mode != extension_disable);
|
|
|
|
|
state->ARB_explicit_attrib_location_warn =
|
|
|
|
|
(ext_mode == extension_warn);
|
|
|
|
|
|
|
|
|
|
unsupported = !state->extensions->ARB_explicit_attrib_location;
|
2010-06-30 17:30:03 -07:00
|
|
|
} else if (strcmp(name, "GL_ARB_fragment_coord_conventions") == 0) {
|
|
|
|
|
state->ARB_fragment_coord_conventions_enable =
|
|
|
|
|
(ext_mode != extension_disable);
|
|
|
|
|
state->ARB_fragment_coord_conventions_warn =
|
|
|
|
|
(ext_mode == extension_warn);
|
|
|
|
|
|
|
|
|
|
unsupported = !state->extensions->ARB_fragment_coord_conventions;
|
2010-04-23 13:32:23 -07:00
|
|
|
} else if (strcmp(name, "GL_ARB_texture_rectangle") == 0) {
|
2010-04-07 17:13:44 -07:00
|
|
|
state->ARB_texture_rectangle_enable = (ext_mode != extension_disable);
|
|
|
|
|
state->ARB_texture_rectangle_warn = (ext_mode == extension_warn);
|
2010-06-30 16:42:07 -07:00
|
|
|
} else if (strcmp(name, "GL_EXT_texture_array") == 0) {
|
|
|
|
|
state->EXT_texture_array_enable = (ext_mode != extension_disable);
|
|
|
|
|
state->EXT_texture_array_warn = (ext_mode == extension_warn);
|
|
|
|
|
|
|
|
|
|
unsupported = !state->extensions->EXT_texture_array;
|
2010-10-06 09:36:02 +10:00
|
|
|
} else if (strcmp(name, "GL_ARB_shader_stencil_export") == 0) {
|
|
|
|
|
if (state->target != fragment_shader) {
|
|
|
|
|
unsupported = true;
|
|
|
|
|
} else {
|
|
|
|
|
state->ARB_shader_stencil_export_enable = (ext_mode != extension_disable);
|
|
|
|
|
state->ARB_shader_stencil_export_warn = (ext_mode == extension_warn);
|
|
|
|
|
unsupported = !state->extensions->ARB_shader_stencil_export;
|
|
|
|
|
}
|
2011-01-27 01:40:39 -08:00
|
|
|
} else if (strcmp(name, "GL_AMD_conservative_depth") == 0) {
|
|
|
|
|
/* The AMD_conservative spec does not forbid requiring the extension in
|
|
|
|
|
* the vertex shader.
|
|
|
|
|
*/
|
|
|
|
|
state->AMD_conservative_depth_enable = (ext_mode != extension_disable);
|
|
|
|
|
state->AMD_conservative_depth_warn = (ext_mode == extension_warn);
|
|
|
|
|
unsupported = !state->extensions->AMD_conservative_depth;
|
2011-02-25 23:11:20 -08:00
|
|
|
} else if (strcmp(name, "GL_OES_texture_3D") == 0 && state->es_shader) {
|
|
|
|
|
state->OES_texture_3D_enable = (ext_mode != extension_disable);
|
|
|
|
|
state->OES_texture_3D_warn = (ext_mode == extension_warn);
|
|
|
|
|
|
|
|
|
|
unsupported = !state->extensions->EXT_texture3D;
|
2010-04-07 16:46:25 -07:00
|
|
|
} else {
|
2010-04-07 16:57:56 -07:00
|
|
|
unsupported = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (unsupported) {
|
|
|
|
|
static const char *const fmt = "extension `%s' unsupported in %s shader";
|
|
|
|
|
|
2010-04-07 16:46:25 -07:00
|
|
|
if (ext_mode == extension_require) {
|
2010-04-07 16:57:56 -07:00
|
|
|
_mesa_glsl_error(name_locp, state, fmt,
|
|
|
|
|
name, _mesa_glsl_shader_target_name(state->target));
|
2010-04-07 16:46:25 -07:00
|
|
|
return false;
|
2010-04-07 14:50:36 -07:00
|
|
|
} else {
|
2010-04-07 16:57:56 -07:00
|
|
|
_mesa_glsl_warning(name_locp, state, fmt,
|
|
|
|
|
name, _mesa_glsl_shader_target_name(state->target));
|
2010-04-07 16:46:25 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-22 13:19:34 -08:00
|
|
|
void
|
|
|
|
|
_mesa_ast_type_qualifier_print(const struct ast_type_qualifier *q)
|
|
|
|
|
{
|
2010-10-05 16:38:47 -07:00
|
|
|
if (q->flags.q.constant)
|
2010-02-22 13:19:34 -08:00
|
|
|
printf("const ");
|
|
|
|
|
|
2010-10-05 16:38:47 -07:00
|
|
|
if (q->flags.q.invariant)
|
2010-02-22 13:19:34 -08:00
|
|
|
printf("invariant ");
|
|
|
|
|
|
2010-10-05 16:38:47 -07:00
|
|
|
if (q->flags.q.attribute)
|
2010-02-22 13:19:34 -08:00
|
|
|
printf("attribute ");
|
|
|
|
|
|
2010-10-05 16:38:47 -07:00
|
|
|
if (q->flags.q.varying)
|
2010-02-22 13:19:34 -08:00
|
|
|
printf("varying ");
|
|
|
|
|
|
2010-10-05 16:38:47 -07:00
|
|
|
if (q->flags.q.in && q->flags.q.out)
|
2010-02-22 13:19:34 -08:00
|
|
|
printf("inout ");
|
|
|
|
|
else {
|
2010-10-05 16:38:47 -07:00
|
|
|
if (q->flags.q.in)
|
2010-02-22 13:19:34 -08:00
|
|
|
printf("in ");
|
|
|
|
|
|
2010-10-05 16:38:47 -07:00
|
|
|
if (q->flags.q.out)
|
2010-02-22 13:19:34 -08:00
|
|
|
printf("out ");
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-05 16:38:47 -07:00
|
|
|
if (q->flags.q.centroid)
|
2010-02-22 13:19:34 -08:00
|
|
|
printf("centroid ");
|
2010-10-05 16:38:47 -07:00
|
|
|
if (q->flags.q.uniform)
|
2010-02-22 13:19:34 -08:00
|
|
|
printf("uniform ");
|
2010-10-05 16:38:47 -07:00
|
|
|
if (q->flags.q.smooth)
|
2010-02-22 13:19:34 -08:00
|
|
|
printf("smooth ");
|
2010-10-05 16:38:47 -07:00
|
|
|
if (q->flags.q.flat)
|
2010-02-22 13:19:34 -08:00
|
|
|
printf("flat ");
|
2010-10-05 16:38:47 -07:00
|
|
|
if (q->flags.q.noperspective)
|
2010-02-22 13:19:34 -08:00
|
|
|
printf("noperspective ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ast_node::print(void) const
|
|
|
|
|
{
|
2010-04-02 11:03:47 -07:00
|
|
|
printf("unhandled node ");
|
2010-02-22 13:19:34 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ast_node::ast_node(void)
|
|
|
|
|
{
|
2010-07-29 16:39:36 -07:00
|
|
|
this->location.source = 0;
|
|
|
|
|
this->location.line = 0;
|
|
|
|
|
this->location.column = 0;
|
2010-02-22 13:19:34 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
{
|
|
|
|
|
printf("{\n");
|
|
|
|
|
|
2010-05-10 11:17:53 -07:00
|
|
|
foreach_list_const(n, &this->statements) {
|
|
|
|
|
ast_node *ast = exec_node_data(ast_node, n, link);
|
|
|
|
|
ast->print();
|
2010-02-22 13:19:34 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printf("}\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ast_compound_statement::ast_compound_statement(int new_scope,
|
|
|
|
|
ast_node *statements)
|
|
|
|
|
{
|
|
|
|
|
this->new_scope = new_scope;
|
|
|
|
|
|
|
|
|
|
if (statements != NULL) {
|
2010-05-10 11:17:53 -07:00
|
|
|
this->statements.push_degenerate_list_at_head(&statements->link);
|
2010-02-22 13:19:34 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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();
|
2010-02-22 19:10:25 -08:00
|
|
|
printf("%s ", operator_string(oper));
|
2010-02-22 13:19:34 -08:00
|
|
|
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:
|
2010-02-22 19:10:25 -08:00
|
|
|
printf("%s ", operator_string(oper));
|
2010-02-22 13:19:34 -08:00
|
|
|
subexpressions[0]->print();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ast_post_inc:
|
|
|
|
|
case ast_post_dec:
|
|
|
|
|
subexpressions[0]->print();
|
2010-02-22 19:10:25 -08:00
|
|
|
printf("%s ", operator_string(oper));
|
2010-02-22 13:19:34 -08:00
|
|
|
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: {
|
|
|
|
|
subexpressions[0]->print();
|
|
|
|
|
printf("( ");
|
|
|
|
|
|
2010-05-10 11:17:53 -07:00
|
|
|
foreach_list_const (n, &this->expressions) {
|
2010-05-14 16:06:41 -07:00
|
|
|
if (n != this->expressions.get_head())
|
|
|
|
|
printf(", ");
|
2010-05-10 11:17:53 -07:00
|
|
|
|
|
|
|
|
ast_node *ast = exec_node_data(ast_node, n, link);
|
|
|
|
|
ast->print();
|
2010-02-22 13:19:34 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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: {
|
|
|
|
|
printf("( ");
|
2010-05-10 11:17:53 -07:00
|
|
|
foreach_list_const(n, & this->expressions) {
|
|
|
|
|
if (n != this->expressions.get_head())
|
2010-02-22 13:19:34 -08:00
|
|
|
printf(", ");
|
|
|
|
|
|
2010-05-10 11:17:53 -07:00
|
|
|
ast_node *ast = exec_node_data(ast_node, n, link);
|
|
|
|
|
ast->print();
|
2010-02-22 13:19:34 -08:00
|
|
|
}
|
|
|
|
|
printf(") ");
|
|
|
|
|
break;
|
|
|
|
|
}
|
2010-02-22 19:10:25 -08:00
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
break;
|
2010-02-22 13:19:34 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
{
|
|
|
|
|
return_type->print();
|
|
|
|
|
printf(" %s (", identifier);
|
|
|
|
|
|
2010-05-10 11:17:53 -07:00
|
|
|
foreach_list_const(n, & this->parameters) {
|
|
|
|
|
ast_node *ast = exec_node_data(ast_node, n, link);
|
|
|
|
|
ast->print();
|
2010-02-22 13:19:34 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printf(")");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ast_function::ast_function(void)
|
2010-03-31 18:23:21 -07:00
|
|
|
: is_definition(false), signature(NULL)
|
2010-02-22 13:19:34 -08:00
|
|
|
{
|
2010-05-10 11:17:53 -07:00
|
|
|
/* empty */
|
2010-02-22 13:19:34 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
{
|
|
|
|
|
assert(type || invariant);
|
|
|
|
|
|
|
|
|
|
if (type)
|
|
|
|
|
type->print();
|
|
|
|
|
else
|
|
|
|
|
printf("invariant ");
|
|
|
|
|
|
2010-05-10 11:17:53 -07:00
|
|
|
foreach_list_const (ptr, & this->declarations) {
|
|
|
|
|
if (ptr != this->declarations.get_head())
|
2010-02-22 13:19:34 -08:00
|
|
|
printf(", ");
|
|
|
|
|
|
2010-05-10 11:17:53 -07:00
|
|
|
ast_node *ast = exec_node_data(ast_node, ptr, link);
|
|
|
|
|
ast->print();
|
2010-02-22 13:19:34 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printf("; ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ast_declarator_list::ast_declarator_list(ast_fully_specified_type *type)
|
|
|
|
|
{
|
|
|
|
|
this->type = type;
|
2010-07-01 17:10:11 -07:00
|
|
|
this->invariant = false;
|
2010-02-22 13:19:34 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
{
|
|
|
|
|
printf("struct %s { ", name);
|
2010-05-10 11:17:53 -07:00
|
|
|
foreach_list_const(n, &this->declarations) {
|
|
|
|
|
ast_node *ast = exec_node_data(ast_node, n, link);
|
|
|
|
|
ast->print();
|
2010-02-22 13:19:34 -08:00
|
|
|
}
|
|
|
|
|
printf("} ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ast_struct_specifier::ast_struct_specifier(char *identifier,
|
|
|
|
|
ast_node *declarator_list)
|
|
|
|
|
{
|
2010-09-18 11:11:09 +02:00
|
|
|
if (identifier == NULL) {
|
|
|
|
|
static unsigned anon_count = 1;
|
2011-01-21 14:32:31 -08:00
|
|
|
identifier = ralloc_asprintf(this, "#anon_struct_%04x", anon_count);
|
2010-09-18 11:11:09 +02:00
|
|
|
anon_count++;
|
|
|
|
|
}
|
2010-02-22 13:19:34 -08:00
|
|
|
name = identifier;
|
2010-05-10 11:17:53 -07:00
|
|
|
this->declarations.push_degenerate_list_at_head(&declarator_list->link);
|
2010-02-22 13:19:34 -08:00
|
|
|
}
|
2010-08-10 13:06:49 -07:00
|
|
|
|
|
|
|
|
bool
|
2010-09-05 22:29:58 +02:00
|
|
|
do_common_optimization(exec_list *ir, bool linked, unsigned max_unroll_iterations)
|
2010-08-10 13:06:49 -07:00
|
|
|
{
|
|
|
|
|
GLboolean progress = GL_FALSE;
|
|
|
|
|
|
2010-11-18 17:54:07 -08:00
|
|
|
progress = lower_instructions(ir, SUB_TO_ADD_NEG) || progress;
|
2010-08-10 13:06:49 -07:00
|
|
|
|
|
|
|
|
if (linked) {
|
|
|
|
|
progress = do_function_inlining(ir) || progress;
|
|
|
|
|
progress = do_dead_functions(ir) || progress;
|
|
|
|
|
}
|
|
|
|
|
progress = do_structure_splitting(ir) || progress;
|
|
|
|
|
progress = do_if_simplification(ir) || progress;
|
2010-11-24 22:02:26 -08:00
|
|
|
progress = do_discard_simplification(ir) || progress;
|
2010-08-10 13:06:49 -07:00
|
|
|
progress = do_copy_propagation(ir) || progress;
|
2011-02-07 23:27:03 -08:00
|
|
|
/*progress = do_copy_propagation_elements(ir) || progress;*/
|
2010-08-10 13:06:49 -07:00
|
|
|
if (linked)
|
|
|
|
|
progress = do_dead_code(ir) || progress;
|
|
|
|
|
else
|
|
|
|
|
progress = do_dead_code_unlinked(ir) || progress;
|
|
|
|
|
progress = do_dead_code_local(ir) || progress;
|
|
|
|
|
progress = do_tree_grafting(ir) || progress;
|
|
|
|
|
progress = do_constant_propagation(ir) || progress;
|
|
|
|
|
if (linked)
|
|
|
|
|
progress = do_constant_variable(ir) || progress;
|
|
|
|
|
else
|
|
|
|
|
progress = do_constant_variable_unlinked(ir) || progress;
|
|
|
|
|
progress = do_constant_folding(ir) || progress;
|
|
|
|
|
progress = do_algebraic(ir) || progress;
|
glsl: add continue/break/return unification/elimination pass (v2)
Changes in v2:
- Base class renamed to ir_control_flow_visitor
- Tried to comply with coding style
This is a new pass that supersedes ir_if_return and "lowers" jumps
to if/else structures.
Currently it causes no regressions on softpipe and nv40, but I'm not sure
whether the piglit glsl tests are thorough enough, so consider this
experimental.
It can be asked to:
1. Pull jumps out of ifs where possible
2. Remove all "continue"s, replacing them with an "execute flag"
3. Replace all "break" with a single conditional one at the end of the loop
4. Replace all "return"s with a single return at the end of the function,
for the main function and/or other functions
This gives several great benefits:
1. All functions can be inlined after this pass
2. nv40 and other pre-DX10 chips without "continue" can be supported
3. nv30 and other pre-DX10 chips with no control flow at all are better supported
Note that for full effect we should also teach the unroller to unroll
loops with a fixed maximum number of iterations but with the canonical
conditional "break" that this pass will insert if asked to.
Continues are lowered by adding a per-loop "execute flag", initialized to
TRUE, that when cleared inhibits all execution until the end of the loop.
Breaks are lowered to continues, plus setting a "break flag" that is checked
at the end of the loop, and trigger the unique "break".
Returns are lowered to breaks/continues, plus adding a "return flag" that
causes loops to break again out of their enclosing loops until all the
loops are exited: then the "execute flag" logic will ignore everything
until the end of the function.
Note that "continue" and "return" can also be implemented by adding
a dummy loop and using break.
However, this is bad for hardware with limited nesting depth, and
prevents further optimization, and thus is not currently performed.
2010-09-07 00:24:08 +02:00
|
|
|
progress = do_lower_jumps(ir) || progress;
|
2010-08-10 13:06:49 -07:00
|
|
|
progress = do_vec_index_to_swizzle(ir) || progress;
|
|
|
|
|
progress = do_swizzle_swizzle(ir) || progress;
|
2010-08-13 07:16:38 -07:00
|
|
|
progress = do_noop_swizzle(ir) || progress;
|
2010-08-10 13:06:49 -07:00
|
|
|
|
2010-09-13 14:25:26 -07:00
|
|
|
progress = optimize_redundant_jumps(ir) || progress;
|
|
|
|
|
|
2010-08-26 16:45:22 -07:00
|
|
|
loop_state *ls = analyze_loop_variables(ir);
|
2011-01-17 22:07:55 -08:00
|
|
|
if (ls->loop_found) {
|
|
|
|
|
progress = set_loop_controls(ir, ls) || progress;
|
|
|
|
|
progress = unroll_loops(ir, ls, max_unroll_iterations) || progress;
|
|
|
|
|
}
|
2010-08-26 16:45:22 -07:00
|
|
|
delete ls;
|
|
|
|
|
|
2010-08-10 13:06:49 -07:00
|
|
|
return progress;
|
|
|
|
|
}
|
2010-08-18 16:56:39 -07:00
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* To be called at GL teardown time, this frees compiler datastructures.
|
|
|
|
|
*
|
|
|
|
|
* After calling this, any previously compiled shaders and shader
|
|
|
|
|
* programs would be invalid. So this should happen at approximately
|
|
|
|
|
* program exit.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
_mesa_destroy_shader_compiler(void)
|
|
|
|
|
{
|
|
|
|
|
_mesa_destroy_shader_compiler_caches();
|
|
|
|
|
|
|
|
|
|
_mesa_glsl_release_types();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Releases compiler caches to trade off performance for memory.
|
|
|
|
|
*
|
|
|
|
|
* Intended to be used with glReleaseShaderCompiler().
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
_mesa_destroy_shader_compiler_caches(void)
|
|
|
|
|
{
|
|
|
|
|
_mesa_glsl_release_functions();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|