From: Nikolay Sivov nsivov@codeweavers.com
--- libs/vkd3d-shader/hlsl.y | 168 ++++++++++++++++++++++++++------------- 1 file changed, 114 insertions(+), 54 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 194d21f4..9ae36cc0 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -1141,54 +1141,130 @@ static struct list *make_list(struct hlsl_ctx *ctx, struct hlsl_ir_node *node) return list; }
-static unsigned int evaluate_static_expression(struct hlsl_ir_node *node) +struct static_expr_value { - if (node->data_type->class != HLSL_CLASS_SCALAR) - return 0; + enum hlsl_base_type type; + union hlsl_constant_value v; +}; + +static int static_expr_value_as_int(const struct static_expr_value *value) +{ + switch (value->type) + { + case HLSL_TYPE_DOUBLE: + return value->v.d; + case HLSL_TYPE_FLOAT: + return value->v.f; + case HLSL_TYPE_INT: + return value->v.i; + case HLSL_TYPE_UINT: + return value->v.u; + default: + vkd3d_unreachable(); + } +} + +static unsigned int static_expr_value_as_uint(const struct static_expr_value *value) +{ + switch (value->type) + { + case HLSL_TYPE_DOUBLE: + return value->v.d; + case HLSL_TYPE_FLOAT: + return value->v.f; + case HLSL_TYPE_INT: + return value->v.i; + case HLSL_TYPE_UINT: + return value->v.u; + default: + vkd3d_unreachable(); + } +} + +static void static_expr_get_value(enum hlsl_ir_expr_op op, const struct static_expr_value *operands, + struct static_expr_value *ret) +{ + switch (op) + { + case HLSL_OP2_ADD: + switch (ret->type) + { + case HLSL_TYPE_INT: + ret->v.i = static_expr_value_as_int(&operands[0]) + static_expr_value_as_int(&operands[1]); + break; + default: + FIXME("Unsupported 'add' for type %u.\n", ret->type); + } + break; + case HLSL_OP2_MUL: + switch (ret->type) + { + case HLSL_TYPE_INT: + ret->v.i = static_expr_value_as_int(&operands[0]) * static_expr_value_as_int(&operands[1]); + break; + default: + FIXME("Unsupported 'mul' for type %u.\n", ret->type); + } + break; + default: + FIXME("Unsupported expression op %u.\n", op); + } +} + +static enum hlsl_base_type expr_common_base_type(enum hlsl_base_type t1, enum hlsl_base_type t2) +{ + if (t1 > HLSL_TYPE_LAST_SCALAR || t2 > HLSL_TYPE_LAST_SCALAR) { + FIXME("Unexpected base type.\n"); + return HLSL_TYPE_FLOAT; + } + if (t1 == t2) + return t1 == HLSL_TYPE_BOOL ? HLSL_TYPE_INT : t1; + if (t1 == HLSL_TYPE_DOUBLE || t2 == HLSL_TYPE_DOUBLE) + return HLSL_TYPE_DOUBLE; + if (t1 == HLSL_TYPE_FLOAT || t2 == HLSL_TYPE_FLOAT + || t1 == HLSL_TYPE_HALF || t2 == HLSL_TYPE_HALF) + return HLSL_TYPE_FLOAT; + if (t1 == HLSL_TYPE_UINT || t2 == HLSL_TYPE_UINT) + return HLSL_TYPE_UINT; + return HLSL_TYPE_INT; +} + +static struct static_expr_value evaluate_static_expression(const struct hlsl_ir_node *node) +{ + struct static_expr_value operands[HLSL_MAX_OPERANDS] = { 0 }, ret = { 0 };
switch (node->type) { case HLSL_IR_CONSTANT: { struct hlsl_ir_constant *constant = hlsl_ir_constant(node); - const union hlsl_constant_value *value = &constant->value[0]; - - switch (constant->node.data_type->base_type) + ret.type = constant->node.data_type->base_type; + ret.v = constant->value[0]; + break; + } + case HLSL_IR_EXPR: + { + struct hlsl_ir_expr *expr = hlsl_ir_expr(node); + switch (expr->op) { - case HLSL_TYPE_UINT: - return value->u; - case HLSL_TYPE_INT: - return value->i; - case HLSL_TYPE_FLOAT: - case HLSL_TYPE_HALF: - return value->f; - case HLSL_TYPE_DOUBLE: - return value->d; - case HLSL_TYPE_BOOL: - return !!value->u; + case HLSL_OP2_ADD: + case HLSL_OP2_MUL: + operands[0] = evaluate_static_expression(expr->operands[0].node); + operands[1] = evaluate_static_expression(expr->operands[1].node); + ret.type = expr_common_base_type(operands[0].type, operands[1].type); + static_expr_get_value(expr->op, operands, &ret); + break; default: - vkd3d_unreachable(); + FIXME("Unhandled op %u.\n", expr->op); + return ret; } + break; } - - case HLSL_IR_EXPR: - case HLSL_IR_INDEX: - case HLSL_IR_LOAD: - case HLSL_IR_RESOURCE_LOAD: - case HLSL_IR_SWIZZLE: + default: FIXME("Unhandled type %s.\n", hlsl_node_type_to_string(node->type)); - return 0; - - case HLSL_IR_CALL: - case HLSL_IR_IF: - case HLSL_IR_JUMP: - case HLSL_IR_LOOP: - case HLSL_IR_RESOURCE_STORE: - case HLSL_IR_STORE: - vkd3d_unreachable(); }
- vkd3d_unreachable(); + return ret; }
static bool expr_compatible_data_types(struct hlsl_type *t1, struct hlsl_type *t2) @@ -1225,24 +1301,6 @@ static bool expr_compatible_data_types(struct hlsl_type *t1, struct hlsl_type *t return false; }
-static enum hlsl_base_type expr_common_base_type(enum hlsl_base_type t1, enum hlsl_base_type t2) -{ - if (t1 > HLSL_TYPE_LAST_SCALAR || t2 > HLSL_TYPE_LAST_SCALAR) { - FIXME("Unexpected base type.\n"); - return HLSL_TYPE_FLOAT; - } - if (t1 == t2) - return t1 == HLSL_TYPE_BOOL ? HLSL_TYPE_INT : t1; - if (t1 == HLSL_TYPE_DOUBLE || t2 == HLSL_TYPE_DOUBLE) - return HLSL_TYPE_DOUBLE; - if (t1 == HLSL_TYPE_FLOAT || t2 == HLSL_TYPE_FLOAT - || t1 == HLSL_TYPE_HALF || t2 == HLSL_TYPE_HALF) - return HLSL_TYPE_FLOAT; - if (t1 == HLSL_TYPE_UINT || t2 == HLSL_TYPE_UINT) - return HLSL_TYPE_UINT; - return HLSL_TYPE_INT; -} - static bool expr_common_shape(struct hlsl_ctx *ctx, struct hlsl_type *t1, struct hlsl_type *t2, const struct vkd3d_shader_location *loc, enum hlsl_type_class *type, unsigned int *dimx, unsigned int *dimy) { @@ -4917,7 +4975,8 @@ type_no_void: } | texture_ms_type '<' type ',' shift_expr '>' { - unsigned int sample_count = evaluate_static_expression(node_from_list($5)); + struct static_expr_value value = evaluate_static_expression(node_from_list($5)); + unsigned int sample_count = static_expr_value_as_uint(&value); destroy_instr_list($5);
$$ = hlsl_new_texture_type(ctx, $1, $3, sample_count); @@ -5111,7 +5170,8 @@ arrays: } | '[' expr ']' arrays { - unsigned int size = evaluate_static_expression(node_from_list($2)); + struct static_expr_value value = evaluate_static_expression(node_from_list($2)); + unsigned int size = static_expr_value_as_uint(&value); uint32_t *new_array;
destroy_instr_list($2);
I don't think we want to reinvent constant folding if we can help it. Rather, we probably want to perform the existing constant folding passes (and other optimization passes, if necessary?) on the relevant block.
Ah, I didn't realize we have the structure in place.