undo a debug/test change
[mesa.git] / src / mesa / shader / slang / slang_codegen.c
index 89a891562eaa77000d456d81e17a628680e05aa0..a25037cd61c3ac566611a000d744210494310f1a 100644 (file)
@@ -143,6 +143,15 @@ _slang_sizeof_type_specifier(const slang_type_specifier *spec)
       return 3 * 3;
    case SLANG_SPEC_MAT4:
       return 4 * 4;
+   case SLANG_SPEC_MAT23:
+   case SLANG_SPEC_MAT32:
+      return 2 * 3;
+   case SLANG_SPEC_MAT24:
+   case SLANG_SPEC_MAT42:
+      return 2 * 4;
+   case SLANG_SPEC_MAT34:
+   case SLANG_SPEC_MAT43:
+      return 3 * 4;
    case SLANG_SPEC_SAMPLER1D:
    case SLANG_SPEC_SAMPLER2D:
    case SLANG_SPEC_SAMPLER3D:
@@ -402,24 +411,6 @@ static slang_asm_info AsmInfo[] = {
 };
 
 
-/**
- * Recursively free an IR tree.
- */
-static void
-_slang_free_ir_tree(slang_ir_node *n)
-{
-#if 1
-   GLuint i;
-   if (!n)
-      return;
-   for (i = 0; i < 3; i++)
-      _slang_free_ir_tree(n->Children[i]);
-   /* Do not free n->BranchNode since it's a child elsewhere */
-   free(n);
-#endif
-}
-
-
 static slang_ir_node *
 new_node3(slang_ir_opcode op,
           slang_ir_node *c0, slang_ir_node *c1, slang_ir_node *c2)
@@ -476,23 +467,45 @@ new_label(slang_label *label)
 }
 
 static slang_ir_node *
-new_float_literal(const float v[4])
+new_float_literal(const float v[4], GLuint size)
 {
-   const GLuint size = (v[0] == v[1] && v[0] == v[2] && v[0] == v[3]) ? 1 : 4;
    slang_ir_node *n = new_node0(IR_FLOAT);
+   assert(size <= 4);
    COPY_4V(n->Value, v);
    /* allocate a storage object, but compute actual location (Index) later */
    n->Store = _slang_new_ir_storage(PROGRAM_CONSTANT, -1, size);
    return n;
 }
 
+
+static slang_ir_node *
+new_not(slang_ir_node *n)
+{
+   return new_node1(IR_NOT, n);
+}
+
+
+/**
+ * Inlined subroutine.
+ */
+static slang_ir_node *
+new_inlined_function_call(slang_ir_node *code, slang_label *name)
+{
+   slang_ir_node *n = new_node1(IR_FUNC, code);
+   assert(name);
+   if (n)
+      n->Label = name;
+   return n;
+}
+
+
 /**
  * Unconditional jump.
  */
 static slang_ir_node *
-new_jump(slang_label *dest)
+new_return(slang_label *dest)
 {
-   slang_ir_node *n = new_node0(IR_JUMP);
+   slang_ir_node *n = new_node0(IR_RETURN);
    assert(dest);
    if (n)
       n->Label = dest;
@@ -515,61 +528,46 @@ new_break(slang_ir_node *loopNode)
    assert(loopNode->Opcode == IR_LOOP);
    if (n) {
       /* insert this node at head of linked list */
-      n->BranchNode = loopNode->BranchNode;
-      loopNode->BranchNode = n;
+      n->List = loopNode->List;
+      loopNode->List = n;
    }
    return n;
 }
 
 
 /**
- * Make new IR_BREAK_IF_TRUE or IR_BREAK_IF_FALSE node.
+ * Make new IR_BREAK_IF_TRUE.
  */
 static slang_ir_node *
-new_break_if(slang_ir_node *loopNode, slang_ir_node *cond, GLboolean breakTrue)
+new_break_if_true(slang_ir_node *loopNode, slang_ir_node *cond)
 {
    slang_ir_node *n;
    assert(loopNode);
    assert(loopNode->Opcode == IR_LOOP);
-   n = new_node1(breakTrue ? IR_BREAK_IF_TRUE : IR_BREAK_IF_FALSE, cond);
+   n = new_node1(IR_BREAK_IF_TRUE, cond);
    if (n) {
       /* insert this node at head of linked list */
-      n->BranchNode = loopNode->BranchNode;
-      loopNode->BranchNode = n;
+      n->List = loopNode->List;
+      loopNode->List = n;
    }
    return n;
 }
 
 
 /**
- * Make new IR_CONT_IF_TRUE or IR_CONT_IF_FALSE node.
+ * Make new IR_CONT_IF_TRUE node.
  */
 static slang_ir_node *
-new_cont_if(slang_ir_node *loopNode, slang_ir_node *cond, GLboolean contTrue)
+new_cont_if_true(slang_ir_node *loopNode, slang_ir_node *cond)
 {
    slang_ir_node *n;
    assert(loopNode);
    assert(loopNode->Opcode == IR_LOOP);
-   n = new_node1(contTrue ? IR_CONT_IF_TRUE : IR_CONT_IF_FALSE, cond);
+   n = new_node1(IR_CONT_IF_TRUE, cond);
    if (n) {
       /* insert this node at head of linked list */
-      n->BranchNode = loopNode->BranchNode;
-      loopNode->BranchNode = n;
-   }
-   return n;
-}
-
-
-static slang_ir_node *
-new_cont(slang_ir_node *loopNode)
-{
-   slang_ir_node *n = new_node0(IR_CONT);
-   assert(loopNode);
-   assert(loopNode->Opcode == IR_LOOP);
-   if (n) {
-      /* insert this node at head of linked list */
-      n->BranchNode = loopNode->BranchNode;
-      loopNode->BranchNode = n;
+      n->List = loopNode->List;
+      loopNode->List = n;
    }
    return n;
 }
@@ -639,6 +637,24 @@ _slang_is_noop(const slang_operation *oper)
 }
 
 
+/**
+ * Recursively search tree for a node of the given type.
+ */
+static slang_operation *
+_slang_find_node_type(slang_operation *oper, slang_operation_type type)
+{
+   GLuint i;
+   if (oper->type == type)
+      return oper;
+   for (i = 0; i < oper->num_children; i++) {
+      slang_operation *p = _slang_find_node_type(&oper->children[i], type);
+      if (p)
+         return p;
+   }
+   return NULL;
+}
+
+
 /**
  * Produce inline code for a call to an assembly instruction.
  * XXX Note: children are passed as asm args in-order, not by name!
@@ -714,11 +730,8 @@ slang_substitute(slang_assemble_ctx *A, slang_operation *oper,
         GLuint i;
          v = _slang_locate_variable(oper->locals, id, GL_TRUE);
         if (!v) {
-           printf("var %s not found!\n", (char *) oper->a_id);
-            _slang_print_var_scope(oper->locals, 6);
-
-            abort();
-           break;
+            _mesa_problem(NULL, "var %s not found!\n", (char *) oper->a_id);
+            return;
         }
 
         /* look for a substitution */
@@ -749,7 +762,7 @@ slang_substitute(slang_assemble_ctx *A, slang_operation *oper,
    case SLANG_OPER_RETURN:
       /* do return replacement here too */
       assert(oper->num_children == 0 || oper->num_children == 1);
-      if (!_slang_is_noop(oper)) {
+      if (oper->num_children == 1 && !_slang_is_noop(&oper->children[0])) {
          /* replace:
           *   return expr;
           * with:
@@ -758,6 +771,14 @@ slang_substitute(slang_assemble_ctx *A, slang_operation *oper,
           * then do substitutions on the assignment.
           */
          slang_operation *blockOper, *assignOper, *returnOper;
+
+         /* check if function actually has a return type */
+         assert(A->CurFunction);
+         if (A->CurFunction->header.type.specifier.type == SLANG_SPEC_VOID) {
+            slang_info_log_error(A->log, "illegal return expression");
+            return;
+         }
+
          blockOper = slang_operation_new(1);
          blockOper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE;
          blockOper->num_children = 2;
@@ -777,7 +798,7 @@ slang_substitute(slang_assemble_ctx *A, slang_operation *oper,
          slang_operation_copy(&assignOper->children[1],
                               &oper->children[0]);
 
-         returnOper->type = SLANG_OPER_RETURN;
+         returnOper->type = SLANG_OPER_RETURN; /* return w/ no value */
          assert(returnOper->num_children == 0);
 
          /* do substitutions on the "__retVal = expr" sub-tree */
@@ -788,6 +809,14 @@ slang_substitute(slang_assemble_ctx *A, slang_operation *oper,
          slang_operation_copy(oper, blockOper);
          slang_operation_destruct(blockOper);
       }
+      else {
+         /* check if return value was expected */
+         assert(A->CurFunction);
+         if (A->CurFunction->header.type.specifier.type != SLANG_SPEC_VOID) {
+            slang_info_log_error(A->log, "return statement requires an expression");
+            return;
+         }
+      }
       break;
 
    case SLANG_OPER_ASSIGN:
@@ -839,6 +868,11 @@ slang_inline_function_call(slang_assemble_ctx * A, slang_function *fun,
    slang_variable **substOld;
    slang_operation **substNew;
    GLuint substCount, numCopyIn, i;
+   slang_function *prevFunction;
+
+   /* save / push */
+   prevFunction = A->CurFunction;
+   A->CurFunction = fun;
 
    /*assert(oper->type == SLANG_OPER_CALL); (or (matrix) multiply, etc) */
    assert(fun->param_count == totalArgs);
@@ -1060,6 +1094,10 @@ slang_inline_function_call(slang_assemble_ctx * A, slang_function *fun,
          fun->parameters->num_variables, numArgs);
    slang_print_tree(top, 0);
 #endif
+
+   /* pop */
+   A->CurFunction = prevFunction;
+
    return top;
 }
 
@@ -1085,16 +1123,28 @@ _slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun,
    else {
       /* non-assembly function */
       inlined = slang_inline_function_call(A, fun, oper, dest);
+      if (inlined && _slang_find_node_type(inlined, SLANG_OPER_RETURN)) {
+         /* This inlined function has one or more 'return' statements.
+          * So, we can't truly inline this function because we need to
+          * implement 'return' with RET (and CAL).
+          * XXX check if there's one 'return' and if it's the very last
+          * statement in the function - we can optimize that case.
+          */
+         assert(inlined->type == SLANG_OPER_BLOCK_NEW_SCOPE ||
+                inlined->type == SLANG_OPER_SEQUENCE);
+         inlined->type = SLANG_OPER_INLINED_CALL;
+         inlined->fun = fun;
+         inlined->label = _slang_label_new_unique((char*) fun->header.a_name);
+      }
    }
 
-   /* Replace the function call with the inlined block */
-#if 0
-   slang_operation_construct(oper);
-   slang_operation_copy(oper, inlined);
-#else
-   *oper = *inlined;  /* XXX slang_operation_copy() */
-#endif
+   if (!inlined)
+      return NULL;
 
+   /* Replace the function call with the inlined block */
+   slang_operation_destruct(oper);
+   *oper = *inlined;
+   /* XXX slang_operation_destruct(inlined) ??? */
 
 #if 0
    assert(inlined->locals);
@@ -1146,7 +1196,8 @@ make_writemask(const char *field)
          mask |= WRITEMASK_W;
          break;
       default:
-         abort();
+         _mesa_problem(NULL, "invalid writemask in make_writemask()");
+         return 0;
       }
       field++;
    }
@@ -1328,6 +1379,22 @@ _slang_is_constant_cond(const slang_operation *oper, GLboolean *value)
 }
 
 
+/**
+ * Test if an operation is a scalar or boolean.
+ */
+static GLboolean
+_slang_is_scalar_or_boolean(slang_assemble_ctx *A, slang_operation *oper)
+{
+   slang_typeinfo type;
+   GLint size;
+
+   slang_typeinfo_construct(&type);
+   _slang_typeof_operation(A, oper, &type);
+   size = _slang_sizeof_type_specifier(&type.spec);
+   slang_typeinfo_destruct(&type);
+   return size == 1;
+}
+
 
 /**
  * Generate loop code using high-level IR_LOOP instruction
@@ -1340,9 +1407,15 @@ _slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper)
     *    BREAK if !expr (child[0])
     *    body code (child[1])
     */
-   slang_ir_node *prevLoop, *loop, *cond, *breakIf, *body;
+   slang_ir_node *prevLoop, *loop, *breakIf, *body;
    GLboolean isConst, constTrue;
 
+   /* type-check expression */
+   if (!_slang_is_scalar_or_boolean(A, &oper->children[0])) {
+      slang_info_log_error(A->log, "scalar/boolean expression expected for 'while'");
+      return NULL;
+   }
+
    /* Check if loop condition is a constant */
    isConst = _slang_is_constant_cond(&oper->children[0], &constTrue);
 
@@ -1357,19 +1430,21 @@ _slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper)
    prevLoop = A->CurLoop;
    A->CurLoop = loop;
 
-   cond = new_cond(_slang_gen_operation(A, &oper->children[0]));
    if (isConst && constTrue) {
       /* while(nonzero constant), no conditional break */
       breakIf = NULL;
    }
    else {
-      breakIf = new_break_if(A->CurLoop, cond, GL_FALSE);
+      slang_ir_node *cond
+         = new_cond(new_not(_slang_gen_operation(A, &oper->children[0])));
+      breakIf = new_break_if_true(A->CurLoop, cond);
    }
    body = _slang_gen_operation(A, &oper->children[1]);
    loop->Children[0] = new_seq(breakIf, body);
 
    /* Do infinite loop detection */
-   if (loop->BranchNode == 0 && isConst && constTrue) {
+   /* loop->List is head of linked list of break/continue nodes */
+   if (!loop->List && isConst && constTrue) {
       /* infinite loop detected */
       A->CurLoop = prevLoop; /* clean-up */
       slang_info_log_error(A->log, "Infinite loop detected!");
@@ -1392,13 +1467,17 @@ _slang_gen_do(slang_assemble_ctx * A, const slang_operation *oper)
    /*
     * LOOP:
     *    body code (child[0])
-    *    BREAK if !expr (child[1])
+    *    tail code:
+    *       BREAK if !expr (child[1])
     */
-   slang_ir_node *prevLoop, *loop, *cond, *breakIf, *body;
+   slang_ir_node *prevLoop, *loop;
    GLboolean isConst, constTrue;
 
-   /* Check if loop condition is a constant */
-   isConst = _slang_is_constant_cond(&oper->children[0], &constTrue);
+   /* type-check expression */
+   if (!_slang_is_scalar_or_boolean(A, &oper->children[1])) {
+      slang_info_log_error(A->log, "scalar/boolean expression expected for 'do/while'");
+      return NULL;
+   }
 
    loop = new_loop(NULL);
 
@@ -1406,16 +1485,22 @@ _slang_gen_do(slang_assemble_ctx * A, const slang_operation *oper)
    prevLoop = A->CurLoop;
    A->CurLoop = loop;
 
-   body = _slang_gen_operation(A, &oper->children[0]);
-   cond = new_cond(_slang_gen_operation(A, &oper->children[1]));
+   /* loop body: */
+   loop->Children[0] = _slang_gen_operation(A, &oper->children[0]);
+
+   /* Check if loop condition is a constant */
+   isConst = _slang_is_constant_cond(&oper->children[1], &constTrue);
    if (isConst && constTrue) {
-      /* while(nonzero constant), no conditional break */
-      breakIf = NULL;
+      /* do { } while(1)   ==> no conditional break */
+      loop->Children[1] = NULL; /* no tail code */
    }
    else {
-      breakIf = new_break_if(A->CurLoop, cond, GL_FALSE);
+      slang_ir_node *cond
+         = new_cond(new_not(_slang_gen_operation(A, &oper->children[1])));
+      loop->Children[1] = new_break_if_true(A->CurLoop, cond);
    }
-   loop->Children[0] = new_seq(body, breakIf);
+
+   /* XXX we should do infinite loop detection, as above */
 
    /* pop loop, restore prev */
    A->CurLoop = prevLoop;
@@ -1431,11 +1516,12 @@ static slang_ir_node *
 _slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper)
 {
    /*
-    * init (child[0])
+    * init code (child[0])
     * LOOP:
     *    BREAK if !expr (child[1])
     *    body code (child[3])
-    *    incr code (child[2])   // XXX continue here
+    *    tail code:
+    *       incr code (child[2])   // XXX continue here
     */
    slang_ir_node *prevLoop, *loop, *cond, *breakIf, *body, *init, *incr;
 
@@ -1446,12 +1532,13 @@ _slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper)
    prevLoop = A->CurLoop;
    A->CurLoop = loop;
 
-   cond = new_cond(_slang_gen_operation(A, &oper->children[1]));
-   breakIf = new_break_if(A->CurLoop, cond, GL_FALSE);
+   cond = new_cond(new_not(_slang_gen_operation(A, &oper->children[1])));
+   breakIf = new_break_if_true(A->CurLoop, cond);
    body = _slang_gen_operation(A, &oper->children[3]);
    incr = _slang_gen_operation(A, &oper->children[2]);
-   loop->Children[0] = new_seq(breakIf,
-                               new_seq(body, incr));
+
+   loop->Children[0] = new_seq(breakIf, body);
+   loop->Children[1] = incr;  /* tail code */
 
    /* pop loop, restore prev */
    A->CurLoop = prevLoop;
@@ -1460,6 +1547,25 @@ _slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper)
 }
 
 
+static slang_ir_node *
+_slang_gen_continue(slang_assemble_ctx * A, const slang_operation *oper)
+{
+   slang_ir_node *n, *loopNode;
+   assert(oper->type == SLANG_OPER_CONTINUE);
+   loopNode = A->CurLoop;
+   assert(loopNode);
+   assert(loopNode->Opcode == IR_LOOP);
+   n = new_node0(IR_CONT);
+   if (n) {
+      n->Parent = loopNode;
+      /* insert this node at head of linked list */
+      n->List = loopNode->List;
+      loopNode->List = n;
+   }
+   return n;
+}
+
+
 /**
  * Determine if the given operation is of a specific type.
  */
@@ -1485,7 +1591,7 @@ static slang_ir_node *
 _slang_gen_if(slang_assemble_ctx * A, const slang_operation *oper)
 {
    /*
-    * eval expr (child[0]), updating condcodes
+    * eval expr (child[0])
     * IF expr THEN
     *    if-body code
     * ELSE
@@ -1494,13 +1600,32 @@ _slang_gen_if(slang_assemble_ctx * A, const slang_operation *oper)
     */
    const GLboolean haveElseClause = !_slang_is_noop(&oper->children[2]);
    slang_ir_node *ifNode, *cond, *ifBody, *elseBody;
+   GLboolean isConst, constTrue;
+
+   /* type-check expression */
+   if (!_slang_is_scalar_or_boolean(A, &oper->children[0])) {
+      slang_info_log_error(A->log, "scalar/boolean expression expected for 'if'");
+      return NULL;
+   }
+
+   isConst = _slang_is_constant_cond(&oper->children[0], &constTrue);
+   if (isConst) {
+      if (constTrue) {
+         /* if (true) ... */
+         return _slang_gen_operation(A, &oper->children[1]);
+      }
+      else {
+         /* if (false) ... */
+         return _slang_gen_operation(A, &oper->children[2]);
+      }
+   }
 
    cond = _slang_gen_operation(A, &oper->children[0]);
    cond = new_cond(cond);
 
    if (is_operation_type(&oper->children[1], SLANG_OPER_BREAK)) {
       /* Special case: generate a conditional break */
-      ifBody = new_break_if(A->CurLoop, cond, GL_TRUE);
+      ifBody = new_break_if_true(A->CurLoop, cond);
       if (haveElseClause) {
          elseBody = _slang_gen_operation(A, &oper->children[2]);
          return new_seq(ifBody, elseBody);
@@ -1509,7 +1634,7 @@ _slang_gen_if(slang_assemble_ctx * A, const slang_operation *oper)
    }
    else if (is_operation_type(&oper->children[1], SLANG_OPER_CONTINUE)) {
       /* Special case: generate a conditional break */
-      ifBody = new_cont_if(A->CurLoop, cond, GL_TRUE);
+      ifBody = new_cont_if_true(A->CurLoop, cond);
       if (haveElseClause) {
          elseBody = _slang_gen_operation(A, &oper->children[2]);
          return new_seq(ifBody, elseBody);
@@ -1530,6 +1655,52 @@ _slang_gen_if(slang_assemble_ctx * A, const slang_operation *oper)
 
 
 
+static slang_ir_node *
+_slang_gen_not(slang_assemble_ctx * A, const slang_operation *oper)
+{
+   slang_ir_node *n;
+
+   assert(oper->type == SLANG_OPER_NOT);
+
+   /* type-check expression */
+   if (!_slang_is_scalar_or_boolean(A, &oper->children[0])) {
+      slang_info_log_error(A->log,
+                           "scalar/boolean expression expected for '!'");
+      return NULL;
+   }
+
+   n = _slang_gen_operation(A, &oper->children[0]);
+   if (n)
+      return new_not(n);
+   else
+      return NULL;
+}
+
+
+static slang_ir_node *
+_slang_gen_xor(slang_assemble_ctx * A, const slang_operation *oper)
+{
+   slang_ir_node *n1, *n2;
+
+   assert(oper->type == SLANG_OPER_LOGICALXOR);
+
+   if (!_slang_is_scalar_or_boolean(A, &oper->children[0]) ||
+       !_slang_is_scalar_or_boolean(A, &oper->children[0])) {
+      slang_info_log_error(A->log,
+                           "scalar/boolean expressions expected for '^^'");
+      return NULL;
+   }
+
+   n1 = _slang_gen_operation(A, &oper->children[0]);
+   if (!n1)
+      return NULL;
+   n2 = _slang_gen_operation(A, &oper->children[1]);
+   if (!n2)
+      return NULL;
+   return new_node2(IR_NOTEQUAL, n1, n2);
+}
+
+
 /**
  * Generate IR node for storage of a temporary of given size.
  */
@@ -1629,7 +1800,7 @@ _slang_gen_select(slang_assemble_ctx *A, slang_operation *oper)
    tree = new_seq(ifNode, tmpVar);
    tree = new_seq(tmpDecl, tree);
 
-   slang_print_ir(tree, 10);
+   /*_slang_print_ir_tree(tree, 10);*/
    return tree;
 }
 
@@ -1702,26 +1873,25 @@ _slang_gen_logical_or(slang_assemble_ctx *A, slang_operation *oper)
 static slang_ir_node *
 _slang_gen_return(slang_assemble_ctx * A, slang_operation *oper)
 {
-   if (oper->num_children == 0 ||
-       (oper->num_children == 1 &&
-        oper->children[0].type == SLANG_OPER_VOID)) {
-      /* Convert from:
-       *   return;
-       * To:
-       *   goto __endOfFunction;
-       */
-      slang_ir_node *n;
-      slang_operation gotoOp;
-      slang_operation_construct(&gotoOp);
-      gotoOp.type = SLANG_OPER_GOTO;
-      gotoOp.label = A->curFuncEndLabel;
-      assert(gotoOp.label);
+   const GLboolean haveReturnValue
+      = (oper->num_children == 1 &&
+         oper->children[0].type != SLANG_OPER_VOID);
+
+   /* error checking */
+   assert(A->CurFunction);
+   if (haveReturnValue &&
+       A->CurFunction->header.type.specifier.type == SLANG_SPEC_VOID) {
+      slang_info_log_error(A->log, "illegal return expression");
+      return NULL;
+   }
+   else if (!haveReturnValue &&
+       A->CurFunction->header.type.specifier.type != SLANG_SPEC_VOID) {
+      slang_info_log_error(A->log, "return statement requires an expression");
+      return NULL;
+   }
 
-      /* assemble the new code */
-      n = _slang_gen_operation(A, &gotoOp);
-      /* destroy temp code */
-      slang_operation_destruct(&gotoOp);
-      return n;
+   if (!haveReturnValue) {
+      return new_return(A->curFuncEndLabel);
    }
    else {
       /*
@@ -1729,9 +1899,9 @@ _slang_gen_return(slang_assemble_ctx * A, slang_operation *oper)
        *   return expr;
        * To:
        *   __retVal = expr;
-       *   goto __endOfFunction;
+       *   return;  // goto __endOfFunction
        */
-      slang_operation *block, *assign, *jump;
+      slang_operation *assign;
       slang_atom a_retVal;
       slang_ir_node *n;
 
@@ -1742,21 +1912,15 @@ _slang_gen_return(slang_assemble_ctx * A, slang_operation *oper)
       {
          slang_variable *v
             = _slang_locate_variable(oper->locals, a_retVal, GL_TRUE);
-         assert(v);
+         if (!v) {
+            /* trying to return a value in a void-valued function */
+            return NULL;
+         }
       }
 #endif
 
-      block = slang_operation_new(1);
-      block->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE;
-      assert(block->locals);
-      block->locals->outer_scope = oper->locals->outer_scope;
-      block->num_children = 2;
-      block->children = slang_operation_new(2);
-
-      /* child[0]: __retVal = expr; */
-      assign = &block->children[0];
+      assign = slang_operation_new(1);
       assign->type = SLANG_OPER_ASSIGN;
-      assign->locals->outer_scope = block->locals;
       assign->num_children = 2;
       assign->children = slang_operation_new(2);
       /* lhs (__retVal) */
@@ -1767,22 +1931,11 @@ _slang_gen_return(slang_assemble_ctx * A, slang_operation *oper)
       /* XXX we might be able to avoid this copy someday */
       slang_operation_copy(&assign->children[1], &oper->children[0]);
 
-      /* child[1]: goto __endOfFunction */
-      jump = &block->children[1];
-      jump->type = SLANG_OPER_GOTO;
-      assert(A->curFuncEndLabel);
-      /* XXX don't call function? */
-      jump->label = A->curFuncEndLabel;
-      assert(jump->label);
-
-#if 0 /* debug */
-      printf("NEW RETURN:\n");
-      slang_print_tree(block, 0);
-#endif
-
       /* assemble the new code */
-      n = _slang_gen_operation(A, block);
-      slang_operation_delete(block);
+      n = new_seq(_slang_gen_operation(A, assign),
+                  new_return(A->curFuncEndLabel));
+
+      slang_operation_delete(assign);
       return n;
    }
 }
@@ -1842,6 +1995,9 @@ _slang_gen_declaration(slang_assemble_ctx *A, slang_operation *oper)
       _slang_simplify(v->initializer, &A->space, A->atoms); 
       rhs = _slang_gen_operation(A, v->initializer);
 #endif
+      if (!rhs)
+         return NULL;
+
       assert(rhs);
       init = new_node2(IR_MOVE, var, rhs);
       /*
@@ -1993,6 +2149,26 @@ _slang_gen_swizzle(slang_ir_node *child, GLuint swizzle)
 static slang_ir_node *
 _slang_gen_assignment(slang_assemble_ctx * A, slang_operation *oper)
 {
+   if (oper->children[0].type == SLANG_OPER_IDENTIFIER) {
+      /* Check that var is writeable */
+      slang_variable *var
+         = _slang_locate_variable(oper->children[0].locals,
+                                  oper->children[0].a_id, GL_TRUE);
+      if (!var) {
+         slang_info_log_error(A->log, "undefined variable '%s'",
+                              (char *) oper->children[0].a_id);
+         return NULL;
+      }
+      if (var->type.qualifier == SLANG_QUAL_CONST ||
+          var->type.qualifier == SLANG_QUAL_ATTRIBUTE ||
+          var->type.qualifier == SLANG_QUAL_UNIFORM) {
+         slang_info_log_error(A->log,
+                              "illegal assignment to read-only variable '%s'",
+                              (char *) oper->children[0].a_id);
+         return NULL;
+      }
+   }
+
    if (oper->children[0].type == SLANG_OPER_IDENTIFIER &&
        oper->children[1].type == SLANG_OPER_CALL) {
       /* Special case of:  x = f(a, b)
@@ -2017,7 +2193,8 @@ _slang_gen_assignment(slang_assemble_ctx * A, slang_operation *oper)
              lhs->Store->File != PROGRAM_TEMPORARY &&
              lhs->Store->File != PROGRAM_VARYING &&
              lhs->Store->File != PROGRAM_UNDEFINED) {
-            slang_info_log_error(A->log, "Assignment to read-only variable");
+            slang_info_log_error(A->log,
+                                 "illegal assignment to read-only l-value");
             return NULL;
          }
       }
@@ -2358,22 +2535,24 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper)
    case SLANG_OPER_BREAK:
       if (!A->CurLoop) {
          slang_info_log_error(A->log, "'break' not in loop");
+         return NULL;
       }
       return new_break(A->CurLoop);
    case SLANG_OPER_CONTINUE:
       if (!A->CurLoop) {
          slang_info_log_error(A->log, "'continue' not in loop");
+         return NULL;
       }
-      return new_cont(A->CurLoop);
+      return _slang_gen_continue(A, oper);
    case SLANG_OPER_DISCARD:
       return new_node0(IR_KILL);
 
    case SLANG_OPER_EQUAL:
-      return new_node2(IR_SEQUAL,
+      return new_node2(IR_EQUAL,
                       _slang_gen_operation(A, &oper->children[0]),
                       _slang_gen_operation(A, &oper->children[1]));
    case SLANG_OPER_NOTEQUAL:
-      return new_node2(IR_SNEQUAL,
+      return new_node2(IR_NOTEQUAL,
                       _slang_gen_operation(A, &oper->children[0]),
                       _slang_gen_operation(A, &oper->children[1]));
    case SLANG_OPER_GREATER:
@@ -2479,20 +2658,9 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper)
         return n;
       }
    case SLANG_OPER_LOGICALXOR:
-      {
-        slang_ir_node *n;
-         assert(oper->num_children == 2);
-        n = _slang_gen_function_call_name(A, "__logicalXor", oper, NULL);
-        return n;
-      }
+      return _slang_gen_xor(A, oper);
    case SLANG_OPER_NOT:
-      {
-        slang_ir_node *n;
-         assert(oper->num_children == 1);
-        n = _slang_gen_function_call_name(A, "__logicalNot", oper, NULL);
-        return n;
-      }
-
+      return _slang_gen_not(A, oper);
    case SLANG_OPER_SELECT:  /* b ? x : y */
       {
         slang_ir_node *n;
@@ -2508,8 +2676,6 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper)
                                            oper, NULL);
    case SLANG_OPER_RETURN:
       return _slang_gen_return(A, oper);
-   case SLANG_OPER_GOTO:
-      return new_jump(oper->label);
    case SLANG_OPER_LABEL:
       return new_label(oper->label);
    case SLANG_OPER_IDENTIFIER:
@@ -2525,7 +2691,7 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper)
    case SLANG_OPER_LITERAL_INT:
       /* fall-through */
    case SLANG_OPER_LITERAL_BOOL:
-      return new_float_literal(oper->literal);
+      return new_float_literal(oper->literal, oper->literal_size);
 
    case SLANG_OPER_POSTINCREMENT:   /* var++ */
       {
@@ -2556,6 +2722,7 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper)
         return n;
       }
 
+   case SLANG_OPER_INLINED_CALL:
    case SLANG_OPER_SEQUENCE:
       {
          slang_ir_node *tree = NULL;
@@ -2564,6 +2731,9 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper)
             slang_ir_node *n = _slang_gen_operation(A, &oper->children[i]);
             tree = tree ? new_seq(tree, n) : n;
          }
+         if (oper->type == SLANG_OPER_INLINED_CALL) {
+            tree = new_inlined_function_call(tree, oper->label);
+         }
          return tree;
       }
 
@@ -2573,8 +2743,8 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper)
       return new_node0(IR_NOP);
 
    default:
-      printf("Unhandled node type %d\n", oper->type);
-      abort();
+      _mesa_problem(NULL, "bad node type %d in _slang_gen_operation",
+                    oper->type);
       return new_node0(IR_NOP);
    }
 
@@ -2773,6 +2943,23 @@ _slang_codegen_function(slang_assemble_ctx * A, slang_function * fun)
       /* we only really generate code for main, all other functions get
        * inlined.
        */
+#if 0
+      /* do some basic error checking though */
+      if (fun->header.type.specifier.type != SLANG_SPEC_VOID) {
+         /* check that non-void functions actually return something */
+         slang_operation *op
+            = _slang_find_node_type(fun->body, SLANG_OPER_RETURN);
+         if (!op) {
+            slang_info_log_error(A->log,
+                                 "function \"%s\" has no return statement",
+                                 (char *) fun->header.a_name);
+            printf(
+                   "function \"%s\" has no return statement\n",
+                   (char *) fun->header.a_name);
+            return GL_FALSE;
+         }
+      }
+#endif
       return GL_TRUE;  /* not an error */
    }
 
@@ -2785,6 +2972,8 @@ _slang_codegen_function(slang_assemble_ctx * A, slang_function * fun)
    assert(A->program->Parameters );
    assert(A->program->Varying);
    assert(A->vartable);
+   A->CurLoop = NULL;
+   A->CurFunction = fun;
 
    /* fold constant expressions, etc. */
    _slang_simplify(fun->body, &A->space, A->atoms);
@@ -2825,7 +3014,7 @@ _slang_codegen_function(slang_assemble_ctx * A, slang_function * fun)
 #endif
 #if 0
    printf("************* IR for %s *******\n", (char*)fun->header.a_name);
-   slang_print_ir(n, 0);
+   _slang_print_ir_tree(n, 0);
 #endif
 #if 0
    printf("************* End codegen function ************\n\n");