summaryrefslogtreecommitdiff
path: root/src/glsl/ir.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/glsl/ir.cpp')
-rw-r--r--src/glsl/ir.cpp402
1 files changed, 328 insertions, 74 deletions
diff --git a/src/glsl/ir.cpp b/src/glsl/ir.cpp
index 87e78eee05..b8b0fed9d1 100644
--- a/src/glsl/ir.cpp
+++ b/src/glsl/ir.cpp
@@ -31,6 +31,21 @@ ir_rvalue::ir_rvalue()
this->type = glsl_type::error_type;
}
+bool ir_rvalue::is_zero() const
+{
+ return false;
+}
+
+bool ir_rvalue::is_one() const
+{
+ return false;
+}
+
+bool ir_rvalue::is_negative_one() const
+{
+ return false;
+}
+
/**
* Modify the swizzle make to move one component to another
*
@@ -177,91 +192,163 @@ ir_assignment::ir_assignment(ir_rvalue *lhs, ir_rvalue *rhs,
ir_expression::ir_expression(int op, const struct glsl_type *type,
+ ir_rvalue *op0)
+{
+ assert(get_num_operands(ir_expression_operation(op)) == 1);
+ this->ir_type = ir_type_expression;
+ this->type = type;
+ this->operation = ir_expression_operation(op);
+ this->operands[0] = op0;
+ this->operands[1] = NULL;
+ this->operands[2] = NULL;
+ this->operands[3] = NULL;
+}
+
+ir_expression::ir_expression(int op, const struct glsl_type *type,
ir_rvalue *op0, ir_rvalue *op1)
{
+ assert(((op1 == NULL) && (get_num_operands(ir_expression_operation(op)) == 1))
+ || (get_num_operands(ir_expression_operation(op)) == 2));
+ this->ir_type = ir_type_expression;
+ this->type = type;
+ this->operation = ir_expression_operation(op);
+ this->operands[0] = op0;
+ this->operands[1] = op1;
+ this->operands[2] = NULL;
+ this->operands[3] = NULL;
+}
+
+ir_expression::ir_expression(int op, const struct glsl_type *type,
+ ir_rvalue *op0, ir_rvalue *op1,
+ ir_rvalue *op2, ir_rvalue *op3)
+{
this->ir_type = ir_type_expression;
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;
+}
+
+ir_expression::ir_expression(int op, ir_rvalue *op0)
+{
+ this->ir_type = ir_type_expression;
+
+ 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:
+ case ir_unop_cos:
+ case ir_unop_dFdx:
+ case ir_unop_dFdy:
+ this->type = op0->type;
+ break;
+
+ case ir_unop_any:
+ this->type = glsl_type::bool_type;
+ break;
+
+ 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)
+{
+ this->ir_type = ir_type_expression;
+
+ 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:
+ if (op0->type->is_scalar()) {
+ this->type = op1->type;
+ } else if (op1->type->is_scalar()) {
+ this->type = op0->type;
+ } else {
+ /* FINISHME: matrix types */
+ assert(!op0->type->is_matrix() && !op1->type->is_matrix());
+ assert(op0->type == op1->type);
+ this->type = op0->type;
+ }
+ break;
+
+ case ir_binop_logic_and:
+ case ir_binop_logic_or:
+ if (op0->type->is_scalar()) {
+ this->type = op1->type;
+ } else if (op1->type->is_scalar()) {
+ this->type = op0->type;
+ }
+ break;
+
+ case ir_binop_dot:
+ this->type = glsl_type::float_type;
+ break;
+
+ default:
+ assert(!"not reached: missing automatic type setup for ir_expression");
+ this->type = glsl_type::float_type;
+ }
}
unsigned int
ir_expression::get_num_operands(ir_expression_operation op)
{
-/* Update ir_print_visitor.cpp when updating this list. */
- const int num_operands[] = {
- 1, /* ir_unop_bit_not */
- 1, /* ir_unop_logic_not */
- 1, /* ir_unop_neg */
- 1, /* ir_unop_abs */
- 1, /* ir_unop_sign */
- 1, /* ir_unop_rcp */
- 1, /* ir_unop_rsq */
- 1, /* ir_unop_sqrt */
- 1, /* ir_unop_exp */
- 1, /* ir_unop_log */
- 1, /* ir_unop_exp2 */
- 1, /* ir_unop_log2 */
- 1, /* ir_unop_f2i */
- 1, /* ir_unop_i2f */
- 1, /* ir_unop_f2b */
- 1, /* ir_unop_b2f */
- 1, /* ir_unop_i2b */
- 1, /* ir_unop_b2i */
- 1, /* ir_unop_u2f */
- 1, /* ir_unop_any */
-
- 1, /* ir_unop_trunc */
- 1, /* ir_unop_ceil */
- 1, /* ir_unop_floor */
- 1, /* ir_unop_fract */
- 1, /* ir_unop_round_even */
-
- 1, /* ir_unop_sin */
- 1, /* ir_unop_cos */
-
- 1, /* ir_unop_dFdx */
- 1, /* ir_unop_dFdy */
-
- 1, /* ir_unop_noise */
-
- 2, /* ir_binop_add */
- 2, /* ir_binop_sub */
- 2, /* ir_binop_mul */
- 2, /* ir_binop_div */
- 2, /* ir_binop_mod */
-
- 2, /* ir_binop_less */
- 2, /* ir_binop_greater */
- 2, /* ir_binop_lequal */
- 2, /* ir_binop_gequal */
- 2, /* ir_binop_equal */
- 2, /* ir_binop_nequal */
- 2, /* ir_binop_all_equal */
- 2, /* ir_binop_any_nequal */
-
- 2, /* ir_binop_lshift */
- 2, /* ir_binop_rshift */
- 2, /* ir_binop_bit_and */
- 2, /* ir_binop_bit_xor */
- 2, /* ir_binop_bit_or */
-
- 2, /* ir_binop_logic_and */
- 2, /* ir_binop_logic_xor */
- 2, /* ir_binop_logic_or */
-
- 2, /* ir_binop_dot */
- 2, /* ir_binop_cross */
- 2, /* ir_binop_min */
- 2, /* ir_binop_max */
-
- 2, /* ir_binop_pow */
- };
+ assert(op <= ir_last_opcode);
+
+ if (op <= ir_last_unop)
+ return 1;
- assert(sizeof(num_operands) / sizeof(num_operands[0]) == ir_binop_pow + 1);
+ if (op <= ir_last_binop)
+ return 2;
- return num_operands[op];
+ if (op == ir_quadop_vector)
+ return 4;
+
+ assert(false);
+ return 0;
}
static const char *const operator_strs[] = {
@@ -292,6 +379,8 @@ static const char *const operator_strs[] = {
"round_even",
"sin",
"cos",
+ "sin_reduced",
+ "cos_reduced",
"dFdx",
"dFdy",
"noise",
@@ -317,16 +406,16 @@ static const char *const operator_strs[] = {
"^^",
"||",
"dot",
- "cross",
"min",
"max",
"pow",
+ "vector",
};
const char *ir_expression::operator_string(ir_expression_operation op)
{
assert((unsigned int) op < Elements(operator_strs));
- assert(Elements(operator_strs) == (ir_binop_pow + 1));
+ assert(Elements(operator_strs) == (ir_quadop_vector + 1));
return operator_strs[op];
}
@@ -689,7 +778,7 @@ ir_constant::has_value(const ir_constant *c) const
if (this->type->is_array()) {
for (unsigned i = 0; i < this->type->length; i++) {
- if (this->array_elements[i]->has_value(c->array_elements[i]))
+ if (!this->array_elements[i]->has_value(c->array_elements[i]))
return false;
}
return true;
@@ -742,6 +831,115 @@ ir_constant::has_value(const ir_constant *c) const
return true;
}
+bool
+ir_constant::is_zero() const
+{
+ if (!this->type->is_scalar() && !this->type->is_vector())
+ return false;
+
+ for (unsigned c = 0; c < this->type->vector_elements; c++) {
+ switch (this->type->base_type) {
+ case GLSL_TYPE_FLOAT:
+ if (this->value.f[c] != 0.0)
+ return false;
+ break;
+ case GLSL_TYPE_INT:
+ if (this->value.i[c] != 0)
+ return false;
+ break;
+ case GLSL_TYPE_UINT:
+ if (this->value.u[c] != 0)
+ return false;
+ break;
+ case GLSL_TYPE_BOOL:
+ if (this->value.b[c] != false)
+ return false;
+ break;
+ 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
+ir_constant::is_one() const
+{
+ if (!this->type->is_scalar() && !this->type->is_vector())
+ return false;
+
+ for (unsigned c = 0; c < this->type->vector_elements; c++) {
+ switch (this->type->base_type) {
+ case GLSL_TYPE_FLOAT:
+ if (this->value.f[c] != 1.0)
+ return false;
+ break;
+ case GLSL_TYPE_INT:
+ if (this->value.i[c] != 1)
+ return false;
+ break;
+ case GLSL_TYPE_UINT:
+ if (this->value.u[c] != 1)
+ return false;
+ break;
+ case GLSL_TYPE_BOOL:
+ if (this->value.b[c] != true)
+ return false;
+ break;
+ 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
+ir_constant::is_negative_one() const
+{
+ if (!this->type->is_scalar() && !this->type->is_vector())
+ return false;
+
+ if (this->type->is_boolean())
+ return false;
+
+ for (unsigned c = 0; c < this->type->vector_elements; c++) {
+ switch (this->type->base_type) {
+ case GLSL_TYPE_FLOAT:
+ if (this->value.f[c] != -1.0)
+ return false;
+ break;
+ case GLSL_TYPE_INT:
+ if (this->value.i[c] != -1)
+ return false;
+ break;
+ case GLSL_TYPE_UINT:
+ if (int(this->value.u[c]) != -1)
+ return false;
+ break;
+ default:
+ /* The only other base types are structures, arrays, samplers, and
+ * booleans. Samplers cannot be constants, and the others should
+ * have been filtered out above.
+ */
+ assert(!"Should not get here.");
+ return false;
+ }
+ }
+
+ return true;
+}
ir_loop::ir_loop()
{
@@ -1239,3 +1437,59 @@ reparent_ir(exec_list *list, void *mem_ctx)
visit_tree((ir_instruction *) node, steal_memory, mem_ctx);
}
}
+
+
+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;
+}