nir/serialize: remove up to 3 consecutive equal ALU instruction headers
[mesa.git] / src / compiler / nir / nir_serialize.c
index 469533f01797054ca6489992d71b99813ac6f04a..85db23beef8e98b185dab67c96772fd7ecf596ae 100644 (file)
@@ -56,6 +56,10 @@ typedef struct {
    const struct glsl_type *last_interface_type;
    struct nir_variable_data last_var_data;
 
+   /* For skipping equal ALU headers (typical after scalarization). */
+   nir_instr_type last_instr_type;
+   uintptr_t last_alu_header_offset;
+
    /* Don't write optional data such as variable names. */
    bool strip;
 } write_ctx;
@@ -99,12 +103,6 @@ write_lookup_object(write_ctx *ctx, const void *obj)
    return (uint32_t)(uintptr_t) entry->data;
 }
 
-static void
-write_object(write_ctx *ctx, const void *obj)
-{
-   blob_write_uint32(ctx->blob, write_lookup_object(ctx, obj));
-}
-
 static void
 read_add_object(read_ctx *ctx, void *obj)
 {
@@ -618,17 +616,26 @@ union packed_instr {
       unsigned writemask:4;
       unsigned op:9;
       unsigned packed_src_ssa_16bit:1;
-      unsigned _pad:2;
+      /* Scalarized ALUs always have the same header. */
+      unsigned num_followup_alu_sharing_header:2;
       unsigned dest:8;
    } alu;
    struct {
       unsigned instr_type:4;
       unsigned deref_type:3;
-      unsigned mode:10;
       unsigned cast_type_same_as_last:1;
-      unsigned _pad:6;
+      unsigned mode:10; /* deref_var redefines this */
+      unsigned packed_src_ssa_16bit:1; /* deref_var redefines this */
+      unsigned _pad:5;  /* deref_var redefines this */
       unsigned dest:8;
    } deref;
+   struct {
+      unsigned instr_type:4;
+      unsigned deref_type:3;
+      unsigned _pad:1;
+      unsigned object_idx:16; /* if 0, the object ID is a separate uint32 */
+      unsigned dest:8;
+   } deref_var;
    struct {
       unsigned instr_type:4;
       unsigned intrinsic:9;
@@ -671,7 +678,8 @@ union packed_instr {
 
 /* Write "lo24" as low 24 bits in the first uint32. */
 static void
-write_dest(write_ctx *ctx, const nir_dest *dst, union packed_instr header)
+write_dest(write_ctx *ctx, const nir_dest *dst, union packed_instr header,
+           nir_instr_type instr_type)
 {
    STATIC_ASSERT(sizeof(union packed_dest) == 1);
    union packed_dest dest;
@@ -686,9 +694,43 @@ write_dest(write_ctx *ctx, const nir_dest *dst, union packed_instr header)
    } else {
       dest.reg.is_indirect = !!(dst->reg.indirect);
    }
-
    header.any.dest = dest.u8;
-   blob_write_uint32(ctx->blob, header.u32);
+
+   /* Check if the current ALU instruction has the same header as the previous
+    * instruction that is also ALU. If it is, we don't have to write
+    * the current header. This is a typical occurence after scalarization.
+    */
+   if (instr_type == nir_instr_type_alu) {
+      bool equal_header = false;
+
+      if (ctx->last_instr_type == nir_instr_type_alu) {
+         assert(ctx->last_alu_header_offset);
+         union packed_instr *last_header =
+            (union packed_instr *)(ctx->blob->data +
+                                   ctx->last_alu_header_offset);
+
+         /* Clear the field that counts ALUs with equal headers. */
+         union packed_instr clean_header;
+         clean_header.u32 = last_header->u32;
+         clean_header.alu.num_followup_alu_sharing_header = 0;
+
+         /* There can be at most 4 consecutive ALU instructions
+          * sharing the same header.
+          */
+         if (last_header->alu.num_followup_alu_sharing_header < 3 &&
+             header.u32 == clean_header.u32) {
+            last_header->alu.num_followup_alu_sharing_header++;
+            equal_header = true;
+         }
+      }
+
+      if (!equal_header) {
+         ctx->last_alu_header_offset = ctx->blob->size;
+         blob_write_uint32(ctx->blob, header.u32);
+      }
+   } else {
+      blob_write_uint32(ctx->blob, header.u32);
+   }
 
    if (dst->is_ssa) {
       write_add_object(ctx, &dst->ssa);
@@ -771,7 +813,7 @@ write_alu(write_ctx *ctx, const nir_alu_instr *alu)
    header.alu.op = alu->op;
    header.alu.packed_src_ssa_16bit = is_alu_src_ssa_16bit(ctx, alu);
 
-   write_dest(ctx, &alu->dest.dest, header);
+   write_dest(ctx, &alu->dest.dest, header, alu->instr.type);
 
    if (header.alu.packed_src_ssa_16bit) {
       for (unsigned i = 0; i < num_srcs; i++) {
@@ -851,31 +893,54 @@ write_deref(write_ctx *ctx, const nir_deref_instr *deref)
 
    header.deref.instr_type = deref->instr.type;
    header.deref.deref_type = deref->deref_type;
-   header.deref.mode = deref->mode;
 
-   if (deref->deref_type == nir_deref_type_cast)
+   if (deref->deref_type == nir_deref_type_cast) {
+      header.deref.mode = deref->mode;
       header.deref.cast_type_same_as_last = deref->type == ctx->last_type;
+   }
 
-   write_dest(ctx, &deref->dest, header);
-
+   unsigned var_idx = 0;
    if (deref->deref_type == nir_deref_type_var) {
-      write_object(ctx, deref->var);
-      return;
+      var_idx = write_lookup_object(ctx, deref->var);
+      if (var_idx && var_idx < (1 << 16))
+         header.deref_var.object_idx = var_idx;
+   }
+
+   if (deref->deref_type == nir_deref_type_array ||
+       deref->deref_type == nir_deref_type_ptr_as_array) {
+      header.deref.packed_src_ssa_16bit =
+         deref->parent.is_ssa && deref->arr.index.is_ssa &&
+         are_object_ids_16bit(ctx);
    }
 
-   write_src(ctx, &deref->parent);
+   write_dest(ctx, &deref->dest, header, deref->instr.type);
 
    switch (deref->deref_type) {
+   case nir_deref_type_var:
+      if (!header.deref_var.object_idx)
+         blob_write_uint32(ctx->blob, var_idx);
+      break;
+
    case nir_deref_type_struct:
+      write_src(ctx, &deref->parent);
       blob_write_uint32(ctx->blob, deref->strct.index);
       break;
 
    case nir_deref_type_array:
    case nir_deref_type_ptr_as_array:
-      write_src(ctx, &deref->arr.index);
+      if (header.deref.packed_src_ssa_16bit) {
+         blob_write_uint16(ctx->blob,
+                           write_lookup_object(ctx, deref->parent.ssa));
+         blob_write_uint16(ctx->blob,
+                           write_lookup_object(ctx, deref->arr.index.ssa));
+      } else {
+         write_src(ctx, &deref->parent);
+         write_src(ctx, &deref->arr.index);
+      }
       break;
 
    case nir_deref_type_cast:
+      write_src(ctx, &deref->parent);
       blob_write_uint32(ctx->blob, deref->cast.ptr_stride);
       if (!header.deref.cast_type_same_as_last) {
          encode_type_to_blob(ctx->blob, deref->type);
@@ -884,7 +949,7 @@ write_deref(write_ctx *ctx, const nir_deref_instr *deref)
       break;
 
    case nir_deref_type_array_wildcard:
-      /* Nothing to do */
+      write_src(ctx, &deref->parent);
       break;
 
    default:
@@ -900,19 +965,20 @@ read_deref(read_ctx *ctx, union packed_instr header)
 
    read_dest(ctx, &deref->dest, &deref->instr, header);
 
-   deref->mode = header.deref.mode;
-
-   if (deref_type == nir_deref_type_var) {
-      deref->var = read_object(ctx);
-      deref->type = deref->var->type;
-      return deref;
-   }
-
-   read_src(ctx, &deref->parent, &deref->instr);
    nir_deref_instr *parent;
 
    switch (deref->deref_type) {
+   case nir_deref_type_var:
+      if (header.deref_var.object_idx)
+         deref->var = read_lookup_object(ctx, header.deref_var.object_idx);
+      else
+         deref->var = read_object(ctx);
+
+      deref->type = deref->var->type;
+      break;
+
    case nir_deref_type_struct:
+      read_src(ctx, &deref->parent, &deref->instr);
       parent = nir_src_as_deref(deref->parent);
       deref->strct.index = blob_read_uint32(ctx->blob);
       deref->type = glsl_get_struct_field(parent->type, deref->strct.index);
@@ -920,15 +986,25 @@ read_deref(read_ctx *ctx, union packed_instr header)
 
    case nir_deref_type_array:
    case nir_deref_type_ptr_as_array:
+      if (header.deref.packed_src_ssa_16bit) {
+         deref->parent.is_ssa = true;
+         deref->parent.ssa = read_lookup_object(ctx, blob_read_uint16(ctx->blob));
+         deref->arr.index.is_ssa = true;
+         deref->arr.index.ssa = read_lookup_object(ctx, blob_read_uint16(ctx->blob));
+      } else {
+         read_src(ctx, &deref->parent, &deref->instr);
+         read_src(ctx, &deref->arr.index, &deref->instr);
+      }
+
       parent = nir_src_as_deref(deref->parent);
       if (deref->deref_type == nir_deref_type_array)
          deref->type = glsl_get_array_element(parent->type);
       else
          deref->type = parent->type;
-      read_src(ctx, &deref->arr.index, &deref->instr);
       break;
 
    case nir_deref_type_cast:
+      read_src(ctx, &deref->parent, &deref->instr);
       deref->cast.ptr_stride = blob_read_uint32(ctx->blob);
       if (header.deref.cast_type_same_as_last) {
          deref->type = ctx->last_type;
@@ -939,6 +1015,7 @@ read_deref(read_ctx *ctx, union packed_instr header)
       break;
 
    case nir_deref_type_array_wildcard:
+      read_src(ctx, &deref->parent, &deref->instr);
       parent = nir_src_as_deref(deref->parent);
       deref->type = glsl_get_array_element(parent->type);
       break;
@@ -947,6 +1024,15 @@ read_deref(read_ctx *ctx, union packed_instr header)
       unreachable("Invalid deref type");
    }
 
+   if (deref_type == nir_deref_type_var) {
+      deref->mode = deref->var->data.mode;
+   } else if (deref->deref_type == nir_deref_type_cast) {
+      deref->mode = header.deref.mode;
+   } else {
+      assert(deref->parent.is_ssa);
+      deref->mode = nir_instr_as_deref(deref->parent.ssa->parent_instr)->mode;
+   }
+
    return deref;
 }
 
@@ -993,7 +1079,7 @@ write_intrinsic(write_ctx *ctx, const nir_intrinsic_instr *intrin)
    }
 
    if (nir_intrinsic_infos[intrin->intrinsic].has_dest)
-      write_dest(ctx, &intrin->dest, header);
+      write_dest(ctx, &intrin->dest, header, intrin->instr.type);
    else
       blob_write_uint32(ctx->blob, header.u32);
 
@@ -1278,7 +1364,7 @@ write_tex(write_ctx *ctx, const nir_tex_instr *tex)
    header.tex.op = tex->op;
    header.tex.texture_array_size = tex->texture_array_size;
 
-   write_dest(ctx, &tex->dest, header);
+   write_dest(ctx, &tex->dest, header, tex->instr.type);
 
    blob_write_uint32(ctx->blob, tex->texture_index);
    blob_write_uint32(ctx->blob, tex->sampler_index);
@@ -1351,7 +1437,7 @@ write_phi(write_ctx *ctx, const nir_phi_instr *phi)
     * and then store enough information so that a later fixup pass can fill
     * them in correctly.
     */
-   write_dest(ctx, &phi->dest, header);
+   write_dest(ctx, &phi->dest, header, phi->instr.type);
 
    nir_foreach_phi_src(src, phi) {
       assert(src->src.is_ssa);
@@ -1519,7 +1605,8 @@ write_instr(write_ctx *ctx, const nir_instr *instr)
    }
 }
 
-static void
+/* Return the number of instructions read. */
+static unsigned
 read_instr(read_ctx *ctx, nir_block *block)
 {
    STATIC_ASSERT(sizeof(union packed_instr) == 4);
@@ -1529,8 +1616,9 @@ read_instr(read_ctx *ctx, nir_block *block)
 
    switch (header.any.instr_type) {
    case nir_instr_type_alu:
-      instr = &read_alu(ctx, header)->instr;
-      break;
+      for (unsigned i = 0; i <= header.alu.num_followup_alu_sharing_header; i++)
+         nir_instr_insert_after_block(block, &read_alu(ctx, header)->instr);
+      return header.alu.num_followup_alu_sharing_header + 1;
    case nir_instr_type_deref:
       instr = &read_deref(ctx, header)->instr;
       break;
@@ -1553,7 +1641,7 @@ read_instr(read_ctx *ctx, nir_block *block)
        * are read so that we can set their sources up.
        */
       read_phi(ctx, block, header);
-      return;
+      return 1;
    case nir_instr_type_jump:
       instr = &read_jump(ctx, header)->instr;
       break;
@@ -1567,6 +1655,7 @@ read_instr(read_ctx *ctx, nir_block *block)
    }
 
    nir_instr_insert_after_block(block, instr);
+   return 1;
 }
 
 static void
@@ -1574,8 +1663,14 @@ write_block(write_ctx *ctx, const nir_block *block)
 {
    write_add_object(ctx, block);
    blob_write_uint32(ctx->blob, exec_list_length(&block->instr_list));
-   nir_foreach_instr(instr, block)
+
+   ctx->last_instr_type = ~0;
+   ctx->last_alu_header_offset = 0;
+
+   nir_foreach_instr(instr, block) {
       write_instr(ctx, instr);
+      ctx->last_instr_type = instr->type;
+   }
 }
 
 static void
@@ -1590,8 +1685,8 @@ read_block(read_ctx *ctx, struct exec_list *cf_list)
 
    read_add_object(ctx, block);
    unsigned num_instrs = blob_read_uint32(ctx->blob);
-   for (unsigned i = 0; i < num_instrs; i++) {
-      read_instr(ctx, block);
+   for (unsigned i = 0; i < num_instrs;) {
+      i += read_instr(ctx, block);
    }
 }