r300/compiler: Introduce control flow instructions and refactor dataflow
[mesa.git] / src / mesa / drivers / dri / r300 / compiler / radeon_program.c
index 0022d0a76ce92f90f892abf24270b5ef24fa87f8..a1ee7c0cab74f6e8abbbb397953ac2da9a5c31fc 100644 (file)
@@ -27,7 +27,9 @@
 
 #include "radeon_program.h"
 
-#include "shader/prog_print.h"
+#include <stdio.h>
+
+#include "radeon_compiler.h"
 
 
 /**
  * one instruction at a time.
  */
 void radeonLocalTransform(
-       struct gl_program *program,
+       struct radeon_compiler * c,
        int num_transformations,
        struct radeon_program_transformation* transformations)
 {
-       struct radeon_transform_context ctx;
-       int ip;
-
-       ctx.Program = program;
-       ctx.OldInstructions = program->Instructions;
-       ctx.OldNumInstructions = program->NumInstructions;
-
-       program->Instructions = 0;
-       program->NumInstructions = 0;
+       struct rc_instruction * inst = c->Program.Instructions.Next;
 
-       for(ip = 0; ip < ctx.OldNumInstructions; ++ip) {
-               struct prog_instruction *instr = ctx.OldInstructions + ip;
+       while(inst != &c->Program.Instructions) {
+               struct rc_instruction * current = inst;
                int i;
 
+               inst = inst->Next;
+
                for(i = 0; i < num_transformations; ++i) {
                        struct radeon_program_transformation* t = transformations + i;
 
-                       if (t->function(&ctx, instr, t->userData))
+                       if (t->function(c, current, t->userData))
                                break;
                }
-
-               if (i >= num_transformations) {
-                       struct prog_instruction* dest = radeonAppendInstructions(program, 1);
-                       _mesa_copy_instructions(dest, instr, 1);
-               }
        }
-
-       _mesa_free_instructions(ctx.OldInstructions, ctx.OldNumInstructions);
 }
 
-
-static void scan_instructions(GLboolean* used, const struct prog_instruction* insts, GLuint count)
+/**
+ * Left multiplication of a register with a swizzle
+ */
+struct rc_src_register lmul_swizzle(unsigned int swizzle, struct rc_src_register srcreg)
 {
-       GLuint i;
-       for (i = 0; i < count; i++) {
-               const struct prog_instruction *inst = insts + i;
-               const GLuint n = _mesa_num_inst_src_regs(inst->Opcode);
-               GLuint k;
-
-               for (k = 0; k < n; k++) {
-                       if (inst->SrcReg[k].File == PROGRAM_TEMPORARY)
-                               used[inst->SrcReg[k].Index] = GL_TRUE;
+       struct rc_src_register tmp = srcreg;
+       int i;
+       tmp.Swizzle = 0;
+       tmp.Negate = 0;
+       for(i = 0; i < 4; ++i) {
+               rc_swizzle swz = GET_SWZ(swizzle, i);
+               if (swz < 4) {
+                       tmp.Swizzle |= GET_SWZ(srcreg.Swizzle, swz) << (i*3);
+                       tmp.Negate |= GET_BIT(srcreg.Negate, swz) << i;
+               } else {
+                       tmp.Swizzle |= swz << (i*3);
                }
        }
+       return tmp;
 }
 
-GLint radeonFindFreeTemporary(struct radeon_transform_context *t)
+unsigned int rc_find_free_temporary(struct radeon_compiler * c)
 {
-       GLboolean used[MAX_PROGRAM_TEMPS];
-       GLuint i;
+       char used[RC_REGISTER_MAX_INDEX];
+       unsigned int i;
+
+       memset(used, 0, sizeof(used));
 
-       _mesa_memset(used, 0, sizeof(used));
-       scan_instructions(used, t->Program->Instructions, t->Program->NumInstructions);
-       scan_instructions(used, t->OldInstructions, t->OldNumInstructions);
+       for (struct rc_instruction * rcinst = c->Program.Instructions.Next; rcinst != &c->Program.Instructions; rcinst = rcinst->Next) {
+               const struct rc_sub_instruction *inst = &rcinst->I;
+               const struct rc_opcode_info *opcode = rc_get_opcode_info(inst->Opcode);
+               unsigned int k;
 
-       for (i = 0; i < MAX_PROGRAM_TEMPS; i++) {
+               for (k = 0; k < opcode->NumSrcRegs; k++) {
+                       if (inst->SrcReg[k].File == RC_FILE_TEMPORARY)
+                               used[inst->SrcReg[k].Index] = 1;
+               }
+
+               if (opcode->HasDstReg) {
+                       if (inst->DstReg.File == RC_FILE_TEMPORARY)
+                               used[inst->DstReg.Index] = 1;
+               }
+       }
+
+       for (i = 0; i < RC_REGISTER_MAX_INDEX; i++) {
                if (!used[i])
                        return i;
        }
 
-       return -1;
+       rc_error(c, "Ran out of temporary registers\n");
+       return 0;
+}
+
+
+struct rc_instruction *rc_alloc_instruction(struct radeon_compiler * c)
+{
+       struct rc_instruction * inst = memory_pool_malloc(&c->Pool, sizeof(struct rc_instruction));
+
+       memset(inst, 0, sizeof(struct rc_instruction));
+
+       inst->I.Opcode = RC_OPCODE_ILLEGAL_OPCODE;
+       inst->I.DstReg.WriteMask = RC_MASK_XYZW;
+       inst->I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZW;
+       inst->I.SrcReg[1].Swizzle = RC_SWIZZLE_XYZW;
+       inst->I.SrcReg[2].Swizzle = RC_SWIZZLE_XYZW;
+
+       return inst;
+}
+
+
+struct rc_instruction *rc_insert_new_instruction(struct radeon_compiler * c, struct rc_instruction * after)
+{
+       struct rc_instruction * inst = rc_alloc_instruction(c);
+
+       inst->Prev = after;
+       inst->Next = after->Next;
+
+       inst->Prev->Next = inst;
+       inst->Next->Prev = inst;
+
+       return inst;
 }
 
+void rc_remove_instruction(struct rc_instruction * inst)
+{
+       inst->Prev->Next = inst->Next;
+       inst->Next->Prev = inst->Prev;
+}
 
 /**
- * Append the given number of instructions to the program and return a
- * pointer to the first new instruction.
+ * Return the number of instructions in the program.
  */
-struct prog_instruction *radeonAppendInstructions(struct gl_program *program, int count)
+unsigned int rc_recompute_ips(struct radeon_compiler * c)
 {
-       int oldnum = program->NumInstructions;
-       _mesa_insert_instructions(program, oldnum, count);
-       return program->Instructions + oldnum;
+       unsigned int ip = 0;
+
+       for(struct rc_instruction * inst = c->Program.Instructions.Next;
+           inst != &c->Program.Instructions;
+           inst = inst->Next) {
+               inst->IP = ip++;
+       }
+
+       c->Program.Instructions.IP = 0xcafedead;
+
+       return ip;
 }