Be more consistant with paths in #includes. Eventually, eliminate a bunch of -I...
[mesa.git] / src / mesa / shader / slang / slang_emit.c
index 64163c4959e9fbe6fdbe7103be521cce65b399f1..02c74095a9e500b4f003ce7dca4061e32cb2e064 100644 (file)
  ***/
 
 
-#include "imports.h"
-#include "context.h"
-#include "macros.h"
-#include "program.h"
-#include "prog_instruction.h"
-#include "prog_parameter.h"
-#include "prog_print.h"
+#include "main/imports.h"
+#include "main/context.h"
+#include "main/macros.h"
+#include "shader/program.h"
+#include "shader/prog_instruction.h"
+#include "shader/prog_parameter.h"
+#include "shader/prog_print.h"
 #include "slang_builtin.h"
 #include "slang_emit.h"
+#include "slang_mem.h"
 
 
 #define PEEPHOLE_OPTIMIZATIONS 1
@@ -86,6 +87,25 @@ new_subroutine(slang_emit_info *emitInfo, GLuint *id)
 }
 
 
+/**
+ * Convert a writemask to a swizzle.  Used for testing cond codes because
+ * we only want to test the cond code component(s) that was set by the
+ * previous instruction.
+ */
+static GLuint
+writemask_to_swizzle(GLuint writemask)
+{
+   if (writemask == WRITEMASK_X)
+      return SWIZZLE_XXXX;
+   if (writemask == WRITEMASK_Y)
+      return SWIZZLE_YYYY;
+   if (writemask == WRITEMASK_Z)
+      return SWIZZLE_ZZZZ;
+   if (writemask == WRITEMASK_W)
+      return SWIZZLE_WWWW;
+   return SWIZZLE_XYZW;  /* shouldn't be hit */
+}
+
 
 /**
  * Swizzle a swizzle.  That is, return swz2(swz1)
@@ -107,7 +127,7 @@ slang_ir_storage *
 _slang_new_ir_storage(enum register_file file, GLint index, GLint size)
 {
    slang_ir_storage *st;
-   st = (slang_ir_storage *) _mesa_calloc(sizeof(slang_ir_storage));
+   st = (slang_ir_storage *) _slang_alloc(sizeof(slang_ir_storage));
    if (st) {
       st->File = file;
       st->Index = index;
@@ -132,6 +152,8 @@ alloc_temp_storage(slang_emit_info *emitInfo, slang_ir_node *n, GLint size)
    if (!_slang_alloc_temp(emitInfo->vt, n->Store)) {
       slang_info_log_error(emitInfo->log,
                            "Ran out of registers, too many temporaries");
+      _slang_free(n->Store);
+      n->Store = NULL;
       return GL_FALSE;
    }
    return GL_TRUE;
@@ -152,6 +174,8 @@ free_temp_storage(slang_var_table *vt, slang_ir_node *n)
          _slang_free_temp(vt, n->Store);
          n->Store->Index = -1;
          n->Store->Size = -1;
+         /*_mesa_free(n->Store);*/ /* XXX leak */
+         n->Store = NULL;
       }
    }
 }
@@ -211,6 +235,27 @@ storage_to_src_reg(struct prog_src_register *src, const slang_ir_storage *st)
 }
 
 
+/*
+ * Setup an instrucion src register to point to a scalar constant.
+ */
+static void
+constant_to_src_reg(struct prog_src_register *src, GLfloat val,
+                    slang_emit_info *emitInfo)
+{
+   GLuint zeroSwizzle;
+   GLint zeroReg;
+   GLfloat value[4];
+
+   value[0] = val;
+   zeroReg = _mesa_add_unnamed_constant(emitInfo->prog->Parameters,
+                                        value, 1, &zeroSwizzle);
+   assert(zeroReg >= 0);
+
+   src->File = PROGRAM_CONSTANT;
+   src->Index = zeroReg;
+   src->Swizzle = zeroSwizzle;
+}
+
 
 /**
  * Add new instruction at end of given program.
@@ -466,8 +511,13 @@ emit_arith(slang_emit_info *emitInfo, slang_ir_node *n)
       /* normal case */
 
       /* gen code for children */
-      for (i = 0; i < info->NumParams; i++)
+      for (i = 0; i < info->NumParams; i++) {
          emit(emitInfo, n->Children[i]);
+         if (!n->Children[i] || !n->Children[i]->Store) {
+            /* error recovery */
+            return NULL;
+         }
+      }
 
       /* gen this instruction and src registers */
       inst = new_instruction(emitInfo, info->InstOpcode);
@@ -485,6 +535,7 @@ emit_arith(slang_emit_info *emitInfo, slang_ir_node *n)
 
    /* result storage */
    if (!n->Store) {
+      /* XXX this size isn't correct, it depends on the operands */
       if (!alloc_temp_storage(emitInfo, n, info->ResultSize))
          return NULL;
    }
@@ -534,16 +585,12 @@ emit_compare(slang_emit_info *emitInfo, slang_ir_node *n)
       storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
    }
    else if (size <= 4) {
-      static const GLfloat zero[4] = { 0, 0, 0, 0 };
-      GLuint zeroSwizzle, swizzle;
-      GLint zeroReg = _mesa_add_unnamed_constant(emitInfo->prog->Parameters,
-                                                 zero, 4, &zeroSwizzle);
+      GLuint swizzle;
       gl_inst_opcode dotOp;
       
-      assert(zeroReg >= 0);
-
+      assert(!n->Store);
       if (!n->Store) {
-         if (!alloc_temp_storage(emitInfo, n, 4))  /* 4 bools */
+         if (!alloc_temp_storage(emitInfo, n, size))  /* 'size' bools */
             return NULL;
       }
 
@@ -561,34 +608,30 @@ emit_compare(slang_emit_info *emitInfo, slang_ir_node *n)
          swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y);
       }
 
-      /* Compute equality, inequality */
+      /* Compute equality, inequality (tmp1 = (A ?= B)) */
       inst = new_instruction(emitInfo, OPCODE_SNE);
       storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
       storage_to_src_reg(&inst->SrcReg[1], n->Children[1]->Store);
       storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
       inst->Comment = _mesa_strdup("Compare values");
-      /* compute D = DP4(D, D)  (reduction) */
+
+      /* Compute tmp2 = DOT(tmp1, tmp1)  (reduction) */
       inst = new_instruction(emitInfo, dotOp);
-      inst->SrcReg[0].File = PROGRAM_TEMPORARY;
-      inst->SrcReg[0].Index = n->Store->Index;
-      inst->SrcReg[0].Swizzle = swizzle;
-      inst->SrcReg[1].File = PROGRAM_TEMPORARY;
-      inst->SrcReg[1].Index = n->Store->Index;
-      inst->SrcReg[1].Swizzle = swizzle;
-      inst->DstReg.File = PROGRAM_TEMPORARY;
-      inst->DstReg.Index = n->Store->Index;
+      storage_to_src_reg(&inst->SrcReg[0], n->Store);
+      storage_to_src_reg(&inst->SrcReg[1], n->Store);
+      inst->SrcReg[0].Swizzle = inst->SrcReg[1].Swizzle = swizzle; /*override*/
+      free_temp_storage(emitInfo->vt, n); /* free tmp1 */
+      if (!alloc_temp_storage(emitInfo, n, 1))  /* alloc tmp2 */
+         return NULL;
+      storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
       inst->Comment = _mesa_strdup("Reduce vec to bool");
+
       if (n->Opcode == IR_EQUAL) {
-         /* compute D.x = !D.x  via D.x = (D.x == 0) */
+         /* compute tmp2.x = !tmp2.x  via tmp2.x = (tmp2.x == 0) */
          inst = new_instruction(emitInfo, OPCODE_SEQ);
-         inst->SrcReg[0].File = PROGRAM_TEMPORARY;
-         inst->SrcReg[0].Index = n->Store->Index;
-         inst->SrcReg[1].File = PROGRAM_CONSTANT;
-         inst->SrcReg[1].Index = zeroReg;
-         inst->SrcReg[1].Swizzle = zeroSwizzle;
-         inst->DstReg.File = PROGRAM_TEMPORARY;
-         inst->DstReg.Index = n->Store->Index;
-         inst->DstReg.WriteMask = WRITEMASK_X;
+         storage_to_src_reg(&inst->SrcReg[0], n->Store);
+         constant_to_src_reg(&inst->SrcReg[1], 0.0, emitInfo);
+         storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
          inst->Comment = _mesa_strdup("Invert true/false");
       }
    }
@@ -757,6 +800,11 @@ emit_func(slang_emit_info *emitInfo, slang_ir_node *n)
                              emitInfo->prog);
 
    if (emitInfo->EmitBeginEndSub) {
+      /* BGNSUB isn't a real instruction.
+       * We require a label (i.e. "foobar:") though, if we're going to
+       * print the program in the NV format.  The BNGSUB instruction is
+       * really just a NOP to attach the label to.
+       */
       inst = new_instruction(emitInfo, OPCODE_BGNSUB);
       inst->Comment = _mesa_strdup(n->Label->Name);
    }
@@ -800,17 +848,8 @@ emit_return(slang_emit_info *emitInfo, slang_ir_node *n)
    assert(n);
    assert(n->Opcode == IR_RETURN);
    assert(n->Label);
-   inst = new_instruction(emitInfo, OPCODE_RET/*BRA*/); /*XXX TEMPORARY*/
-   inst->DstReg.CondMask = COND_TR;  /* always return/branch */
-
-   if (inst->Opcode == OPCODE_BRA) {
-      inst->BranchTarget = _slang_label_get_location(n->Label);
-      if (inst->BranchTarget < 0) {
-         _slang_label_add_reference(n->Label,
-                                    emitInfo->prog->NumInstructions - 1);
-      }
-   }
-
+   inst = new_instruction(emitInfo, OPCODE_RET);
+   inst->DstReg.CondMask = COND_TR;  /* always return */
    return inst;
 }
 
@@ -859,7 +898,11 @@ emit_tex(slang_emit_info *emitInfo, slang_ir_node *n)
 
    /* Child[0] is the sampler (a uniform which'll indicate the texture unit) */
    assert(n->Children[0]->Store);
+   /* Store->Index is the sampler index */
+   assert(n->Children[0]->Store->Index >= 0);
+   /* Store->Size is the texture target */
    assert(n->Children[0]->Store->Size >= TEXTURE_1D_INDEX);
+   assert(n->Children[0]->Store->Size <= TEXTURE_RECT_INDEX);
 
    inst->Sampler = n->Children[0]->Store->Index; /* i.e. uniform's index */
    inst->TexSrcTarget = n->Children[0]->Store->Size;
@@ -877,17 +920,26 @@ emit_move(slang_emit_info *emitInfo, slang_ir_node *n)
 
    /* lhs */
    emit(emitInfo, n->Children[0]);
+   if (!n->Children[0]->Store || n->Children[0]->Store->Index < 0) {
+      /* an error should have been already recorded */
+      return NULL;
+   }
 
    /* rhs */
    assert(n->Children[1]);
    inst = emit(emitInfo, n->Children[1]);
 
-   if (!n->Children[1]->Store) {
-      slang_info_log_error(emitInfo->log, "invalid assignment");
+   if (!n->Children[1]->Store || n->Children[1]->Store->Index < 0) {
+      if (!emitInfo->log->text) {
+         slang_info_log_error(emitInfo->log, "invalid assignment");
+      }
       return NULL;
    }
+
    assert(n->Children[1]->Store->Index >= 0);
 
+   /*assert(n->Children[0]->Store->Size == n->Children[1]->Store->Size);*/
+
    n->Store = n->Children[0]->Store;
 
 #if PEEPHOLE_OPTIMIZATIONS
@@ -949,28 +1001,39 @@ emit_move(slang_emit_info *emitInfo, slang_ir_node *n)
 }
 
 
+/**
+ * An IR_COND node wraps a boolean expression which is used by an
+ * IF or WHILE test.  This is where we'll set condition codes, if needed.
+ */
 static struct prog_instruction *
 emit_cond(slang_emit_info *emitInfo, slang_ir_node *n)
 {
    struct prog_instruction *inst;
 
+   assert(n->Opcode == IR_COND);
+
    if (!n->Children[0])
       return NULL;
 
+   /* emit code for the expression */
    inst = emit(emitInfo, n->Children[0]);
 
+   if (!n->Children[0]->Store) {
+      /* error recovery */
+      return NULL;
+   }
+
+   assert(n->Children[0]->Store);
+   /*assert(n->Children[0]->Store->Size == 1);*/
+
    if (emitInfo->EmitCondCodes) {
-      /* Conditional expression (in if/while/for stmts).
-       * Need to update condition code register.
-       * Next instruction is typically an IR_IF.
-       */
       if (inst &&
           n->Children[0]->Store &&
           inst->DstReg.File == n->Children[0]->Store->File &&
           inst->DstReg.Index == n->Children[0]->Store->Index) {
          /* The previous instruction wrote to the register who's value
-          * we're testing.  Just update that instruction so that the
-          * condition codes are updated.
+          * we're testing.  Just fix that instruction so that the
+          * condition codes are computed.
           */
          inst->CondUpdate = GL_TRUE;
          n->Store = n->Children[0]->Store;
@@ -980,10 +1043,8 @@ emit_cond(slang_emit_info *emitInfo, slang_ir_node *n)
          /* 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.
-          * Note: must use full 4-component vector since all four
-          * condition codes must be set identically.
           */
-         if (!alloc_temp_storage(emitInfo, n, 4))
+         if (!alloc_temp_storage(emitInfo, n, 1))
             return NULL;
          inst = new_instruction(emitInfo, OPCODE_MOV);
          inst->CondUpdate = GL_TRUE;
@@ -991,13 +1052,13 @@ emit_cond(slang_emit_info *emitInfo, slang_ir_node *n)
          storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
          _slang_free_temp(emitInfo->vt, n->Store);
          inst->Comment = _mesa_strdup("COND expr");
-         return inst; /* XXX or null? */
+         return inst;
       }
    }
    else {
-      /* No-op */
+      /* No-op: the boolean result of the expression is in a regular reg */
       n->Store = n->Children[0]->Store;
-      return NULL;
+      return inst;
    }
 }
 
@@ -1008,20 +1069,37 @@ emit_cond(slang_emit_info *emitInfo, slang_ir_node *n)
 static struct prog_instruction *
 emit_not(slang_emit_info *emitInfo, slang_ir_node *n)
 {
-   GLfloat zero = 0.0;
-   slang_ir_storage st;
+   static const struct {
+      gl_inst_opcode op, opNot;
+   } operators[] = {
+      { OPCODE_SLT, OPCODE_SGE },
+      { OPCODE_SLE, OPCODE_SGT },
+      { OPCODE_SGT, OPCODE_SLE },
+      { OPCODE_SGE, OPCODE_SLT },
+      { OPCODE_SEQ, OPCODE_SNE },
+      { OPCODE_SNE, OPCODE_SEQ },
+      { 0, 0 }
+   };
    struct prog_instruction *inst;
-
-   /* need zero constant */
-   st.File = PROGRAM_CONSTANT;
-   st.Size = 1;
-   st.Index = _mesa_add_unnamed_constant(emitInfo->prog->Parameters, &zero,
-                                         1, &st.Swizzle);
+   GLuint i;
 
    /* child expr */
-   (void) emit(emitInfo, n->Children[0]);
-   /* XXXX if child instr is SGT convert to SLE, if SEQ, SNE, etc */
+   inst = emit(emitInfo, n->Children[0]);
+
+#if PEEPHOLE_OPTIMIZATIONS
+   if (inst) {
+      /* if the prev instruction was a comparison instruction, invert it */
+      for (i = 0; operators[i].op; i++) {
+         if (inst->Opcode == operators[i].op) {
+            inst->Opcode = operators[i].opNot;
+            n->Store = n->Children[0]->Store;
+            return inst;
+         }
+      }
+   }
+#endif
 
+   /* else, invert using SEQ (v = v == 0) */
    if (!n->Store)
       if (!alloc_temp_storage(emitInfo, n, n->Children[0]->Store->Size))
          return NULL;
@@ -1029,8 +1107,7 @@ emit_not(slang_emit_info *emitInfo, slang_ir_node *n)
    inst = new_instruction(emitInfo, OPCODE_SEQ);
    storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
    storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
-   storage_to_src_reg(&inst->SrcReg[1], &st);
-
+   constant_to_src_reg(&inst->SrcReg[1], 0.0, emitInfo);
    free_temp_storage(emitInfo->vt, n->Children[0]);
 
    inst->Comment = _mesa_strdup("NOT");
@@ -1042,10 +1119,21 @@ static struct prog_instruction *
 emit_if(slang_emit_info *emitInfo, slang_ir_node *n)
 {
    struct gl_program *prog = emitInfo->prog;
-   struct prog_instruction *ifInst;
    GLuint ifInstLoc, elseInstLoc = 0;
+   GLuint condWritemask = 0;
 
-   emit(emitInfo, n->Children[0]);  /* the condition */
+   /* emit condition expression code */
+   {
+      struct prog_instruction *inst;
+      inst = emit(emitInfo, n->Children[0]);
+      if (emitInfo->EmitCondCodes) {
+         if (!inst) {
+            /* error recovery */
+            return NULL;
+         }
+         condWritemask = inst->DstReg.WriteMask;
+      }
+   }
 
 #if 0
    assert(n->Children[0]->Store->Size == 1); /* a bool! */
@@ -1053,9 +1141,13 @@ emit_if(slang_emit_info *emitInfo, slang_ir_node *n)
 
    ifInstLoc = prog->NumInstructions;
    if (emitInfo->EmitHighLevelInstructions) {
-      ifInst = new_instruction(emitInfo, OPCODE_IF);
+      struct prog_instruction *ifInst = new_instruction(emitInfo, OPCODE_IF);
       if (emitInfo->EmitCondCodes) {
          ifInst->DstReg.CondMask = COND_NE;  /* if cond is non-zero */
+         /* only test the cond code (1 of 4) that was updated by the
+          * previous instruction.
+          */
+         ifInst->DstReg.CondSwizzle = writemask_to_swizzle(condWritemask);
       }
       else {
          /* test reg.x */
@@ -1064,13 +1156,10 @@ emit_if(slang_emit_info *emitInfo, slang_ir_node *n)
    }
    else {
       /* conditional jump to else, or endif */
-      ifInst = new_instruction(emitInfo, OPCODE_BRA);
+      struct prog_instruction *ifInst = new_instruction(emitInfo, OPCODE_BRA);
       ifInst->DstReg.CondMask = COND_EQ;  /* BRA if cond is zero */
       ifInst->Comment = _mesa_strdup("if zero");
-   }
-   if (emitInfo->EmitCondCodes) {
-      /* which condition code to use: */
-      ifInst->DstReg.CondSwizzle = n->Children[0]->Store->Swizzle;
+      ifInst->DstReg.CondSwizzle = writemask_to_swizzle(condWritemask);
    }
 
    /* if body */
@@ -1089,15 +1178,12 @@ emit_if(slang_emit_info *emitInfo, slang_ir_node *n)
          inst->Comment = _mesa_strdup("else");
          inst->DstReg.CondMask = COND_TR;  /* always branch */
       }
-      ifInst = prog->Instructions + ifInstLoc;
-      ifInst->BranchTarget = prog->NumInstructions;
-
+      prog->Instructions[ifInstLoc].BranchTarget = prog->NumInstructions;
       emit(emitInfo, n->Children[2]);
    }
    else {
       /* no else body */
-      ifInst = prog->Instructions + ifInstLoc;
-      ifInst->BranchTarget = prog->NumInstructions + 1;
+      prog->Instructions[ifInstLoc].BranchTarget = prog->NumInstructions;
    }
 
    if (emitInfo->EmitHighLevelInstructions) {
@@ -1105,9 +1191,7 @@ emit_if(slang_emit_info *emitInfo, slang_ir_node *n)
    }
 
    if (n->Children[2]) {
-      struct prog_instruction *elseInst;
-      elseInst = prog->Instructions + elseInstLoc;
-      elseInst->BranchTarget = prog->NumInstructions;
+      prog->Instructions[elseInstLoc].BranchTarget = prog->NumInstructions;
    }
    return NULL;
 }
@@ -1117,7 +1201,7 @@ static struct prog_instruction *
 emit_loop(slang_emit_info *emitInfo, slang_ir_node *n)
 {
    struct gl_program *prog = emitInfo->prog;
-   struct prog_instruction *beginInst, *endInst;
+   struct prog_instruction *endInst;
    GLuint beginInstLoc, tailInstLoc, endInstLoc;
    slang_ir_node *ir;
 
@@ -1153,8 +1237,7 @@ emit_loop(slang_emit_info *emitInfo, slang_ir_node *n)
 
    if (emitInfo->EmitHighLevelInstructions) {
       /* BGNLOOP's BranchTarget points to the ENDLOOP inst */
-      beginInst = prog->Instructions + beginInstLoc;
-      beginInst->BranchTarget = prog->NumInstructions - 1;
+      prog->Instructions[beginInstLoc].BranchTarget = prog->NumInstructions -1;
    }
 
    /* Done emitting loop code.  Now walk over the loop's linked list of
@@ -1165,22 +1248,16 @@ emit_loop(slang_emit_info *emitInfo, slang_ir_node *n)
       struct prog_instruction *inst = prog->Instructions + ir->InstLocation;
       assert(inst->BranchTarget < 0);
       if (ir->Opcode == IR_BREAK ||
-          ir->Opcode == IR_BREAK_IF_FALSE ||
           ir->Opcode == IR_BREAK_IF_TRUE) {
          assert(inst->Opcode == OPCODE_BRK ||
-                inst->Opcode == OPCODE_BRK0 ||
-                inst->Opcode == OPCODE_BRK1 ||
                 inst->Opcode == OPCODE_BRA);
          /* go to instruction after end of loop */
          inst->BranchTarget = endInstLoc + 1;
       }
       else {
          assert(ir->Opcode == IR_CONT ||
-                ir->Opcode == IR_CONT_IF_FALSE ||
                 ir->Opcode == IR_CONT_IF_TRUE);
          assert(inst->Opcode == OPCODE_CONT ||
-                inst->Opcode == OPCODE_CONT0 ||
-                inst->Opcode == OPCODE_CONT1 ||
                 inst->Opcode == OPCODE_BRA);
          /* go to instruction at tail of loop */
          inst->BranchTarget = endInstLoc;
@@ -1232,16 +1309,12 @@ emit_cont_break(slang_emit_info *emitInfo, slang_ir_node *n)
  * Either OPCODE_CONT, OPCODE_BRK or OPCODE_BRA will be emitted.
  */
 static struct prog_instruction *
-emit_cont_break_if(slang_emit_info *emitInfo, slang_ir_node *n,
-                   GLboolean breakTrue)
+emit_cont_break_if_true(slang_emit_info *emitInfo, slang_ir_node *n)
 {
-   gl_inst_opcode opcode;
    struct prog_instruction *inst;
 
    assert(n->Opcode == IR_CONT_IF_TRUE ||
-          n->Opcode == IR_CONT_IF_FALSE ||
-          n->Opcode == IR_BREAK_IF_TRUE ||
-          n->Opcode == IR_BREAK_IF_FALSE);
+          n->Opcode == IR_BREAK_IF_TRUE);
 
    /* evaluate condition expr, setting cond codes */
    inst = emit(emitInfo, n->Children[0]);
@@ -1254,37 +1327,45 @@ emit_cont_break_if(slang_emit_info *emitInfo, slang_ir_node *n,
 
    /* opcode selection */
    if (emitInfo->EmitHighLevelInstructions) {
+      const gl_inst_opcode opcode
+         = (n->Opcode == IR_CONT_IF_TRUE) ? OPCODE_CONT : OPCODE_BRK;
       if (emitInfo->EmitCondCodes) {
-         if (n->Opcode == IR_CONT_IF_TRUE ||
-             n->Opcode == IR_CONT_IF_FALSE)
-            opcode = OPCODE_CONT;
-         else
-            opcode = OPCODE_BRK;
+         /* Get the writemask from the previous instruction which set
+          * the condcodes.  Use that writemask as the CondSwizzle.
+          */
+         const GLuint condWritemask = inst->DstReg.WriteMask;
+         inst = new_instruction(emitInfo, opcode);
+         inst->DstReg.CondMask = COND_NE;
+         inst->DstReg.CondSwizzle = writemask_to_swizzle(condWritemask);
+         return inst;
       }
       else {
-         if (n->Opcode == IR_CONT_IF_TRUE)
-            opcode = OPCODE_CONT1;
-         else if (n->Opcode == IR_CONT_IF_FALSE)
-            opcode = OPCODE_CONT0;
-         else if (n->Opcode == IR_BREAK_IF_TRUE)
-            opcode = OPCODE_BRK1;
-         else if (n->Opcode == IR_BREAK_IF_FALSE)
-            opcode = OPCODE_BRK0;
-      }
-   }
-   else {
-      opcode = OPCODE_BRA;
-   }
+         /* IF reg
+          *    BRK/CONT;
+          * ENDIF
+          */
+         GLint ifInstLoc;
+         ifInstLoc = emitInfo->prog->NumInstructions;
+         inst = new_instruction(emitInfo, OPCODE_IF);
+         storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
+         n->InstLocation = emitInfo->prog->NumInstructions;
 
-   inst = new_instruction(emitInfo, opcode);
-   if (emitInfo->EmitCondCodes) {
-      inst->DstReg.CondMask = breakTrue ? COND_NE : COND_EQ;
+         inst = new_instruction(emitInfo, opcode);
+         inst = new_instruction(emitInfo, OPCODE_ENDIF);
+
+         emitInfo->prog->Instructions[ifInstLoc].BranchTarget
+            = emitInfo->prog->NumInstructions;
+         return inst;
+      }
    }
    else {
-      /* BRK0, BRK1, CONT0, CONT1 uses SrcReg[0] as the condition */
-      storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
+      const GLuint condWritemask = inst->DstReg.WriteMask;
+      assert(emitInfo->EmitCondCodes);
+      inst = new_instruction(emitInfo, OPCODE_BRA);
+      inst->DstReg.CondMask = COND_NE;
+      inst->DstReg.CondSwizzle = writemask_to_swizzle(condWritemask);
+      return inst;
    }
-   return inst;
 }
 
 
@@ -1502,9 +1583,9 @@ emit(slang_emit_info *emitInfo, slang_ir_node *n)
       }
 
       if (n->Store->Index < 0) {
-         printf("#### VAR %s not allocated!\n", (char*)n->Var->a_name);
+         /* probably ran out of registers */
+         return NULL;
       }
-      assert(n->Store->Index >= 0);
       assert(n->Store->Size > 0);
       break;
 
@@ -1618,12 +1699,9 @@ emit(slang_emit_info *emitInfo, slang_ir_node *n)
 
    case IR_LOOP:
       return emit_loop(emitInfo, n);
-   case IR_BREAK_IF_FALSE:
-   case IR_CONT_IF_FALSE:
-      return emit_cont_break_if(emitInfo, n, GL_FALSE);
    case IR_BREAK_IF_TRUE:
    case IR_CONT_IF_TRUE:
-      return emit_cont_break_if(emitInfo, n, GL_TRUE);
+      return emit_cont_break_if_true(emitInfo, n);
    case IR_BREAK:
       /* fall-through */
    case IR_CONT:
@@ -1685,6 +1763,7 @@ _slang_resolve_subroutines(slang_emit_info *emitInfo)
    mainP->Instructions = _mesa_realloc_instructions(mainP->Instructions,
                                                     mainP->NumInstructions,
                                                     total);
+   mainP->NumInstructions = total;
    for (i = 0; i < emitInfo->NumSubroutines; i++) {
       struct gl_program *sub = emitInfo->Subroutines[i];
       _mesa_copy_instructions(mainP->Instructions + subroutineLoc[i],
@@ -1694,7 +1773,13 @@ _slang_resolve_subroutines(slang_emit_info *emitInfo)
       sub->Parameters = NULL; /* prevent double-free */
       _mesa_delete_program(ctx, sub);
    }
-   mainP->NumInstructions = total;
+
+   /* free subroutine list */
+   if (emitInfo->Subroutines) {
+      _mesa_free(emitInfo->Subroutines);
+      emitInfo->Subroutines = NULL;
+   }
+   emitInfo->NumSubroutines = 0;
 
    /* Examine CAL instructions.
     * At this point, the BranchTarget field of the CAL instructions is
@@ -1734,7 +1819,11 @@ _slang_emit_code(slang_ir_node *n, slang_var_table *vt,
    emitInfo.EmitHighLevelInstructions = ctx->Shader.EmitHighLevelInstructions;
    emitInfo.EmitCondCodes = ctx->Shader.EmitCondCodes;
    emitInfo.EmitComments = ctx->Shader.EmitComments;
-   emitInfo.EmitBeginEndSub = 0;  /* XXX for compiler debug only */
+   emitInfo.EmitBeginEndSub = GL_TRUE;
+
+   if (!emitInfo.EmitCondCodes) {
+      emitInfo.EmitHighLevelInstructions = GL_TRUE;
+   }      
 
    (void) emit(&emitInfo, n);