X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fglsl%2Fir.cpp;h=d6594cd9a3e65063b4a72754aa8781d2100d3c7c;hb=440dfb45834e18ebd9acfc37aa31797d8803e51b;hp=86dc49015433fe8a8aa0f412e4aad433daab20da;hpb=4dfb89904c0a3d2166e9a3fc0253a254680e91bc;p=mesa.git diff --git a/src/glsl/ir.cpp b/src/glsl/ir.cpp index 86dc4901543..d6594cd9a3e 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 * @@ -55,6 +70,9 @@ update_rhs_swizzle(ir_swizzle_mask &m, unsigned from, unsigned to) void ir_assignment::set_lhs(ir_rvalue *lhs) { + void *mem_ctx = this; + bool swizzled = false; + while (lhs != NULL) { ir_swizzle *swiz = lhs->as_swizzle(); @@ -82,7 +100,21 @@ ir_assignment::set_lhs(ir_rvalue *lhs) this->write_mask = write_mask; lhs = swiz->val; - this->rhs = new(this) ir_swizzle(this->rhs, rhs_swiz); + 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); } assert((lhs == NULL) || lhs->as_dereference()); @@ -122,6 +154,16 @@ ir_assignment::ir_assignment(ir_dereference *lhs, ir_rvalue *rhs, this->rhs = rhs; this->lhs = lhs; this->write_mask = write_mask; + + 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); + } } ir_assignment::ir_assignment(ir_rvalue *lhs, ir_rvalue *rhs, @@ -149,91 +191,218 @@ 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_sin: + case ir_unop_cos: + case ir_unop_sin_reduced: + case ir_unop_cos_reduced: + case ir_unop_dFdx: + case ir_unop_dFdy: + this->type = op0->type; + break; + + case ir_unop_f2i: + case ir_unop_b2i: + case ir_unop_u2i: + 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: + this->type = glsl_type::get_instance(GLSL_TYPE_FLOAT, + op0->type->vector_elements, 1); + break; + + case ir_unop_f2b: + case ir_unop_i2b: + this->type = glsl_type::get_instance(GLSL_TYPE_BOOL, + op0->type->vector_elements, 1); + break; + + case ir_unop_i2u: + this->type = glsl_type::get_instance(GLSL_TYPE_UINT, + op0->type->vector_elements, 1); + break; + + case ir_unop_noise: + this->type = glsl_type::float_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: + case ir_binop_div: + case ir_binop_mod: + 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_xor: + case ir_binop_logic_or: + case ir_binop_bit_and: + case ir_binop_bit_xor: + case ir_binop_bit_or: + if (op0->type->is_scalar()) { + this->type = op1->type; + } else if (op1->type->is_scalar()) { + this->type = op0->type; + } + break; + + 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; + + case ir_binop_dot: + this->type = glsl_type::float_type; + break; + + case ir_binop_lshift: + case ir_binop_rshift: + this->type = op0->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_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); - assert(sizeof(num_operands) / sizeof(num_operands[0]) == ir_binop_pow + 1); + if (op <= ir_last_unop) + return 1; - return num_operands[op]; + if (op <= ir_last_binop) + return 2; + + if (op == ir_quadop_vector) + return 4; + + assert(false); + return 0; } static const char *const operator_strs[] = { @@ -256,13 +425,18 @@ static const char *const operator_strs[] = { "i2b", "b2i", "u2f", + "i2u", + "u2i", "any", "trunc", "ceil", "floor", "fract", + "round_even", "sin", "cos", + "sin_reduced", + "cos_reduced", "dFdx", "dFdy", "noise", @@ -288,16 +462,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]; } @@ -306,6 +480,22 @@ const char *ir_expression::operator_string() return operator_string(this->operation); } +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 ""; + } +} + ir_expression_operation ir_expression::get_operator(const char *str) { @@ -396,7 +586,7 @@ ir_constant::ir_constant(const struct glsl_type *type, exec_list *value_list) || type->is_record() || type->is_array()); if (type->is_array()) { - this->array_elements = talloc_array(this, ir_constant *, type->length); + this->array_elements = ralloc_array(this, ir_constant *, type->length); unsigned i = 0; foreach_list(node, value_list) { ir_constant *value = (ir_constant *) node; @@ -660,7 +850,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; @@ -713,6 +903,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() { @@ -745,7 +1044,7 @@ ir_dereference_array::ir_dereference_array(ir_rvalue *value, ir_dereference_array::ir_dereference_array(ir_variable *var, ir_rvalue *array_index) { - void *ctx = talloc_parent(var); + void *ctx = ralloc_parent(var); this->ir_type = ir_type_dereference_array; this->array_index = array_index; @@ -778,7 +1077,7 @@ ir_dereference_record::ir_dereference_record(ir_rvalue *value, { this->ir_type = ir_type_dereference_record; this->record = value; - this->field = talloc_strdup(this, field); + this->field = ralloc_strdup(this, field); this->type = (this->record != NULL) ? this->record->type->field_type(field) : glsl_type::error_type; } @@ -787,32 +1086,17 @@ ir_dereference_record::ir_dereference_record(ir_rvalue *value, ir_dereference_record::ir_dereference_record(ir_variable *var, const char *field) { - void *ctx = talloc_parent(var); + void *ctx = ralloc_parent(var); this->ir_type = ir_type_dereference_record; this->record = new(ctx) ir_dereference_variable(var); - this->field = talloc_strdup(this, field); + this->field = ralloc_strdup(this, field); this->type = (this->record != NULL) ? this->record->type->field_type(field) : glsl_type::error_type; } -bool type_contains_sampler(const glsl_type *type) -{ - if (type->is_array()) { - return type_contains_sampler(type->fields.array); - } else if (type->is_record()) { - for (unsigned int i = 0; i < type->length; i++) { - if (type_contains_sampler(type->fields.structure[i].type)) - return true; - } - return false; - } else { - return type->is_sampler(); - } -} - bool -ir_dereference::is_lvalue() +ir_dereference::is_lvalue() const { ir_variable *var = this->variable_referenced(); @@ -821,23 +1105,20 @@ ir_dereference::is_lvalue() if ((var == NULL) || var->read_only) return false; - if (this->type->is_array() && !var->array_lvalue) - return false; - /* From page 17 (page 23 of the PDF) of the GLSL 1.20 spec: * * "Samplers cannot be treated as l-values; hence cannot be used * as out or inout function parameters, nor can they be * assigned into." */ - if (type_contains_sampler(this->type)) + if (this->type->contains_sampler()) return false; return true; } -const char *tex_opcode_strs[] = { "tex", "txb", "txl", "txd", "txf" }; +const char *tex_opcode_strs[] = { "tex", "txb", "txl", "txd", "txf", "txs" }; const char *ir_texture::opcode_string() { @@ -859,21 +1140,21 @@ ir_texture::get_opcode(const char *str) void -ir_texture::set_sampler(ir_dereference *sampler) +ir_texture::set_sampler(ir_dereference *sampler, const glsl_type *type) { assert(sampler != NULL); + assert(type != NULL); this->sampler = sampler; + this->type = type; - switch (sampler->type->sampler_type) { - case GLSL_TYPE_FLOAT: - this->type = glsl_type::vec4_type; - break; - case GLSL_TYPE_INT: - this->type = glsl_type::ivec4_type; - break; - case GLSL_TYPE_UINT: - this->type = glsl_type::uvec4_type; - break; + if (this->op == ir_txs) { + assert(type->base_type == GLSL_TYPE_INT); + } 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); } } @@ -954,7 +1235,7 @@ ir_swizzle::ir_swizzle(ir_rvalue *val, ir_swizzle_mask mask) ir_swizzle * ir_swizzle::create(ir_rvalue *val, const char *str, unsigned vector_length) { - void *ctx = talloc_parent(val); + void *ctx = ralloc_parent(val); /* For each possible swizzle character, this table encodes the value in * \c idx_map that represents the 0th element of the vector. For invalid @@ -1030,7 +1311,7 @@ ir_swizzle::create(ir_rvalue *val, const char *str, unsigned vector_length) #undef I ir_variable * -ir_swizzle::variable_referenced() +ir_swizzle::variable_referenced() const { return this->val->variable_referenced(); } @@ -1039,16 +1320,19 @@ ir_swizzle::variable_referenced() ir_variable::ir_variable(const struct glsl_type *type, const char *name, ir_variable_mode mode) : max_array_access(0), read_only(false), centroid(false), invariant(false), - mode(mode), interpolation(ir_var_smooth), array_lvalue(false) + mode(mode), interpolation(ir_var_smooth) { this->ir_type = ir_type_variable; this->type = type; - this->name = talloc_strdup(this, name); + this->name = ralloc_strdup(this, name); + this->explicit_location = false; this->location = -1; this->warn_extension = NULL; this->constant_value = NULL; this->origin_upper_left = false; this->pixel_center_integer = false; + this->depth_layout = ir_depth_layout_none; + this->used = false; if (type && type->base_type == GLSL_TYPE_SAMPLER) this->read_only = true; @@ -1085,6 +1369,21 @@ ir_function_signature::ir_function_signature(const glsl_type *return_type) } +static bool +modes_match(unsigned a, unsigned b) +{ + if (a == b) + return true; + + /* Accept "in" vs. "const in" */ + if ((a == ir_var_const_in && b == ir_var_in) || + (b == ir_var_const_in && a == ir_var_in)) + return true; + + return false; +} + + const char * ir_function_signature::qualifiers_match(exec_list *params) { @@ -1097,7 +1396,7 @@ ir_function_signature::qualifiers_match(exec_list *params) ir_variable *b = (ir_variable *)iter_b.get(); if (a->read_only != b->read_only || - a->mode != b->mode || + !modes_match(a->mode, b->mode) || a->interpolation != b->interpolation || a->centroid != b->centroid) { @@ -1132,16 +1431,16 @@ ir_function_signature::replace_parameters(exec_list *new_params) ir_function::ir_function(const char *name) { this->ir_type = ir_type_function; - this->name = talloc_strdup(this, name); + this->name = ralloc_strdup(this, name); } bool -ir_function::has_builtin_signature() +ir_function::has_user_signature() { foreach_list(n, &this->signatures) { ir_function_signature *const sig = (ir_function_signature *) n; - if (sig->is_builtin) + if (!sig->is_builtin) return true; } return false; @@ -1198,7 +1497,7 @@ steal_memory(ir_instruction *ir, void *new_ctx) } } - talloc_steal(new_ctx, ir); + ralloc_steal(new_ctx, ir); } @@ -1209,3 +1508,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; +}