2010-03-15 20:04:13 +00:00
|
|
|
/*
|
|
|
|
* Copyright © 2010 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.
|
|
|
|
*/
|
|
|
|
|
2010-03-19 18:57:24 +00:00
|
|
|
#include "glsl_symbol_table.h"
|
2010-03-15 20:04:13 +00:00
|
|
|
#include "ast.h"
|
|
|
|
#include "glsl_types.h"
|
|
|
|
#include "ir.h"
|
2010-08-23 10:51:42 +01:00
|
|
|
#include "main/core.h" /* for MIN2 */
|
2010-06-26 00:10:43 +01:00
|
|
|
|
2010-07-14 21:22:07 +01:00
|
|
|
static ir_rvalue *
|
|
|
|
convert_component(ir_rvalue *src, const glsl_type *desired_type);
|
|
|
|
|
2010-09-02 04:03:17 +01:00
|
|
|
bool
|
|
|
|
apply_implicit_conversion(const glsl_type *to, ir_rvalue * &from,
|
|
|
|
struct _mesa_glsl_parse_state *state);
|
|
|
|
|
2010-04-01 00:28:51 +01:00
|
|
|
static unsigned
|
|
|
|
process_parameters(exec_list *instructions, exec_list *actual_parameters,
|
2010-05-10 19:17:53 +01:00
|
|
|
exec_list *parameters,
|
2010-04-01 00:28:51 +01:00
|
|
|
struct _mesa_glsl_parse_state *state)
|
2010-03-15 20:26:02 +00:00
|
|
|
{
|
2010-04-01 00:28:51 +01:00
|
|
|
unsigned count = 0;
|
|
|
|
|
2014-06-25 06:02:24 +01:00
|
|
|
foreach_list_typed(ast_node, ast, link, parameters) {
|
2010-06-10 01:31:02 +01:00
|
|
|
ir_rvalue *result = ast->hir(instructions, state);
|
|
|
|
|
|
|
|
ir_constant *const constant = result->constant_expression_value();
|
|
|
|
if (constant != NULL)
|
|
|
|
result = constant;
|
2010-03-15 20:26:02 +00:00
|
|
|
|
2010-05-10 18:47:14 +01:00
|
|
|
actual_parameters->push_tail(result);
|
|
|
|
count++;
|
2010-03-15 20:26:02 +00:00
|
|
|
}
|
|
|
|
|
2010-04-01 00:28:51 +01:00
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-08-06 01:21:39 +01:00
|
|
|
/**
|
|
|
|
* Generate a source prototype for a function signature
|
|
|
|
*
|
|
|
|
* \param return_type Return type of the function. May be \c NULL.
|
|
|
|
* \param name Name of the function.
|
2011-07-08 18:34:38 +01:00
|
|
|
* \param parameters List of \c ir_instruction nodes representing the
|
|
|
|
* parameter list for the function. This may be either a
|
|
|
|
* formal (\c ir_variable) or actual (\c ir_rvalue)
|
|
|
|
* parameter list. Only the type is used.
|
2010-08-06 01:21:39 +01:00
|
|
|
*
|
|
|
|
* \return
|
2011-01-21 22:32:31 +00:00
|
|
|
* A ralloced string representing the prototype of the function.
|
2010-08-06 01:21:39 +01:00
|
|
|
*/
|
|
|
|
char *
|
|
|
|
prototype_string(const glsl_type *return_type, const char *name,
|
|
|
|
exec_list *parameters)
|
|
|
|
{
|
|
|
|
char *str = NULL;
|
|
|
|
|
|
|
|
if (return_type != NULL)
|
2011-02-02 07:31:35 +00:00
|
|
|
str = ralloc_asprintf(NULL, "%s ", return_type->name);
|
2010-08-06 01:21:39 +01:00
|
|
|
|
2011-01-21 22:32:31 +00:00
|
|
|
ralloc_asprintf_append(&str, "%s(", name);
|
2010-08-06 01:21:39 +01:00
|
|
|
|
|
|
|
const char *comma = "";
|
2014-06-25 05:34:05 +01:00
|
|
|
foreach_in_list(const ir_variable, param, parameters) {
|
2011-01-21 22:32:31 +00:00
|
|
|
ralloc_asprintf_append(&str, "%s%s", comma, param->type->name);
|
2010-08-06 01:21:39 +01:00
|
|
|
comma = ", ";
|
|
|
|
}
|
|
|
|
|
2011-01-21 22:32:31 +00:00
|
|
|
ralloc_strcat(&str, ")");
|
2010-08-06 01:21:39 +01:00
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2013-11-22 23:11:50 +00:00
|
|
|
static bool
|
|
|
|
verify_image_parameter(YYLTYPE *loc, _mesa_glsl_parse_state *state,
|
|
|
|
const ir_variable *formal, const ir_variable *actual)
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* From the ARB_shader_image_load_store specification:
|
|
|
|
*
|
|
|
|
* "The values of image variables qualified with coherent,
|
|
|
|
* volatile, restrict, readonly, or writeonly may not be passed
|
|
|
|
* to functions whose formal parameters lack such
|
|
|
|
* qualifiers. [...] It is legal to have additional qualifiers
|
|
|
|
* on a formal parameter, but not to have fewer."
|
|
|
|
*/
|
glsl: Use bit-flags image attributes and uint16_t for the image format
All of the GL image enums fit in 16-bits.
Also move the fields from the anonymous "image" structucture to the next
higher structure. This will enable packing the bits with the other
bitfield.
Valgrind massif results for a trimmed apitrace of dota2:
n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)
Before (32-bit): 76 40,572,916,873 68,831,248 63,328,783 5,502,465 0
After (32-bit): 70 40,577,421,777 68,487,584 62,973,695 5,513,889 0
Before (64-bit): 60 36,822,640,058 96,526,824 88,735,296 7,791,528 0
After (64-bit): 74 37,124,603,758 95,891,808 88,466,712 7,425,096 0
A real savings of 346KiB on 32-bit and 262KiB on 64-bit.
Signed-off-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
2014-07-14 23:48:38 +01:00
|
|
|
if (actual->data.image_coherent && !formal->data.image_coherent) {
|
2013-11-22 23:11:50 +00:00
|
|
|
_mesa_glsl_error(loc, state,
|
|
|
|
"function call parameter `%s' drops "
|
|
|
|
"`coherent' qualifier", formal->name);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
glsl: Use bit-flags image attributes and uint16_t for the image format
All of the GL image enums fit in 16-bits.
Also move the fields from the anonymous "image" structucture to the next
higher structure. This will enable packing the bits with the other
bitfield.
Valgrind massif results for a trimmed apitrace of dota2:
n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)
Before (32-bit): 76 40,572,916,873 68,831,248 63,328,783 5,502,465 0
After (32-bit): 70 40,577,421,777 68,487,584 62,973,695 5,513,889 0
Before (64-bit): 60 36,822,640,058 96,526,824 88,735,296 7,791,528 0
After (64-bit): 74 37,124,603,758 95,891,808 88,466,712 7,425,096 0
A real savings of 346KiB on 32-bit and 262KiB on 64-bit.
Signed-off-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
2014-07-14 23:48:38 +01:00
|
|
|
if (actual->data.image_volatile && !formal->data.image_volatile) {
|
2013-11-22 23:11:50 +00:00
|
|
|
_mesa_glsl_error(loc, state,
|
|
|
|
"function call parameter `%s' drops "
|
|
|
|
"`volatile' qualifier", formal->name);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
glsl: Use bit-flags image attributes and uint16_t for the image format
All of the GL image enums fit in 16-bits.
Also move the fields from the anonymous "image" structucture to the next
higher structure. This will enable packing the bits with the other
bitfield.
Valgrind massif results for a trimmed apitrace of dota2:
n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)
Before (32-bit): 76 40,572,916,873 68,831,248 63,328,783 5,502,465 0
After (32-bit): 70 40,577,421,777 68,487,584 62,973,695 5,513,889 0
Before (64-bit): 60 36,822,640,058 96,526,824 88,735,296 7,791,528 0
After (64-bit): 74 37,124,603,758 95,891,808 88,466,712 7,425,096 0
A real savings of 346KiB on 32-bit and 262KiB on 64-bit.
Signed-off-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
2014-07-14 23:48:38 +01:00
|
|
|
if (actual->data.image_restrict && !formal->data.image_restrict) {
|
2013-11-22 23:11:50 +00:00
|
|
|
_mesa_glsl_error(loc, state,
|
|
|
|
"function call parameter `%s' drops "
|
|
|
|
"`restrict' qualifier", formal->name);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
glsl: Use bit-flags image attributes and uint16_t for the image format
All of the GL image enums fit in 16-bits.
Also move the fields from the anonymous "image" structucture to the next
higher structure. This will enable packing the bits with the other
bitfield.
Valgrind massif results for a trimmed apitrace of dota2:
n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)
Before (32-bit): 76 40,572,916,873 68,831,248 63,328,783 5,502,465 0
After (32-bit): 70 40,577,421,777 68,487,584 62,973,695 5,513,889 0
Before (64-bit): 60 36,822,640,058 96,526,824 88,735,296 7,791,528 0
After (64-bit): 74 37,124,603,758 95,891,808 88,466,712 7,425,096 0
A real savings of 346KiB on 32-bit and 262KiB on 64-bit.
Signed-off-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
2014-07-14 23:48:38 +01:00
|
|
|
if (actual->data.image_read_only && !formal->data.image_read_only) {
|
2013-11-22 23:11:50 +00:00
|
|
|
_mesa_glsl_error(loc, state,
|
|
|
|
"function call parameter `%s' drops "
|
|
|
|
"`readonly' qualifier", formal->name);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
glsl: Use bit-flags image attributes and uint16_t for the image format
All of the GL image enums fit in 16-bits.
Also move the fields from the anonymous "image" structucture to the next
higher structure. This will enable packing the bits with the other
bitfield.
Valgrind massif results for a trimmed apitrace of dota2:
n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)
Before (32-bit): 76 40,572,916,873 68,831,248 63,328,783 5,502,465 0
After (32-bit): 70 40,577,421,777 68,487,584 62,973,695 5,513,889 0
Before (64-bit): 60 36,822,640,058 96,526,824 88,735,296 7,791,528 0
After (64-bit): 74 37,124,603,758 95,891,808 88,466,712 7,425,096 0
A real savings of 346KiB on 32-bit and 262KiB on 64-bit.
Signed-off-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
2014-07-14 23:48:38 +01:00
|
|
|
if (actual->data.image_write_only && !formal->data.image_write_only) {
|
2013-11-22 23:11:50 +00:00
|
|
|
_mesa_glsl_error(loc, state,
|
|
|
|
"function call parameter `%s' drops "
|
|
|
|
"`writeonly' qualifier", formal->name);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-12-23 18:58:23 +00:00
|
|
|
/**
|
2012-03-29 03:24:45 +01:00
|
|
|
* Verify that 'out' and 'inout' actual parameters are lvalues. Also, verify
|
|
|
|
* that 'const_in' formal parameters (an extension in our IR) correspond to
|
|
|
|
* ir_constant actual parameters.
|
2011-12-23 18:58:23 +00:00
|
|
|
*/
|
2012-03-29 03:24:45 +01:00
|
|
|
static bool
|
|
|
|
verify_parameter_modes(_mesa_glsl_parse_state *state,
|
|
|
|
ir_function_signature *sig,
|
|
|
|
exec_list &actual_ir_parameters,
|
|
|
|
exec_list &actual_ast_parameters)
|
2011-11-09 11:01:54 +00:00
|
|
|
{
|
2012-03-29 03:24:45 +01:00
|
|
|
exec_node *actual_ir_node = actual_ir_parameters.head;
|
|
|
|
exec_node *actual_ast_node = actual_ast_parameters.head;
|
2011-11-09 11:01:54 +00:00
|
|
|
|
2014-06-25 05:34:05 +01:00
|
|
|
foreach_in_list(const ir_variable, formal, &sig->parameters) {
|
2012-03-29 03:24:45 +01:00
|
|
|
/* The lists must be the same length. */
|
|
|
|
assert(!actual_ir_node->is_tail_sentinel());
|
|
|
|
assert(!actual_ast_node->is_tail_sentinel());
|
2011-12-23 18:58:23 +00:00
|
|
|
|
2012-03-29 03:24:45 +01:00
|
|
|
const ir_rvalue *const actual = (ir_rvalue *) actual_ir_node;
|
|
|
|
const ast_expression *const actual_ast =
|
|
|
|
exec_node_data(ast_expression, actual_ast_node, link);
|
2011-11-09 11:01:54 +00:00
|
|
|
|
2012-03-29 03:24:45 +01:00
|
|
|
/* FIXME: 'loc' is incorrect (as of 2011-01-21). It is always
|
|
|
|
* FIXME: 0:0(0).
|
|
|
|
*/
|
|
|
|
YYLTYPE loc = actual_ast->get_location();
|
2011-11-09 11:01:54 +00:00
|
|
|
|
2012-03-29 03:24:45 +01:00
|
|
|
/* Verify that 'const_in' parameters are ir_constants. */
|
2013-12-12 11:51:01 +00:00
|
|
|
if (formal->data.mode == ir_var_const_in &&
|
2012-03-29 03:24:45 +01:00
|
|
|
actual->ir_type != ir_type_constant) {
|
|
|
|
_mesa_glsl_error(&loc, state,
|
|
|
|
"parameter `in %s' must be a constant expression",
|
2011-11-09 11:01:54 +00:00
|
|
|
formal->name);
|
2012-03-29 03:24:45 +01:00
|
|
|
return false;
|
2011-11-09 11:01:54 +00:00
|
|
|
}
|
|
|
|
|
2013-11-10 08:19:31 +00:00
|
|
|
/* Verify that shader_in parameters are shader inputs */
|
|
|
|
if (formal->data.must_be_shader_input) {
|
|
|
|
ir_variable *var = actual->variable_referenced();
|
|
|
|
if (var && var->data.mode != ir_var_shader_in) {
|
|
|
|
_mesa_glsl_error(&loc, state,
|
|
|
|
"parameter `%s` must be a shader input",
|
|
|
|
formal->name);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (actual->ir_type == ir_type_swizzle) {
|
|
|
|
_mesa_glsl_error(&loc, state,
|
|
|
|
"parameter `%s` must not be swizzled",
|
|
|
|
formal->name);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-29 03:24:45 +01:00
|
|
|
/* Verify that 'out' and 'inout' actual parameters are lvalues. */
|
2013-12-12 11:51:01 +00:00
|
|
|
if (formal->data.mode == ir_var_function_out
|
|
|
|
|| formal->data.mode == ir_var_function_inout) {
|
2011-11-09 11:01:54 +00:00
|
|
|
const char *mode = NULL;
|
2013-12-12 11:51:01 +00:00
|
|
|
switch (formal->data.mode) {
|
2013-01-11 22:39:32 +00:00
|
|
|
case ir_var_function_out: mode = "out"; break;
|
|
|
|
case ir_var_function_inout: mode = "inout"; break;
|
|
|
|
default: assert(false); break;
|
2011-11-09 11:01:54 +00:00
|
|
|
}
|
2012-03-29 03:24:45 +01:00
|
|
|
|
|
|
|
/* This AST-based check catches errors like f(i++). The IR-based
|
|
|
|
* is_lvalue() is insufficient because the actual parameter at the
|
|
|
|
* IR-level is just a temporary value, which is an l-value.
|
2011-11-09 11:01:54 +00:00
|
|
|
*/
|
2012-03-29 03:24:45 +01:00
|
|
|
if (actual_ast->non_lvalue_description != NULL) {
|
|
|
|
_mesa_glsl_error(&loc, state,
|
|
|
|
"function parameter '%s %s' references a %s",
|
|
|
|
mode, formal->name,
|
|
|
|
actual_ast->non_lvalue_description);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-03-30 01:02:15 +01:00
|
|
|
ir_variable *var = actual->variable_referenced();
|
2012-04-24 01:24:13 +01:00
|
|
|
if (var)
|
2013-12-12 11:51:01 +00:00
|
|
|
var->data.assigned = true;
|
2012-04-24 01:24:13 +01:00
|
|
|
|
2013-12-12 10:57:57 +00:00
|
|
|
if (var && var->data.read_only) {
|
2012-04-24 01:24:13 +01:00
|
|
|
_mesa_glsl_error(&loc, state,
|
|
|
|
"function parameter '%s %s' references the "
|
|
|
|
"read-only variable '%s'",
|
|
|
|
mode, formal->name,
|
|
|
|
actual->variable_referenced()->name);
|
|
|
|
return false;
|
|
|
|
} else if (!actual->is_lvalue()) {
|
2013-03-23 00:45:52 +00:00
|
|
|
/* Even though ir_binop_vector_extract is not an l-value, let it
|
|
|
|
* slop through. generate_call will handle it correctly.
|
|
|
|
*/
|
|
|
|
ir_expression *const expr = ((ir_rvalue *) actual)->as_expression();
|
|
|
|
if (expr == NULL
|
|
|
|
|| expr->operation != ir_binop_vector_extract
|
|
|
|
|| !expr->operands[0]->is_lvalue()) {
|
|
|
|
_mesa_glsl_error(&loc, state,
|
|
|
|
"function parameter '%s %s' is not an lvalue",
|
|
|
|
mode, formal->name);
|
|
|
|
return false;
|
|
|
|
}
|
2011-11-09 11:01:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-22 23:11:50 +00:00
|
|
|
if (formal->type->is_image() &&
|
|
|
|
actual->variable_referenced()) {
|
|
|
|
if (!verify_image_parameter(&loc, state, formal,
|
|
|
|
actual->variable_referenced()))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-03-29 03:24:45 +01:00
|
|
|
actual_ir_node = actual_ir_node->next;
|
|
|
|
actual_ast_node = actual_ast_node->next;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-03-23 00:45:52 +00:00
|
|
|
static void
|
|
|
|
fix_parameter(void *mem_ctx, ir_rvalue *actual, const glsl_type *formal_type,
|
|
|
|
exec_list *before_instructions, exec_list *after_instructions,
|
|
|
|
bool parameter_is_inout)
|
|
|
|
{
|
|
|
|
ir_expression *const expr = actual->as_expression();
|
|
|
|
|
|
|
|
/* If the types match exactly and the parameter is not a vector-extract,
|
|
|
|
* nothing needs to be done to fix the parameter.
|
|
|
|
*/
|
|
|
|
if (formal_type == actual->type
|
|
|
|
&& (expr == NULL || expr->operation != ir_binop_vector_extract))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* To convert an out parameter, we need to create a temporary variable to
|
|
|
|
* hold the value before conversion, and then perform the conversion after
|
|
|
|
* the function call returns.
|
|
|
|
*
|
|
|
|
* This has the effect of transforming code like this:
|
|
|
|
*
|
|
|
|
* void f(out int x);
|
|
|
|
* float value;
|
|
|
|
* f(value);
|
|
|
|
*
|
|
|
|
* Into IR that's equivalent to this:
|
|
|
|
*
|
|
|
|
* void f(out int x);
|
|
|
|
* float value;
|
|
|
|
* int out_parameter_conversion;
|
|
|
|
* f(out_parameter_conversion);
|
|
|
|
* value = float(out_parameter_conversion);
|
|
|
|
*
|
|
|
|
* If the parameter is an ir_expression of ir_binop_vector_extract,
|
|
|
|
* additional conversion is needed in the post-call re-write.
|
|
|
|
*/
|
|
|
|
ir_variable *tmp =
|
|
|
|
new(mem_ctx) ir_variable(formal_type, "inout_tmp", ir_var_temporary);
|
|
|
|
|
|
|
|
before_instructions->push_tail(tmp);
|
|
|
|
|
|
|
|
/* If the parameter is an inout parameter, copy the value of the actual
|
|
|
|
* parameter to the new temporary. Note that no type conversion is allowed
|
|
|
|
* here because inout parameters must match types exactly.
|
|
|
|
*/
|
|
|
|
if (parameter_is_inout) {
|
|
|
|
/* Inout parameters should never require conversion, since that would
|
|
|
|
* require an implicit conversion to exist both to and from the formal
|
|
|
|
* parameter type, and there are no bidirectional implicit conversions.
|
|
|
|
*/
|
|
|
|
assert (actual->type == formal_type);
|
|
|
|
|
|
|
|
ir_dereference_variable *const deref_tmp_1 =
|
|
|
|
new(mem_ctx) ir_dereference_variable(tmp);
|
|
|
|
ir_assignment *const assignment =
|
|
|
|
new(mem_ctx) ir_assignment(deref_tmp_1, actual);
|
|
|
|
before_instructions->push_tail(assignment);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Replace the parameter in the call with a dereference of the new
|
|
|
|
* temporary.
|
|
|
|
*/
|
|
|
|
ir_dereference_variable *const deref_tmp_2 =
|
|
|
|
new(mem_ctx) ir_dereference_variable(tmp);
|
|
|
|
actual->replace_with(deref_tmp_2);
|
|
|
|
|
|
|
|
|
|
|
|
/* Copy the temporary variable to the actual parameter with optional
|
|
|
|
* type conversion applied.
|
|
|
|
*/
|
|
|
|
ir_rvalue *rhs = new(mem_ctx) ir_dereference_variable(tmp);
|
|
|
|
if (actual->type != formal_type)
|
|
|
|
rhs = convert_component(rhs, actual->type);
|
|
|
|
|
|
|
|
ir_rvalue *lhs = actual;
|
|
|
|
if (expr != NULL && expr->operation == ir_binop_vector_extract) {
|
|
|
|
rhs = new(mem_ctx) ir_expression(ir_triop_vector_insert,
|
|
|
|
expr->operands[0]->type,
|
|
|
|
expr->operands[0]->clone(mem_ctx, NULL),
|
|
|
|
rhs,
|
|
|
|
expr->operands[1]->clone(mem_ctx, NULL));
|
|
|
|
lhs = expr->operands[0]->clone(mem_ctx, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
ir_assignment *const assignment_2 = new(mem_ctx) ir_assignment(lhs, rhs);
|
|
|
|
after_instructions->push_tail(assignment_2);
|
|
|
|
}
|
|
|
|
|
2012-03-29 03:24:45 +01:00
|
|
|
/**
|
2013-11-23 18:39:34 +00:00
|
|
|
* Generate a function call.
|
|
|
|
*
|
|
|
|
* For non-void functions, this returns a dereference of the temporary variable
|
|
|
|
* which stores the return value for the call. For void functions, this returns
|
|
|
|
* NULL.
|
2012-03-29 03:24:45 +01:00
|
|
|
*/
|
|
|
|
static ir_rvalue *
|
|
|
|
generate_call(exec_list *instructions, ir_function_signature *sig,
|
2012-12-11 20:54:02 +00:00
|
|
|
exec_list *actual_parameters,
|
2012-03-29 03:24:45 +01:00
|
|
|
struct _mesa_glsl_parse_state *state)
|
|
|
|
{
|
|
|
|
void *ctx = state;
|
|
|
|
exec_list post_call_conversions;
|
|
|
|
|
|
|
|
/* Perform implicit conversion of arguments. For out parameters, we need
|
|
|
|
* to place them in a temporary variable and do the conversion after the
|
|
|
|
* call takes place. Since we haven't emitted the call yet, we'll place
|
|
|
|
* the post-call conversions in a temporary exec_list, and emit them later.
|
|
|
|
*/
|
glsl: Use a new foreach_two_lists macro for walking two lists at once.
When handling function calls, we often want to walk through the list of
formal parameters and list of actual parameters at the same time.
(Both are guaranteed to be the same length.)
Previously, we used a pattern of:
exec_list_iterator 1st_iter = <1st list>.iterator();
foreach_iter(exec_list_iterator, 2nd_iter, <2nd list>) {
...
1st_iter.next();
}
This was awkward, since you had to manually iterate through one of
the two lists.
This patch introduces a foreach_two_lists macro which safely walks
through two lists at the same time, so you can simply do:
foreach_two_lists(1st_node, <1st list>, 2nd_node, <2nd list>) {
...
}
v2: Rename macro from foreach_list2 to foreach_two_lists, as suggested
by Ian Romanick.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Matt Turner <mattst88@gmail.com>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2014-01-11 00:39:17 +00:00
|
|
|
foreach_two_lists(formal_node, &sig->parameters,
|
|
|
|
actual_node, actual_parameters) {
|
|
|
|
ir_rvalue *actual = (ir_rvalue *) actual_node;
|
|
|
|
ir_variable *formal = (ir_variable *) formal_node;
|
2012-03-29 03:24:45 +01:00
|
|
|
|
2011-11-09 11:01:54 +00:00
|
|
|
if (formal->type->is_numeric() || formal->type->is_boolean()) {
|
2013-12-12 11:51:01 +00:00
|
|
|
switch (formal->data.mode) {
|
2011-11-09 11:01:54 +00:00
|
|
|
case ir_var_const_in:
|
2013-01-11 22:39:32 +00:00
|
|
|
case ir_var_function_in: {
|
2011-11-09 11:01:54 +00:00
|
|
|
ir_rvalue *converted
|
|
|
|
= convert_component(actual, formal->type);
|
|
|
|
actual->replace_with(converted);
|
|
|
|
break;
|
|
|
|
}
|
2013-01-11 22:39:32 +00:00
|
|
|
case ir_var_function_out:
|
|
|
|
case ir_var_function_inout:
|
2013-03-23 00:45:52 +00:00
|
|
|
fix_parameter(ctx, actual, formal->type,
|
|
|
|
instructions, &post_call_conversions,
|
2013-12-12 11:51:01 +00:00
|
|
|
formal->data.mode == ir_var_function_inout);
|
2011-11-09 11:01:54 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert (!"Illegal formal parameter mode");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
glsl: Convert ir_call to be a statement rather than a value.
Aside from ir_call, our IR is cleanly split into two classes:
- Statements (typeless; used for side effects, control flow)
- Values (deeply nestable, pure, typed expression trees)
Unfortunately, ir_call confused all this:
- For void functions, we placed ir_call directly in the instruction
stream, treating it as an untyped statement. Yet, it was a subclass
of ir_rvalue, and no other ir_rvalue could be used in this way.
- For functions with a return value, ir_call could be placed in
arbitrary expression trees. While this fit naturally with the source
language, it meant that expressions might not be pure, making it
difficult to transform and optimize them. To combat this, we always
emitted ir_call directly in the RHS of an ir_assignment, only using
a temporary variable in expression trees. Many passes relied on this
assumption; the acos and atan built-ins violated it.
This patch makes ir_call a statement (ir_instruction) rather than a
value (ir_rvalue). Non-void calls now take a ir_dereference of a
variable, and store the return value there---effectively a call and
assignment rolled into one. They cannot be embedded in expressions.
All expression trees are now pure, without exception.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2012-03-20 22:56:37 +00:00
|
|
|
/* If the function call is a constant expression, don't generate any
|
|
|
|
* instructions; just generate an ir_constant.
|
2011-11-09 11:01:54 +00:00
|
|
|
*
|
2012-08-02 16:18:12 +01:00
|
|
|
* Function calls were first allowed to be constant expressions in GLSL
|
|
|
|
* 1.20 and GLSL ES 3.00.
|
2011-11-09 11:01:54 +00:00
|
|
|
*/
|
2012-08-02 16:18:12 +01:00
|
|
|
if (state->is_version(120, 300)) {
|
2012-05-02 22:11:38 +01:00
|
|
|
ir_constant *value = sig->constant_expression_value(actual_parameters, NULL);
|
glsl: Convert ir_call to be a statement rather than a value.
Aside from ir_call, our IR is cleanly split into two classes:
- Statements (typeless; used for side effects, control flow)
- Values (deeply nestable, pure, typed expression trees)
Unfortunately, ir_call confused all this:
- For void functions, we placed ir_call directly in the instruction
stream, treating it as an untyped statement. Yet, it was a subclass
of ir_rvalue, and no other ir_rvalue could be used in this way.
- For functions with a return value, ir_call could be placed in
arbitrary expression trees. While this fit naturally with the source
language, it meant that expressions might not be pure, making it
difficult to transform and optimize them. To combat this, we always
emitted ir_call directly in the RHS of an ir_assignment, only using
a temporary variable in expression trees. Many passes relied on this
assumption; the acos and atan built-ins violated it.
This patch makes ir_call a statement (ir_instruction) rather than a
value (ir_rvalue). Non-void calls now take a ir_dereference of a
variable, and store the return value there---effectively a call and
assignment rolled into one. They cannot be embedded in expressions.
All expression trees are now pure, without exception.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2012-03-20 22:56:37 +00:00
|
|
|
if (value != NULL) {
|
|
|
|
return value;
|
2011-11-09 11:01:54 +00:00
|
|
|
}
|
glsl: Convert ir_call to be a statement rather than a value.
Aside from ir_call, our IR is cleanly split into two classes:
- Statements (typeless; used for side effects, control flow)
- Values (deeply nestable, pure, typed expression trees)
Unfortunately, ir_call confused all this:
- For void functions, we placed ir_call directly in the instruction
stream, treating it as an untyped statement. Yet, it was a subclass
of ir_rvalue, and no other ir_rvalue could be used in this way.
- For functions with a return value, ir_call could be placed in
arbitrary expression trees. While this fit naturally with the source
language, it meant that expressions might not be pure, making it
difficult to transform and optimize them. To combat this, we always
emitted ir_call directly in the RHS of an ir_assignment, only using
a temporary variable in expression trees. Many passes relied on this
assumption; the acos and atan built-ins violated it.
This patch makes ir_call a statement (ir_instruction) rather than a
value (ir_rvalue). Non-void calls now take a ir_dereference of a
variable, and store the return value there---effectively a call and
assignment rolled into one. They cannot be embedded in expressions.
All expression trees are now pure, without exception.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2012-03-20 22:56:37 +00:00
|
|
|
}
|
2011-11-09 11:01:54 +00:00
|
|
|
|
glsl: Convert ir_call to be a statement rather than a value.
Aside from ir_call, our IR is cleanly split into two classes:
- Statements (typeless; used for side effects, control flow)
- Values (deeply nestable, pure, typed expression trees)
Unfortunately, ir_call confused all this:
- For void functions, we placed ir_call directly in the instruction
stream, treating it as an untyped statement. Yet, it was a subclass
of ir_rvalue, and no other ir_rvalue could be used in this way.
- For functions with a return value, ir_call could be placed in
arbitrary expression trees. While this fit naturally with the source
language, it meant that expressions might not be pure, making it
difficult to transform and optimize them. To combat this, we always
emitted ir_call directly in the RHS of an ir_assignment, only using
a temporary variable in expression trees. Many passes relied on this
assumption; the acos and atan built-ins violated it.
This patch makes ir_call a statement (ir_instruction) rather than a
value (ir_rvalue). Non-void calls now take a ir_dereference of a
variable, and store the return value there---effectively a call and
assignment rolled into one. They cannot be embedded in expressions.
All expression trees are now pure, without exception.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2012-03-20 22:56:37 +00:00
|
|
|
ir_dereference_variable *deref = NULL;
|
|
|
|
if (!sig->return_type->is_void()) {
|
|
|
|
/* Create a new temporary to hold the return value. */
|
2014-07-09 03:04:52 +01:00
|
|
|
char *const name = ir_variable::temporaries_allocate_names
|
|
|
|
? ralloc_asprintf(ctx, "%s_retval", sig->function_name())
|
|
|
|
: NULL;
|
|
|
|
|
2011-11-09 11:01:54 +00:00
|
|
|
ir_variable *var;
|
|
|
|
|
2014-07-09 03:04:52 +01:00
|
|
|
var = new(ctx) ir_variable(sig->return_type, name, ir_var_temporary);
|
2011-11-09 11:01:54 +00:00
|
|
|
instructions->push_tail(var);
|
|
|
|
|
2014-07-09 03:04:52 +01:00
|
|
|
ralloc_free(name);
|
|
|
|
|
2011-11-09 11:01:54 +00:00
|
|
|
deref = new(ctx) ir_dereference_variable(var);
|
|
|
|
}
|
glsl: Convert ir_call to be a statement rather than a value.
Aside from ir_call, our IR is cleanly split into two classes:
- Statements (typeless; used for side effects, control flow)
- Values (deeply nestable, pure, typed expression trees)
Unfortunately, ir_call confused all this:
- For void functions, we placed ir_call directly in the instruction
stream, treating it as an untyped statement. Yet, it was a subclass
of ir_rvalue, and no other ir_rvalue could be used in this way.
- For functions with a return value, ir_call could be placed in
arbitrary expression trees. While this fit naturally with the source
language, it meant that expressions might not be pure, making it
difficult to transform and optimize them. To combat this, we always
emitted ir_call directly in the RHS of an ir_assignment, only using
a temporary variable in expression trees. Many passes relied on this
assumption; the acos and atan built-ins violated it.
This patch makes ir_call a statement (ir_instruction) rather than a
value (ir_rvalue). Non-void calls now take a ir_dereference of a
variable, and store the return value there---effectively a call and
assignment rolled into one. They cannot be embedded in expressions.
All expression trees are now pure, without exception.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2012-03-20 22:56:37 +00:00
|
|
|
ir_call *call = new(ctx) ir_call(sig, deref, actual_parameters);
|
|
|
|
instructions->push_tail(call);
|
|
|
|
|
|
|
|
/* Also emit any necessary out-parameter conversions. */
|
2011-11-09 11:01:54 +00:00
|
|
|
instructions->append_list(&post_call_conversions);
|
glsl: Convert ir_call to be a statement rather than a value.
Aside from ir_call, our IR is cleanly split into two classes:
- Statements (typeless; used for side effects, control flow)
- Values (deeply nestable, pure, typed expression trees)
Unfortunately, ir_call confused all this:
- For void functions, we placed ir_call directly in the instruction
stream, treating it as an untyped statement. Yet, it was a subclass
of ir_rvalue, and no other ir_rvalue could be used in this way.
- For functions with a return value, ir_call could be placed in
arbitrary expression trees. While this fit naturally with the source
language, it meant that expressions might not be pure, making it
difficult to transform and optimize them. To combat this, we always
emitted ir_call directly in the RHS of an ir_assignment, only using
a temporary variable in expression trees. Many passes relied on this
assumption; the acos and atan built-ins violated it.
This patch makes ir_call a statement (ir_instruction) rather than a
value (ir_rvalue). Non-void calls now take a ir_dereference of a
variable, and store the return value there---effectively a call and
assignment rolled into one. They cannot be embedded in expressions.
All expression trees are now pure, without exception.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2012-03-20 22:56:37 +00:00
|
|
|
|
|
|
|
return deref ? deref->clone(ctx, NULL) : NULL;
|
2011-11-09 11:01:54 +00:00
|
|
|
}
|
2010-08-06 01:21:39 +01:00
|
|
|
|
glsl: Split up function matching and call generation a bit more.
We used to have one big function, match_signature_by_name, which found
a matching signature, performed out-parameter conversions, and generated
the ir_call. As the code for matching against built-in functions became
more complicated, I split it internally, creating generate_call().
However, I left the same awkward interface. This patch splits it into
three functions:
1. match_signature_by_name()
This now takes a name, a list of parameters, the symbol table, and
returns an ir_function_signature. Simple and one purpose: matching.
2. no_matching_function_error()
Generate the "no matching function" error and list of prototypes.
This was complex enough that I felt it deserved its own function.
3. generate_call()
Do the out-parameter conversion and generate the ir_call. This
could probably use more splitting.
The caller now has a more natural workflow: find a matching signature,
then either generate an error or a call.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2012-03-28 23:57:50 +01:00
|
|
|
/**
|
|
|
|
* Given a function name and parameter list, find the matching signature.
|
|
|
|
*/
|
|
|
|
static ir_function_signature *
|
|
|
|
match_function_by_name(const char *name,
|
|
|
|
exec_list *actual_parameters,
|
2010-11-11 20:11:27 +00:00
|
|
|
struct _mesa_glsl_parse_state *state)
|
2010-04-01 00:28:51 +01:00
|
|
|
{
|
2010-06-25 21:14:37 +01:00
|
|
|
void *ctx = state;
|
2010-11-11 20:11:27 +00:00
|
|
|
ir_function *f = state->symbols->get_function(name);
|
glsl: Always search for an exact function signature match.
Previously, we would fail to compile the following shader due to a bug
in lazy built-in importing:
#version 130
void main() {
float f = abs(5.0);
int i = abs(5);
}
The first call, abs(5.0), would fail to find a local signature, look
through the built-ins, and import "float abs(float)".
The second call, abs(5), would find the newly imported float signature
in the local shader, and settle for that. Unfortunately, it failed to
search the built-ins for the correct/exact signature, "int abs(int)".
Thus, abs(5) ended up being a float, causing a bizarre type error when
we tried to assign it to an int.
Fixes piglit test builtin-overload-matching.frag.
This is /not/ a candidate for stable branches, as it should only be
possible to trigger this bug using GLSL 1.30's built-in functions that
take integer arguments. Plus, the changes are fairly invasive.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
2011-11-11 08:43:06 +00:00
|
|
|
ir_function_signature *local_sig = NULL;
|
|
|
|
ir_function_signature *sig = NULL;
|
|
|
|
|
|
|
|
/* Is the function hidden by a record type constructor? */
|
|
|
|
if (state->symbols->get_type(name))
|
|
|
|
goto done; /* no match */
|
|
|
|
|
|
|
|
/* Is the function hidden by a variable (impossible in 1.10)? */
|
2012-08-02 01:44:02 +01:00
|
|
|
if (!state->symbols->separate_function_namespace
|
|
|
|
&& state->symbols->get_variable(name))
|
glsl: Always search for an exact function signature match.
Previously, we would fail to compile the following shader due to a bug
in lazy built-in importing:
#version 130
void main() {
float f = abs(5.0);
int i = abs(5);
}
The first call, abs(5.0), would fail to find a local signature, look
through the built-ins, and import "float abs(float)".
The second call, abs(5), would find the newly imported float signature
in the local shader, and settle for that. Unfortunately, it failed to
search the built-ins for the correct/exact signature, "int abs(int)".
Thus, abs(5) ended up being a float, causing a bizarre type error when
we tried to assign it to an int.
Fixes piglit test builtin-overload-matching.frag.
This is /not/ a candidate for stable branches, as it should only be
possible to trigger this bug using GLSL 1.30's built-in functions that
take integer arguments. Plus, the changes are fairly invasive.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
2011-11-11 08:43:06 +00:00
|
|
|
goto done; /* no match */
|
|
|
|
|
|
|
|
if (f != NULL) {
|
2014-07-24 22:05:40 +01:00
|
|
|
/* In desktop GL, the presence of a user-defined signature hides any
|
|
|
|
* built-in signatures, so we must ignore them. In contrast, in ES2
|
|
|
|
* user-defined signatures add new overloads, so we must consider them.
|
|
|
|
*/
|
|
|
|
bool allow_builtins = state->es_shader || !f->has_user_signature();
|
|
|
|
|
glsl: Always search for an exact function signature match.
Previously, we would fail to compile the following shader due to a bug
in lazy built-in importing:
#version 130
void main() {
float f = abs(5.0);
int i = abs(5);
}
The first call, abs(5.0), would fail to find a local signature, look
through the built-ins, and import "float abs(float)".
The second call, abs(5), would find the newly imported float signature
in the local shader, and settle for that. Unfortunately, it failed to
search the built-ins for the correct/exact signature, "int abs(int)".
Thus, abs(5) ended up being a float, causing a bizarre type error when
we tried to assign it to an int.
Fixes piglit test builtin-overload-matching.frag.
This is /not/ a candidate for stable branches, as it should only be
possible to trigger this bug using GLSL 1.30's built-in functions that
take integer arguments. Plus, the changes are fairly invasive.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
2011-11-11 08:43:06 +00:00
|
|
|
/* Look for a match in the local shader. If exact, we're done. */
|
|
|
|
bool is_exact = false;
|
2013-08-31 07:11:55 +01:00
|
|
|
sig = local_sig = f->matching_signature(state, actual_parameters,
|
2014-07-24 22:05:40 +01:00
|
|
|
allow_builtins, &is_exact);
|
glsl: Always search for an exact function signature match.
Previously, we would fail to compile the following shader due to a bug
in lazy built-in importing:
#version 130
void main() {
float f = abs(5.0);
int i = abs(5);
}
The first call, abs(5.0), would fail to find a local signature, look
through the built-ins, and import "float abs(float)".
The second call, abs(5), would find the newly imported float signature
in the local shader, and settle for that. Unfortunately, it failed to
search the built-ins for the correct/exact signature, "int abs(int)".
Thus, abs(5) ended up being a float, causing a bizarre type error when
we tried to assign it to an int.
Fixes piglit test builtin-overload-matching.frag.
This is /not/ a candidate for stable branches, as it should only be
possible to trigger this bug using GLSL 1.30's built-in functions that
take integer arguments. Plus, the changes are fairly invasive.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
2011-11-11 08:43:06 +00:00
|
|
|
if (is_exact)
|
|
|
|
goto done;
|
|
|
|
|
2014-07-24 22:05:40 +01:00
|
|
|
if (!allow_builtins)
|
glsl: Always search for an exact function signature match.
Previously, we would fail to compile the following shader due to a bug
in lazy built-in importing:
#version 130
void main() {
float f = abs(5.0);
int i = abs(5);
}
The first call, abs(5.0), would fail to find a local signature, look
through the built-ins, and import "float abs(float)".
The second call, abs(5), would find the newly imported float signature
in the local shader, and settle for that. Unfortunately, it failed to
search the built-ins for the correct/exact signature, "int abs(int)".
Thus, abs(5) ended up being a float, causing a bizarre type error when
we tried to assign it to an int.
Fixes piglit test builtin-overload-matching.frag.
This is /not/ a candidate for stable branches, as it should only be
possible to trigger this bug using GLSL 1.30's built-in functions that
take integer arguments. Plus, the changes are fairly invasive.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
2011-11-11 08:43:06 +00:00
|
|
|
goto done;
|
|
|
|
}
|
2010-06-24 02:11:51 +01:00
|
|
|
|
glsl: Always search for an exact function signature match.
Previously, we would fail to compile the following shader due to a bug
in lazy built-in importing:
#version 130
void main() {
float f = abs(5.0);
int i = abs(5);
}
The first call, abs(5.0), would fail to find a local signature, look
through the built-ins, and import "float abs(float)".
The second call, abs(5), would find the newly imported float signature
in the local shader, and settle for that. Unfortunately, it failed to
search the built-ins for the correct/exact signature, "int abs(int)".
Thus, abs(5) ended up being a float, causing a bizarre type error when
we tried to assign it to an int.
Fixes piglit test builtin-overload-matching.frag.
This is /not/ a candidate for stable branches, as it should only be
possible to trigger this bug using GLSL 1.30's built-in functions that
take integer arguments. Plus, the changes are fairly invasive.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
2011-11-11 08:43:06 +00:00
|
|
|
/* Local shader has no exact candidates; check the built-ins. */
|
2013-09-02 04:48:45 +01:00
|
|
|
_mesa_glsl_initialize_builtin_functions();
|
|
|
|
sig = _mesa_glsl_find_builtin_function(state, name, actual_parameters);
|
2010-04-01 00:28:51 +01:00
|
|
|
|
glsl: Always search for an exact function signature match.
Previously, we would fail to compile the following shader due to a bug
in lazy built-in importing:
#version 130
void main() {
float f = abs(5.0);
int i = abs(5);
}
The first call, abs(5.0), would fail to find a local signature, look
through the built-ins, and import "float abs(float)".
The second call, abs(5), would find the newly imported float signature
in the local shader, and settle for that. Unfortunately, it failed to
search the built-ins for the correct/exact signature, "int abs(int)".
Thus, abs(5) ended up being a float, causing a bizarre type error when
we tried to assign it to an int.
Fixes piglit test builtin-overload-matching.frag.
This is /not/ a candidate for stable branches, as it should only be
possible to trigger this bug using GLSL 1.30's built-in functions that
take integer arguments. Plus, the changes are fairly invasive.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
2011-11-11 08:43:06 +00:00
|
|
|
done:
|
2010-03-15 20:26:02 +00:00
|
|
|
if (sig != NULL) {
|
glsl: Always search for an exact function signature match.
Previously, we would fail to compile the following shader due to a bug
in lazy built-in importing:
#version 130
void main() {
float f = abs(5.0);
int i = abs(5);
}
The first call, abs(5.0), would fail to find a local signature, look
through the built-ins, and import "float abs(float)".
The second call, abs(5), would find the newly imported float signature
in the local shader, and settle for that. Unfortunately, it failed to
search the built-ins for the correct/exact signature, "int abs(int)".
Thus, abs(5) ended up being a float, causing a bizarre type error when
we tried to assign it to an int.
Fixes piglit test builtin-overload-matching.frag.
This is /not/ a candidate for stable branches, as it should only be
possible to trigger this bug using GLSL 1.30's built-in functions that
take integer arguments. Plus, the changes are fairly invasive.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
2011-11-11 08:43:06 +00:00
|
|
|
/* If the match is from a linked built-in shader, import the prototype. */
|
|
|
|
if (sig != local_sig) {
|
|
|
|
if (f == NULL) {
|
|
|
|
f = new(ctx) ir_function(name);
|
|
|
|
state->symbols->add_global_function(f);
|
|
|
|
emit_function(state, f);
|
|
|
|
}
|
|
|
|
f->add_signature(sig->clone_prototype(f, NULL));
|
|
|
|
}
|
glsl: Split up function matching and call generation a bit more.
We used to have one big function, match_signature_by_name, which found
a matching signature, performed out-parameter conversions, and generated
the ir_call. As the code for matching against built-in functions became
more complicated, I split it internally, creating generate_call().
However, I left the same awkward interface. This patch splits it into
three functions:
1. match_signature_by_name()
This now takes a name, a list of parameters, the symbol table, and
returns an ir_function_signature. Simple and one purpose: matching.
2. no_matching_function_error()
Generate the "no matching function" error and list of prototypes.
This was complex enough that I felt it deserved its own function.
3. generate_call()
Do the out-parameter conversion and generate the ir_call. This
could probably use more splitting.
The caller now has a more natural workflow: find a matching signature,
then either generate an error or a call.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2012-03-28 23:57:50 +01:00
|
|
|
}
|
|
|
|
return sig;
|
|
|
|
}
|
glsl: Always search for an exact function signature match.
Previously, we would fail to compile the following shader due to a bug
in lazy built-in importing:
#version 130
void main() {
float f = abs(5.0);
int i = abs(5);
}
The first call, abs(5.0), would fail to find a local signature, look
through the built-ins, and import "float abs(float)".
The second call, abs(5), would find the newly imported float signature
in the local shader, and settle for that. Unfortunately, it failed to
search the built-ins for the correct/exact signature, "int abs(int)".
Thus, abs(5) ended up being a float, causing a bizarre type error when
we tried to assign it to an int.
Fixes piglit test builtin-overload-matching.frag.
This is /not/ a candidate for stable branches, as it should only be
possible to trigger this bug using GLSL 1.30's built-in functions that
take integer arguments. Plus, the changes are fairly invasive.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
2011-11-11 08:43:06 +00:00
|
|
|
|
2013-11-23 20:06:24 +00:00
|
|
|
static void
|
|
|
|
print_function_prototypes(_mesa_glsl_parse_state *state, YYLTYPE *loc,
|
|
|
|
ir_function *f)
|
|
|
|
{
|
|
|
|
if (f == NULL)
|
|
|
|
return;
|
|
|
|
|
2014-06-25 05:34:05 +01:00
|
|
|
foreach_in_list(ir_function_signature, sig, &f->signatures) {
|
2013-11-23 20:06:24 +00:00
|
|
|
if (sig->is_builtin() && !sig->is_builtin_available(state))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
char *str = prototype_string(sig->return_type, f->name, &sig->parameters);
|
|
|
|
_mesa_glsl_error(loc, state, " %s", str);
|
|
|
|
ralloc_free(str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
glsl: Split up function matching and call generation a bit more.
We used to have one big function, match_signature_by_name, which found
a matching signature, performed out-parameter conversions, and generated
the ir_call. As the code for matching against built-in functions became
more complicated, I split it internally, creating generate_call().
However, I left the same awkward interface. This patch splits it into
three functions:
1. match_signature_by_name()
This now takes a name, a list of parameters, the symbol table, and
returns an ir_function_signature. Simple and one purpose: matching.
2. no_matching_function_error()
Generate the "no matching function" error and list of prototypes.
This was complex enough that I felt it deserved its own function.
3. generate_call()
Do the out-parameter conversion and generate the ir_call. This
could probably use more splitting.
The caller now has a more natural workflow: find a matching signature,
then either generate an error or a call.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2012-03-28 23:57:50 +01:00
|
|
|
/**
|
|
|
|
* Raise a "no matching function" error, listing all possible overloads the
|
|
|
|
* compiler considered so developers can figure out what went wrong.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
no_matching_function_error(const char *name,
|
|
|
|
YYLTYPE *loc,
|
|
|
|
exec_list *actual_parameters,
|
|
|
|
_mesa_glsl_parse_state *state)
|
|
|
|
{
|
2013-12-09 09:18:26 +00:00
|
|
|
gl_shader *sh = _mesa_glsl_get_builtin_function_shader();
|
|
|
|
|
|
|
|
if (state->symbols->get_function(name) == NULL
|
|
|
|
&& (!state->uses_builtin_functions
|
|
|
|
|| sh->symbols->get_function(name) == NULL)) {
|
|
|
|
_mesa_glsl_error(loc, state, "no function with name '%s'", name);
|
|
|
|
} else {
|
|
|
|
char *str = prototype_string(NULL, name, actual_parameters);
|
|
|
|
_mesa_glsl_error(loc, state,
|
|
|
|
"no matching function for call to `%s'; candidates are:",
|
|
|
|
str);
|
|
|
|
ralloc_free(str);
|
2010-08-06 01:21:39 +01:00
|
|
|
|
2013-12-09 09:18:26 +00:00
|
|
|
print_function_prototypes(state, loc, state->symbols->get_function(name));
|
2010-08-06 01:21:39 +01:00
|
|
|
|
2013-12-09 09:18:26 +00:00
|
|
|
if (state->uses_builtin_functions) {
|
|
|
|
print_function_prototypes(state, loc, sh->symbols->get_function(name));
|
|
|
|
}
|
2010-03-15 20:26:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-27 00:38:58 +00:00
|
|
|
/**
|
|
|
|
* Perform automatic type conversion of constructor parameters
|
2010-07-20 07:45:23 +01:00
|
|
|
*
|
|
|
|
* This implements the rules in the "Conversion and Scalar Constructors"
|
|
|
|
* section (GLSL 1.10 section 5.4.1), not the "Implicit Conversions" rules.
|
2010-03-27 00:38:58 +00:00
|
|
|
*/
|
|
|
|
static ir_rvalue *
|
|
|
|
convert_component(ir_rvalue *src, const glsl_type *desired_type)
|
|
|
|
{
|
2011-01-21 22:32:31 +00:00
|
|
|
void *ctx = ralloc_parent(src);
|
2010-03-27 00:38:58 +00:00
|
|
|
const unsigned a = desired_type->base_type;
|
|
|
|
const unsigned b = src->type->base_type;
|
2010-06-07 23:08:04 +01:00
|
|
|
ir_expression *result = NULL;
|
2010-03-27 00:38:58 +00:00
|
|
|
|
|
|
|
if (src->type->is_error())
|
|
|
|
return src;
|
|
|
|
|
|
|
|
assert(a <= GLSL_TYPE_BOOL);
|
|
|
|
assert(b <= GLSL_TYPE_BOOL);
|
|
|
|
|
2011-06-15 07:23:49 +01:00
|
|
|
if (a == b)
|
2010-03-27 00:38:58 +00:00
|
|
|
return src;
|
|
|
|
|
|
|
|
switch (a) {
|
|
|
|
case GLSL_TYPE_UINT:
|
2011-06-15 07:23:49 +01:00
|
|
|
switch (b) {
|
|
|
|
case GLSL_TYPE_INT:
|
|
|
|
result = new(ctx) ir_expression(ir_unop_i2u, src);
|
|
|
|
break;
|
|
|
|
case GLSL_TYPE_FLOAT:
|
2012-06-13 23:50:23 +01:00
|
|
|
result = new(ctx) ir_expression(ir_unop_f2u, src);
|
2011-06-15 07:23:49 +01:00
|
|
|
break;
|
|
|
|
case GLSL_TYPE_BOOL:
|
|
|
|
result = new(ctx) ir_expression(ir_unop_i2u,
|
|
|
|
new(ctx) ir_expression(ir_unop_b2i, src));
|
|
|
|
break;
|
2015-02-05 10:04:58 +00:00
|
|
|
case GLSL_TYPE_DOUBLE:
|
|
|
|
result = new(ctx) ir_expression(ir_unop_d2u, src);
|
|
|
|
break;
|
2011-06-15 07:23:49 +01:00
|
|
|
}
|
|
|
|
break;
|
2010-03-27 00:38:58 +00:00
|
|
|
case GLSL_TYPE_INT:
|
2011-06-15 07:23:49 +01:00
|
|
|
switch (b) {
|
|
|
|
case GLSL_TYPE_UINT:
|
|
|
|
result = new(ctx) ir_expression(ir_unop_u2i, src);
|
|
|
|
break;
|
|
|
|
case GLSL_TYPE_FLOAT:
|
|
|
|
result = new(ctx) ir_expression(ir_unop_f2i, src);
|
|
|
|
break;
|
|
|
|
case GLSL_TYPE_BOOL:
|
|
|
|
result = new(ctx) ir_expression(ir_unop_b2i, src);
|
|
|
|
break;
|
2015-02-05 10:04:58 +00:00
|
|
|
case GLSL_TYPE_DOUBLE:
|
|
|
|
result = new(ctx) ir_expression(ir_unop_d2i, src);
|
|
|
|
break;
|
2010-03-27 00:38:58 +00:00
|
|
|
}
|
2010-06-11 21:49:00 +01:00
|
|
|
break;
|
2010-03-27 00:38:58 +00:00
|
|
|
case GLSL_TYPE_FLOAT:
|
|
|
|
switch (b) {
|
|
|
|
case GLSL_TYPE_UINT:
|
2010-06-24 02:11:51 +01:00
|
|
|
result = new(ctx) ir_expression(ir_unop_u2f, desired_type, src, NULL);
|
2010-06-07 23:08:04 +01:00
|
|
|
break;
|
2010-03-27 00:38:58 +00:00
|
|
|
case GLSL_TYPE_INT:
|
2010-06-24 02:11:51 +01:00
|
|
|
result = new(ctx) ir_expression(ir_unop_i2f, desired_type, src, NULL);
|
2010-06-07 23:08:04 +01:00
|
|
|
break;
|
2010-03-27 00:38:58 +00:00
|
|
|
case GLSL_TYPE_BOOL:
|
2010-06-24 02:11:51 +01:00
|
|
|
result = new(ctx) ir_expression(ir_unop_b2f, desired_type, src, NULL);
|
2010-06-07 23:08:04 +01:00
|
|
|
break;
|
2015-02-05 10:04:58 +00:00
|
|
|
case GLSL_TYPE_DOUBLE:
|
|
|
|
result = new(ctx) ir_expression(ir_unop_d2f, desired_type, src, NULL);
|
|
|
|
break;
|
2010-03-27 00:38:58 +00:00
|
|
|
}
|
|
|
|
break;
|
2010-06-26 00:19:45 +01:00
|
|
|
case GLSL_TYPE_BOOL:
|
2010-06-12 00:52:09 +01:00
|
|
|
switch (b) {
|
2010-06-26 00:19:45 +01:00
|
|
|
case GLSL_TYPE_UINT:
|
2011-06-15 07:23:49 +01:00
|
|
|
result = new(ctx) ir_expression(ir_unop_i2b,
|
|
|
|
new(ctx) ir_expression(ir_unop_u2i, src));
|
|
|
|
break;
|
2010-06-26 00:19:45 +01:00
|
|
|
case GLSL_TYPE_INT:
|
|
|
|
result = new(ctx) ir_expression(ir_unop_i2b, desired_type, src, NULL);
|
|
|
|
break;
|
|
|
|
case GLSL_TYPE_FLOAT:
|
|
|
|
result = new(ctx) ir_expression(ir_unop_f2b, desired_type, src, NULL);
|
|
|
|
break;
|
2015-02-05 10:04:58 +00:00
|
|
|
case GLSL_TYPE_DOUBLE:
|
|
|
|
result = new(ctx) ir_expression(ir_unop_d2b, desired_type, src, NULL);
|
|
|
|
break;
|
2010-06-12 00:52:09 +01:00
|
|
|
}
|
2010-06-26 00:19:45 +01:00
|
|
|
break;
|
2015-02-05 10:04:58 +00:00
|
|
|
case GLSL_TYPE_DOUBLE:
|
|
|
|
switch (b) {
|
|
|
|
case GLSL_TYPE_INT:
|
|
|
|
result = new(ctx) ir_expression(ir_unop_i2d, src);
|
|
|
|
break;
|
|
|
|
case GLSL_TYPE_UINT:
|
|
|
|
result = new(ctx) ir_expression(ir_unop_u2d, src);
|
|
|
|
break;
|
|
|
|
case GLSL_TYPE_BOOL:
|
|
|
|
result = new(ctx) ir_expression(ir_unop_f2d,
|
|
|
|
new(ctx) ir_expression(ir_unop_b2f, src));
|
|
|
|
break;
|
|
|
|
case GLSL_TYPE_FLOAT:
|
|
|
|
result = new(ctx) ir_expression(ir_unop_f2d, desired_type, src, NULL);
|
|
|
|
break;
|
|
|
|
}
|
2010-03-27 00:38:58 +00:00
|
|
|
}
|
|
|
|
|
2010-06-07 23:08:04 +01:00
|
|
|
assert(result != NULL);
|
2011-06-15 07:23:49 +01:00
|
|
|
assert(result->type == desired_type);
|
2010-06-07 23:08:04 +01:00
|
|
|
|
2010-07-20 07:45:23 +01:00
|
|
|
/* Try constant folding; it may fold in the conversion we just added. */
|
2010-06-07 23:08:04 +01:00
|
|
|
ir_constant *const constant = result->constant_expression_value();
|
|
|
|
return (constant != NULL) ? (ir_rvalue *) constant : (ir_rvalue *) result;
|
2010-03-27 00:38:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Dereference a specific component from a scalar, vector, or matrix
|
|
|
|
*/
|
|
|
|
static ir_rvalue *
|
|
|
|
dereference_component(ir_rvalue *src, unsigned component)
|
|
|
|
{
|
2011-01-21 22:32:31 +00:00
|
|
|
void *ctx = ralloc_parent(src);
|
2010-03-27 00:38:58 +00:00
|
|
|
assert(component < src->type->components());
|
|
|
|
|
2010-06-05 00:20:35 +01:00
|
|
|
/* If the source is a constant, just create a new constant instead of a
|
|
|
|
* dereference of the existing constant.
|
|
|
|
*/
|
|
|
|
ir_constant *constant = src->as_constant();
|
|
|
|
if (constant)
|
2010-06-24 02:11:51 +01:00
|
|
|
return new(ctx) ir_constant(constant, component);
|
2010-06-05 00:20:35 +01:00
|
|
|
|
2010-03-27 00:38:58 +00:00
|
|
|
if (src->type->is_scalar()) {
|
|
|
|
return src;
|
|
|
|
} else if (src->type->is_vector()) {
|
2010-06-24 02:11:51 +01:00
|
|
|
return new(ctx) ir_swizzle(src, component, 0, 0, 0, 1);
|
2010-03-27 00:38:58 +00:00
|
|
|
} else {
|
|
|
|
assert(src->type->is_matrix());
|
|
|
|
|
|
|
|
/* Dereference a row of the matrix, then call this function again to get
|
|
|
|
* a specific element from that row.
|
|
|
|
*/
|
|
|
|
const int c = component / src->type->column_type()->vector_elements;
|
|
|
|
const int r = component % src->type->column_type()->vector_elements;
|
2010-06-24 02:11:51 +01:00
|
|
|
ir_constant *const col_index = new(ctx) ir_constant(c);
|
|
|
|
ir_dereference *const col = new(ctx) ir_dereference_array(src, col_index);
|
2010-03-27 00:38:58 +00:00
|
|
|
|
|
|
|
col->type = src->type->column_type();
|
|
|
|
|
|
|
|
return dereference_component(col, r);
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(!"Should not get here.");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-06-29 23:45:46 +01:00
|
|
|
static ir_rvalue *
|
|
|
|
process_vec_mat_constructor(exec_list *instructions,
|
|
|
|
const glsl_type *constructor_type,
|
|
|
|
YYLTYPE *loc, exec_list *parameters,
|
|
|
|
struct _mesa_glsl_parse_state *state)
|
|
|
|
{
|
|
|
|
void *ctx = state;
|
|
|
|
|
|
|
|
/* The ARB_shading_language_420pack spec says:
|
|
|
|
*
|
|
|
|
* "If an initializer is a list of initializers enclosed in curly braces,
|
|
|
|
* the variable being declared must be a vector, a matrix, an array, or a
|
|
|
|
* structure.
|
|
|
|
*
|
|
|
|
* int i = { 1 }; // illegal, i is not an aggregate"
|
|
|
|
*/
|
|
|
|
if (constructor_type->vector_elements <= 1) {
|
2013-07-26 03:56:43 +01:00
|
|
|
_mesa_glsl_error(loc, state, "aggregates can only initialize vectors, "
|
2013-06-29 23:45:46 +01:00
|
|
|
"matrices, arrays, and structs");
|
|
|
|
return ir_rvalue::error_value(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
exec_list actual_parameters;
|
|
|
|
const unsigned parameter_count =
|
|
|
|
process_parameters(instructions, &actual_parameters, parameters, state);
|
|
|
|
|
|
|
|
if (parameter_count == 0
|
|
|
|
|| (constructor_type->is_vector() &&
|
|
|
|
constructor_type->vector_elements != parameter_count)
|
|
|
|
|| (constructor_type->is_matrix() &&
|
|
|
|
constructor_type->matrix_columns != parameter_count)) {
|
|
|
|
_mesa_glsl_error(loc, state, "%s constructor must have %u parameters",
|
|
|
|
constructor_type->is_vector() ? "vector" : "matrix",
|
|
|
|
constructor_type->vector_elements);
|
|
|
|
return ir_rvalue::error_value(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool all_parameters_are_constant = true;
|
|
|
|
|
|
|
|
/* Type cast each parameter and, if possible, fold constants. */
|
2014-06-25 05:58:35 +01:00
|
|
|
foreach_in_list_safe(ir_rvalue, ir, &actual_parameters) {
|
2013-06-29 23:45:46 +01:00
|
|
|
ir_rvalue *result = ir;
|
|
|
|
|
|
|
|
/* Apply implicit conversions (not the scalar constructor rules!). See
|
|
|
|
* the spec quote above. */
|
2015-02-05 10:04:58 +00:00
|
|
|
if (constructor_type->base_type != result->type->base_type) {
|
2013-06-29 23:45:46 +01:00
|
|
|
const glsl_type *desired_type =
|
2015-02-05 10:04:58 +00:00
|
|
|
glsl_type::get_instance(constructor_type->base_type,
|
2013-06-29 23:45:46 +01:00
|
|
|
ir->type->vector_elements,
|
|
|
|
ir->type->matrix_columns);
|
2014-05-04 09:23:57 +01:00
|
|
|
if (result->type->can_implicitly_convert_to(desired_type, state)) {
|
2013-06-29 23:45:46 +01:00
|
|
|
/* Even though convert_component() implements the constructor
|
|
|
|
* conversion rules (not the implicit conversion rules), its safe
|
|
|
|
* to use it here because we already checked that the implicit
|
|
|
|
* conversion is legal.
|
|
|
|
*/
|
|
|
|
result = convert_component(ir, desired_type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (constructor_type->is_matrix()) {
|
|
|
|
if (result->type != constructor_type->column_type()) {
|
|
|
|
_mesa_glsl_error(loc, state, "type error in matrix constructor: "
|
|
|
|
"expected: %s, found %s",
|
|
|
|
constructor_type->column_type()->name,
|
|
|
|
result->type->name);
|
|
|
|
return ir_rvalue::error_value(ctx);
|
|
|
|
}
|
|
|
|
} else if (result->type != constructor_type->get_scalar_type()) {
|
|
|
|
_mesa_glsl_error(loc, state, "type error in vector constructor: "
|
|
|
|
"expected: %s, found %s",
|
|
|
|
constructor_type->get_scalar_type()->name,
|
|
|
|
result->type->name);
|
|
|
|
return ir_rvalue::error_value(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Attempt to convert the parameter to a constant valued expression.
|
|
|
|
* After doing so, track whether or not all the parameters to the
|
|
|
|
* constructor are trivially constant valued expressions.
|
|
|
|
*/
|
|
|
|
ir_rvalue *const constant = result->constant_expression_value();
|
|
|
|
|
|
|
|
if (constant != NULL)
|
|
|
|
result = constant;
|
|
|
|
else
|
|
|
|
all_parameters_are_constant = false;
|
|
|
|
|
|
|
|
ir->replace_with(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (all_parameters_are_constant)
|
|
|
|
return new(ctx) ir_constant(constructor_type, &actual_parameters);
|
|
|
|
|
|
|
|
ir_variable *var = new(ctx) ir_variable(constructor_type, "vec_mat_ctor",
|
|
|
|
ir_var_temporary);
|
|
|
|
instructions->push_tail(var);
|
|
|
|
|
|
|
|
int i = 0;
|
2014-07-10 16:55:31 +01:00
|
|
|
|
2014-06-25 05:34:05 +01:00
|
|
|
foreach_in_list(ir_rvalue, rhs, &actual_parameters) {
|
2014-07-10 16:55:31 +01:00
|
|
|
ir_instruction *assignment = NULL;
|
|
|
|
|
|
|
|
if (var->type->is_matrix()) {
|
|
|
|
ir_rvalue *lhs = new(ctx) ir_dereference_array(var,
|
|
|
|
new(ctx) ir_constant(i));
|
|
|
|
assignment = new(ctx) ir_assignment(lhs, rhs, NULL);
|
|
|
|
} else {
|
|
|
|
/* use writemask rather than index for vector */
|
|
|
|
assert(var->type->is_vector());
|
|
|
|
assert(i < 4);
|
|
|
|
ir_dereference *lhs = new(ctx) ir_dereference_variable(var);
|
|
|
|
assignment = new(ctx) ir_assignment(lhs, rhs, NULL, (unsigned)(1 << i));
|
|
|
|
}
|
2013-06-29 23:45:46 +01:00
|
|
|
|
|
|
|
instructions->push_tail(assignment);
|
|
|
|
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return new(ctx) ir_dereference_variable(var);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-04-01 00:48:48 +01:00
|
|
|
static ir_rvalue *
|
|
|
|
process_array_constructor(exec_list *instructions,
|
|
|
|
const glsl_type *constructor_type,
|
2010-05-10 19:17:53 +01:00
|
|
|
YYLTYPE *loc, exec_list *parameters,
|
2010-04-01 00:48:48 +01:00
|
|
|
struct _mesa_glsl_parse_state *state)
|
|
|
|
{
|
2010-06-25 21:14:37 +01:00
|
|
|
void *ctx = state;
|
2010-04-01 00:48:48 +01:00
|
|
|
/* Array constructors come in two forms: sized and unsized. Sized array
|
|
|
|
* constructors look like 'vec4[2](a, b)', where 'a' and 'b' are vec4
|
|
|
|
* variables. In this case the number of parameters must exactly match the
|
|
|
|
* specified size of the array.
|
|
|
|
*
|
|
|
|
* Unsized array constructors look like 'vec4[](a, b)', where 'a' and 'b'
|
|
|
|
* are vec4 variables. In this case the size of the array being constructed
|
|
|
|
* is determined by the number of parameters.
|
|
|
|
*
|
|
|
|
* From page 52 (page 58 of the PDF) of the GLSL 1.50 spec:
|
|
|
|
*
|
|
|
|
* "There must be exactly the same number of arguments as the size of
|
|
|
|
* the array being constructed. If no size is present in the
|
|
|
|
* constructor, then the array is explicitly sized to the number of
|
|
|
|
* arguments provided. The arguments are assigned in order, starting at
|
|
|
|
* element 0, to the elements of the constructed array. Each argument
|
|
|
|
* must be the same type as the element type of the array, or be a type
|
|
|
|
* that can be converted to the element type of the array according to
|
|
|
|
* Section 4.1.10 "Implicit Conversions.""
|
|
|
|
*/
|
|
|
|
exec_list actual_parameters;
|
|
|
|
const unsigned parameter_count =
|
|
|
|
process_parameters(instructions, &actual_parameters, parameters, state);
|
2013-10-23 11:31:27 +01:00
|
|
|
bool is_unsized_array = constructor_type->is_unsized_array();
|
2010-04-01 00:48:48 +01:00
|
|
|
|
2013-10-23 11:31:27 +01:00
|
|
|
if ((parameter_count == 0) ||
|
|
|
|
(!is_unsized_array && (constructor_type->length != parameter_count))) {
|
|
|
|
const unsigned min_param = is_unsized_array
|
|
|
|
? 1 : constructor_type->length;
|
2010-04-01 00:48:48 +01:00
|
|
|
|
|
|
|
_mesa_glsl_error(loc, state, "array constructor must have %s %u "
|
|
|
|
"parameter%s",
|
2013-10-23 11:31:27 +01:00
|
|
|
is_unsized_array ? "at least" : "exactly",
|
2010-04-01 00:48:48 +01:00
|
|
|
min_param, (min_param <= 1) ? "" : "s");
|
2011-09-22 23:04:56 +01:00
|
|
|
return ir_rvalue::error_value(ctx);
|
2010-04-01 00:48:48 +01:00
|
|
|
}
|
|
|
|
|
2013-10-23 11:31:27 +01:00
|
|
|
if (is_unsized_array) {
|
2010-04-01 00:48:48 +01:00
|
|
|
constructor_type =
|
2010-07-20 23:33:40 +01:00
|
|
|
glsl_type::get_array_instance(constructor_type->element_type(),
|
2010-04-01 00:48:48 +01:00
|
|
|
parameter_count);
|
|
|
|
assert(constructor_type != NULL);
|
|
|
|
assert(constructor_type->length == parameter_count);
|
|
|
|
}
|
|
|
|
|
2010-07-20 07:49:58 +01:00
|
|
|
bool all_parameters_are_constant = true;
|
2010-04-01 00:48:48 +01:00
|
|
|
|
2010-07-20 07:49:58 +01:00
|
|
|
/* Type cast each parameter and, if possible, fold constants. */
|
2014-06-25 05:58:35 +01:00
|
|
|
foreach_in_list_safe(ir_rvalue, ir, &actual_parameters) {
|
2010-07-20 07:49:58 +01:00
|
|
|
ir_rvalue *result = ir;
|
|
|
|
|
2015-02-05 10:04:58 +00:00
|
|
|
const glsl_base_type element_base_type =
|
|
|
|
constructor_type->element_type()->base_type;
|
|
|
|
|
2011-07-27 21:00:02 +01:00
|
|
|
/* Apply implicit conversions (not the scalar constructor rules!). See
|
|
|
|
* the spec quote above. */
|
2015-02-05 10:04:58 +00:00
|
|
|
if (element_base_type != result->type->base_type) {
|
|
|
|
const glsl_type *desired_type =
|
|
|
|
glsl_type::get_instance(element_base_type,
|
|
|
|
ir->type->vector_elements,
|
|
|
|
ir->type->matrix_columns);
|
|
|
|
|
2014-05-04 09:23:57 +01:00
|
|
|
if (result->type->can_implicitly_convert_to(desired_type, state)) {
|
2011-07-27 21:00:02 +01:00
|
|
|
/* Even though convert_component() implements the constructor
|
|
|
|
* conversion rules (not the implicit conversion rules), its safe
|
|
|
|
* to use it here because we already checked that the implicit
|
|
|
|
* conversion is legal.
|
|
|
|
*/
|
|
|
|
result = convert_component(ir, desired_type);
|
|
|
|
}
|
2010-07-20 07:49:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (result->type != constructor_type->element_type()) {
|
|
|
|
_mesa_glsl_error(loc, state, "type error in array constructor: "
|
|
|
|
"expected: %s, found %s",
|
|
|
|
constructor_type->element_type()->name,
|
|
|
|
result->type->name);
|
2013-06-29 23:32:09 +01:00
|
|
|
return ir_rvalue::error_value(ctx);
|
2010-07-20 07:49:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Attempt to convert the parameter to a constant valued expression.
|
|
|
|
* After doing so, track whether or not all the parameters to the
|
|
|
|
* constructor are trivially constant valued expressions.
|
|
|
|
*/
|
|
|
|
ir_rvalue *const constant = result->constant_expression_value();
|
|
|
|
|
|
|
|
if (constant != NULL)
|
|
|
|
result = constant;
|
|
|
|
else
|
|
|
|
all_parameters_are_constant = false;
|
|
|
|
|
|
|
|
ir->replace_with(result);
|
|
|
|
}
|
|
|
|
|
2010-07-20 09:06:33 +01:00
|
|
|
if (all_parameters_are_constant)
|
|
|
|
return new(ctx) ir_constant(constructor_type, &actual_parameters);
|
2010-04-01 00:48:48 +01:00
|
|
|
|
2010-07-20 07:49:58 +01:00
|
|
|
ir_variable *var = new(ctx) ir_variable(constructor_type, "array_ctor",
|
|
|
|
ir_var_temporary);
|
|
|
|
instructions->push_tail(var);
|
|
|
|
|
|
|
|
int i = 0;
|
2014-06-25 05:34:05 +01:00
|
|
|
foreach_in_list(ir_rvalue, rhs, &actual_parameters) {
|
2010-07-20 07:49:58 +01:00
|
|
|
ir_rvalue *lhs = new(ctx) ir_dereference_array(var,
|
|
|
|
new(ctx) ir_constant(i));
|
2010-04-01 00:48:48 +01:00
|
|
|
|
2010-07-20 07:49:58 +01:00
|
|
|
ir_instruction *assignment = new(ctx) ir_assignment(lhs, rhs, NULL);
|
|
|
|
instructions->push_tail(assignment);
|
|
|
|
|
|
|
|
i++;
|
|
|
|
}
|
2010-04-01 00:48:48 +01:00
|
|
|
|
2010-07-20 07:49:58 +01:00
|
|
|
return new(ctx) ir_dereference_variable(var);
|
2010-04-01 00:48:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-06-10 01:26:20 +01:00
|
|
|
/**
|
|
|
|
* Try to convert a record constructor to a constant expression
|
|
|
|
*/
|
|
|
|
static ir_constant *
|
|
|
|
constant_record_constructor(const glsl_type *constructor_type,
|
2010-09-01 21:46:04 +01:00
|
|
|
exec_list *parameters, void *mem_ctx)
|
2010-06-10 01:26:20 +01:00
|
|
|
{
|
2014-06-25 05:34:05 +01:00
|
|
|
foreach_in_list(ir_instruction, node, parameters) {
|
|
|
|
ir_constant *constant = node->as_constant();
|
2010-09-02 03:54:27 +01:00
|
|
|
if (constant == NULL)
|
2010-06-10 01:26:20 +01:00
|
|
|
return NULL;
|
2010-09-02 03:54:27 +01:00
|
|
|
node->replace_with(constant);
|
2010-06-10 01:26:20 +01:00
|
|
|
}
|
|
|
|
|
2010-09-01 21:46:04 +01:00
|
|
|
return new(mem_ctx) ir_constant(constructor_type, parameters);
|
2010-06-10 01:26:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-06-23 23:19:40 +01:00
|
|
|
/**
|
|
|
|
* Determine if a list consists of a single scalar r-value
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
single_scalar_parameter(exec_list *parameters)
|
|
|
|
{
|
|
|
|
const ir_rvalue *const p = (ir_rvalue *) parameters->head;
|
|
|
|
assert(((ir_rvalue *)p)->as_rvalue() != NULL);
|
|
|
|
|
2010-07-29 21:52:25 +01:00
|
|
|
return (p->type->is_scalar() && p->next->is_tail_sentinel());
|
2010-06-23 23:19:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generate inline code for a vector constructor
|
|
|
|
*
|
|
|
|
* The generated constructor code will consist of a temporary variable
|
|
|
|
* declaration of the same type as the constructor. A sequence of assignments
|
|
|
|
* from constructor parameters to the temporary will follow.
|
|
|
|
*
|
|
|
|
* \return
|
|
|
|
* An \c ir_dereference_variable of the temprorary generated in the constructor
|
|
|
|
* body.
|
|
|
|
*/
|
|
|
|
ir_rvalue *
|
|
|
|
emit_inline_vector_constructor(const glsl_type *type,
|
|
|
|
exec_list *instructions,
|
|
|
|
exec_list *parameters,
|
|
|
|
void *ctx)
|
|
|
|
{
|
|
|
|
assert(!parameters->is_empty());
|
|
|
|
|
2010-08-03 19:40:26 +01:00
|
|
|
ir_variable *var = new(ctx) ir_variable(type, "vec_ctor", ir_var_temporary);
|
2010-06-23 23:19:40 +01:00
|
|
|
instructions->push_tail(var);
|
|
|
|
|
|
|
|
/* There are two kinds of vector constructors.
|
|
|
|
*
|
|
|
|
* - Construct a vector from a single scalar by replicating that scalar to
|
|
|
|
* all components of the vector.
|
|
|
|
*
|
|
|
|
* - Construct a vector from an arbirary combination of vectors and
|
|
|
|
* scalars. The components of the constructor parameters are assigned
|
|
|
|
* to the vector in order until the vector is full.
|
|
|
|
*/
|
|
|
|
const unsigned lhs_components = type->components();
|
|
|
|
if (single_scalar_parameter(parameters)) {
|
|
|
|
ir_rvalue *first_param = (ir_rvalue *)parameters->head;
|
|
|
|
ir_rvalue *rhs = new(ctx) ir_swizzle(first_param, 0, 0, 0, 0,
|
|
|
|
lhs_components);
|
|
|
|
ir_dereference_variable *lhs = new(ctx) ir_dereference_variable(var);
|
2010-08-04 00:05:54 +01:00
|
|
|
const unsigned mask = (1U << lhs_components) - 1;
|
2010-06-23 23:19:40 +01:00
|
|
|
|
|
|
|
assert(rhs->type == lhs->type);
|
|
|
|
|
2010-08-04 00:05:54 +01:00
|
|
|
ir_instruction *inst = new(ctx) ir_assignment(lhs, rhs, NULL, mask);
|
2010-06-23 23:19:40 +01:00
|
|
|
instructions->push_tail(inst);
|
|
|
|
} else {
|
|
|
|
unsigned base_component = 0;
|
2010-09-22 19:47:03 +01:00
|
|
|
unsigned base_lhs_component = 0;
|
2010-08-31 22:44:13 +01:00
|
|
|
ir_constant_data data;
|
2010-09-22 19:47:03 +01:00
|
|
|
unsigned constant_mask = 0, constant_components = 0;
|
2010-08-31 22:44:13 +01:00
|
|
|
|
|
|
|
memset(&data, 0, sizeof(data));
|
|
|
|
|
2014-06-25 05:34:05 +01:00
|
|
|
foreach_in_list(ir_rvalue, param, parameters) {
|
2010-08-04 00:05:54 +01:00
|
|
|
unsigned rhs_components = param->type->components();
|
2010-06-23 23:19:40 +01:00
|
|
|
|
|
|
|
/* Do not try to assign more components to the vector than it has!
|
|
|
|
*/
|
2010-09-22 19:47:03 +01:00
|
|
|
if ((rhs_components + base_lhs_component) > lhs_components) {
|
|
|
|
rhs_components = lhs_components - base_lhs_component;
|
2010-06-23 23:19:40 +01:00
|
|
|
}
|
|
|
|
|
2010-08-31 22:44:13 +01:00
|
|
|
const ir_constant *const c = param->as_constant();
|
|
|
|
if (c != NULL) {
|
|
|
|
for (unsigned i = 0; i < rhs_components; i++) {
|
|
|
|
switch (c->type->base_type) {
|
|
|
|
case GLSL_TYPE_UINT:
|
|
|
|
data.u[i + base_component] = c->get_uint_component(i);
|
|
|
|
break;
|
|
|
|
case GLSL_TYPE_INT:
|
|
|
|
data.i[i + base_component] = c->get_int_component(i);
|
|
|
|
break;
|
|
|
|
case GLSL_TYPE_FLOAT:
|
|
|
|
data.f[i + base_component] = c->get_float_component(i);
|
|
|
|
break;
|
2015-02-05 10:04:58 +00:00
|
|
|
case GLSL_TYPE_DOUBLE:
|
|
|
|
data.d[i + base_component] = c->get_double_component(i);
|
|
|
|
break;
|
2010-08-31 22:44:13 +01:00
|
|
|
case GLSL_TYPE_BOOL:
|
|
|
|
data.b[i + base_component] = c->get_bool_component(i);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(!"Should not get here.");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Mask of fields to be written in the assignment.
|
|
|
|
*/
|
2010-09-22 19:47:03 +01:00
|
|
|
constant_mask |= ((1U << rhs_components) - 1) << base_lhs_component;
|
2010-10-25 20:44:55 +01:00
|
|
|
constant_components += rhs_components;
|
2010-06-23 23:19:40 +01:00
|
|
|
|
2010-09-22 19:47:03 +01:00
|
|
|
base_component += rhs_components;
|
|
|
|
}
|
|
|
|
/* Advance the component index by the number of components
|
|
|
|
* that were just assigned.
|
2010-08-04 00:05:54 +01:00
|
|
|
*/
|
2010-09-22 19:47:03 +01:00
|
|
|
base_lhs_component += rhs_components;
|
2010-08-31 22:44:13 +01:00
|
|
|
}
|
2010-06-23 23:19:40 +01:00
|
|
|
|
2010-08-31 22:44:13 +01:00
|
|
|
if (constant_mask != 0) {
|
2010-08-04 00:05:54 +01:00
|
|
|
ir_dereference *lhs = new(ctx) ir_dereference_variable(var);
|
2010-09-22 19:47:03 +01:00
|
|
|
const glsl_type *rhs_type = glsl_type::get_instance(var->type->base_type,
|
|
|
|
constant_components,
|
|
|
|
1);
|
|
|
|
ir_rvalue *rhs = new(ctx) ir_constant(rhs_type, &data);
|
2010-06-23 23:19:40 +01:00
|
|
|
|
2010-08-04 00:05:54 +01:00
|
|
|
ir_instruction *inst =
|
2010-08-31 22:44:13 +01:00
|
|
|
new(ctx) ir_assignment(lhs, rhs, NULL, constant_mask);
|
2010-06-23 23:19:40 +01:00
|
|
|
instructions->push_tail(inst);
|
2010-08-31 22:44:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
base_component = 0;
|
2014-06-25 05:34:05 +01:00
|
|
|
foreach_in_list(ir_rvalue, param, parameters) {
|
2010-08-31 22:44:13 +01:00
|
|
|
unsigned rhs_components = param->type->components();
|
|
|
|
|
|
|
|
/* Do not try to assign more components to the vector than it has!
|
|
|
|
*/
|
|
|
|
if ((rhs_components + base_component) > lhs_components) {
|
|
|
|
rhs_components = lhs_components - base_component;
|
|
|
|
}
|
|
|
|
|
|
|
|
const ir_constant *const c = param->as_constant();
|
|
|
|
if (c == NULL) {
|
|
|
|
/* Mask of fields to be written in the assignment.
|
|
|
|
*/
|
|
|
|
const unsigned write_mask = ((1U << rhs_components) - 1)
|
|
|
|
<< base_component;
|
|
|
|
|
|
|
|
ir_dereference *lhs = new(ctx) ir_dereference_variable(var);
|
2010-11-15 21:41:06 +00:00
|
|
|
|
|
|
|
/* Generate a swizzle so that LHS and RHS sizes match.
|
|
|
|
*/
|
|
|
|
ir_rvalue *rhs =
|
|
|
|
new(ctx) ir_swizzle(param, 0, 1, 2, 3, rhs_components);
|
2010-08-31 22:44:13 +01:00
|
|
|
|
|
|
|
ir_instruction *inst =
|
|
|
|
new(ctx) ir_assignment(lhs, rhs, NULL, write_mask);
|
|
|
|
instructions->push_tail(inst);
|
|
|
|
}
|
2010-06-23 23:19:40 +01:00
|
|
|
|
|
|
|
/* Advance the component index by the number of components that were
|
|
|
|
* just assigned.
|
|
|
|
*/
|
|
|
|
base_component += rhs_components;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return new(ctx) ir_dereference_variable(var);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-06-26 00:10:43 +01:00
|
|
|
/**
|
|
|
|
* Generate assignment of a portion of a vector to a portion of a matrix column
|
|
|
|
*
|
|
|
|
* \param src_base First component of the source to be used in assignment
|
|
|
|
* \param column Column of destination to be assiged
|
|
|
|
* \param row_base First component of the destination column to be assigned
|
|
|
|
* \param count Number of components to be assigned
|
|
|
|
*
|
|
|
|
* \note
|
|
|
|
* \c src_base + \c count must be less than or equal to the number of components
|
|
|
|
* in the source vector.
|
|
|
|
*/
|
|
|
|
ir_instruction *
|
|
|
|
assign_to_matrix_column(ir_variable *var, unsigned column, unsigned row_base,
|
|
|
|
ir_rvalue *src, unsigned src_base, unsigned count,
|
2010-08-04 04:05:53 +01:00
|
|
|
void *mem_ctx)
|
2010-06-26 00:10:43 +01:00
|
|
|
{
|
2010-08-04 04:05:53 +01:00
|
|
|
ir_constant *col_idx = new(mem_ctx) ir_constant(column);
|
2010-08-04 00:05:54 +01:00
|
|
|
ir_dereference *column_ref = new(mem_ctx) ir_dereference_array(var, col_idx);
|
2010-06-26 00:10:43 +01:00
|
|
|
|
|
|
|
assert(column_ref->type->components() >= (row_base + count));
|
|
|
|
assert(src->type->components() >= (src_base + count));
|
|
|
|
|
2010-11-20 01:16:12 +00:00
|
|
|
/* Generate a swizzle that extracts the number of components from the source
|
|
|
|
* that are to be assigned to the column of the matrix.
|
2010-08-04 00:05:54 +01:00
|
|
|
*/
|
2010-11-20 01:16:12 +00:00
|
|
|
if (count < src->type->vector_elements) {
|
|
|
|
src = new(mem_ctx) ir_swizzle(src,
|
|
|
|
src_base + 0, src_base + 1,
|
|
|
|
src_base + 2, src_base + 3,
|
|
|
|
count);
|
|
|
|
}
|
2010-08-04 00:05:54 +01:00
|
|
|
|
|
|
|
/* Mask of fields to be written in the assignment.
|
|
|
|
*/
|
|
|
|
const unsigned write_mask = ((1U << count) - 1) << row_base;
|
|
|
|
|
2010-11-20 01:16:12 +00:00
|
|
|
return new(mem_ctx) ir_assignment(column_ref, src, NULL, write_mask);
|
2010-06-26 00:10:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generate inline code for a matrix constructor
|
|
|
|
*
|
|
|
|
* The generated constructor code will consist of a temporary variable
|
|
|
|
* declaration of the same type as the constructor. A sequence of assignments
|
|
|
|
* from constructor parameters to the temporary will follow.
|
|
|
|
*
|
|
|
|
* \return
|
|
|
|
* An \c ir_dereference_variable of the temprorary generated in the constructor
|
|
|
|
* body.
|
|
|
|
*/
|
|
|
|
ir_rvalue *
|
|
|
|
emit_inline_matrix_constructor(const glsl_type *type,
|
|
|
|
exec_list *instructions,
|
|
|
|
exec_list *parameters,
|
|
|
|
void *ctx)
|
|
|
|
{
|
|
|
|
assert(!parameters->is_empty());
|
|
|
|
|
2010-08-03 19:40:26 +01:00
|
|
|
ir_variable *var = new(ctx) ir_variable(type, "mat_ctor", ir_var_temporary);
|
2010-06-26 00:10:43 +01:00
|
|
|
instructions->push_tail(var);
|
|
|
|
|
|
|
|
/* There are three kinds of matrix constructors.
|
|
|
|
*
|
|
|
|
* - Construct a matrix from a single scalar by replicating that scalar to
|
|
|
|
* along the diagonal of the matrix and setting all other components to
|
|
|
|
* zero.
|
|
|
|
*
|
|
|
|
* - Construct a matrix from an arbirary combination of vectors and
|
|
|
|
* scalars. The components of the constructor parameters are assigned
|
|
|
|
* to the matrix in colum-major order until the matrix is full.
|
|
|
|
*
|
|
|
|
* - Construct a matrix from a single matrix. The source matrix is copied
|
|
|
|
* to the upper left portion of the constructed matrix, and the remaining
|
|
|
|
* elements take values from the identity matrix.
|
|
|
|
*/
|
|
|
|
ir_rvalue *const first_param = (ir_rvalue *) parameters->head;
|
|
|
|
if (single_scalar_parameter(parameters)) {
|
|
|
|
/* Assign the scalar to the X component of a vec4, and fill the remaining
|
|
|
|
* components with zero.
|
|
|
|
*/
|
2015-02-05 10:04:58 +00:00
|
|
|
glsl_base_type param_base_type = first_param->type->base_type;
|
|
|
|
assert(param_base_type == GLSL_TYPE_FLOAT ||
|
|
|
|
param_base_type == GLSL_TYPE_DOUBLE);
|
2010-06-28 21:22:55 +01:00
|
|
|
ir_variable *rhs_var =
|
2015-02-05 10:04:58 +00:00
|
|
|
new(ctx) ir_variable(glsl_type::get_instance(param_base_type, 4, 1),
|
|
|
|
"mat_ctor_vec",
|
|
|
|
ir_var_temporary);
|
2010-06-26 00:10:43 +01:00
|
|
|
instructions->push_tail(rhs_var);
|
|
|
|
|
|
|
|
ir_constant_data zero;
|
2015-02-05 10:04:58 +00:00
|
|
|
for (unsigned i = 0; i < 4; i++)
|
|
|
|
if (param_base_type == GLSL_TYPE_FLOAT)
|
|
|
|
zero.f[i] = 0.0;
|
|
|
|
else
|
|
|
|
zero.d[i] = 0.0;
|
2010-06-26 00:10:43 +01:00
|
|
|
|
|
|
|
ir_instruction *inst =
|
|
|
|
new(ctx) ir_assignment(new(ctx) ir_dereference_variable(rhs_var),
|
|
|
|
new(ctx) ir_constant(rhs_var->type, &zero),
|
|
|
|
NULL);
|
|
|
|
instructions->push_tail(inst);
|
|
|
|
|
2010-08-04 00:05:54 +01:00
|
|
|
ir_dereference *const rhs_ref = new(ctx) ir_dereference_variable(rhs_var);
|
2010-06-26 00:10:43 +01:00
|
|
|
|
2010-08-04 00:05:54 +01:00
|
|
|
inst = new(ctx) ir_assignment(rhs_ref, first_param, NULL, 0x01);
|
2010-06-26 00:10:43 +01:00
|
|
|
instructions->push_tail(inst);
|
|
|
|
|
|
|
|
/* Assign the temporary vector to each column of the destination matrix
|
|
|
|
* with a swizzle that puts the X component on the diagonal of the
|
|
|
|
* matrix. In some cases this may mean that the X component does not
|
|
|
|
* get assigned into the column at all (i.e., when the matrix has more
|
|
|
|
* columns than rows).
|
|
|
|
*/
|
|
|
|
static const unsigned rhs_swiz[4][4] = {
|
|
|
|
{ 0, 1, 1, 1 },
|
|
|
|
{ 1, 0, 1, 1 },
|
|
|
|
{ 1, 1, 0, 1 },
|
|
|
|
{ 1, 1, 1, 0 }
|
|
|
|
};
|
|
|
|
|
2010-08-13 02:00:35 +01:00
|
|
|
const unsigned cols_to_init = MIN2(type->matrix_columns,
|
|
|
|
type->vector_elements);
|
2010-06-26 00:10:43 +01:00
|
|
|
for (unsigned i = 0; i < cols_to_init; i++) {
|
|
|
|
ir_constant *const col_idx = new(ctx) ir_constant(i);
|
|
|
|
ir_rvalue *const col_ref = new(ctx) ir_dereference_array(var, col_idx);
|
|
|
|
|
|
|
|
ir_rvalue *const rhs_ref = new(ctx) ir_dereference_variable(rhs_var);
|
|
|
|
ir_rvalue *const rhs = new(ctx) ir_swizzle(rhs_ref, rhs_swiz[i],
|
|
|
|
type->vector_elements);
|
|
|
|
|
|
|
|
inst = new(ctx) ir_assignment(col_ref, rhs, NULL);
|
|
|
|
instructions->push_tail(inst);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (unsigned i = cols_to_init; i < type->matrix_columns; i++) {
|
|
|
|
ir_constant *const col_idx = new(ctx) ir_constant(i);
|
|
|
|
ir_rvalue *const col_ref = new(ctx) ir_dereference_array(var, col_idx);
|
|
|
|
|
|
|
|
ir_rvalue *const rhs_ref = new(ctx) ir_dereference_variable(rhs_var);
|
|
|
|
ir_rvalue *const rhs = new(ctx) ir_swizzle(rhs_ref, 1, 1, 1, 1,
|
|
|
|
type->vector_elements);
|
|
|
|
|
|
|
|
inst = new(ctx) ir_assignment(col_ref, rhs, NULL);
|
|
|
|
instructions->push_tail(inst);
|
|
|
|
}
|
|
|
|
} else if (first_param->type->is_matrix()) {
|
|
|
|
/* From page 50 (56 of the PDF) of the GLSL 1.50 spec:
|
|
|
|
*
|
|
|
|
* "If a matrix is constructed from a matrix, then each component
|
|
|
|
* (column i, row j) in the result that has a corresponding
|
|
|
|
* component (column i, row j) in the argument will be initialized
|
|
|
|
* from there. All other components will be initialized to the
|
|
|
|
* identity matrix. If a matrix argument is given to a matrix
|
|
|
|
* constructor, it is an error to have any other arguments."
|
|
|
|
*/
|
2010-07-29 21:52:25 +01:00
|
|
|
assert(first_param->next->is_tail_sentinel());
|
2010-06-26 00:10:43 +01:00
|
|
|
ir_rvalue *const src_matrix = first_param;
|
|
|
|
|
|
|
|
/* If the source matrix is smaller, pre-initialize the relavent parts of
|
|
|
|
* the destination matrix to the identity matrix.
|
|
|
|
*/
|
|
|
|
if ((src_matrix->type->matrix_columns < var->type->matrix_columns)
|
|
|
|
|| (src_matrix->type->vector_elements < var->type->vector_elements)) {
|
|
|
|
|
|
|
|
/* If the source matrix has fewer rows, every column of the destination
|
|
|
|
* must be initialized. Otherwise only the columns in the destination
|
|
|
|
* that do not exist in the source must be initialized.
|
|
|
|
*/
|
|
|
|
unsigned col =
|
|
|
|
(src_matrix->type->vector_elements < var->type->vector_elements)
|
|
|
|
? 0 : src_matrix->type->matrix_columns;
|
|
|
|
|
|
|
|
const glsl_type *const col_type = var->type->column_type();
|
|
|
|
for (/* empty */; col < var->type->matrix_columns; col++) {
|
|
|
|
ir_constant_data ident;
|
|
|
|
|
|
|
|
ident.f[0] = 0.0;
|
|
|
|
ident.f[1] = 0.0;
|
|
|
|
ident.f[2] = 0.0;
|
|
|
|
ident.f[3] = 0.0;
|
|
|
|
|
|
|
|
ident.f[col] = 1.0;
|
|
|
|
|
|
|
|
ir_rvalue *const rhs = new(ctx) ir_constant(col_type, &ident);
|
|
|
|
|
|
|
|
ir_rvalue *const lhs =
|
|
|
|
new(ctx) ir_dereference_array(var, new(ctx) ir_constant(col));
|
|
|
|
|
|
|
|
ir_instruction *inst = new(ctx) ir_assignment(lhs, rhs, NULL);
|
|
|
|
instructions->push_tail(inst);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Assign columns from the source matrix to the destination matrix.
|
|
|
|
*
|
|
|
|
* Since the parameter will be used in the RHS of multiple assignments,
|
|
|
|
* generate a temporary and copy the paramter there.
|
|
|
|
*/
|
2010-06-28 21:22:55 +01:00
|
|
|
ir_variable *const rhs_var =
|
2010-08-03 19:40:26 +01:00
|
|
|
new(ctx) ir_variable(first_param->type, "mat_ctor_mat",
|
2010-07-20 01:12:42 +01:00
|
|
|
ir_var_temporary);
|
2010-06-26 00:10:43 +01:00
|
|
|
instructions->push_tail(rhs_var);
|
|
|
|
|
|
|
|
ir_dereference *const rhs_var_ref =
|
|
|
|
new(ctx) ir_dereference_variable(rhs_var);
|
|
|
|
ir_instruction *const inst =
|
|
|
|
new(ctx) ir_assignment(rhs_var_ref, first_param, NULL);
|
|
|
|
instructions->push_tail(inst);
|
|
|
|
|
2010-09-02 00:10:01 +01:00
|
|
|
const unsigned last_row = MIN2(src_matrix->type->vector_elements,
|
|
|
|
var->type->vector_elements);
|
|
|
|
const unsigned last_col = MIN2(src_matrix->type->matrix_columns,
|
|
|
|
var->type->matrix_columns);
|
2010-06-26 00:10:43 +01:00
|
|
|
|
2010-08-04 00:05:54 +01:00
|
|
|
unsigned swiz[4] = { 0, 0, 0, 0 };
|
2010-09-22 19:47:03 +01:00
|
|
|
for (unsigned i = 1; i < last_row; i++)
|
2010-08-04 00:05:54 +01:00
|
|
|
swiz[i] = i;
|
|
|
|
|
2010-09-02 00:10:01 +01:00
|
|
|
const unsigned write_mask = (1U << last_row) - 1;
|
2010-08-04 00:05:54 +01:00
|
|
|
|
2010-06-26 00:10:43 +01:00
|
|
|
for (unsigned i = 0; i < last_col; i++) {
|
2010-08-04 00:05:54 +01:00
|
|
|
ir_dereference *const lhs =
|
2010-06-26 00:10:43 +01:00
|
|
|
new(ctx) ir_dereference_array(var, new(ctx) ir_constant(i));
|
|
|
|
ir_rvalue *const rhs_col =
|
|
|
|
new(ctx) ir_dereference_array(rhs_var, new(ctx) ir_constant(i));
|
|
|
|
|
|
|
|
/* If one matrix has columns that are smaller than the columns of the
|
|
|
|
* other matrix, wrap the column access of the larger with a swizzle
|
|
|
|
* so that the LHS and RHS of the assignment have the same size (and
|
|
|
|
* therefore have the same type).
|
|
|
|
*
|
|
|
|
* It would be perfectly valid to unconditionally generate the
|
|
|
|
* swizzles, this this will typically result in a more compact IR tree.
|
|
|
|
*/
|
|
|
|
ir_rvalue *rhs;
|
2010-08-04 00:05:54 +01:00
|
|
|
if (lhs->type->vector_elements != rhs_col->type->vector_elements) {
|
2010-09-22 19:47:03 +01:00
|
|
|
rhs = new(ctx) ir_swizzle(rhs_col, swiz, last_row);
|
2010-06-26 00:10:43 +01:00
|
|
|
} else {
|
|
|
|
rhs = rhs_col;
|
|
|
|
}
|
|
|
|
|
2010-08-04 00:05:54 +01:00
|
|
|
ir_instruction *inst =
|
|
|
|
new(ctx) ir_assignment(lhs, rhs, NULL, write_mask);
|
2010-06-26 00:10:43 +01:00
|
|
|
instructions->push_tail(inst);
|
|
|
|
}
|
|
|
|
} else {
|
2010-08-17 23:57:48 +01:00
|
|
|
const unsigned cols = type->matrix_columns;
|
|
|
|
const unsigned rows = type->vector_elements;
|
2010-06-26 00:10:43 +01:00
|
|
|
unsigned col_idx = 0;
|
|
|
|
unsigned row_idx = 0;
|
|
|
|
|
2014-06-25 05:34:05 +01:00
|
|
|
foreach_in_list(ir_rvalue, rhs, parameters) {
|
2010-06-26 00:10:43 +01:00
|
|
|
const unsigned components_remaining_this_column = rows - row_idx;
|
|
|
|
unsigned rhs_components = rhs->type->components();
|
|
|
|
unsigned rhs_base = 0;
|
|
|
|
|
|
|
|
/* Since the parameter might be used in the RHS of two assignments,
|
|
|
|
* generate a temporary and copy the paramter there.
|
|
|
|
*/
|
2010-06-28 21:22:55 +01:00
|
|
|
ir_variable *rhs_var =
|
2010-08-03 19:40:26 +01:00
|
|
|
new(ctx) ir_variable(rhs->type, "mat_ctor_vec", ir_var_temporary);
|
2010-06-26 00:10:43 +01:00
|
|
|
instructions->push_tail(rhs_var);
|
|
|
|
|
|
|
|
ir_dereference *rhs_var_ref =
|
|
|
|
new(ctx) ir_dereference_variable(rhs_var);
|
|
|
|
ir_instruction *inst = new(ctx) ir_assignment(rhs_var_ref, rhs, NULL);
|
|
|
|
instructions->push_tail(inst);
|
|
|
|
|
|
|
|
/* Assign the current parameter to as many components of the matrix
|
|
|
|
* as it will fill.
|
|
|
|
*
|
|
|
|
* NOTE: A single vector parameter can span two matrix columns. A
|
|
|
|
* single vec4, for example, can completely fill a mat2.
|
|
|
|
*/
|
|
|
|
if (rhs_components >= components_remaining_this_column) {
|
2010-08-13 02:00:35 +01:00
|
|
|
const unsigned count = MIN2(rhs_components,
|
|
|
|
components_remaining_this_column);
|
2010-06-26 00:10:43 +01:00
|
|
|
|
|
|
|
rhs_var_ref = new(ctx) ir_dereference_variable(rhs_var);
|
|
|
|
|
|
|
|
ir_instruction *inst = assign_to_matrix_column(var, col_idx,
|
|
|
|
row_idx,
|
|
|
|
rhs_var_ref, 0,
|
|
|
|
count, ctx);
|
|
|
|
instructions->push_tail(inst);
|
|
|
|
|
|
|
|
rhs_base = count;
|
|
|
|
|
|
|
|
col_idx++;
|
|
|
|
row_idx = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If there is data left in the parameter and components left to be
|
|
|
|
* set in the destination, emit another assignment. It is possible
|
|
|
|
* that the assignment could be of a vec4 to the last element of the
|
|
|
|
* matrix. In this case col_idx==cols, but there is still data
|
|
|
|
* left in the source parameter. Obviously, don't emit an assignment
|
|
|
|
* to data outside the destination matrix.
|
|
|
|
*/
|
|
|
|
if ((col_idx < cols) && (rhs_base < rhs_components)) {
|
|
|
|
const unsigned count = rhs_components - rhs_base;
|
|
|
|
|
|
|
|
rhs_var_ref = new(ctx) ir_dereference_variable(rhs_var);
|
|
|
|
|
|
|
|
ir_instruction *inst = assign_to_matrix_column(var, col_idx,
|
|
|
|
row_idx,
|
|
|
|
rhs_var_ref,
|
|
|
|
rhs_base,
|
|
|
|
count, ctx);
|
|
|
|
instructions->push_tail(inst);
|
|
|
|
|
|
|
|
row_idx += count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return new(ctx) ir_dereference_variable(var);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-09-01 21:46:04 +01:00
|
|
|
ir_rvalue *
|
|
|
|
emit_inline_record_constructor(const glsl_type *type,
|
|
|
|
exec_list *instructions,
|
|
|
|
exec_list *parameters,
|
|
|
|
void *mem_ctx)
|
|
|
|
{
|
|
|
|
ir_variable *const var =
|
|
|
|
new(mem_ctx) ir_variable(type, "record_ctor", ir_var_temporary);
|
|
|
|
ir_dereference_variable *const d = new(mem_ctx) ir_dereference_variable(var);
|
|
|
|
|
|
|
|
instructions->push_tail(var);
|
|
|
|
|
|
|
|
exec_node *node = parameters->head;
|
|
|
|
for (unsigned i = 0; i < type->length; i++) {
|
|
|
|
assert(!node->is_tail_sentinel());
|
|
|
|
|
|
|
|
ir_dereference *const lhs =
|
|
|
|
new(mem_ctx) ir_dereference_record(d->clone(mem_ctx, NULL),
|
|
|
|
type->fields.structure[i].name);
|
|
|
|
|
|
|
|
ir_rvalue *const rhs = ((ir_instruction *) node)->as_rvalue();
|
|
|
|
assert(rhs != NULL);
|
|
|
|
|
|
|
|
ir_instruction *const assign = new(mem_ctx) ir_assignment(lhs, rhs, NULL);
|
|
|
|
|
|
|
|
instructions->push_tail(assign);
|
|
|
|
node = node->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-06-13 20:05:21 +01:00
|
|
|
static ir_rvalue *
|
|
|
|
process_record_constructor(exec_list *instructions,
|
|
|
|
const glsl_type *constructor_type,
|
|
|
|
YYLTYPE *loc, exec_list *parameters,
|
|
|
|
struct _mesa_glsl_parse_state *state)
|
|
|
|
{
|
|
|
|
void *ctx = state;
|
|
|
|
exec_list actual_parameters;
|
|
|
|
|
|
|
|
process_parameters(instructions, &actual_parameters,
|
|
|
|
parameters, state);
|
|
|
|
|
|
|
|
exec_node *node = actual_parameters.head;
|
|
|
|
for (unsigned i = 0; i < constructor_type->length; i++) {
|
|
|
|
ir_rvalue *ir = (ir_rvalue *) node;
|
|
|
|
|
|
|
|
if (node->is_tail_sentinel()) {
|
|
|
|
_mesa_glsl_error(loc, state,
|
|
|
|
"insufficient parameters to constructor for `%s'",
|
|
|
|
constructor_type->name);
|
|
|
|
return ir_rvalue::error_value(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (apply_implicit_conversion(constructor_type->fields.structure[i].type,
|
|
|
|
ir, state)) {
|
|
|
|
node->replace_with(ir);
|
|
|
|
} else {
|
|
|
|
_mesa_glsl_error(loc, state,
|
|
|
|
"parameter type mismatch in constructor for `%s.%s' "
|
|
|
|
"(%s vs %s)",
|
|
|
|
constructor_type->name,
|
|
|
|
constructor_type->fields.structure[i].name,
|
|
|
|
ir->type->name,
|
|
|
|
constructor_type->fields.structure[i].type->name);
|
|
|
|
return ir_rvalue::error_value(ctx);;
|
|
|
|
}
|
|
|
|
|
|
|
|
node = node->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!node->is_tail_sentinel()) {
|
|
|
|
_mesa_glsl_error(loc, state, "too many parameters in constructor "
|
|
|
|
"for `%s'", constructor_type->name);
|
|
|
|
return ir_rvalue::error_value(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
ir_rvalue *const constant =
|
|
|
|
constant_record_constructor(constructor_type, &actual_parameters,
|
|
|
|
state);
|
|
|
|
|
|
|
|
return (constant != NULL)
|
|
|
|
? constant
|
|
|
|
: emit_inline_record_constructor(constructor_type, instructions,
|
|
|
|
&actual_parameters, state);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-26 07:25:36 +00:00
|
|
|
ir_rvalue *
|
2010-03-15 20:04:13 +00:00
|
|
|
ast_function_expression::hir(exec_list *instructions,
|
|
|
|
struct _mesa_glsl_parse_state *state)
|
|
|
|
{
|
2010-06-25 21:14:37 +01:00
|
|
|
void *ctx = state;
|
2010-03-15 20:04:13 +00:00
|
|
|
/* There are three sorts of function calls.
|
|
|
|
*
|
2010-07-09 02:03:28 +01:00
|
|
|
* 1. constructors - The first subexpression is an ast_type_specifier.
|
2010-03-15 20:04:13 +00:00
|
|
|
* 2. methods - Only the .length() method of array types.
|
|
|
|
* 3. functions - Calls to regular old functions.
|
|
|
|
*
|
|
|
|
* Method calls are actually detected when the ast_field_selection
|
|
|
|
* expression is handled.
|
|
|
|
*/
|
|
|
|
if (is_constructor()) {
|
2010-03-23 22:08:30 +00:00
|
|
|
const ast_type_specifier *type = (ast_type_specifier *) subexpressions[0];
|
|
|
|
YYLTYPE loc = type->get_location();
|
2010-04-01 00:22:56 +01:00
|
|
|
const char *name;
|
2010-03-23 22:08:30 +00:00
|
|
|
|
2010-04-01 00:22:56 +01:00
|
|
|
const glsl_type *const constructor_type = type->glsl_type(& name, state);
|
2010-03-23 22:08:30 +00:00
|
|
|
|
2011-01-28 01:52:19 +00:00
|
|
|
/* constructor_type can be NULL if a variable with the same name as the
|
|
|
|
* structure has come into scope.
|
|
|
|
*/
|
|
|
|
if (constructor_type == NULL) {
|
|
|
|
_mesa_glsl_error(& loc, state, "unknown type `%s' (structure name "
|
|
|
|
"may be shadowed by a variable with the same name)",
|
|
|
|
type->type_name);
|
2011-09-22 23:04:56 +01:00
|
|
|
return ir_rvalue::error_value(ctx);
|
2011-01-28 01:52:19 +00:00
|
|
|
}
|
|
|
|
|
2010-03-23 22:08:30 +00:00
|
|
|
|
2014-12-04 08:40:56 +00:00
|
|
|
/* Constructors for opaque types are illegal.
|
2010-03-23 22:08:30 +00:00
|
|
|
*/
|
2014-12-04 08:40:56 +00:00
|
|
|
if (constructor_type->contains_opaque()) {
|
|
|
|
_mesa_glsl_error(& loc, state, "cannot construct opaque type `%s'",
|
2010-03-23 22:08:30 +00:00
|
|
|
constructor_type->name);
|
2011-09-22 23:04:56 +01:00
|
|
|
return ir_rvalue::error_value(ctx);
|
2010-03-23 22:08:30 +00:00
|
|
|
}
|
|
|
|
|
2010-04-01 00:25:21 +01:00
|
|
|
if (constructor_type->is_array()) {
|
2012-08-02 16:18:12 +01:00
|
|
|
if (!state->check_version(120, 300, &loc,
|
2012-08-05 17:57:01 +01:00
|
|
|
"array constructors forbidden")) {
|
2011-09-22 23:04:56 +01:00
|
|
|
return ir_rvalue::error_value(ctx);
|
2010-04-01 00:25:21 +01:00
|
|
|
}
|
|
|
|
|
2010-04-01 00:48:48 +01:00
|
|
|
return process_array_constructor(instructions, constructor_type,
|
2010-05-10 18:47:14 +01:00
|
|
|
& loc, &this->expressions, state);
|
2010-04-01 00:25:21 +01:00
|
|
|
}
|
2010-03-23 22:08:30 +00:00
|
|
|
|
2010-09-01 21:46:04 +01:00
|
|
|
|
2013-06-10 21:28:40 +01:00
|
|
|
/* There are two kinds of constructor calls. Constructors for arrays and
|
|
|
|
* structures must have the exact number of arguments with matching types
|
|
|
|
* in the correct order. These constructors follow essentially the same
|
|
|
|
* type matching rules as functions.
|
|
|
|
*
|
|
|
|
* Constructors for built-in language types, such as mat4 and vec2, are
|
|
|
|
* free form. The only requirements are that the parameters must provide
|
|
|
|
* enough values of the correct scalar type and that no arguments are
|
|
|
|
* given past the last used argument.
|
|
|
|
*
|
|
|
|
* When using the C-style initializer syntax from GLSL 4.20, constructors
|
|
|
|
* must have the exact number of arguments with matching types in the
|
|
|
|
* correct order.
|
2010-03-23 22:08:30 +00:00
|
|
|
*/
|
2011-01-28 01:52:19 +00:00
|
|
|
if (constructor_type->is_record()) {
|
2013-06-13 20:05:21 +01:00
|
|
|
return process_record_constructor(instructions, constructor_type,
|
|
|
|
&loc, &this->expressions,
|
|
|
|
state);
|
2011-01-28 01:52:19 +00:00
|
|
|
}
|
|
|
|
|
2010-07-09 02:03:28 +01:00
|
|
|
if (!constructor_type->is_numeric() && !constructor_type->is_boolean())
|
2011-09-22 23:04:56 +01:00
|
|
|
return ir_rvalue::error_value(ctx);
|
2010-03-27 00:38:58 +00:00
|
|
|
|
2010-07-09 02:03:28 +01:00
|
|
|
/* Total number of components of the type being constructed. */
|
|
|
|
const unsigned type_components = constructor_type->components();
|
2010-05-10 18:47:14 +01:00
|
|
|
|
2010-07-09 02:03:28 +01:00
|
|
|
/* Number of components from parameters that have actually been
|
|
|
|
* consumed. This is used to perform several kinds of error checking.
|
|
|
|
*/
|
|
|
|
unsigned components_used = 0;
|
2010-05-10 18:47:14 +01:00
|
|
|
|
2010-07-09 02:03:28 +01:00
|
|
|
unsigned matrix_parameters = 0;
|
|
|
|
unsigned nonmatrix_parameters = 0;
|
|
|
|
exec_list actual_parameters;
|
2010-03-27 00:38:58 +00:00
|
|
|
|
2014-06-25 06:02:24 +01:00
|
|
|
foreach_list_typed(ast_node, ast, link, &this->expressions) {
|
2014-06-01 19:43:15 +01:00
|
|
|
ir_rvalue *result = ast->hir(instructions, state);
|
2010-03-27 00:38:58 +00:00
|
|
|
|
|
|
|
/* From page 50 (page 56 of the PDF) of the GLSL 1.50 spec:
|
|
|
|
*
|
2010-07-09 02:03:28 +01:00
|
|
|
* "It is an error to provide extra arguments beyond this
|
|
|
|
* last used argument."
|
2010-03-27 00:38:58 +00:00
|
|
|
*/
|
2010-07-09 02:03:28 +01:00
|
|
|
if (components_used >= type_components) {
|
|
|
|
_mesa_glsl_error(& loc, state, "too many parameters to `%s' "
|
|
|
|
"constructor",
|
2010-03-27 00:38:58 +00:00
|
|
|
constructor_type->name);
|
2011-09-22 23:04:56 +01:00
|
|
|
return ir_rvalue::error_value(ctx);
|
2010-03-27 00:38:58 +00:00
|
|
|
}
|
|
|
|
|
2010-07-09 02:03:28 +01:00
|
|
|
if (!result->type->is_numeric() && !result->type->is_boolean()) {
|
|
|
|
_mesa_glsl_error(& loc, state, "cannot construct `%s' from a "
|
|
|
|
"non-numeric data type",
|
2010-03-27 00:38:58 +00:00
|
|
|
constructor_type->name);
|
2011-09-22 23:04:56 +01:00
|
|
|
return ir_rvalue::error_value(ctx);
|
2010-03-27 00:38:58 +00:00
|
|
|
}
|
|
|
|
|
2010-07-09 02:03:28 +01:00
|
|
|
/* Count the number of matrix and nonmatrix parameters. This
|
|
|
|
* is used below to enforce some of the constructor rules.
|
|
|
|
*/
|
|
|
|
if (result->type->is_matrix())
|
|
|
|
matrix_parameters++;
|
|
|
|
else
|
|
|
|
nonmatrix_parameters++;
|
2010-03-27 00:38:58 +00:00
|
|
|
|
2010-07-09 02:03:28 +01:00
|
|
|
actual_parameters.push_tail(result);
|
|
|
|
components_used += result->type->components();
|
2010-03-27 00:38:58 +00:00
|
|
|
}
|
2010-03-23 22:08:30 +00:00
|
|
|
|
2010-07-09 02:03:28 +01:00
|
|
|
/* From page 28 (page 34 of the PDF) of the GLSL 1.10 spec:
|
|
|
|
*
|
|
|
|
* "It is an error to construct matrices from other matrices. This
|
|
|
|
* is reserved for future use."
|
|
|
|
*/
|
2012-08-05 17:57:01 +01:00
|
|
|
if (matrix_parameters > 0
|
|
|
|
&& constructor_type->is_matrix()
|
|
|
|
&& !state->check_version(120, 100, &loc,
|
|
|
|
"cannot construct `%s' from a matrix",
|
|
|
|
constructor_type->name)) {
|
2011-09-22 23:04:56 +01:00
|
|
|
return ir_rvalue::error_value(ctx);
|
2010-07-09 02:03:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* From page 50 (page 56 of the PDF) of the GLSL 1.50 spec:
|
|
|
|
*
|
|
|
|
* "If a matrix argument is given to a matrix constructor, it is
|
|
|
|
* an error to have any other arguments."
|
|
|
|
*/
|
|
|
|
if ((matrix_parameters > 0)
|
|
|
|
&& ((matrix_parameters + nonmatrix_parameters) > 1)
|
|
|
|
&& constructor_type->is_matrix()) {
|
|
|
|
_mesa_glsl_error(& loc, state, "for matrix `%s' constructor, "
|
|
|
|
"matrix must be only parameter",
|
|
|
|
constructor_type->name);
|
2011-09-22 23:04:56 +01:00
|
|
|
return ir_rvalue::error_value(ctx);
|
2010-07-09 02:03:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* From page 28 (page 34 of the PDF) of the GLSL 1.10 spec:
|
|
|
|
*
|
|
|
|
* "In these cases, there must be enough components provided in the
|
|
|
|
* arguments to provide an initializer for every component in the
|
|
|
|
* constructed value."
|
|
|
|
*/
|
2010-09-01 23:04:57 +01:00
|
|
|
if (components_used < type_components && components_used != 1
|
|
|
|
&& matrix_parameters == 0) {
|
2010-07-09 02:03:28 +01:00
|
|
|
_mesa_glsl_error(& loc, state, "too few components to construct "
|
|
|
|
"`%s'",
|
|
|
|
constructor_type->name);
|
2011-09-22 23:04:56 +01:00
|
|
|
return ir_rvalue::error_value(ctx);
|
2010-07-09 02:03:28 +01:00
|
|
|
}
|
|
|
|
|
2010-07-09 02:15:32 +01:00
|
|
|
/* Later, we cast each parameter to the same base type as the
|
|
|
|
* constructor. Since there are no non-floating point matrices, we
|
|
|
|
* need to break them up into a series of column vectors.
|
|
|
|
*/
|
|
|
|
if (constructor_type->base_type != GLSL_TYPE_FLOAT) {
|
2014-06-25 05:58:35 +01:00
|
|
|
foreach_in_list_safe(ir_rvalue, matrix, &actual_parameters) {
|
2010-07-09 02:15:32 +01:00
|
|
|
if (!matrix->type->is_matrix())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Create a temporary containing the matrix. */
|
2010-07-20 01:12:42 +01:00
|
|
|
ir_variable *var = new(ctx) ir_variable(matrix->type, "matrix_tmp",
|
|
|
|
ir_var_temporary);
|
2010-07-09 02:15:32 +01:00
|
|
|
instructions->push_tail(var);
|
|
|
|
instructions->push_tail(new(ctx) ir_assignment(new(ctx)
|
|
|
|
ir_dereference_variable(var), matrix, NULL));
|
|
|
|
var->constant_value = matrix->constant_expression_value();
|
|
|
|
|
|
|
|
/* Replace the matrix with dereferences of its columns. */
|
|
|
|
for (int i = 0; i < matrix->type->matrix_columns; i++) {
|
|
|
|
matrix->insert_before(new (ctx) ir_dereference_array(var,
|
|
|
|
new(ctx) ir_constant(i)));
|
|
|
|
}
|
|
|
|
matrix->remove();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool all_parameters_are_constant = true;
|
|
|
|
|
|
|
|
/* Type cast each parameter and, if possible, fold constants.*/
|
2014-06-25 05:58:35 +01:00
|
|
|
foreach_in_list_safe(ir_rvalue, ir, &actual_parameters) {
|
2010-07-09 02:15:32 +01:00
|
|
|
const glsl_type *desired_type =
|
|
|
|
glsl_type::get_instance(constructor_type->base_type,
|
|
|
|
ir->type->vector_elements,
|
|
|
|
ir->type->matrix_columns);
|
|
|
|
ir_rvalue *result = convert_component(ir, desired_type);
|
|
|
|
|
|
|
|
/* Attempt to convert the parameter to a constant valued expression.
|
|
|
|
* After doing so, track whether or not all the parameters to the
|
|
|
|
* constructor are trivially constant valued expressions.
|
|
|
|
*/
|
|
|
|
ir_rvalue *const constant = result->constant_expression_value();
|
|
|
|
|
|
|
|
if (constant != NULL)
|
|
|
|
result = constant;
|
|
|
|
else
|
|
|
|
all_parameters_are_constant = false;
|
|
|
|
|
|
|
|
if (result != ir) {
|
2010-07-20 05:44:03 +01:00
|
|
|
ir->replace_with(result);
|
2010-07-09 02:15:32 +01:00
|
|
|
}
|
|
|
|
}
|
2010-07-09 02:03:28 +01:00
|
|
|
|
|
|
|
/* If all of the parameters are trivially constant, create a
|
|
|
|
* constant representing the complete collection of parameters.
|
|
|
|
*/
|
|
|
|
if (all_parameters_are_constant) {
|
2010-09-01 23:31:06 +01:00
|
|
|
return new(ctx) ir_constant(constructor_type, &actual_parameters);
|
2010-07-09 02:03:28 +01:00
|
|
|
} else if (constructor_type->is_scalar()) {
|
|
|
|
return dereference_component((ir_rvalue *) actual_parameters.head,
|
|
|
|
0);
|
|
|
|
} else if (constructor_type->is_vector()) {
|
|
|
|
return emit_inline_vector_constructor(constructor_type,
|
|
|
|
instructions,
|
|
|
|
&actual_parameters,
|
|
|
|
ctx);
|
|
|
|
} else {
|
|
|
|
assert(constructor_type->is_matrix());
|
|
|
|
return emit_inline_matrix_constructor(constructor_type,
|
|
|
|
instructions,
|
|
|
|
&actual_parameters,
|
|
|
|
ctx);
|
|
|
|
}
|
2010-03-15 20:04:13 +00:00
|
|
|
} else {
|
|
|
|
const ast_expression *id = subexpressions[0];
|
glsl: Split up function matching and call generation a bit more.
We used to have one big function, match_signature_by_name, which found
a matching signature, performed out-parameter conversions, and generated
the ir_call. As the code for matching against built-in functions became
more complicated, I split it internally, creating generate_call().
However, I left the same awkward interface. This patch splits it into
three functions:
1. match_signature_by_name()
This now takes a name, a list of parameters, the symbol table, and
returns an ir_function_signature. Simple and one purpose: matching.
2. no_matching_function_error()
Generate the "no matching function" error and list of prototypes.
This was complex enough that I felt it deserved its own function.
3. generate_call()
Do the out-parameter conversion and generate the ir_call. This
could probably use more splitting.
The caller now has a more natural workflow: find a matching signature,
then either generate an error or a call.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2012-03-28 23:57:50 +01:00
|
|
|
const char *func_name = id->primary_expression.identifier;
|
2013-12-09 08:38:35 +00:00
|
|
|
YYLTYPE loc = get_location();
|
2010-06-10 01:23:26 +01:00
|
|
|
exec_list actual_parameters;
|
|
|
|
|
|
|
|
process_parameters(instructions, &actual_parameters, &this->expressions,
|
|
|
|
state);
|
2010-03-15 20:04:13 +00:00
|
|
|
|
glsl: Split up function matching and call generation a bit more.
We used to have one big function, match_signature_by_name, which found
a matching signature, performed out-parameter conversions, and generated
the ir_call. As the code for matching against built-in functions became
more complicated, I split it internally, creating generate_call().
However, I left the same awkward interface. This patch splits it into
three functions:
1. match_signature_by_name()
This now takes a name, a list of parameters, the symbol table, and
returns an ir_function_signature. Simple and one purpose: matching.
2. no_matching_function_error()
Generate the "no matching function" error and list of prototypes.
This was complex enough that I felt it deserved its own function.
3. generate_call()
Do the out-parameter conversion and generate the ir_call. This
could probably use more splitting.
The caller now has a more natural workflow: find a matching signature,
then either generate an error or a call.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2012-03-28 23:57:50 +01:00
|
|
|
ir_function_signature *sig =
|
|
|
|
match_function_by_name(func_name, &actual_parameters, state);
|
|
|
|
|
|
|
|
ir_rvalue *value = NULL;
|
|
|
|
if (sig == NULL) {
|
|
|
|
no_matching_function_error(func_name, &loc, &actual_parameters, state);
|
2011-09-22 23:04:56 +01:00
|
|
|
value = ir_rvalue::error_value(ctx);
|
2012-03-29 03:24:45 +01:00
|
|
|
} else if (!verify_parameter_modes(state, sig, actual_parameters, this->expressions)) {
|
|
|
|
/* an error has already been emitted */
|
2011-09-22 23:04:56 +01:00
|
|
|
value = ir_rvalue::error_value(ctx);
|
glsl: Split up function matching and call generation a bit more.
We used to have one big function, match_signature_by_name, which found
a matching signature, performed out-parameter conversions, and generated
the ir_call. As the code for matching against built-in functions became
more complicated, I split it internally, creating generate_call().
However, I left the same awkward interface. This patch splits it into
three functions:
1. match_signature_by_name()
This now takes a name, a list of parameters, the symbol table, and
returns an ir_function_signature. Simple and one purpose: matching.
2. no_matching_function_error()
Generate the "no matching function" error and list of prototypes.
This was complex enough that I felt it deserved its own function.
3. generate_call()
Do the out-parameter conversion and generate the ir_call. This
could probably use more splitting.
The caller now has a more natural workflow: find a matching signature,
then either generate an error or a call.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2012-03-28 23:57:50 +01:00
|
|
|
} else {
|
2013-11-23 18:39:34 +00:00
|
|
|
value = generate_call(instructions, sig, &actual_parameters, state);
|
glsl: Split up function matching and call generation a bit more.
We used to have one big function, match_signature_by_name, which found
a matching signature, performed out-parameter conversions, and generated
the ir_call. As the code for matching against built-in functions became
more complicated, I split it internally, creating generate_call().
However, I left the same awkward interface. This patch splits it into
three functions:
1. match_signature_by_name()
This now takes a name, a list of parameters, the symbol table, and
returns an ir_function_signature. Simple and one purpose: matching.
2. no_matching_function_error()
Generate the "no matching function" error and list of prototypes.
This was complex enough that I felt it deserved its own function.
3. generate_call()
Do the out-parameter conversion and generate the ir_call. This
could probably use more splitting.
The caller now has a more natural workflow: find a matching signature,
then either generate an error or a call.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2012-03-28 23:57:50 +01:00
|
|
|
}
|
2011-12-23 18:58:23 +00:00
|
|
|
|
|
|
|
return value;
|
2010-03-15 20:04:13 +00:00
|
|
|
}
|
|
|
|
|
2011-09-22 23:04:56 +01:00
|
|
|
return ir_rvalue::error_value(ctx);
|
2010-03-15 20:04:13 +00:00
|
|
|
}
|
2013-06-30 03:27:50 +01:00
|
|
|
|
|
|
|
ir_rvalue *
|
|
|
|
ast_aggregate_initializer::hir(exec_list *instructions,
|
|
|
|
struct _mesa_glsl_parse_state *state)
|
|
|
|
{
|
|
|
|
void *ctx = state;
|
|
|
|
YYLTYPE loc = this->get_location();
|
2013-07-12 19:05:38 +01:00
|
|
|
|
|
|
|
if (!this->constructor_type) {
|
|
|
|
_mesa_glsl_error(&loc, state, "type of C-style initializer unknown");
|
|
|
|
return ir_rvalue::error_value(ctx);
|
|
|
|
}
|
glsl: Simplify aggregate type inference to prepare for ARB_arrays_of_arrays.
Most of the time it is not necessary to perform type inference to
compile GLSL; the type of every expression can be inferred from the
contents of the expression itself (and previous type declarations).
The exception is aggregate initializers: their type is determined by
the LHS of the variable being assigned to. For example, in the
statement:
mat2 foo = { { 1, 2 }, { 3, 4 } };
the type of { 1, 2 } is only known to be vec2 (as opposed to, say,
ivec2, uvec2, int[2], or a struct) because of the fact that the result
is being assigned to a mat2.
Previous to this patch, we handled this situation by doing some type
inference during parsing: when parsing a declaration like the one
above, we would call _mesa_set_aggregate_type(), which would infer the
type of each aggregate initializer and store it in the corresponding
ast_aggregate_initializer::constructor_type field. Since this
happened at parse time, we couldn't do the type inference using
glsl_type objects; we had to use ast_type_specifiers, which are much
more awkward to work with. Things are about to get more complicated
when we add support for ARB_arrays_of_arrays.
This patch simplifies things by postponing the call to
_mesa_set_aggregate_type() until ast-to-hir time, when we have access
to glsl_type objects. As a side benefit, we only need to have one
call to _mesa_set_aggregate_type() now, instead of six.
Reviewed-by: Matt Turner <mattst88@gmail.com>
2014-01-21 23:41:26 +00:00
|
|
|
const glsl_type *const constructor_type = this->constructor_type;
|
2013-06-30 03:27:50 +01:00
|
|
|
|
|
|
|
if (!state->ARB_shading_language_420pack_enable) {
|
|
|
|
_mesa_glsl_error(&loc, state, "C-style initialization requires the "
|
|
|
|
"GL_ARB_shading_language_420pack extension");
|
|
|
|
return ir_rvalue::error_value(ctx);
|
|
|
|
}
|
|
|
|
|
glsl: Simplify aggregate type inference to prepare for ARB_arrays_of_arrays.
Most of the time it is not necessary to perform type inference to
compile GLSL; the type of every expression can be inferred from the
contents of the expression itself (and previous type declarations).
The exception is aggregate initializers: their type is determined by
the LHS of the variable being assigned to. For example, in the
statement:
mat2 foo = { { 1, 2 }, { 3, 4 } };
the type of { 1, 2 } is only known to be vec2 (as opposed to, say,
ivec2, uvec2, int[2], or a struct) because of the fact that the result
is being assigned to a mat2.
Previous to this patch, we handled this situation by doing some type
inference during parsing: when parsing a declaration like the one
above, we would call _mesa_set_aggregate_type(), which would infer the
type of each aggregate initializer and store it in the corresponding
ast_aggregate_initializer::constructor_type field. Since this
happened at parse time, we couldn't do the type inference using
glsl_type objects; we had to use ast_type_specifiers, which are much
more awkward to work with. Things are about to get more complicated
when we add support for ARB_arrays_of_arrays.
This patch simplifies things by postponing the call to
_mesa_set_aggregate_type() until ast-to-hir time, when we have access
to glsl_type objects. As a side benefit, we only need to have one
call to _mesa_set_aggregate_type() now, instead of six.
Reviewed-by: Matt Turner <mattst88@gmail.com>
2014-01-21 23:41:26 +00:00
|
|
|
if (constructor_type->is_array()) {
|
2013-06-30 03:27:50 +01:00
|
|
|
return process_array_constructor(instructions, constructor_type, &loc,
|
|
|
|
&this->expressions, state);
|
|
|
|
}
|
|
|
|
|
glsl: Simplify aggregate type inference to prepare for ARB_arrays_of_arrays.
Most of the time it is not necessary to perform type inference to
compile GLSL; the type of every expression can be inferred from the
contents of the expression itself (and previous type declarations).
The exception is aggregate initializers: their type is determined by
the LHS of the variable being assigned to. For example, in the
statement:
mat2 foo = { { 1, 2 }, { 3, 4 } };
the type of { 1, 2 } is only known to be vec2 (as opposed to, say,
ivec2, uvec2, int[2], or a struct) because of the fact that the result
is being assigned to a mat2.
Previous to this patch, we handled this situation by doing some type
inference during parsing: when parsing a declaration like the one
above, we would call _mesa_set_aggregate_type(), which would infer the
type of each aggregate initializer and store it in the corresponding
ast_aggregate_initializer::constructor_type field. Since this
happened at parse time, we couldn't do the type inference using
glsl_type objects; we had to use ast_type_specifiers, which are much
more awkward to work with. Things are about to get more complicated
when we add support for ARB_arrays_of_arrays.
This patch simplifies things by postponing the call to
_mesa_set_aggregate_type() until ast-to-hir time, when we have access
to glsl_type objects. As a side benefit, we only need to have one
call to _mesa_set_aggregate_type() now, instead of six.
Reviewed-by: Matt Turner <mattst88@gmail.com>
2014-01-21 23:41:26 +00:00
|
|
|
if (constructor_type->is_record()) {
|
2013-06-30 03:27:50 +01:00
|
|
|
return process_record_constructor(instructions, constructor_type, &loc,
|
|
|
|
&this->expressions, state);
|
|
|
|
}
|
|
|
|
|
|
|
|
return process_vec_mat_constructor(instructions, constructor_type, &loc,
|
|
|
|
&this->expressions, state);
|
|
|
|
}
|