Checkpoint: re-org of (global) variable allocation code. More to come...
[mesa.git] / src / mesa / shader / slang / slang_emit.c
index 3d9d525e181ecf9f1db87c56bf1294110ead93fb..4c952e2e0ae08ef12ef18cb5286bcb70c1ffa918 100644 (file)
@@ -78,6 +78,7 @@ static slang_ir_info IrInfo[] = {
    { IR_FLOOR, "IR_FLOOR", OPCODE_FLR, 4, 1 },
    { IR_FRAC, "IR_FRAC", OPCODE_FRC, 4, 1 },
    { IR_ABS, "IR_ABS", OPCODE_ABS, 4, 1 },
+   { IR_NEG, "IR_NEG", 0/*spec case*/, 4, 1 },
    { IR_SIN, "IR_SIN", OPCODE_SIN, 1, 1 },
    { IR_COS, "IR_COS", OPCODE_COS, 1, 1 },
    /* other */
@@ -85,11 +86,14 @@ static slang_ir_info IrInfo[] = {
    { IR_LABEL, "IR_LABEL", 0, 0, 0 },
    { IR_JUMP, "IR_JUMP", 0, 0, 0 },
    { IR_CJUMP, "IR_CJUMP", 0, 0, 0 },
+   { IR_COND, "IR_COND", 0, 0, 0 },
    { IR_CALL, "IR_CALL", 0, 0, 0 },
    { IR_MOVE, "IR_MOVE", 0, 0, 1 },
    { IR_NOT, "IR_NOT", 0, 1, 1 },
    { IR_VAR, "IR_VAR", 0, 0, 0 },
    { IR_VAR_DECL, "IR_VAR_DECL", 0, 0, 0 },
+   { IR_TEX, "IR_TEX", OPCODE_TEX, 4, 1 },
+   { IR_TEXB, "IR_TEXB", OPCODE_TXB, 4, 2 },
    { IR_FLOAT, "IR_FLOAT", 0, 0, 0 },
    { IR_FIELD, "IR_FIELD", 0, 0, 0 },
    { IR_NOP, NULL, OPCODE_NOP, 0, 0 }
@@ -180,6 +184,7 @@ storage_string(const slang_ir_storage *st)
       "UNIFORM",
       "WRITE_ONLY",
       "ADDRESS",
+      "SAMPLER",
       "UNDEFINED"
    };
    static char s[100];
@@ -190,7 +195,8 @@ storage_string(const slang_ir_storage *st)
       sprintf(s, "%s[%d..%d]", files[st->File], st->Index,
               st->Index + st->Size - 1);
 #endif
-   sprintf(s, "%s", files[st->File]);
+   assert(st->File < sizeof(files) / sizeof(files[0]));
+   sprintf(s, "%s[%d]", files[st->File], st->Index);
    return s;
 }
 
@@ -245,8 +251,7 @@ _slang_sizeof_type_specifier(const slang_type_specifier *spec)
    case slang_spec_samplerCube:
    case slang_spec_sampler1DShadow:
    case slang_spec_sampler2DShadow:
-      abort();
-      return 0;
+      return 1; /* special case */
    case slang_spec_struct:
       return sizeof_struct(spec->_struct);
    case slang_spec_array:
@@ -259,7 +264,6 @@ _slang_sizeof_type_specifier(const slang_type_specifier *spec)
 }
 
 
-
 static GLuint
 sizeof_type(const slang_fully_specified_type *t)
 {
@@ -267,6 +271,23 @@ sizeof_type(const slang_fully_specified_type *t)
 }
 
 
+static GLboolean
+is_sampler_type(const slang_fully_specified_type *t)
+{
+   switch (t->specifier.type) {
+   case slang_spec_sampler1D:
+   case slang_spec_sampler2D:
+   case slang_spec_sampler3D:
+   case slang_spec_samplerCube:
+   case slang_spec_sampler1DShadow:
+   case slang_spec_sampler2DShadow:
+      return GL_TRUE;
+   default:
+      return GL_FALSE;
+   }
+}
+
+
 #define IND 0
 void
 slang_print_ir(const slang_ir_node *n, int indent)
@@ -300,6 +321,10 @@ slang_print_ir(const slang_ir_node *n, int indent)
    case IR_LABEL:
       printf("LABEL: %s\n", n->Target);
       break;
+   case IR_COND:
+      printf("COND\n");
+      slang_print_ir(n->Children[0], indent + 3);
+      break;
    case IR_JUMP:
       printf("JUMP %s\n", n->Target);
       break;
@@ -364,6 +389,15 @@ alloc_temporary(slang_gen_context *gc, GLint size)
 }
 
 
+static GLint
+alloc_sampler(slang_gen_context *gc)
+{
+   GLint sampler = gc->NumSamplers;
+   gc->NumSamplers++;
+   return sampler;
+}
+
+
 static GLboolean
 is_temporary(const slang_gen_context *gc, const slang_ir_storage *st)
 {
@@ -386,87 +420,6 @@ free_temporary(slang_gen_context *gc, GLuint r, GLint size)
 }
 
 
-
-static GLint
-slang_find_input(GLenum target, const char *name, GLint index)
-{
-   struct input_info {
-      const char *Name;
-      GLuint Attrib;
-   };
-   static const struct input_info vertInputs[] = {
-      { "gl_Vertex", VERT_ATTRIB_POS },
-      { "gl_Normal", VERT_ATTRIB_NORMAL },
-      { "gl_Color", VERT_ATTRIB_COLOR0 },
-      { "gl_SecondaryColor", VERT_ATTRIB_COLOR1 },
-      { NULL, 0 }
-   };
-   static const struct input_info fragInputs[] = {
-      { NULL, 0 }
-   };
-   const struct input_info *inputs;
-   GLuint i;
-
-   if (target == GL_VERTEX_PROGRAM_ARB) {
-      inputs = vertInputs;
-   }
-   else {
-      assert(target == GL_FRAGMENT_PROGRAM_ARB);
-      inputs = fragInputs;
-   }
-
-   for (i = 0; inputs[i].Name; i++) {
-      if (strcmp(inputs[i].Name, name) == 0) {
-         /* found */
-         return inputs[i].Attrib;
-      }
-   }
-   return -1;
-}
-
-
-static GLint
-slang_find_output(GLenum target, const char *name, GLint index)
-{
-   struct output_info {
-      const char *Name;
-      GLuint Attrib;
-   };
-   static const struct output_info vertOutputs[] = {
-      { "gl_Position", VERT_RESULT_HPOS },
-      { "gl_FrontColor", VERT_RESULT_COL0 },
-      { "gl_BackColor", VERT_RESULT_BFC0 },
-      { "gl_FrontSecondaryColor", VERT_RESULT_COL1 },
-      { "gl_BackSecondaryColor", VERT_RESULT_BFC1 },
-      { "gl_TexCoord", VERT_RESULT_TEX0 }, /* XXX indexed */
-      { "gl_FogFragCoord", VERT_RESULT_FOGC },
-      { NULL, 0 }
-   };
-   static const struct output_info fragOutputs[] = {
-      { "gl_FragColor", FRAG_RESULT_COLR },
-      { NULL, 0 }
-   };
-   const struct output_info *outputs;
-   GLuint i;
-
-   if (target == GL_VERTEX_PROGRAM_ARB) {
-      outputs = vertOutputs;
-   }
-   else {
-      assert(target == GL_FRAGMENT_PROGRAM_ARB);
-      outputs = fragOutputs;
-   }
-
-   for (i = 0; outputs[i].Name; i++) {
-      if (strcmp(outputs[i].Name, name) == 0) {
-         /* found */
-         return outputs[i].Attrib;
-      }
-   }
-   return -1;
-}
-
-
 /**
  * Lookup a named constant and allocate storage for the parameter in
  * the given parameter list.
@@ -528,15 +481,15 @@ slang_lookup_statevar(const char *name, GLint index,
    };
    static const struct state_info state[] = {
       { "gl_ModelViewMatrix", 4, SWIZZLE_NOOP,
-        { STATE_MATRIX, STATE_MODELVIEW, 0, 0, 0, STATE_MATRIX_TRANSPOSE } },
+        { STATE_MATRIX, STATE_MODELVIEW, 0, 0, 0, 0 } },
       { "gl_NormalMatrix", 3, SWIZZLE_NOOP,
-        { STATE_MATRIX, STATE_MODELVIEW, 0, 0, 0, STATE_MATRIX_INVTRANS } },
+        { STATE_MATRIX, STATE_MODELVIEW, 0, 0, 0, 0 } },
       { "gl_ProjectionMatrix", 4, SWIZZLE_NOOP,
-        { STATE_MATRIX, STATE_PROJECTION, 0, 0, 0, STATE_MATRIX_TRANSPOSE } },
+        { STATE_MATRIX, STATE_PROJECTION, 0, 0, 0, 0 } },
       { "gl_ModelViewProjectionMatrix", 4, SWIZZLE_NOOP,
-        { STATE_MATRIX, STATE_MVP, 0, 0, 0, STATE_MATRIX_TRANSPOSE } },
+        { STATE_MATRIX, STATE_MVP, 0, 0, 0, 0 } },
       { "gl_TextureMatrix", 4, SWIZZLE_NOOP,
-        { STATE_MATRIX, STATE_TEXTURE, 0, 0, 0, STATE_MATRIX_TRANSPOSE } },
+        { STATE_MATRIX, STATE_TEXTURE, 0, 0, 0, 0 } },
       { NULL, 0, 0, {0, 0, 0, 0, 0, 0} }
    };
    GLuint i;
@@ -575,38 +528,13 @@ slang_lookup_statevar(const char *name, GLint index,
 
 
 static GLint
-slang_alloc_uniform(struct gl_program *prog, const char *name)
+slang_alloc_uniform(struct gl_program *prog, const char *name, GLuint size)
 {
-   GLint i = _mesa_add_uniform(prog->Parameters, name, 4);
+   GLint i = _mesa_add_uniform(prog->Parameters, name, size);
    return i;
 }
 
 
-static GLint
-slang_alloc_varying(struct gl_program *prog, const char *name)
-{
-   GLint i = _mesa_add_varying(prog->Varying, name, 4); /* XXX fix size */
-#if 0
-   if (prog->Target == GL_VERTEX_PROGRAM_ARB) {
-#ifdef OLD_LINK
-      i += VERT_RESULT_VAR0;
-      prog->OutputsWritten |= (1 << i);
-#else
-      prog->OutputsWritten |= (1 << (i + VERT_RESULT_VAR0));
-#endif
-   }
-   else {
-#ifdef OLD_LINK
-      i += FRAG_ATTRIB_VAR0;
-      prog->InputsRead |= (1 << i);
-#else
-      prog->InputsRead |= (1 << (i + FRAG_ATTRIB_VAR0));
-#endif
-   }
-#endif
-   return i;
-}
-
 
 /**
  * Allocate temporary storage for an intermediate result (such as for
@@ -631,9 +559,6 @@ slang_alloc_temp_storage(slang_gen_context *gc, slang_ir_node *n, GLint size)
  *   2. Allocate storage for user-declared variables.
  *   3. Allocate intermediate/unnamed storage for complex expressions.
  *   4. other?
- *
- * If gc or prog is NULL, we may only be able to determine the Store->File
- * but not an Index (register).
  */
 void
 slang_resolve_storage(slang_gen_context *gc, slang_ir_node *n,
@@ -660,7 +585,16 @@ slang_resolve_storage(slang_gen_context *gc, slang_ir_node *n,
    if (n->Opcode == IR_VAR_DECL) {
       /* storage declaration */
       assert(n->Var);
-      if (n->Store->Index < 0) { /* XXX assert this? */
+      if (is_sampler_type(&n->Var->type)) {
+         /* i.e. "uniform sampler2D tex;" */
+         n->Store->File = PROGRAM_SAMPLER;
+         n->Store->Size = 1; /* never used */
+         n->Store->Index = alloc_sampler(gc);
+         n->Store->Index = slang_alloc_uniform(prog, (char *) n->Var->a_name, 1);
+         printf("********** Alloc sampler uniform %d\n", n->Store->Index);
+         abort(); /* this is a locally-declared sampler */
+      }
+      else if (n->Store->Index < 0) { /* XXX assert this? */
          assert(gc);
          n->Store->File = PROGRAM_TEMPORARY;
          n->Store->Size = sizeof_type(&n->Var->type);
@@ -676,11 +610,20 @@ slang_resolve_storage(slang_gen_context *gc, slang_ir_node *n,
       return;
    }
 
-   if (n->Opcode == IR_VAR && n->Store->File == PROGRAM_UNDEFINED) {
+   /*
+   assert(!is_sampler_type(&n->Var->type));
+   */
+   assert(n->Opcode == IR_VAR);
+
+   assert(n->Store->File != PROGRAM_UNDEFINED);
+
+   if (n->Opcode == IR_VAR && (n->Store->File == PROGRAM_UNDEFINED
+                               || n->Store->Index < 0)) {
       /* try to determine the storage for this variable */
       GLint i;
 
       assert(n->Var);
+      assert(n->Store->Size > 0);
 
       if (n->Store->Size < 0) {
          /* determine var/storage size now */
@@ -698,25 +641,10 @@ slang_resolve_storage(slang_gen_context *gc, slang_ir_node *n,
              n->Var->type.qualifier == slang_qual_const);
 #endif
 
-      i = slang_find_input(prog->Target, (char *) n->Var->a_name, 0);
-      if (i >= 0) {
-         n->Store->File = PROGRAM_INPUT;
-         n->Store->Index = i;
-         assert(n->Store->Size > 0);
-         prog->InputsRead |= (1 << i);
-         return;
-      }
-
-      i = slang_find_output(prog->Target, (char *) n->Var->a_name, 0);
-      if (i >= 0) {
-         n->Store->File = PROGRAM_OUTPUT;
-         n->Store->Index = i;
-         prog->OutputsWritten |= (1 << i);
-         return;
-      }
-
       i = slang_lookup_statevar((char *) n->Var->a_name, 0, prog->Parameters);
       if (i >= 0) {
+         assert(n->Store->File == PROGRAM_STATE_VAR /*||
+                                                      n->Store->File == PROGRAM_UNIFORM*/);
          n->Store->File = PROGRAM_STATE_VAR;
          n->Store->Index = i;
          return;
@@ -724,36 +652,12 @@ slang_resolve_storage(slang_gen_context *gc, slang_ir_node *n,
 
       i = slang_lookup_constant((char *) n->Var->a_name, 0, prog->Parameters);
       if (i >= 0) {
+         assert(n->Store->File == PROGRAM_CONSTANT);
          n->Store->File = PROGRAM_CONSTANT;
          n->Store->Index = i;
          return;
       }
 
-      /* probably a uniform or varying */
-      if (n->Var->type.qualifier == slang_qual_uniform) {
-         i = slang_alloc_uniform(prog, (char *) n->Var->a_name);
-         if (i >= 0) {
-            n->Store->File = PROGRAM_UNIFORM;
-            n->Store->Index = i;
-            return;
-         }
-      }
-      else if (n->Var->type.qualifier == slang_qual_varying) {
-         i = slang_alloc_varying(prog, (char *) n->Var->a_name);
-         if (i >= 0) {
-#ifdef OLD_LINK
-            if (prog->Target == GL_VERTEX_PROGRAM_ARB)
-               n->Store->File = PROGRAM_OUTPUT;
-            else
-               n->Store->File = PROGRAM_INPUT;
-#else
-            n->Store->File = PROGRAM_VARYING;
-#endif
-            n->Store->Index = i;
-            return;
-         }
-      }
-
       if (n->Store->File == PROGRAM_UNDEFINED && n->Store->Index < 0) {
          /* ordinary local var */
          assert(n->Store->Size > 0);
@@ -913,7 +817,6 @@ emit_unop(slang_gen_context *gc, slang_ir_node *n, struct gl_program *prog)
    emit(gc, n->Children[0], prog);
 
    inst = new_instruction(prog, info->InstOpcode);
-   /*slang_resolve_storage(gc, n, prog);*/
 
    if (!n->Store)
       slang_alloc_temp_storage(gc, n, info->ResultSize);
@@ -929,6 +832,98 @@ emit_unop(slang_gen_context *gc, slang_ir_node *n, struct gl_program *prog)
 }
 
 
+static struct prog_instruction *
+emit_negation(slang_gen_context *gc, slang_ir_node *n, struct gl_program *prog)
+{
+   /* Implement as MOV dst, -src; */
+   /* XXX we could look at the previous instruction and in some circumstances
+    * modify it to accomplish the negation.
+    */
+   struct prog_instruction *inst;
+
+   emit(gc, n->Children[0], prog);
+
+   if (!n->Store)
+      slang_alloc_temp_storage(gc, n, n->Children[0]->Store->Size);
+
+   inst = new_instruction(prog, OPCODE_MOV);
+   storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
+   storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store,
+                      n->Children[0]->Swizzle);
+   inst->SrcReg[0].NegateBase = NEGATE_XYZW;
+   inst->Comment = n->Comment;
+   return inst;
+}
+
+
+static struct prog_instruction *
+emit_label(const char *target, struct gl_program *prog)
+{
+   struct prog_instruction *inst;
+   inst = new_instruction(prog, OPCODE_NOP);
+   inst->Comment = _mesa_strdup(target);
+   return inst;
+}
+
+
+static struct prog_instruction *
+emit_cjump(const char *target, struct gl_program *prog)
+{
+   struct prog_instruction *inst;
+   inst = new_instruction(prog, OPCODE_BRA);
+   inst->DstReg.CondMask = COND_EQ;  /* branch if equal to zero */
+   inst->DstReg.CondSwizzle = SWIZZLE_X;
+   inst->Comment = _mesa_strdup(target);
+   return inst;
+}
+
+
+static struct prog_instruction *
+emit_jump(const char *target, struct gl_program *prog)
+{
+   struct prog_instruction *inst;
+   inst = new_instruction(prog, OPCODE_BRA);
+   inst->DstReg.CondMask = COND_TR;  /* always branch */
+   /*inst->DstReg.CondSwizzle = SWIZZLE_X;*/
+   inst->Comment = _mesa_strdup(target);
+   return inst;
+}
+
+
+static struct prog_instruction *
+emit_tex(slang_gen_context *gc, slang_ir_node *n, struct gl_program *prog)
+{
+   struct prog_instruction *inst;
+   if (n->Opcode == IR_TEX) {
+      inst = new_instruction(prog, OPCODE_TEX);
+   }
+   else {
+      assert(n->Opcode == IR_TEXB);
+      inst = new_instruction(prog, OPCODE_TXB);
+   }
+
+   if (!n->Store)
+      slang_alloc_temp_storage(gc, n, 4);
+
+   storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
+
+   /* Child[1] is the coord */
+   storage_to_src_reg(&inst->SrcReg[0], n->Children[1]->Store,
+                      n->Children[1]->Swizzle);
+
+   /* Child[0] is the sampler (a uniform which'll indicate the texture unit) */
+   assert(n->Children[0]->Store);
+   assert(n->Children[0]->Store->Size >= TEXTURE_1D_INDEX);
+
+   inst->Sampler = n->Children[0]->Store->Index; /* i.e. uniform's index */
+   inst->TexSrcTarget = n->Children[0]->Store->Size;
+   inst->TexSrcUnit = 27; /* Dummy value; the TexSrcUnit will be computed at
+                           * link time, using the sampler uniform's value.
+                           */
+   return inst;
+}
+
+
 static struct prog_instruction *
 emit(slang_gen_context *gc, slang_ir_node *n, struct gl_program *prog)
 {
@@ -1034,7 +1029,6 @@ emit(slang_gen_context *gc, slang_ir_node *n, struct gl_program *prog)
    case IR_EXP:
    case IR_EXP2:
       return emit_binop(gc, n, prog);
-      break;
    case IR_RSQ:
    case IR_RCP:
    case IR_FLOOR:
@@ -1043,19 +1037,49 @@ emit(slang_gen_context *gc, slang_ir_node *n, struct gl_program *prog)
    case IR_SIN:
    case IR_COS:
       return emit_unop(gc, n, prog);
-      break;
+   case IR_TEX:
+   case IR_TEXB:
+      return emit_tex(gc, n, prog);
+   case IR_NEG:
+      return emit_negation(gc, n, prog);
    case IR_LABEL:
-      /*printf("LAB: %s\n", n->Target);*/
-      break;
-   case IR_JUMP:
-#if 0
-      inst = new_instruction(prog, OPCODE_BRA);
-      inst->Comment = _mesa_strdup(n->Target);
-#endif
-      break;
+      return emit_label(n->Target, prog);
    case IR_FLOAT:
       n->Store = alloc_constant(n->Value, 4, prog); /*XXX fix size */
       break;
+   case IR_COND:
+      {
+         /* Conditional expression (in if/while/for stmts).
+          * Need to update condition code register.
+          * Next instruction is typically an IR_CJUMP.
+          */
+         /* last child expr instruction: */
+         struct prog_instruction *inst = emit(gc, n->Children[0], prog);
+         if (inst) {
+            /* set inst's CondUpdate flag */
+            inst->CondUpdate = GL_TRUE;
+            return inst; /* XXX or null? */
+         }
+         else {
+            /* This'll happen for things like "if (i) ..." where no code
+             * is normally generated for the expression "i".
+             * Generate a move instruction just to set condition codes.
+             */
+            slang_alloc_temp_storage(gc, n, 1);
+            inst = new_instruction(prog, OPCODE_MOV);
+            inst->CondUpdate = GL_TRUE;
+            storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
+            storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store,
+                               n->Children[0]->Swizzle);
+            free_temporary(gc, n->Store->Index, n->Store->Size);
+            return inst; /* XXX or null? */
+         }
+      }
+      return NULL;
+   case IR_JUMP:
+      return emit_jump(n->Target, prog);
+   case IR_CJUMP:
+      return emit_cjump(n->Target, prog);
    default:
       printf("emit: ?\n");
       abort();