From 1d165b0548639df48c406fd6514298309e68aba9 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Mon, 10 Sep 2018 22:38:29 -0700 Subject: [PATCH] glsl: Add new expressions for INTEL_shader_integer_functions2 v2: Re-write iadd64_saturate and isub64_saturate to avoid undefined overflow behavior. Also fix copy-and-paste bug in isub64_saturate. Suggested by Caio. v3: Avoid signed integer overflow for abs_sub(0, INT_MIN). Noticed by Caio. v4: Alternate fix for signed integer overflow for abs_sub(0, INT_MIN). I tried the previous methon in a small test program with -ftrapv, and it failed. Reviewed-by: Caio Marcelo de Oliveira Filho Part-of: --- src/compiler/glsl/ir.cpp | 40 ++++++++++++++++++++ src/compiler/glsl/ir_constant_expression.cpp | 36 ++++++++++++++++++ src/compiler/glsl/ir_expression_operation.py | 26 +++++++++++++ src/compiler/glsl/ir_validate.cpp | 24 ++++++++++++ src/mesa/program/ir_to_mesa.cpp | 7 ++++ 5 files changed, 133 insertions(+) diff --git a/src/compiler/glsl/ir.cpp b/src/compiler/glsl/ir.cpp index 7a6fe46073a..3f4802013f2 100644 --- a/src/compiler/glsl/ir.cpp +++ b/src/compiler/glsl/ir.cpp @@ -257,6 +257,7 @@ ir_expression::ir_expression(int op, ir_rvalue *op0) case ir_unop_dFdy_fine: case ir_unop_bitfield_reverse: case ir_unop_interpolate_at_centroid: + case ir_unop_clz: case ir_unop_saturate: case ir_unop_atan: this->type = op0->type; @@ -500,6 +501,7 @@ ir_expression::ir_expression(int op, ir_rvalue *op0, ir_rvalue *op1) break; case ir_binop_imul_high: + case ir_binop_mul_32x16: case ir_binop_carry: case ir_binop_borrow: case ir_binop_lshift: @@ -510,6 +512,44 @@ ir_expression::ir_expression(int op, ir_rvalue *op0, ir_rvalue *op1) this->type = op0->type; break; + case ir_binop_add_sat: + case ir_binop_sub_sat: + case ir_binop_avg: + case ir_binop_avg_round: + assert(op0->type == op1->type); + this->type = op0->type; + break; + + case ir_binop_abs_sub: { + enum glsl_base_type base; + + assert(op0->type == op1->type); + + switch (op0->type->base_type) { + case GLSL_TYPE_UINT: + case GLSL_TYPE_INT: + base = GLSL_TYPE_UINT; + break; + case GLSL_TYPE_UINT8: + case GLSL_TYPE_INT8: + base = GLSL_TYPE_UINT8; + break; + case GLSL_TYPE_UINT16: + case GLSL_TYPE_INT16: + base = GLSL_TYPE_UINT16; + break; + case GLSL_TYPE_UINT64: + case GLSL_TYPE_INT64: + base = GLSL_TYPE_UINT64; + break; + default: + unreachable(!"Invalid base type."); + } + + this->type = glsl_type::get_instance(base, op0->type->vector_elements, 1); + break; + } + case ir_binop_vector_extract: this->type = op0->type->get_scalar_type(); break; diff --git a/src/compiler/glsl/ir_constant_expression.cpp b/src/compiler/glsl/ir_constant_expression.cpp index 5b1b5aa8eff..d7f0abe8304 100644 --- a/src/compiler/glsl/ir_constant_expression.cpp +++ b/src/compiler/glsl/ir_constant_expression.cpp @@ -416,6 +416,42 @@ unpack_half_1x16(uint16_t u) return _mesa_half_to_float(u); } +static int32_t +iadd_saturate(int32_t a, int32_t b) +{ + return CLAMP(int64_t(a) + int64_t(b), INT32_MIN, INT32_MAX); +} + +static int64_t +iadd64_saturate(int64_t a, int64_t b) +{ + if (a < 0 && b < INT64_MIN - a) + return INT64_MIN; + + if (a > 0 && b > INT64_MAX - a) + return INT64_MAX; + + return a + b; +} + +static int32_t +isub_saturate(int32_t a, int32_t b) +{ + return CLAMP(int64_t(a) - int64_t(b), INT32_MIN, INT32_MAX); +} + +static int64_t +isub64_saturate(int64_t a, int64_t b) +{ + if (b > 0 && a < INT64_MIN + b) + return INT64_MIN; + + if (b < 0 && a > INT64_MAX + b) + return INT64_MAX; + + return a - b; +} + /** * Get the constant that is ultimately referenced by an r-value, in a constant * expression evaluation context. diff --git a/src/compiler/glsl/ir_expression_operation.py b/src/compiler/glsl/ir_expression_operation.py index 757546d28e1..d5c43e6e53a 100644 --- a/src/compiler/glsl/ir_expression_operation.py +++ b/src/compiler/glsl/ir_expression_operation.py @@ -539,6 +539,7 @@ ir_expression_operation = [ operation("bit_count", 1, source_types=(uint_type, int_type), dest_type=int_type, c_expression="util_bitcount({src0})"), operation("find_msb", 1, source_types=(uint_type, int_type), dest_type=int_type, c_expression={'u': "find_msb_uint({src0})", 'i': "find_msb_int({src0})"}), operation("find_lsb", 1, source_types=(uint_type, int_type), dest_type=int_type, c_expression="find_msb_uint({src0} & -{src0})"), + operation("clz", 1, source_types=(uint_type,), dest_type=uint_type, c_expression="(unsigned)(31 - find_msb_uint({src0}))"), operation("saturate", 1, printable_name="sat", source_types=(float_type,), c_expression="CLAMP({src0}, 0.0f, 1.0f)"), @@ -584,8 +585,33 @@ ir_expression_operation = [ operation("add", 2, printable_name="+", source_types=numeric_types, c_expression="{src0} + {src1}", flags=vector_scalar_operation), operation("sub", 2, printable_name="-", source_types=numeric_types, c_expression="{src0} - {src1}", flags=vector_scalar_operation), + operation("add_sat", 2, printable_name="add_sat", source_types=integer_types, c_expression={ + 'u': "({src0} + {src1}) < {src0} ? UINT32_MAX : ({src0} + {src1})", + 'i': "iadd_saturate({src0}, {src1})", + 'u64': "({src0} + {src1}) < {src0} ? UINT64_MAX : ({src0} + {src1})", + 'i64': "iadd64_saturate({src0}, {src1})" + }), + operation("sub_sat", 2, printable_name="sub_sat", source_types=integer_types, c_expression={ + 'u': "({src1} > {src0}) ? 0 : {src0} - {src1}", + 'i': "isub_saturate({src0}, {src1})", + 'u64': "({src1} > {src0}) ? 0 : {src0} - {src1}", + 'i64': "isub64_saturate({src0}, {src1})" + }), + operation("abs_sub", 2, printable_name="abs_sub", source_types=integer_types, c_expression={ + 'u': "({src1} > {src0}) ? {src1} - {src0} : {src0} - {src1}", + 'i': "({src1} > {src0}) ? (unsigned){src1} - (unsigned){src0} : (unsigned){src0} - (unsigned){src1}", + 'u64': "({src1} > {src0}) ? {src1} - {src0} : {src0} - {src1}", + 'i64': "({src1} > {src0}) ? (uint64_t){src1} - (uint64_t){src0} : (uint64_t){src0} - (uint64_t){src1}", + }), + operation("avg", 2, printable_name="average", source_types=integer_types, c_expression="({src0} >> 1) + ({src1} >> 1) + (({src0} & {src1}) & 1)"), + operation("avg_round", 2, printable_name="average_rounded", source_types=integer_types, c_expression="({src0} >> 1) + ({src1} >> 1) + (({src0} | {src1}) & 1)"), + # "Floating-point or low 32-bit integer multiply." operation("mul", 2, printable_name="*", source_types=numeric_types, c_expression="{src0} * {src1}"), + operation("mul_32x16", 2, printable_name="*", source_types=(uint_type, int_type), c_expression={ + 'u': "{src0} * (uint16_t){src1}", + 'i': "{src0} * (int16_t){src0}" + }), operation("imul_high", 2), # Calculates the high 32-bits of a 64-bit multiply. operation("div", 2, printable_name="/", source_types=numeric_types, c_expression={'u': "{src1} == 0 ? 0 : {src0} / {src1}", 'i': "{src1} == 0 ? 0 : {src0} / {src1}", 'u64': "{src1} == 0 ? 0 : {src0} / {src1}", 'i64': "{src1} == 0 ? 0 : {src0} / {src1}", 'default': "{src0} / {src1}"}, flags=vector_scalar_operation), diff --git a/src/compiler/glsl/ir_validate.cpp b/src/compiler/glsl/ir_validate.cpp index d0ffad0bd39..80b0ce9efe1 100644 --- a/src/compiler/glsl/ir_validate.cpp +++ b/src/compiler/glsl/ir_validate.cpp @@ -546,6 +546,11 @@ ir_validate::visit_leave(ir_expression *ir) assert(ir->type->base_type == GLSL_TYPE_INT); break; + case ir_unop_clz: + assert(ir->operands[0]->type == ir->type); + assert(ir->type->base_type == GLSL_TYPE_UINT); + break; + case ir_unop_noise: /* XXX what can we assert here? */ break; @@ -649,6 +654,25 @@ ir_validate::visit_leave(ir_expression *ir) } break; + case ir_binop_abs_sub: + assert(ir->operands[0]->type == ir->operands[1]->type); + assert(ir->operands[0]->type->is_integer_32_64()); + assert(ir->operands[0]->type->vector_elements == + ir->type->vector_elements); + assert(ir->type->base_type == GLSL_TYPE_UINT || + ir->type->base_type == GLSL_TYPE_UINT64); + break; + + case ir_binop_add_sat: + case ir_binop_sub_sat: + case ir_binop_avg: + case ir_binop_avg_round: + assert(ir->type == ir->operands[0]->type); + assert(ir->type == ir->operands[1]->type); + assert(ir->type->is_integer_32_64()); + break; + + case ir_binop_mul_32x16: case ir_binop_imul_high: assert(ir->type == ir->operands[0]->type); assert(ir->type == ir->operands[1]->type); diff --git a/src/mesa/program/ir_to_mesa.cpp b/src/mesa/program/ir_to_mesa.cpp index dfc52e718d1..2bf01098db9 100644 --- a/src/mesa/program/ir_to_mesa.cpp +++ b/src/mesa/program/ir_to_mesa.cpp @@ -1296,6 +1296,12 @@ ir_to_mesa_visitor::visit(ir_expression *ir) case ir_binop_ldexp: case ir_binop_carry: case ir_binop_borrow: + case ir_binop_abs_sub: + case ir_binop_add_sat: + case ir_binop_sub_sat: + case ir_binop_avg: + case ir_binop_avg_round: + case ir_binop_mul_32x16: case ir_binop_imul_high: case ir_unop_interpolate_at_centroid: case ir_binop_interpolate_at_offset: @@ -1340,6 +1346,7 @@ ir_to_mesa_visitor::visit(ir_expression *ir) case ir_unop_unpack_image_2x32: case ir_unop_atan: case ir_binop_atan2: + case ir_unop_clz: assert(!"not supported"); break; -- 2.30.2