From 34546d61c1112aad888c3b8f07604bffb3f2e7b9 Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Thu, 27 Jun 2013 15:23:21 -0400 Subject: [PATCH] draw/gallivm: export overflow arithmetic to its own file We'll be reusing this code so lets put it in a common file and use it in the draw module. Signed-off-by: Zack Rusin --- src/gallium/auxiliary/Makefile.sources | 1 + src/gallium/auxiliary/draw/draw_llvm.c | 55 ++---- .../auxiliary/gallivm/lp_bld_arit_overflow.c | 165 ++++++++++++++++++ .../auxiliary/gallivm/lp_bld_arit_overflow.h | 57 ++++++ 4 files changed, 234 insertions(+), 44 deletions(-) create mode 100644 src/gallium/auxiliary/gallivm/lp_bld_arit_overflow.c create mode 100644 src/gallium/auxiliary/gallivm/lp_bld_arit_overflow.h diff --git a/src/gallium/auxiliary/Makefile.sources b/src/gallium/auxiliary/Makefile.sources index 20ff5ba73ef..47517626d32 100644 --- a/src/gallium/auxiliary/Makefile.sources +++ b/src/gallium/auxiliary/Makefile.sources @@ -163,6 +163,7 @@ GENERATED_SOURCES := \ GALLIVM_SOURCES := \ gallivm/lp_bld_arit.c \ + gallivm/lp_bld_arit_overflow.c \ gallivm/lp_bld_assert.c \ gallivm/lp_bld_bitarit.c \ gallivm/lp_bld_const.c \ diff --git a/src/gallium/auxiliary/draw/draw_llvm.c b/src/gallium/auxiliary/draw/draw_llvm.c index 33cccfe99aa..97b463f4ff8 100644 --- a/src/gallium/auxiliary/draw/draw_llvm.c +++ b/src/gallium/auxiliary/draw/draw_llvm.c @@ -32,6 +32,7 @@ #include "draw_gs.h" #include "gallivm/lp_bld_arit.h" +#include "gallivm/lp_bld_arit_overflow.h" #include "gallivm/lp_bld_logic.h" #include "gallivm/lp_bld_const.h" #include "gallivm/lp_bld_swizzle.h" @@ -699,13 +700,7 @@ generate_fetch(struct gallivm_state *gallivm, LLVMValueRef temp_ptr = lp_build_alloca(gallivm, lp_build_vec_type(gallivm, lp_float32_vec4_type()), ""); - LLVMValueRef ofbit, oresult; - LLVMTypeRef oelems[2] = { - LLVMInt32TypeInContext(gallivm->context), - LLVMInt1TypeInContext(gallivm->context) - }; - LLVMTypeRef otype = LLVMStructTypeInContext(gallivm->context, - oelems, 2, FALSE); + LLVMValueRef ofbit = NULL; struct lp_build_if_state if_ctx; if (velem->instance_divisor) { @@ -715,44 +710,16 @@ generate_fetch(struct gallivm_state *gallivm, "instance_divisor"); } - oresult = lp_build_intrinsic_binary(builder, - "llvm.umul.with.overflow.i32", - otype, vb_stride, index); - ofbit = LLVMBuildExtractValue(builder, oresult, 1, ""); - stride = LLVMBuildExtractValue(builder, oresult, 0, ""); - - oresult = lp_build_intrinsic_binary(builder, - "llvm.uadd.with.overflow.i32", - otype, stride, vb_buffer_offset); - ofbit = LLVMBuildOr( - builder, ofbit, - LLVMBuildExtractValue(builder, oresult, 1, ""), - ""); - stride = LLVMBuildExtractValue(builder, oresult, 0, ""); - - oresult = lp_build_intrinsic_binary( - builder, - "llvm.uadd.with.overflow.i32", - otype, stride, - lp_build_const_int32(gallivm, velem->src_offset)); - ofbit = LLVMBuildOr( - builder, ofbit, - LLVMBuildExtractValue(builder, oresult, 1, ""), - ""); - stride = LLVMBuildExtractValue(builder, oresult, 0, ""); - - - oresult = lp_build_intrinsic_binary( - builder, - "llvm.uadd.with.overflow.i32", - otype, stride, + stride = lp_build_umul_overflow(gallivm, vb_stride, index, &ofbit); + stride = lp_build_uadd_overflow(gallivm, stride, vb_buffer_offset, &ofbit); + stride = lp_build_uadd_overflow( + gallivm, stride, + lp_build_const_int32(gallivm, velem->src_offset), &ofbit); + needed_buffer_size = lp_build_uadd_overflow( + gallivm, stride, lp_build_const_int32(gallivm, - util_format_get_blocksize(velem->src_format))); - ofbit = LLVMBuildOr( - builder, ofbit, - LLVMBuildExtractValue(builder, oresult, 1, ""), - ""); - needed_buffer_size = LLVMBuildExtractValue(builder, oresult, 0, ""); + util_format_get_blocksize(velem->src_format)), + &ofbit); buffer_overflowed = LLVMBuildICmp(builder, LLVMIntUGT, needed_buffer_size, buffer_size, diff --git a/src/gallium/auxiliary/gallivm/lp_bld_arit_overflow.c b/src/gallium/auxiliary/gallivm/lp_bld_arit_overflow.c new file mode 100644 index 00000000000..43f266086e8 --- /dev/null +++ b/src/gallium/auxiliary/gallivm/lp_bld_arit_overflow.c @@ -0,0 +1,165 @@ +/************************************************************************** + * + * Copyright 2013 + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +/** + * @file + * Helper + * + * The functions in this file implement arthmetic operations with support + * for overflow detection and reporting. + * + */ + +#include "lp_bld_arit_overflow.h" + +#include "lp_bld_type.h" +#include "lp_bld_const.h" +#include "lp_bld_init.h" +#include "lp_bld_intr.h" +#include "lp_bld_logic.h" +#include "lp_bld_pack.h" +#include "lp_bld_debug.h" +#include "lp_bld_bitarit.h" + +#include "util/u_memory.h" +#include "util/u_debug.h" +#include "util/u_math.h" +#include "util/u_string.h" +#include "util/u_cpu_detect.h" + +#include + + +static LLVMValueRef +build_binary_int_overflow(struct gallivm_state *gallivm, + const char *intr_prefix, + LLVMValueRef a, + LLVMValueRef b, + LLVMValueRef *ofbit) +{ + static const int MAX_INTR_STR = 256; + LLVMBuilderRef builder = gallivm->builder; + char intr_str[MAX_INTR_STR]; + LLVMTypeRef type_ref; + LLVMTypeKind type_kind; + LLVMTypeRef oelems[2] = { + LLVMInt32TypeInContext(gallivm->context), + LLVMInt1TypeInContext(gallivm->context) + }; + LLVMValueRef oresult; + LLVMTypeRef otype; + + debug_assert(LLVMTypeOf(a) == LLVMTypeOf(b)); + type_ref = LLVMTypeOf(a); + type_kind = LLVMGetTypeKind(type_ref); + + debug_assert(type_kind == LLVMIntegerTypeKind); + + switch (LLVMGetIntTypeWidth(type_ref)) { + case 16: + snprintf(intr_str, MAX_INTR_STR - 1, "%s.i16", + intr_prefix); + oelems[0] = LLVMInt16TypeInContext(gallivm->context); + break; + case 32: + snprintf(intr_str, MAX_INTR_STR - 1, "%s.i32", + intr_prefix); + oelems[0] = LLVMInt32TypeInContext(gallivm->context); + break; + case 64: + snprintf(intr_str, MAX_INTR_STR - 1, "%s.i64", + intr_prefix); + oelems[0] = LLVMInt64TypeInContext(gallivm->context); + break; + default: + debug_assert(!"Unsupported integer width in overflow computation!"); + } + + otype = LLVMStructTypeInContext(gallivm->context, oelems, 2, FALSE); + oresult = lp_build_intrinsic_binary(builder, intr_str, + otype, a, b); + if (ofbit) { + if (*ofbit) { + *ofbit = LLVMBuildOr( + builder, *ofbit, + LLVMBuildExtractValue(builder, oresult, 1, ""), ""); + } else { + *ofbit = LLVMBuildExtractValue(builder, oresult, 1, ""); + } + } + + return LLVMBuildExtractValue(builder, oresult, 0, ""); +} + +/** + * Performs unsigned addition of two integers and reports + * overflow if detected. + * + * The values @a and @b must be of the same integer type. If + * an overflow is detected the IN/OUT @ofbit parameter is used: + * - if it's pointing to a null value, the overflow bit is simply + * stored inside the variable it's pointing to, + * - if it's pointing to a valid value, then that variable, + * which must be of i1 type, is ORed with the newly detected + * overflow bit. This is done to allow chaining of a number of + * overflow functions together without having to test the + * overflow bit after every single one. + */ +LLVMValueRef +lp_build_uadd_overflow(struct gallivm_state *gallivm, + LLVMValueRef a, + LLVMValueRef b, + LLVMValueRef *ofbit) +{ + return build_binary_int_overflow(gallivm, "llvm.uadd.with.overflow", + a, b, ofbit); +} + +/** + * Performs unsigned multiplication of two integers and + * reports overflow if detected. + * + * The values @a and @b must be of the same integer type. If + * an overflow is detected the IN/OUT @ofbit parameter is used: + * - if it's pointing to a null value, the overflow bit is simply + * stored inside the variable it's pointing to, + * - if it's pointing to a valid value, then that variable, + * which must be of i1 type, is ORed with the newly detected + * overflow bit. This is done to allow chaining of a number of + * overflow functions together without having to test the + * overflow bit after every single one. + */ +LLVMValueRef +lp_build_umul_overflow(struct gallivm_state *gallivm, + LLVMValueRef a, + LLVMValueRef b, + LLVMValueRef *ofbit) +{ + return build_binary_int_overflow(gallivm, "llvm.umul.with.overflow", + a, b, ofbit); +} diff --git a/src/gallium/auxiliary/gallivm/lp_bld_arit_overflow.h b/src/gallium/auxiliary/gallivm/lp_bld_arit_overflow.h new file mode 100644 index 00000000000..8c35a04181b --- /dev/null +++ b/src/gallium/auxiliary/gallivm/lp_bld_arit_overflow.h @@ -0,0 +1,57 @@ +/************************************************************************** + * + * Copyright 2013 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * @file + * Helper arithmetic functions with support for overflow detection + * and reporting. + * + * @author Zack Rusin + */ + + +#ifndef LP_BLD_ARIT_OVERFLOW_H +#define LP_BLD_ARIT_OVERFLOW_H + + +#include "gallivm/lp_bld.h" + +struct gallivm_state; + +LLVMValueRef +lp_build_uadd_overflow(struct gallivm_state *gallivm, + LLVMValueRef a, + LLVMValueRef b, + LLVMValueRef *ofbit); + +LLVMValueRef +lp_build_umul_overflow(struct gallivm_state *gallivm, + LLVMValueRef a, + LLVMValueRef b, + LLVMValueRef *ofbit); + +#endif /* !LP_BLD_ARIT_OVERFLOW_H */ -- 2.30.2