draw/gallivm: export overflow arithmetic to its own file
authorZack Rusin <zackr@vmware.com>
Thu, 27 Jun 2013 19:23:21 +0000 (15:23 -0400)
committerZack Rusin <zackr@vmware.com>
Fri, 28 Jun 2013 08:24:24 +0000 (04:24 -0400)
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 <zackr@vmware.com>
src/gallium/auxiliary/Makefile.sources
src/gallium/auxiliary/draw/draw_llvm.c
src/gallium/auxiliary/gallivm/lp_bld_arit_overflow.c [new file with mode: 0644]
src/gallium/auxiliary/gallivm/lp_bld_arit_overflow.h [new file with mode: 0644]

index 20ff5ba73ef104f567da885302d42ccd9be7a81e..47517626d325ca7fb586d9570a434a53de093ca4 100644 (file)
@@ -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 \
index 33cccfe99aa5e6e0f7ef7c98164c11c61e06996e..97b463f4ff8bad37c7fcfdf16d16f92bcbf10ab7 100644 (file)
@@ -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 (file)
index 0000000..43f2660
--- /dev/null
@@ -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 <float.h>
+
+
+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 (file)
index 0000000..8c35a04
--- /dev/null
@@ -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 <zackr@vmware.com>
+ */
+
+
+#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 */