[Mesa-dev] [PATCH v2 5/8] glsl: pass mem_ctx to constant_expression_value(...) and friends

Timothy Arceri tarceri at itsqueeze.com
Thu Aug 10 10:42:29 UTC 2017


The main motivation for this is that threaded compilation can fall
over if we were to allocate IR inside constant_expression_value()
when calling it on a builtin. This is because builtins are shared
across the whole OpenGL context.

f81ede469910d worked around the problem by cloning the entire
builtin before constant_expression_value() could be called on
it. However cloning the whole function each time we referenced
it lead to a significant reduction in the GLSL IR compiler
performance. This change along with the following patch
helps fix that performance regression.

Other advantages are that we reduce the number of calls to
ralloc_parent(), and for loop unrolling we free constants after
they are used rather than leaving them hanging around.

Cc: Kenneth Graunke <kenneth at whitecape.org>
Cc: Lionel Landwerlin <lionel.g.landwerlin at intel.com>
---
 src/compiler/glsl/ast_array_index.cpp            |   2 +-
 src/compiler/glsl/ast_function.cpp               |  17 ++--
 src/compiler/glsl/ast_to_hir.cpp                 |  15 ++-
 src/compiler/glsl/ast_type.cpp                   |   7 +-
 src/compiler/glsl/ir.h                           |  37 +++++---
 src/compiler/glsl/ir_constant_expression.cpp     | 114 +++++++++++++++--------
 src/compiler/glsl/linker.cpp                     |   2 +-
 src/compiler/glsl/loop_controls.cpp              |   6 +-
 src/compiler/glsl/loop_unroll.cpp                |   2 +-
 src/compiler/glsl/lower_buffer_access.cpp        |   2 +-
 src/compiler/glsl/lower_distance.cpp             |   3 +-
 src/compiler/glsl/lower_tess_level.cpp           |   3 +-
 src/compiler/glsl/lower_vec_index_to_swizzle.cpp |   7 +-
 src/compiler/glsl/lower_vector_derefs.cpp        |   3 +-
 src/compiler/glsl/lower_vector_insert.cpp        |   3 +-
 src/compiler/glsl/opt_algebraic.cpp              |   9 +-
 src/compiler/glsl/opt_constant_folding.cpp       |   5 +-
 src/compiler/glsl/opt_constant_propagation.cpp   |   3 +-
 src/compiler/glsl/opt_constant_variable.cpp      |   2 +-
 src/compiler/glsl/opt_if_simplification.cpp      |   3 +-
 src/mesa/program/ir_to_mesa.cpp                  |   6 +-
 src/mesa/state_tracker/st_glsl_to_tgsi.cpp       |   7 +-
 22 files changed, 168 insertions(+), 90 deletions(-)

diff --git a/src/compiler/glsl/ast_array_index.cpp b/src/compiler/glsl/ast_array_index.cpp
index efddbed6ea..3b30f6858e 100644
--- a/src/compiler/glsl/ast_array_index.cpp
+++ b/src/compiler/glsl/ast_array_index.cpp
@@ -160,21 +160,21 @@ _mesa_ast_array_index_to_hir(void *mem_ctx,
       } else if (!idx->type->is_scalar()) {
          _mesa_glsl_error(& idx_loc, state, "array index must be scalar");
       }
    }
 
    /* If the array index is a constant expression and the array has a
     * declared size, ensure that the access is in-bounds.  If the array
     * index is not a constant expression, ensure that the array has a
     * declared size.
     */
-   ir_constant *const const_index = idx->constant_expression_value();
+   ir_constant *const const_index = idx->constant_expression_value(mem_ctx);
    if (const_index != NULL && idx->type->is_integer()) {
       const int idx = const_index->value.i[0];
       const char *type_name = "error";
       unsigned bound = 0;
 
       /* From page 24 (page 30 of the PDF) of the GLSL 1.50 spec:
        *
        *    "It is illegal to declare an array with a size, and then
        *    later (in the same shader) index the same array with an
        *    integral constant expression greater than or equal to the
diff --git a/src/compiler/glsl/ast_function.cpp b/src/compiler/glsl/ast_function.cpp
index f7e90fba5b..b121ab9210 100644
--- a/src/compiler/glsl/ast_function.cpp
+++ b/src/compiler/glsl/ast_function.cpp
@@ -30,32 +30,35 @@
 #include "builtin_functions.h"
 
 static ir_rvalue *
 convert_component(ir_rvalue *src, const glsl_type *desired_type);
 
 static unsigned
 process_parameters(exec_list *instructions, exec_list *actual_parameters,
                    exec_list *parameters,
                    struct _mesa_glsl_parse_state *state)
 {
+   void *mem_ctx = state;
    unsigned count = 0;
 
    foreach_list_typed(ast_node, ast, link, parameters) {
       /* We need to process the parameters first in order to know if we can
        * raise or not a unitialized warning. Calling set_is_lhs silence the
        * warning for now. Raising the warning or not will be checked at
        * verify_parameter_modes.
        */
       ast->set_is_lhs(true);
       ir_rvalue *result = ast->hir(instructions, state);
 
-      ir_constant *const constant = result->constant_expression_value();
+      ir_constant *const constant =
+         result->constant_expression_value(mem_ctx);
+
       if (constant != NULL)
          result = constant;
 
       actual_parameters->push_tail(result);
       count++;
    }
 
    return count;
 }
 
@@ -511,21 +514,22 @@ generate_call(exec_list *instructions, ir_function_signature *sig,
     *         - a built-in function call whose arguments are all constant
     *           expressions, with the exception of the texture lookup
     *           functions.  The built-in functions dFdx, dFdy, and fwidth must
     *           return 0 when evaluated inside an initializer with an argument
     *           that is a constant expression."
     *
     * If the function call is a constant expression, don't generate any
     * instructions; just generate an ir_constant.
     */
    if (state->is_version(120, 100)) {
-      ir_constant *value = sig->constant_expression_value(actual_parameters,
+      ir_constant *value = sig->constant_expression_value(ctx,
+                                                          actual_parameters,
                                                           NULL);
       if (value != NULL) {
          return value;
       }
    }
 
    ir_dereference_variable *deref = NULL;
    if (!sig->return_type->is_void()) {
       /* Create a new temporary to hold the return value. */
       char *const name = ir_variable::temporaries_allocate_names
@@ -932,21 +936,21 @@ convert_component(ir_rvalue *src, const glsl_type *desired_type)
             ir_expression(ir_unop_pack_image_2x32, desired_type, src);
          break;
       }
       break;
    }
 
    assert(result != NULL);
    assert(result->type == desired_type);
 
    /* Try constant folding; it may fold in the conversion we just added. */
-   ir_constant *const constant = result->constant_expression_value();
+   ir_constant *const constant = result->constant_expression_value(ctx);
    return (constant != NULL) ? (ir_rvalue *) constant : (ir_rvalue *) result;
 }
 
 
 /**
  * Perform automatic type and constant conversion of constructor parameters
  *
  * This implements the rules in the "Implicit Conversions" rules, not the
  * "Conversion and Scalar Constructors".
  *
@@ -960,39 +964,40 @@ convert_component(ir_rvalue *src, const glsl_type *desired_type)
  * \param state  GLSL compiler state
  *
  * \return
  * If the attempt to convert into a constant expression succeeds, \c true is
  * returned. Otherwise \c false is returned.
  */
 static bool
 implicitly_convert_component(ir_rvalue * &from, const glsl_base_type to,
                              struct _mesa_glsl_parse_state *state)
 {
+   void *mem_ctx = state;
    ir_rvalue *result = from;
 
    if (to != from->type->base_type) {
       const glsl_type *desired_type =
          glsl_type::get_instance(to,
                                  from->type->vector_elements,
                                  from->type->matrix_columns);
 
       if (from->type->can_implicitly_convert_to(desired_type, state)) {
          /* Even though convert_component() implements the constructor
           * conversion rules (not the implicit conversion rules), its safe
           * to use it here because we already checked that the implicit
           * conversion is legal.
           */
          result = convert_component(from, desired_type);
       }
    }
 
-   ir_rvalue *const constant = result->constant_expression_value();
+   ir_rvalue *const constant = result->constant_expression_value(mem_ctx);
 
    if (constant != NULL)
       result = constant;
 
    if (from != result) {
       from->replace_with(result);
       from = result;
    }
 
    return constant != NULL;
@@ -2147,21 +2152,21 @@ ast_function_expression::hir(exec_list *instructions,
             if (!matrix->type->is_matrix())
                continue;
 
             /* Create a temporary containing the matrix. */
             ir_variable *var = new(ctx) ir_variable(matrix->type, "matrix_tmp",
                                                     ir_var_temporary);
             instructions->push_tail(var);
             instructions->push_tail(
                new(ctx) ir_assignment(new(ctx) ir_dereference_variable(var),
                                       matrix, NULL));
-            var->constant_value = matrix->constant_expression_value();
+            var->constant_value = matrix->constant_expression_value(ctx);
 
             /* Replace the matrix with dereferences of its columns. */
             for (int i = 0; i < matrix->type->matrix_columns; i++) {
                matrix->insert_before(
                   new (ctx) ir_dereference_array(var,
                                                  new(ctx) ir_constant(i)));
             }
             matrix->remove();
          }
       }
@@ -2214,21 +2219,21 @@ ast_function_expression::hir(exec_list *instructions,
                                        ir->type->vector_elements,
                                        ir->type->matrix_columns);
          }
 
          ir_rvalue *result = convert_component(ir, desired_type);
 
          /* Attempt to convert the parameter to a constant valued expression.
           * After doing so, track whether or not all the parameters to the
           * constructor are trivially constant valued expressions.
           */
-         ir_rvalue *const constant = result->constant_expression_value();
+         ir_rvalue *const constant = result->constant_expression_value(ctx);
 
          if (constant != NULL)
             result = constant;
          else
             all_parameters_are_constant = false;
 
          if (result != ir) {
             ir->replace_with(result);
          }
       }
diff --git a/src/compiler/glsl/ast_to_hir.cpp b/src/compiler/glsl/ast_to_hir.cpp
index ee80605232..a07c0ecf95 100644
--- a/src/compiler/glsl/ast_to_hir.cpp
+++ b/src/compiler/glsl/ast_to_hir.cpp
@@ -1838,21 +1838,21 @@ ast_expression::do_hir(exec_list *instructions,
        *  "Except for array indexing, structure member selection, and
        *   parentheses, opaque variables are not allowed to be operands in
        *   expressions; such use results in a compile-time error."
        */
       if (type->contains_opaque()) {
          _mesa_glsl_error(&loc, state, "opaque variables cannot be operands "
                           "of the ?: operator");
          error_emitted = true;
       }
 
-      ir_constant *cond_val = op[0]->constant_expression_value();
+      ir_constant *cond_val = op[0]->constant_expression_value(ctx);
 
       if (then_instructions.is_empty()
           && else_instructions.is_empty()
           && cond_val != NULL) {
          result = cond_val->value.b[0] ? op[1] : op[2];
       } else {
          /* The copy to conditional_tmp reads the whole array. */
          if (type->is_array()) {
             mark_whole_array_access(op[1]);
             mark_whole_array_access(op[2]);
@@ -2222,20 +2222,22 @@ ast_compound_statement::hir(exec_list *instructions,
 }
 
 /**
  * Evaluate the given exec_node (which should be an ast_node representing
  * a single array dimension) and return its integer value.
  */
 static unsigned
 process_array_size(exec_node *node,
                    struct _mesa_glsl_parse_state *state)
 {
+   void *mem_ctx = state;
+
    exec_list dummy_instructions;
 
    ast_node *array_size = exec_node_data(ast_node, node, link);
 
    /**
     * Dimensions other than the outermost dimension can by unsized if they
     * are immediately sized by a constructor or initializer.
     */
    if (((ast_expression*)array_size)->oper == ast_unsized_array_dim)
       return 0;
@@ -2254,21 +2256,21 @@ process_array_size(exec_node *node,
                        "array size must be integer type");
       return 0;
    }
 
    if (!ir->type->is_scalar()) {
       _mesa_glsl_error(& loc, state,
                        "array size must be scalar type");
       return 0;
    }
 
-   ir_constant *const size = ir->constant_expression_value();
+   ir_constant *const size = ir->constant_expression_value(mem_ctx);
    if (size == NULL ||
        (state->is_version(120, 300) &&
         array_size->has_sequence_subexpression())) {
       _mesa_glsl_error(& loc, state, "array size must be a "
                        "constant valued expression");
       return 0;
    }
 
    if (size->value.i[0] <= 0) {
       _mesa_glsl_error(& loc, state, "array size must be > 0");
@@ -4319,20 +4321,21 @@ get_variable_being_redeclared(ir_variable *var, YYLTYPE loc,
 
 /**
  * Generate the IR for an initializer in a variable declaration
  */
 ir_rvalue *
 process_initializer(ir_variable *var, ast_declaration *decl,
                     ast_fully_specified_type *type,
                     exec_list *initializer_instructions,
                     struct _mesa_glsl_parse_state *state)
 {
+   void *mem_ctx = state;
    ir_rvalue *result = NULL;
 
    YYLTYPE initializer_loc = decl->initializer->get_location();
 
    /* From page 24 (page 30 of the PDF) of the GLSL 1.10 spec:
     *
     *    "All uniform variables are read-only and are initialized either
     *    directly by an application via API commands, or indirectly by
     *    OpenGL."
     */
@@ -4453,21 +4456,23 @@ process_initializer(ir_variable *var, ast_declaration *decl,
           *     hence cannot be used to declare an array size.
           *
           *     RESOLUTION: The result of a sequence operator is not a
           *     constant-expression."
           *
           * Section 4.3.3 (Constant Expressions) of the GLSL 4.30.9 spec
           * contains language almost identical to the section 4.3.3 in the
           * GLSL ES 3.00.4 spec.  This is a new limitation for these GLSL
           * versions.
           */
-         ir_constant *constant_value = rhs->constant_expression_value();
+         ir_constant *constant_value =
+            rhs->constant_expression_value(mem_ctx);
+
          if (!constant_value ||
              (state->is_version(430, 300) &&
               decl->initializer->has_sequence_subexpression())) {
             const char *const variable_mode =
                (type->qualifier.flags.q.constant)
                ? "const"
                : ((type->qualifier.flags.q.uniform) ? "uniform" : "global");
 
             /* If ARB_shading_language_420pack is enabled, initializers of
              * const-qualified local variables do not have to be constant
@@ -4513,21 +4518,21 @@ process_initializer(ir_variable *var, ast_declaration *decl,
          do_assignment(initializer_instructions, state,
                        NULL,
                        lhs, rhs,
                        &result, true,
                        true,
                        type->get_location());
          initializer_type = result->type;
       } else
          initializer_type = rhs->type;
 
-      var->constant_initializer = rhs->constant_expression_value();
+      var->constant_initializer = rhs->constant_expression_value(mem_ctx);
       var->data.has_initializer = true;
 
       /* If the declared variable is an unsized array, it must inherrit
        * its full type from the initializer.  A declaration such as
        *
        *     uniform float a[] = float[](1.0, 2.0, 3.0, 3.0);
        *
        * becomes
        *
        *     uniform float a[4] = float[](1.0, 2.0, 3.0, 3.0);
@@ -6645,21 +6650,21 @@ ast_case_label::hir(exec_list *instructions,
       new(ctx) ir_dereference_variable(state->switch_state.is_fallthru_var);
 
    ir_rvalue *const true_val = new(ctx) ir_constant(true);
 
    /* If not default case, ... */
    if (this->test_value != NULL) {
       /* Conditionally set fallthru state based on
        * comparison of cached test expression value to case label.
        */
       ir_rvalue *const label_rval = this->test_value->hir(instructions, state);
-      ir_constant *label_const = label_rval->constant_expression_value();
+      ir_constant *label_const = label_rval->constant_expression_value(ctx);
 
       if (!label_const) {
          YYLTYPE loc = this->test_value->get_location();
 
          _mesa_glsl_error(& loc, state,
                           "switch statement case label must be a "
                           "constant expression");
 
          /* Stuff a dummy value in to allow processing to continue. */
          label_const = new(ctx) ir_constant(0);
diff --git a/src/compiler/glsl/ast_type.cpp b/src/compiler/glsl/ast_type.cpp
index 63c026ad06..ee8697ba21 100644
--- a/src/compiler/glsl/ast_type.cpp
+++ b/src/compiler/glsl/ast_type.cpp
@@ -859,21 +859,23 @@ ast_layout_expression::process_qualifier_constant(struct _mesa_glsl_parse_state
       min_value = 1;
 
    for (exec_node *node = layout_const_expressions.get_head_raw();
         !node->is_tail_sentinel(); node = node->next) {
 
       exec_list dummy_instructions;
       ast_node *const_expression = exec_node_data(ast_node, node, link);
 
       ir_rvalue *const ir = const_expression->hir(&dummy_instructions, state);
 
-      ir_constant *const const_int = ir->constant_expression_value();
+      ir_constant *const const_int =
+         ir->constant_expression_value(ralloc_parent(ir));
+
       if (const_int == NULL || !const_int->type->is_integer()) {
          YYLTYPE loc = const_expression->get_location();
          _mesa_glsl_error(&loc, state, "%s must be an integral constant "
                           "expression", qual_indentifier);
          return false;
       }
 
       if (const_int->value.i[0] < min_value) {
          YYLTYPE loc = const_expression->get_location();
          _mesa_glsl_error(&loc, state, "%s layout qualifier is invalid "
@@ -914,21 +916,22 @@ process_qualifier_constant(struct _mesa_glsl_parse_state *state,
 {
    exec_list dummy_instructions;
 
    if (const_expression == NULL) {
       *value = 0;
       return true;
    }
 
    ir_rvalue *const ir = const_expression->hir(&dummy_instructions, state);
 
-   ir_constant *const const_int = ir->constant_expression_value();
+   ir_constant *const const_int =
+      ir->constant_expression_value(ralloc_parent(ir));
    if (const_int == NULL || !const_int->type->is_integer()) {
       _mesa_glsl_error(loc, state, "%s must be an integral constant "
                        "expression", qual_indentifier);
       return false;
    }
 
    if (const_int->value.i[0] < 0) {
       _mesa_glsl_error(loc, state, "%s layout qualifier is invalid (%d < 0)",
                        qual_indentifier, const_int->value.u[0]);
       return false;
diff --git a/src/compiler/glsl/ir.h b/src/compiler/glsl/ir.h
index 170759abeb..e2b72772a2 100644
--- a/src/compiler/glsl/ir.h
+++ b/src/compiler/glsl/ir.h
@@ -222,21 +222,22 @@ public:
 
    virtual ir_rvalue *clone(void *mem_ctx, struct hash_table *) const;
 
    virtual void accept(ir_visitor *v)
    {
       v->visit(this);
    }
 
    virtual ir_visitor_status accept(ir_hierarchical_visitor *);
 
-   virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL);
+   virtual ir_constant *constant_expression_value(void *mem_ctx,
+                                                  struct hash_table *variable_context = NULL);
 
    ir_rvalue *as_rvalue_to_saturate();
 
    virtual bool is_lvalue(const struct _mesa_glsl_parse_state *state = NULL) const
    {
       return false;
    }
 
    /**
     * Get the variable that is ultimately referenced by an r-value
@@ -1163,21 +1164,23 @@ public:
       v->visit(this);
    }
 
    virtual ir_visitor_status accept(ir_hierarchical_visitor *);
 
    /**
     * Attempt to evaluate this function as a constant expression,
     * given a list of the actual parameters and the variable context.
     * Returns NULL for non-built-ins.
     */
-   ir_constant *constant_expression_value(exec_list *actual_parameters, struct hash_table *variable_context);
+   ir_constant *constant_expression_value(void *mem_ctx,
+                                          exec_list *actual_parameters,
+                                          struct hash_table *variable_context);
 
    /**
     * Get the name of the function for which this is a signature
     */
    const char *function_name() const;
 
    /**
     * Get a handle to the function for which this is a signature
     *
     * There is no setter function, this function returns a \c const pointer,
@@ -1266,21 +1269,22 @@ private:
     * Helper function to run a list of instructions for constant
     * expression evaluation.
     *
     * The hash table represents the values of the visible variables.
     * There are no scoping issues because the table is indexed on
     * ir_variable pointers, not variable names.
     *
     * Returns false if the expression is not constant, true otherwise,
     * and the value in *result if result is non-NULL.
     */
-   bool constant_expression_evaluate_expression_list(const struct exec_list &body,
+   bool constant_expression_evaluate_expression_list(void *mem_ctx,
+                                                     const struct exec_list &body,
 						     struct hash_table *variable_context,
 						     ir_constant **result);
 };
 
 
 /**
  * Header for tracking multiple overloaded functions with the same name.
  * Contains a list of ir_function_signatures representing each of the
  * actual functions.
  */
@@ -1422,21 +1426,22 @@ public:
     *
     * \note
     * Since a write mask is supplied, the LHS must already be a bare
     * \c ir_dereference.  The cannot be any swizzles in the LHS.
     */
    ir_assignment(ir_dereference *lhs, ir_rvalue *rhs, ir_rvalue *condition,
 		 unsigned write_mask);
 
    virtual ir_assignment *clone(void *mem_ctx, struct hash_table *ht) const;
 
-   virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL);
+   virtual ir_constant *constant_expression_value(void *mem_ctx,
+                                                  struct hash_table *variable_context = NULL);
 
    virtual void accept(ir_visitor *v)
    {
       v->visit(this);
    }
 
    virtual ir_visitor_status accept(ir_hierarchical_visitor *);
 
    /**
     * Get a whole variable written by an assignment
@@ -1528,21 +1533,22 @@ public:
    /**
     * Attempt to constant-fold the expression
     *
     * The "variable_context" hash table links ir_variable * to ir_constant *
     * that represent the variables' values.  \c NULL represents an empty
     * context.
     *
     * If the expression cannot be constant folded, this method will return
     * \c NULL.
     */
-   virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL);
+   virtual ir_constant *constant_expression_value(void *mem_ctx,
+                                                  struct hash_table *variable_context = NULL);
 
    /**
     * This is only here for ir_reader to used for testing purposes please use
     * the precomputed num_operands field if you need the number of operands.
     */
    static unsigned get_num_operands(ir_expression_operation);
 
    /**
     * Return whether the expression operates on vectors horizontally.
     */
@@ -1609,21 +1615,22 @@ public:
 	   exec_list *actual_parameters,
 	   ir_variable *var, ir_rvalue *array_idx)
       : ir_instruction(ir_type_call), return_deref(return_deref), callee(callee), sub_var(var), array_idx(array_idx)
    {
       assert(callee->return_type != NULL);
       actual_parameters->move_nodes_to(& this->actual_parameters);
    }
 
    virtual ir_call *clone(void *mem_ctx, struct hash_table *ht) const;
 
-   virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL);
+   virtual ir_constant *constant_expression_value(void *mem_ctx,
+                                                  struct hash_table *variable_context = NULL);
 
    virtual void accept(ir_visitor *v)
    {
       v->visit(this);
    }
 
    virtual ir_visitor_status accept(ir_hierarchical_visitor *);
 
    /**
     * Get the name of the function being called.
@@ -1831,21 +1838,22 @@ public:
    ir_texture(enum ir_texture_opcode op)
       : ir_rvalue(ir_type_texture),
         op(op), sampler(NULL), coordinate(NULL), projector(NULL),
         shadow_comparator(NULL), offset(NULL)
    {
       memset(&lod_info, 0, sizeof(lod_info));
    }
 
    virtual ir_texture *clone(void *mem_ctx, struct hash_table *) const;
 
-   virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL);
+   virtual ir_constant *constant_expression_value(void *mem_ctx,
+                                                  struct hash_table *variable_context = NULL);
 
    virtual void accept(ir_visitor *v)
    {
       v->visit(this);
    }
 
    virtual ir_visitor_status accept(ir_hierarchical_visitor *);
 
    virtual bool equals(const ir_instruction *ir,
                        enum ir_node_type ignore = ir_type_unset) const;
@@ -1928,21 +1936,22 @@ class ir_swizzle : public ir_rvalue {
 public:
    ir_swizzle(ir_rvalue *, unsigned x, unsigned y, unsigned z, unsigned w,
               unsigned count);
 
    ir_swizzle(ir_rvalue *val, const unsigned *components, unsigned count);
 
    ir_swizzle(ir_rvalue *val, ir_swizzle_mask mask);
 
    virtual ir_swizzle *clone(void *mem_ctx, struct hash_table *) const;
 
-   virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL);
+   virtual ir_constant *constant_expression_value(void *mem_ctx,
+                                                  struct hash_table *variable_context = NULL);
 
    /**
     * Construct an ir_swizzle from the textual representation.  Can fail.
     */
    static ir_swizzle *create(ir_rvalue *, const char *, unsigned vector_length);
 
    virtual void accept(ir_visitor *v)
    {
       v->visit(this);
    }
@@ -1994,21 +2003,22 @@ protected:
 };
 
 
 class ir_dereference_variable : public ir_dereference {
 public:
    ir_dereference_variable(ir_variable *var);
 
    virtual ir_dereference_variable *clone(void *mem_ctx,
 					  struct hash_table *) const;
 
-   virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL);
+   virtual ir_constant *constant_expression_value(void *mem_ctx,
+                                                  struct hash_table *variable_context = NULL);
 
    virtual bool equals(const ir_instruction *ir,
                        enum ir_node_type ignore = ir_type_unset) const;
 
    /**
     * Get the variable that is ultimately referenced by an r-value
     */
    virtual ir_variable *variable_referenced() const
    {
       return this->var;
@@ -2041,21 +2051,22 @@ public:
 
 class ir_dereference_array : public ir_dereference {
 public:
    ir_dereference_array(ir_rvalue *value, ir_rvalue *array_index);
 
    ir_dereference_array(ir_variable *var, ir_rvalue *array_index);
 
    virtual ir_dereference_array *clone(void *mem_ctx,
 				       struct hash_table *) const;
 
-   virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL);
+   virtual ir_constant *constant_expression_value(void *mem_ctx,
+                                                  struct hash_table *variable_context = NULL);
 
    virtual bool equals(const ir_instruction *ir,
                        enum ir_node_type ignore = ir_type_unset) const;
 
    /**
     * Get the variable that is ultimately referenced by an r-value
     */
    virtual ir_variable *variable_referenced() const
    {
       return this->array->variable_referenced();
@@ -2078,21 +2089,22 @@ private:
 
 class ir_dereference_record : public ir_dereference {
 public:
    ir_dereference_record(ir_rvalue *value, const char *field);
 
    ir_dereference_record(ir_variable *var, const char *field);
 
    virtual ir_dereference_record *clone(void *mem_ctx,
 					struct hash_table *) const;
 
-   virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL);
+   virtual ir_constant *constant_expression_value(void *mem_ctx,
+                                                  struct hash_table *variable_context = NULL);
 
    /**
     * Get the variable that is ultimately referenced by an r-value
     */
    virtual ir_variable *variable_referenced() const
    {
       return this->record->variable_referenced();
    }
 
    virtual void accept(ir_visitor *v)
@@ -2149,21 +2161,22 @@ public:
     */
    ir_constant(const ir_constant *c, unsigned i);
 
    /**
     * Return a new ir_constant of the specified type containing all zeros.
     */
    static ir_constant *zero(void *mem_ctx, const glsl_type *type);
 
    virtual ir_constant *clone(void *mem_ctx, struct hash_table *) const;
 
-   virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL);
+   virtual ir_constant *constant_expression_value(void *mem_ctx,
+                                                  struct hash_table *variable_context = NULL);
 
    virtual void accept(ir_visitor *v)
    {
       v->visit(this);
    }
 
    virtual ir_visitor_status accept(ir_hierarchical_visitor *);
 
    virtual bool equals(const ir_instruction *ir,
                        enum ir_node_type ignore = ir_type_unset) const;
diff --git a/src/compiler/glsl/ir_constant_expression.cpp b/src/compiler/glsl/ir_constant_expression.cpp
index a493657d35..25b00a749f 100644
--- a/src/compiler/glsl/ir_constant_expression.cpp
+++ b/src/compiler/glsl/ir_constant_expression.cpp
@@ -502,21 +502,21 @@ constant_referenced(const ir_dereference *deref,
    default:
       assert(!"Should not get here.");
       break;
    }
 
    return store != NULL;
 }
 
 
 ir_constant *
-ir_rvalue::constant_expression_value(struct hash_table *)
+ir_rvalue::constant_expression_value(void *mem_ctx, struct hash_table *)
 {
    assert(this->type->is_error());
    return NULL;
 }
 
 static uint32_t
 bitfield_reverse(uint32_t v)
 {
    /* http://graphics.stanford.edu/~seander/bithacks.html#BitReverseObvious */
    uint32_t r = v; // r will be reversed bits of v; first get LSB of v
@@ -621,32 +621,37 @@ bitfield_insert(uint32_t base, uint32_t insert, int offset, int bits)
 
       insert <<= offset;
       insert &= insert_mask;
       base &= ~insert_mask;
 
       return base | insert;
    }
 }
 
 ir_constant *
-ir_expression::constant_expression_value(struct hash_table *variable_context)
+ir_expression::constant_expression_value(void *mem_ctx,
+                                         struct hash_table *variable_context)
 {
+   assert(mem_ctx);
+
    if (this->type->is_error())
       return NULL;
 
    ir_constant *op[ARRAY_SIZE(this->operands)] = { NULL, };
    ir_constant_data data;
 
    memset(&data, 0, sizeof(data));
 
    for (unsigned operand = 0; operand < this->num_operands; operand++) {
-      op[operand] = this->operands[operand]->constant_expression_value(variable_context);
+      op[operand] =
+         this->operands[operand]->constant_expression_value(mem_ctx,
+                                                            variable_context);
       if (!op[operand])
          return NULL;
    }
 
    if (op[1] != NULL)
       switch (this->operation) {
       case ir_binop_lshift:
       case ir_binop_rshift:
       case ir_binop_ldexp:
       case ir_binop_interpolate_at_offset:
@@ -669,114 +674,119 @@ ir_expression::constant_expression_value(struct hash_table *variable_context)
     */
    unsigned c0_inc = op0_scalar ? 0 : 1;
    unsigned c1_inc = op1_scalar ? 0 : 1;
    unsigned components;
    if (op1_scalar || !op[1]) {
       components = op[0]->type->components();
    } else {
       components = op[1]->type->components();
    }
 
-   void *ctx = ralloc_parent(this);
-
    /* Handle array operations here, rather than below. */
    if (op[0]->type->is_array()) {
       assert(op[1] != NULL && op[1]->type->is_array());
       switch (this->operation) {
       case ir_binop_all_equal:
-         return new(ctx) ir_constant(op[0]->has_value(op[1]));
+         return new(mem_ctx) ir_constant(op[0]->has_value(op[1]));
       case ir_binop_any_nequal:
-         return new(ctx) ir_constant(!op[0]->has_value(op[1]));
+         return new(mem_ctx) ir_constant(!op[0]->has_value(op[1]));
       default:
          break;
       }
       return NULL;
    }
 
 #include "ir_expression_operation_constant.h"
 
-   return new(ctx) ir_constant(this->type, &data);
+   return new(mem_ctx) ir_constant(this->type, &data);
 }
 
 
 ir_constant *
-ir_texture::constant_expression_value(struct hash_table *)
+ir_texture::constant_expression_value(void *mem_ctx, struct hash_table *)
 {
    /* texture lookups aren't constant expressions */
    return NULL;
 }
 
 
 ir_constant *
-ir_swizzle::constant_expression_value(struct hash_table *variable_context)
+ir_swizzle::constant_expression_value(void *mem_ctx,
+                                      struct hash_table *variable_context)
 {
-   ir_constant *v = this->val->constant_expression_value(variable_context);
+   assert(mem_ctx);
+
+   ir_constant *v = this->val->constant_expression_value(mem_ctx,
+                                                         variable_context);
 
    if (v != NULL) {
       ir_constant_data data = { { 0 } };
 
       const unsigned swiz_idx[4] = {
          this->mask.x, this->mask.y, this->mask.z, this->mask.w
       };
 
       for (unsigned i = 0; i < this->mask.num_components; i++) {
          switch (v->type->base_type) {
          case GLSL_TYPE_UINT:
          case GLSL_TYPE_INT:   data.u[i] = v->value.u[swiz_idx[i]]; break;
          case GLSL_TYPE_FLOAT: data.f[i] = v->value.f[swiz_idx[i]]; break;
          case GLSL_TYPE_BOOL:  data.b[i] = v->value.b[swiz_idx[i]]; break;
          case GLSL_TYPE_DOUBLE:data.d[i] = v->value.d[swiz_idx[i]]; break;
          default:              assert(!"Should not get here."); break;
          }
       }
 
-      void *ctx = ralloc_parent(this);
-      return new(ctx) ir_constant(this->type, &data);
+      return new(mem_ctx) ir_constant(this->type, &data);
    }
    return NULL;
 }
 
 
 ir_constant *
-ir_dereference_variable::constant_expression_value(struct hash_table *variable_context)
+ir_dereference_variable::constant_expression_value(void *mem_ctx,
+                                                   struct hash_table *variable_context)
 {
    assert(var);
+   assert(mem_ctx);
 
    /* Give priority to the context hashtable, if it exists */
    if (variable_context) {
       hash_entry *entry = _mesa_hash_table_search(variable_context, var);
 
       if(entry)
          return (ir_constant *) entry->data;
    }
 
    /* The constant_value of a uniform variable is its initializer,
     * not the lifetime constant value of the uniform.
     */
    if (var->data.mode == ir_var_uniform)
       return NULL;
 
    if (!var->constant_value)
       return NULL;
 
-   return var->constant_value->clone(ralloc_parent(var), NULL);
+   return var->constant_value->clone(mem_ctx, NULL);
 }
 
 
 ir_constant *
-ir_dereference_array::constant_expression_value(struct hash_table *variable_context)
+ir_dereference_array::constant_expression_value(void *mem_ctx,
+                                                struct hash_table *variable_context)
 {
-   ir_constant *array = this->array->constant_expression_value(variable_context);
-   ir_constant *idx = this->array_index->constant_expression_value(variable_context);
+   assert(mem_ctx);
+
+   ir_constant *array = this->array->constant_expression_value(mem_ctx, variable_context);
+   ir_constant *idx = this->array_index->constant_expression_value(mem_ctx, variable_context);
 
    if ((array != NULL) && (idx != NULL)) {
-      void *ctx = ralloc_parent(this);
       if (array->type->is_matrix()) {
          /* Array access of a matrix results in a vector.
           */
          const unsigned column = idx->value.u[0];
 
          const glsl_type *const column_type = array->type->column_type();
 
          /* Offset in the constant matrix to the first element of the column
           * to be extracted.
           */
@@ -802,150 +812,170 @@ ir_dereference_array::constant_expression_value(struct hash_table *variable_cont
             for (unsigned i = 0; i < column_type->vector_elements; i++)
                data.d[i] = array->value.d[mat_idx + i];
 
             break;
 
          default:
             assert(!"Should not get here.");
             break;
          }
 
-         return new(ctx) ir_constant(column_type, &data);
+         return new(mem_ctx) ir_constant(column_type, &data);
       } else if (array->type->is_vector()) {
          const unsigned component = idx->value.u[0];
 
-         return new(ctx) ir_constant(array, component);
+         return new(mem_ctx) ir_constant(array, component);
       } else {
          const unsigned index = idx->value.u[0];
-         return array->get_array_element(index)->clone(ctx, NULL);
+         return array->get_array_element(index)->clone(mem_ctx, NULL);
       }
    }
    return NULL;
 }
 
 
 ir_constant *
-ir_dereference_record::constant_expression_value(struct hash_table *)
+ir_dereference_record::constant_expression_value(void *mem_ctx,
+                                                 struct hash_table *)
 {
-   ir_constant *v = this->record->constant_expression_value();
+   assert(mem_ctx);
+
+   ir_constant *v = this->record->constant_expression_value(mem_ctx);
 
    return (v != NULL) ? v->get_record_field(this->field_idx) : NULL;
 }
 
 
 ir_constant *
-ir_assignment::constant_expression_value(struct hash_table *)
+ir_assignment::constant_expression_value(void *mem_ctx, struct hash_table *)
 {
    /* FINISHME: Handle CEs involving assignment (return RHS) */
    return NULL;
 }
 
 
 ir_constant *
-ir_constant::constant_expression_value(struct hash_table *)
+ir_constant::constant_expression_value(void *mem_ctx, struct hash_table *)
 {
    return this;
 }
 
 
 ir_constant *
-ir_call::constant_expression_value(struct hash_table *variable_context)
+ir_call::constant_expression_value(void *mem_ctx, struct hash_table *variable_context)
 {
-   return this->callee->constant_expression_value(&this->actual_parameters, variable_context);
+   assert(mem_ctx);
+
+   return this->callee->constant_expression_value(mem_ctx,
+                                                  &this->actual_parameters,
+                                                  variable_context);
 }
 
 
-bool ir_function_signature::constant_expression_evaluate_expression_list(const struct exec_list &body,
+bool ir_function_signature::constant_expression_evaluate_expression_list(void *mem_ctx,
+                                                                        const struct exec_list &body,
                                                                          struct hash_table *variable_context,
                                                                          ir_constant **result)
 {
+   assert(mem_ctx);
+
    foreach_in_list(ir_instruction, inst, &body) {
       switch(inst->ir_type) {
 
          /* (declare () type symbol) */
       case ir_type_variable: {
          ir_variable *var = inst->as_variable();
          _mesa_hash_table_insert(variable_context, var, ir_constant::zero(this, var->type));
          break;
       }
 
          /* (assign [condition] (write-mask) (ref) (value)) */
       case ir_type_assignment: {
          ir_assignment *asg = inst->as_assignment();
          if (asg->condition) {
-            ir_constant *cond = asg->condition->constant_expression_value(variable_context);
+            ir_constant *cond =
+               asg->condition->constant_expression_value(mem_ctx,
+                                                         variable_context);
             if (!cond)
                return false;
             if (!cond->get_bool_component(0))
                break;
          }
 
          ir_constant *store = NULL;
          int offset = 0;
 
          if (!constant_referenced(asg->lhs, variable_context, store, offset))
             return false;
 
-         ir_constant *value = asg->rhs->constant_expression_value(variable_context);
+         ir_constant *value =
+            asg->rhs->constant_expression_value(mem_ctx, variable_context);
 
          if (!value)
             return false;
 
          store->copy_masked_offset(value, offset, asg->write_mask);
          break;
       }
 
          /* (return (expression)) */
       case ir_type_return:
          assert (result);
-         *result = inst->as_return()->value->constant_expression_value(variable_context);
+         *result =
+            inst->as_return()->value->constant_expression_value(mem_ctx,
+                                                                variable_context);
          return *result != NULL;
 
          /* (call name (ref) (params))*/
       case ir_type_call: {
          ir_call *call = inst->as_call();
 
          /* Just say no to void functions in constant expressions.  We
           * don't need them at that point.
           */
 
          if (!call->return_deref)
             return false;
 
          ir_constant *store = NULL;
          int offset = 0;
 
          if (!constant_referenced(call->return_deref, variable_context,
                                   store, offset))
             return false;
 
-         ir_constant *value = call->constant_expression_value(variable_context);
+         ir_constant *value =
+            call->constant_expression_value(mem_ctx, variable_context);
 
          if(!value)
             return false;
 
          store->copy_offset(value, offset);
          break;
       }
 
          /* (if condition (then-instructions) (else-instructions)) */
       case ir_type_if: {
          ir_if *iif = inst->as_if();
 
-         ir_constant *cond = iif->condition->constant_expression_value(variable_context);
+         ir_constant *cond =
+            iif->condition->constant_expression_value(mem_ctx,
+                                                      variable_context);
          if (!cond || !cond->type->is_boolean())
             return false;
 
          exec_list &branch = cond->get_bool_component(0) ? iif->then_instructions : iif->else_instructions;
 
          *result = NULL;
-         if (!constant_expression_evaluate_expression_list(branch, variable_context, result))
+         if (!constant_expression_evaluate_expression_list(mem_ctx, branch,
+                                                           variable_context,
+                                                           result))
             return false;
 
          /* If there was a return in the branch chosen, drop out now. */
          if (*result)
             return true;
 
          break;
       }
 
          /* Every other expression type, we drop out. */
@@ -955,22 +985,26 @@ bool ir_function_signature::constant_expression_evaluate_expression_list(const s
    }
 
    /* Reaching the end of the block is not an error condition */
    if (result)
       *result = NULL;
 
    return true;
 }
 
 ir_constant *
-ir_function_signature::constant_expression_value(exec_list *actual_parameters, struct hash_table *variable_context)
+ir_function_signature::constant_expression_value(void *mem_ctx,
+                                                 exec_list *actual_parameters,
+                                                 struct hash_table *variable_context)
 {
+   assert(mem_ctx);
+
    const glsl_type *type = this->return_type;
    if (type == glsl_type::void_type)
       return NULL;
 
    /* From the GLSL 1.20 spec, page 23:
     * "Function calls to user-defined functions (non-built-in functions)
     *  cannot be used to form constant expressions."
     */
    if (!this->is_builtin())
       return NULL;
@@ -991,35 +1025,37 @@ ir_function_signature::constant_expression_value(exec_list *actual_parameters, s
    hash_table *deref_hash = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
                                                     _mesa_key_pointer_equal);
 
    /* If "origin" is non-NULL, then the function body is there.  So we
     * have to use the variable objects from the object with the body,
     * but the parameter instanciation on the current object.
     */
    const exec_node *parameter_info = origin ? origin->parameters.get_head_raw() : parameters.get_head_raw();
 
    foreach_in_list(ir_rvalue, n, actual_parameters) {
-      ir_constant *constant = n->constant_expression_value(variable_context);
+      ir_constant *constant =
+         n->constant_expression_value(mem_ctx, variable_context);
       if (constant == NULL) {
          _mesa_hash_table_destroy(deref_hash, NULL);
          return NULL;
       }
 
 
       ir_variable *var = (ir_variable *)parameter_info;
       _mesa_hash_table_insert(deref_hash, var, constant);
 
       parameter_info = parameter_info->next;
    }
 
    ir_constant *result = NULL;
 
    /* Now run the builtin function until something non-constant
     * happens or we get the result.
     */
-   if (constant_expression_evaluate_expression_list(origin ? origin->body : body, deref_hash, &result) && result)
-      result = result->clone(ralloc_parent(this), NULL);
+   if (constant_expression_evaluate_expression_list(mem_ctx, origin ? origin->body : body, deref_hash, &result) &&
+       result)
+      result = result->clone(mem_ctx, NULL);
 
    _mesa_hash_table_destroy(deref_hash, NULL);
 
    return result;
 }
diff --git a/src/compiler/glsl/linker.cpp b/src/compiler/glsl/linker.cpp
index 5f22eb36ae..9af7d8033a 100644
--- a/src/compiler/glsl/linker.cpp
+++ b/src/compiler/glsl/linker.cpp
@@ -421,21 +421,21 @@ public:
    }
 
    ir_visitor_status visit_enter(ir_dereference_array *ir)
    {
       if (!ir->variable_referenced())
          return visit_continue;
 
       if (!ir->variable_referenced()->type->contains_sampler())
          return visit_continue;
 
-      if (!ir->array_index->constant_expression_value()) {
+      if (!ir->array_index->constant_expression_value(ralloc_parent(ir))) {
          dynamic_sampler_array_indexing = true;
          return visit_stop;
       }
       return visit_continue;
    }
 
    bool uses_dynamic_sampler_array_indexing()
    {
       return dynamic_sampler_array_indexing;
    }
diff --git a/src/compiler/glsl/loop_controls.cpp b/src/compiler/glsl/loop_controls.cpp
index fa739afa24..895954fc2d 100644
--- a/src/compiler/glsl/loop_controls.cpp
+++ b/src/compiler/glsl/loop_controls.cpp
@@ -89,33 +89,33 @@ calculate_iterations(ir_rvalue *from, ir_rvalue *to, ir_rvalue *increment,
       return -1;
 
    void *mem_ctx = ralloc_context(NULL);
 
    ir_expression *const sub =
       new(mem_ctx) ir_expression(ir_binop_sub, from->type, to, from);
 
    ir_expression *const div =
       new(mem_ctx) ir_expression(ir_binop_div, sub->type, sub, increment);
 
-   ir_constant *iter = div->constant_expression_value();
+   ir_constant *iter = div->constant_expression_value(mem_ctx);
    if (iter == NULL) {
       ralloc_free(mem_ctx);
       return -1;
    }
 
    if (!iter->type->is_integer()) {
       const ir_expression_operation op = iter->type->is_double()
          ? ir_unop_d2i : ir_unop_f2i;
       ir_rvalue *cast =
          new(mem_ctx) ir_expression(op, glsl_type::int_type, iter, NULL);
 
-      iter = cast->constant_expression_value();
+      iter = cast->constant_expression_value(mem_ctx);
    }
 
    int iter_value = iter->get_int_component(0);
 
    /* Make sure that the calculated number of iterations satisfies the exit
     * condition.  This is needed to catch off-by-one errors and some types of
     * ill-formed loops.  For example, we need to detect that the following
     * loop does not have a maximum iteration count.
     *
     *    for (float x = 0.0; x != 0.9; x += 0.2)
@@ -146,21 +146,21 @@ calculate_iterations(ir_rvalue *from, ir_rvalue *to, ir_rvalue *increment,
       ir_expression *const mul =
 	 new(mem_ctx) ir_expression(ir_binop_mul, increment->type, iter,
 				    increment);
 
       ir_expression *const add =
 	 new(mem_ctx) ir_expression(ir_binop_add, mul->type, mul, from);
 
       ir_expression *const cmp =
 	 new(mem_ctx) ir_expression(op, glsl_type::bool_type, add, to);
 
-      ir_constant *const cmp_result = cmp->constant_expression_value();
+      ir_constant *const cmp_result = cmp->constant_expression_value(mem_ctx);
 
       assert(cmp_result != NULL);
       if (cmp_result->get_bool_component(0)) {
 	 iter_value += bias[i];
 	 valid_loop = true;
 	 break;
       }
    }
 
    ralloc_free(mem_ctx);
diff --git a/src/compiler/glsl/loop_unroll.cpp b/src/compiler/glsl/loop_unroll.cpp
index bc377dff3b..dbb3fa2fa5 100644
--- a/src/compiler/glsl/loop_unroll.cpp
+++ b/src/compiler/glsl/loop_unroll.cpp
@@ -99,21 +99,21 @@ public:
    }
 
    virtual ir_visitor_status visit_enter(ir_dereference_array *ir)
    {
       /* Force unroll in case of dynamic indexing with sampler arrays
        * when EmitNoIndirectSampler is set.
        */
       if (options->EmitNoIndirectSampler) {
          if ((ir->array->type->is_array() &&
               ir->array->type->contains_sampler()) &&
-             !ir->array_index->constant_expression_value()) {
+             !ir->array_index->constant_expression_value(ralloc_parent(ir))) {
             unsupported_variable_indexing = true;
             return visit_continue;
          }
       }
 
       /* Check for arrays variably-indexed by a loop induction variable.
        * Unrolling the loop may convert that access into constant-indexing.
        *
        * Many drivers don't support particular kinds of variable indexing,
        * and have to resort to using lower_variable_index_to_cond_assign to
diff --git a/src/compiler/glsl/lower_buffer_access.cpp b/src/compiler/glsl/lower_buffer_access.cpp
index 76d366c4b9..caffaf9bfb 100644
--- a/src/compiler/glsl/lower_buffer_access.cpp
+++ b/src/compiler/glsl/lower_buffer_access.cpp
@@ -397,21 +397,21 @@ lower_buffer_access::setup_buffer_access(void *mem_ctx,
                array_stride = deref_array->type->std140_size(array_row_major);
                array_stride = glsl_align(array_stride, 16);
             }
          }
 
          ir_rvalue *array_index = deref_array->array_index;
          if (array_index->type->base_type == GLSL_TYPE_INT)
             array_index = i2u(array_index);
 
          ir_constant *const_index =
-            array_index->constant_expression_value(NULL);
+            array_index->constant_expression_value(mem_ctx, NULL);
          if (const_index) {
             *const_offset += array_stride * const_index->value.u[0];
          } else {
             *offset = add(*offset,
                           mul(array_index,
                               new(mem_ctx) ir_constant(array_stride)));
          }
          deref = deref_array->array->as_dereference();
          break;
       }
diff --git a/src/compiler/glsl/lower_distance.cpp b/src/compiler/glsl/lower_distance.cpp
index ff04e9a26d..4d8d66b7cc 100644
--- a/src/compiler/glsl/lower_distance.cpp
+++ b/src/compiler/glsl/lower_distance.cpp
@@ -228,21 +228,22 @@ lower_distance_visitor::create_indices(ir_rvalue *old_index,
    void *ctx = ralloc_parent(old_index);
 
    /* Make sure old_index is a signed int so that the bitwise "shift" and
     * "and" operations below type check properly.
     */
    if (old_index->type != glsl_type::int_type) {
       assert (old_index->type == glsl_type::uint_type);
       old_index = new(ctx) ir_expression(ir_unop_u2i, old_index);
    }
 
-   ir_constant *old_index_constant = old_index->constant_expression_value();
+   ir_constant *old_index_constant =
+      old_index->constant_expression_value(ctx);
    if (old_index_constant) {
       /* gl_ClipDistance is being accessed via a constant index.  Don't bother
        * creating expressions to calculate the lowered indices.  Just create
        * constants.
        */
       int const_val = old_index_constant->get_int_component(0) + offset;
       array_index = new(ctx) ir_constant(const_val / 4);
       swizzle_index = new(ctx) ir_constant(const_val % 4);
    } else {
       /* Create a variable to hold the value of old_index (so that we
diff --git a/src/compiler/glsl/lower_tess_level.cpp b/src/compiler/glsl/lower_tess_level.cpp
index 0a244f1439..b0965eb562 100644
--- a/src/compiler/glsl/lower_tess_level.cpp
+++ b/src/compiler/glsl/lower_tess_level.cpp
@@ -257,21 +257,22 @@ lower_tess_level_visitor::fix_lhs(ir_assignment *ir)
     *
     *     (vector_extract gl_TessLevel*MESA, j).
     */
    assert(expr->operation == ir_binop_vector_extract);
    assert(expr->operands[0]->ir_type == ir_type_dereference_variable);
    assert((expr->operands[0]->type == glsl_type::vec4_type) ||
           (expr->operands[0]->type == glsl_type::vec2_type));
 
    ir_dereference *const new_lhs = (ir_dereference *) expr->operands[0];
 
-   ir_constant *old_index_constant = expr->operands[1]->constant_expression_value();
+   ir_constant *old_index_constant =
+      expr->operands[1]->constant_expression_value(mem_ctx);
    if (!old_index_constant) {
       ir->rhs = new(mem_ctx) ir_expression(ir_triop_vector_insert,
                                            expr->operands[0]->type,
                                            new_lhs->clone(mem_ctx, NULL),
                                            ir->rhs,
                                            expr->operands[1]);
    }
    ir->set_lhs(new_lhs);
 
    if (old_index_constant) {
diff --git a/src/compiler/glsl/lower_vec_index_to_swizzle.cpp b/src/compiler/glsl/lower_vec_index_to_swizzle.cpp
index b49255e05d..fdbad16a34 100644
--- a/src/compiler/glsl/lower_vec_index_to_swizzle.cpp
+++ b/src/compiler/glsl/lower_vec_index_to_swizzle.cpp
@@ -56,45 +56,46 @@ public:
 void
 ir_vec_index_to_swizzle_visitor::handle_rvalue(ir_rvalue **rv)
 {
    if (*rv == NULL)
       return;
 
    ir_expression *const expr = (*rv)->as_expression();
    if (expr == NULL || expr->operation != ir_binop_vector_extract)
       return;
 
-   ir_constant *const idx = expr->operands[1]->constant_expression_value();
+   void *mem_ctx = ralloc_parent(expr);
+   ir_constant *const idx =
+      expr->operands[1]->constant_expression_value(mem_ctx);
    if (idx == NULL)
       return;
 
-   void *ctx = ralloc_parent(expr);
    this->progress = true;
 
    /* Page 40 of the GLSL 1.20 spec says:
     *
     *     "When indexing with non-constant expressions, behavior is undefined
     *     if the index is negative, or greater than or equal to the size of
     *     the vector."
     *
     * The quoted spec text mentions non-constant expressions, but this code
     * operates on constants.  These constants are the result of non-constant
     * expressions that have been optimized to constants.  The common case here
     * is a loop counter from an unrolled loop that is used to index a vector.
     *
     * The ir_swizzle constructor gets angry if the index is negative or too
     * large.  For simplicity sake, just clamp the index to [0, size-1].
     */
    const int i = CLAMP(idx->value.i[0], 0,
                        (int) expr->operands[0]->type->vector_elements - 1);
 
-   *rv = new(ctx) ir_swizzle(expr->operands[0], i, 0, 0, 0, 1);
+   *rv = new(mem_ctx) ir_swizzle(expr->operands[0], i, 0, 0, 0, 1);
 }
 
 bool
 do_vec_index_to_swizzle(exec_list *instructions)
 {
    ir_vec_index_to_swizzle_visitor v;
 
    v.run(instructions);
 
    return v.progress;
diff --git a/src/compiler/glsl/lower_vector_derefs.cpp b/src/compiler/glsl/lower_vector_derefs.cpp
index f7bf68db36..a83658d20f 100644
--- a/src/compiler/glsl/lower_vector_derefs.cpp
+++ b/src/compiler/glsl/lower_vector_derefs.cpp
@@ -54,22 +54,23 @@ vector_deref_visitor::visit_enter(ir_assignment *ir)
    if (!ir->lhs || ir->lhs->ir_type != ir_type_dereference_array)
       return ir_rvalue_enter_visitor::visit_enter(ir);
 
    ir_dereference_array *const deref = (ir_dereference_array *) ir->lhs;
    if (!deref->array->type->is_vector())
       return ir_rvalue_enter_visitor::visit_enter(ir);
 
    ir_dereference *const new_lhs = (ir_dereference *) deref->array;
    ir->set_lhs(new_lhs);
 
-   ir_constant *old_index_constant = deref->array_index->constant_expression_value();
    void *mem_ctx = ralloc_parent(ir);
+   ir_constant *old_index_constant =
+      deref->array_index->constant_expression_value(mem_ctx);
    if (!old_index_constant) {
       ir->rhs = new(mem_ctx) ir_expression(ir_triop_vector_insert,
                                            new_lhs->type,
                                            new_lhs->clone(mem_ctx, NULL),
                                            ir->rhs,
                                            deref->array_index);
       ir->write_mask = (1 << new_lhs->type->vector_elements) - 1;
    } else {
       ir->write_mask = 1 << old_index_constant->get_int_component(0);
    }
diff --git a/src/compiler/glsl/lower_vector_insert.cpp b/src/compiler/glsl/lower_vector_insert.cpp
index 26d31b03c1..ceaa5887c8 100644
--- a/src/compiler/glsl/lower_vector_insert.cpp
+++ b/src/compiler/glsl/lower_vector_insert.cpp
@@ -58,21 +58,22 @@ vector_insert_visitor::handle_rvalue(ir_rvalue **rv)
    if (*rv == NULL || (*rv)->ir_type != ir_type_expression)
       return;
 
    ir_expression *const expr = (ir_expression *) *rv;
 
    if (likely(expr->operation != ir_triop_vector_insert))
       return;
 
    factory.mem_ctx = ralloc_parent(expr);
 
-   ir_constant *const idx = expr->operands[2]->constant_expression_value();
+   ir_constant *const idx =
+      expr->operands[2]->constant_expression_value(factory.mem_ctx);
    if (idx != NULL) {
       /* Replace (vector_insert (vec) (scalar) (index)) with a dereference of
        * a new temporary.  The new temporary gets assigned as
        *
        *     t = vec
        *     t.mask = scalar
        *
        * where mask is the component selected by index.
        */
       ir_variable *const temp =
diff --git a/src/compiler/glsl/opt_algebraic.cpp b/src/compiler/glsl/opt_algebraic.cpp
index 382b4617d1..31d1f74462 100644
--- a/src/compiler/glsl/opt_algebraic.cpp
+++ b/src/compiler/glsl/opt_algebraic.cpp
@@ -256,23 +256,25 @@ ir_algebraic_visitor::reassociate_constant(ir_expression *ir1, int const_index,
    if (!ir2 || ir1->operation != ir2->operation)
       return false;
 
    /* Don't want to even think about matrices. */
    if (ir1->operands[0]->type->is_matrix() ||
        ir1->operands[1]->type->is_matrix() ||
        ir2->operands[0]->type->is_matrix() ||
        ir2->operands[1]->type->is_matrix())
       return false;
 
+   void *mem_ctx = ralloc_parent(ir2);
+
    ir_constant *ir2_const[2];
-   ir2_const[0] = ir2->operands[0]->constant_expression_value();
-   ir2_const[1] = ir2->operands[1]->constant_expression_value();
+   ir2_const[0] = ir2->operands[0]->constant_expression_value(mem_ctx);
+   ir2_const[1] = ir2->operands[1]->constant_expression_value(mem_ctx);
 
    if (ir2_const[0] && ir2_const[1])
       return false;
 
    if (ir2_const[0]) {
       reassociate_operands(ir1, const_index, ir2, 1);
       return true;
    } else if (ir2_const[1]) {
       reassociate_operands(ir1, const_index, ir2, 0);
       return true;
@@ -326,21 +328,22 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
          return mul(matrix_mul->operands[0],
                     mul(matrix_mul->operands[1], ir->operands[1]));
       }
    }
 
    assert(ir->num_operands <= 4);
    for (unsigned i = 0; i < ir->num_operands; i++) {
       if (ir->operands[i]->type->is_matrix())
 	 return ir;
 
-      op_const[i] = ir->operands[i]->constant_expression_value();
+      op_const[i] =
+         ir->operands[i]->constant_expression_value(ralloc_parent(ir));
       op_expr[i] = ir->operands[i]->as_expression();
    }
 
    if (this->mem_ctx == NULL)
       this->mem_ctx = ralloc_parent(ir);
 
    switch (ir->operation) {
    case ir_unop_bit_not:
       if (op_expr[0] && op_expr[0]->operation == ir_unop_bit_not)
          return op_expr[0]->operands[0];
diff --git a/src/compiler/glsl/opt_constant_folding.cpp b/src/compiler/glsl/opt_constant_folding.cpp
index e72aec78f6..3b9394d135 100644
--- a/src/compiler/glsl/opt_constant_folding.cpp
+++ b/src/compiler/glsl/opt_constant_folding.cpp
@@ -93,21 +93,22 @@ ir_constant_fold(ir_rvalue **rvalue)
 
    /* No constant folding can be performed on variable dereferences.  We need
     * to explicitly avoid them, as calling constant_expression_value() on a
     * variable dereference will return a clone of var->constant_value.  This
     * would make us propagate the value into the tree, which isn't our job.
     */
    ir_dereference_variable *var_ref = (*rvalue)->as_dereference_variable();
    if (var_ref)
       return false;
 
-   ir_constant *constant = (*rvalue)->constant_expression_value();
+   ir_constant *constant =
+      (*rvalue)->constant_expression_value(ralloc_parent(*rvalue));
    if (constant) {
       *rvalue = constant;
       return true;
    }
    return false;
 }
 
 void
 ir_constant_folding_visitor::handle_rvalue(ir_rvalue **rvalue)
 {
@@ -182,21 +183,21 @@ ir_constant_folding_visitor::visit_enter(ir_call *ir)
 	 ir_rvalue *new_param = param_rval;
 
 	 handle_rvalue(&new_param);
 	 if (new_param != param_rval) {
 	    param_rval->replace_with(new_param);
 	 }
       }
    }
 
    /* Next, see if the call can be replaced with an assignment of a constant */
-   ir_constant *const_val = ir->constant_expression_value();
+   ir_constant *const_val = ir->constant_expression_value(ralloc_parent(ir));
 
    if (const_val != NULL) {
       ir_assignment *assignment =
 	 new(ralloc_parent(ir)) ir_assignment(ir->return_deref, const_val);
       ir->replace_with(assignment);
    }
 
    return visit_continue_with_parent;
 }
 
diff --git a/src/compiler/glsl/opt_constant_propagation.cpp b/src/compiler/glsl/opt_constant_propagation.cpp
index 4039512097..52e3937bb1 100644
--- a/src/compiler/glsl/opt_constant_propagation.cpp
+++ b/src/compiler/glsl/opt_constant_propagation.cpp
@@ -147,21 +147,22 @@ void
 ir_constant_propagation_visitor::constant_folding(ir_rvalue **rvalue)
 {
    if (this->in_assignee || *rvalue == NULL)
       return;
 
    if (ir_constant_fold(rvalue))
       this->progress = true;
 
    ir_dereference_variable *var_ref = (*rvalue)->as_dereference_variable();
    if (var_ref && !var_ref->type->is_array()) {
-      ir_constant *constant = var_ref->constant_expression_value();
+      ir_constant *constant =
+         var_ref->constant_expression_value(ralloc_parent(var_ref));
       if (constant) {
          *rvalue = constant;
          this->progress = true;
       }
    }
 }
 
 void
 ir_constant_propagation_visitor::constant_propagation(ir_rvalue **rvalue) {
 
diff --git a/src/compiler/glsl/opt_constant_variable.cpp b/src/compiler/glsl/opt_constant_variable.cpp
index 1c06ffe675..914b46004c 100644
--- a/src/compiler/glsl/opt_constant_variable.cpp
+++ b/src/compiler/glsl/opt_constant_variable.cpp
@@ -124,21 +124,21 @@ ir_constant_variable_visitor::visit_enter(ir_assignment *ir)
       return visit_continue;
 
    /* Ignore buffer variables, since the underlying storage is shared
     * and we can't be sure that this variable won't be written by another
     * thread.
     */
    if (var->data.mode == ir_var_shader_storage ||
        var->data.mode == ir_var_shader_shared)
       return visit_continue;
 
-   constval = ir->rhs->constant_expression_value();
+   constval = ir->rhs->constant_expression_value(ralloc_parent(ir));
    if (!constval)
       return visit_continue;
 
    /* Mark this entry as having a constant assignment (if the
     * assignment count doesn't go >1).  do_constant_variable will fix
     * up the variable with the constant value later.
     */
    entry->constval = constval;
 
    return visit_continue;
diff --git a/src/compiler/glsl/opt_if_simplification.cpp b/src/compiler/glsl/opt_if_simplification.cpp
index e05f03190a..136ef87729 100644
--- a/src/compiler/glsl/opt_if_simplification.cpp
+++ b/src/compiler/glsl/opt_if_simplification.cpp
@@ -77,21 +77,22 @@ ir_if_simplification_visitor::visit_leave(ir_if *ir)
       ir->remove();
       this->made_progress = true;
       return visit_continue;
    }
 
    /* FINISHME: Ideally there would be a way to note that the condition results
     * FINISHME: in a constant before processing both of the other subtrees.
     * FINISHME: This can probably be done with some flags, but it would take
     * FINISHME: some work to get right.
     */
-   ir_constant *condition_constant = ir->condition->constant_expression_value();
+   ir_constant *condition_constant =
+      ir->condition->constant_expression_value(ralloc_parent(ir));
    if (condition_constant) {
       /* Move the contents of the one branch of the conditional
        * that matters out.
        */
       if (condition_constant->value.b[0]) {
          ir->insert_before(&ir->then_instructions);
       } else {
          ir->insert_before(&ir->else_instructions);
       }
       ir->remove();
diff --git a/src/mesa/program/ir_to_mesa.cpp b/src/mesa/program/ir_to_mesa.cpp
index 96b06621b5..e141ac4b71 100644
--- a/src/mesa/program/ir_to_mesa.cpp
+++ b/src/mesa/program/ir_to_mesa.cpp
@@ -1536,21 +1536,21 @@ ir_to_mesa_visitor::visit(ir_dereference_variable *ir)
    this->result = src_reg(entry->file, entry->index, var->type);
 }
 
 void
 ir_to_mesa_visitor::visit(ir_dereference_array *ir)
 {
    ir_constant *index;
    src_reg src;
    int element_size = type_size(ir->type);
 
-   index = ir->array_index->constant_expression_value();
+   index = ir->array_index->constant_expression_value(ralloc_parent(ir));
 
    ir->array->accept(this);
    src = this->result;
 
    if (index) {
       src.index += index->value.i[0] * element_size;
    } else {
       /* Variable index array dereference.  It eats the "vec4" of the
        * base of the array and an index that offsets the Mesa register
        * index.
@@ -1650,22 +1650,24 @@ static void
 calc_sampler_offsets(struct gl_shader_program *prog, ir_dereference *deref,
                      unsigned *offset, unsigned *array_elements,
                      unsigned *location)
 {
    if (deref->ir_type == ir_type_dereference_variable)
       return;
 
    switch (deref->ir_type) {
    case ir_type_dereference_array: {
       ir_dereference_array *deref_arr = deref->as_dereference_array();
+
+      void *mem_ctx = ralloc_parent(deref_arr);
       ir_constant *array_index =
-         deref_arr->array_index->constant_expression_value();
+         deref_arr->array_index->constant_expression_value(mem_ctx);
 
       if (!array_index) {
 	 /* GLSL 1.10 and 1.20 allowed variable sampler array indices,
 	  * while GLSL 1.30 requires that the array indices be
 	  * constant integer expressions.  We don't expect any driver
 	  * to actually work with a really variable array index, so
 	  * all that would work would be an unrolled loop counter that ends
 	  * up being constant above.
 	  */
          ralloc_strcat(&prog->data->InfoLog,
diff --git a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
index bada7f4ea8..e8f7ecac92 100644
--- a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
+++ b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
@@ -2828,21 +2828,21 @@ shrink_array_declarations(struct inout_decl *decls, unsigned count,
 }
 
 void
 glsl_to_tgsi_visitor::visit(ir_dereference_array *ir)
 {
    ir_constant *index;
    st_src_reg src;
    int element_size = type_size(ir->type);
    bool is_2D = false;
 
-   index = ir->array_index->constant_expression_value();
+   index = ir->array_index->constant_expression_value(ralloc_parent(ir));
 
    ir->array->accept(this);
    src = this->result;
 
    if (ir->array->ir_type != ir_type_dereference_array) {
       switch (this->prog->Target) {
       case GL_TESS_CONTROL_PROGRAM_NV:
          is_2D = (src.file == PROGRAM_INPUT || src.file == PROGRAM_OUTPUT) &&
                  !ir->variable_referenced()->data.patch;
          break;
@@ -4130,21 +4130,24 @@ glsl_to_tgsi_visitor::calc_deref_offsets(ir_dereference *tail,
 
       calc_deref_offsets(deref_record->record->as_dereference(), array_elements, index, indirect, location);
 
       assert(field_index >= 0);
       *location += struct_type->record_location_offset(field_index);
       break;
    }
 
    case ir_type_dereference_array: {
       ir_dereference_array *deref_arr = tail->as_dereference_array();
-      ir_constant *array_index = deref_arr->array_index->constant_expression_value();
+
+      void *mem_ctx = ralloc_parent(deref_arr);
+      ir_constant *array_index =
+         deref_arr->array_index->constant_expression_value(mem_ctx);
 
       if (!array_index) {
          st_src_reg temp_reg;
          st_dst_reg temp_dst;
 
          temp_reg = get_temp(glsl_type::uint_type);
          temp_dst = st_dst_reg(temp_reg);
          temp_dst.writemask = 1;
 
          deref_arr->array_index->accept(this);
-- 
2.13.4



More information about the mesa-dev mailing list