Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame^] | 1 | //==-- llvm/Support/CheckedArithmetic.h - Safe arithmetical operations *- C++ // |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This file contains generic functions for operating on integers which |
| 11 | // give the indication on whether the operation has overflown. |
| 12 | // |
| 13 | //===----------------------------------------------------------------------===// |
| 14 | |
| 15 | #ifndef LLVM_SUPPORT_CHECKEDARITHMETIC_H |
| 16 | #define LLVM_SUPPORT_CHECKEDARITHMETIC_H |
| 17 | |
| 18 | #include "llvm/ADT/APInt.h" |
| 19 | |
| 20 | #include <type_traits> |
| 21 | |
| 22 | namespace { |
| 23 | |
| 24 | /// Utility function to apply a given method of \c APInt \p F to \p LHS and |
| 25 | /// \p RHS, and write the output into \p Res. |
| 26 | /// \return Whether the operation overflows. |
| 27 | template <typename T, typename F> |
| 28 | typename std::enable_if<std::is_integral<T>::value && sizeof(T) * 8 <= 64, |
| 29 | bool>::type |
| 30 | checkedOp(T LHS, T RHS, F Op, T *Res = nullptr, bool Signed = true) { |
| 31 | llvm::APInt ALHS(/*BitSize=*/sizeof(T) * 8, LHS, Signed); |
| 32 | llvm::APInt ARHS(/*BitSize=*/sizeof(T) * 8, RHS, Signed); |
| 33 | bool Overflow; |
| 34 | llvm::APInt Out = (ALHS.*Op)(ARHS, Overflow); |
| 35 | if (Res) |
| 36 | *Res = Signed ? Out.getSExtValue() : Out.getZExtValue(); |
| 37 | return Overflow; |
| 38 | } |
| 39 | } |
| 40 | |
| 41 | namespace llvm { |
| 42 | |
| 43 | /// Add two signed integers \p LHS and \p RHS, write into \p Res if non-null. |
| 44 | /// Does not guarantee saturating arithmetic. |
| 45 | /// \return Whether the result overflows. |
| 46 | template <typename T> |
| 47 | typename std::enable_if<std::is_signed<T>::value, bool>::type |
| 48 | checkedAdd(T LHS, T RHS, T *Res = nullptr) { |
| 49 | return checkedOp(LHS, RHS, &llvm::APInt::sadd_ov, Res); |
| 50 | } |
| 51 | |
| 52 | /// Multiply two signed integers \p LHS and \p RHS, write into \p Res if |
| 53 | /// non-null. |
| 54 | /// Does not guarantee saturating arithmetic. |
| 55 | /// \return Whether the result overflows. |
| 56 | template <typename T> |
| 57 | typename std::enable_if<std::is_signed<T>::value, bool>::type |
| 58 | checkedMul(T LHS, T RHS, T *Res = nullptr) { |
| 59 | return checkedOp(LHS, RHS, &llvm::APInt::smul_ov, Res); |
| 60 | } |
| 61 | |
| 62 | /// Add two unsigned integers \p LHS and \p RHS, write into \p Res if non-null. |
| 63 | /// Does not guarantee saturating arithmetic. |
| 64 | /// \return Whether the result overflows. |
| 65 | template <typename T> |
| 66 | typename std::enable_if<std::is_unsigned<T>::value, bool>::type |
| 67 | checkedAddUnsigned(T LHS, T RHS, T *Res = nullptr) { |
| 68 | return checkedOp(LHS, RHS, &llvm::APInt::uadd_ov, Res, /*Signed=*/false); |
| 69 | } |
| 70 | |
| 71 | /// Multiply two unsigned integers \p LHS and \p RHS, write into \p Res if |
| 72 | /// non-null. |
| 73 | /// Does not guarantee saturating arithmetic. |
| 74 | /// \return Whether the result overflows. |
| 75 | template <typename T> |
| 76 | typename std::enable_if<std::is_unsigned<T>::value, bool>::type |
| 77 | checkedMulUnsigned(T LHS, T RHS, T *Res = nullptr) { |
| 78 | return checkedOp(LHS, RHS, &llvm::APInt::umul_ov, Res, /*Signed=*/false); |
| 79 | } |
| 80 | |
| 81 | } // End llvm namespace |
| 82 | |
| 83 | #endif |