Skip to content

Commit f4ec179

Browse files
authored
[ARM] Fix undefined behavior in isLegalAddImmediate (#132219)
Building clang under UBsan, it reported an integer overflow in this function when the input value was -2^63, because it's UB to pass the maximum negative value of an integer type to `std::abs`. Fixed by adding a new absolute-value function in `MathExtras.h` whose return type is the unsigned version of the argument type, and using that instead. (This seems like the kind of thing C++ should have already had, but apparently it doesn't, and I couldn't find an existing one in LLVM Support either.)
1 parent 6da8f56 commit f4ec179

File tree

2 files changed

+10
-1
lines changed

2 files changed

+10
-1
lines changed

llvm/include/llvm/Support/MathExtras.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,15 @@ inline int64_t SignExtend64(uint64_t X, unsigned B) {
595595
return int64_t(X << (64 - B)) >> (64 - B);
596596
}
597597

598+
/// Return the absolute value of a signed integer, converted to the
599+
/// corresponding unsigned integer type. Avoids undefined behavior in std::abs
600+
/// when you pass it INT_MIN or similar.
601+
template <typename T, typename U = std::make_unsigned_t<T>>
602+
constexpr U AbsoluteValue(T X) {
603+
// If X is negative, cast it to the unsigned type _before_ negating it.
604+
return X < 0 ? -static_cast<U>(X) : X;
605+
}
606+
598607
/// Subtract two unsigned integers, X and Y, of type T and return the absolute
599608
/// value of the result.
600609
template <typename U, typename V, typename T = common_uint<U, V>>

llvm/lib/Target/ARM/ARMISelLowering.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19691,7 +19691,7 @@ bool ARMTargetLowering::isLegalICmpImmediate(int64_t Imm) const {
1969119691
/// immediate into a register.
1969219692
bool ARMTargetLowering::isLegalAddImmediate(int64_t Imm) const {
1969319693
// Same encoding for add/sub, just flip the sign.
19694-
int64_t AbsImm = std::abs(Imm);
19694+
uint64_t AbsImm = AbsoluteValue(Imm);
1969519695
if (!Subtarget->isThumb())
1969619696
return ARM_AM::getSOImmVal(AbsImm) != -1;
1969719697
if (Subtarget->isThumb2())

0 commit comments

Comments
 (0)