diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index a1e3aacd..ec3f5826 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -1422,6 +1422,7 @@ struct hlsl_reg hlsl_reg_from_deref(struct hlsl_ctx *ctx, const struct hlsl_dere bool hlsl_copy_propagation_execute(struct hlsl_ctx *ctx, struct hlsl_block *block); bool hlsl_fold_constant_exprs(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context); +bool hlsl_fold_constant_identities(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context); bool hlsl_fold_constant_swizzles(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context); bool hlsl_transform_ir(struct hlsl_ctx *ctx, bool (*func)(struct hlsl_ctx *ctx, struct hlsl_ir_node *, void *), struct hlsl_block *block, void *context); diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index a6d6b336..94acb70f 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -5427,6 +5427,7 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry do { progress = hlsl_transform_ir(ctx, hlsl_fold_constant_exprs, body, NULL); + progress |= hlsl_transform_ir(ctx, hlsl_fold_constant_identities, body, NULL); progress |= hlsl_transform_ir(ctx, hlsl_fold_constant_swizzles, body, NULL); progress |= hlsl_copy_propagation_execute(ctx, body); progress |= hlsl_transform_ir(ctx, fold_swizzle_chains, body, NULL); diff --git a/libs/vkd3d-shader/hlsl_constant_ops.c b/libs/vkd3d-shader/hlsl_constant_ops.c index 4cea98e9..526ce88b 100644 --- a/libs/vkd3d-shader/hlsl_constant_ops.c +++ b/libs/vkd3d-shader/hlsl_constant_ops.c @@ -1396,6 +1396,97 @@ bool hlsl_fold_constant_exprs(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, return success; } +static bool constant_is_zero(struct hlsl_ir_constant *const_arg) +{ + struct hlsl_type *data_type = const_arg->node.data_type; + unsigned int k; + + for (k = 0; k < data_type->dimx; ++k) + { + switch (data_type->base_type) + { + case HLSL_TYPE_FLOAT: + case HLSL_TYPE_HALF: + if (const_arg->value.u[k].f != 0.0f) + return false; + break; + + case HLSL_TYPE_DOUBLE: + if (const_arg->value.u[k].d != 0.0) + return false; + break; + + case HLSL_TYPE_UINT: + case HLSL_TYPE_INT: + case HLSL_TYPE_BOOL: + if (const_arg->value.u[k].u != 0) + return false; + break; + + default: + return false; + } + } + return true; +} + +bool hlsl_fold_constant_identities(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) +{ + struct hlsl_ir_constant *const_arg = NULL; + struct hlsl_ir_node *mut_arg = NULL; + struct hlsl_ir_node *res_node; + struct hlsl_ir_expr *expr; + unsigned int i; + + if (instr->type != HLSL_IR_EXPR) + return false; + expr = hlsl_ir_expr(instr); + + if (instr->data_type->class > HLSL_CLASS_VECTOR) + return false; + + /* Verify that the expression has two operands. */ + for (i = 0; i < ARRAY_SIZE(expr->operands); ++i) + { + if (!!expr->operands[i].node != (i < 2)) + return false; + } + + if (expr->operands[0].node->type == HLSL_IR_CONSTANT) + { + const_arg = hlsl_ir_constant(expr->operands[0].node); + mut_arg = expr->operands[1].node; + } + else if (expr->operands[1].node->type == HLSL_IR_CONSTANT) + { + mut_arg = expr->operands[0].node; + const_arg = hlsl_ir_constant(expr->operands[1].node); + } + else + { + return false; + } + + res_node = NULL; + switch (expr->op) + { + case HLSL_OP2_ADD: + if (constant_is_zero(const_arg)) + res_node = mut_arg; + break; + + default: + break; + } + + if (res_node) + { + hlsl_replace_node(&expr->node, res_node); + return true; + } + return false; +} + bool hlsl_fold_constant_swizzles(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) { struct hlsl_constant_value value;