ir_visitor_status
ir_vec_index_to_cond_assign_visitor::visit_enter(ir_expression *ir)
{
	unsigned int i;

	for (i = 0; i < ir->get_num_operands(); i++)
	{
		ir->operands[i] = convert_vec_index_to_cond_assign(ir->operands[i]);
	}

	return visit_continue;
}
ir_rvalue *
ir_vec_index_to_cond_assign_visitor::convert_vector_extract_to_cond_assign(ir_rvalue *ir)
{
   ir_expression *const expr = ir->as_expression();

   if (expr == NULL || expr->operation != ir_binop_vector_extract)
      return ir;

   return convert_vec_index_to_cond_assign(ralloc_parent(ir),
                                           expr->operands[0],
                                           expr->operands[1],
                                           ir->type);
}
ir_visitor_status
ir_vec_index_to_cond_assign_visitor::visit_leave(ir_assignment *ir)
{
	ir_variable *index, *var;
	ir_dereference_variable *deref;
	ir_assignment *assign;
	int i;

	ir->rhs = convert_vec_index_to_cond_assign(ir->rhs);
	if (ir->condition)
		ir->condition = convert_vec_index_to_cond_assign(ir->condition);

	/* Last, handle the LHS */
	ir_dereference_array *orig_deref = ir->lhs->as_dereference_array();

	if (!orig_deref ||
		orig_deref->array->type->is_matrix() ||
		orig_deref->array->type->is_array())
		return visit_continue;

	void *mem_ctx = ralloc_parent(ir);

	check(orig_deref->array_index->type->base_type == GLSL_TYPE_INT);

	exec_list list;

	/* Store the index to a temporary to avoid reusing its tree. */
	index = new(ir)ir_variable(glsl_type::int_type, "vec_index_tmp_i",
		ir_var_temporary);
	list.push_tail(index);
	deref = new(ir)ir_dereference_variable(index);
	assign = new(ir)ir_assignment(deref, orig_deref->array_index, NULL);
	list.push_tail(assign);

	/* Store the RHS to a temporary to avoid reusing its tree. */
	var = new(ir)ir_variable(ir->rhs->type, "vec_index_tmp_v",
		ir_var_temporary);
	list.push_tail(var);
	deref = new(ir)ir_dereference_variable(var);
	assign = new(ir)ir_assignment(deref, ir->rhs, NULL);
	list.push_tail(assign);

	/* Generate a single comparison condition "mask" for all of the components
	* in the vector.
	*/
	ir_rvalue *const cond_deref =
		compare_index_block(&list, index, 0,
		orig_deref->array->type->vector_elements,
		mem_ctx);

	/* Generate a conditional move of each vector element to the temp. */
	for (i = 0; i < orig_deref->array->type->vector_elements; i++)
	{
		ir_rvalue *condition_swizzle =
			new(ir)ir_swizzle(cond_deref->clone(ir, NULL), i, 0, 0, 0, 1);


		/* Just clone the rest of the deref chain when trying to get at the
		* underlying variable.
		*/
		ir_rvalue *swizzle =
			new(ir)ir_swizzle(orig_deref->array->clone(mem_ctx, NULL),
			i, 0, 0, 0, 1);

		deref = new(ir)ir_dereference_variable(var);
		assign = new(ir)ir_assignment(swizzle, deref, condition_swizzle);
		list.push_tail(assign);
	}

	/* If the original assignment has a condition, respect that original
	* condition!  This is acomplished by wrapping the new conditional
	* assignments in an if-statement that uses the original condition.
	*/
	if (ir->condition != NULL)
	{
		/* No need to clone the condition because the IR that it hangs on is
		* going to be removed from the instruction sequence.
		*/
		ir_if *if_stmt = new(mem_ctx)ir_if(ir->condition);

		list.move_nodes_to(&if_stmt->then_instructions);
		ir->insert_before(if_stmt);
	}
	else
	{
		ir->insert_before(&list);
	}

	ir->remove();

	this->progress = true;

	return visit_continue;
}
	}

	ir->remove();

	this->progress = true;

	return visit_continue;
}

ir_visitor_status
ir_vec_index_to_cond_assign_visitor::visit_enter(ir_call *ir)
{
	foreach_iter(exec_list_iterator, iter, *ir)
	{
		ir_rvalue *param = (ir_rvalue *)iter.get();
		ir_rvalue *new_param = convert_vec_index_to_cond_assign(param);

		if (new_param != param)
		{
			param->replace_with(new_param);
		}
	}

	return visit_continue;
}

ir_visitor_status
ir_vec_index_to_cond_assign_visitor::visit_enter(ir_return *ir)
{
	if (ir->value)
	{