mesa: rework GLSL array code generation
authorBrian Paul <brian.paul@tungstengraphics.com>
Wed, 19 Nov 2008 21:12:25 +0000 (14:12 -0700)
committerBrian Paul <brianp@vmware.com>
Tue, 6 Jan 2009 15:49:40 +0000 (08:49 -0700)
We now express arrays in terms of indirect addressing.  For example:
  dst = a[i];
becomes:
  MOV dst, TEMP[1 + TEMP[2].y];
At instruction-emit time indirect addressing is converted into ARL/
ADDR-relative form:
  ARL ADDR.x, TEMP[2].y;
  MOV dst, TEMP[1 + ADDR.x];
This fixes a number of array-related issues.  Arrays of arrays and complex
array/struct nesting works now.
There may be some regressions, but more work is coming.

(cherry picked from commit ae0ff8097b85d3537a7be1674d55a44a9bd6018e)

src/mesa/shader/slang/slang_codegen.c
src/mesa/shader/slang/slang_emit.c
src/mesa/shader/slang/slang_ir.c
src/mesa/shader/slang/slang_ir.h
src/mesa/shader/slang/slang_vartable.h

index d93ef8f..c0bb008 100644 (file)
@@ -3113,7 +3113,7 @@ _slang_gen_struct_field(slang_assemble_ctx * A, slang_operation *oper)
       /* oper->a_id is the field name */
       slang_ir_node *base, *n;
       slang_typeinfo field_ti;
-      GLint fieldSize, fieldOffset = -1, swz;
+      GLint fieldSize, fieldOffset = -1;
 
       /* type of field */
       slang_typeinfo_construct(&field_ti);
@@ -3146,22 +3146,12 @@ _slang_gen_struct_field(slang_assemble_ctx * A, slang_operation *oper)
       if (!n)
          return NULL;
 
-
-      /* setup the storage info for this node */
-      swz = fieldOffset % 4;
-
       n->Field = (char *) oper->a_id;
-      n->Store = _slang_new_ir_storage_relative(fieldOffset / 4,
-                                                fieldSize,
-                                                base->Store);
-      if (fieldSize == 1)
-         n->Store->Swizzle = MAKE_SWIZZLE4(swz, swz, swz, swz);
-      else if (fieldSize == 2)
-         n->Store->Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y,
-                                           SWIZZLE_NIL, SWIZZLE_NIL);
-      else if (fieldSize == 3)
-         n->Store->Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y,
-                                           SWIZZLE_Z, SWIZZLE_NIL);
+
+      /* Store the field's offset in storage->Index */
+      n->Store = _slang_new_ir_storage(base->Store->File,
+                                       fieldOffset,
+                                       fieldSize);
 
       return n;
    }
@@ -3254,12 +3244,12 @@ _slang_gen_array_element(slang_assemble_ctx * A, slang_operation *oper)
          }
 
          elem = new_node2(IR_ELEMENT, array, index);
-         elem->Store = _slang_new_ir_storage_relative(constIndex,
-                                                      elemSize,
-                                                      array->Store);
 
-         assert(elem->Store->Parent);
-         /* XXX try to do some array bounds checking here */
+         /* The storage info here will be updated during code emit */
+         elem->Store = _slang_new_ir_storage(array->Store->File,
+                                             array->Store->Index,
+                                             elemSize);
+
          return elem;
       }
       else {
index 665b288..62cdd00 100644 (file)
@@ -261,13 +261,16 @@ fix_swizzle(GLuint swizzle)
 static void
 storage_to_dst_reg(struct prog_dst_register *dst, const slang_ir_storage *st)
 {
+   const GLboolean relAddr = st->RelAddr;
    const GLint size = st->Size;
    GLint index = st->Index;
    GLuint swizzle = st->Swizzle;
 
+   assert(index >= 0);
    /* if this is storage relative to some parent storage, walk up the tree */
    while (st->Parent) {
       st = st->Parent;
+      assert(st->Index >= 0);
       index += st->Index;
       swizzle = _slang_swizzle_swizzle(st->Swizzle, swizzle);
    }
@@ -304,6 +307,8 @@ storage_to_dst_reg(struct prog_dst_register *dst, const slang_ir_storage *st)
       }
       dst->WriteMask = writemask;
    }
+
+   dst->RelAddr = relAddr;
 }
 
 
@@ -318,8 +323,10 @@ storage_to_src_reg(struct prog_src_register *src, const slang_ir_storage *st)
    GLuint swizzle = st->Swizzle;
 
    /* if this is storage relative to some parent storage, walk up the tree */
+   assert(index >= 0);
    while (st->Parent) {
       st = st->Parent;
+      assert(st->Index >= 0);
       index += st->Index;
       swizzle = _slang_swizzle_swizzle(fix_swizzle(st->Swizzle), swizzle);
    }
@@ -413,19 +420,131 @@ new_instruction(slang_emit_info *emitInfo, gl_inst_opcode opcode)
 }
 
 
+static struct prog_instruction *
+emit_arl_load(slang_emit_info *emitInfo,
+              enum register_file file, GLint index, GLuint swizzle)
+{
+   struct prog_instruction *inst = new_instruction(emitInfo, OPCODE_ARL);
+   inst->SrcReg[0].File = file;
+   inst->SrcReg[0].Index = index;
+   inst->SrcReg[0].Swizzle = swizzle;
+   inst->DstReg.File = PROGRAM_ADDRESS;
+   inst->DstReg.Index = 0;
+   inst->DstReg.WriteMask = WRITEMASK_X;
+   return inst;
+}
+
+
 /**
  * Emit a new instruction with given opcode, operands.
+ * At this point the instruction may have multiple indirect register
+ * loads/stores.  We convert those into ARL loads and address-relative
+ * operands.  See comments inside.
+ * At some point in the future we could directly emit indirectly addressed
+ * registers in Mesa GPU instructions.
  */
 static struct prog_instruction *
 emit_instruction(slang_emit_info *emitInfo,
                  gl_inst_opcode opcode,
                  const slang_ir_storage *dst,
+                 const slang_ir_storage *src0,
                  const slang_ir_storage *src1,
-                 const slang_ir_storage *src2,
-                 const slang_ir_storage *src3)
+                 const slang_ir_storage *src2)
 {
    struct prog_instruction *inst;
+   GLuint numIndirect = 0;
+   const slang_ir_storage *src[3];
+   slang_ir_storage newSrc[3], newDst;
+   GLuint i;
+   GLboolean isTemp[3];
+
+   isTemp[0] = isTemp[1] = isTemp[2] = GL_FALSE;
+
+   src[0] = src0;
+   src[1] = src1;
+   src[2] = src2;
+
+   /* count up how many operands are indirect loads */
+   for (i = 0; i < 3; i++) {
+      if (src[i] && src[i]->IsIndirect)
+         numIndirect++;
+   }
+   if (dst && dst->IsIndirect)
+      numIndirect++;
+
+   /* Take special steps for indirect register loads.
+    * If we had multiple address registers this would be simpler.
+    * For example, this GLSL code:
+    *    x[i] = y[j] + z[k];
+    * would translate into something like:
+    *    ARL ADDR.x, i;
+    *    ARL ADDR.y, j;
+    *    ARL ADDR.z, k;
+    *    ADD TEMP[ADDR.x+5], TEMP[ADDR.y+9], TEMP[ADDR.z+4];
+    * But since we currently only have one address register we have to do this:
+    *    ARL ADDR.x, i;
+    *    MOV t1, TEMP[ADDR.x+9];
+    *    ARL ADDR.x, j;
+    *    MOV t2, TEMP[ADDR.x+4];
+    *    ARL ADDR.x, k;
+    *    ADD TEMP[ADDR.x+5], t1, t2;
+    * The code here figures this out...
+    */
+   if (numIndirect > 0) {
+      for (i = 0; i < 3; i++) {
+         if (src[i] && src[i]->IsIndirect) {
+            /* load the ARL register with the indirect register */
+            emit_arl_load(emitInfo,
+                          src[i]->IndirectFile,
+                          src[i]->IndirectIndex,
+                          src[i]->IndirectSwizzle);
+
+            if (numIndirect > 1) {
+               /* Need to load src[i] into a temporary register */
+               slang_ir_storage srcRelAddr;
+               alloc_local_temp(emitInfo, &newSrc[i], src[i]->Size);
+               isTemp[i] = GL_TRUE;
+
+               /* set RelAddr flag on src register */
+               srcRelAddr = *src[i];
+               srcRelAddr.RelAddr = GL_TRUE;
+               srcRelAddr.IsIndirect = GL_FALSE; /* not really needed */
+
+               /* MOV newSrc, srcRelAddr; */
+               inst = emit_instruction(emitInfo,
+                                       OPCODE_MOV,
+                                       &newSrc[i],
+                                       &srcRelAddr,
+                                       NULL,
+                                       NULL);
+
+               src[i] = &newSrc[i];
+            }
+            else {
+               /* just rewrite the src[i] storage to be ARL-relative */
+               newSrc[i] = *src[i];
+               newSrc[i].RelAddr = GL_TRUE;
+               newSrc[i].IsIndirect = GL_FALSE; /* not really needed */
+               src[i] = &newSrc[i];
+            }
+         }
+      }
+   }
+
+   /* Take special steps for indirect dest register write */
+   if (dst && dst->IsIndirect) {
+      /* load the ARL register with the indirect register */
+      emit_arl_load(emitInfo,
+                    dst->IndirectFile,
+                    dst->IndirectIndex,
+                    dst->IndirectSwizzle);
+      newDst = *dst;
+      newDst.RelAddr = GL_TRUE;
+      newDst.IsIndirect = GL_FALSE;
+      dst = &newDst;
+   }
 
+   /* OK, emit the instruction and its dst, src regs */
    inst = new_instruction(emitInfo, opcode);
    if (!inst)
       return NULL;
@@ -433,33 +552,17 @@ emit_instruction(slang_emit_info *emitInfo,
    if (dst)
       storage_to_dst_reg(&inst->DstReg, dst);
 
-   if (src1)
-      storage_to_src_reg(&inst->SrcReg[0], src1);
-   if (src2)
-      storage_to_src_reg(&inst->SrcReg[1], src2);
-   if (src3)
-      storage_to_src_reg(&inst->SrcReg[2], src3);   
-
-   return inst;
-}
-
+   for (i = 0; i < 3; i++) {
+      if (src[i])
+         storage_to_src_reg(&inst->SrcReg[i], src[i]);
+   }
 
-/**
- * Emit an ARL instruction.
- */
-static struct prog_instruction *
-emit_arl_instruction(slang_emit_info *emitInfo,
-                     GLint addrReg,
-                     const slang_ir_storage *src)
-{
-   struct prog_instruction *inst;
+   /* Free any temp registers that we allocated above */
+   for (i = 0; i < 3; i++) {
+      if (isTemp[i])
+         _slang_free_temp(emitInfo->vt, &newSrc[i]);
+   }
 
-   assert(addrReg == 0); /* only one addr reg at this time */
-   inst = new_instruction(emitInfo, OPCODE_ARL);
-   storage_to_src_reg(&inst->SrcReg[0], src);
-   inst->DstReg.File = PROGRAM_ADDRESS;
-   inst->DstReg.Index = addrReg;
-   inst->DstReg.WriteMask = WRITEMASK_X;
    return inst;
 }
 
@@ -1217,7 +1320,8 @@ emit_copy(slang_emit_info *emitInfo, slang_ir_node *n)
    if (inst &&
        _slang_is_temp(emitInfo->vt, n->Children[1]->Store) &&
        (inst->DstReg.File == n->Children[1]->Store->File) &&
-       (inst->DstReg.Index == n->Children[1]->Store->Index)) {
+       (inst->DstReg.Index == n->Children[1]->Store->Index) &&
+       !n->Children[0]->Store->IsIndirect) {
       /* Peephole optimization:
        * The Right-Hand-Side has its results in a temporary place.
        * Modify the RHS (and the prev instruction) to store its results
@@ -1675,80 +1779,38 @@ emit_swizzle(slang_emit_info *emitInfo, slang_ir_node *n)
 
    inst = emit(emitInfo, n->Children[0]);
 
-   /* setup storage info, if needed */
-   if (!n->Store->Parent)
-      n->Store->Parent = n->Children[0]->Store;
-
+#if 0
    assert(n->Store->Parent);
-
+   /* Apply this node's swizzle to parent's storage */
+   GLuint swizzle = n->Store->Swizzle;
+   _slang_copy_ir_storage(n->Store, n->Store->Parent);
+   n->Store->Swizzle = _slang_swizzle_swizzle(n->Store->Swizzle, swizzle);
+   assert(!n->Store->Parent);
+#endif
    return inst;
 }
 
 
 /**
- * Move a block registers from src to dst (or move a single register).
- * \param size  size of block, in floats (<=4 means one register)
+ * Dereference array element:  element == array[index]
+ * This basically involves emitting code for computing the array index
+ * and updating the node/element's storage info.
  */
 static struct prog_instruction *
-move_block(slang_emit_info *emitInfo,
-           GLuint size, GLboolean relAddr,
-           const slang_ir_storage *dst,
-           const slang_ir_storage *src)
+emit_array_element(slang_emit_info *emitInfo, slang_ir_node *n)
 {
+   slang_ir_storage *arrayStore, *indexStore;
+   const int elemSize = n->Store->Size;           /* number of floats */
+   const GLint elemSizeVec = (elemSize + 3) / 4;  /* number of vec4 */
    struct prog_instruction *inst;
 
-   if (size > 4) {
-      /* move matrix/struct etc (block of registers) */
-      slang_ir_storage dstStore = *dst;
-      slang_ir_storage srcStore = *src;
-
-      dstStore.Size = 4;
-      srcStore.Size = 4;
-      while (size >= 4) {
-         inst = emit_instruction(emitInfo, OPCODE_MOV,
-                                 &dstStore,
-                                 &srcStore,
-                                 NULL,
-                                 NULL);
-         inst->SrcReg[0].RelAddr = relAddr;
-         inst_comment(inst, "IR_COPY block");
-         srcStore.Index++;
-         dstStore.Index++;
-         size -= 4;
-      }
-   }
-   else {
-      /* single register move */
-      inst = emit_instruction(emitInfo,
-                              OPCODE_MOV,
-                              dst,
-                              src,
-                              NULL,
-                              NULL);
-      inst->SrcReg[0].RelAddr = relAddr;
-   }
-   return inst;
-}
-
-
-
-/**
- * Dereference array element.  Just resolve storage for the array
- * element represented by this node.
- * This is typically where Indirect addressing comes into play.
- * See comments on struct slang_ir_storage.
- */
-static struct prog_instruction *
-emit_array_element(slang_emit_info *emitInfo, slang_ir_node *n)
-{
    assert(n->Opcode == IR_ELEMENT);
-   assert(n->Store);
-   assert(n->Store->File == PROGRAM_UNDEFINED);
-   assert(n->Store->Parent);
-   assert(n->Store->Size > 0);
+   assert(elemSize > 0);
 
+   /* special case for built-in state variables, like light state */
    {
       slang_ir_storage *root = n->Store;
+      assert(!root->Parent);
       while (root->Parent)
          root = root->Parent;
 
@@ -1759,69 +1821,98 @@ emit_array_element(slang_emit_info *emitInfo, slang_ir_node *n)
       }
    }
 
-   /* do codegen for array */
+   /* do codegen for array itself */
    emit(emitInfo, n->Children[0]);
+   arrayStore = n->Children[0]->Store;
+
+   /* The initial array element storage is the array's storage,
+    * then modified below.
+    */
+   _slang_copy_ir_storage(n->Store, arrayStore);
+
 
    if (n->Children[1]->Opcode == IR_FLOAT) {
-      /* Constant array index.
-       * Set Store's index to be the offset of the array element in
-       * the register file.
-       */
+      /* Constant array index */
       const GLint element = (GLint) n->Children[1]->Value[0];
-      const GLint sz = (n->Store->Size + 3) / 4; /* size in slots/registers */
 
-      n->Store->Index = sz * element;
-      assert(n->Store->Parent);
+      /* this element's storage is the array's storage, plus constant offset */
+      n->Store->Index += elemSizeVec * element;
    }
    else {
       /* Variable array index */
-      struct prog_instruction *inst;
 
       /* do codegen for array index expression */
       emit(emitInfo, n->Children[1]);
+      indexStore = n->Children[1]->Store;
+
+      if (indexStore->IsIndirect) {
+         /* need to put the array index into a temporary since we can't
+          * directly support a[b[i]] constructs.
+          */
+
 
-      /* 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);
+         /*indexStore = tempstore();*/
+      }
 
-      if (n->Store->Size > 4) {
-         /* need to multiply the index by the element size */
-         const GLint elemSize = (n->Store->Size + 3) / 4;
-         slang_ir_storage indexTemp, elemSizeStore;
 
-         /* constant containing the element size */
-         constant_to_storage(emitInfo, (float) elemSize, &elemSizeStore);
+      if (elemSize > 4) {
+         /* need to multiply array index by array element size */
+         struct prog_instruction *inst;
+         slang_ir_storage *indexTemp;
+         slang_ir_storage elemSizeStore;
 
          /* allocate 1 float indexTemp */
-         alloc_local_temp(emitInfo, &indexTemp, 1);
+         indexTemp = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, 1);
+         _slang_alloc_temp(emitInfo->vt, indexTemp);
+
+         /* allocate a constant containing the element size */
+         constant_to_storage(emitInfo, (float) elemSizeVec, &elemSizeStore);
 
-         /* MUL temp, index, elemSize */
-         inst = emit_instruction(emitInfo, OPCODE_MUL,
-                                 &indexTemp, /* dest */
-                                 n->Children[1]->Store, /* the index */
+         /* multiply array index by element size */
+         inst = emit_instruction(emitInfo,
+                                 OPCODE_MUL,
+                                 indexTemp, /* dest */
+                                 indexStore, /* the index */
                                  &elemSizeStore,
                                  NULL);
 
-         /* load ADDR[0].X = temp */
-         inst = emit_arl_instruction(emitInfo, 0, &indexTemp);
-
-         _slang_free_temp(emitInfo->vt, &indexTemp);
+         indexStore = indexTemp;
       }
-      else {
-         /* simply load address reg w/ array index */
-         inst = emit_arl_instruction(emitInfo, 0, n->Children[1]->Store);
+
+      if (arrayStore->IsIndirect) {
+         /* ex: in a[i][j], a[i] (the arrayStore) is indirect */
+         /* Need to add indexStore to arrayStore->Indirect store */
+         slang_ir_storage indirectArray;
+         slang_ir_storage *indexTemp;
+
+         _slang_init_ir_storage(&indirectArray,
+                                arrayStore->IndirectFile,
+                                arrayStore->IndirectIndex,
+                                1,
+                                arrayStore->IndirectSwizzle);
+
+         /* allocate 1 float indexTemp */
+         indexTemp = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, 1);
+         _slang_alloc_temp(emitInfo->vt, indexTemp);
+
+         inst = emit_instruction(emitInfo,
+                                 OPCODE_ADD,
+                                 indexTemp,      /* dest */
+                                 indexStore,     /* the index */
+                                 &indirectArray, /* indirect array base */
+                                 NULL);
+
+         indexStore = indexTemp;
       }
 
-      /* copy from array element to temp storage */
-      move_block(emitInfo, n->Store->Size, GL_TRUE,
-                 n->Store, n->Children[0]->Store);
+      /* update the array element storage info */
+      n->Store->IsIndirect = GL_TRUE;
+      n->Store->IndirectFile = indexStore->File;
+      n->Store->IndirectIndex = indexStore->Index;
+      n->Store->IndirectSwizzle = indexStore->Swizzle;
    }
 
-   /* if array element size is one, make sure we only access X */
-   if (n->Store->Size == 1)
-      n->Store->Swizzle = SWIZZLE_XXXX;
+   n->Store->Size = elemSize;
 
    return NULL; /* no instruction */
 }
@@ -1834,9 +1925,11 @@ static struct prog_instruction *
 emit_struct_field(slang_emit_info *emitInfo, slang_ir_node *n)
 {
    slang_ir_storage *root = n->Store;
+   GLint fieldOffset, fieldSize;
 
    assert(n->Opcode == IR_FIELD);
 
+   assert(!root->Parent);
    while (root->Parent)
       root = root->Parent;
 
@@ -1852,12 +1945,45 @@ emit_struct_field(slang_emit_info *emitInfo, slang_ir_node *n)
          slang_info_log_error(emitInfo->log, "Error parsing state variable");
          return NULL;
       }
+      return NULL;
    }
    else {
       /* do codegen for struct */
       emit(emitInfo, n->Children[0]);
+      assert(n->Children[0]->Store->Index >= 0);
    }
 
+   fieldOffset = n->Store->Index;
+   fieldSize = n->Store->Size;
+
+   _slang_copy_ir_storage(n->Store, n->Children[0]->Store);
+
+   n->Store->Index = n->Children[0]->Store->Index + fieldOffset / 4;
+   /* XXX test this:
+   n->Store->Index += fieldOffset / 4;
+   */
+
+   switch (fieldSize) {
+   case 1:
+      {
+         GLint swz = fieldOffset % 4;
+         n->Store->Swizzle = MAKE_SWIZZLE4(swz, swz, swz, swz);
+      }
+      break;
+   case 2:
+      n->Store->Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y,
+                                        SWIZZLE_NIL, SWIZZLE_NIL);
+      break;
+   case 3:
+      n->Store->Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y,
+                                        SWIZZLE_Z, SWIZZLE_NIL);
+      break;
+   default:
+      n->Store->Swizzle = SWIZZLE_XYZW;
+   }
+
+   assert(n->Store->Index >= 0);
+
    return NULL; /* no instruction */
 }
 
@@ -1914,7 +2040,7 @@ emit_var_decl(slang_emit_info *emitInfo, slang_ir_node *n)
 
 /**
  * Emit code for a reference to a variable.
- * Actually, no code is generated but we may do some memory alloation.
+ * Actually, no code is generated but we may do some memory allocation.
  * In particular, state vars (uniforms) are allocated on an as-needed basis.
  */
 static struct prog_instruction *
@@ -2132,7 +2258,7 @@ _slang_resolve_subroutines(slang_emit_info *emitInfo)
       total += emitInfo->Subroutines[i]->NumInstructions;
    }
 
-   /* adjust BrancTargets within the functions */
+   /* adjust BranchTargets within the functions */
    for (i = 0; i < emitInfo->NumSubroutines; i++) {
       struct gl_program *sub = emitInfo->Subroutines[i];
       GLuint j;
@@ -2201,7 +2327,7 @@ _slang_emit_code(slang_ir_node *n, slang_var_table *vt,
    emitInfo.prog = prog;
    emitInfo.Subroutines = NULL;
    emitInfo.NumSubroutines = 0;
-   emitInfo.MaxInstructions = 0;
+   emitInfo.MaxInstructions = prog->NumInstructions;
 
    emitInfo.EmitHighLevelInstructions = ctx->Shader.EmitHighLevelInstructions;
    emitInfo.EmitCondCodes = ctx->Shader.EmitCondCodes;
index 105ab5b..b459acc 100644 (file)
@@ -112,6 +112,20 @@ _slang_ir_info(slang_ir_opcode opcode)
 }
 
 
+void
+_slang_init_ir_storage(slang_ir_storage *st,
+                       enum register_file file, GLint index, GLint size,
+                       GLuint swizzle)
+{
+   st->File = file;
+   st->Index = index;
+   st->Size = size;
+   st->Swizzle = swizzle;
+   st->Parent = NULL;
+   st->IsIndirect = GL_FALSE;
+}
+
+
 /**
  * Return a new slang_ir_storage object.
  */
@@ -126,6 +140,7 @@ _slang_new_ir_storage(enum register_file file, GLint index, GLint size)
       st->Size = size;
       st->Swizzle = SWIZZLE_NOOP;
       st->Parent = NULL;
+      st->IsIndirect = GL_FALSE;
    }
    return st;
 }
@@ -146,6 +161,7 @@ _slang_new_ir_storage_swz(enum register_file file, GLint index, GLint size,
       st->Size = size;
       st->Swizzle = swizzle;
       st->Parent = NULL;
+      st->IsIndirect = GL_FALSE;
    }
    return st;
 }
@@ -166,11 +182,45 @@ _slang_new_ir_storage_relative(GLint index, GLint size,
       st->Size = size;
       st->Swizzle = SWIZZLE_NOOP;
       st->Parent = parent;
+      st->IsIndirect = GL_FALSE;
+   }
+   return st;
+}
+
+
+slang_ir_storage *
+_slang_new_ir_storage_indirect(enum register_file file,
+                               GLint index,
+                               GLint size,
+                               enum register_file indirectFile,
+                               GLint indirectIndex,
+                               GLuint indirectSwizzle)
+{
+   slang_ir_storage *st;
+   st = (slang_ir_storage *) _slang_alloc(sizeof(slang_ir_storage));
+   if (st) {
+      st->File = file;
+      st->Index = index;
+      st->Size = size;
+      st->Swizzle = SWIZZLE_NOOP;
+      st->IsIndirect = GL_TRUE;
+      st->IndirectFile = indirectFile;
+      st->IndirectIndex = indirectIndex;
+      st->IndirectSwizzle = indirectSwizzle;
    }
    return st;
 }
 
 
+/* XXX temporary function */
+void
+_slang_copy_ir_storage(slang_ir_storage *dst, const slang_ir_storage *src)
+{
+   *dst = *src;
+   dst->Parent = NULL;
+}
+
+
 
 static const char *
 _slang_ir_name(slang_ir_opcode opcode)
index 4cd81f0..cc784d4 100644 (file)
@@ -137,24 +137,53 @@ typedef enum
 
 
 /**
- * Describes where data storage is allocated.
+ * Describes where data/variables are stored in the various register files.
+ *
+ * In the simple case, the File, Index and Size fields indicate where
+ * a variable is stored.  For example, a vec3 variable may be stored
+ * as (File=PROGRAM_TEMPORARY, Index=6, Size=3).  Or, File[Index].
+ * Or, a program input like color may be stored as
+ * (File=PROGRAM_INPUT,Index=3,Size=4);
+ *
+ * For single-float values, the Swizzle field indicates which component
+ * of the vector contains the float.
+ *
+ * If IsIndirect is set, the storage is accessed through an indirect
+ * register lookup.  The value in question will be located at:
+ *   File[Index + IndirectFile[IndirectIndex]]
+ *
+ * This is primary used for indexing arrays.  For example, consider this
+ * GLSL code:
+ *   uniform int i;
+ *   float a[10];
+ *   float x = a[i];
+ *
+ * here, storage for a[i] would be described by (File=PROGRAM_TEMPORAY,
+ * Index=aPos, IndirectFile=PROGRAM_UNIFORM, IndirectIndex=iPos), which
+ * would mean TEMP[aPos + UNIFORM[iPos]]
  */
-struct _slang_ir_storage
+struct slang_ir_storage_
 {
    enum register_file File;  /**< PROGRAM_TEMPORARY, PROGRAM_INPUT, etc */
    GLint Index;  /**< -1 means unallocated */
    GLint Size;  /**< number of floats */
-   GLuint Swizzle;
+   GLuint Swizzle; /**< Swizzle AND writemask info */
    GLint RefCount; /**< Used during IR tree delete */
-   GLboolean RelAddr;
+
+   GLboolean RelAddr; /* we'll remove this eventually */
+
+   GLboolean IsIndirect;
+   enum register_file IndirectFile;
+   GLint IndirectIndex;
+   GLuint IndirectSwizzle;
 
    /** If Parent is non-null, Index is relative to parent.
     * The other fields are ignored.
     */
-   struct _slang_ir_storage *Parent;
+   struct slang_ir_storage_ *Parent;
 };
 
-typedef struct _slang_ir_storage slang_ir_storage;
+typedef struct slang_ir_storage_ slang_ir_storage;
 
 
 /**
@@ -196,6 +225,11 @@ extern const slang_ir_info *
 _slang_ir_info(slang_ir_opcode opcode);
 
 
+extern void
+_slang_init_ir_storage(slang_ir_storage *st,
+                       enum register_file file, GLint index, GLint size,
+                       GLuint swizzle);
+
 extern slang_ir_storage *
 _slang_new_ir_storage(enum register_file file, GLint index, GLint size);
 
@@ -209,6 +243,17 @@ _slang_new_ir_storage_relative(GLint index, GLint size,
                                slang_ir_storage *parent);
 
 
+extern slang_ir_storage *
+_slang_new_ir_storage_indirect(enum register_file file,
+                               GLint index,
+                               GLint size,
+                               enum register_file indirectFile,
+                               GLint indirectIndex,
+                               GLuint indirectSwizzle);
+
+extern void
+_slang_copy_ir_storage(slang_ir_storage *dst, const slang_ir_storage *src);
+
 
 extern void
 _slang_free_ir_tree(slang_ir_node *n);
index 8a3b992..94bcd63 100644 (file)
@@ -2,7 +2,7 @@
 #ifndef SLANG_VARTABLE_H
 #define SLANG_VARTABLE_H
 
-struct _slang_ir_storage;
+struct slang_ir_storage_;
 
 typedef struct slang_var_table_ slang_var_table;
 
@@ -27,16 +27,16 @@ extern struct slang_variable_ *
 _slang_find_variable(const slang_var_table *t, slang_atom name);
 
 extern GLboolean
-_slang_alloc_var(slang_var_table *t, struct _slang_ir_storage *store);
+_slang_alloc_var(slang_var_table *t, struct slang_ir_storage_ *store);
 
 extern GLboolean
-_slang_alloc_temp(slang_var_table *t, struct _slang_ir_storage *store);
+_slang_alloc_temp(slang_var_table *t, struct slang_ir_storage_ *store);
 
 extern void
-_slang_free_temp(slang_var_table *t, struct _slang_ir_storage *store);
+_slang_free_temp(slang_var_table *t, struct slang_ir_storage_ *store);
 
 extern GLboolean
-_slang_is_temp(const slang_var_table *t, const struct _slang_ir_storage *store);
+_slang_is_temp(const slang_var_table *t, const struct slang_ir_storage_ *store);
 
 
 #endif /* SLANG_VARTABLE_H */