+/* This method is the only one supported by gcc. Unions in particular
+ * are iffy, and read-through-converted-pointer is killed by strict
+ * aliasing. OTOH, the compiler sees through the memcpy, so the
+ * resulting asm is reasonable.
+ */
+static float
+bitcast_u2f(unsigned int u)
+{
+ assert(sizeof(float) == sizeof(unsigned int));
+ float f;
+ memcpy(&f, &u, sizeof(f));
+ return f;
+}
+
+static unsigned int
+bitcast_f2u(float f)
+{
+ assert(sizeof(float) == sizeof(unsigned int));
+ unsigned int u;
+ memcpy(&u, &f, sizeof(f));
+ return u;
+}
+
+/**
+ * Evaluate one component of a floating-point 4x8 unpacking function.
+ */
+typedef uint8_t
+(*pack_1x8_func_t)(float);
+
+/**
+ * Evaluate one component of a floating-point 2x16 unpacking function.
+ */
+typedef uint16_t
+(*pack_1x16_func_t)(float);
+
+/**
+ * Evaluate one component of a floating-point 4x8 unpacking function.
+ */
+typedef float
+(*unpack_1x8_func_t)(uint8_t);
+
+/**
+ * Evaluate one component of a floating-point 2x16 unpacking function.
+ */
+typedef float
+(*unpack_1x16_func_t)(uint16_t);
+
+/**
+ * Evaluate a 2x16 floating-point packing function.
+ */
+static uint32_t
+pack_2x16(pack_1x16_func_t pack_1x16,
+ float x, float y)
+{
+ /* From section 8.4 of the GLSL ES 3.00 spec:
+ *
+ * packSnorm2x16
+ * -------------
+ * The first component of the vector will be written to the least
+ * significant bits of the output; the last component will be written to
+ * the most significant bits.
+ *
+ * The specifications for the other packing functions contain similar
+ * language.
+ */
+ uint32_t u = 0;
+ u |= ((uint32_t) pack_1x16(x) << 0);
+ u |= ((uint32_t) pack_1x16(y) << 16);
+ return u;
+}
+
+/**
+ * Evaluate a 4x8 floating-point packing function.
+ */
+static uint32_t
+pack_4x8(pack_1x8_func_t pack_1x8,
+ float x, float y, float z, float w)
+{
+ /* From section 8.4 of the GLSL 4.30 spec:
+ *
+ * packSnorm4x8
+ * ------------
+ * The first component of the vector will be written to the least
+ * significant bits of the output; the last component will be written to
+ * the most significant bits.
+ *
+ * The specifications for the other packing functions contain similar
+ * language.
+ */
+ uint32_t u = 0;
+ u |= ((uint32_t) pack_1x8(x) << 0);
+ u |= ((uint32_t) pack_1x8(y) << 8);
+ u |= ((uint32_t) pack_1x8(z) << 16);
+ u |= ((uint32_t) pack_1x8(w) << 24);
+ return u;
+}
+
+/**
+ * Evaluate a 2x16 floating-point unpacking function.
+ */
+static void
+unpack_2x16(unpack_1x16_func_t unpack_1x16,
+ uint32_t u,
+ float *x, float *y)
+{
+ /* From section 8.4 of the GLSL ES 3.00 spec:
+ *
+ * unpackSnorm2x16
+ * ---------------
+ * The first component of the returned vector will be extracted from
+ * the least significant bits of the input; the last component will be
+ * extracted from the most significant bits.
+ *
+ * The specifications for the other unpacking functions contain similar
+ * language.
+ */
+ *x = unpack_1x16((uint16_t) (u & 0xffff));
+ *y = unpack_1x16((uint16_t) (u >> 16));
+}
+
+/**
+ * Evaluate a 4x8 floating-point unpacking function.
+ */
+static void
+unpack_4x8(unpack_1x8_func_t unpack_1x8, uint32_t u,
+ float *x, float *y, float *z, float *w)
+{
+ /* From section 8.4 of the GLSL 4.30 spec:
+ *
+ * unpackSnorm4x8
+ * --------------
+ * The first component of the returned vector will be extracted from
+ * the least significant bits of the input; the last component will be
+ * extracted from the most significant bits.
+ *
+ * The specifications for the other unpacking functions contain similar
+ * language.
+ */
+ *x = unpack_1x8((uint8_t) (u & 0xff));
+ *y = unpack_1x8((uint8_t) (u >> 8));
+ *z = unpack_1x8((uint8_t) (u >> 16));
+ *w = unpack_1x8((uint8_t) (u >> 24));
+}
+
+/**
+ * Evaluate one component of packSnorm4x8.
+ */
+static uint8_t
+pack_snorm_1x8(float x)
+{
+ /* From section 8.4 of the GLSL 4.30 spec:
+ *
+ * packSnorm4x8
+ * ------------
+ * The conversion for component c of v to fixed point is done as
+ * follows:
+ *
+ * packSnorm4x8: round(clamp(c, -1, +1) * 127.0)
+ *
+ * We must first cast the float to an int, because casting a negative
+ * float to a uint is undefined.
+ */
+ return (uint8_t) (int8_t)
+ _mesa_round_to_even(CLAMP(x, -1.0f, +1.0f) * 127.0f);
+}
+
+/**
+ * Evaluate one component of packSnorm2x16.
+ */
+static uint16_t
+pack_snorm_1x16(float x)
+{
+ /* From section 8.4 of the GLSL ES 3.00 spec:
+ *
+ * packSnorm2x16
+ * -------------
+ * The conversion for component c of v to fixed point is done as
+ * follows:
+ *
+ * packSnorm2x16: round(clamp(c, -1, +1) * 32767.0)
+ *
+ * We must first cast the float to an int, because casting a negative
+ * float to a uint is undefined.
+ */
+ return (uint16_t) (int16_t)
+ _mesa_round_to_even(CLAMP(x, -1.0f, +1.0f) * 32767.0f);
+}
+
+/**
+ * Evaluate one component of unpackSnorm4x8.
+ */
+static float
+unpack_snorm_1x8(uint8_t u)
+{
+ /* From section 8.4 of the GLSL 4.30 spec:
+ *
+ * unpackSnorm4x8
+ * --------------
+ * The conversion for unpacked fixed-point value f to floating point is
+ * done as follows:
+ *
+ * unpackSnorm4x8: clamp(f / 127.0, -1, +1)
+ */
+ return CLAMP((int8_t) u / 127.0f, -1.0f, +1.0f);
+}
+
+/**
+ * Evaluate one component of unpackSnorm2x16.
+ */
+static float
+unpack_snorm_1x16(uint16_t u)
+{
+ /* From section 8.4 of the GLSL ES 3.00 spec:
+ *
+ * unpackSnorm2x16
+ * ---------------
+ * The conversion for unpacked fixed-point value f to floating point is
+ * done as follows:
+ *
+ * unpackSnorm2x16: clamp(f / 32767.0, -1, +1)
+ */
+ return CLAMP((int16_t) u / 32767.0f, -1.0f, +1.0f);
+}
+
+/**
+ * Evaluate one component packUnorm4x8.
+ */
+static uint8_t
+pack_unorm_1x8(float x)
+{
+ /* From section 8.4 of the GLSL 4.30 spec:
+ *
+ * packUnorm4x8
+ * ------------
+ * The conversion for component c of v to fixed point is done as
+ * follows:
+ *
+ * packUnorm4x8: round(clamp(c, 0, +1) * 255.0)
+ */
+ return (uint8_t) _mesa_round_to_even(CLAMP(x, 0.0f, 1.0f) * 255.0f);
+}
+
+/**
+ * Evaluate one component packUnorm2x16.
+ */
+static uint16_t
+pack_unorm_1x16(float x)
+{
+ /* From section 8.4 of the GLSL ES 3.00 spec:
+ *
+ * packUnorm2x16
+ * -------------
+ * The conversion for component c of v to fixed point is done as
+ * follows:
+ *
+ * packUnorm2x16: round(clamp(c, 0, +1) * 65535.0)
+ */
+ return (uint16_t) _mesa_round_to_even(CLAMP(x, 0.0f, 1.0f) * 65535.0f);
+}
+
+/**
+ * Evaluate one component of unpackUnorm4x8.
+ */
+static float
+unpack_unorm_1x8(uint8_t u)
+{
+ /* From section 8.4 of the GLSL 4.30 spec:
+ *
+ * unpackUnorm4x8
+ * --------------
+ * The conversion for unpacked fixed-point value f to floating point is
+ * done as follows:
+ *
+ * unpackUnorm4x8: f / 255.0
+ */
+ return (float) u / 255.0f;
+}
+
+/**
+ * Evaluate one component of unpackUnorm2x16.
+ */
+static float
+unpack_unorm_1x16(uint16_t u)
+{
+ /* From section 8.4 of the GLSL ES 3.00 spec:
+ *
+ * unpackUnorm2x16
+ * ---------------
+ * The conversion for unpacked fixed-point value f to floating point is
+ * done as follows:
+ *
+ * unpackUnorm2x16: f / 65535.0
+ */
+ return (float) u / 65535.0f;
+}
+
+/**
+ * Evaluate one component of packHalf2x16.
+ */
+static uint16_t
+pack_half_1x16(float x)
+{
+ return _mesa_float_to_half(x);
+}
+
+/**
+ * Evaluate one component of unpackHalf2x16.
+ */
+static float
+unpack_half_1x16(uint16_t u)
+{
+ return _mesa_half_to_float(u);
+}
+
+/**
+ * Get the constant that is ultimately referenced by an r-value, in a constant
+ * expression evaluation context.
+ *
+ * The offset is used when the reference is to a specific column of a matrix.
+ */
+static bool
+constant_referenced(const ir_dereference *deref,
+ struct hash_table *variable_context,
+ ir_constant *&store, int &offset)
+{
+ store = NULL;
+ offset = 0;
+
+ if (variable_context == NULL)
+ return false;
+
+ switch (deref->ir_type) {
+ case ir_type_dereference_array: {
+ const ir_dereference_array *const da =
+ (const ir_dereference_array *) deref;
+
+ ir_constant *const index_c =
+ da->array_index->constant_expression_value(variable_context);
+
+ if (!index_c || !index_c->type->is_scalar() || !index_c->type->is_integer())
+ break;
+
+ const int index = index_c->type->base_type == GLSL_TYPE_INT ?
+ index_c->get_int_component(0) :
+ index_c->get_uint_component(0);
+
+ ir_constant *substore;
+ int suboffset;
+
+ const ir_dereference *const deref = da->array->as_dereference();
+ if (!deref)
+ break;
+
+ if (!constant_referenced(deref, variable_context, substore, suboffset))
+ break;
+
+ const glsl_type *const vt = da->array->type;
+ if (vt->is_array()) {
+ store = substore->get_array_element(index);
+ offset = 0;
+ } else if (vt->is_matrix()) {
+ store = substore;
+ offset = index * vt->vector_elements;
+ } else if (vt->is_vector()) {
+ store = substore;
+ offset = suboffset + index;
+ }
+
+ break;
+ }
+
+ case ir_type_dereference_record: {
+ const ir_dereference_record *const dr =
+ (const ir_dereference_record *) deref;
+
+ const ir_dereference *const deref = dr->record->as_dereference();
+ if (!deref)
+ break;
+
+ ir_constant *substore;
+ int suboffset;
+
+ if (!constant_referenced(deref, variable_context, substore, suboffset))
+ break;
+
+ /* Since we're dropping it on the floor...
+ */
+ assert(suboffset == 0);
+
+ store = substore->get_record_field(dr->field);
+ break;
+ }
+
+ case ir_type_dereference_variable: {
+ const ir_dereference_variable *const dv =
+ (const ir_dereference_variable *) deref;
+
+ store = (ir_constant *) hash_table_find(variable_context, dv->var);
+ break;
+ }
+
+ default:
+ assert(!"Should not get here.");
+ break;
+ }
+
+ return store != NULL;
+}
+
+
+ir_constant *
+ir_rvalue::constant_expression_value(struct hash_table *)
+{
+ assert(this->type->is_error());
+ return NULL;
+}
+