Merge branch 'mesa_7_7_branch'
[mesa.git] / src / mesa / shader / slang / slang_emit.c
index ea446fa5d49bc689025abcc74778c33a62e10e10..c9ecbd275b8bf6d9da8a37747c2dec4185952d90 100644 (file)
@@ -38,7 +38,6 @@
 
 #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"
@@ -62,6 +61,8 @@ typedef struct
 
    GLuint MaxInstructions;  /**< size of prog->Instructions[] buffer */
 
+   GLboolean UnresolvedFunctions;
+
    /* code-gen options */
    GLboolean EmitHighLevelInstructions;
    GLboolean EmitCondCodes;
@@ -79,8 +80,8 @@ new_subroutine(slang_emit_info *emitInfo, GLuint *id)
 
    emitInfo->Subroutines = (struct gl_program **)
       _mesa_realloc(emitInfo->Subroutines,
-                    n * sizeof(struct gl_program),
-                    (n + 1) * sizeof(struct gl_program));
+                    n * sizeof(struct gl_program *),
+                    (n + 1) * sizeof(struct gl_program *));
    emitInfo->Subroutines[n] = ctx->Driver.NewProgram(ctx, emitInfo->prog->Target, 0);
    emitInfo->Subroutines[n]->Parameters = emitInfo->prog->Parameters;
    emitInfo->NumSubroutines++;
@@ -164,7 +165,7 @@ _slang_var_swizzle(GLint size, GLint comp)
 {
    switch (size) {
    case 1:
-      return MAKE_SWIZZLE4(comp, comp, comp, comp);
+      return MAKE_SWIZZLE4(comp, SWIZZLE_NIL, SWIZZLE_NIL, SWIZZLE_NIL);
    case 2:
       return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_NIL, SWIZZLE_NIL);
    case 3:
@@ -193,6 +194,9 @@ alloc_node_storage(slang_emit_info *emitInfo, slang_ir_node *n,
    if (!n->Store) {
       assert(defaultSize > 0);
       n->Store = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, defaultSize);
+      if (!n->Store) {
+         return GL_FALSE;
+      }
    }
 
    /* now allocate actual register(s).  I.e. set n->Store->Index >= 0 */
@@ -429,6 +433,9 @@ new_instruction(slang_emit_info *emitInfo, gl_inst_opcode opcode)
          _mesa_realloc_instructions(prog->Instructions,
                                     prog->NumInstructions,
                                     emitInfo->MaxInstructions);
+      if (!prog->Instructions) {
+         return NULL;
+      }
    }
 
    inst = prog->Instructions + prog->NumInstructions;
@@ -446,15 +453,17 @@ 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)
+              gl_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;
+   if (inst) {
+      inst->SrcReg[0].File = file;
+      inst->SrcReg[0].Index = index;
+      inst->SrcReg[0].Swizzle = fix_swizzle(swizzle);
+      inst->DstReg.File = PROGRAM_ADDRESS;
+      inst->DstReg.Index = 0;
+      inst->DstReg.WriteMask = WRITEMASK_X;
+   }
    return inst;
 }
 
@@ -541,6 +550,9 @@ emit_instruction(slang_emit_info *emitInfo,
                                        &srcRelAddr,
                                        NULL,
                                        NULL);
+               if (!inst) {
+                  return NULL;
+               }
 
                src[i] = &newSrc[i];
             }
@@ -763,7 +775,9 @@ static struct prog_instruction *
 emit_comment(slang_emit_info *emitInfo, const char *comment)
 {
    struct prog_instruction *inst = new_instruction(emitInfo, OPCODE_NOP);
-   inst_comment(inst, comment);
+   if (inst) {
+      inst_comment(inst, comment);
+   }
    return inst;
 }
 
@@ -790,7 +804,9 @@ emit_arith(slang_emit_info *emitInfo, slang_ir_node *n)
       emit(emitInfo, n->Children[0]->Children[0]);  /* A */
       emit(emitInfo, n->Children[0]->Children[1]);  /* B */
       emit(emitInfo, n->Children[1]);  /* C */
-      alloc_node_storage(emitInfo, n, -1);  /* dest */
+      if (!alloc_node_storage(emitInfo, n, -1)) {  /* dest */
+         return NULL;
+      }
 
       inst = emit_instruction(emitInfo,
                               OPCODE_MAD,
@@ -811,7 +827,9 @@ emit_arith(slang_emit_info *emitInfo, slang_ir_node *n)
       emit(emitInfo, n->Children[0]);  /* A */
       emit(emitInfo, n->Children[1]->Children[0]);  /* B */
       emit(emitInfo, n->Children[1]->Children[1]);  /* C */
-      alloc_node_storage(emitInfo, n, -1);  /* dest */
+      if (!alloc_node_storage(emitInfo, n, -1)) {  /* dest */
+         return NULL;
+      }
 
       inst = emit_instruction(emitInfo,
                               OPCODE_MAD,
@@ -837,7 +855,9 @@ emit_arith(slang_emit_info *emitInfo, slang_ir_node *n)
    }
 
    /* result storage */
-   alloc_node_storage(emitInfo, n, -1);
+   if (!alloc_node_storage(emitInfo, n, -1)) {
+      return NULL;
+   }
 
    inst = emit_instruction(emitInfo,
                            info->InstOpcode,
@@ -872,7 +892,9 @@ emit_compare(slang_emit_info *emitInfo, slang_ir_node *n)
    emit(emitInfo, n->Children[1]);
 
    if (n->Children[0]->Store->Size != n->Children[1]->Store->Size) {
+      /* XXX this error should have been caught in slang_codegen.c */
       slang_info_log_error(emitInfo->log, "invalid operands to == or !=");
+      n->Store = NULL;
       return NULL;
    }
 
@@ -902,6 +924,7 @@ emit_compare(slang_emit_info *emitInfo, slang_ir_node *n)
       slang_ir_storage tempStore;
 
       if (!alloc_local_temp(emitInfo, &tempStore, 4)) {
+         n->Store = NULL;
          return NULL;
          /* out of temps */
       }
@@ -927,6 +950,9 @@ emit_compare(slang_emit_info *emitInfo, slang_ir_node *n)
                               n->Children[0]->Store,
                               n->Children[1]->Store,
                               NULL);
+      if (!inst) {
+         return NULL;
+      }
       inst_comment(inst, "Compare values");
 
       /* Compute val = DOT(temp, temp)  (reduction) */
@@ -936,6 +962,9 @@ emit_compare(slang_emit_info *emitInfo, slang_ir_node *n)
                               &tempStore,
                               &tempStore,
                               NULL);
+      if (!inst) {
+         return NULL;
+      }
       inst->SrcReg[0].Swizzle = inst->SrcReg[1].Swizzle = swizzle; /*override*/
       inst_comment(inst, "Reduce vec to bool");
 
@@ -951,6 +980,9 @@ emit_compare(slang_emit_info *emitInfo, slang_ir_node *n)
                                  n->Store,
                                  &zero,
                                  NULL);
+         if (!inst) {
+            return NULL;
+         }
          inst_comment(inst, "Invert true/false");
       }
    }
@@ -980,6 +1012,9 @@ emit_compare(slang_emit_info *emitInfo, slang_ir_node *n)
                                     &srcStore0,
                                     &srcStore1,
                                     NULL);
+            if (!inst) {
+               return NULL;
+            }
             inst_comment(inst, "Begin struct/array comparison");
          }
          else {
@@ -989,12 +1024,18 @@ emit_compare(slang_emit_info *emitInfo, slang_ir_node *n)
                                     &srcStore0,
                                     &srcStore1,
                                     NULL);
+            if (!inst) {
+               return NULL;
+            }
             /* ADD accTemp, accTemp, sneTemp; # like logical-OR */
             inst = emit_instruction(emitInfo, OPCODE_ADD,
                                     &accTemp, /* dest */
                                     &accTemp,
                                     &sneTemp,
                                     NULL);
+            if (!inst) {
+               return NULL;
+            }
          }
       }
 
@@ -1004,6 +1045,9 @@ emit_compare(slang_emit_info *emitInfo, slang_ir_node *n)
                               &accTemp,
                               &accTemp,
                               NULL);
+      if (!inst) {
+         return NULL;
+      }
       inst_comment(inst, "End struct/array comparison");
 
       if (n->Opcode == IR_EQUAL) {
@@ -1015,6 +1059,9 @@ emit_compare(slang_emit_info *emitInfo, slang_ir_node *n)
                                  n->Store,
                                  &zero,
                                  NULL);
+         if (!inst) {
+            return NULL;
+         }
          inst_comment(inst, "Invert true/false");
       }
 
@@ -1088,7 +1135,9 @@ emit_clamp(slang_emit_info *emitInfo, slang_ir_node *n)
     * the intermediate result.  Use a temp register instead.
     */
    _mesa_bzero(&tmpNode, sizeof(tmpNode));
-   alloc_node_storage(emitInfo, &tmpNode, n->Store->Size);
+   if (!alloc_node_storage(emitInfo, &tmpNode, n->Store->Size)) {
+      return NULL;
+   }
 
    /* tmp = max(ch[0], ch[1]) */
    inst = emit_instruction(emitInfo, OPCODE_MAX,
@@ -1096,6 +1145,9 @@ emit_clamp(slang_emit_info *emitInfo, slang_ir_node *n)
                            n->Children[0]->Store,
                            n->Children[1]->Store,
                            NULL);
+   if (!inst) {
+      return NULL;
+   }
 
    /* n->dest = min(tmp, ch[2]) */
    inst = emit_instruction(emitInfo, OPCODE_MIN,
@@ -1130,7 +1182,9 @@ emit_negation(slang_emit_info *emitInfo, slang_ir_node *n)
                            n->Children[0]->Store,
                            NULL,
                            NULL);
-   inst->SrcReg[0].NegateBase = NEGATE_XYZW;
+   if (inst) {
+      inst->SrcReg[0].Negate = NEGATE_XYZW;
+   }
    return inst;
 }
 
@@ -1186,6 +1240,9 @@ emit_fcall(slang_emit_info *emitInfo, slang_ir_node *n)
        * really just a NOP to attach the label to.
        */
       inst = new_instruction(emitInfo, OPCODE_BGNSUB);
+      if (!inst) {
+         return NULL;
+      }
       inst_comment(inst, n->Label->Name);
    }
 
@@ -1197,10 +1254,16 @@ emit_fcall(slang_emit_info *emitInfo, slang_ir_node *n)
    inst = prev_instruction(emitInfo);
    if (inst && inst->Opcode != OPCODE_RET) {
       inst = new_instruction(emitInfo, OPCODE_RET);
+      if (!inst) {
+         return NULL;
+      }
    }
 
    if (emitInfo->EmitBeginEndSub) {
       inst = new_instruction(emitInfo, OPCODE_ENDSUB);
+      if (!inst) {
+         return NULL;
+      }
       inst_comment(inst, n->Label->Name);
    }
 
@@ -1210,6 +1273,9 @@ emit_fcall(slang_emit_info *emitInfo, slang_ir_node *n)
 
    /* emit the function call */
    inst = new_instruction(emitInfo, OPCODE_CAL);
+   if (!inst) {
+      return NULL;
+   }
    /* The branch target is just the subroutine number (changed later) */
    inst->BranchTarget = subroutineId;
    inst_comment(inst, n->Label->Name);
@@ -1230,7 +1296,9 @@ emit_return(slang_emit_info *emitInfo, slang_ir_node *n)
    assert(n->Opcode == IR_RETURN);
    assert(n->Label);
    inst = new_instruction(emitInfo, OPCODE_RET);
-   inst->DstReg.CondMask = COND_TR;  /* always return */
+   if (inst) {
+      inst->DstReg.CondMask = COND_TR;  /* always return */
+   }
    return inst;
 }
 
@@ -1244,6 +1312,9 @@ emit_kill(slang_emit_info *emitInfo)
     * Note that ARB-KILL depends on sign of vector operand.
     */
    inst = new_instruction(emitInfo, OPCODE_KIL_NV);
+   if (!inst) {
+      return NULL;
+   }
    inst->DstReg.CondMask = COND_TR;  /* always kill */
 
    assert(emitInfo->prog->Target == GL_FRAGMENT_PROGRAM_ARB);
@@ -1259,16 +1330,33 @@ emit_tex(slang_emit_info *emitInfo, slang_ir_node *n)
 {
    struct prog_instruction *inst;
    gl_inst_opcode opcode;
+   GLboolean shadow = GL_FALSE;
 
-   if (n->Opcode == IR_TEX) {
+   switch (n->Opcode) {
+   case IR_TEX:
       opcode = OPCODE_TEX;
-   }
-   else if (n->Opcode == IR_TEXB) {
+      break;
+   case IR_TEX_SH:
+      opcode = OPCODE_TEX;
+      shadow = GL_TRUE;
+      break;
+   case IR_TEXB:
       opcode = OPCODE_TXB;
-   }
-   else {
-      assert(n->Opcode == IR_TEXP);
+      break;
+   case IR_TEXB_SH:
+      opcode = OPCODE_TXB;
+      shadow = GL_TRUE;
+      break;
+   case IR_TEXP:
+      opcode = OPCODE_TXP;
+      break;
+   case IR_TEXP_SH:
       opcode = OPCODE_TXP;
+      shadow = GL_TRUE;
+      break;
+   default:
+      _mesa_problem(NULL, "Bad IR TEX code");
+      return NULL;
    }
 
    if (n->Children[0]->Opcode == IR_ELEMENT) {
@@ -1299,6 +1387,11 @@ emit_tex(slang_emit_info *emitInfo, slang_ir_node *n)
                            n->Children[1]->Store,
                            NULL,
                            NULL);
+   if (!inst) {
+      return NULL;
+   }
+
+   inst->TexShadow = shadow;
 
    /* Store->Index is the uniform/sampler index */
    assert(n->Children[0]->Store->Index >= 0);
@@ -1335,7 +1428,8 @@ emit_copy(slang_emit_info *emitInfo, slang_ir_node *n)
    inst = emit(emitInfo, n->Children[1]);
 
    if (!n->Children[1]->Store || n->Children[1]->Store->Index < 0) {
-      if (!emitInfo->log->text) {
+      if (!emitInfo->log->text && !emitInfo->UnresolvedFunctions) {
+         /* XXX this error should have been caught in slang_codegen.c */
          slang_info_log_error(emitInfo->log, "invalid assignment");
       }
       return NULL;
@@ -1358,6 +1452,7 @@ emit_copy(slang_emit_info *emitInfo, slang_ir_node *n)
 
 #if PEEPHOLE_OPTIMIZATIONS
    if (inst &&
+       (n->Children[1]->Opcode != IR_SWIZZLE) &&
        _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) &&
@@ -1374,13 +1469,9 @@ emit_copy(slang_emit_info *emitInfo, slang_ir_node *n)
        * becomes:
        *   MUL a, x, y;
        */
-      if (n->Children[1]->Opcode != IR_SWIZZLE)
-         _slang_free_temp(emitInfo->vt, n->Children[1]->Store);
-      *n->Children[1]->Store = *n->Children[0]->Store;
 
       /* fixup the previous instruction (which stored the RHS result) */
       assert(n->Children[0]->Store->Index >= 0);
-
       storage_to_dst_reg(&inst->DstReg, n->Children[0]->Store);
       return inst;
    }
@@ -1401,6 +1492,9 @@ emit_copy(slang_emit_info *emitInfo, slang_ir_node *n)
                                     &srcStore,
                                     NULL,
                                     NULL);
+            if (!inst) {
+               return NULL;
+            }
             inst_comment(inst, "IR_COPY block");
             srcStore.Index++;
             dstStore.Index++;
@@ -1416,6 +1510,9 @@ emit_copy(slang_emit_info *emitInfo, slang_ir_node *n)
                                  n->Children[1]->Store,
                                  NULL,
                                  NULL);
+         if (!inst) {
+            return NULL;
+         }
          dstAnnot = storage_annotation(n->Children[0], emitInfo->prog);
          srcAnnot = storage_annotation(n->Children[1], emitInfo->prog);
          inst->Comment = instruction_annotation(inst->Opcode, dstAnnot,
@@ -1477,6 +1574,9 @@ emit_cond(slang_emit_info *emitInfo, slang_ir_node *n)
                                  n->Children[0]->Store,
                                  NULL,
                                  NULL);
+         if (!inst) {
+            return NULL;
+         }
          inst->CondUpdate = GL_TRUE;
          inst_comment(inst, "COND expr");
          _slang_free_temp(emitInfo->vt, n->Store);
@@ -1539,6 +1639,9 @@ emit_not(slang_emit_info *emitInfo, slang_ir_node *n)
                            n->Children[0]->Store,
                            &zero,
                            NULL);
+   if (!inst) {
+      return NULL;
+   }
    inst_comment(inst, "NOT");
 
    free_node_storage(emitInfo->vt, n->Children[0]);
@@ -1578,8 +1681,10 @@ emit_if(slang_emit_info *emitInfo, slang_ir_node *n)
    if (emitInfo->EmitHighLevelInstructions) {
       if (emitInfo->EmitCondCodes) {
          /* IF condcode THEN ... */
-         struct prog_instruction *ifInst;
-         ifInst = new_instruction(emitInfo, OPCODE_IF);
+         struct prog_instruction *ifInst = new_instruction(emitInfo, OPCODE_IF);
+         if (!ifInst) {
+            return NULL;
+         }
          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.
@@ -1587,17 +1692,25 @@ emit_if(slang_emit_info *emitInfo, slang_ir_node *n)
          ifInst->DstReg.CondSwizzle = writemask_to_swizzle(condWritemask);
       }
       else {
+         struct prog_instruction *inst;
+
          /* IF src[0] THEN ... */
-         emit_instruction(emitInfo, OPCODE_IF,
-                          NULL, /* dst */
-                          n->Children[0]->Store, /* op0 */
-                          NULL,
-                          NULL);
+         inst = emit_instruction(emitInfo, OPCODE_IF,
+                                 NULL, /* dst */
+                                 n->Children[0]->Store, /* op0 */
+                                 NULL,
+                                 NULL);
+         if (!inst) {
+            return NULL;
+         }
       }
    }
    else {
       /* conditional jump to else, or endif */
       struct prog_instruction *ifInst = new_instruction(emitInfo, OPCODE_BRA);
+      if (!ifInst) {
+         return NULL;
+      }
       ifInst->DstReg.CondMask = COND_EQ;  /* BRA if cond is zero */
       inst_comment(ifInst, "if zero");
       ifInst->DstReg.CondSwizzle = writemask_to_swizzle(condWritemask);
@@ -1610,16 +1723,22 @@ emit_if(slang_emit_info *emitInfo, slang_ir_node *n)
       /* have else body */
       elseInstLoc = prog->NumInstructions;
       if (emitInfo->EmitHighLevelInstructions) {
-         (void) new_instruction(emitInfo, OPCODE_ELSE);
+         struct prog_instruction *inst = new_instruction(emitInfo, OPCODE_ELSE);
+         if (!inst) {
+            return NULL;
+         }
+         prog->Instructions[ifInstLoc].BranchTarget = prog->NumInstructions - 1;
       }
       else {
          /* jump to endif instruction */
-         struct prog_instruction *inst;
-         inst = new_instruction(emitInfo, OPCODE_BRA);
+         struct prog_instruction *inst = new_instruction(emitInfo, OPCODE_BRA);
+         if (!inst) {
+            return NULL;
+         }
          inst_comment(inst, "else");
          inst->DstReg.CondMask = COND_TR;  /* always branch */
+         prog->Instructions[ifInstLoc].BranchTarget = prog->NumInstructions;
       }
-      prog->Instructions[ifInstLoc].BranchTarget = prog->NumInstructions;
       emit(emitInfo, n->Children[2]);
    }
    else {
@@ -1628,11 +1747,20 @@ emit_if(slang_emit_info *emitInfo, slang_ir_node *n)
    }
 
    if (emitInfo->EmitHighLevelInstructions) {
-      (void) new_instruction(emitInfo, OPCODE_ENDIF);
+      struct prog_instruction *inst = new_instruction(emitInfo, OPCODE_ENDIF);
+      if (!inst) {
+         return NULL;
+      }
    }
 
-   if (n->Children[2]) {
-      prog->Instructions[elseInstLoc].BranchTarget = prog->NumInstructions;
+   if (elseInstLoc) {
+      /* point ELSE instruction BranchTarget at ENDIF */
+      if (emitInfo->EmitHighLevelInstructions) {
+         prog->Instructions[elseInstLoc].BranchTarget = prog->NumInstructions - 1;
+      }
+      else {
+         prog->Instructions[elseInstLoc].BranchTarget = prog->NumInstructions;
+      }
    }
    return NULL;
 }
@@ -1649,7 +1777,10 @@ emit_loop(slang_emit_info *emitInfo, slang_ir_node *n)
    /* emit OPCODE_BGNLOOP */
    beginInstLoc = prog->NumInstructions;
    if (emitInfo->EmitHighLevelInstructions) {
-      (void) new_instruction(emitInfo, OPCODE_BGNLOOP);
+      struct prog_instruction *inst = new_instruction(emitInfo, OPCODE_BGNLOOP);
+      if (!inst) {
+         return NULL;
+      }
    }
 
    /* body */
@@ -1667,10 +1798,16 @@ emit_loop(slang_emit_info *emitInfo, slang_ir_node *n)
    if (emitInfo->EmitHighLevelInstructions) {
       /* emit OPCODE_ENDLOOP */
       endInst = new_instruction(emitInfo, OPCODE_ENDLOOP);
+      if (!endInst) {
+         return NULL;
+      }
    }
    else {
       /* emit unconditional BRA-nch */
       endInst = new_instruction(emitInfo, OPCODE_BRA);
+      if (!endInst) {
+         return NULL;
+      }
       endInst->DstReg.CondMask = COND_TR;  /* always true */
    }
    /* ENDLOOP's BranchTarget points to the BGNLOOP inst */
@@ -1683,7 +1820,7 @@ emit_loop(slang_emit_info *emitInfo, slang_ir_node *n)
 
    /* Done emitting loop code.  Now walk over the loop's linked list of
     * BREAK and CONT nodes, filling in their BranchTarget fields (which
-    * will point to the ENDLOOP+1 or BGNLOOP instructions, respectively).
+    * will point to the corresponding ENDLOOP instruction.
     */
    for (ir = n->List; ir; ir = ir->List) {
       struct prog_instruction *inst = prog->Instructions + ir->InstLocation;
@@ -1692,8 +1829,13 @@ emit_loop(slang_emit_info *emitInfo, slang_ir_node *n)
           ir->Opcode == IR_BREAK_IF_TRUE) {
          assert(inst->Opcode == OPCODE_BRK ||
                 inst->Opcode == OPCODE_BRA);
-         /* go to instruction after end of loop */
-         inst->BranchTarget = endInstLoc + 1;
+         /* go to instruction at end of loop */
+         if (emitInfo->EmitHighLevelInstructions) {
+            inst->BranchTarget = endInstLoc;
+         }
+         else {
+            inst->BranchTarget = endInstLoc + 1;
+         }
       }
       else {
          assert(ir->Opcode == IR_CONT ||
@@ -1740,7 +1882,9 @@ emit_cont_break(slang_emit_info *emitInfo, slang_ir_node *n)
    }
    n->InstLocation = emitInfo->prog->NumInstructions;
    inst = new_instruction(emitInfo, opcode);
-   inst->DstReg.CondMask = COND_TR;  /* always true */
+   if (inst) {
+      inst->DstReg.CondMask = COND_TR;  /* always true */
+   }
    return inst;
 }
 
@@ -1776,8 +1920,10 @@ emit_cont_break_if_true(slang_emit_info *emitInfo, slang_ir_node *n)
           */
          const GLuint condWritemask = inst->DstReg.WriteMask;
          inst = new_instruction(emitInfo, opcode);
-         inst->DstReg.CondMask = COND_NE;
-         inst->DstReg.CondSwizzle = writemask_to_swizzle(condWritemask);
+         if (inst) {
+            inst->DstReg.CondMask = COND_NE;
+            inst->DstReg.CondSwizzle = writemask_to_swizzle(condWritemask);
+         }
          return inst;
       }
       else {
@@ -1792,13 +1938,22 @@ emit_cont_break_if_true(slang_emit_info *emitInfo, slang_ir_node *n)
                                  n->Children[0]->Store,
                                  NULL,
                                  NULL);
+         if (!inst) {
+            return NULL;
+         }
          n->InstLocation = emitInfo->prog->NumInstructions;
 
          inst = new_instruction(emitInfo, opcode);
+         if (!inst) {
+            return NULL;
+         }
          inst = new_instruction(emitInfo, OPCODE_ENDIF);
+         if (!inst) {
+            return NULL;
+         }
 
          emitInfo->prog->Instructions[ifInstLoc].BranchTarget
-            = emitInfo->prog->NumInstructions;
+            = emitInfo->prog->NumInstructions - 1;
          return inst;
       }
    }
@@ -1806,13 +1961,34 @@ emit_cont_break_if_true(slang_emit_info *emitInfo, slang_ir_node *n)
       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);
+      if (inst) {
+         inst->DstReg.CondMask = COND_NE;
+         inst->DstReg.CondSwizzle = writemask_to_swizzle(condWritemask);
+      }
       return inst;
    }
 }
 
 
+/**
+ * Return the size of a swizzle mask given that some swizzle components
+ * may be NIL/undefined.  For example:
+ *  swizzle_size(".zzxx") = 4
+ *  swizzle_size(".xy??") = 2
+ *  swizzle_size(".w???") = 1
+ */
+static GLuint
+swizzle_size(GLuint swizzle)
+{
+   GLuint i;
+   for (i = 0; i < 4; i++) {
+      if (GET_SWZ(swizzle, i) == SWIZZLE_NIL)
+         return i;
+   }
+   return 4;
+}
+
+
 static struct prog_instruction *
 emit_swizzle(slang_emit_info *emitInfo, slang_ir_node *n)
 {
@@ -1820,14 +1996,25 @@ emit_swizzle(slang_emit_info *emitInfo, slang_ir_node *n)
 
    inst = emit(emitInfo, n->Children[0]);
 
-#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);
+   if (!n->Store->Parent) {
+      /* this covers a case such as "(b ? p : q).x" */
+      n->Store->Parent = n->Children[0]->Store;
+      assert(n->Store->Parent);
+   }
+
+   {
+      const GLuint swizzle = n->Store->Swizzle;
+      /* new storage is parent storage with updated Swizzle + Size fields */
+      _slang_copy_ir_storage(n->Store, n->Store->Parent);
+      /* Apply this node's swizzle to parent's storage */
+      n->Store->Swizzle = _slang_swizzle_swizzle(n->Store->Swizzle, swizzle);
+      /* Update size */
+      n->Store->Size = swizzle_size(n->Store->Swizzle);
+   }
+
    assert(!n->Store->Parent);
-#endif
+   assert(n->Store->Index >= 0);
+
    return inst;
 }
 
@@ -1924,6 +2111,9 @@ emit_array_element(slang_emit_info *emitInfo, slang_ir_node *n)
                                  indexStore, /* the index */
                                  &elemSizeStore,
                                  NULL);
+         if (!inst) {
+            return NULL;
+         }
 
          indexStore = indexTemp;
       }
@@ -1950,6 +2140,9 @@ emit_array_element(slang_emit_info *emitInfo, slang_ir_node *n)
                                  indexStore,     /* the index */
                                  &indirectArray, /* indirect array base */
                                  NULL);
+         if (!inst) {
+            return NULL;
+         }
 
          indexStore = indexTemp;
       }
@@ -2107,6 +2300,7 @@ emit_var_ref(slang_emit_info *emitInfo, slang_ir_node *n)
       if (index < 0) {
          /* error */
          char s[100];
+         /* XXX isn't this really an out of memory/resources error? */
          _mesa_snprintf(s, sizeof(s), "Undefined variable '%s'",
                         (char *) n->Var->a_name);
          slang_info_log_error(emitInfo->log, s);
@@ -2120,6 +2314,10 @@ emit_var_ref(slang_emit_info *emitInfo, slang_ir_node *n)
       /* mark var as used */
       _mesa_use_uniform(emitInfo->prog->Parameters, (char *) n->Var->a_name);
    }
+   else if (n->Store->File == PROGRAM_INPUT) {
+      assert(n->Store->Index >= 0);
+      emitInfo->prog->InputsRead |= (1 << n->Store->Index);
+   }
 
    if (n->Store->Index < 0) {
       /* probably ran out of registers */
@@ -2142,6 +2340,14 @@ emit(slang_emit_info *emitInfo, slang_ir_node *n)
       return NULL;
    }
 
+   if (n->Comment) {
+      inst = new_instruction(emitInfo, OPCODE_NOP);
+      if (inst) {
+         inst->Comment = _mesa_strdup(n->Comment);
+      }
+      inst = NULL;
+   }
+
    switch (n->Opcode) {
    case IR_SEQ:
       /* sequence of two sub-trees */
@@ -2224,6 +2430,7 @@ emit(slang_emit_info *emitInfo, slang_ir_node *n)
    case IR_POW:
    /* trinary operators */
    case IR_LRP:
+   case IR_CMP:
       return emit_arith(emitInfo, n);
 
    case IR_EQUAL:
@@ -2235,6 +2442,9 @@ emit(slang_emit_info *emitInfo, slang_ir_node *n)
    case IR_TEX:
    case IR_TEXB:
    case IR_TEXP:
+   case IR_TEX_SH:
+   case IR_TEXB_SH:
+   case IR_TEXP_SH:
       return emit_tex(emitInfo, n);
    case IR_NEG:
       return emit_negation(emitInfo, n);
@@ -2424,7 +2634,9 @@ _slang_emit_code(slang_ir_node *n, slang_var_table *vt,
       maxUniforms = ctx->Const.VertexProgram.MaxUniformComponents / 4;
    }
    if (prog->Parameters->NumParameters > maxUniforms) {
-      slang_info_log_error(log, "Constant/uniform register limit exceeded");
+      slang_info_log_error(log, "Constant/uniform register limit exceeded "
+                           "(max=%u vec4)", maxUniforms);
+
       return GL_FALSE;
    }
 
@@ -2434,6 +2646,9 @@ _slang_emit_code(slang_ir_node *n, slang_var_table *vt,
    if (withEnd) {
       struct prog_instruction *inst;
       inst = new_instruction(&emitInfo, OPCODE_END);
+      if (!inst) {
+         return GL_FALSE;
+      }
    }
 
    _slang_resolve_subroutines(&emitInfo);