[WTF] Use __builtin_xxx_overflow for CheckedArithmetic
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 5 Mar 2018 02:15:12 +0000 (02:15 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 5 Mar 2018 02:15:12 +0000 (02:15 +0000)
https://bugs.webkit.org/show_bug.cgi?id=183319

Reviewed by Darin Adler.

GCC and Clang has the builtins for arithmetic operations with overflow flags.
CheckedArithmetic operations can be done with this builtins. Since the compiler
can use overflow flags, potentially this is more efficient. CheckedArithmetic
already has TestWebKitAPI tests and we ensured the tests pass.

* wtf/CheckedArithmetic.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229208 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WTF/ChangeLog
Source/WTF/wtf/CheckedArithmetic.h

index b470228..6616fbd 100644 (file)
@@ -1,3 +1,17 @@
+2018-03-04  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [WTF] Use __builtin_xxx_overflow for CheckedArithmetic
+        https://bugs.webkit.org/show_bug.cgi?id=183319
+
+        Reviewed by Darin Adler.
+
+        GCC and Clang has the builtins for arithmetic operations with overflow flags.
+        CheckedArithmetic operations can be done with this builtins. Since the compiler
+        can use overflow flags, potentially this is more efficient. CheckedArithmetic
+        already has TestWebKitAPI tests and we ensured the tests pass.
+
+        * wtf/CheckedArithmetic.h:
+
 2018-03-02  Yusuke Suzuki  <utatane.tea@gmail.com>
 
         [WTF] Remove RunLoop and RunLoop::Timer's interface using double as seconds
index 8bd3064..8568ed1 100644 (file)
@@ -270,6 +270,9 @@ template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOper
 
     static inline bool add(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
     {
+#if COMPILER(GCC_OR_CLANG)
+        return !__builtin_add_overflow(lhs, rhs, &result);
+#else
         if (signsMatch(lhs, rhs)) {
             if (lhs >= 0) {
                 if ((std::numeric_limits<ResultType>::max() - rhs) < lhs)
@@ -282,10 +285,14 @@ template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOper
         } // if the signs do not match this operation can't overflow
         result = lhs + rhs;
         return true;
+#endif
     }
 
     static inline bool sub(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
     {
+#if COMPILER(GCC_OR_CLANG)
+        return !__builtin_sub_overflow(lhs, rhs, &result);
+#else
         if (!signsMatch(lhs, rhs)) {
             if (lhs >= 0) {
                 if (lhs > std::numeric_limits<ResultType>::max() + rhs)
@@ -297,10 +304,14 @@ template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOper
         } // if the signs match this operation can't overflow
         result = lhs - rhs;
         return true;
+#endif
     }
 
     static inline bool multiply(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
     {
+#if COMPILER(GCC_OR_CLANG)
+        return !__builtin_mul_overflow(lhs, rhs, &result);
+#else
         if (signsMatch(lhs, rhs)) {
             if (lhs >= 0) {
                 if (lhs && (std::numeric_limits<ResultType>::max() / lhs) < rhs)
@@ -322,6 +333,7 @@ template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOper
         }
         result = lhs * rhs;
         return true;
+#endif
     }
 
     static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; }
@@ -332,24 +344,35 @@ template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOper
     // LHS and RHS are unsigned types so bounds checks are nice and easy
     static inline bool add(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
     {
+#if COMPILER(GCC_OR_CLANG)
+        return !__builtin_add_overflow(lhs, rhs, &result);
+#else
         ResultType temp = lhs + rhs;
         if (temp < lhs)
             return false;
         result = temp;
         return true;
+#endif
     }
 
     static inline bool sub(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
     {
+#if COMPILER(GCC_OR_CLANG)
+        return !__builtin_sub_overflow(lhs, rhs, &result);
+#else
         ResultType temp = lhs - rhs;
         if (temp > lhs)
             return false;
         result = temp;
         return true;
+#endif
     }
 
     static inline bool multiply(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
     {
+#if COMPILER(GCC_OR_CLANG)
+        return !__builtin_mul_overflow(lhs, rhs, &result);
+#else
         if (!lhs || !rhs) {
             result = 0;
             return true;
@@ -358,6 +381,7 @@ template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOper
             return false;
         result = lhs * rhs;
         return true;
+#endif
     }
 
     static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; }
@@ -367,6 +391,9 @@ template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOper
 template <typename ResultType> struct ArithmeticOperations<int, unsigned, ResultType, true, false> {
     static inline bool add(int64_t lhs, int64_t rhs, ResultType& result)
     {
+#if COMPILER(GCC_OR_CLANG)
+        return !__builtin_add_overflow(lhs, rhs, &result);
+#else
         int64_t temp = lhs + rhs;
         if (temp < std::numeric_limits<ResultType>::min())
             return false;
@@ -374,10 +401,14 @@ template <typename ResultType> struct ArithmeticOperations<int, unsigned, Result
             return false;
         result = static_cast<ResultType>(temp);
         return true;
+#endif
     }
     
     static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result)
     {
+#if COMPILER(GCC_OR_CLANG)
+        return !__builtin_sub_overflow(lhs, rhs, &result);
+#else
         int64_t temp = lhs - rhs;
         if (temp < std::numeric_limits<ResultType>::min())
             return false;
@@ -385,10 +416,14 @@ template <typename ResultType> struct ArithmeticOperations<int, unsigned, Result
             return false;
         result = static_cast<ResultType>(temp);
         return true;
+#endif
     }
 
     static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result)
     {
+#if COMPILER(GCC_OR_CLANG)
+        return !__builtin_mul_overflow(lhs, rhs, &result);
+#else
         int64_t temp = lhs * rhs;
         if (temp < std::numeric_limits<ResultType>::min())
             return false;
@@ -396,6 +431,7 @@ template <typename ResultType> struct ArithmeticOperations<int, unsigned, Result
             return false;
         result = static_cast<ResultType>(temp);
         return true;
+#endif
     }
 
     static inline bool equals(int lhs, unsigned rhs)