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" |
Andrew Scull | cdfcccc | 2018-10-05 20:58:37 +0100 | [diff] [blame] | 19 | #include "llvm/ADT/Optional.h" |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 20 | |
| 21 | #include <type_traits> |
| 22 | |
| 23 | namespace { |
| 24 | |
| 25 | /// Utility function to apply a given method of \c APInt \p F to \p LHS and |
Andrew Scull | cdfcccc | 2018-10-05 20:58:37 +0100 | [diff] [blame] | 26 | /// \p RHS. |
| 27 | /// \return Empty optional if the operation overflows, or result otherwise. |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 28 | template <typename T, typename F> |
| 29 | typename std::enable_if<std::is_integral<T>::value && sizeof(T) * 8 <= 64, |
Andrew Scull | cdfcccc | 2018-10-05 20:58:37 +0100 | [diff] [blame] | 30 | llvm::Optional<T>>::type |
| 31 | checkedOp(T LHS, T RHS, F Op, bool Signed = true) { |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 32 | llvm::APInt ALHS(/*BitSize=*/sizeof(T) * 8, LHS, Signed); |
| 33 | llvm::APInt ARHS(/*BitSize=*/sizeof(T) * 8, RHS, Signed); |
| 34 | bool Overflow; |
| 35 | llvm::APInt Out = (ALHS.*Op)(ARHS, Overflow); |
Andrew Scull | cdfcccc | 2018-10-05 20:58:37 +0100 | [diff] [blame] | 36 | if (Overflow) |
| 37 | return llvm::None; |
| 38 | return Signed ? Out.getSExtValue() : Out.getZExtValue(); |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 39 | } |
| 40 | } |
| 41 | |
| 42 | namespace llvm { |
| 43 | |
Andrew Scull | cdfcccc | 2018-10-05 20:58:37 +0100 | [diff] [blame] | 44 | /// Add two signed integers \p LHS and \p RHS. |
| 45 | /// \return Optional of sum if no signed overflow occurred, |
| 46 | /// \c None otherwise. |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 47 | template <typename T> |
Andrew Scull | cdfcccc | 2018-10-05 20:58:37 +0100 | [diff] [blame] | 48 | typename std::enable_if<std::is_signed<T>::value, llvm::Optional<T>>::type |
| 49 | checkedAdd(T LHS, T RHS) { |
| 50 | return checkedOp(LHS, RHS, &llvm::APInt::sadd_ov); |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 51 | } |
| 52 | |
Andrew Scull | cdfcccc | 2018-10-05 20:58:37 +0100 | [diff] [blame] | 53 | /// Multiply two signed integers \p LHS and \p RHS. |
| 54 | /// \return Optional of product if no signed overflow occurred, |
| 55 | /// \c None otherwise. |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 56 | template <typename T> |
Andrew Scull | cdfcccc | 2018-10-05 20:58:37 +0100 | [diff] [blame] | 57 | typename std::enable_if<std::is_signed<T>::value, llvm::Optional<T>>::type |
| 58 | checkedMul(T LHS, T RHS) { |
| 59 | return checkedOp(LHS, RHS, &llvm::APInt::smul_ov); |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 60 | } |
| 61 | |
Andrew Scull | cdfcccc | 2018-10-05 20:58:37 +0100 | [diff] [blame] | 62 | /// Multiply A and B, and add C to the resulting product. |
| 63 | /// \return Optional of result if no signed overflow occurred, |
| 64 | /// \c None otherwise. |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 65 | template <typename T> |
Andrew Scull | cdfcccc | 2018-10-05 20:58:37 +0100 | [diff] [blame] | 66 | typename std::enable_if<std::is_signed<T>::value, llvm::Optional<T>>::type |
| 67 | checkedMulAdd(T A, T B, T C) { |
| 68 | if (auto Product = checkedMul(A, B)) |
| 69 | return checkedAdd(*Product, C); |
| 70 | return llvm::None; |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 71 | } |
| 72 | |
Andrew Scull | cdfcccc | 2018-10-05 20:58:37 +0100 | [diff] [blame] | 73 | /// Add two unsigned integers \p LHS and \p RHS. |
| 74 | /// \return Optional of sum if no unsigned overflow occurred, |
| 75 | /// \c None otherwise. |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 76 | template <typename T> |
Andrew Scull | cdfcccc | 2018-10-05 20:58:37 +0100 | [diff] [blame] | 77 | typename std::enable_if<std::is_unsigned<T>::value, llvm::Optional<T>>::type |
| 78 | checkedAddUnsigned(T LHS, T RHS) { |
| 79 | return checkedOp(LHS, RHS, &llvm::APInt::uadd_ov, /*Signed=*/false); |
| 80 | } |
| 81 | |
| 82 | /// Multiply two unsigned integers \p LHS and \p RHS. |
| 83 | /// \return Optional of product if no unsigned overflow occurred, |
| 84 | /// \c None otherwise. |
| 85 | template <typename T> |
| 86 | typename std::enable_if<std::is_unsigned<T>::value, llvm::Optional<T>>::type |
| 87 | checkedMulUnsigned(T LHS, T RHS) { |
| 88 | return checkedOp(LHS, RHS, &llvm::APInt::umul_ov, /*Signed=*/false); |
| 89 | } |
| 90 | |
| 91 | /// Multiply unsigned integers A and B, and add C to the resulting product. |
| 92 | /// \return Optional of result if no unsigned overflow occurred, |
| 93 | /// \c None otherwise. |
| 94 | template <typename T> |
| 95 | typename std::enable_if<std::is_unsigned<T>::value, llvm::Optional<T>>::type |
| 96 | checkedMulAddUnsigned(T A, T B, T C) { |
| 97 | if (auto Product = checkedMulUnsigned(A, B)) |
| 98 | return checkedAddUnsigned(*Product, C); |
| 99 | return llvm::None; |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 100 | } |
| 101 | |
| 102 | } // End llvm namespace |
| 103 | |
| 104 | #endif |