From: Eric Anholt Date: Tue, 30 Nov 2010 19:23:28 +0000 (-0800) Subject: glsl: Fix structure and array comparisions. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=ff79633d9f930e396933a0ad9564824ec73ea4dc;p=mesa.git glsl: Fix structure and array comparisions. We were trying to emit a single ir_expression to compare the whole thing. The backends (ir_to_mesa.cpp and brw_fs.cpp so far) expected ir_binop_any_nequal or ir_binop_all_equal to apply to at most a vector (with matrices broken down by the lowering pass). Break them down to a bunch of ORed or ANDed any_nequals/all_equals. Fixes: glsl-array-compare glsl-array-compare-02 glsl-fs-struct-equal glsl-fs-struct-notequal Bug #31909 --- diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp index fd9ed556806..0978100acd9 100644 --- a/src/glsl/ast_to_hir.cpp +++ b/src/glsl/ast_to_hir.cpp @@ -745,6 +745,75 @@ ast_node::hir(exec_list *instructions, return NULL; } +static ir_rvalue * +do_comparison(void *mem_ctx, int operation, ir_rvalue *op0, ir_rvalue *op1) +{ + int join_op; + + if (operation == ir_binop_all_equal) + join_op = ir_binop_logic_and; + else + join_op = ir_binop_logic_or; + + switch (op0->type->base_type) { + case GLSL_TYPE_FLOAT: + case GLSL_TYPE_UINT: + case GLSL_TYPE_INT: + case GLSL_TYPE_BOOL: + return new(mem_ctx) ir_expression(operation, op0, op1); + + case GLSL_TYPE_ARRAY: { + ir_rvalue *last = NULL; + + for (unsigned int i = 0; i < op0->type->length; i++) { + ir_rvalue *e0, *e1, *result; + + e0 = new(mem_ctx) ir_dereference_array(op0->clone(mem_ctx, NULL), + new(mem_ctx) ir_constant(i)); + e1 = new(mem_ctx) ir_dereference_array(op1->clone(mem_ctx, NULL), + new(mem_ctx) ir_constant(i)); + result = do_comparison(mem_ctx, operation, e0, e1); + + if (last) { + last = new(mem_ctx) ir_expression(join_op, last, result); + } else { + last = result; + } + } + return last; + } + + case GLSL_TYPE_STRUCT: { + ir_rvalue *last = NULL; + + for (unsigned int i = 0; i < op0->type->length; i++) { + ir_rvalue *e0, *e1, *result; + const char *field_name = op0->type->fields.structure[i].name; + + e0 = new(mem_ctx) ir_dereference_record(op0->clone(mem_ctx, NULL), + field_name); + e1 = new(mem_ctx) ir_dereference_record(op1->clone(mem_ctx, NULL), + field_name); + result = do_comparison(mem_ctx, operation, e0, e1); + + if (last) { + last = new(mem_ctx) ir_expression(join_op, last, result); + } else { + last = result; + } + } + return last; + } + + case GLSL_TYPE_ERROR: + case GLSL_TYPE_VOID: + case GLSL_TYPE_SAMPLER: + /* I assume a comparison of a struct containing a sampler just + * ignores the sampler present in the type. + */ + return new(mem_ctx) ir_constant(true); + } +} ir_rvalue * ast_expression::hir(exec_list *instructions, @@ -941,8 +1010,7 @@ ast_expression::hir(exec_list *instructions, error_emitted = true; } - result = new(ctx) ir_expression(operations[this->oper], glsl_type::bool_type, - op[0], op[1]); + result = do_comparison(ctx, operations[this->oper], op[0], op[1]); type = glsl_type::bool_type; assert(result->type == glsl_type::bool_type);