mesa: fix a GLSL array indexing codegen bug
authorBrian Paul <brian.paul@tungstengraphics.com>
Wed, 5 Nov 2008 21:03:15 +0000 (14:03 -0700)
committerBrian Paul <brian.paul@tungstengraphics.com>
Wed, 5 Nov 2008 21:03:15 +0000 (14:03 -0700)
Expressions like array[i] + array[j] didn't work properly before.

src/mesa/shader/slang/slang_codegen.c
src/mesa/shader/slang/slang_emit.c

index e7b2bad8c2493af856d232f78a80c3e19de0f3e1..d83e3b01e6b3268ae0a307c7ce62c7449ef15cae 100644 (file)
@@ -3253,7 +3253,7 @@ _slang_gen_array_element(slang_assemble_ctx * A, slang_operation *oper)
       index = _slang_gen_operation(A, &oper->children[1]);
       if (array && index) {
          /* bounds check */
-         GLint constIndex = 0;
+         GLint constIndex = -1;
          if (index->Opcode == IR_FLOAT) {
             constIndex = (int) index->Value[0];
             if (constIndex < 0 || constIndex >= arrayLen) {
index 010b55827f6d2be2311d22f3f9c266040137db54..672ec4bd6067790594694f54538cf049e25562fb 100644 (file)
@@ -330,6 +330,17 @@ constant_to_src_reg(struct prog_src_register *src, GLfloat val,
 }
 
 
+static void
+address_to_dst_reg(struct prog_dst_register *dst, GLuint index)
+{
+   assert(index == 0); /* only one address reg at this time */
+   dst->File = PROGRAM_ADDRESS;
+   dst->Index = index;
+   dst->WriteMask = WRITEMASK_X;
+}
+
+
+
 /**
  * Add new instruction at end of given program.
  * \param prog  the program to append instruction onto
@@ -614,6 +625,7 @@ emit_arith(slang_emit_info *emitInfo, slang_ir_node *n)
 
    /* result storage */
    alloc_node_storage(emitInfo, n, -1);
+
    assert(n->Store->Index >= 0);
    if (n->Store->Size == 2)
       n->Writemask = WRITEMASK_XY;
@@ -1545,6 +1557,60 @@ emit_swizzle(slang_emit_info *emitInfo, slang_ir_node *n)
 }
 
 
+/**
+ * Move a block registers from src to dst (or move a single register).
+ * \param size  size of block, in floats (<=4 means one register)
+ */
+static struct prog_instruction *
+move_block(slang_emit_info *emitInfo,
+           GLuint size, GLboolean relAddr,
+           const slang_ir_storage *dst,
+           const slang_ir_storage *src)
+{
+   struct prog_instruction *inst;
+
+   if (size > 4) {
+      /* move matrix/struct etc (block of registers) */
+      slang_ir_storage dstStore = *dst;
+      slang_ir_storage srcStore = *src;
+      //GLint size = srcStore.Size;
+      /*ASSERT(n->Children[0]->Writemask == WRITEMASK_XYZW);
+      ASSERT(n->Children[1]->Store->Swizzle == SWIZZLE_NOOP);
+      */
+      dstStore.Size = 4;
+      srcStore.Size = 4;
+      while (size >= 4) {
+         inst = new_instruction(emitInfo, OPCODE_MOV);
+         inst->Comment = _mesa_strdup("IR_COPY block");
+         storage_to_dst_reg(&inst->DstReg, &dstStore, WRITEMASK_XYZW);
+         storage_to_src_reg(&inst->SrcReg[0], &srcStore);
+         inst->SrcReg[0].RelAddr = relAddr;
+         srcStore.Index++;
+         dstStore.Index++;
+         size -= 4;
+      }
+   }
+   else {
+      /* single register move */
+      GLuint writemask;
+      if (size == 1) {
+         GLuint comp = GET_SWZ(src->Swizzle, 0);
+         assert(comp < 4);
+         writemask = WRITEMASK_X << comp;
+      }
+      else {
+         writemask = WRITEMASK_XYZW;
+      }
+      inst = new_instruction(emitInfo, OPCODE_MOV);
+      storage_to_dst_reg(&inst->DstReg, dst, writemask);
+      storage_to_src_reg(&inst->SrcReg[0], src);
+      inst->SrcReg[0].RelAddr = relAddr;
+   }
+   return inst;
+}
+
+
+
 /**
  * Dereference array element.  Just resolve storage for the array
  * element represented by this node.
@@ -1591,16 +1657,43 @@ emit_array_element(slang_emit_info *emitInfo, slang_ir_node *n)
       /* do codegen for array index expression */
       emit(emitInfo, n->Children[1]);
 
-      inst = new_instruction(emitInfo, OPCODE_ARL);
+      /* allocate temp storage for the array element */
+      assert(n->Store->Index < 0);
+      n->Store->File = PROGRAM_TEMPORARY;
+      n->Store->Parent = NULL;
+      alloc_node_storage(emitInfo, n, -1);
 
-      storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
-      storage_to_src_reg(&inst->SrcReg[0], n->Children[1]->Store);
+      if (n->Store->Size > 4) {
+         /* need to multiply the index by the element size */
+         GLint elemSize = (n->Store->Size + 3) / 4;
+         slang_ir_storage indexTemp;
+
+         /* allocate 1 float indexTemp */
+         alloc_local_temp(emitInfo, &indexTemp, 1);
+
+         /* MUL temp, index, elemSize */
+         inst = new_instruction(emitInfo, OPCODE_MUL);
+         storage_to_dst_reg(&inst->DstReg, &indexTemp, WRITEMASK_X);
+         storage_to_src_reg(&inst->SrcReg[0], n->Children[1]->Store);
+         constant_to_src_reg(&inst->SrcReg[1], elemSize, emitInfo);
+
+         /* load ADDR[0].X = temp */
+         inst = new_instruction(emitInfo, OPCODE_ARL);
+         storage_to_src_reg(&inst->SrcReg[0], &indexTemp);
+         address_to_dst_reg(&inst->DstReg, 0);
 
-      inst->DstReg.File = PROGRAM_ADDRESS;
-      inst->DstReg.Index = 0; /* always address register [0] */
-      inst->Comment = _mesa_strdup("ARL ADDR");
+         _slang_free_temp(emitInfo->vt, &indexTemp);
+      }
+      else {
+         /* simply load address reg w/ array index */
+         inst = new_instruction(emitInfo, OPCODE_ARL);
+         storage_to_src_reg(&inst->SrcReg[0], n->Children[1]->Store);
+         address_to_dst_reg(&inst->DstReg, 0);
+      }
 
-      n->Store->RelAddr = GL_TRUE;
+      /* copy from array element to temp storage */
+      move_block(emitInfo, n->Store->Size, GL_TRUE,
+                 n->Store, n->Children[0]->Store);
    }
 
    /* if array element size is one, make sure we only access X */