[RFC,01/17] etnaviv: add basic block based backend ir: eir

Submitted by Christian Gmeiner on May 10, 2019, 9:08 a.m.

Details

Message ID 20190510090915.2739-2-christian.gmeiner@gmail.com
State New
Headers show
Series "An other look at nir" ( rev: 1 ) in Mesa

Not browsing as part of any series.

Commit Message

Christian Gmeiner May 10, 2019, 9:08 a.m.
Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>
---
 src/etnaviv/compiler/eir.c                  | 239 ++++++++++
 src/etnaviv/compiler/eir.h                  | 499 ++++++++++++++++++++
 src/etnaviv/compiler/eir_uniform.c          | 108 +++++
 src/etnaviv/compiler/meson.build            |  38 ++
 src/etnaviv/compiler/tests/eir_assemble.cpp | 114 +++++
 src/etnaviv/compiler/tests/eir_uniform.cpp  | 324 +++++++++++++
 src/etnaviv/compiler/tests/meson.build      |  44 ++
 src/etnaviv/meson.build                     |   1 +
 8 files changed, 1367 insertions(+)
 create mode 100644 src/etnaviv/compiler/eir.c
 create mode 100644 src/etnaviv/compiler/eir.h
 create mode 100644 src/etnaviv/compiler/eir_uniform.c
 create mode 100644 src/etnaviv/compiler/meson.build
 create mode 100644 src/etnaviv/compiler/tests/eir_assemble.cpp
 create mode 100644 src/etnaviv/compiler/tests/eir_uniform.cpp
 create mode 100644 src/etnaviv/compiler/tests/meson.build

Patch hide | download patch | download mbox

diff --git a/src/etnaviv/compiler/eir.c b/src/etnaviv/compiler/eir.c
new file mode 100644
index 00000000000..398ae7443c5
--- /dev/null
+++ b/src/etnaviv/compiler/eir.c
@@ -0,0 +1,239 @@ 
+/*
+ * Copyright (c) 2018 Etnaviv Project
+ * Copyright (C) 2018 Zodiac Inflight Innovations
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Christian Gmeiner <christian.gmeiner@gmail.com>
+ */
+
+#include "eir.h"
+#include <stdlib.h>
+#include <string.h>
+#include "util/ralloc.h"
+
+struct eir *
+eir_create(void)
+{
+   struct eir *ir = rzalloc(NULL, struct eir);
+
+   list_inithead(&ir->block_list);
+   util_dynarray_init(&ir->reg_alloc, ir);
+   util_dynarray_init(&ir->uniform_alloc, ir);
+
+   return ir;
+}
+
+void
+eir_destroy(struct eir *ir)
+{
+   assert(ir);
+   util_dynarray_fini(&ir->reg_alloc);
+   util_dynarray_fini(&ir->uniform_alloc);
+   ralloc_free(ir);
+}
+
+struct eir_block *
+eir_block_create(struct eir *ir)
+{
+   assert(ir);
+   struct eir_block *block = rzalloc(ir, struct eir_block);
+
+   block->ir = ir;
+   block->num = ir->blocks++;
+   list_inithead(&block->node);
+   list_inithead(&block->instr_list);
+
+   list_addtail(&block->node, &ir->block_list);
+
+   return block;
+}
+
+struct eir_instruction *
+eir_instruction_create(struct eir_block *block, enum gc_op opc)
+{
+   assert(block);
+   struct eir_instruction *instr = rzalloc(block, struct eir_instruction);
+
+   instr->block = block;
+   list_addtail(&instr->node, &block->instr_list);
+
+   instr->gc.opcode = opc;
+
+   return instr;
+}
+
+struct eir_register
+eir_temp_register(struct eir *ir, unsigned num_components)
+{
+   assert(num_components >= 1 && num_components <= 4);
+
+   struct eir_register reg = {
+      .type = EIR_REG_TEMP,
+      .index = util_dynarray_num_elements(&ir->reg_alloc, unsigned),
+   };
+
+   util_dynarray_append(&ir->reg_alloc, unsigned, num_components);
+
+   return reg;
+}
+
+void
+eir_link_blocks(struct eir_block *predecessor, struct eir_block *successor)
+{
+   assert(predecessor);
+   assert(successor);
+
+   if (predecessor->successors[0]) {
+      assert(!predecessor->successors[1]);
+      predecessor->successors[1] = successor;
+   } else {
+      predecessor->successors[0] = successor;
+   }
+}
+
+static void
+convert_sampler(const struct eir_register *eir, struct gc_instr_sampler *sampler)
+{
+   assert(eir->type == EIR_REG_SAMPLER);
+
+   sampler->id = eir->index;
+   sampler->swiz = eir->swizzle;
+   sampler->amode = GC_ADDRESSING_MODE_DIRECT;
+}
+
+static void
+convert_src(const struct eir_register *eir, struct gc_instr_src *gc)
+{
+   assert(!gc->use);
+   assert(eir->type != EIR_REG_UNDEF);
+   assert(eir->type != EIR_REG_SAMPLER);
+
+   gc->use = true;
+   gc->reg = eir->index;
+   gc->abs = eir->abs;
+   gc->neg = eir->neg;
+   gc->swiz = eir->swizzle;
+
+   switch (eir->type) {
+   case EIR_REG_TEMP:
+      gc->rgroup = GC_REGISTER_GROUP_TEMP;
+      break;
+
+   case EIR_REG_UNIFORM:
+      gc->rgroup = GC_REGISTER_GROUP_UNIFORM;
+      break;
+
+   default:
+      unreachable("unhandled type");
+   }
+}
+
+static void
+convert_dst(const struct eir_register *eir, struct gc_instr_dst *gc)
+{
+   assert(!gc->comps);
+
+   gc->reg = eir->index;
+   gc->comps = eir->writemask;
+}
+
+static void
+eir_to_gc(struct eir_instruction *instr)
+{
+   struct gc_instr *gc = &instr->gc;
+
+   if (gc_op_num_src(gc->opcode)) {
+      const unsigned swizzle = gc_op_src_swizzle(gc->opcode);
+
+      /* src swizzle */
+      for (int i = 0; i < gc_op_num_src(gc->opcode); i++) {
+         const unsigned shift = i * 2;
+         const unsigned mask = 0x3 << shift;
+         const unsigned index = (swizzle & mask) >> shift;
+
+         if (index == 0x3)
+            continue;
+
+         if (instr->src[i].type == EIR_REG_UNDEF)
+            continue;
+
+         switch (gc->type) {
+         case GC_OP_TYPE_ALU:
+            convert_src(&instr->src[i], &gc->alu.src[index]);
+            break;
+
+         case GC_OP_TYPE_BRANCH:
+            convert_src(&instr->src[i], &gc->branch.src[index]);
+            break;
+
+         case GC_OP_TYPE_SAMPLER:
+            if (i == 0)
+               convert_sampler(&instr->src[0], &gc->sampler);
+            else if (i == 1)
+               convert_src(&instr->src[1], &gc->sampler.src);
+            else
+               unreachable("unkown sampler index");
+
+            break;
+         }
+      }
+
+      /* special handling for src replication */
+      if (gc->type == GC_OP_TYPE_ALU && swizzle & SWIZ_REP_SRC0_TO_SRC2) {
+         assert(gc->type == GC_OP_TYPE_ALU);
+         convert_src(&instr->src[0], &gc->alu.src[2]);
+      }
+   }
+
+   if (gc_op_has_dst(gc->opcode))
+      convert_dst(&instr->dst, &gc->dst);
+}
+
+uint32_t *
+eir_assemble(const struct eir *ir, struct eir_info *info)
+{
+   assert(ir);
+   assert(info);
+   uint32_t *ptr, *dwords;
+
+   memset(info, 0, sizeof(*info));
+
+   eir_for_each_block(block, ir) {
+      eir_for_each_inst(instr, block) {
+         info->sizedwords += 4;
+      }
+   }
+
+   ptr = dwords = calloc(4, info->sizedwords);
+   if (!ptr)
+      return NULL;
+
+   eir_for_each_block(block, ir) {
+      eir_for_each_inst(instr, block) {
+         eir_to_gc(instr);
+         gc_pack_instr(&instr->gc, dwords);
+         dwords += 4;
+      }
+   }
+
+   return ptr;
+}
diff --git a/src/etnaviv/compiler/eir.h b/src/etnaviv/compiler/eir.h
new file mode 100644
index 00000000000..e2185b004f1
--- /dev/null
+++ b/src/etnaviv/compiler/eir.h
@@ -0,0 +1,499 @@ 
+/*
+ * Copyright (c) 2018 Etnaviv Project
+ * Copyright (C) 2018 Zodiac Inflight Innovations
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Christian Gmeiner <christian.gmeiner@gmail.com>
+ */
+
+#ifndef H_EIR
+#define H_EIR
+
+#include <assert.h>
+#include "util/list.h"
+#include "util/u_dynarray.h"
+#include "util/u_math.h"
+#include "etnaviv/gc/gc_instr.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+struct eir;
+struct eir_block;
+
+struct eir_register
+{
+   enum {
+      EIR_REG_UNDEF = 0,
+      EIR_REG_TEMP,
+      EIR_REG_UNIFORM,
+      EIR_REG_SAMPLER,
+   } type;
+
+   unsigned index;
+
+   /* dst only: */
+   unsigned writemask:4;
+   /* src only: */
+   unsigned swizzle:8;
+   unsigned abs:1;
+   unsigned neg:1;
+};
+
+struct eir_instruction
+{
+   struct eir_block *block;
+   struct list_head node;  /* entry in eir_block's instruction list */
+
+   /* Pre-register-allocation references to src/dst registers */
+   struct eir_register dst;
+   struct eir_register src[3];
+
+   struct gc_instr gc;  /* instruction being wrapped. */
+};
+
+struct eir_block
+{
+   struct eir *ir;
+   struct list_head node;  /* entry in eir's block list */
+   struct list_head instr_list;
+
+   unsigned num;
+
+   struct eir_block *successors[2];
+
+   /* per-pass extra block data */
+   void *data;
+};
+
+enum eir_uniform_contents
+{
+   EIR_UNIFORM_UNUSED,
+   EIR_UNIFORM_CONSTANT,
+   EIR_UNIFORM_IMAGE_WIDTH,
+   EIR_UNIFORM_IMAGE_HEIGHT,
+   EIR_UNIFORM_IMAGE_DEPTH,
+};
+
+static inline const char *
+eir_uniform_content(enum eir_uniform_contents content)
+{
+   switch(content) {
+   case EIR_UNIFORM_UNUSED:
+      return "unused";
+   case EIR_UNIFORM_CONSTANT:
+      return "constant";
+   case EIR_UNIFORM_IMAGE_WIDTH:
+      return "image width";
+   case EIR_UNIFORM_IMAGE_HEIGHT:
+      return "image height";
+   case EIR_UNIFORM_IMAGE_DEPTH:
+      return "image depth";
+   default:
+      unreachable("unhandled content type");
+      break;
+   }
+
+   return NULL;
+}
+
+struct eir_uniform_data
+{
+   enum eir_uniform_contents content;
+   uint32_t data;
+};
+
+struct eir
+{
+   struct list_head block_list;
+   unsigned blocks;
+
+   /* attributes/varyings: */
+   unsigned num_inputs;
+   struct {
+      unsigned slot;
+      unsigned reg;
+      unsigned ncomp;
+   } inputs[16];
+
+   /* varyings/outputs: */
+   unsigned num_outputs;
+   struct {
+      unsigned slot;
+      unsigned reg;
+      unsigned ncomp;
+   } outputs[16];
+
+   /* keep track of numer of allocated registers
+    * and the used components per register */
+   struct util_dynarray reg_alloc;
+
+   /* keep track of number of allocated uniforms */
+   struct util_dynarray uniform_alloc;
+   unsigned uniform_offset;
+};
+
+struct eir_info {
+	uint16_t sizedwords;
+};
+
+struct eir *
+eir_create(void);
+
+void
+eir_destroy(struct eir *ir);
+
+struct eir_block *
+eir_block_create(struct eir *ir);
+
+struct eir_instruction *
+eir_instruction_create(struct eir_block *block, enum gc_op opc);
+
+struct eir_register
+eir_temp_register(struct eir *ir, unsigned num_components);
+
+struct eir_register
+eir_uniform_register_vec4(struct eir *ir,
+                          const unsigned ncomp,
+                          const enum eir_uniform_contents *contents,
+                          const uint32_t *values);
+
+static inline struct eir_register
+eir_uniform_register(struct eir *ir, const enum eir_uniform_contents content, uint32_t value)
+{
+   const enum eir_uniform_contents contents[] = {
+      content
+   };
+
+   const uint32_t values[] = {
+      value
+   };
+
+   return eir_uniform_register_vec4(ir, 1, contents, values);
+}
+
+static inline struct eir_register
+eir_uniform_register_ui(struct eir *ir, uint32_t value)
+{
+   static const enum eir_uniform_contents contents[] = {
+      EIR_UNIFORM_CONSTANT
+   };
+
+   uint32_t values[] = {
+      value
+   };
+
+   return eir_uniform_register_vec4(ir, 1, contents, values);
+}
+
+static inline struct eir_register
+eir_uniform_register_f(struct eir *ir, float value)
+{
+   static const enum eir_uniform_contents contents[] = {
+      EIR_UNIFORM_CONSTANT
+   };
+
+   uint32_t values[] = {
+      fui(value)
+   };
+
+   return eir_uniform_register_vec4(ir, 1, contents, values);
+}
+
+static inline struct eir_register
+eir_uniform_register_vec4_ui(struct eir *ir, const unsigned ncomp, const uint32_t *values)
+{
+   static const enum eir_uniform_contents contents[] =
+   {
+      EIR_UNIFORM_CONSTANT,
+      EIR_UNIFORM_CONSTANT,
+      EIR_UNIFORM_CONSTANT,
+      EIR_UNIFORM_CONSTANT,
+   };
+
+   return eir_uniform_register_vec4(ir, ncomp, contents, values);
+}
+
+static inline struct eir_register
+eir_uniform_register_vec4_f(struct eir *ir, const unsigned ncomp, float *values)
+{
+   static const enum eir_uniform_contents contents[] =
+   {
+      EIR_UNIFORM_CONSTANT,
+      EIR_UNIFORM_CONSTANT,
+      EIR_UNIFORM_CONSTANT,
+      EIR_UNIFORM_CONSTANT,
+   };
+
+   uint32_t val[4];
+
+   for (unsigned i = 0; i < ncomp; i++)
+      val[i] = fui(values[i]);
+
+   return eir_uniform_register_vec4(ir, ncomp, contents, val);
+}
+
+void
+eir_link_blocks(struct eir_block *predecessor, struct eir_block *successor);
+
+static inline void
+eir_assign_input(struct eir *ir, unsigned idx, unsigned slot, unsigned ncomp)
+{
+   assert(ir);
+   assert(idx < ARRAY_SIZE(ir->inputs));
+
+   ir->inputs[idx].reg = idx;
+   ir->inputs[idx].slot = slot;
+   ir->inputs[idx].ncomp = ncomp;
+
+   ir->num_inputs = MAX2(ir->num_inputs, idx + 1);
+}
+
+static inline void
+eir_assign_output(struct eir *ir, unsigned idx, unsigned slot, unsigned ncomp)
+{
+   assert(ir);
+   assert(idx < ARRAY_SIZE(ir->outputs));
+
+   ir->outputs[idx].reg = idx;
+   ir->outputs[idx].slot = slot;
+   ir->outputs[idx].ncomp = ncomp;
+
+   ir->num_outputs = MAX2(ir->num_outputs, idx + 1);
+}
+
+void
+eir_calculate_live_intervals(struct eir *ir);
+
+int
+eir_temp_range_start(const struct eir* ir, unsigned n);
+
+int
+eir_temp_range_end(const struct eir* ir, unsigned n);
+
+uint32_t *
+eir_assemble(const struct eir *ir, struct eir_info *info);
+
+static inline struct eir_instruction *
+eir_SET(struct eir_block *block, struct eir_register *dst,
+        struct eir_register *src0, enum gc_cond condition,
+        struct eir_register *src1)
+{
+   struct eir_instruction *instr;
+
+   assert(gc_op_has_dst(GC_SET));
+   assert(gc_op_num_src(GC_SET) == 2);
+
+   instr = eir_instruction_create(block, GC_SET);
+   instr->gc.type = GC_OP_TYPE_ALU;
+   instr->gc.condition = condition;
+   instr->dst = *dst;
+   instr->src[0] = *src0;
+   instr->src[1] = *src1;
+
+   return instr;
+}
+
+static inline struct eir_instruction *
+eir_BRANCH(struct eir_block *block, struct eir_register *src0,
+           struct eir_register *src1)
+{
+   struct eir_instruction *instr;
+
+   assert(!gc_op_has_dst(GC_BRANCH));
+   assert(gc_op_num_src(GC_BRANCH) == 2);
+
+   instr = eir_instruction_create(block, GC_BRANCH);
+   instr->gc.type = GC_OP_TYPE_BRANCH;
+   instr->gc.branch.imm = ~0;
+   instr->src[0] = *src0;
+   instr->src[1] = *src1;
+
+   return instr;
+}
+
+static inline struct eir_instruction *
+eir_TEXKILL_IF(struct eir_block *block, struct eir_register *src0,
+               enum gc_cond condition, struct eir_register *src1)
+{
+   struct eir_instruction *instr;
+
+   assert(!gc_op_has_dst(GC_TEXKILL_IF));
+   assert(gc_op_num_src(GC_TEXKILL_IF) == 2);
+
+   instr = eir_instruction_create(block, GC_TEXKILL_IF);
+   instr->gc.type = GC_OP_TYPE_ALU;
+   instr->gc.condition = condition;
+   instr->src[0] = *src0;
+   instr->src[1] = *src1;
+
+   return instr;
+}
+
+#define ALU0(opc) \
+static inline struct eir_instruction * \
+eir_##opc(struct eir_block *block) \
+{ \
+   struct eir_instruction *instr; \
+   \
+   assert(!gc_op_has_dst(GC_##opc));\
+   assert(gc_op_num_src(GC_##opc) == 0);\
+   \
+   instr = eir_instruction_create(block, GC_##opc); \
+   instr->gc.type = GC_OP_TYPE_ALU; \
+   \
+   return instr; \
+}
+
+#define ALU1(opc) \
+static inline struct eir_instruction * \
+eir_##opc(struct eir_block *block, struct eir_register *dst, \
+          struct eir_register *src0) \
+{ \
+   struct eir_instruction *instr; \
+   \
+   assert(gc_op_has_dst(GC_##opc));\
+   assert(gc_op_num_src(GC_##opc) >= 1);\
+   \
+   instr = eir_instruction_create(block, GC_##opc); \
+   instr->gc.type = GC_OP_TYPE_ALU; \
+   instr->dst = *dst; \
+   instr->src[0] = *src0; \
+   \
+   return instr; \
+}
+
+#define ALU2(opc) \
+static inline struct eir_instruction * \
+eir_##opc(struct eir_block *block, struct eir_register *dst, \
+          struct eir_register *src0, struct eir_register *src1) \
+{ \
+   struct eir_instruction *instr; \
+   \
+   assert(gc_op_has_dst(GC_##opc));\
+   assert(gc_op_num_src(GC_##opc) == 2);\
+   \
+   instr = eir_instruction_create(block, GC_##opc); \
+   instr->gc.type = GC_OP_TYPE_ALU; \
+   instr->dst = *dst; \
+   instr->src[0] = *src0; \
+   instr->src[1] = *src1; \
+   \
+   return instr; \
+}
+
+#define ALU3(opc) \
+static inline struct eir_instruction * \
+eir_##opc(struct eir_block *block, struct eir_register *dst, \
+          struct eir_register *src0, struct eir_register *src1, \
+          struct eir_register *src2) \
+{ \
+   struct eir_instruction *instr; \
+   \
+   assert(gc_op_has_dst(GC_##opc));\
+   assert(gc_op_num_src(GC_##opc) == 3);\
+   \
+   instr = eir_instruction_create(block, GC_##opc); \
+   instr->gc.type = GC_OP_TYPE_ALU; \
+   instr->dst = *dst; \
+   instr->src[0] = *src0; \
+   instr->src[1] = *src1; \
+   instr->src[2] = *src2; \
+   \
+   return instr; \
+}
+
+#define TEX(opc) \
+static inline struct eir_instruction * \
+eir_##opc(struct eir_block *block, struct eir_register *dst, \
+          struct eir_register *sampler, struct eir_register *src) \
+{ \
+   struct eir_instruction *instr; \
+   \
+   assert(gc_op_has_dst(GC_##opc));\
+   assert(gc_op_num_src(GC_##opc) == 2); \
+   \
+   instr = eir_instruction_create(block, GC_##opc); \
+   instr->gc.type = GC_OP_TYPE_SAMPLER; \
+   instr->dst = *dst; \
+   instr->src[0] = *sampler; \
+   instr->src[1] = *src; \
+   \
+   return instr; \
+}
+
+ALU0(NOP);
+ALU0(TEXKILL);
+
+ALU1(MOV);
+ALU1(MOVAR);
+ALU1(RCP);
+ALU1(RSQ);
+ALU1(CEIL);
+ALU1(FLOOR);
+ALU1(FRC);
+ALU1(LOG);
+ALU1(SQRT);
+ALU1(SIN);
+ALU1(COS);
+ALU1(EXP);
+ALU1(DSX);
+ALU1(DSY);
+
+ALU2(ADD);
+ALU2(MUL);
+ALU2(DP2);
+ALU2(DP3);
+ALU2(DP4);
+
+ALU3(MAD);
+ALU3(SELECT);
+
+TEX(TEXLD);
+TEX(TEXLDB);
+TEX(TEXLDL);
+
+#define eir_for_each_block(block, ir)                                   \
+   list_for_each_entry(struct eir_block, block, &ir->block_list, node)
+
+#define eir_for_each_block_rev(block, ir)                               \
+   list_for_each_entry_rev(struct eir_block, block, &ir->block_list, node)
+
+/* Loop over the non-NULL members of the successors array. */
+#define eir_for_each_successor(succ, block)                             \
+   for (struct eir_block *succ = block->successors[0];                  \
+         succ != NULL;                                                  \
+         succ = (succ == block->successors[1] ? NULL :                  \
+               block->successors[1]))
+
+#define eir_for_each_inst(inst, block)                                  \
+   list_for_each_entry(struct eir_instruction, inst, &block->instr_list, node)
+
+#define eir_for_each_inst_safe(inst, block)                                  \
+   list_for_each_entry_safe(struct eir_instruction, inst, &block->instr_list, node)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // H_EIR
diff --git a/src/etnaviv/compiler/eir_uniform.c b/src/etnaviv/compiler/eir_uniform.c
new file mode 100644
index 00000000000..7f75215e480
--- /dev/null
+++ b/src/etnaviv/compiler/eir_uniform.c
@@ -0,0 +1,108 @@ 
+/*
+ * Copyright (c) 2018 Etnaviv Project
+ * Copyright (C) 2018 Zodiac Inflight Innovations
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Christian Gmeiner <christian.gmeiner@gmail.com>
+ */
+
+#include "eir.h"
+
+static inline void
+append_uniform(struct eir *ir, enum eir_uniform_contents content, uint32_t value)
+{
+   struct eir_uniform_data d = {
+      .content = content,
+      .data = value
+   };
+
+   util_dynarray_append(&ir->uniform_alloc, struct eir_uniform_data, d);
+}
+
+struct eir_register
+eir_uniform_register_vec4(struct eir *ir,
+                          const unsigned ncomp,
+                          const enum eir_uniform_contents *contents,
+                          const uint32_t *values)
+{
+   const unsigned size = util_dynarray_num_elements(&ir->uniform_alloc, struct eir_uniform_data);
+   unsigned idx, i;
+
+   /* is there already something useful to reuse? */
+   for (idx = 0; idx < size; idx++) {
+      const struct eir_uniform_data *data;
+
+      for (i = 0; i < ncomp; i++) {
+         data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, idx + i);
+
+         if (data->content == EIR_UNIFORM_UNUSED)
+            continue;
+
+         if (data->content != contents[i] || data->data != values[i])
+            break;
+      }
+
+		/* matched all components */
+		if (i == ncomp)
+			break;
+   }
+
+   /* do we need to update unused items? */
+   if (idx != size) {
+      struct eir_uniform_data *data;
+
+      for (i = 0; i < ncomp; i++) {
+         data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, idx + i);
+
+         data->content = contents[i];
+         data->data = values[i];
+      }
+   }
+
+	/* need to allocate new immediate */
+	if (idx == size) {
+      /* pad out current uniform vector - if needed */
+      if (size % 4)
+         for (i = size % 4; i < ncomp; i++)
+            append_uniform(ir, EIR_UNIFORM_UNUSED, 0);
+
+      for (i = 0; i < ncomp; i++)
+         append_uniform(ir, contents[i], values[i]);
+
+      idx = util_dynarray_num_elements(&ir->uniform_alloc, struct eir_uniform_data);
+      idx -= ncomp;
+   }
+
+   idx += ir->uniform_offset;
+
+   struct eir_register reg = {
+      .type = EIR_REG_UNIFORM,
+      .index = idx / 4,
+   };
+
+   if (ncomp == 4)
+      reg.swizzle = INST_SWIZ_IDENTITY;
+   else
+      reg.swizzle = INST_SWIZ_BROADCAST(idx & 3);
+
+   return reg;
+}
diff --git a/src/etnaviv/compiler/meson.build b/src/etnaviv/compiler/meson.build
new file mode 100644
index 00000000000..8affe6ebd48
--- /dev/null
+++ b/src/etnaviv/compiler/meson.build
@@ -0,0 +1,38 @@ 
+# Copyright (c) 2018 Etnaviv Project
+# Copyright (C) 2018 Zodiac Inflight Innovations
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sub license,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the
+# next paragraph) shall be included in all copies or substantial portions
+# of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+
+libetnaviv_compiler_files = files(
+  'eir.c',
+  'eir.h',
+  'eir_uniform.c',
+)
+
+libetnaviv_compiler = static_library(
+  ['etnaviv_compiler'],
+  libetnaviv_compiler_files,
+  include_directories : [inc_common, inc_etnaviv],
+  c_args : [c_vis_args, no_override_init_args],
+  dependencies : [dep_libdrm, dep_valgrind, idep_nir],
+  build_by_default : true,
+)
+
+subdir('tests')
diff --git a/src/etnaviv/compiler/tests/eir_assemble.cpp b/src/etnaviv/compiler/tests/eir_assemble.cpp
new file mode 100644
index 00000000000..63535908a32
--- /dev/null
+++ b/src/etnaviv/compiler/tests/eir_assemble.cpp
@@ -0,0 +1,114 @@ 
+/*
+ * Copyright (c) 2018 Etnaviv Project
+ * Copyright (C) 2018 Zodiac Inflight Innovations
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Christian Gmeiner <christian.gmeiner@gmail.com>
+ */
+
+#include <gtest/gtest.h>
+#include "etnaviv/compiler/eir.h"
+
+TEST (AssembleTest, NopAssembleDisassemble)
+{
+   struct eir *ir = eir_create();
+   struct eir_block *block = eir_block_create(ir);
+
+   eir_NOP(block);
+
+   struct eir_info info;
+   void *bin = eir_assemble(ir, &info);
+   ASSERT_TRUE(bin);
+
+   eir_destroy(ir);
+
+   struct gc_instr instr;
+   gc_unpack_instr((uint32_t* )bin, &instr);
+
+   ASSERT_EQ(instr.type, GC_OP_TYPE_ALU);
+   ASSERT_EQ(instr.opcode, GC_NOP);
+
+   ASSERT_EQ(info.sizedwords, 4);
+
+   free(bin);
+}
+
+TEST (AssembleTest, Swizzle)
+{
+   struct eir *ir = eir_create();
+   struct eir_block *block = eir_block_create(ir);
+
+   struct eir_register d = eir_temp_register(ir, 4);
+   struct eir_register s0 = eir_temp_register(ir, 4);
+   struct eir_register s1 = eir_temp_register(ir, 4);
+
+   eir_ADD(block, &d, &s0, &s1);
+
+   struct eir_info info;
+   void *bin = eir_assemble(ir, &info);
+   ASSERT_TRUE(bin);
+
+   eir_destroy(ir);
+
+   struct gc_instr instr;
+   gc_unpack_instr((uint32_t* )bin, &instr);
+
+   ASSERT_EQ(instr.type, GC_OP_TYPE_ALU);
+   ASSERT_EQ(instr.opcode, GC_ADD);
+   ASSERT_TRUE(instr.alu.src[0].use);
+   ASSERT_FALSE(instr.alu.src[1].use);
+   ASSERT_TRUE(instr.alu.src[2].use);
+   ASSERT_EQ(instr.alu.src[0].reg, 1);
+   ASSERT_EQ(instr.alu.src[2].reg, 2);
+   ASSERT_EQ(instr.dst.reg, 0);
+
+   free(bin);
+}
+
+TEST (AssembleTest, SwizzleReplicate)
+{
+   struct eir *ir = eir_create();
+   struct eir_block *block = eir_block_create(ir);
+
+   struct eir_register d = eir_temp_register(ir, 4);
+   struct eir_register s = eir_temp_register(ir, 4);
+   eir_DSX(block, &d, &s);
+
+   struct eir_info info;
+   void *bin = eir_assemble(ir, &info);
+   ASSERT_TRUE(bin);
+
+   eir_destroy(ir);
+
+   struct gc_instr instr;
+   gc_unpack_instr((uint32_t* )bin, &instr);
+
+   ASSERT_EQ(instr.type, GC_OP_TYPE_ALU);
+   ASSERT_EQ(instr.opcode, GC_DSX);
+   ASSERT_TRUE(instr.alu.src[0].use);
+   ASSERT_FALSE(instr.alu.src[1].use);
+   ASSERT_TRUE(instr.alu.src[2].use);
+   ASSERT_EQ(instr.alu.src[0].reg, 1);
+   ASSERT_EQ(instr.alu.src[2].reg, 1);
+
+   free(bin);
+}
diff --git a/src/etnaviv/compiler/tests/eir_uniform.cpp b/src/etnaviv/compiler/tests/eir_uniform.cpp
new file mode 100644
index 00000000000..867e51ab384
--- /dev/null
+++ b/src/etnaviv/compiler/tests/eir_uniform.cpp
@@ -0,0 +1,324 @@ 
+/*
+ * Copyright (c) 2018 Etnaviv Project
+ * Copyright (C) 2018 Zodiac Inflight Innovations
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Christian Gmeiner <christian.gmeiner@gmail.com>
+ */
+
+#include <gtest/gtest.h>
+#include "etnaviv/compiler/eir.h"
+
+TEST (UniformTest, Basic)
+{
+   struct eir *ir = eir_create();
+   struct eir_register u;
+   const struct eir_uniform_data *data;
+
+   u = eir_uniform_register_ui(ir, 1);
+
+   ASSERT_EQ(u.type, eir_register::EIR_REG_UNIFORM);
+   ASSERT_EQ(u.index, 0);
+   ASSERT_EQ(u.swizzle, INST_SWIZ_BROADCAST(0));
+
+   data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, 0);
+   ASSERT_EQ(data->content, EIR_UNIFORM_CONSTANT);
+   ASSERT_EQ(data->data, 1);
+
+   eir_destroy(ir);
+}
+
+TEST (UniformTest, ReuseUnused)
+{
+   struct eir *ir = eir_create();
+   struct eir_register u1, u2;
+
+   eir_uniform_register(ir, EIR_UNIFORM_UNUSED, 0);
+
+   ASSERT_EQ(util_dynarray_num_elements(&ir->uniform_alloc, struct eir_uniform_data), 1);
+
+   u1 = eir_uniform_register_ui(ir, 1);
+   u2 = eir_uniform_register_ui(ir, 1);
+
+   ASSERT_EQ(util_dynarray_num_elements(&ir->uniform_alloc, struct eir_uniform_data), 1);
+
+   ASSERT_EQ(u1.type, eir_register::EIR_REG_UNIFORM);
+   ASSERT_EQ(u1.index, 0);
+   ASSERT_EQ(u1.swizzle, INST_SWIZ_BROADCAST(0));
+
+   ASSERT_EQ(u2.type, eir_register::EIR_REG_UNIFORM);
+   ASSERT_EQ(u2.index, 0);
+   ASSERT_EQ(u2.swizzle, INST_SWIZ_BROADCAST(0));
+
+   eir_destroy(ir);
+}
+
+TEST (UniformTest, ReuseUnusedCausedByVec4)
+{
+   struct eir *ir = eir_create();
+   struct eir_register u1, u2, u3;
+
+   u1 = eir_uniform_register_ui(ir, 0);
+
+   ASSERT_EQ(util_dynarray_num_elements(&ir->uniform_alloc, struct eir_uniform_data), 1);
+
+   uint32_t v[] = {
+      10,
+      11,
+      12,
+      13,
+   };
+
+   u2 = eir_uniform_register_vec4_ui(ir, 4, v);
+
+   ASSERT_EQ(util_dynarray_num_elements(&ir->uniform_alloc, struct eir_uniform_data), 8);
+
+   u3 = eir_uniform_register_ui(ir, 1);
+
+   ASSERT_EQ(util_dynarray_num_elements(&ir->uniform_alloc, struct eir_uniform_data), 8);
+
+   ASSERT_EQ(u1.type, eir_register::EIR_REG_UNIFORM);
+   ASSERT_EQ(u1.index, 0);
+   ASSERT_EQ(u1.swizzle, INST_SWIZ_BROADCAST(0));
+
+   ASSERT_EQ(u2.type, eir_register::EIR_REG_UNIFORM);
+   ASSERT_EQ(u2.index, 1);
+   ASSERT_EQ(u2.swizzle, INST_SWIZ_IDENTITY);
+
+   ASSERT_EQ(u3.type, eir_register::EIR_REG_UNIFORM);
+   ASSERT_EQ(u3.index, 0);
+   ASSERT_EQ(u3.swizzle, INST_SWIZ_BROADCAST(1));
+
+   eir_destroy(ir);
+}
+
+TEST (UniformTest, EqualUniforms)
+{
+   struct eir *ir = eir_create();
+   struct eir_register u1, u2;
+
+   u1 = eir_uniform_register_ui(ir, 1);
+   u2 = eir_uniform_register_ui(ir, 1);
+
+   ASSERT_EQ(u1.type, eir_register::EIR_REG_UNIFORM);
+   ASSERT_EQ(u1.index, 0);
+   ASSERT_EQ(u1.swizzle, INST_SWIZ_BROADCAST(0));
+
+   ASSERT_EQ(u2.type, eir_register::EIR_REG_UNIFORM);
+   ASSERT_EQ(u2.index, 0);
+   ASSERT_EQ(u2.swizzle, INST_SWIZ_BROADCAST(0));
+
+   eir_destroy(ir);
+}
+
+TEST (UniformTest, MultipeSwizzles)
+{
+   struct eir *ir = eir_create();
+   struct eir_register u1, u2, u3, u4, u5;
+   const struct eir_uniform_data *data;
+
+   u1 = eir_uniform_register_ui(ir, 0);
+   u2 = eir_uniform_register_ui(ir, 1);
+   u3 = eir_uniform_register_ui(ir, 2);
+   u4 = eir_uniform_register_ui(ir, 3);
+   u5 = eir_uniform_register_ui(ir, 4);
+
+   ASSERT_EQ(u1.type, eir_register::EIR_REG_UNIFORM);
+   ASSERT_EQ(u1.index, 0);
+   ASSERT_EQ(u1.swizzle, INST_SWIZ_BROADCAST(0));
+
+   data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, 0);
+   ASSERT_EQ(data->content, EIR_UNIFORM_CONSTANT);
+   ASSERT_EQ(data->data, 0);
+
+
+   ASSERT_EQ(u2.type, eir_register::EIR_REG_UNIFORM);
+   ASSERT_EQ(u2.index, 0);
+   ASSERT_EQ(u2.swizzle, INST_SWIZ_BROADCAST(1));
+
+   data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, 1);
+   ASSERT_EQ(data->content, EIR_UNIFORM_CONSTANT);
+   ASSERT_EQ(data->data, 1);
+
+
+   ASSERT_EQ(u3.type, eir_register::EIR_REG_UNIFORM);
+   ASSERT_EQ(u3.index, 0);
+   ASSERT_EQ(u3.swizzle, INST_SWIZ_BROADCAST(2));
+
+   data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, 2);
+   ASSERT_EQ(data->content, EIR_UNIFORM_CONSTANT);
+   ASSERT_EQ(data->data, 2);
+
+   ASSERT_EQ(u4.type, eir_register::EIR_REG_UNIFORM);
+   ASSERT_EQ(u4.index, 0);
+   ASSERT_EQ(u4.swizzle, INST_SWIZ_BROADCAST(3));
+
+   data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, 3);
+   ASSERT_EQ(data->content, EIR_UNIFORM_CONSTANT);
+   ASSERT_EQ(data->data, 3);
+
+
+   ASSERT_EQ(u5.type, eir_register::EIR_REG_UNIFORM);
+   ASSERT_EQ(u5.index, 1);
+   ASSERT_EQ(u5.swizzle, INST_SWIZ_BROADCAST(0));
+
+   data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, 4);
+   ASSERT_EQ(data->content, EIR_UNIFORM_CONSTANT);
+   ASSERT_EQ(data->data, 4);
+
+   eir_destroy(ir);
+}
+
+TEST (UniformTest, BasicVec4)
+{
+   static const uint32_t values[4] = { 1, 2, 3, 4 };
+   struct eir *ir = eir_create();
+   struct eir_register u;
+   struct eir_uniform_data *data;
+
+   u = eir_uniform_register_vec4_ui(ir, 4, values);
+
+   ASSERT_EQ(u.type, eir_register::EIR_REG_UNIFORM);
+   ASSERT_EQ(u.index, 0);
+   ASSERT_EQ(u.swizzle, INST_SWIZ_IDENTITY);
+
+   data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, 0);
+   ASSERT_EQ(data->content, EIR_UNIFORM_CONSTANT);
+   ASSERT_EQ(data->data, 1);
+
+   data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, 1);
+   ASSERT_EQ(data->content, EIR_UNIFORM_CONSTANT);
+   ASSERT_EQ(data->data, 2);
+
+   data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, 2);
+   ASSERT_EQ(data->content, EIR_UNIFORM_CONSTANT);
+   ASSERT_EQ(data->data, 3);
+
+   data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, 3);
+   ASSERT_EQ(data->content, EIR_UNIFORM_CONSTANT);
+   ASSERT_EQ(data->data, 4);
+
+   eir_destroy(ir);
+}
+
+TEST (UniformTest, EqualUnfiormsVec4)
+{
+   static const uint32_t values[4] = { 1, 2, 3, 4 };
+   struct eir *ir = eir_create();
+   struct eir_register u1, u2;
+   struct eir_uniform_data *data;
+
+   u1 = eir_uniform_register_vec4_ui(ir, 4, values);
+   u2 = eir_uniform_register_vec4_ui(ir, 4, values);
+
+   ASSERT_EQ(u1.type, eir_register::EIR_REG_UNIFORM);
+   ASSERT_EQ(u1.index, 0);
+   ASSERT_EQ(u1.swizzle, INST_SWIZ_IDENTITY);
+
+   ASSERT_EQ(u2.type, eir_register::EIR_REG_UNIFORM);
+   ASSERT_EQ(u2.index, 0);
+   ASSERT_EQ(u2.swizzle, INST_SWIZ_IDENTITY);
+
+
+   data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, 0);
+   ASSERT_EQ(data->content, EIR_UNIFORM_CONSTANT);
+   ASSERT_EQ(data->data, 1);
+
+   data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, 1);
+   ASSERT_EQ(data->content, EIR_UNIFORM_CONSTANT);
+   ASSERT_EQ(data->data, 2);
+
+   data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, 2);
+   ASSERT_EQ(data->content, EIR_UNIFORM_CONSTANT);
+   ASSERT_EQ(data->data, 3);
+
+   data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, 3);
+   ASSERT_EQ(data->content, EIR_UNIFORM_CONSTANT);
+   ASSERT_EQ(data->data, 4);
+
+   eir_destroy(ir);
+}
+
+TEST (UniformTest, ncomp1)
+{
+   struct eir *ir = eir_create();
+
+   static const eir_uniform_contents contents[4] = {
+      EIR_UNIFORM_CONSTANT,
+      EIR_UNIFORM_UNUSED,
+      EIR_UNIFORM_CONSTANT,
+      EIR_UNIFORM_CONSTANT,
+   };
+
+   static const uint32_t values[4] = {
+      1,
+      2,
+      3,
+      4,
+   };
+
+   eir_uniform_register_vec4(ir, 4, contents, values);
+
+   struct eir_register u = eir_uniform_register_ui(ir, 2);
+
+   ASSERT_EQ(u.type, eir_register::EIR_REG_UNIFORM);
+   ASSERT_EQ(u.index, 0);
+   ASSERT_EQ(u.swizzle, INST_SWIZ_BROADCAST(1));
+}
+
+TEST (UniformTest, ncomp2)
+{
+   struct eir *ir = eir_create();
+
+   static const eir_uniform_contents contents[] = {
+      EIR_UNIFORM_CONSTANT,
+      EIR_UNIFORM_UNUSED,
+      EIR_UNIFORM_UNUSED,
+      EIR_UNIFORM_CONSTANT,
+   };
+
+   static const uint32_t values[] = {
+      1,
+      2,
+      3,
+      4,
+   };
+
+   eir_uniform_register_vec4(ir, 4, contents, values);
+
+
+   static const eir_uniform_contents c[] = {
+      EIR_UNIFORM_CONSTANT,
+      EIR_UNIFORM_CONSTANT,
+   };
+
+   static const uint32_t v[] = {
+      10,
+      10,
+   };
+
+   struct eir_register u = eir_uniform_register_vec4(ir, 2, c, v);
+
+   ASSERT_EQ(u.type, eir_register::EIR_REG_UNIFORM);
+   ASSERT_EQ(u.index, 0);
+   ASSERT_EQ(u.swizzle, INST_SWIZ_BROADCAST(1));
+}
diff --git a/src/etnaviv/compiler/tests/meson.build b/src/etnaviv/compiler/tests/meson.build
new file mode 100644
index 00000000000..c7506f04ed5
--- /dev/null
+++ b/src/etnaviv/compiler/tests/meson.build
@@ -0,0 +1,44 @@ 
+# Copyright (c) 2018 Etnaviv Project
+# Copyright (C) 2018 Zodiac Inflight Innovations
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sub license,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the
+# next paragraph) shall be included in all copies or substantial portions
+# of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+
+test(
+  'eir_assemble',
+  executable(
+    'eir_assemble', 'eir_assemble.cpp',
+    cpp_args : [cpp_vis_args, cpp_msvc_compat_args],
+    link_with: [libetnaviv_gc, libetnaviv_compiler, libmesa_util],
+    include_directories: [inc_common, inc_etnaviv],
+    dependencies : [dep_clock, dep_thread, idep_gtest],
+  )
+)
+
+test(
+  'eir_uniform',
+  executable(
+    'eir_uniform', 'eir_uniform.cpp',
+    cpp_args : [cpp_vis_args, cpp_msvc_compat_args],
+    link_with: [libetnaviv_gc, libetnaviv_compiler, libmesa_util],
+    include_directories: [inc_common, inc_etnaviv],
+    dependencies : [dep_clock, dep_thread, idep_gtest],
+  )
+)
+
diff --git a/src/etnaviv/meson.build b/src/etnaviv/meson.build
index a706feafe86..e2a6408d7c3 100644
--- a/src/etnaviv/meson.build
+++ b/src/etnaviv/meson.build
@@ -23,3 +23,4 @@ 
 inc_etnaviv = include_directories('.')
 
 subdir('gc')
+subdir('compiler')