Skip to content

Commit 987c62a

Browse files
author
git apple-llvm automerger
committed
Merge commit '29d8c346c58c' from llvm.org/main into next
2 parents c662cd2 + 29d8c34 commit 987c62a

File tree

1 file changed

+73
-5
lines changed

1 file changed

+73
-5
lines changed

flang/include/flang/Common/format.h

Lines changed: 73 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "Fortran-consts.h"
1313
#include "enum-set.h"
1414
#include <cstring>
15+
#include <limits>
1516

1617
// Define a FormatValidator class template to validate a format expression
1718
// of a given CHAR type. To enable use in runtime library code as well as
@@ -28,6 +29,71 @@
2829

2930
namespace Fortran::common {
3031

32+
// AddOverflow and MulOverflow are copied from
33+
// llvm/include/llvm/Support/MathExtras.h and specialised to int64_t.
34+
35+
/// Add two signed integers, computing the two's complement truncated result,
36+
/// returning true if overflow occurred.
37+
static inline bool AddOverflow(int64_t X, int64_t Y, int64_t &Result) {
38+
#if __has_builtin(__builtin_add_overflow)
39+
return __builtin_add_overflow(X, Y, &Result);
40+
#else
41+
// Perform the unsigned addition.
42+
const uint64_t UX = static_cast<uint64_t>(X);
43+
const uint64_t UY = static_cast<uint64_t>(Y);
44+
const uint64_t UResult = UX + UY;
45+
46+
// Convert to signed.
47+
Result = static_cast<int64_t>(UResult);
48+
49+
// Adding two positive numbers should result in a positive number.
50+
if (X > 0 && Y > 0) {
51+
return Result <= 0;
52+
}
53+
// Adding two negatives should result in a negative number.
54+
if (X < 0 && Y < 0) {
55+
return Result >= 0;
56+
}
57+
return false;
58+
#endif
59+
}
60+
61+
/// Multiply two signed integers, computing the two's complement truncated
62+
/// result, returning true if an overflow occurred.
63+
static inline bool MulOverflow(int64_t X, int64_t Y, int64_t &Result) {
64+
#if __has_builtin(__builtin_mul_overflow)
65+
return __builtin_mul_overflow(X, Y, &Result);
66+
#else
67+
// Perform the unsigned multiplication on absolute values.
68+
const uint64_t UX =
69+
X < 0 ? (0 - static_cast<uint64_t>(X)) : static_cast<uint64_t>(X);
70+
const uint64_t UY =
71+
Y < 0 ? (0 - static_cast<uint64_t>(Y)) : static_cast<uint64_t>(Y);
72+
const uint64_t UResult = UX * UY;
73+
74+
// Convert to signed.
75+
const bool IsNegative = (X < 0) ^ (Y < 0);
76+
Result = IsNegative ? (0 - UResult) : UResult;
77+
78+
// If any of the args was 0, result is 0 and no overflow occurs.
79+
if (UX == 0 || UY == 0) {
80+
return false;
81+
}
82+
83+
// UX and UY are in [1, 2^n], where n is the number of digits.
84+
// Check how the max allowed absolute value (2^n for negative, 2^(n-1) for
85+
// positive) divided by an argument compares to the other.
86+
if (IsNegative) {
87+
return UX > (static_cast<uint64_t>(std::numeric_limits<int64_t>::max()) +
88+
uint64_t(1)) /
89+
UY;
90+
} else {
91+
return UX >
92+
(static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) / UY;
93+
}
94+
#endif
95+
}
96+
3197
struct FormatMessage {
3298
const char *text; // message text; may have one %s argument
3399
const char *arg; // optional %s argument value
@@ -214,16 +280,18 @@ template <typename CHAR> void FormatValidator<CHAR>::NextToken() {
214280
case '7':
215281
case '8':
216282
case '9': {
217-
int64_t lastValue;
218283
const CHAR *lastCursor;
219284
integerValue_ = 0;
220285
bool overflow{false};
221286
do {
222-
lastValue = integerValue_;
223287
lastCursor = cursor_;
224-
integerValue_ = 10 * integerValue_ + c - '0';
225-
if (lastValue > integerValue_) {
226-
overflow = true;
288+
if (!overflow) {
289+
overflow =
290+
MulOverflow(static_cast<int64_t>(10), integerValue_, integerValue_);
291+
}
292+
if (!overflow) {
293+
overflow = AddOverflow(
294+
integerValue_, static_cast<int64_t>(c - '0'), integerValue_);
227295
}
228296
c = NextChar();
229297
} while (c >= '0' && c <= '9');

0 commit comments

Comments
 (0)