return true;
 
    case nir_intrinsic_store_output: {
-      alu_node = ppir_node_create_dest(block, ppir_op_store_color, NULL, 0);
+      /* In simple cases where the store_output is ssa, that register
+       * can be directly marked as the output.
+       * If discard is used or the source is not ssa, things can get a
+       * lot more complicated, so don't try to optimize those and fall
+       * back to inserting a mov at the end.
+       * If the source node will only be able to output to pipeline
+       * registers, fall back to the mov as well. */
+      if (!block->comp->uses_discard && instr->src->is_ssa) {
+         node = block->comp->var_nodes[instr->src->ssa->index];
+         switch (node->op) {
+         case ppir_op_load_uniform:
+         case ppir_op_const:
+            break;
+         default:
+            node->is_end = 1;
+            return true;
+         }
+      }
+
+      alu_node = ppir_node_create_dest(block, ppir_op_mov, NULL, 0);
       if (!alu_node)
          return false;
 
       ppir_node_add_src(block->comp, &alu_node->node, alu_node->src, instr->src,
                         u_bit_consecutive(0, instr->num_components));
 
+      alu_node->node.is_end = 1;
+
       list_addtail(&alu_node->node.list, &block->node_list);
       return true;
    }
 static void ppir_add_ordering_deps(ppir_compiler *comp)
 {
    /* Some intrinsics do not have explicit dependencies and thus depend
-    * on instructions order. Consider discard_if and store_ouput as
-    * example. If we don't add fake dependency of discard_if to store_output
-    * scheduler may put store_output first and since store_output terminates
+    * on instructions order. Consider discard_if and the is_end node as
+    * example. If we don't add fake dependency of discard_if to is_end,
+    * scheduler may put the is_end first and since is_end terminates
     * shader on Utgard PP, rest of it will never be executed.
     * Add fake dependencies for discard/branch/store to preserve
     * instruction order.
          if (prev_node && ppir_node_is_root(node) && node->op != ppir_op_const) {
             ppir_node_add_dep(prev_node, node, ppir_dep_sequence);
          }
-         if (node->op == ppir_op_discard ||
-             node->op == ppir_op_store_color ||
+         if (node->is_end ||
+             node->op == ppir_op_discard ||
              node->op == ppir_op_store_temp ||
              node->op == ppir_op_branch) {
             prev_node = node;
       return false;
 
    comp->ra = ra;
+   comp->uses_discard = nir->info.fs.uses_discard;
 
    /* 1st pass: create ppir blocks */
    nir_foreach_function(function, nir) {
 
       .name = "const",
       .type = ppir_node_type_const,
    },
-   [ppir_op_store_color] = {
-      .name = "st_col",
-      .type = ppir_node_type_alu,
-      .slots = (int []) {
-         PPIR_INSTR_SLOT_ALU_VEC_ADD, PPIR_INSTR_SLOT_ALU_VEC_MUL,
-         PPIR_INSTR_SLOT_END
-      },
-   },
    [ppir_op_store_temp] = {
       .name = "st_temp",
       .type = ppir_node_type_store,
    ppir_node_add_dep(move, node, ppir_dep_src);
    list_addtail(&move->list, &node->list);
 
+   if (node->is_end) {
+      node->is_end = false;
+      move->is_end = true;
+   }
+
    return move;
 }
 
 
    return ppir_instr_insert_node(succ->instr, node);
 }
 
-static bool ppir_do_one_node_to_instr(ppir_block *block, ppir_node *node, ppir_node **next)
+static bool ppir_do_one_node_to_instr(ppir_block *block, ppir_node *node)
 {
    switch (node->type) {
    case ppir_node_type_alu:
       if (!node->instr && !create_new_instr(block, node))
          return false;
 
-      if (node->op == ppir_op_store_color)
-         node->instr->is_end = true;
-
       break;
    }
    case ppir_node_type_load:
 
 static bool ppir_do_node_to_instr(ppir_block *block, ppir_node *node)
 {
-   ppir_node *next = node;
-
    /* first try pipeline sched, if that didn't succeed try normal scheduling */
    if (!ppir_do_node_to_instr_try_insert(block, node))
-      if (!ppir_do_one_node_to_instr(block, node, &next))
+      if (!ppir_do_one_node_to_instr(block, node))
          return false;
 
-   /* next may have been updated in ppir_do_one_node_to_instr */
-   node = next;
+   if (node->is_end)
+      node->instr->is_end = true;
 
    /* we have to make sure the dep not be destroyed (due to
     * succ change) in ppir_do_node_to_instr, otherwise we can't