2010-02-22 13:19:34 -08: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.
|
|
|
|
|
*/
|
|
|
|
|
#include <string.h>
|
2010-08-23 17:51:42 +08:00
|
|
|
#include "main/core.h" /* for MAX2 */
|
2010-02-22 13:19:34 -08:00
|
|
|
#include "ir.h"
|
|
|
|
|
#include "glsl_types.h"
|
|
|
|
|
|
2014-05-27 19:49:04 -07:00
|
|
|
ir_rvalue::ir_rvalue(enum ir_node_type t)
|
|
|
|
|
: ir_instruction(t)
|
2010-07-22 16:45:37 -07:00
|
|
|
{
|
|
|
|
|
this->type = glsl_type::error_type;
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-18 17:11:17 -08:00
|
|
|
bool ir_rvalue::is_zero() const
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ir_rvalue::is_one() const
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-16 11:59:22 -08:00
|
|
|
bool ir_rvalue::is_negative_one() const
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-02 18:48:25 -07:00
|
|
|
/**
|
|
|
|
|
* Modify the swizzle make to move one component to another
|
|
|
|
|
*
|
|
|
|
|
* \param m IR swizzle to be modified
|
|
|
|
|
* \param from Component in the RHS that is to be swizzled
|
|
|
|
|
* \param to Desired swizzle location of \c from
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
update_rhs_swizzle(ir_swizzle_mask &m, unsigned from, unsigned to)
|
|
|
|
|
{
|
|
|
|
|
switch (to) {
|
|
|
|
|
case 0: m.x = from; break;
|
|
|
|
|
case 1: m.y = from; break;
|
|
|
|
|
case 2: m.z = from; break;
|
|
|
|
|
case 3: m.w = from; break;
|
|
|
|
|
default: assert(!"Should not get here.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m.num_components = MAX2(m.num_components, (to + 1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ir_assignment::set_lhs(ir_rvalue *lhs)
|
|
|
|
|
{
|
2010-09-22 11:47:03 -07:00
|
|
|
void *mem_ctx = this;
|
|
|
|
|
bool swizzled = false;
|
|
|
|
|
|
2010-08-02 18:48:25 -07:00
|
|
|
while (lhs != NULL) {
|
|
|
|
|
ir_swizzle *swiz = lhs->as_swizzle();
|
|
|
|
|
|
|
|
|
|
if (swiz == NULL)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
unsigned write_mask = 0;
|
|
|
|
|
ir_swizzle_mask rhs_swiz = { 0, 0, 0, 0, 0, 0 };
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < swiz->mask.num_components; i++) {
|
|
|
|
|
unsigned c = 0;
|
|
|
|
|
|
|
|
|
|
switch (i) {
|
|
|
|
|
case 0: c = swiz->mask.x; break;
|
|
|
|
|
case 1: c = swiz->mask.y; break;
|
|
|
|
|
case 2: c = swiz->mask.z; break;
|
|
|
|
|
case 3: c = swiz->mask.w; break;
|
|
|
|
|
default: assert(!"Should not get here.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
write_mask |= (((this->write_mask >> i) & 1) << c);
|
|
|
|
|
update_rhs_swizzle(rhs_swiz, i, c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->write_mask = write_mask;
|
|
|
|
|
lhs = swiz->val;
|
|
|
|
|
|
2010-09-22 11:47:03 -07:00
|
|
|
this->rhs = new(mem_ctx) ir_swizzle(this->rhs, rhs_swiz);
|
|
|
|
|
swizzled = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (swizzled) {
|
|
|
|
|
/* Now, RHS channels line up with the LHS writemask. Collapse it
|
|
|
|
|
* to just the channels that will be written.
|
|
|
|
|
*/
|
|
|
|
|
ir_swizzle_mask rhs_swiz = { 0, 0, 0, 0, 0, 0 };
|
|
|
|
|
int rhs_chan = 0;
|
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
|
if (write_mask & (1 << i))
|
|
|
|
|
update_rhs_swizzle(rhs_swiz, i, rhs_chan++);
|
|
|
|
|
}
|
|
|
|
|
this->rhs = new(mem_ctx) ir_swizzle(this->rhs, rhs_swiz);
|
2010-08-02 18:48:25 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert((lhs == NULL) || lhs->as_dereference());
|
|
|
|
|
|
|
|
|
|
this->lhs = (ir_dereference *) lhs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ir_variable *
|
|
|
|
|
ir_assignment::whole_variable_written()
|
|
|
|
|
{
|
|
|
|
|
ir_variable *v = this->lhs->whole_variable_referenced();
|
|
|
|
|
|
|
|
|
|
if (v == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
if (v->type->is_scalar())
|
|
|
|
|
return v;
|
|
|
|
|
|
|
|
|
|
if (v->type->is_vector()) {
|
|
|
|
|
const unsigned mask = (1U << v->type->vector_elements) - 1;
|
|
|
|
|
|
|
|
|
|
if (mask != this->write_mask)
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Either all the vector components are assigned or the variable is some
|
|
|
|
|
* composite type (and the whole thing is assigned.
|
|
|
|
|
*/
|
|
|
|
|
return v;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ir_assignment::ir_assignment(ir_dereference *lhs, ir_rvalue *rhs,
|
|
|
|
|
ir_rvalue *condition, unsigned write_mask)
|
2014-05-27 19:49:04 -07:00
|
|
|
: ir_instruction(ir_type_assignment)
|
2010-08-02 18:48:25 -07:00
|
|
|
{
|
|
|
|
|
this->condition = condition;
|
|
|
|
|
this->rhs = rhs;
|
|
|
|
|
this->lhs = lhs;
|
|
|
|
|
this->write_mask = write_mask;
|
2010-09-22 11:47:03 -07:00
|
|
|
|
|
|
|
|
if (lhs->type->is_scalar() || lhs->type->is_vector()) {
|
|
|
|
|
int lhs_components = 0;
|
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
|
if (write_mask & (1 << i))
|
|
|
|
|
lhs_components++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(lhs_components == this->rhs->type->vector_elements);
|
|
|
|
|
}
|
2010-08-02 18:48:25 -07:00
|
|
|
}
|
|
|
|
|
|
2010-03-26 00:25:36 -07:00
|
|
|
ir_assignment::ir_assignment(ir_rvalue *lhs, ir_rvalue *rhs,
|
|
|
|
|
ir_rvalue *condition)
|
2014-05-27 19:49:04 -07:00
|
|
|
: ir_instruction(ir_type_assignment)
|
2010-02-22 13:19:34 -08:00
|
|
|
{
|
|
|
|
|
this->condition = condition;
|
2010-08-02 18:48:25 -07:00
|
|
|
this->rhs = rhs;
|
|
|
|
|
|
|
|
|
|
/* If the RHS is a vector type, assume that all components of the vector
|
|
|
|
|
* type are being written to the LHS. The write mask comes from the RHS
|
|
|
|
|
* because we can have a case where the LHS is a vec4 and the RHS is a
|
|
|
|
|
* vec3. In that case, the assignment is:
|
|
|
|
|
*
|
|
|
|
|
* (assign (...) (xyz) (var_ref lhs) (var_ref rhs))
|
|
|
|
|
*/
|
|
|
|
|
if (rhs->type->is_vector())
|
|
|
|
|
this->write_mask = (1U << rhs->type->vector_elements) - 1;
|
|
|
|
|
else if (rhs->type->is_scalar())
|
|
|
|
|
this->write_mask = 1;
|
|
|
|
|
else
|
|
|
|
|
this->write_mask = 0;
|
|
|
|
|
|
|
|
|
|
this->set_lhs(lhs);
|
2010-02-22 13:19:34 -08:00
|
|
|
}
|
|
|
|
|
|
2010-11-16 12:01:42 -08:00
|
|
|
ir_expression::ir_expression(int op, const struct glsl_type *type,
|
|
|
|
|
ir_rvalue *op0, ir_rvalue *op1,
|
|
|
|
|
ir_rvalue *op2, ir_rvalue *op3)
|
2014-05-27 19:49:04 -07:00
|
|
|
: ir_rvalue(ir_type_expression)
|
2010-11-16 12:01:42 -08:00
|
|
|
{
|
|
|
|
|
this->type = type;
|
|
|
|
|
this->operation = ir_expression_operation(op);
|
|
|
|
|
this->operands[0] = op0;
|
|
|
|
|
this->operands[1] = op1;
|
|
|
|
|
this->operands[2] = op2;
|
|
|
|
|
this->operands[3] = op3;
|
2012-12-01 23:40:42 -08:00
|
|
|
#ifndef NDEBUG
|
|
|
|
|
int num_operands = get_num_operands(this->operation);
|
|
|
|
|
for (int i = num_operands; i < 4; i++) {
|
|
|
|
|
assert(this->operands[i] == NULL);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2010-02-22 13:19:34 -08:00
|
|
|
}
|
|
|
|
|
|
2010-11-03 10:21:07 -07:00
|
|
|
ir_expression::ir_expression(int op, ir_rvalue *op0)
|
2014-05-27 19:49:04 -07:00
|
|
|
: ir_rvalue(ir_type_expression)
|
2010-11-03 10:21:07 -07:00
|
|
|
{
|
|
|
|
|
this->operation = ir_expression_operation(op);
|
|
|
|
|
this->operands[0] = op0;
|
|
|
|
|
this->operands[1] = NULL;
|
|
|
|
|
this->operands[2] = NULL;
|
|
|
|
|
this->operands[3] = NULL;
|
|
|
|
|
|
|
|
|
|
assert(op <= ir_last_unop);
|
|
|
|
|
|
|
|
|
|
switch (this->operation) {
|
|
|
|
|
case ir_unop_bit_not:
|
|
|
|
|
case ir_unop_logic_not:
|
|
|
|
|
case ir_unop_neg:
|
|
|
|
|
case ir_unop_abs:
|
|
|
|
|
case ir_unop_sign:
|
|
|
|
|
case ir_unop_rcp:
|
|
|
|
|
case ir_unop_rsq:
|
|
|
|
|
case ir_unop_sqrt:
|
|
|
|
|
case ir_unop_exp:
|
|
|
|
|
case ir_unop_log:
|
|
|
|
|
case ir_unop_exp2:
|
|
|
|
|
case ir_unop_log2:
|
|
|
|
|
case ir_unop_trunc:
|
|
|
|
|
case ir_unop_ceil:
|
|
|
|
|
case ir_unop_floor:
|
|
|
|
|
case ir_unop_fract:
|
|
|
|
|
case ir_unop_round_even:
|
2010-12-06 16:00:24 -08:00
|
|
|
case ir_unop_sin:
|
2010-11-03 10:21:07 -07:00
|
|
|
case ir_unop_cos:
|
|
|
|
|
case ir_unop_dFdx:
|
2014-08-13 23:33:04 -04:00
|
|
|
case ir_unop_dFdx_coarse:
|
|
|
|
|
case ir_unop_dFdx_fine:
|
2010-11-03 10:21:07 -07:00
|
|
|
case ir_unop_dFdy:
|
2014-08-13 23:33:04 -04:00
|
|
|
case ir_unop_dFdy_coarse:
|
|
|
|
|
case ir_unop_dFdy_fine:
|
2013-09-03 13:58:04 -07:00
|
|
|
case ir_unop_bitfield_reverse:
|
2013-11-10 19:13:54 +13:00
|
|
|
case ir_unop_interpolate_at_centroid:
|
2014-06-20 11:56:48 -07:00
|
|
|
case ir_unop_saturate:
|
2010-11-03 10:21:07 -07:00
|
|
|
this->type = op0->type;
|
|
|
|
|
break;
|
|
|
|
|
|
2010-12-06 16:00:24 -08:00
|
|
|
case ir_unop_f2i:
|
|
|
|
|
case ir_unop_b2i:
|
2011-06-14 23:34:11 -07:00
|
|
|
case ir_unop_u2i:
|
2015-02-05 11:50:43 +02:00
|
|
|
case ir_unop_d2i:
|
2012-05-08 20:40:33 +02:00
|
|
|
case ir_unop_bitcast_f2i:
|
2013-09-03 13:58:04 -07:00
|
|
|
case ir_unop_bit_count:
|
|
|
|
|
case ir_unop_find_msb:
|
|
|
|
|
case ir_unop_find_lsb:
|
2010-12-06 16:00:24 -08:00
|
|
|
this->type = glsl_type::get_instance(GLSL_TYPE_INT,
|
|
|
|
|
op0->type->vector_elements, 1);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ir_unop_b2f:
|
|
|
|
|
case ir_unop_i2f:
|
|
|
|
|
case ir_unop_u2f:
|
2015-02-05 11:50:43 +02:00
|
|
|
case ir_unop_d2f:
|
2012-05-08 20:40:33 +02:00
|
|
|
case ir_unop_bitcast_i2f:
|
|
|
|
|
case ir_unop_bitcast_u2f:
|
2010-12-06 16:00:24 -08:00
|
|
|
this->type = glsl_type::get_instance(GLSL_TYPE_FLOAT,
|
|
|
|
|
op0->type->vector_elements, 1);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ir_unop_f2b:
|
|
|
|
|
case ir_unop_i2b:
|
2015-02-05 11:50:43 +02:00
|
|
|
case ir_unop_d2b:
|
2010-12-06 16:00:24 -08:00
|
|
|
this->type = glsl_type::get_instance(GLSL_TYPE_BOOL,
|
|
|
|
|
op0->type->vector_elements, 1);
|
|
|
|
|
break;
|
|
|
|
|
|
2015-02-05 11:50:43 +02:00
|
|
|
case ir_unop_f2d:
|
|
|
|
|
case ir_unop_i2d:
|
|
|
|
|
case ir_unop_u2d:
|
|
|
|
|
this->type = glsl_type::get_instance(GLSL_TYPE_DOUBLE,
|
|
|
|
|
op0->type->vector_elements, 1);
|
|
|
|
|
break;
|
|
|
|
|
|
2011-06-14 23:34:11 -07:00
|
|
|
case ir_unop_i2u:
|
2012-06-13 15:47:45 -07:00
|
|
|
case ir_unop_f2u:
|
2015-02-05 11:50:43 +02:00
|
|
|
case ir_unop_d2u:
|
2012-05-08 20:40:33 +02:00
|
|
|
case ir_unop_bitcast_f2u:
|
2011-06-14 23:34:11 -07:00
|
|
|
this->type = glsl_type::get_instance(GLSL_TYPE_UINT,
|
|
|
|
|
op0->type->vector_elements, 1);
|
|
|
|
|
break;
|
|
|
|
|
|
2010-12-06 16:00:24 -08:00
|
|
|
case ir_unop_noise:
|
2012-11-19 10:48:25 -08:00
|
|
|
case ir_unop_unpack_half_2x16_split_x:
|
|
|
|
|
case ir_unop_unpack_half_2x16_split_y:
|
2010-12-06 16:00:24 -08:00
|
|
|
this->type = glsl_type::float_type;
|
|
|
|
|
break;
|
|
|
|
|
|
2015-02-05 11:50:43 +02:00
|
|
|
case ir_unop_unpack_double_2x32:
|
|
|
|
|
this->type = glsl_type::uvec2_type;
|
|
|
|
|
break;
|
|
|
|
|
|
2010-11-03 10:21:07 -07:00
|
|
|
case ir_unop_any:
|
|
|
|
|
this->type = glsl_type::bool_type;
|
|
|
|
|
break;
|
|
|
|
|
|
2012-11-19 10:48:25 -08:00
|
|
|
case ir_unop_pack_snorm_2x16:
|
2013-01-21 14:12:37 -08:00
|
|
|
case ir_unop_pack_snorm_4x8:
|
2012-11-19 10:48:25 -08:00
|
|
|
case ir_unop_pack_unorm_2x16:
|
2013-01-21 14:12:37 -08:00
|
|
|
case ir_unop_pack_unorm_4x8:
|
2012-11-19 10:48:25 -08:00
|
|
|
case ir_unop_pack_half_2x16:
|
|
|
|
|
this->type = glsl_type::uint_type;
|
|
|
|
|
break;
|
|
|
|
|
|
2015-02-05 11:50:43 +02:00
|
|
|
case ir_unop_pack_double_2x32:
|
|
|
|
|
this->type = glsl_type::double_type;
|
|
|
|
|
break;
|
|
|
|
|
|
2012-11-19 10:48:25 -08:00
|
|
|
case ir_unop_unpack_snorm_2x16:
|
|
|
|
|
case ir_unop_unpack_unorm_2x16:
|
|
|
|
|
case ir_unop_unpack_half_2x16:
|
|
|
|
|
this->type = glsl_type::vec2_type;
|
|
|
|
|
break;
|
|
|
|
|
|
2013-01-21 14:12:37 -08:00
|
|
|
case ir_unop_unpack_snorm_4x8:
|
|
|
|
|
case ir_unop_unpack_unorm_4x8:
|
|
|
|
|
this->type = glsl_type::vec4_type;
|
|
|
|
|
break;
|
|
|
|
|
|
2015-02-05 11:50:43 +02:00
|
|
|
case ir_unop_frexp_sig:
|
|
|
|
|
this->type = op0->type;
|
|
|
|
|
break;
|
|
|
|
|
case ir_unop_frexp_exp:
|
|
|
|
|
this->type = glsl_type::get_instance(GLSL_TYPE_INT,
|
|
|
|
|
op0->type->vector_elements, 1);
|
|
|
|
|
break;
|
|
|
|
|
|
2010-11-03 10:21:07 -07:00
|
|
|
default:
|
|
|
|
|
assert(!"not reached: missing automatic type setup for ir_expression");
|
|
|
|
|
this->type = op0->type;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ir_expression::ir_expression(int op, ir_rvalue *op0, ir_rvalue *op1)
|
2014-05-27 19:49:04 -07:00
|
|
|
: ir_rvalue(ir_type_expression)
|
2010-11-03 10:21:07 -07:00
|
|
|
{
|
|
|
|
|
this->operation = ir_expression_operation(op);
|
|
|
|
|
this->operands[0] = op0;
|
|
|
|
|
this->operands[1] = op1;
|
|
|
|
|
this->operands[2] = NULL;
|
|
|
|
|
this->operands[3] = NULL;
|
|
|
|
|
|
|
|
|
|
assert(op > ir_last_unop);
|
|
|
|
|
|
|
|
|
|
switch (this->operation) {
|
|
|
|
|
case ir_binop_all_equal:
|
|
|
|
|
case ir_binop_any_nequal:
|
|
|
|
|
this->type = glsl_type::bool_type;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ir_binop_add:
|
|
|
|
|
case ir_binop_sub:
|
|
|
|
|
case ir_binop_min:
|
|
|
|
|
case ir_binop_max:
|
|
|
|
|
case ir_binop_pow:
|
|
|
|
|
case ir_binop_mul:
|
2010-12-06 16:00:24 -08:00
|
|
|
case ir_binop_div:
|
|
|
|
|
case ir_binop_mod:
|
2010-11-03 10:21:07 -07:00
|
|
|
if (op0->type->is_scalar()) {
|
|
|
|
|
this->type = op1->type;
|
|
|
|
|
} else if (op1->type->is_scalar()) {
|
|
|
|
|
this->type = op0->type;
|
|
|
|
|
} else {
|
2015-03-27 10:45:07 -07:00
|
|
|
if (this->operation == ir_binop_mul) {
|
|
|
|
|
this->type = glsl_type::get_mul_type(op0->type, op1->type);
|
|
|
|
|
} else {
|
|
|
|
|
assert(op0->type == op1->type);
|
|
|
|
|
this->type = op0->type;
|
|
|
|
|
}
|
2010-11-03 10:21:07 -07:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ir_binop_logic_and:
|
2010-12-06 16:00:24 -08:00
|
|
|
case ir_binop_logic_xor:
|
2010-11-03 10:21:07 -07:00
|
|
|
case ir_binop_logic_or:
|
2010-12-06 16:00:24 -08:00
|
|
|
case ir_binop_bit_and:
|
|
|
|
|
case ir_binop_bit_xor:
|
|
|
|
|
case ir_binop_bit_or:
|
2013-01-15 12:16:12 -08:00
|
|
|
assert(!op0->type->is_matrix());
|
|
|
|
|
assert(!op1->type->is_matrix());
|
2010-11-03 10:21:07 -07:00
|
|
|
if (op0->type->is_scalar()) {
|
2013-01-15 12:11:37 -08:00
|
|
|
this->type = op1->type;
|
2010-11-03 10:21:07 -07:00
|
|
|
} else if (op1->type->is_scalar()) {
|
2013-01-15 12:11:37 -08:00
|
|
|
this->type = op0->type;
|
2013-01-15 12:16:12 -08:00
|
|
|
} else {
|
|
|
|
|
assert(op0->type->vector_elements == op1->type->vector_elements);
|
|
|
|
|
this->type = op0->type;
|
2010-11-03 10:21:07 -07:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2010-12-06 16:00:24 -08:00
|
|
|
case ir_binop_equal:
|
|
|
|
|
case ir_binop_nequal:
|
|
|
|
|
case ir_binop_lequal:
|
|
|
|
|
case ir_binop_gequal:
|
|
|
|
|
case ir_binop_less:
|
|
|
|
|
case ir_binop_greater:
|
|
|
|
|
assert(op0->type == op1->type);
|
|
|
|
|
this->type = glsl_type::get_instance(GLSL_TYPE_BOOL,
|
|
|
|
|
op0->type->vector_elements, 1);
|
|
|
|
|
break;
|
|
|
|
|
|
2010-11-03 10:21:07 -07:00
|
|
|
case ir_binop_dot:
|
2015-02-05 11:50:43 +02:00
|
|
|
this->type = op0->type->get_base_type();
|
2010-11-03 10:21:07 -07:00
|
|
|
break;
|
|
|
|
|
|
2012-11-19 10:48:25 -08:00
|
|
|
case ir_binop_pack_half_2x16_split:
|
|
|
|
|
this->type = glsl_type::uint_type;
|
|
|
|
|
break;
|
|
|
|
|
|
2013-09-17 21:34:15 -07:00
|
|
|
case ir_binop_imul_high:
|
2013-09-19 12:56:10 -07:00
|
|
|
case ir_binop_carry:
|
|
|
|
|
case ir_binop_borrow:
|
2010-12-06 16:00:24 -08:00
|
|
|
case ir_binop_lshift:
|
|
|
|
|
case ir_binop_rshift:
|
2013-09-05 16:57:29 -07:00
|
|
|
case ir_binop_bfm:
|
2013-08-22 13:31:18 -07:00
|
|
|
case ir_binop_ldexp:
|
2013-11-10 19:13:54 +13:00
|
|
|
case ir_binop_interpolate_at_offset:
|
|
|
|
|
case ir_binop_interpolate_at_sample:
|
2010-12-06 16:00:24 -08:00
|
|
|
this->type = op0->type;
|
|
|
|
|
break;
|
|
|
|
|
|
2013-03-06 11:05:14 -08:00
|
|
|
case ir_binop_vector_extract:
|
|
|
|
|
this->type = op0->type->get_scalar_type();
|
|
|
|
|
break;
|
|
|
|
|
|
2010-11-03 10:21:07 -07:00
|
|
|
default:
|
|
|
|
|
assert(!"not reached: missing automatic type setup for ir_expression");
|
|
|
|
|
this->type = glsl_type::float_type;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-03 11:52:40 -07:00
|
|
|
ir_expression::ir_expression(int op, ir_rvalue *op0, ir_rvalue *op1,
|
|
|
|
|
ir_rvalue *op2)
|
2014-05-27 19:49:04 -07:00
|
|
|
: ir_rvalue(ir_type_expression)
|
2013-09-03 11:52:40 -07:00
|
|
|
{
|
|
|
|
|
this->operation = ir_expression_operation(op);
|
|
|
|
|
this->operands[0] = op0;
|
|
|
|
|
this->operands[1] = op1;
|
|
|
|
|
this->operands[2] = op2;
|
|
|
|
|
this->operands[3] = NULL;
|
|
|
|
|
|
|
|
|
|
assert(op > ir_last_binop && op <= ir_last_triop);
|
|
|
|
|
|
|
|
|
|
switch (this->operation) {
|
|
|
|
|
case ir_triop_fma:
|
|
|
|
|
case ir_triop_lrp:
|
|
|
|
|
case ir_triop_bitfield_extract:
|
|
|
|
|
case ir_triop_vector_insert:
|
|
|
|
|
this->type = op0->type;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ir_triop_bfi:
|
2013-08-19 10:45:46 -07:00
|
|
|
case ir_triop_csel:
|
2013-09-03 11:52:40 -07:00
|
|
|
this->type = op1->type;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(!"not reached: missing automatic type setup for ir_expression");
|
|
|
|
|
this->type = glsl_type::float_type;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-01 18:07:08 -10:00
|
|
|
unsigned int
|
2010-04-07 16:56:57 -07:00
|
|
|
ir_expression::get_num_operands(ir_expression_operation op)
|
2010-04-01 18:07:08 -10:00
|
|
|
{
|
2010-11-17 15:31:35 -08:00
|
|
|
assert(op <= ir_last_opcode);
|
|
|
|
|
|
|
|
|
|
if (op <= ir_last_unop)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
if (op <= ir_last_binop)
|
|
|
|
|
return 2;
|
2010-11-17 22:42:51 -08:00
|
|
|
|
2012-12-01 23:49:26 -08:00
|
|
|
if (op <= ir_last_triop)
|
|
|
|
|
return 3;
|
|
|
|
|
|
2013-04-09 17:45:12 -07:00
|
|
|
if (op <= ir_last_quadop)
|
2010-11-16 12:01:42 -08:00
|
|
|
return 4;
|
|
|
|
|
|
2010-11-17 22:42:51 -08:00
|
|
|
assert(false);
|
|
|
|
|
return 0;
|
2010-04-01 18:07:08 -10:00
|
|
|
}
|
2010-02-22 13:19:34 -08:00
|
|
|
|
2010-04-07 17:18:29 -07:00
|
|
|
static const char *const operator_strs[] = {
|
|
|
|
|
"~",
|
|
|
|
|
"!",
|
2010-04-21 23:47:07 -07:00
|
|
|
"neg",
|
2010-04-07 17:18:29 -07:00
|
|
|
"abs",
|
2010-05-03 20:05:57 -07:00
|
|
|
"sign",
|
2010-04-07 17:18:29 -07:00
|
|
|
"rcp",
|
|
|
|
|
"rsq",
|
|
|
|
|
"sqrt",
|
|
|
|
|
"exp",
|
|
|
|
|
"log",
|
|
|
|
|
"exp2",
|
|
|
|
|
"log2",
|
|
|
|
|
"f2i",
|
2012-06-13 15:47:45 -07:00
|
|
|
"f2u",
|
2010-04-07 17:18:29 -07:00
|
|
|
"i2f",
|
|
|
|
|
"f2b",
|
|
|
|
|
"b2f",
|
|
|
|
|
"i2b",
|
|
|
|
|
"b2i",
|
|
|
|
|
"u2f",
|
2011-06-14 23:34:11 -07:00
|
|
|
"i2u",
|
|
|
|
|
"u2i",
|
2015-02-05 11:50:43 +02:00
|
|
|
"d2f",
|
|
|
|
|
"f2d",
|
|
|
|
|
"d2i",
|
|
|
|
|
"i2d",
|
|
|
|
|
"d2u",
|
|
|
|
|
"u2d",
|
|
|
|
|
"d2b",
|
2012-05-08 20:40:32 +02:00
|
|
|
"bitcast_i2f",
|
|
|
|
|
"bitcast_f2i",
|
|
|
|
|
"bitcast_u2f",
|
|
|
|
|
"bitcast_f2u",
|
2010-08-23 12:21:33 -07:00
|
|
|
"any",
|
2010-04-07 17:18:29 -07:00
|
|
|
"trunc",
|
|
|
|
|
"ceil",
|
|
|
|
|
"floor",
|
2010-07-01 10:37:11 -07:00
|
|
|
"fract",
|
2010-10-14 13:37:03 -07:00
|
|
|
"round_even",
|
2010-05-03 22:11:17 -07:00
|
|
|
"sin",
|
|
|
|
|
"cos",
|
2010-06-09 14:42:41 -07:00
|
|
|
"dFdx",
|
2014-08-13 23:33:04 -04:00
|
|
|
"dFdxCoarse",
|
|
|
|
|
"dFdxFine",
|
2010-06-09 14:42:41 -07:00
|
|
|
"dFdy",
|
2014-08-13 23:33:04 -04:00
|
|
|
"dFdyCoarse",
|
|
|
|
|
"dFdyFine",
|
2012-11-19 10:48:25 -08:00
|
|
|
"packSnorm2x16",
|
2013-01-21 14:12:37 -08:00
|
|
|
"packSnorm4x8",
|
2012-11-19 10:48:25 -08:00
|
|
|
"packUnorm2x16",
|
2013-01-21 14:12:37 -08:00
|
|
|
"packUnorm4x8",
|
2012-11-19 10:48:25 -08:00
|
|
|
"packHalf2x16",
|
|
|
|
|
"unpackSnorm2x16",
|
2013-01-21 14:12:37 -08:00
|
|
|
"unpackSnorm4x8",
|
2012-11-19 10:48:25 -08:00
|
|
|
"unpackUnorm2x16",
|
2013-01-21 14:12:37 -08:00
|
|
|
"unpackUnorm4x8",
|
2012-11-19 10:48:25 -08:00
|
|
|
"unpackHalf2x16",
|
|
|
|
|
"unpackHalf2x16_split_x",
|
|
|
|
|
"unpackHalf2x16_split_y",
|
2013-04-09 17:45:12 -07:00
|
|
|
"bitfield_reverse",
|
|
|
|
|
"bit_count",
|
|
|
|
|
"find_msb",
|
|
|
|
|
"find_lsb",
|
2014-06-20 11:56:48 -07:00
|
|
|
"sat",
|
2015-02-05 11:50:43 +02:00
|
|
|
"packDouble2x32",
|
|
|
|
|
"unpackDouble2x32",
|
|
|
|
|
"frexp_sig",
|
|
|
|
|
"frexp_exp",
|
2010-09-01 21:12:10 -07:00
|
|
|
"noise",
|
2013-11-10 19:13:54 +13:00
|
|
|
"interpolate_at_centroid",
|
2010-04-07 17:18:29 -07:00
|
|
|
"+",
|
|
|
|
|
"-",
|
|
|
|
|
"*",
|
2013-09-17 21:34:15 -07:00
|
|
|
"imul_high",
|
2010-04-07 17:18:29 -07:00
|
|
|
"/",
|
2013-09-19 12:56:10 -07:00
|
|
|
"carry",
|
|
|
|
|
"borrow",
|
2010-04-07 17:18:29 -07:00
|
|
|
"%",
|
|
|
|
|
"<",
|
|
|
|
|
">",
|
|
|
|
|
"<=",
|
|
|
|
|
">=",
|
|
|
|
|
"==",
|
|
|
|
|
"!=",
|
2010-09-08 01:31:39 +02:00
|
|
|
"all_equal",
|
|
|
|
|
"any_nequal",
|
2010-04-07 17:18:29 -07:00
|
|
|
"<<",
|
|
|
|
|
">>",
|
|
|
|
|
"&",
|
|
|
|
|
"^",
|
|
|
|
|
"|",
|
|
|
|
|
"&&",
|
|
|
|
|
"^^",
|
|
|
|
|
"||",
|
|
|
|
|
"dot",
|
|
|
|
|
"min",
|
|
|
|
|
"max",
|
|
|
|
|
"pow",
|
2012-11-19 10:48:25 -08:00
|
|
|
"packHalf2x16_split",
|
2013-04-09 22:43:05 -07:00
|
|
|
"bfm",
|
glsl: Add a "ubo_load" expression type for fetches from UBOs.
Drivers will probably want to be able to take UBO references in a
shader like:
uniform ubo1 {
float a;
float b;
float c;
float d;
}
void main() {
gl_FragColor = vec4(a, b, c, d);
}
and generate a single aligned vec4 load out of the UBO. For intel,
this involves recognizing the shared offset of the aligned loads and
CSEing them out. Obviously that involves breaking things down to
loads from an offset from a particular UBO first. Thus, the driver
doesn't want to see
variable_ref(ir_variable("a")),
and even more so does it not want to see
array_ref(record_ref(variable_ref(ir_variable("a")),
"field1"), variable_ref(ir_variable("i"))).
where a.field1[i] is a row_major matrix.
Instead, we're going to make a lowering pass to break UBO references
down to expressions that are obvious to codegen, and amenable to
merging through CSE.
v2: Fix some partial thoughts in the ir_binop comment (review by Kenneth)
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
2012-07-09 15:52:53 -07:00
|
|
|
"ubo_load",
|
2013-08-22 13:31:18 -07:00
|
|
|
"ldexp",
|
2013-03-06 11:05:14 -08:00
|
|
|
"vector_extract",
|
2013-11-10 19:13:54 +13:00
|
|
|
"interpolate_at_offset",
|
|
|
|
|
"interpolate_at_sample",
|
2013-04-23 17:19:06 -07:00
|
|
|
"fma",
|
2012-12-01 23:49:26 -08:00
|
|
|
"lrp",
|
2013-08-19 10:45:46 -07:00
|
|
|
"csel",
|
2013-04-09 22:43:05 -07:00
|
|
|
"bfi",
|
2013-04-09 17:45:12 -07:00
|
|
|
"bitfield_extract",
|
2013-03-12 12:42:51 -07:00
|
|
|
"vector_insert",
|
2013-04-09 17:45:12 -07:00
|
|
|
"bitfield_insert",
|
2010-11-16 12:01:42 -08:00
|
|
|
"vector",
|
2010-04-07 17:18:29 -07:00
|
|
|
};
|
|
|
|
|
|
2010-08-27 13:53:25 -07:00
|
|
|
const char *ir_expression::operator_string(ir_expression_operation op)
|
|
|
|
|
{
|
2015-02-28 09:11:23 -07:00
|
|
|
assert((unsigned int) op < ARRAY_SIZE(operator_strs));
|
|
|
|
|
assert(ARRAY_SIZE(operator_strs) == (ir_quadop_vector + 1));
|
2010-08-27 13:53:25 -07:00
|
|
|
return operator_strs[op];
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-07 17:18:29 -07:00
|
|
|
const char *ir_expression::operator_string()
|
|
|
|
|
{
|
2010-08-27 13:53:25 -07:00
|
|
|
return operator_string(this->operation);
|
2010-04-07 17:18:29 -07:00
|
|
|
}
|
|
|
|
|
|
2011-01-27 01:40:22 -08:00
|
|
|
const char*
|
|
|
|
|
depth_layout_string(ir_depth_layout layout)
|
|
|
|
|
{
|
|
|
|
|
switch(layout) {
|
|
|
|
|
case ir_depth_layout_none: return "";
|
|
|
|
|
case ir_depth_layout_any: return "depth_any";
|
|
|
|
|
case ir_depth_layout_greater: return "depth_greater";
|
|
|
|
|
case ir_depth_layout_less: return "depth_less";
|
|
|
|
|
case ir_depth_layout_unchanged: return "depth_unchanged";
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-07 17:18:29 -07:00
|
|
|
ir_expression_operation
|
|
|
|
|
ir_expression::get_operator(const char *str)
|
|
|
|
|
{
|
|
|
|
|
const int operator_count = sizeof(operator_strs) / sizeof(operator_strs[0]);
|
|
|
|
|
for (int op = 0; op < operator_count; op++) {
|
|
|
|
|
if (strcmp(str, operator_strs[op]) == 0)
|
|
|
|
|
return (ir_expression_operation) op;
|
|
|
|
|
}
|
|
|
|
|
return (ir_expression_operation) -1;
|
|
|
|
|
}
|
2010-02-22 13:19:34 -08:00
|
|
|
|
2010-06-09 17:18:04 -07:00
|
|
|
ir_constant::ir_constant()
|
2014-05-27 19:49:04 -07:00
|
|
|
: ir_rvalue(ir_type_constant)
|
2010-06-09 17:18:04 -07:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-11 16:57:47 -07:00
|
|
|
ir_constant::ir_constant(const struct glsl_type *type,
|
|
|
|
|
const ir_constant_data *data)
|
2014-05-27 19:49:04 -07:00
|
|
|
: ir_rvalue(ir_type_constant)
|
2010-02-22 13:19:34 -08:00
|
|
|
{
|
2010-06-11 16:57:47 -07:00
|
|
|
assert((type->base_type >= GLSL_TYPE_UINT)
|
|
|
|
|
&& (type->base_type <= GLSL_TYPE_BOOL));
|
2010-02-22 13:19:34 -08:00
|
|
|
|
|
|
|
|
this->type = type;
|
2010-06-11 16:57:47 -07:00
|
|
|
memcpy(& this->value, data, sizeof(this->value));
|
2010-02-22 13:19:34 -08:00
|
|
|
}
|
|
|
|
|
|
2013-08-05 15:15:37 -07:00
|
|
|
ir_constant::ir_constant(float f, unsigned vector_elements)
|
2014-05-27 19:49:04 -07:00
|
|
|
: ir_rvalue(ir_type_constant)
|
2010-03-26 12:07:44 -07:00
|
|
|
{
|
2013-08-05 15:15:37 -07:00
|
|
|
assert(vector_elements <= 4);
|
|
|
|
|
this->type = glsl_type::get_instance(GLSL_TYPE_FLOAT, vector_elements, 1);
|
|
|
|
|
for (unsigned i = 0; i < vector_elements; i++) {
|
|
|
|
|
this->value.f[i] = f;
|
|
|
|
|
}
|
|
|
|
|
for (unsigned i = vector_elements; i < 16; i++) {
|
2010-08-28 23:55:51 -07:00
|
|
|
this->value.f[i] = 0;
|
|
|
|
|
}
|
2010-03-26 12:07:44 -07:00
|
|
|
}
|
|
|
|
|
|
2015-02-05 11:50:43 +02:00
|
|
|
ir_constant::ir_constant(double d, unsigned vector_elements)
|
|
|
|
|
: ir_rvalue(ir_type_constant)
|
|
|
|
|
{
|
|
|
|
|
assert(vector_elements <= 4);
|
|
|
|
|
this->type = glsl_type::get_instance(GLSL_TYPE_DOUBLE, vector_elements, 1);
|
|
|
|
|
for (unsigned i = 0; i < vector_elements; i++) {
|
|
|
|
|
this->value.d[i] = d;
|
|
|
|
|
}
|
|
|
|
|
for (unsigned i = vector_elements; i < 16; i++) {
|
|
|
|
|
this->value.d[i] = 0.0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-05 15:15:37 -07:00
|
|
|
ir_constant::ir_constant(unsigned int u, unsigned vector_elements)
|
2014-05-27 19:49:04 -07:00
|
|
|
: ir_rvalue(ir_type_constant)
|
2010-03-26 12:07:44 -07:00
|
|
|
{
|
2013-08-05 15:15:37 -07:00
|
|
|
assert(vector_elements <= 4);
|
|
|
|
|
this->type = glsl_type::get_instance(GLSL_TYPE_UINT, vector_elements, 1);
|
|
|
|
|
for (unsigned i = 0; i < vector_elements; i++) {
|
|
|
|
|
this->value.u[i] = u;
|
|
|
|
|
}
|
|
|
|
|
for (unsigned i = vector_elements; i < 16; i++) {
|
2010-08-28 23:55:51 -07:00
|
|
|
this->value.u[i] = 0;
|
|
|
|
|
}
|
2010-03-26 12:07:44 -07:00
|
|
|
}
|
|
|
|
|
|
2013-08-05 15:15:37 -07:00
|
|
|
ir_constant::ir_constant(int integer, unsigned vector_elements)
|
2014-05-27 19:49:04 -07:00
|
|
|
: ir_rvalue(ir_type_constant)
|
2010-03-26 12:07:44 -07:00
|
|
|
{
|
2013-08-05 15:15:37 -07:00
|
|
|
assert(vector_elements <= 4);
|
|
|
|
|
this->type = glsl_type::get_instance(GLSL_TYPE_INT, vector_elements, 1);
|
|
|
|
|
for (unsigned i = 0; i < vector_elements; i++) {
|
|
|
|
|
this->value.i[i] = integer;
|
|
|
|
|
}
|
|
|
|
|
for (unsigned i = vector_elements; i < 16; i++) {
|
2010-08-28 23:55:51 -07:00
|
|
|
this->value.i[i] = 0;
|
|
|
|
|
}
|
2010-03-26 12:07:44 -07:00
|
|
|
}
|
|
|
|
|
|
2013-08-05 15:15:37 -07:00
|
|
|
ir_constant::ir_constant(bool b, unsigned vector_elements)
|
2014-05-27 19:49:04 -07:00
|
|
|
: ir_rvalue(ir_type_constant)
|
2010-03-26 12:07:44 -07:00
|
|
|
{
|
2013-08-05 15:15:37 -07:00
|
|
|
assert(vector_elements <= 4);
|
|
|
|
|
this->type = glsl_type::get_instance(GLSL_TYPE_BOOL, vector_elements, 1);
|
|
|
|
|
for (unsigned i = 0; i < vector_elements; i++) {
|
|
|
|
|
this->value.b[i] = b;
|
|
|
|
|
}
|
|
|
|
|
for (unsigned i = vector_elements; i < 16; i++) {
|
2010-08-28 23:55:51 -07:00
|
|
|
this->value.b[i] = false;
|
|
|
|
|
}
|
2010-03-26 12:07:44 -07:00
|
|
|
}
|
|
|
|
|
|
2010-06-04 16:13:35 -07:00
|
|
|
ir_constant::ir_constant(const ir_constant *c, unsigned i)
|
2014-05-27 19:49:04 -07:00
|
|
|
: ir_rvalue(ir_type_constant)
|
2010-06-04 16:13:35 -07:00
|
|
|
{
|
|
|
|
|
this->type = c->type->get_base_type();
|
|
|
|
|
|
|
|
|
|
switch (this->type->base_type) {
|
|
|
|
|
case GLSL_TYPE_UINT: this->value.u[0] = c->value.u[i]; break;
|
|
|
|
|
case GLSL_TYPE_INT: this->value.i[0] = c->value.i[i]; break;
|
|
|
|
|
case GLSL_TYPE_FLOAT: this->value.f[0] = c->value.f[i]; break;
|
|
|
|
|
case GLSL_TYPE_BOOL: this->value.b[0] = c->value.b[i]; break;
|
2015-02-05 11:50:43 +02:00
|
|
|
case GLSL_TYPE_DOUBLE: this->value.d[0] = c->value.d[i]; break;
|
2010-06-04 16:13:35 -07:00
|
|
|
default: assert(!"Should not get here."); break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-04 16:34:38 -07:00
|
|
|
ir_constant::ir_constant(const struct glsl_type *type, exec_list *value_list)
|
2014-05-27 19:49:04 -07:00
|
|
|
: ir_rvalue(ir_type_constant)
|
2010-06-04 16:34:38 -07:00
|
|
|
{
|
|
|
|
|
this->type = type;
|
|
|
|
|
|
2010-06-09 17:11:50 -07:00
|
|
|
assert(type->is_scalar() || type->is_vector() || type->is_matrix()
|
2010-07-20 01:06:33 -07:00
|
|
|
|| type->is_record() || type->is_array());
|
|
|
|
|
|
|
|
|
|
if (type->is_array()) {
|
2011-01-21 14:32:31 -08:00
|
|
|
this->array_elements = ralloc_array(this, ir_constant *, type->length);
|
2010-07-20 01:06:33 -07:00
|
|
|
unsigned i = 0;
|
2014-06-24 21:34:05 -07:00
|
|
|
foreach_in_list(ir_constant, value, value_list) {
|
2010-07-20 01:06:33 -07:00
|
|
|
assert(value->as_constant() != NULL);
|
|
|
|
|
|
|
|
|
|
this->array_elements[i++] = value;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
2010-06-09 17:11:50 -07:00
|
|
|
|
|
|
|
|
/* If the constant is a record, the types of each of the entries in
|
|
|
|
|
* value_list must be a 1-for-1 match with the structure components. Each
|
|
|
|
|
* entry must also be a constant. Just move the nodes from the value_list
|
|
|
|
|
* to the list in the ir_constant.
|
|
|
|
|
*/
|
|
|
|
|
/* FINISHME: Should there be some type checking and / or assertions here? */
|
|
|
|
|
/* FINISHME: Should the new constant take ownership of the nodes from
|
|
|
|
|
* FINISHME: value_list, or should it make copies?
|
|
|
|
|
*/
|
|
|
|
|
if (type->is_record()) {
|
|
|
|
|
value_list->move_nodes_to(& this->components);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-29 13:15:56 -07:00
|
|
|
for (unsigned i = 0; i < 16; i++) {
|
|
|
|
|
this->value.u[i] = 0;
|
|
|
|
|
}
|
2010-06-04 16:34:38 -07:00
|
|
|
|
|
|
|
|
ir_constant *value = (ir_constant *) (value_list->head);
|
|
|
|
|
|
2010-09-01 15:31:06 -07:00
|
|
|
/* Constructors with exactly one scalar argument are special for vectors
|
|
|
|
|
* and matrices. For vectors, the scalar value is replicated to fill all
|
|
|
|
|
* the components. For matrices, the scalar fills the components of the
|
|
|
|
|
* diagonal while the rest is filled with 0.
|
|
|
|
|
*/
|
|
|
|
|
if (value->type->is_scalar() && value->next->is_tail_sentinel()) {
|
|
|
|
|
if (type->is_matrix()) {
|
|
|
|
|
/* Matrix - fill diagonal (rest is already set to 0) */
|
2015-02-05 11:50:43 +02:00
|
|
|
assert(type->base_type == GLSL_TYPE_FLOAT ||
|
|
|
|
|
type->base_type == GLSL_TYPE_DOUBLE);
|
|
|
|
|
for (unsigned i = 0; i < type->matrix_columns; i++) {
|
|
|
|
|
if (type->base_type == GLSL_TYPE_FLOAT)
|
|
|
|
|
this->value.f[i * type->vector_elements + i] =
|
|
|
|
|
value->value.f[0];
|
|
|
|
|
else
|
|
|
|
|
this->value.d[i * type->vector_elements + i] =
|
|
|
|
|
value->value.d[0];
|
|
|
|
|
}
|
2010-09-01 15:31:06 -07:00
|
|
|
} else {
|
|
|
|
|
/* Vector or scalar - fill all components */
|
|
|
|
|
switch (type->base_type) {
|
|
|
|
|
case GLSL_TYPE_UINT:
|
|
|
|
|
case GLSL_TYPE_INT:
|
|
|
|
|
for (unsigned i = 0; i < type->components(); i++)
|
|
|
|
|
this->value.u[i] = value->value.u[0];
|
|
|
|
|
break;
|
|
|
|
|
case GLSL_TYPE_FLOAT:
|
|
|
|
|
for (unsigned i = 0; i < type->components(); i++)
|
|
|
|
|
this->value.f[i] = value->value.f[0];
|
|
|
|
|
break;
|
2015-02-05 11:50:43 +02:00
|
|
|
case GLSL_TYPE_DOUBLE:
|
|
|
|
|
for (unsigned i = 0; i < type->components(); i++)
|
|
|
|
|
this->value.d[i] = value->value.d[0];
|
|
|
|
|
break;
|
2010-09-01 15:31:06 -07:00
|
|
|
case GLSL_TYPE_BOOL:
|
|
|
|
|
for (unsigned i = 0; i < type->components(); i++)
|
|
|
|
|
this->value.b[i] = value->value.b[0];
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(!"Should not get here.");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2010-09-01 15:37:13 -07:00
|
|
|
if (type->is_matrix() && value->type->is_matrix()) {
|
|
|
|
|
assert(value->next->is_tail_sentinel());
|
|
|
|
|
|
|
|
|
|
/* From section 5.4.2 of the GLSL 1.20 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."
|
|
|
|
|
*/
|
|
|
|
|
unsigned cols = MIN2(type->matrix_columns, value->type->matrix_columns);
|
|
|
|
|
unsigned rows = MIN2(type->vector_elements, value->type->vector_elements);
|
|
|
|
|
for (unsigned i = 0; i < cols; i++) {
|
|
|
|
|
for (unsigned j = 0; j < rows; j++) {
|
|
|
|
|
const unsigned src = i * value->type->vector_elements + j;
|
|
|
|
|
const unsigned dst = i * type->vector_elements + j;
|
|
|
|
|
this->value.f[dst] = value->value.f[src];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* "All other components will be initialized to the identity matrix." */
|
|
|
|
|
for (unsigned i = cols; i < type->matrix_columns; i++)
|
|
|
|
|
this->value.f[i * type->vector_elements + i] = 1.0;
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-04 16:34:38 -07:00
|
|
|
/* Use each component from each entry in the value_list to initialize one
|
|
|
|
|
* component of the constant being constructed.
|
|
|
|
|
*/
|
|
|
|
|
for (unsigned i = 0; i < type->components(); /* empty */) {
|
|
|
|
|
assert(value->as_constant() != NULL);
|
2010-07-29 13:52:25 -07:00
|
|
|
assert(!value->is_tail_sentinel());
|
2010-06-04 16:34:38 -07:00
|
|
|
|
|
|
|
|
for (unsigned j = 0; j < value->type->components(); j++) {
|
|
|
|
|
switch (type->base_type) {
|
|
|
|
|
case GLSL_TYPE_UINT:
|
|
|
|
|
this->value.u[i] = value->get_uint_component(j);
|
|
|
|
|
break;
|
|
|
|
|
case GLSL_TYPE_INT:
|
|
|
|
|
this->value.i[i] = value->get_int_component(j);
|
|
|
|
|
break;
|
|
|
|
|
case GLSL_TYPE_FLOAT:
|
|
|
|
|
this->value.f[i] = value->get_float_component(j);
|
|
|
|
|
break;
|
|
|
|
|
case GLSL_TYPE_BOOL:
|
|
|
|
|
this->value.b[i] = value->get_bool_component(j);
|
|
|
|
|
break;
|
2015-02-05 11:50:43 +02:00
|
|
|
case GLSL_TYPE_DOUBLE:
|
|
|
|
|
this->value.d[i] = value->get_double_component(j);
|
|
|
|
|
break;
|
2010-06-04 16:34:38 -07:00
|
|
|
default:
|
|
|
|
|
/* FINISHME: What to do? Exceptions are not the answer.
|
|
|
|
|
*/
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
i++;
|
|
|
|
|
if (i >= type->components())
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value = (ir_constant *) value->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-21 15:54:15 -07:00
|
|
|
ir_constant *
|
|
|
|
|
ir_constant::zero(void *mem_ctx, const glsl_type *type)
|
|
|
|
|
{
|
2012-05-02 23:11:37 +02:00
|
|
|
assert(type->is_scalar() || type->is_vector() || type->is_matrix()
|
|
|
|
|
|| type->is_record() || type->is_array());
|
2010-07-21 15:54:15 -07:00
|
|
|
|
|
|
|
|
ir_constant *c = new(mem_ctx) ir_constant;
|
|
|
|
|
c->type = type;
|
|
|
|
|
memset(&c->value, 0, sizeof(c->value));
|
|
|
|
|
|
2012-05-02 23:11:37 +02:00
|
|
|
if (type->is_array()) {
|
|
|
|
|
c->array_elements = ralloc_array(c, ir_constant *, type->length);
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < type->length; i++)
|
2015-04-30 20:45:54 +10:00
|
|
|
c->array_elements[i] = ir_constant::zero(c, type->fields.array);
|
2012-05-02 23:11:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (type->is_record()) {
|
|
|
|
|
for (unsigned i = 0; i < type->length; i++) {
|
|
|
|
|
ir_constant *comp = ir_constant::zero(mem_ctx, type->fields.structure[i].type);
|
|
|
|
|
c->components.push_tail(comp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-21 15:54:15 -07:00
|
|
|
return c;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-04 16:30:07 -07:00
|
|
|
bool
|
|
|
|
|
ir_constant::get_bool_component(unsigned i) const
|
|
|
|
|
{
|
|
|
|
|
switch (this->type->base_type) {
|
|
|
|
|
case GLSL_TYPE_UINT: return this->value.u[i] != 0;
|
|
|
|
|
case GLSL_TYPE_INT: return this->value.i[i] != 0;
|
|
|
|
|
case GLSL_TYPE_FLOAT: return ((int)this->value.f[i]) != 0;
|
|
|
|
|
case GLSL_TYPE_BOOL: return this->value.b[i];
|
2015-02-05 11:50:43 +02:00
|
|
|
case GLSL_TYPE_DOUBLE: return this->value.d[i] != 0.0;
|
2010-06-04 16:30:07 -07:00
|
|
|
default: assert(!"Should not get here."); break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Must return something to make the compiler happy. This is clearly an
|
|
|
|
|
* error case.
|
|
|
|
|
*/
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float
|
|
|
|
|
ir_constant::get_float_component(unsigned i) const
|
|
|
|
|
{
|
|
|
|
|
switch (this->type->base_type) {
|
|
|
|
|
case GLSL_TYPE_UINT: return (float) this->value.u[i];
|
|
|
|
|
case GLSL_TYPE_INT: return (float) this->value.i[i];
|
|
|
|
|
case GLSL_TYPE_FLOAT: return this->value.f[i];
|
2012-11-04 16:43:44 -07:00
|
|
|
case GLSL_TYPE_BOOL: return this->value.b[i] ? 1.0f : 0.0f;
|
2015-02-05 11:50:43 +02:00
|
|
|
case GLSL_TYPE_DOUBLE: return (float) this->value.d[i];
|
|
|
|
|
default: assert(!"Should not get here."); break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Must return something to make the compiler happy. This is clearly an
|
|
|
|
|
* error case.
|
|
|
|
|
*/
|
|
|
|
|
return 0.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double
|
|
|
|
|
ir_constant::get_double_component(unsigned i) const
|
|
|
|
|
{
|
|
|
|
|
switch (this->type->base_type) {
|
|
|
|
|
case GLSL_TYPE_UINT: return (double) this->value.u[i];
|
|
|
|
|
case GLSL_TYPE_INT: return (double) this->value.i[i];
|
|
|
|
|
case GLSL_TYPE_FLOAT: return (double) this->value.f[i];
|
|
|
|
|
case GLSL_TYPE_BOOL: return this->value.b[i] ? 1.0 : 0.0;
|
|
|
|
|
case GLSL_TYPE_DOUBLE: return this->value.d[i];
|
2010-06-04 16:30:07 -07:00
|
|
|
default: assert(!"Should not get here."); break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Must return something to make the compiler happy. This is clearly an
|
|
|
|
|
* error case.
|
|
|
|
|
*/
|
|
|
|
|
return 0.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
ir_constant::get_int_component(unsigned i) const
|
|
|
|
|
{
|
|
|
|
|
switch (this->type->base_type) {
|
|
|
|
|
case GLSL_TYPE_UINT: return this->value.u[i];
|
|
|
|
|
case GLSL_TYPE_INT: return this->value.i[i];
|
|
|
|
|
case GLSL_TYPE_FLOAT: return (int) this->value.f[i];
|
|
|
|
|
case GLSL_TYPE_BOOL: return this->value.b[i] ? 1 : 0;
|
2015-02-05 11:50:43 +02:00
|
|
|
case GLSL_TYPE_DOUBLE: return (int) this->value.d[i];
|
2010-06-04 16:30:07 -07:00
|
|
|
default: assert(!"Should not get here."); break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Must return something to make the compiler happy. This is clearly an
|
|
|
|
|
* error case.
|
|
|
|
|
*/
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned
|
|
|
|
|
ir_constant::get_uint_component(unsigned i) const
|
|
|
|
|
{
|
|
|
|
|
switch (this->type->base_type) {
|
|
|
|
|
case GLSL_TYPE_UINT: return this->value.u[i];
|
|
|
|
|
case GLSL_TYPE_INT: return this->value.i[i];
|
|
|
|
|
case GLSL_TYPE_FLOAT: return (unsigned) this->value.f[i];
|
|
|
|
|
case GLSL_TYPE_BOOL: return this->value.b[i] ? 1 : 0;
|
2015-02-05 11:50:43 +02:00
|
|
|
case GLSL_TYPE_DOUBLE: return (unsigned) this->value.d[i];
|
2010-06-04 16:30:07 -07:00
|
|
|
default: assert(!"Should not get here."); break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Must return something to make the compiler happy. This is clearly an
|
|
|
|
|
* error case.
|
|
|
|
|
*/
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-20 01:06:33 -07:00
|
|
|
ir_constant *
|
|
|
|
|
ir_constant::get_array_element(unsigned i) const
|
|
|
|
|
{
|
|
|
|
|
assert(this->type->is_array());
|
2010-08-17 12:57:28 -07:00
|
|
|
|
|
|
|
|
/* From page 35 (page 41 of the PDF) of the GLSL 1.20 spec:
|
|
|
|
|
*
|
|
|
|
|
* "Behavior is undefined if a shader subscripts an array with an index
|
|
|
|
|
* less than 0 or greater than or equal to the size the array was
|
|
|
|
|
* declared with."
|
|
|
|
|
*
|
|
|
|
|
* Most out-of-bounds accesses are removed before things could get this far.
|
|
|
|
|
* There are cases where non-constant array index values can get constant
|
|
|
|
|
* folded.
|
|
|
|
|
*/
|
|
|
|
|
if (int(i) < 0)
|
|
|
|
|
i = 0;
|
|
|
|
|
else if (i >= this->type->length)
|
|
|
|
|
i = this->type->length - 1;
|
2010-07-20 01:06:33 -07:00
|
|
|
|
|
|
|
|
return array_elements[i];
|
|
|
|
|
}
|
2010-02-22 13:19:34 -08:00
|
|
|
|
2010-06-09 17:28:54 -07:00
|
|
|
ir_constant *
|
|
|
|
|
ir_constant::get_record_field(const char *name)
|
|
|
|
|
{
|
|
|
|
|
int idx = this->type->field_index(name);
|
|
|
|
|
|
|
|
|
|
if (idx < 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
if (this->components.is_empty())
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
exec_node *node = this->components.head;
|
|
|
|
|
for (int i = 0; i < idx; i++) {
|
|
|
|
|
node = node->next;
|
|
|
|
|
|
|
|
|
|
/* If the end of the list is encountered before the element matching the
|
|
|
|
|
* requested field is found, return NULL.
|
|
|
|
|
*/
|
2010-07-29 13:52:25 -07:00
|
|
|
if (node->is_tail_sentinel())
|
2010-06-09 17:28:54 -07:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (ir_constant *) node;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 23:11:40 +02:00
|
|
|
void
|
|
|
|
|
ir_constant::copy_offset(ir_constant *src, int offset)
|
|
|
|
|
{
|
|
|
|
|
switch (this->type->base_type) {
|
|
|
|
|
case GLSL_TYPE_UINT:
|
|
|
|
|
case GLSL_TYPE_INT:
|
|
|
|
|
case GLSL_TYPE_FLOAT:
|
2015-02-05 11:50:43 +02:00
|
|
|
case GLSL_TYPE_DOUBLE:
|
2012-05-02 23:11:40 +02:00
|
|
|
case GLSL_TYPE_BOOL: {
|
|
|
|
|
unsigned int size = src->type->components();
|
|
|
|
|
assert (size <= this->type->components() - offset);
|
|
|
|
|
for (unsigned int i=0; i<size; i++) {
|
|
|
|
|
switch (this->type->base_type) {
|
|
|
|
|
case GLSL_TYPE_UINT:
|
|
|
|
|
value.u[i+offset] = src->get_uint_component(i);
|
|
|
|
|
break;
|
|
|
|
|
case GLSL_TYPE_INT:
|
|
|
|
|
value.i[i+offset] = src->get_int_component(i);
|
|
|
|
|
break;
|
|
|
|
|
case GLSL_TYPE_FLOAT:
|
|
|
|
|
value.f[i+offset] = src->get_float_component(i);
|
|
|
|
|
break;
|
|
|
|
|
case GLSL_TYPE_BOOL:
|
|
|
|
|
value.b[i+offset] = src->get_bool_component(i);
|
|
|
|
|
break;
|
2015-02-05 11:50:43 +02:00
|
|
|
case GLSL_TYPE_DOUBLE:
|
|
|
|
|
value.d[i+offset] = src->get_double_component(i);
|
|
|
|
|
break;
|
2012-05-02 23:11:40 +02:00
|
|
|
default: // Shut up the compiler
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case GLSL_TYPE_STRUCT: {
|
|
|
|
|
assert (src->type == this->type);
|
|
|
|
|
this->components.make_empty();
|
2014-06-24 21:34:05 -07:00
|
|
|
foreach_in_list(ir_constant, orig, &src->components) {
|
2012-05-02 23:11:40 +02:00
|
|
|
this->components.push_tail(orig->clone(this, NULL));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case GLSL_TYPE_ARRAY: {
|
|
|
|
|
assert (src->type == this->type);
|
|
|
|
|
for (unsigned i = 0; i < this->type->length; i++) {
|
|
|
|
|
this->array_elements[i] = src->array_elements[i]->clone(this, NULL);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(!"Should not get here.");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ir_constant::copy_masked_offset(ir_constant *src, int offset, unsigned int mask)
|
|
|
|
|
{
|
|
|
|
|
assert (!type->is_array() && !type->is_record());
|
|
|
|
|
|
|
|
|
|
if (!type->is_vector() && !type->is_matrix()) {
|
|
|
|
|
offset = 0;
|
|
|
|
|
mask = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int id = 0;
|
|
|
|
|
for (int i=0; i<4; i++) {
|
|
|
|
|
if (mask & (1 << i)) {
|
|
|
|
|
switch (this->type->base_type) {
|
|
|
|
|
case GLSL_TYPE_UINT:
|
|
|
|
|
value.u[i+offset] = src->get_uint_component(id++);
|
|
|
|
|
break;
|
|
|
|
|
case GLSL_TYPE_INT:
|
|
|
|
|
value.i[i+offset] = src->get_int_component(id++);
|
|
|
|
|
break;
|
|
|
|
|
case GLSL_TYPE_FLOAT:
|
|
|
|
|
value.f[i+offset] = src->get_float_component(id++);
|
|
|
|
|
break;
|
|
|
|
|
case GLSL_TYPE_BOOL:
|
|
|
|
|
value.b[i+offset] = src->get_bool_component(id++);
|
|
|
|
|
break;
|
2015-02-05 11:50:43 +02:00
|
|
|
case GLSL_TYPE_DOUBLE:
|
|
|
|
|
value.d[i+offset] = src->get_double_component(id++);
|
|
|
|
|
break;
|
2012-05-02 23:11:40 +02:00
|
|
|
default:
|
|
|
|
|
assert(!"Should not get here.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-06-09 17:28:54 -07:00
|
|
|
|
2010-06-17 19:50:36 -07:00
|
|
|
bool
|
|
|
|
|
ir_constant::has_value(const ir_constant *c) const
|
|
|
|
|
{
|
|
|
|
|
if (this->type != c->type)
|
|
|
|
|
return false;
|
|
|
|
|
|
2010-07-20 03:08:32 -07:00
|
|
|
if (this->type->is_array()) {
|
|
|
|
|
for (unsigned i = 0; i < this->type->length; i++) {
|
2010-12-02 08:52:58 -08:00
|
|
|
if (!this->array_elements[i]->has_value(c->array_elements[i]))
|
2010-07-20 03:08:32 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-17 19:50:36 -07:00
|
|
|
if (this->type->base_type == GLSL_TYPE_STRUCT) {
|
|
|
|
|
const exec_node *a_node = this->components.head;
|
|
|
|
|
const exec_node *b_node = c->components.head;
|
|
|
|
|
|
2010-07-29 13:52:25 -07:00
|
|
|
while (!a_node->is_tail_sentinel()) {
|
|
|
|
|
assert(!b_node->is_tail_sentinel());
|
2010-06-17 19:50:36 -07:00
|
|
|
|
|
|
|
|
const ir_constant *const a_field = (ir_constant *) a_node;
|
|
|
|
|
const ir_constant *const b_field = (ir_constant *) b_node;
|
|
|
|
|
|
|
|
|
|
if (!a_field->has_value(b_field))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
a_node = a_node->next;
|
|
|
|
|
b_node = b_node->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < this->type->components(); i++) {
|
|
|
|
|
switch (this->type->base_type) {
|
|
|
|
|
case GLSL_TYPE_UINT:
|
|
|
|
|
if (this->value.u[i] != c->value.u[i])
|
|
|
|
|
return false;
|
|
|
|
|
break;
|
|
|
|
|
case GLSL_TYPE_INT:
|
|
|
|
|
if (this->value.i[i] != c->value.i[i])
|
|
|
|
|
return false;
|
|
|
|
|
break;
|
|
|
|
|
case GLSL_TYPE_FLOAT:
|
|
|
|
|
if (this->value.f[i] != c->value.f[i])
|
|
|
|
|
return false;
|
|
|
|
|
break;
|
|
|
|
|
case GLSL_TYPE_BOOL:
|
|
|
|
|
if (this->value.b[i] != c->value.b[i])
|
|
|
|
|
return false;
|
|
|
|
|
break;
|
2015-02-05 11:50:43 +02:00
|
|
|
case GLSL_TYPE_DOUBLE:
|
|
|
|
|
if (this->value.d[i] != c->value.d[i])
|
|
|
|
|
return false;
|
|
|
|
|
break;
|
2010-06-17 19:50:36 -07:00
|
|
|
default:
|
|
|
|
|
assert(!"Should not get here.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-12 10:19:08 -08:00
|
|
|
bool
|
2014-01-05 22:42:31 -08:00
|
|
|
ir_constant::is_value(float f, int i) const
|
2010-11-12 10:19:08 -08:00
|
|
|
{
|
|
|
|
|
if (!this->type->is_scalar() && !this->type->is_vector())
|
|
|
|
|
return false;
|
|
|
|
|
|
2014-01-05 22:42:31 -08:00
|
|
|
/* Only accept boolean values for 0/1. */
|
|
|
|
|
if (int(bool(i)) != i && this->type->is_boolean())
|
|
|
|
|
return false;
|
|
|
|
|
|
2010-11-12 10:19:08 -08:00
|
|
|
for (unsigned c = 0; c < this->type->vector_elements; c++) {
|
|
|
|
|
switch (this->type->base_type) {
|
|
|
|
|
case GLSL_TYPE_FLOAT:
|
2014-01-05 22:42:31 -08:00
|
|
|
if (this->value.f[c] != f)
|
2010-11-12 10:19:08 -08:00
|
|
|
return false;
|
|
|
|
|
break;
|
|
|
|
|
case GLSL_TYPE_INT:
|
2014-01-05 22:42:31 -08:00
|
|
|
if (this->value.i[c] != i)
|
2010-11-12 10:19:08 -08:00
|
|
|
return false;
|
|
|
|
|
break;
|
|
|
|
|
case GLSL_TYPE_UINT:
|
2014-01-05 22:42:31 -08:00
|
|
|
if (this->value.u[c] != unsigned(i))
|
2010-11-12 10:19:08 -08:00
|
|
|
return false;
|
|
|
|
|
break;
|
|
|
|
|
case GLSL_TYPE_BOOL:
|
2014-01-05 22:42:31 -08:00
|
|
|
if (this->value.b[c] != bool(i))
|
2010-11-12 10:19:08 -08:00
|
|
|
return false;
|
|
|
|
|
break;
|
2015-02-05 11:50:43 +02:00
|
|
|
case GLSL_TYPE_DOUBLE:
|
|
|
|
|
if (this->value.d[c] != double(f))
|
|
|
|
|
return false;
|
|
|
|
|
break;
|
2010-11-12 10:19:08 -08:00
|
|
|
default:
|
|
|
|
|
/* The only other base types are structures, arrays, and samplers.
|
|
|
|
|
* Samplers cannot be constants, and the others should have been
|
|
|
|
|
* filtered out above.
|
|
|
|
|
*/
|
|
|
|
|
assert(!"Should not get here.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2014-01-05 22:42:31 -08:00
|
|
|
ir_constant::is_zero() const
|
2010-11-12 10:19:08 -08:00
|
|
|
{
|
2014-01-05 22:42:31 -08:00
|
|
|
return is_value(0.0, 0);
|
|
|
|
|
}
|
2010-11-12 10:19:08 -08:00
|
|
|
|
2014-01-05 22:42:31 -08:00
|
|
|
bool
|
|
|
|
|
ir_constant::is_one() const
|
|
|
|
|
{
|
|
|
|
|
return is_value(1.0, 1);
|
2010-11-12 10:19:08 -08:00
|
|
|
}
|
2010-08-26 15:11:26 -07:00
|
|
|
|
2010-11-16 11:59:22 -08:00
|
|
|
bool
|
|
|
|
|
ir_constant::is_negative_one() const
|
|
|
|
|
{
|
2014-01-05 22:42:31 -08:00
|
|
|
return is_value(-1.0, -1);
|
2010-11-16 11:59:22 -08:00
|
|
|
}
|
|
|
|
|
|
2014-04-06 18:34:59 -07:00
|
|
|
bool
|
|
|
|
|
ir_constant::is_uint16_constant() const
|
|
|
|
|
{
|
|
|
|
|
if (!type->is_integer())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return value.u[0] < (1 << 16);
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-26 15:11:26 -07:00
|
|
|
ir_loop::ir_loop()
|
2014-05-27 19:49:04 -07:00
|
|
|
: ir_instruction(ir_type_loop)
|
2010-08-26 15:11:26 -07:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-05-19 11:37:35 +02:00
|
|
|
ir_dereference_variable::ir_dereference_variable(ir_variable *var)
|
2014-05-27 19:49:04 -07:00
|
|
|
: ir_dereference(ir_type_dereference_variable)
|
2010-02-22 13:19:34 -08:00
|
|
|
{
|
2012-03-13 13:05:16 -07:00
|
|
|
assert(var != NULL);
|
|
|
|
|
|
2010-02-22 13:19:34 -08:00
|
|
|
this->var = var;
|
2012-03-13 13:05:16 -07:00
|
|
|
this->type = var->type;
|
2010-02-22 13:19:34 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-05-19 11:37:35 +02:00
|
|
|
ir_dereference_array::ir_dereference_array(ir_rvalue *value,
|
|
|
|
|
ir_rvalue *array_index)
|
2014-05-27 19:49:04 -07:00
|
|
|
: ir_dereference(ir_type_dereference_array)
|
2010-03-25 17:01:15 -07:00
|
|
|
{
|
2010-05-19 13:52:29 +02:00
|
|
|
this->array_index = array_index;
|
2010-05-19 11:37:35 +02:00
|
|
|
this->set_array(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ir_dereference_array::ir_dereference_array(ir_variable *var,
|
|
|
|
|
ir_rvalue *array_index)
|
2014-05-27 19:49:04 -07:00
|
|
|
: ir_dereference(ir_type_dereference_array)
|
2010-05-19 11:37:35 +02:00
|
|
|
{
|
2011-01-21 14:32:31 -08:00
|
|
|
void *ctx = ralloc_parent(var);
|
2010-06-23 18:11:51 -07:00
|
|
|
|
2010-05-19 13:52:29 +02:00
|
|
|
this->array_index = array_index;
|
2010-06-23 18:11:51 -07:00
|
|
|
this->set_array(new(ctx) ir_dereference_variable(var));
|
2010-05-19 11:37:35 +02:00
|
|
|
}
|
2010-04-01 18:02:48 -07:00
|
|
|
|
2010-05-19 11:37:35 +02:00
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ir_dereference_array::set_array(ir_rvalue *value)
|
|
|
|
|
{
|
2012-03-13 12:39:32 -07:00
|
|
|
assert(value != NULL);
|
|
|
|
|
|
2010-05-19 13:52:29 +02:00
|
|
|
this->array = value;
|
2010-05-19 11:37:35 +02:00
|
|
|
|
2012-03-13 12:39:32 -07:00
|
|
|
const glsl_type *const vt = this->array->type;
|
2010-04-01 18:02:48 -07:00
|
|
|
|
2012-03-13 12:39:32 -07:00
|
|
|
if (vt->is_array()) {
|
2015-04-30 20:45:54 +10:00
|
|
|
type = vt->fields.array;
|
2012-03-13 12:39:32 -07:00
|
|
|
} else if (vt->is_matrix()) {
|
|
|
|
|
type = vt->column_type();
|
|
|
|
|
} else if (vt->is_vector()) {
|
|
|
|
|
type = vt->get_base_type();
|
2010-04-01 18:02:48 -07:00
|
|
|
}
|
2010-05-19 11:37:35 +02:00
|
|
|
}
|
2010-04-01 18:02:48 -07:00
|
|
|
|
2010-05-19 11:37:35 +02:00
|
|
|
|
|
|
|
|
ir_dereference_record::ir_dereference_record(ir_rvalue *value,
|
|
|
|
|
const char *field)
|
2014-05-27 19:49:04 -07:00
|
|
|
: ir_dereference(ir_type_dereference_record)
|
2010-05-19 11:37:35 +02:00
|
|
|
{
|
2012-03-13 12:51:15 -07:00
|
|
|
assert(value != NULL);
|
|
|
|
|
|
2010-05-19 13:52:29 +02:00
|
|
|
this->record = value;
|
2011-01-21 14:32:31 -08:00
|
|
|
this->field = ralloc_strdup(this, field);
|
2012-03-13 12:51:15 -07:00
|
|
|
this->type = this->record->type->field_type(field);
|
2010-03-25 17:01:15 -07:00
|
|
|
}
|
|
|
|
|
|
2010-05-19 11:37:35 +02:00
|
|
|
|
|
|
|
|
ir_dereference_record::ir_dereference_record(ir_variable *var,
|
|
|
|
|
const char *field)
|
2014-05-27 19:49:04 -07:00
|
|
|
: ir_dereference(ir_type_dereference_record)
|
2010-04-19 15:40:49 -07:00
|
|
|
{
|
2011-01-21 14:32:31 -08:00
|
|
|
void *ctx = ralloc_parent(var);
|
2010-06-23 18:11:51 -07:00
|
|
|
|
|
|
|
|
this->record = new(ctx) ir_dereference_variable(var);
|
2011-01-21 14:32:31 -08:00
|
|
|
this->field = ralloc_strdup(this, field);
|
2012-03-13 12:51:15 -07:00
|
|
|
this->type = this->record->type->field_type(field);
|
2010-04-19 15:40:49 -07:00
|
|
|
}
|
|
|
|
|
|
2010-04-01 20:27:35 -10:00
|
|
|
bool
|
2011-08-02 15:22:25 -07:00
|
|
|
ir_dereference::is_lvalue() const
|
2010-04-01 20:27:35 -10:00
|
|
|
{
|
2010-05-19 11:37:35 +02:00
|
|
|
ir_variable *var = this->variable_referenced();
|
2010-04-01 20:27:35 -10:00
|
|
|
|
2010-05-19 11:37:35 +02:00
|
|
|
/* Every l-value derference chain eventually ends in a variable.
|
2010-04-21 11:54:02 -07:00
|
|
|
*/
|
2013-12-12 12:57:57 +02:00
|
|
|
if ((var == NULL) || var->data.read_only)
|
2010-05-19 11:37:35 +02:00
|
|
|
return false;
|
2010-05-14 17:35:42 -07:00
|
|
|
|
2013-11-25 19:38:37 -08:00
|
|
|
/* From section 4.1.7 of the GLSL 4.40 spec:
|
2010-08-25 23:27:56 -07:00
|
|
|
*
|
2013-11-25 19:38:37 -08:00
|
|
|
* "Opaque variables cannot be treated as l-values; hence cannot
|
|
|
|
|
* be used as out or inout function parameters, nor can they be
|
|
|
|
|
* assigned into."
|
2010-08-25 23:27:56 -07:00
|
|
|
*/
|
2013-11-25 19:38:37 -08:00
|
|
|
if (this->type->contains_opaque())
|
2010-08-25 23:27:56 -07:00
|
|
|
return false;
|
|
|
|
|
|
2010-05-19 11:37:35 +02:00
|
|
|
return true;
|
2010-05-14 17:35:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-04-22 16:58:16 +08:00
|
|
|
static const char * const tex_opcode_strs[] = { "tex", "txb", "txl", "txd", "txf", "txf_ms", "txs", "lod", "tg4", "query_levels" };
|
2010-05-26 16:41:47 -07:00
|
|
|
|
|
|
|
|
const char *ir_texture::opcode_string()
|
|
|
|
|
{
|
|
|
|
|
assert((unsigned int) op <=
|
|
|
|
|
sizeof(tex_opcode_strs) / sizeof(tex_opcode_strs[0]));
|
|
|
|
|
return tex_opcode_strs[op];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ir_texture_opcode
|
|
|
|
|
ir_texture::get_opcode(const char *str)
|
|
|
|
|
{
|
|
|
|
|
const int count = sizeof(tex_opcode_strs) / sizeof(tex_opcode_strs[0]);
|
|
|
|
|
for (int op = 0; op < count; op++) {
|
|
|
|
|
if (strcmp(str, tex_opcode_strs[op]) == 0)
|
|
|
|
|
return (ir_texture_opcode) op;
|
|
|
|
|
}
|
|
|
|
|
return (ir_texture_opcode) -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-06-03 15:07:34 -07:00
|
|
|
void
|
2011-02-25 14:29:36 -08:00
|
|
|
ir_texture::set_sampler(ir_dereference *sampler, const glsl_type *type)
|
2010-06-03 15:07:34 -07:00
|
|
|
{
|
|
|
|
|
assert(sampler != NULL);
|
2011-02-25 14:29:36 -08:00
|
|
|
assert(type != NULL);
|
2010-06-03 15:07:34 -07:00
|
|
|
this->sampler = sampler;
|
2011-02-25 14:29:36 -08:00
|
|
|
this->type = type;
|
2010-06-03 15:07:34 -07:00
|
|
|
|
2013-09-26 19:37:30 +12:00
|
|
|
if (this->op == ir_txs || this->op == ir_query_levels) {
|
2011-02-25 14:45:33 -08:00
|
|
|
assert(type->base_type == GLSL_TYPE_INT);
|
2012-09-23 19:50:41 +10:00
|
|
|
} else if (this->op == ir_lod) {
|
|
|
|
|
assert(type->vector_elements == 2);
|
|
|
|
|
assert(type->base_type == GLSL_TYPE_FLOAT);
|
2011-02-25 14:45:33 -08:00
|
|
|
} else {
|
|
|
|
|
assert(sampler->type->sampler_type == (int) type->base_type);
|
|
|
|
|
if (sampler->type->sampler_shadow)
|
|
|
|
|
assert(type->vector_elements == 4 || type->vector_elements == 1);
|
|
|
|
|
else
|
|
|
|
|
assert(type->vector_elements == 4);
|
|
|
|
|
}
|
2010-06-03 15:07:34 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-06-25 15:25:27 -07:00
|
|
|
void
|
|
|
|
|
ir_swizzle::init_mask(const unsigned *comp, unsigned count)
|
2010-03-24 15:12:21 -07:00
|
|
|
{
|
|
|
|
|
assert((count >= 1) && (count <= 4));
|
|
|
|
|
|
2010-06-25 15:25:27 -07:00
|
|
|
memset(&this->mask, 0, sizeof(this->mask));
|
|
|
|
|
this->mask.num_components = count;
|
|
|
|
|
|
|
|
|
|
unsigned dup_mask = 0;
|
|
|
|
|
switch (count) {
|
|
|
|
|
case 4:
|
|
|
|
|
assert(comp[3] <= 3);
|
|
|
|
|
dup_mask |= (1U << comp[3])
|
|
|
|
|
& ((1U << comp[0]) | (1U << comp[1]) | (1U << comp[2]));
|
|
|
|
|
this->mask.w = comp[3];
|
|
|
|
|
|
|
|
|
|
case 3:
|
|
|
|
|
assert(comp[2] <= 3);
|
|
|
|
|
dup_mask |= (1U << comp[2])
|
|
|
|
|
& ((1U << comp[0]) | (1U << comp[1]));
|
|
|
|
|
this->mask.z = comp[2];
|
|
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
|
assert(comp[1] <= 3);
|
|
|
|
|
dup_mask |= (1U << comp[1])
|
|
|
|
|
& ((1U << comp[0]));
|
|
|
|
|
this->mask.y = comp[1];
|
|
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
|
assert(comp[0] <= 3);
|
|
|
|
|
this->mask.x = comp[0];
|
|
|
|
|
}
|
2010-03-24 15:12:21 -07:00
|
|
|
|
2010-06-25 15:25:27 -07:00
|
|
|
this->mask.has_duplicates = dup_mask != 0;
|
2010-03-26 01:20:08 -07:00
|
|
|
|
|
|
|
|
/* Based on the number of elements in the swizzle and the base type
|
|
|
|
|
* (i.e., float, int, unsigned, or bool) of the vector being swizzled,
|
|
|
|
|
* generate the type of the resulting value.
|
|
|
|
|
*/
|
|
|
|
|
type = glsl_type::get_instance(val->type->base_type, mask.num_components, 1);
|
2010-03-24 15:12:21 -07:00
|
|
|
}
|
|
|
|
|
|
2010-06-25 15:25:27 -07:00
|
|
|
ir_swizzle::ir_swizzle(ir_rvalue *val, unsigned x, unsigned y, unsigned z,
|
|
|
|
|
unsigned w, unsigned count)
|
2014-05-27 19:49:04 -07:00
|
|
|
: ir_rvalue(ir_type_swizzle), val(val)
|
2010-06-25 15:25:27 -07:00
|
|
|
{
|
|
|
|
|
const unsigned components[4] = { x, y, z, w };
|
|
|
|
|
this->init_mask(components, count);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ir_swizzle::ir_swizzle(ir_rvalue *val, const unsigned *comp,
|
|
|
|
|
unsigned count)
|
2014-05-27 19:49:04 -07:00
|
|
|
: ir_rvalue(ir_type_swizzle), val(val)
|
2010-06-25 15:25:27 -07:00
|
|
|
{
|
|
|
|
|
this->init_mask(comp, count);
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-03 17:08:01 -07:00
|
|
|
ir_swizzle::ir_swizzle(ir_rvalue *val, ir_swizzle_mask mask)
|
2014-05-27 19:49:04 -07:00
|
|
|
: ir_rvalue(ir_type_swizzle)
|
2010-05-03 17:08:01 -07:00
|
|
|
{
|
|
|
|
|
this->val = val;
|
|
|
|
|
this->mask = mask;
|
|
|
|
|
this->type = glsl_type::get_instance(val->type->base_type,
|
|
|
|
|
mask.num_components, 1);
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-26 01:20:08 -07:00
|
|
|
#define X 1
|
|
|
|
|
#define R 5
|
|
|
|
|
#define S 9
|
|
|
|
|
#define I 13
|
|
|
|
|
|
|
|
|
|
ir_swizzle *
|
|
|
|
|
ir_swizzle::create(ir_rvalue *val, const char *str, unsigned vector_length)
|
|
|
|
|
{
|
2011-01-21 14:32:31 -08:00
|
|
|
void *ctx = ralloc_parent(val);
|
2010-06-23 18:11:51 -07:00
|
|
|
|
2010-03-26 01:20:08 -07:00
|
|
|
/* For each possible swizzle character, this table encodes the value in
|
|
|
|
|
* \c idx_map that represents the 0th element of the vector. For invalid
|
|
|
|
|
* swizzle characters (e.g., 'k'), a special value is used that will allow
|
|
|
|
|
* detection of errors.
|
|
|
|
|
*/
|
|
|
|
|
static const unsigned char base_idx[26] = {
|
|
|
|
|
/* a b c d e f g h i j k l m */
|
|
|
|
|
R, R, I, I, I, I, R, I, I, I, I, I, I,
|
|
|
|
|
/* n o p q r s t u v w x y z */
|
|
|
|
|
I, I, S, S, R, S, S, I, I, X, X, X, X
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Each valid swizzle character has an entry in the previous table. This
|
|
|
|
|
* table encodes the base index encoded in the previous table plus the actual
|
|
|
|
|
* index of the swizzle character. When processing swizzles, the first
|
|
|
|
|
* character in the string is indexed in the previous table. Each character
|
|
|
|
|
* in the string is indexed in this table, and the value found there has the
|
|
|
|
|
* value form the first table subtracted. The result must be on the range
|
|
|
|
|
* [0,3].
|
|
|
|
|
*
|
|
|
|
|
* For example, the string "wzyx" will get X from the first table. Each of
|
|
|
|
|
* the charcaters will get X+3, X+2, X+1, and X+0 from this table. After
|
|
|
|
|
* subtraction, the swizzle values are { 3, 2, 1, 0 }.
|
|
|
|
|
*
|
|
|
|
|
* The string "wzrg" will get X from the first table. Each of the characters
|
|
|
|
|
* will get X+3, X+2, R+0, and R+1 from this table. After subtraction, the
|
|
|
|
|
* swizzle values are { 3, 2, 4, 5 }. Since 4 and 5 are outside the range
|
|
|
|
|
* [0,3], the error is detected.
|
|
|
|
|
*/
|
|
|
|
|
static const unsigned char idx_map[26] = {
|
|
|
|
|
/* a b c d e f g h i j k l m */
|
|
|
|
|
R+3, R+2, 0, 0, 0, 0, R+1, 0, 0, 0, 0, 0, 0,
|
|
|
|
|
/* n o p q r s t u v w x y z */
|
|
|
|
|
0, 0, S+2, S+3, R+0, S+0, S+1, 0, 0, X+3, X+0, X+1, X+2
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int swiz_idx[4] = { 0, 0, 0, 0 };
|
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Validate the first character in the swizzle string and look up the base
|
|
|
|
|
* index value as described above.
|
|
|
|
|
*/
|
|
|
|
|
if ((str[0] < 'a') || (str[0] > 'z'))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
const unsigned base = base_idx[str[0] - 'a'];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; (i < 4) && (str[i] != '\0'); i++) {
|
|
|
|
|
/* Validate the next character, and, as described above, convert it to a
|
|
|
|
|
* swizzle index.
|
|
|
|
|
*/
|
|
|
|
|
if ((str[i] < 'a') || (str[i] > 'z'))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
swiz_idx[i] = idx_map[str[i] - 'a'] - base;
|
|
|
|
|
if ((swiz_idx[i] < 0) || (swiz_idx[i] >= (int) vector_length))
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (str[i] != '\0')
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2010-06-23 18:11:51 -07:00
|
|
|
return new(ctx) ir_swizzle(val, swiz_idx[0], swiz_idx[1], swiz_idx[2],
|
|
|
|
|
swiz_idx[3], i);
|
2010-03-26 01:20:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef X
|
|
|
|
|
#undef R
|
|
|
|
|
#undef S
|
|
|
|
|
#undef I
|
2010-03-24 15:12:21 -07:00
|
|
|
|
2010-05-14 17:35:42 -07:00
|
|
|
ir_variable *
|
2011-08-02 15:22:25 -07:00
|
|
|
ir_swizzle::variable_referenced() const
|
2010-05-14 17:35:42 -07:00
|
|
|
{
|
|
|
|
|
return this->val->variable_referenced();
|
|
|
|
|
}
|
2010-03-24 15:12:21 -07:00
|
|
|
|
2010-07-19 17:12:42 -07:00
|
|
|
|
glsl: Don't allocate a name for ir_var_temporary variables
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): 74 40,578,719,715 67,762,208 62,263,404 5,498,804 0
After (32-bit): 52 40,565,579,466 66,359,800 61,187,818 5,171,982 0
Before (64-bit): 74 37,129,541,061 95,195,160 87,369,671 7,825,489 0
After (64-bit): 76 37,134,691,404 93,271,352 85,900,223 7,371,129 0
A real savings of 1.0MiB on 32-bit and 1.4MiB on 64-bit.
Signed-off-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Matt Turner <mattst88@gmail.com>
2014-07-08 19:03:52 -07:00
|
|
|
bool ir_variable::temporaries_allocate_names = false;
|
|
|
|
|
|
2014-07-08 16:57:33 -07:00
|
|
|
const char ir_variable::tmp_name[] = "compiler_temp";
|
|
|
|
|
|
2010-07-19 17:12:42 -07:00
|
|
|
ir_variable::ir_variable(const struct glsl_type *type, const char *name,
|
|
|
|
|
ir_variable_mode mode)
|
glsl: Squish ir_variable::max_ifc_array_access and ::state_slots together
At least one of these pointers must be NULL, and we can determine which
will be NULL by looking at other fields. Use this information to store
both pointers in the same location.
If anyone can think of a better name for the union than "u", I'm all
ears.
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): 63 40,574,239,515 68,117,280 62,618,607 5,498,673 0
After (32-bit): 44 40,577,049,140 68,118,608 62,441,063 5,677,545 0
Before (64-bit): 53 37,126,451,468 95,150,256 87,711,304 7,438,952 0
After (64-bit): 63 37,122,829,194 95,153,008 87,333,600 7,819,408 0
A real savings of 173KiB on 32-bit and 368KiB on 64-bit.
Signed-off-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Matt Turner <mattst88@gmail.com>
Reviewed-by: Tapani Pälli <tapani.palli@intel.com>
2014-05-27 18:34:24 -07:00
|
|
|
: ir_instruction(ir_type_variable)
|
2010-02-22 13:19:34 -08:00
|
|
|
{
|
|
|
|
|
this->type = type;
|
2014-07-08 16:57:33 -07:00
|
|
|
|
glsl: Don't allocate a name for ir_var_temporary variables
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): 74 40,578,719,715 67,762,208 62,263,404 5,498,804 0
After (32-bit): 52 40,565,579,466 66,359,800 61,187,818 5,171,982 0
Before (64-bit): 74 37,129,541,061 95,195,160 87,369,671 7,825,489 0
After (64-bit): 76 37,134,691,404 93,271,352 85,900,223 7,371,129 0
A real savings of 1.0MiB on 32-bit and 1.4MiB on 64-bit.
Signed-off-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Matt Turner <mattst88@gmail.com>
2014-07-08 19:03:52 -07:00
|
|
|
if (mode == ir_var_temporary && !ir_variable::temporaries_allocate_names)
|
|
|
|
|
name = NULL;
|
|
|
|
|
|
2014-07-08 16:57:33 -07:00
|
|
|
/* The ir_variable clone method may call this constructor with name set to
|
|
|
|
|
* tmp_name.
|
|
|
|
|
*/
|
|
|
|
|
assert(name != NULL
|
|
|
|
|
|| mode == ir_var_temporary
|
|
|
|
|
|| mode == ir_var_function_in
|
|
|
|
|
|| mode == ir_var_function_out
|
|
|
|
|
|| mode == ir_var_function_inout);
|
|
|
|
|
assert(name != ir_variable::tmp_name
|
|
|
|
|
|| mode == ir_var_temporary);
|
|
|
|
|
if (mode == ir_var_temporary
|
|
|
|
|
&& (name == NULL || name == ir_variable::tmp_name)) {
|
|
|
|
|
this->name = ir_variable::tmp_name;
|
|
|
|
|
} else {
|
|
|
|
|
this->name = ralloc_strdup(this, name);
|
|
|
|
|
}
|
glsl: Squish ir_variable::max_ifc_array_access and ::state_slots together
At least one of these pointers must be NULL, and we can determine which
will be NULL by looking at other fields. Use this information to store
both pointers in the same location.
If anyone can think of a better name for the union than "u", I'm all
ears.
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): 63 40,574,239,515 68,117,280 62,618,607 5,498,673 0
After (32-bit): 44 40,577,049,140 68,118,608 62,441,063 5,677,545 0
Before (64-bit): 53 37,126,451,468 95,150,256 87,711,304 7,438,952 0
After (64-bit): 63 37,122,829,194 95,153,008 87,333,600 7,819,408 0
A real savings of 173KiB on 32-bit and 368KiB on 64-bit.
Signed-off-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Matt Turner <mattst88@gmail.com>
Reviewed-by: Tapani Pälli <tapani.palli@intel.com>
2014-05-27 18:34:24 -07:00
|
|
|
|
|
|
|
|
this->u.max_ifc_array_access = NULL;
|
|
|
|
|
|
glsl: move variables in to ir_variable::data, part II
This patch moves following bitfields and variables to the data
structure:
explicit_location, explicit_index, explicit_binding, has_initializer,
is_unmatched_generic_inout, location_frac, from_named_ifc_block_nonarray,
from_named_ifc_block_array, depth_layout, location, index, binding,
max_array_access, atomic
Signed-off-by: Tapani Pälli <tapani.palli@intel.com>
Reviewed-by: Paul Berry <stereotype441@gmail.com>
2013-12-12 15:08:59 +02:00
|
|
|
this->data.explicit_location = false;
|
|
|
|
|
this->data.has_initializer = false;
|
|
|
|
|
this->data.location = -1;
|
|
|
|
|
this->data.location_frac = 0;
|
glsl: Eliminate ir_variable::data.atomic.buffer_index
Just use ir_variable::data.binding... because that's the where the
binding is stored for everything else that can use layout(binding=).
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): 50 40,564,927,443 69,185,408 63,683,871 5,501,537 0
After (32-bit): 74 40,580,119,657 69,186,544 63,506,327 5,680,217 0
Before (64-bit): 59 36,822,048,449 96,526,888 89,113,000 7,413,888 0
After (64-bit): 89 36,822,971,897 96,526,616 88,735,296 7,791,320 0
A real savings of 173KiB on 32-bit and 368KiB on 64-bit.
Signed-off-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
2014-07-14 15:48:36 -07:00
|
|
|
this->data.binding = 0;
|
glsl: Replace ir_variable::warn_extension pointer with an 8-bit index
Also move the new warn_extension_index into ir_variable::data. This
enables slightly better packing.
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): 82 40,580,040,531 68,488,992 62,973,695 5,515,297 0
After (32-bit): 73 40,580,476,304 68,488,400 62,796,151 5,692,249 0
Before (64-bit): 65 37,124,013,542 95,892,768 88,466,712 7,426,056 0
After (64-bit): 71 37,124,890,613 95,889,584 88,089,008 7,800,576 0
A real savings of 173KiB on 32-bit and 368KiB on 64-bit.
Signed-off-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Matt Turner <mattst88@gmail.com>
Reviewed-by: Tapani Pälli <tapani.palli@intel.com>
2014-05-14 13:25:14 -07:00
|
|
|
this->data.warn_extension_index = 0;
|
2010-04-06 10:30:54 -07:00
|
|
|
this->constant_value = NULL;
|
2011-10-31 14:31:07 -07:00
|
|
|
this->constant_initializer = NULL;
|
2013-12-12 13:51:01 +02:00
|
|
|
this->data.origin_upper_left = false;
|
|
|
|
|
this->data.pixel_center_integer = false;
|
glsl: move variables in to ir_variable::data, part II
This patch moves following bitfields and variables to the data
structure:
explicit_location, explicit_index, explicit_binding, has_initializer,
is_unmatched_generic_inout, location_frac, from_named_ifc_block_nonarray,
from_named_ifc_block_array, depth_layout, location, index, binding,
max_array_access, atomic
Signed-off-by: Tapani Pälli <tapani.palli@intel.com>
Reviewed-by: Paul Berry <stereotype441@gmail.com>
2013-12-12 15:08:59 +02:00
|
|
|
this->data.depth_layout = ir_depth_layout_none;
|
2013-12-12 13:51:01 +02:00
|
|
|
this->data.used = false;
|
2013-12-12 12:57:57 +02:00
|
|
|
this->data.read_only = false;
|
|
|
|
|
this->data.centroid = false;
|
|
|
|
|
this->data.sample = false;
|
|
|
|
|
this->data.invariant = false;
|
2013-12-12 13:51:01 +02:00
|
|
|
this->data.how_declared = ir_var_declared_normally;
|
|
|
|
|
this->data.mode = mode;
|
|
|
|
|
this->data.interpolation = INTERP_QUALIFIER_NONE;
|
glsl: move variables in to ir_variable::data, part II
This patch moves following bitfields and variables to the data
structure:
explicit_location, explicit_index, explicit_binding, has_initializer,
is_unmatched_generic_inout, location_frac, from_named_ifc_block_nonarray,
from_named_ifc_block_array, depth_layout, location, index, binding,
max_array_access, atomic
Signed-off-by: Tapani Pälli <tapani.palli@intel.com>
Reviewed-by: Paul Berry <stereotype441@gmail.com>
2013-12-12 15:08:59 +02:00
|
|
|
this->data.max_array_access = 0;
|
|
|
|
|
this->data.atomic.offset = 0;
|
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 15:48:38 -07:00
|
|
|
this->data.image_read_only = false;
|
|
|
|
|
this->data.image_write_only = false;
|
|
|
|
|
this->data.image_coherent = false;
|
|
|
|
|
this->data.image_volatile = false;
|
|
|
|
|
this->data.image_restrict = false;
|
2010-03-26 16:37:53 -07:00
|
|
|
|
2013-10-02 16:19:59 -07:00
|
|
|
if (type != NULL) {
|
|
|
|
|
if (type->base_type == GLSL_TYPE_SAMPLER)
|
2013-12-12 12:57:57 +02:00
|
|
|
this->data.read_only = true;
|
2013-10-02 16:19:59 -07:00
|
|
|
|
|
|
|
|
if (type->is_interface())
|
|
|
|
|
this->init_interface_type(type);
|
|
|
|
|
else if (type->is_array() && type->fields.array->is_interface())
|
|
|
|
|
this->init_interface_type(type->fields.array);
|
|
|
|
|
}
|
2010-02-22 13:19:34 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-06-18 19:00:28 -07:00
|
|
|
const char *
|
2013-10-22 14:48:08 -07:00
|
|
|
interpolation_string(unsigned interpolation)
|
2010-06-18 19:00:28 -07:00
|
|
|
{
|
2013-10-22 14:48:08 -07:00
|
|
|
switch (interpolation) {
|
glsl: Distinguish between no interpolation qualifier and 'smooth'
Previously, we treated the 'smooth' qualifier as equivalent to no
qualifier at all. However, this is incorrect for the built-in color
variables (gl_FrontColor, gl_BackColor, gl_FrontSecondaryColor, and
gl_BackSecondaryColor). For those variables, if there is no qualifier
at all, interpolation should be flat if the shade model is GL_FLAT,
and smooth if the shade model is GL_SMOOTH.
To make this possible, I added a new value to the
glsl_interp_qualifier enum, INTERP_QUALIFIER_NONE.
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-10-21 07:40:37 -07:00
|
|
|
case INTERP_QUALIFIER_NONE: return "no";
|
2011-10-25 18:06:37 -07:00
|
|
|
case INTERP_QUALIFIER_SMOOTH: return "smooth";
|
|
|
|
|
case INTERP_QUALIFIER_FLAT: return "flat";
|
|
|
|
|
case INTERP_QUALIFIER_NOPERSPECTIVE: return "noperspective";
|
2010-06-18 19:00:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(!"Should not get here.");
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-10-21 07:55:48 -07:00
|
|
|
glsl_interp_qualifier
|
|
|
|
|
ir_variable::determine_interpolation_mode(bool flat_shade)
|
|
|
|
|
{
|
2013-12-12 13:51:01 +02:00
|
|
|
if (this->data.interpolation != INTERP_QUALIFIER_NONE)
|
|
|
|
|
return (glsl_interp_qualifier) this->data.interpolation;
|
glsl: move variables in to ir_variable::data, part II
This patch moves following bitfields and variables to the data
structure:
explicit_location, explicit_index, explicit_binding, has_initializer,
is_unmatched_generic_inout, location_frac, from_named_ifc_block_nonarray,
from_named_ifc_block_array, depth_layout, location, index, binding,
max_array_access, atomic
Signed-off-by: Tapani Pälli <tapani.palli@intel.com>
Reviewed-by: Paul Berry <stereotype441@gmail.com>
2013-12-12 15:08:59 +02:00
|
|
|
int location = this->data.location;
|
2011-10-21 07:55:48 -07:00
|
|
|
bool is_gl_Color =
|
2013-02-23 09:00:58 -08:00
|
|
|
location == VARYING_SLOT_COL0 || location == VARYING_SLOT_COL1;
|
2011-10-21 07:55:48 -07:00
|
|
|
if (flat_shade && is_gl_Color)
|
|
|
|
|
return INTERP_QUALIFIER_FLAT;
|
|
|
|
|
else
|
|
|
|
|
return INTERP_QUALIFIER_SMOOTH;
|
|
|
|
|
}
|
|
|
|
|
|
glsl: Replace ir_variable::warn_extension pointer with an 8-bit index
Also move the new warn_extension_index into ir_variable::data. This
enables slightly better packing.
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): 82 40,580,040,531 68,488,992 62,973,695 5,515,297 0
After (32-bit): 73 40,580,476,304 68,488,400 62,796,151 5,692,249 0
Before (64-bit): 65 37,124,013,542 95,892,768 88,466,712 7,426,056 0
After (64-bit): 71 37,124,890,613 95,889,584 88,089,008 7,800,576 0
A real savings of 173KiB on 32-bit and 368KiB on 64-bit.
Signed-off-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Matt Turner <mattst88@gmail.com>
Reviewed-by: Tapani Pälli <tapani.palli@intel.com>
2014-05-14 13:25:14 -07:00
|
|
|
const char *const ir_variable::warn_extension_table[] = {
|
|
|
|
|
"",
|
|
|
|
|
"GL_ARB_shader_stencil_export",
|
|
|
|
|
"GL_AMD_shader_stencil_export",
|
|
|
|
|
};
|
|
|
|
|
|
2014-05-13 11:59:01 -07:00
|
|
|
void
|
|
|
|
|
ir_variable::enable_extension_warning(const char *extension)
|
|
|
|
|
{
|
2015-02-28 09:11:23 -07:00
|
|
|
for (unsigned i = 0; i < ARRAY_SIZE(warn_extension_table); i++) {
|
glsl: Replace ir_variable::warn_extension pointer with an 8-bit index
Also move the new warn_extension_index into ir_variable::data. This
enables slightly better packing.
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): 82 40,580,040,531 68,488,992 62,973,695 5,515,297 0
After (32-bit): 73 40,580,476,304 68,488,400 62,796,151 5,692,249 0
Before (64-bit): 65 37,124,013,542 95,892,768 88,466,712 7,426,056 0
After (64-bit): 71 37,124,890,613 95,889,584 88,089,008 7,800,576 0
A real savings of 173KiB on 32-bit and 368KiB on 64-bit.
Signed-off-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Matt Turner <mattst88@gmail.com>
Reviewed-by: Tapani Pälli <tapani.palli@intel.com>
2014-05-14 13:25:14 -07:00
|
|
|
if (strcmp(warn_extension_table[i], extension) == 0) {
|
|
|
|
|
this->data.warn_extension_index = i;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(!"Should not get here.");
|
|
|
|
|
this->data.warn_extension_index = 0;
|
2014-05-13 11:59:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
|
|
|
|
ir_variable::get_extension_warning() const
|
|
|
|
|
{
|
glsl: Replace ir_variable::warn_extension pointer with an 8-bit index
Also move the new warn_extension_index into ir_variable::data. This
enables slightly better packing.
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): 82 40,580,040,531 68,488,992 62,973,695 5,515,297 0
After (32-bit): 73 40,580,476,304 68,488,400 62,796,151 5,692,249 0
Before (64-bit): 65 37,124,013,542 95,892,768 88,466,712 7,426,056 0
After (64-bit): 71 37,124,890,613 95,889,584 88,089,008 7,800,576 0
A real savings of 173KiB on 32-bit and 368KiB on 64-bit.
Signed-off-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Matt Turner <mattst88@gmail.com>
Reviewed-by: Tapani Pälli <tapani.palli@intel.com>
2014-05-14 13:25:14 -07:00
|
|
|
return this->data.warn_extension_index == 0
|
|
|
|
|
? NULL : warn_extension_table[this->data.warn_extension_index];
|
2014-05-13 11:59:01 -07:00
|
|
|
}
|
2011-10-21 07:55:48 -07:00
|
|
|
|
glsl: Store a predicate for whether a built-in signature is available.
For the upcoming built-in function rewrite, we'll need to be able to
answer "Is this built-in function signature available?".
This is actually a somewhat complex question, since it depends on the
language version, GLSL vs. GLSL ES, enabled extensions, and the current
shader stage.
Storing such a set of constraints in a structure would be painful, so
instead we store a function pointer. When creating a signature, we
simply point to a predicate that inspects _mesa_glsl_parse_state and
answers whether the signature is available in the current shader.
Unfortunately, IR reader doesn't actually know when built-in functions
are available, so this patch makes it lie and say that they're always
present. This allows us to hook up the new functionality; it just won't
be useful until real data is populated. In the meantime, the existing
profile mechanism ensures built-ins are available in the right places.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Matt Turner <mattst88@gmail.com>
Reviewed-by: Paul Berry <stereotype441@gmail.com>
2013-08-30 16:00:43 -07:00
|
|
|
ir_function_signature::ir_function_signature(const glsl_type *return_type,
|
|
|
|
|
builtin_available_predicate b)
|
2014-05-27 19:49:04 -07:00
|
|
|
: ir_instruction(ir_type_function_signature),
|
|
|
|
|
return_type(return_type), is_defined(false), is_intrinsic(false),
|
2013-09-25 11:55:06 -07:00
|
|
|
builtin_avail(b), _function(NULL)
|
2010-02-22 13:19:34 -08:00
|
|
|
{
|
2012-05-02 23:11:41 +02:00
|
|
|
this->origin = NULL;
|
2010-02-22 13:19:34 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-08-30 16:12:55 -07:00
|
|
|
bool
|
|
|
|
|
ir_function_signature::is_builtin() const
|
|
|
|
|
{
|
2013-09-09 14:53:22 -07:00
|
|
|
return builtin_avail != NULL;
|
2013-08-30 16:12:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-08-30 00:06:30 -07:00
|
|
|
bool
|
|
|
|
|
ir_function_signature::is_builtin_available(const _mesa_glsl_parse_state *state) const
|
|
|
|
|
{
|
|
|
|
|
/* We can't call the predicate without a state pointer, so just say that
|
|
|
|
|
* the signature is available. At compile time, we need the filtering,
|
|
|
|
|
* but also receive a valid state pointer. At link time, we're resolving
|
|
|
|
|
* imported built-in prototypes to their definitions, which will always
|
|
|
|
|
* be an exact match. So we can skip the filtering.
|
|
|
|
|
*/
|
|
|
|
|
if (state == NULL)
|
|
|
|
|
return true;
|
|
|
|
|
|
2013-09-09 14:53:22 -07:00
|
|
|
assert(builtin_avail != NULL);
|
|
|
|
|
return builtin_avail(state);
|
2013-08-30 00:06:30 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-01-12 15:37:37 -08:00
|
|
|
static bool
|
|
|
|
|
modes_match(unsigned a, unsigned b)
|
|
|
|
|
{
|
|
|
|
|
if (a == b)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
/* Accept "in" vs. "const in" */
|
2013-01-11 14:39:32 -08:00
|
|
|
if ((a == ir_var_const_in && b == ir_var_function_in) ||
|
|
|
|
|
(b == ir_var_const_in && a == ir_var_function_in))
|
2011-01-12 15:37:37 -08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-04-28 11:49:12 -07:00
|
|
|
const char *
|
|
|
|
|
ir_function_signature::qualifiers_match(exec_list *params)
|
|
|
|
|
{
|
|
|
|
|
/* check that the qualifiers match. */
|
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-10 16:39:17 -08:00
|
|
|
foreach_two_lists(a_node, &this->parameters, b_node, params) {
|
|
|
|
|
ir_variable *a = (ir_variable *) a_node;
|
|
|
|
|
ir_variable *b = (ir_variable *) b_node;
|
2010-04-28 11:49:12 -07:00
|
|
|
|
2013-12-12 12:57:57 +02:00
|
|
|
if (a->data.read_only != b->data.read_only ||
|
2013-12-12 13:51:01 +02:00
|
|
|
!modes_match(a->data.mode, b->data.mode) ||
|
|
|
|
|
a->data.interpolation != b->data.interpolation ||
|
2013-12-12 12:57:57 +02:00
|
|
|
a->data.centroid != b->data.centroid ||
|
2013-12-08 04:56:06 +01:00
|
|
|
a->data.sample != b->data.sample ||
|
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 15:48:38 -07:00
|
|
|
a->data.image_read_only != b->data.image_read_only ||
|
|
|
|
|
a->data.image_write_only != b->data.image_write_only ||
|
|
|
|
|
a->data.image_coherent != b->data.image_coherent ||
|
|
|
|
|
a->data.image_volatile != b->data.image_volatile ||
|
|
|
|
|
a->data.image_restrict != b->data.image_restrict) {
|
2010-04-28 11:49:12 -07:00
|
|
|
|
|
|
|
|
/* parameter a's qualifiers don't match */
|
|
|
|
|
return a->name;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-04-28 12:44:24 -07:00
|
|
|
void
|
|
|
|
|
ir_function_signature::replace_parameters(exec_list *new_params)
|
|
|
|
|
{
|
|
|
|
|
/* Destroy all of the previous parameter information. If the previous
|
|
|
|
|
* parameter information comes from the function prototype, it may either
|
|
|
|
|
* specify incorrect parameter names or not have names at all.
|
|
|
|
|
*/
|
|
|
|
|
new_params->move_nodes_to(¶meters);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-03-23 17:42:04 -07:00
|
|
|
ir_function::ir_function(const char *name)
|
2014-05-27 19:49:04 -07:00
|
|
|
: ir_instruction(ir_type_function)
|
2010-02-22 13:19:34 -08:00
|
|
|
{
|
2011-01-21 14:32:31 -08:00
|
|
|
this->name = ralloc_strdup(this, name);
|
2010-09-05 01:48:11 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
2010-09-16 02:52:25 -07:00
|
|
|
ir_function::has_user_signature()
|
2010-09-05 01:48:11 -07:00
|
|
|
{
|
2014-06-24 21:34:05 -07:00
|
|
|
foreach_in_list(ir_function_signature, sig, &this->signatures) {
|
2013-08-30 16:12:55 -07:00
|
|
|
if (!sig->is_builtin())
|
2010-09-05 01:48:11 -07:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
2010-02-22 13:19:34 -08:00
|
|
|
}
|
2010-03-11 14:34:27 -08:00
|
|
|
|
|
|
|
|
|
2011-09-22 15:04:56 -07:00
|
|
|
ir_rvalue *
|
|
|
|
|
ir_rvalue::error_value(void *mem_ctx)
|
2010-03-11 14:34:27 -08:00
|
|
|
{
|
2014-05-27 19:49:04 -07:00
|
|
|
ir_rvalue *v = new(mem_ctx) ir_rvalue(ir_type_unset);
|
2010-03-11 14:34:27 -08:00
|
|
|
|
2011-09-22 15:04:56 -07:00
|
|
|
v->type = glsl_type::error_type;
|
|
|
|
|
return v;
|
2010-03-11 14:34:27 -08:00
|
|
|
}
|
2010-04-06 11:52:09 -07:00
|
|
|
|
2010-07-07 11:33:13 -07:00
|
|
|
|
2010-04-06 11:52:09 -07:00
|
|
|
void
|
|
|
|
|
visit_exec_list(exec_list *list, ir_visitor *visitor)
|
|
|
|
|
{
|
2014-06-24 21:58:35 -07:00
|
|
|
foreach_in_list_safe(ir_instruction, node, list) {
|
|
|
|
|
node->accept(visitor);
|
2010-04-06 11:52:09 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-20 11:27:38 -07:00
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
steal_memory(ir_instruction *ir, void *new_ctx)
|
|
|
|
|
{
|
2010-07-23 12:49:17 -07:00
|
|
|
ir_variable *var = ir->as_variable();
|
2010-07-26 19:26:53 -07:00
|
|
|
ir_constant *constant = ir->as_constant();
|
2010-07-23 12:49:17 -07:00
|
|
|
if (var != NULL && var->constant_value != NULL)
|
2010-07-27 15:25:07 -07:00
|
|
|
steal_memory(var->constant_value, ir);
|
2010-07-26 19:26:53 -07:00
|
|
|
|
2011-10-31 14:31:07 -07:00
|
|
|
if (var != NULL && var->constant_initializer != NULL)
|
|
|
|
|
steal_memory(var->constant_initializer, ir);
|
|
|
|
|
|
2010-07-26 19:26:53 -07:00
|
|
|
/* The components of aggregate constants are not visited by the normal
|
|
|
|
|
* visitor, so steal their values by hand.
|
|
|
|
|
*/
|
|
|
|
|
if (constant != NULL) {
|
|
|
|
|
if (constant->type->is_record()) {
|
2014-06-24 21:34:05 -07:00
|
|
|
foreach_in_list(ir_constant, field, &constant->components) {
|
2010-07-26 19:26:53 -07:00
|
|
|
steal_memory(field, ir);
|
|
|
|
|
}
|
|
|
|
|
} else if (constant->type->is_array()) {
|
|
|
|
|
for (unsigned int i = 0; i < constant->type->length; i++) {
|
|
|
|
|
steal_memory(constant->array_elements[i], ir);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-21 14:32:31 -08:00
|
|
|
ralloc_steal(new_ctx, ir);
|
2010-07-20 11:27:38 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
reparent_ir(exec_list *list, void *mem_ctx)
|
|
|
|
|
{
|
2014-06-24 21:34:05 -07:00
|
|
|
foreach_in_list(ir_instruction, node, list) {
|
|
|
|
|
visit_tree(node, steal_memory, mem_ctx);
|
2010-07-20 11:27:38 -07:00
|
|
|
}
|
|
|
|
|
}
|
2010-11-19 18:27:41 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
static ir_rvalue *
|
|
|
|
|
try_min_one(ir_rvalue *ir)
|
|
|
|
|
{
|
|
|
|
|
ir_expression *expr = ir->as_expression();
|
|
|
|
|
|
|
|
|
|
if (!expr || expr->operation != ir_binop_min)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
if (expr->operands[0]->is_one())
|
|
|
|
|
return expr->operands[1];
|
|
|
|
|
|
|
|
|
|
if (expr->operands[1]->is_one())
|
|
|
|
|
return expr->operands[0];
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static ir_rvalue *
|
|
|
|
|
try_max_zero(ir_rvalue *ir)
|
|
|
|
|
{
|
|
|
|
|
ir_expression *expr = ir->as_expression();
|
|
|
|
|
|
|
|
|
|
if (!expr || expr->operation != ir_binop_max)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
if (expr->operands[0]->is_zero())
|
|
|
|
|
return expr->operands[1];
|
|
|
|
|
|
|
|
|
|
if (expr->operands[1]->is_zero())
|
|
|
|
|
return expr->operands[0];
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ir_rvalue *
|
|
|
|
|
ir_rvalue::as_rvalue_to_saturate()
|
|
|
|
|
{
|
|
|
|
|
ir_expression *expr = this->as_expression();
|
|
|
|
|
|
|
|
|
|
if (!expr)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
ir_rvalue *max_zero = try_max_zero(expr);
|
|
|
|
|
if (max_zero) {
|
|
|
|
|
return try_min_one(max_zero);
|
|
|
|
|
} else {
|
|
|
|
|
ir_rvalue *min_one = try_min_one(expr);
|
|
|
|
|
if (min_one) {
|
|
|
|
|
return try_max_zero(min_one);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2013-02-15 09:46:50 -06:00
|
|
|
|
|
|
|
|
|
|
|
|
|
unsigned
|
|
|
|
|
vertices_per_prim(GLenum prim)
|
|
|
|
|
{
|
|
|
|
|
switch (prim) {
|
|
|
|
|
case GL_POINTS:
|
|
|
|
|
return 1;
|
|
|
|
|
case GL_LINES:
|
|
|
|
|
return 2;
|
|
|
|
|
case GL_TRIANGLES:
|
|
|
|
|
return 3;
|
|
|
|
|
case GL_LINES_ADJACENCY:
|
|
|
|
|
return 4;
|
|
|
|
|
case GL_TRIANGLES_ADJACENCY:
|
|
|
|
|
return 6;
|
|
|
|
|
default:
|
|
|
|
|
assert(!"Bad primitive");
|
|
|
|
|
return 3;
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-09-25 11:44:41 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Generate a string describing the mode of a variable
|
|
|
|
|
*/
|
|
|
|
|
const char *
|
|
|
|
|
mode_string(const ir_variable *var)
|
|
|
|
|
{
|
2013-12-12 13:51:01 +02:00
|
|
|
switch (var->data.mode) {
|
2013-09-25 11:44:41 -07:00
|
|
|
case ir_var_auto:
|
2013-12-12 12:57:57 +02:00
|
|
|
return (var->data.read_only) ? "global constant" : "global variable";
|
2013-09-25 11:44:41 -07:00
|
|
|
|
|
|
|
|
case ir_var_uniform:
|
|
|
|
|
return "uniform";
|
|
|
|
|
|
|
|
|
|
case ir_var_shader_in:
|
|
|
|
|
return "shader input";
|
|
|
|
|
|
|
|
|
|
case ir_var_shader_out:
|
|
|
|
|
return "shader output";
|
|
|
|
|
|
|
|
|
|
case ir_var_function_in:
|
|
|
|
|
case ir_var_const_in:
|
|
|
|
|
return "function input";
|
|
|
|
|
|
|
|
|
|
case ir_var_function_out:
|
|
|
|
|
return "function output";
|
|
|
|
|
|
|
|
|
|
case ir_var_function_inout:
|
|
|
|
|
return "function inout";
|
|
|
|
|
|
|
|
|
|
case ir_var_system_value:
|
|
|
|
|
return "shader input";
|
|
|
|
|
|
|
|
|
|
case ir_var_temporary:
|
|
|
|
|
return "compiler temporary";
|
|
|
|
|
|
|
|
|
|
case ir_var_mode_count:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(!"Should not get here.");
|
|
|
|
|
return "invalid variable";
|
|
|
|
|
}
|