* member available.
*/
ir_variable *in_var(const glsl_type *type, const char *name);
+ ir_variable *in_mediump_var(const glsl_type *type, const char *name);
+ ir_variable *in_highp_var(const glsl_type *type, const char *name);
ir_variable *out_var(const glsl_type *type, const char *name);
+ ir_variable *out_lowp_var(const glsl_type *type, const char *name);
+ ir_variable *out_highp_var(const glsl_type *type, const char *name);
ir_constant *imm(float f, unsigned vector_elements=1);
ir_constant *imm(bool b, unsigned vector_elements=1);
ir_constant *imm(int i, unsigned vector_elements=1);
ir_expression_operation opcode,
const glsl_type *return_type,
const glsl_type *param_type);
+ ir_function_signature *unop_precision(builtin_available_predicate avail,
+ ir_expression_operation opcode,
+ const glsl_type *return_type,
+ const glsl_type *param_type, uint32_t precision);
ir_function_signature *binop(builtin_available_predicate avail,
ir_expression_operation opcode,
const glsl_type *return_type,
}
ir_variable *
+builtin_builder::in_highp_var(const glsl_type *type, const char *name)
+{
+ ir_variable *var = in_var(type, name);
+ var->data.precision = GLSL_PRECISION_HIGH;
+ return var;
+}
+
+ir_variable *
+builtin_builder::in_mediump_var(const glsl_type *type, const char *name)
+{
+ ir_variable *var = in_var(type, name);
+ var->data.precision = GLSL_PRECISION_MEDIUM;
+ return var;
+}
+
+ir_variable *
builtin_builder::out_var(const glsl_type *type, const char *name)
{
return new(mem_ctx) ir_variable(type, name, ir_var_function_out);
}
+ir_variable *
+builtin_builder::out_lowp_var(const glsl_type *type, const char *name)
+{
+ ir_variable *var = out_var(type, name);
+ var->data.precision = GLSL_PRECISION_LOW;
+ return var;
+}
+
+ir_variable *
+builtin_builder::out_highp_var(const glsl_type *type, const char *name)
+{
+ ir_variable *var = out_var(type, name);
+ var->data.precision = GLSL_PRECISION_HIGH;
+ return var;
+}
+
ir_constant *
builtin_builder::imm(bool b, unsigned vector_elements)
{
ir_function_signature *
builtin_builder::_packUnorm2x16(builtin_available_predicate avail)
{
- ir_variable *v = in_var(glsl_type::vec2_type, "v");
+ ir_variable *v = in_highp_var(glsl_type::vec2_type, "v");
MAKE_SIG(glsl_type::uint_type, avail, 1, v);
+ sig->return_precision = GLSL_PRECISION_HIGH;
body.emit(ret(expr(ir_unop_pack_unorm_2x16, v)));
return sig;
}
{
ir_variable *v = in_var(glsl_type::vec2_type, "v");
MAKE_SIG(glsl_type::uint_type, avail, 1, v);
+ sig->return_precision = GLSL_PRECISION_HIGH;
body.emit(ret(expr(ir_unop_pack_snorm_2x16, v)));
return sig;
}
ir_function_signature *
builtin_builder::_packUnorm4x8(builtin_available_predicate avail)
{
- ir_variable *v = in_var(glsl_type::vec4_type, "v");
+ ir_variable *v = in_mediump_var(glsl_type::vec4_type, "v");
MAKE_SIG(glsl_type::uint_type, avail, 1, v);
+ sig->return_precision = GLSL_PRECISION_HIGH;
body.emit(ret(expr(ir_unop_pack_unorm_4x8, v)));
return sig;
}
ir_function_signature *
builtin_builder::_packSnorm4x8(builtin_available_predicate avail)
{
- ir_variable *v = in_var(glsl_type::vec4_type, "v");
+ ir_variable *v = in_mediump_var(glsl_type::vec4_type, "v");
MAKE_SIG(glsl_type::uint_type, avail, 1, v);
+ sig->return_precision = GLSL_PRECISION_HIGH;
body.emit(ret(expr(ir_unop_pack_snorm_4x8, v)));
return sig;
}
ir_function_signature *
builtin_builder::_unpackUnorm2x16(builtin_available_predicate avail)
{
- ir_variable *p = in_var(glsl_type::uint_type, "p");
+ ir_variable *p = in_highp_var(glsl_type::uint_type, "p");
MAKE_SIG(glsl_type::vec2_type, avail, 1, p);
+ sig->return_precision = GLSL_PRECISION_HIGH;
body.emit(ret(expr(ir_unop_unpack_unorm_2x16, p)));
return sig;
}
ir_function_signature *
builtin_builder::_unpackSnorm2x16(builtin_available_predicate avail)
{
- ir_variable *p = in_var(glsl_type::uint_type, "p");
+ ir_variable *p = in_highp_var(glsl_type::uint_type, "p");
MAKE_SIG(glsl_type::vec2_type, avail, 1, p);
+ sig->return_precision = GLSL_PRECISION_HIGH;
body.emit(ret(expr(ir_unop_unpack_snorm_2x16, p)));
return sig;
}
ir_function_signature *
builtin_builder::_unpackUnorm4x8(builtin_available_predicate avail)
{
- ir_variable *p = in_var(glsl_type::uint_type, "p");
+ ir_variable *p = in_highp_var(glsl_type::uint_type, "p");
MAKE_SIG(glsl_type::vec4_type, avail, 1, p);
+ sig->return_precision = GLSL_PRECISION_MEDIUM;
body.emit(ret(expr(ir_unop_unpack_unorm_4x8, p)));
return sig;
}
ir_function_signature *
builtin_builder::_unpackSnorm4x8(builtin_available_predicate avail)
{
- ir_variable *p = in_var(glsl_type::uint_type, "p");
+ ir_variable *p = in_highp_var(glsl_type::uint_type, "p");
MAKE_SIG(glsl_type::vec4_type, avail, 1, p);
+ sig->return_precision = GLSL_PRECISION_MEDIUM;
body.emit(ret(expr(ir_unop_unpack_snorm_4x8, p)));
return sig;
}
ir_function_signature *
builtin_builder::_packHalf2x16(builtin_available_predicate avail)
{
- ir_variable *v = in_var(glsl_type::vec2_type, "v");
+ ir_variable *v = in_mediump_var(glsl_type::vec2_type, "v");
MAKE_SIG(glsl_type::uint_type, avail, 1, v);
+ sig->return_precision = GLSL_PRECISION_HIGH;
body.emit(ret(expr(ir_unop_pack_half_2x16, v)));
return sig;
}
ir_function_signature *
builtin_builder::_unpackHalf2x16(builtin_available_predicate avail)
{
- ir_variable *p = in_var(glsl_type::uint_type, "p");
+ ir_variable *p = in_highp_var(glsl_type::uint_type, "p");
MAKE_SIG(glsl_type::vec2_type, avail, 1, p);
+ sig->return_precision = GLSL_PRECISION_MEDIUM;
body.emit(ret(expr(ir_unop_unpack_half_2x16, p)));
return sig;
}
ir_variable *s = in_var(sampler_type, "sampler");
/* The sampler always exists; add optional lod later. */
MAKE_SIG(return_type, avail, 1, s);
+ sig->return_precision = GLSL_PRECISION_HIGH;
ir_texture *tex = new(mem_ctx) ir_texture(ir_txs);
tex->set_sampler(new(mem_ctx) ir_dereference_variable(s), return_type);
return sig;
}
-UNOP(bitfieldReverse, ir_unop_bitfield_reverse, gpu_shader5_or_es31_or_integer_functions)
+ir_function_signature *
+builtin_builder::_bitfieldReverse(const glsl_type *type)
+{
+ ir_variable *x = in_highp_var(type, "x");
+ MAKE_SIG(type, gpu_shader5_or_es31_or_integer_functions, 1, x);
+ sig->return_precision = GLSL_PRECISION_HIGH;
+ body.emit(ret(expr(ir_unop_bitfield_reverse, x)));
+ return sig;
+}
ir_function_signature *
builtin_builder::_bitCount(const glsl_type *type)
{
- return unop(gpu_shader5_or_es31_or_integer_functions, ir_unop_bit_count,
- glsl_type::ivec(type->vector_elements), type);
+ ir_variable *x = in_var(type, "x");
+ MAKE_SIG(glsl_type::ivec(type->vector_elements), gpu_shader5_or_es31_or_integer_functions, 1, x);
+ sig->return_precision = GLSL_PRECISION_LOW;
+ body.emit(ret(expr(ir_unop_bit_count, x)));
+ return sig;
}
ir_function_signature *
builtin_builder::_findLSB(const glsl_type *type)
{
- return unop(gpu_shader5_or_es31_or_integer_functions, ir_unop_find_lsb,
- glsl_type::ivec(type->vector_elements), type);
+ ir_variable *x = in_highp_var(type, "x");
+ MAKE_SIG(glsl_type::ivec(type->vector_elements), gpu_shader5_or_es31_or_integer_functions, 1, x);
+ sig->return_precision = GLSL_PRECISION_LOW;
+ body.emit(ret(expr(ir_unop_find_lsb, x)));
+ return sig;
}
ir_function_signature *
builtin_builder::_findMSB(const glsl_type *type)
{
- return unop(gpu_shader5_or_es31_or_integer_functions, ir_unop_find_msb,
- glsl_type::ivec(type->vector_elements), type);
+ ir_variable *x = in_highp_var(type, "x");
+ MAKE_SIG(glsl_type::ivec(type->vector_elements), gpu_shader5_or_es31_or_integer_functions, 1, x);
+ sig->return_precision = GLSL_PRECISION_LOW;
+ body.emit(ret(expr(ir_unop_find_msb, x)));
+ return sig;
}
ir_function_signature *
ir_function_signature *
builtin_builder::_ldexp(const glsl_type *x_type, const glsl_type *exp_type)
{
- return binop(x_type->is_double() ? fp64 : gpu_shader5_or_es31_or_integer_functions,
- ir_binop_ldexp, x_type, x_type, exp_type);
+ ir_variable *x = in_highp_var(x_type, "x");
+ ir_variable *y = in_highp_var(exp_type, "y");
+ MAKE_SIG(x_type, x_type->is_double() ? fp64 : gpu_shader5_or_es31_or_integer_functions, 2, x, y);
+ sig->return_precision = GLSL_PRECISION_HIGH;
+ body.emit(ret(expr(ir_binop_ldexp, x, y)));
+ return sig;
}
ir_function_signature *
builtin_builder::_dfrexp(const glsl_type *x_type, const glsl_type *exp_type)
{
- ir_variable *x = in_var(x_type, "x");
+ ir_variable *x = in_highp_var(x_type, "x");
ir_variable *exponent = out_var(exp_type, "exp");
MAKE_SIG(x_type, fp64, 2, x, exponent);
ir_function_signature *
builtin_builder::_frexp(const glsl_type *x_type, const glsl_type *exp_type)
{
- ir_variable *x = in_var(x_type, "x");
- ir_variable *exponent = out_var(exp_type, "exp");
+ ir_variable *x = in_highp_var(x_type, "x");
+ ir_variable *exponent = out_highp_var(exp_type, "exp");
MAKE_SIG(x_type, gpu_shader5_or_es31_or_integer_functions, 2, x, exponent);
+ sig->return_precision = GLSL_PRECISION_HIGH;
const unsigned vec_elem = x_type->vector_elements;
const glsl_type *bvec = glsl_type::get_instance(GLSL_TYPE_BOOL, vec_elem, 1);
ir_function_signature *
builtin_builder::_uaddCarry(const glsl_type *type)
{
- ir_variable *x = in_var(type, "x");
- ir_variable *y = in_var(type, "y");
- ir_variable *carry = out_var(type, "carry");
+ ir_variable *x = in_highp_var(type, "x");
+ ir_variable *y = in_highp_var(type, "y");
+ ir_variable *carry = out_lowp_var(type, "carry");
MAKE_SIG(type, gpu_shader5_or_es31_or_integer_functions, 3, x, y, carry);
+ sig->return_precision = GLSL_PRECISION_HIGH;
body.emit(assign(carry, ir_builder::carry(x, y)));
body.emit(ret(add(x, y)));
ir_function_signature *
builtin_builder::_usubBorrow(const glsl_type *type)
{
- ir_variable *x = in_var(type, "x");
- ir_variable *y = in_var(type, "y");
- ir_variable *borrow = out_var(type, "borrow");
+ ir_variable *x = in_highp_var(type, "x");
+ ir_variable *y = in_highp_var(type, "y");
+ ir_variable *borrow = out_lowp_var(type, "borrow");
MAKE_SIG(type, gpu_shader5_or_es31_or_integer_functions, 3, x, y, borrow);
+ sig->return_precision = GLSL_PRECISION_HIGH;
body.emit(assign(borrow, ir_builder::borrow(x, y)));
body.emit(ret(sub(x, y)));
unpack_type = glsl_type::uvec2_type;
}
- ir_variable *x = in_var(type, "x");
- ir_variable *y = in_var(type, "y");
- ir_variable *msb = out_var(type, "msb");
- ir_variable *lsb = out_var(type, "lsb");
+ ir_variable *x = in_highp_var(type, "x");
+ ir_variable *y = in_highp_var(type, "y");
+ ir_variable *msb = out_highp_var(type, "msb");
+ ir_variable *lsb = out_highp_var(type, "lsb");
MAKE_SIG(glsl_type::void_type, gpu_shader5_or_es31_or_integer_functions, 4, x, y, msb, lsb);
ir_variable *unpack_val = body.make_temp(unpack_type, "_unpack_val");
} else {
ir_variable *ret_val =
body.make_temp(sig->return_type, "_ret_val");
+ /* all non-void image functions return highp, so make our temporary and return
+ * value in the signature highp.
+ */
+ ret_val->data.precision = GLSL_PRECISION_HIGH;
body.emit(call(f, ret_val, sig->parameters));
body.emit(ret(ret_val));
}
} else {
sig->intrinsic_id = id;
}
+ sig->return_precision = GLSL_PRECISION_HIGH;
return sig;
}
ir_rvalue *param = (ir_rvalue*)ir->actual_parameters.get_head();
ir_variable *resource = param->variable_referenced();
- assert(ir->callee->return_precision == GLSL_PRECISION_NONE);
+ assert(ir->callee->return_precision == GLSL_PRECISION_HIGH);
assert(resource->type->without_array()->is_image());
/* GLSL ES 3.20 requires that images have a precision modifier, but if
}
/* Return the declared precision for user-defined functions. */
- if (!ir->callee->is_builtin())
+ if (!ir->callee->is_builtin() || ir->callee->return_precision != GLSL_PRECISION_NONE)
return ir->callee->return_precision;
/* Handle special calls. */
* uses lower precision. The function parameters don't matter.
*/
if (var && var->type->without_array()->is_sampler()) {
- /* textureSize always returns highp. */
- if (!strcmp(ir->callee_name(), "textureSize"))
- return GLSL_PRECISION_HIGH;
-
/* textureGatherOffsets always takes a highp array of constants. As
* per the discussion https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/16547#note_1393704
* trying to lower the precision results in segfault later on
}
}
- if (/* Parameters are always highp: */
+ if (ir->callee->return_precision != GLSL_PRECISION_NONE)
+ return ir->callee->return_precision;
+
+ if (/* Parameters are always implicitly promoted to highp: */
!strcmp(ir->callee_name(), "floatBitsToInt") ||
!strcmp(ir->callee_name(), "floatBitsToUint") ||
!strcmp(ir->callee_name(), "intBitsToFloat") ||
!strcmp(ir->callee_name(), "uintBitsToFloat") ||
- !strcmp(ir->callee_name(), "bitfieldReverse") ||
- !strcmp(ir->callee_name(), "frexp") ||
- !strcmp(ir->callee_name(), "ldexp") ||
- /* Parameters and outputs are always highp: */
- /* TODO: The operations are highp, but carry and borrow outputs are lowp. */
- !strcmp(ir->callee_name(), "uaddCarry") ||
- !strcmp(ir->callee_name(), "usubBorrow") ||
- !strcmp(ir->callee_name(), "imulExtended") ||
- !strcmp(ir->callee_name(), "umulExtended") ||
- !strcmp(ir->callee_name(), "unpackUnorm2x16") ||
- !strcmp(ir->callee_name(), "unpackSnorm2x16") ||
- /* Outputs are highp: */
- !strcmp(ir->callee_name(), "packUnorm2x16") ||
- !strcmp(ir->callee_name(), "packSnorm2x16") ||
- /* Parameters are mediump and outputs are highp. The parameters should
- * be optimized in NIR, not here, e.g:
- * - packHalf2x16 can just be a bitcast from f16vec2 to uint32
- * - Other opcodes don't have to convert parameters to highp if the hw
- * has f16 versions. Optimize in NIR accordingly.
- */
- !strcmp(ir->callee_name(), "packHalf2x16") ||
- !strcmp(ir->callee_name(), "packUnorm4x8") ||
- !strcmp(ir->callee_name(), "packSnorm4x8") ||
/* Atomic functions are not lowered. */
strstr(ir->callee_name(), "atomic") == ir->callee_name())
return GLSL_PRECISION_HIGH;
- assert(ir->callee->return_precision == GLSL_PRECISION_NONE);
-
/* Number of parameters to check if they are lowerable. */
unsigned check_parameters = ir->actual_parameters.length();
check_parameters = 1;
} else if (!strcmp(ir->callee_name(), "bitfieldInsert")) {
check_parameters = 2;
- } if (function_always_returns_mediump_or_lowp(ir->callee_name())) {
- /* These only lower the return value. Parameters keep their precision,
- * which is preserved in map_builtin.
- */
- check_parameters = 0;
}
/* If the call is to a builtin, then the function won’t have a return
handle_precision(var->type, return_precision);
if (lower_state == SHOULD_LOWER) {
- /* There probably shouldn’t be any situations where multiple ir_call
- * instructions write to the same temporary?
+ /* Function calls always write to a temporary return value in the caller,
+ * which has no other users. That temp may start with the precision of
+ * the function's signature, but if we're inferring the precision of an
+ * unqualified builtin operation (particularly the imageLoad overrides!)
+ * then we need to update it.
*/
- assert(var->data.precision == GLSL_PRECISION_NONE);
var->data.precision = GLSL_PRECISION_MEDIUM;
} else {
var->data.precision = GLSL_PRECISION_HIGH;