[PATCH 4/5] d3dcompiler: Store derefs as an offset to a variable.

Zebediah Figura z.figura12 at gmail.com
Mon May 4 15:03:45 CDT 2020


Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---
One potential change to this patch is to always store an offset. Currently NULL
is used to signify an offset of 0, partly to save space, and partly because
otherwise new_var_deref() would need a bit of restructuring. But always using an
offset would simplify some code.

 dlls/d3dcompiler_43/d3dcompiler_private.h |  25 +---
 dlls/d3dcompiler_43/hlsl.y                | 143 +++++++++++++---------
 dlls/d3dcompiler_43/utils.c               |  76 ++----------
 3 files changed, 97 insertions(+), 147 deletions(-)

diff --git a/dlls/d3dcompiler_43/d3dcompiler_private.h b/dlls/d3dcompiler_43/d3dcompiler_private.h
index 387e932a6cc..983057d543c 100644
--- a/dlls/d3dcompiler_43/d3dcompiler_private.h
+++ b/dlls/d3dcompiler_43/d3dcompiler_private.h
@@ -841,30 +841,11 @@ struct hlsl_ir_swizzle
     DWORD swizzle;
 };
 
-enum hlsl_ir_deref_type
-{
-    HLSL_IR_DEREF_VAR,
-    HLSL_IR_DEREF_ARRAY,
-    HLSL_IR_DEREF_RECORD,
-};
-
 struct hlsl_deref
 {
-    enum hlsl_ir_deref_type type;
-    union
-    {
-        struct hlsl_ir_var *var;
-        struct
-        {
-            struct hlsl_ir_node *array;
-            struct hlsl_ir_node *index;
-        } array;
-        struct
-        {
-            struct hlsl_ir_node *record;
-            struct hlsl_struct_field *field;
-        } record;
-    } v;
+    struct hlsl_ir_var *var;
+    struct hlsl_ir_node *offset;
+    DWORD writemask;
 };
 
 struct hlsl_ir_deref
diff --git a/dlls/d3dcompiler_43/hlsl.y b/dlls/d3dcompiler_43/hlsl.y
index cc868757a26..24157c8fdc9 100644
--- a/dlls/d3dcompiler_43/hlsl.y
+++ b/dlls/d3dcompiler_43/hlsl.y
@@ -538,15 +538,29 @@ static struct hlsl_ir_assignment *make_simple_assignment(struct hlsl_ir_var *lhs
         return NULL;
 
     init_node(&assign->node, HLSL_IR_ASSIGNMENT, rhs->data_type, rhs->loc);
-    assign->lhs.type = HLSL_IR_DEREF_VAR;
-    assign->lhs.v.var = lhs;
+    assign->lhs.var = lhs;
     assign->rhs = rhs;
     if (type_is_single_reg(lhs->data_type))
-        assign->writemask = (1 << lhs->data_type->dimx) - 1;
+        assign->lhs.writemask = assign->writemask = (1 << lhs->data_type->dimx) - 1;
 
     return assign;
 }
 
+static struct hlsl_ir_constant *new_uint_constant(unsigned int n, const struct source_location loc)
+{
+    struct hlsl_type *type;
+    struct hlsl_ir_constant *c;
+
+    if (!(type = new_hlsl_type(d3dcompiler_strdup("uint"), HLSL_CLASS_SCALAR, HLSL_TYPE_UINT, 1, 1)))
+        return NULL;
+
+    if (!(c = d3dcompiler_alloc(sizeof(*c))))
+        return NULL;
+    init_node(&c->node, HLSL_IR_CONSTANT, type, loc);
+    c->v.value.u[0] = n;
+    return c;
+}
+
 static struct hlsl_ir_deref *new_var_deref(struct hlsl_ir_var *var, const struct source_location loc)
 {
     struct hlsl_ir_deref *deref = d3dcompiler_alloc(sizeof(*deref));
@@ -557,60 +571,76 @@ static struct hlsl_ir_deref *new_var_deref(struct hlsl_ir_var *var, const struct
         return NULL;
     }
     init_node(&deref->node, HLSL_IR_DEREF, var->data_type, loc);
-    deref->src.type = HLSL_IR_DEREF_VAR;
-    deref->src.v.var = var;
+    deref->src.var = var;
+    if (type_is_single_reg(var->data_type))
+        deref->src.writemask = (1 << var->data_type->dimx) - 1;
     return deref;
 }
 
-static struct hlsl_ir_node *get_var_deref(struct hlsl_ir_node *node)
+static struct hlsl_ir_deref *new_deref(struct hlsl_ir_node *var_node, struct hlsl_ir_node *offset,
+        struct hlsl_type *data_type, const struct source_location loc)
 {
-    struct hlsl_ir_assignment *assign;
+    struct hlsl_ir_node *add = NULL;
     struct hlsl_ir_deref *deref;
     struct hlsl_ir_var *var;
-    char name[27];
 
-    if (node->type == HLSL_IR_DEREF)
-        return node;
+    if (var_node->type == HLSL_IR_DEREF)
+    {
+        const struct hlsl_deref *src = &deref_from_node(var_node)->src;
 
-    sprintf(name, "<deref-%p>", node);
-    if (!(var = new_synthetic_var(name, node->data_type, node->loc)))
-        return NULL;
+        var = src->var;
+        if (src->offset)
+        {
+            if (!(add = new_binary_expr(HLSL_IR_BINOP_ADD, src->offset, offset, loc)))
+                return NULL;
+            list_add_after(&offset->entry, &add->entry);
+            offset = add;
+        }
+    }
+    else
+    {
+        struct hlsl_ir_assignment *assign;
+        char name[27];
+
+        sprintf(name, "<deref-%p>", var_node);
+        if (!(var = new_synthetic_var(name, var_node->data_type, var_node->loc)))
+            return NULL;
 
-    TRACE("Synthesized variable %p for %s node.\n", var, debug_node_type(node->type));
+        TRACE("Synthesized variable %p for %s node.\n", var, debug_node_type(var_node->type));
 
-    if (!(assign = make_simple_assignment(var, node)))
-        return NULL;
-    list_add_after(&node->entry, &assign->node.entry);
+        if (!(assign = make_simple_assignment(var, var_node)))
+            return NULL;
 
-    if (!(deref = new_var_deref(var, var->loc)))
+        list_add_after(&var_node->entry, &assign->node.entry);
+    }
+
+    if (!(deref = d3dcompiler_alloc(sizeof(*deref))))
         return NULL;
-    list_add_after(&assign->node.entry, &deref->node.entry);
-    return &deref->node;
+    init_node(&deref->node, HLSL_IR_DEREF, data_type, loc);
+    deref->src.var = var;
+    deref->src.offset = offset;
+    if (type_is_single_reg(data_type))
+        deref->src.writemask = (1 << data_type->dimx) - 1;
+    list_add_after(&offset->entry, &deref->node.entry);
+    return deref;
 }
 
 static struct hlsl_ir_deref *new_record_deref(struct hlsl_ir_node *record,
-        struct hlsl_struct_field *field, const struct source_location loc)
+        const struct hlsl_struct_field *field, const struct source_location loc)
 {
-    struct hlsl_ir_deref *deref;
+    struct hlsl_ir_constant *c;
 
-    if (!(record = get_var_deref(record)))
-        return NULL;
-
-    if (!(deref = d3dcompiler_alloc(sizeof(*deref))))
+    if (!(c = new_uint_constant(field->reg_offset, loc)))
         return NULL;
+    list_add_after(&record->entry, &c->node.entry);
 
-    init_node(&deref->node, HLSL_IR_DEREF, field->type, loc);
-    deref->src.type = HLSL_IR_DEREF_RECORD;
-    deref->src.v.record.record = record;
-    deref->src.v.record.field = field;
-    return deref;
+    return new_deref(record, &c->node, field->type, loc);
 }
 
 static struct hlsl_ir_deref *new_array_deref(struct hlsl_ir_node *array,
         struct hlsl_ir_node *index, const struct source_location loc)
 {
     const struct hlsl_type *expr_type = array->data_type;
-    struct hlsl_ir_deref *deref;
     struct hlsl_type *data_type;
 
     TRACE("Array dereference from type %s.\n", debug_hlsl_type(expr_type));
@@ -621,6 +651,7 @@ static struct hlsl_ir_deref *new_array_deref(struct hlsl_ir_node *array,
     }
     else if (expr_type->type == HLSL_CLASS_MATRIX || expr_type->type == HLSL_CLASS_VECTOR)
     {
+        /* This needs to be lowered now, while we still have type information. */
         FIXME("Index of matrix or vector type.\n");
         return NULL;
     }
@@ -633,17 +664,21 @@ static struct hlsl_ir_deref *new_array_deref(struct hlsl_ir_node *array,
         return NULL;
     }
 
-    if (!(array = get_var_deref(array)))
-        return NULL;
+    if (data_type->reg_size > 1)
+    {
+        struct hlsl_ir_constant *c;
+        struct hlsl_ir_node *mul;
 
-    if (!(deref = d3dcompiler_alloc(sizeof(*deref))))
-        return NULL;
+        if (!(c = new_uint_constant(data_type->reg_size, loc)))
+            return NULL;
+        list_add_after(&index->entry, &c->node.entry);
+        if (!(mul = new_binary_expr(HLSL_IR_BINOP_MUL, index, &c->node, loc)))
+            return NULL;
+        list_add_after(&c->node.entry, &mul->entry);
+        index = mul;
+    }
 
-    init_node(&deref->node, HLSL_IR_DEREF, data_type, loc);
-    deref->src.type = HLSL_IR_DEREF_ARRAY;
-    deref->src.v.array.array = array;
-    deref->src.v.array.index = index;
-    return deref;
+    return new_deref(array, index, data_type, loc);
 }
 
 static void struct_var_initializer(struct list *list, struct hlsl_ir_var *var,
@@ -2748,22 +2783,6 @@ static unsigned int index_instructions(struct list *instrs, unsigned int index)
     return index;
 }
 
-/* Walk the chain of derefs and retrieve the actual variable we care about. */
-static struct hlsl_ir_var *hlsl_var_from_deref(const struct hlsl_deref *deref)
-{
-    switch (deref->type)
-    {
-        case HLSL_IR_DEREF_VAR:
-            return deref->v.var;
-        case HLSL_IR_DEREF_ARRAY:
-            return hlsl_var_from_deref(&deref_from_node(deref->v.array.array)->src);
-        case HLSL_IR_DEREF_RECORD:
-            return hlsl_var_from_deref(&deref_from_node(deref->v.record.record)->src);
-    }
-    assert(0);
-    return NULL;
-}
-
 /* Compute the earliest and latest liveness for each variable. In the case that
  * a variable is accessed inside of a loop, we promote its liveness to extend
  * to at least the range of the entire loop. Note that we don't need to do this
@@ -2781,10 +2800,12 @@ static void compute_liveness_recurse(struct list *instrs, unsigned int loop_firs
         case HLSL_IR_ASSIGNMENT:
         {
             struct hlsl_ir_assignment *assignment = assignment_from_node(instr);
-            var = hlsl_var_from_deref(&assignment->lhs);
+            var = assignment->lhs.var;
             if (!var->first_write)
                 var->first_write = loop_first ? min(instr->index, loop_first) : instr->index;
             assignment->rhs->last_read = instr->index;
+            if (assignment->lhs.offset)
+                assignment->lhs.offset->last_read = instr->index;
             break;
         }
         case HLSL_IR_CONSTANT:
@@ -2800,10 +2821,10 @@ static void compute_liveness_recurse(struct list *instrs, unsigned int loop_firs
         case HLSL_IR_DEREF:
         {
             struct hlsl_ir_deref *deref = deref_from_node(instr);
-            var = hlsl_var_from_deref(&deref->src);
+            var = deref->src.var;
             var->last_read = loop_last ? max(instr->index, loop_last) : instr->index;
-            if (deref->src.type == HLSL_IR_DEREF_ARRAY)
-                deref->src.v.array.index->last_read = instr->index;
+            if (deref->src.offset)
+                deref->src.offset->last_read = instr->index;
             break;
         }
         case HLSL_IR_EXPR:
diff --git a/dlls/d3dcompiler_43/utils.c b/dlls/d3dcompiler_43/utils.c
index ac9da97f27c..4b1f99de65d 100644
--- a/dlls/d3dcompiler_43/utils.c
+++ b/dlls/d3dcompiler_43/utils.c
@@ -1437,29 +1437,6 @@ static unsigned int invert_swizzle(unsigned int *swizzle, unsigned int writemask
     return new_writemask;
 }
 
-static BOOL validate_lhs_deref(const struct hlsl_ir_node *lhs)
-{
-    struct hlsl_ir_deref *deref;
-
-    if (lhs->type != HLSL_IR_DEREF)
-    {
-        hlsl_report_message(lhs->loc, HLSL_LEVEL_ERROR, "invalid lvalue");
-        return FALSE;
-    }
-
-    deref = deref_from_node(lhs);
-
-    if (deref->src.type == HLSL_IR_DEREF_VAR)
-        return TRUE;
-    if (deref->src.type == HLSL_IR_DEREF_ARRAY)
-        return validate_lhs_deref(deref->src.v.array.array);
-    if (deref->src.type == HLSL_IR_DEREF_RECORD)
-        return validate_lhs_deref(deref->src.v.record.record);
-
-    assert(0);
-    return FALSE;
-}
-
 struct hlsl_ir_node *make_assignment(struct hlsl_ir_node *lhs, enum parse_assign_op assign_op,
         struct hlsl_ir_node *rhs)
 {
@@ -1513,12 +1490,6 @@ struct hlsl_ir_node *make_assignment(struct hlsl_ir_node *lhs, enum parse_assign
         lhs = lhs_inner;
     }
 
-    if (!validate_lhs_deref(lhs))
-    {
-        d3dcompiler_free(assign);
-        return NULL;
-    }
-
     TRACE("Creating proper assignment expression.\n");
     if (writemask == BWRITERSP_WRITEMASK_ALL)
         type = lhs->data_type;
@@ -1562,26 +1533,12 @@ struct hlsl_ir_node *make_assignment(struct hlsl_ir_node *lhs, enum parse_assign
         enum hlsl_ir_expr_op op = op_from_assignment(assign_op);
         struct hlsl_ir_node *expr;
 
-        if (assign->lhs.type != HLSL_IR_DEREF_VAR)
-        {
-            FIXME("LHS expression not supported in compound assignments yet.\n");
-            assign->rhs = rhs;
-        }
-        else
-        {
-            TRACE("Adding an expression for the compound assignment.\n");
-            expr = new_binary_expr(op, lhs, rhs, lhs->loc);
-            list_add_after(&rhs->entry, &expr->entry);
-            assign->rhs = expr;
-        }
-    }
-    else
-    {
-        list_remove(&lhs->entry);
-        /* Don't recursively free the deref; we just copied its members. */
-        d3dcompiler_free(lhs);
-        assign->rhs = rhs;
+        TRACE("Adding an expression for the compound assignment.\n");
+        expr = new_binary_expr(op, lhs, rhs, lhs->loc);
+        list_add_after(&rhs->entry, &expr->entry);
+        rhs = expr;
     }
+    assign->rhs = rhs;
 
     return &assign->node;
 }
@@ -1879,23 +1836,14 @@ static void debug_dump_ir_var(const struct hlsl_ir_var *var)
 
 static void debug_dump_deref(const struct hlsl_deref *deref)
 {
-    switch (deref->type)
+    wine_dbg_printf("deref(");
+    debug_dump_ir_var(deref->var);
+    wine_dbg_printf(")");
+    if (deref->offset)
     {
-        case HLSL_IR_DEREF_VAR:
-            wine_dbg_printf("deref(");
-            debug_dump_ir_var(deref->v.var);
-            wine_dbg_printf(")");
-            break;
-        case HLSL_IR_DEREF_ARRAY:
-            debug_dump_src(deref->v.array.array);
-            wine_dbg_printf("[");
-            debug_dump_src(deref->v.array.index);
-            wine_dbg_printf("]");
-            break;
-        case HLSL_IR_DEREF_RECORD:
-            debug_dump_src(deref->v.record.record);
-            wine_dbg_printf(".%s", debugstr_a(deref->v.record.field->name));
-            break;
+        wine_dbg_printf("[");
+        debug_dump_src(deref->offset);
+        wine_dbg_printf("]");
     }
 }
 
-- 
2.26.2




More information about the wine-devel mailing list