Home | History | Annotate | Download | only in gallivm
      1 /**************************************************************************
      2  *
      3  * Copyright 2013
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the
      8  * "Software"), to deal in the Software without restriction, including
      9  * without limitation the rights to use, copy, modify, merge, publish,
     10  * distribute, sub license, and/or sell copies of the Software, and to
     11  * permit persons to whom the Software is furnished to do so, subject to
     12  * the following conditions:
     13  *
     14  * The above copyright notice and this permission notice (including the
     15  * next paragraph) shall be included in all copies or substantial portions
     16  * of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
     22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     25  *
     26  **************************************************************************/
     27 
     28 
     29 /**
     30  * @file
     31  * Helper
     32  *
     33  * The functions in this file implement arthmetic operations with support
     34  * for overflow detection and reporting.
     35  *
     36  */
     37 
     38 #include "lp_bld_arit_overflow.h"
     39 
     40 #include "lp_bld_type.h"
     41 #include "lp_bld_const.h"
     42 #include "lp_bld_init.h"
     43 #include "lp_bld_intr.h"
     44 #include "lp_bld_logic.h"
     45 #include "lp_bld_pack.h"
     46 #include "lp_bld_debug.h"
     47 #include "lp_bld_bitarit.h"
     48 
     49 #include "util/u_memory.h"
     50 #include "util/u_debug.h"
     51 #include "util/u_math.h"
     52 #include "util/u_string.h"
     53 #include "util/u_cpu_detect.h"
     54 
     55 #include <float.h>
     56 
     57 
     58 static LLVMValueRef
     59 build_binary_int_overflow(struct gallivm_state *gallivm,
     60                           const char *intr_prefix,
     61                           LLVMValueRef a,
     62                           LLVMValueRef b,
     63                           LLVMValueRef *ofbit)
     64 {
     65    LLVMBuilderRef builder = gallivm->builder;
     66    char intr_str[256];
     67    LLVMTypeRef type_ref;
     68    LLVMTypeKind type_kind;
     69    unsigned type_width;
     70    LLVMTypeRef oelems[2];
     71    LLVMValueRef oresult;
     72    LLVMTypeRef otype;
     73 
     74    debug_assert(LLVMTypeOf(a) == LLVMTypeOf(b));
     75    type_ref = LLVMTypeOf(a);
     76    type_kind = LLVMGetTypeKind(type_ref);
     77 
     78    debug_assert(type_kind == LLVMIntegerTypeKind);
     79    type_width = LLVMGetIntTypeWidth(type_ref);
     80 
     81    debug_assert(type_width == 16 || type_width == 32 || type_width == 64);
     82 
     83    util_snprintf(intr_str, sizeof intr_str, "%s.i%u",
     84                  intr_prefix, type_width);
     85 
     86    oelems[0] = type_ref;
     87    oelems[1] = LLVMInt1TypeInContext(gallivm->context);
     88 
     89    otype = LLVMStructTypeInContext(gallivm->context, oelems, 2, FALSE);
     90    oresult = lp_build_intrinsic_binary(builder, intr_str,
     91                                        otype, a, b);
     92    if (ofbit) {
     93       if (*ofbit) {
     94          *ofbit = LLVMBuildOr(
     95             builder, *ofbit,
     96             LLVMBuildExtractValue(builder, oresult, 1, ""), "");
     97       } else {
     98          *ofbit = LLVMBuildExtractValue(builder, oresult, 1, "");
     99       }
    100    }
    101 
    102    return LLVMBuildExtractValue(builder, oresult, 0, "");
    103 }
    104 
    105 /**
    106  * Performs unsigned addition of two integers and reports
    107  * overflow if detected.
    108  *
    109  * The values @a and @b must be of the same integer type. If
    110  * an overflow is detected the IN/OUT @ofbit parameter is used:
    111  * - if it's pointing to a null value, the overflow bit is simply
    112  *   stored inside the variable it's pointing to,
    113  * - if it's pointing to a valid value, then that variable,
    114  *   which must be of i1 type, is ORed with the newly detected
    115  *   overflow bit. This is done to allow chaining of a number of
    116  *   overflow functions together without having to test the
    117  *   overflow bit after every single one.
    118  */
    119 LLVMValueRef
    120 lp_build_uadd_overflow(struct gallivm_state *gallivm,
    121                        LLVMValueRef a,
    122                        LLVMValueRef b,
    123                        LLVMValueRef *ofbit)
    124 {
    125    return build_binary_int_overflow(gallivm, "llvm.uadd.with.overflow",
    126                                     a, b, ofbit);
    127 }
    128 
    129 /**
    130  * Performs unsigned subtraction of two integers and reports
    131  * overflow if detected.
    132  *
    133  * The values @a and @b must be of the same integer type. If
    134  * an overflow is detected the IN/OUT @ofbit parameter is used:
    135  * - if it's pointing to a null value, the overflow bit is simply
    136  *   stored inside the variable it's pointing to,
    137  * - if it's pointing to a valid value, then that variable,
    138  *   which must be of i1 type, is ORed with the newly detected
    139  *   overflow bit. This is done to allow chaining of a number of
    140  *   overflow functions together without having to test the
    141  *   overflow bit after every single one.
    142  */
    143 LLVMValueRef
    144 lp_build_usub_overflow(struct gallivm_state *gallivm,
    145                        LLVMValueRef a,
    146                        LLVMValueRef b,
    147                        LLVMValueRef *ofbit)
    148 {
    149    return build_binary_int_overflow(gallivm, "llvm.usub.with.overflow",
    150                                     a, b, ofbit);
    151 }
    152 
    153 /**
    154  * Performs unsigned multiplication of  two integers and
    155  * reports overflow if detected.
    156  *
    157  * The values @a and @b must be of the same integer type. If
    158  * an overflow is detected the IN/OUT @ofbit parameter is used:
    159  * - if it's pointing to a null value, the overflow bit is simply
    160  *   stored inside the variable it's pointing to,
    161  * - if it's pointing to a valid value, then that variable,
    162  *   which must be of i1 type, is ORed with the newly detected
    163  *   overflow bit. This is done to allow chaining of a number of
    164  *   overflow functions together without having to test the
    165  *   overflow bit after every single one.
    166  */
    167 LLVMValueRef
    168 lp_build_umul_overflow(struct gallivm_state *gallivm,
    169                        LLVMValueRef a,
    170                        LLVMValueRef b,
    171                        LLVMValueRef *ofbit)
    172 {
    173    return build_binary_int_overflow(gallivm, "llvm.umul.with.overflow",
    174                                     a, b, ofbit);
    175 }
    176