CheckedArithmetic.h revision 341825
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#include "llvm/ADT/Optional.h" 20 21#include <type_traits> 22 23namespace { 24 25/// Utility function to apply a given method of \c APInt \p F to \p LHS and 26/// \p RHS. 27/// \return Empty optional if the operation overflows, or result otherwise. 28template <typename T, typename F> 29typename std::enable_if<std::is_integral<T>::value && sizeof(T) * 8 <= 64, 30 llvm::Optional<T>>::type 31checkedOp(T LHS, T RHS, F Op, bool Signed = true) { 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); 36 if (Overflow) 37 return llvm::None; 38 return Signed ? Out.getSExtValue() : Out.getZExtValue(); 39} 40} 41 42namespace llvm { 43 44/// Add two signed integers \p LHS and \p RHS. 45/// \return Optional of sum if no signed overflow occurred, 46/// \c None otherwise. 47template <typename T> 48typename std::enable_if<std::is_signed<T>::value, llvm::Optional<T>>::type 49checkedAdd(T LHS, T RHS) { 50 return checkedOp(LHS, RHS, &llvm::APInt::sadd_ov); 51} 52 53/// Multiply two signed integers \p LHS and \p RHS. 54/// \return Optional of product if no signed overflow occurred, 55/// \c None otherwise. 56template <typename T> 57typename std::enable_if<std::is_signed<T>::value, llvm::Optional<T>>::type 58checkedMul(T LHS, T RHS) { 59 return checkedOp(LHS, RHS, &llvm::APInt::smul_ov); 60} 61 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. 65template <typename T> 66typename std::enable_if<std::is_signed<T>::value, llvm::Optional<T>>::type 67checkedMulAdd(T A, T B, T C) { 68 if (auto Product = checkedMul(A, B)) 69 return checkedAdd(*Product, C); 70 return llvm::None; 71} 72 73/// Add two unsigned integers \p LHS and \p RHS. 74/// \return Optional of sum if no unsigned overflow occurred, 75/// \c None otherwise. 76template <typename T> 77typename std::enable_if<std::is_unsigned<T>::value, llvm::Optional<T>>::type 78checkedAddUnsigned(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. 85template <typename T> 86typename std::enable_if<std::is_unsigned<T>::value, llvm::Optional<T>>::type 87checkedMulUnsigned(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. 94template <typename T> 95typename std::enable_if<std::is_unsigned<T>::value, llvm::Optional<T>>::type 96checkedMulAddUnsigned(T A, T B, T C) { 97 if (auto Product = checkedMulUnsigned(A, B)) 98 return checkedAddUnsigned(*Product, C); 99 return llvm::None; 100} 101 102} // End llvm namespace 103 104#endif 105