aboutsummaryrefslogtreecommitdiff
path: root/backend/lib/Support/APInt.cpp
diff options
context:
space:
mode:
authorRichard-Qin-X <richard.qin.001@gmail.com>2026-08-13 06:52:15 +0800
committerRichard-Qin-X <richard.qin.001@gmail.com>2026-08-13 06:52:15 +0800
commitaa7c85ca71859aab15bdf1e6dc1ea3a5aa5d1e28 (patch)
tree20d94c4debfe4900e362c6c7f8443bcfbd58ec28 /backend/lib/Support/APInt.cpp
parentd62f022c92fcc3ebe2269273628943a0089683fd (diff)
downloadrcc-project-aa7c85ca71859aab15bdf1e6dc1ea3a5aa5d1e28.tar.gz
rcc-project-aa7c85ca71859aab15bdf1e6dc1ea3a5aa5d1e28.tar.xz
[Support] Split APInt and APFloat ownership
Diffstat (limited to 'backend/lib/Support/APInt.cpp')
-rw-r--r--backend/lib/Support/APInt.cpp395
1 files changed, 395 insertions, 0 deletions
diff --git a/backend/lib/Support/APInt.cpp b/backend/lib/Support/APInt.cpp
new file mode 100644
index 0000000..898deee
--- /dev/null
+++ b/backend/lib/Support/APInt.cpp
@@ -0,0 +1,395 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "rcc/ADT/APInt.h"
+
+#include <algorithm>
+#include <bit>
+#include <cstddef>
+#include <cstdint>
+#include <limits>
+#include <ranges>
+#include <span>
+#include <string>
+#include <string_view>
+#include <utility>
+#include <vector>
+
+namespace rcc {
+namespace {
+
+[[nodiscard]] constexpr std::size_t wordCount(std::uint32_t BitWidth) noexcept {
+ return (static_cast<std::size_t>(BitWidth) + 63U) / 64U;
+}
+
+[[nodiscard]] constexpr std::uint64_t highWordMask(std::uint32_t BitWidth) noexcept {
+ const std::uint32_t UsedBits = BitWidth % 64U;
+ if (UsedBits == 0)
+ return std::numeric_limits<std::uint64_t>::max();
+ return (std::uint64_t{1} << UsedBits) - 1U;
+}
+
+[[nodiscard]] std::size_t significantWordCount(std::span<const std::uint64_t> Words) noexcept {
+ std::size_t Count = Words.size();
+ while (Count != 0 && Words[Count - 1U] == 0)
+ --Count;
+ return Count;
+}
+
+[[nodiscard]] Expected<void> verifyAPInt(std::uint32_t BitWidth,
+ std::span<const std::uint64_t> Words, ErrorCode Code) {
+ if (BitWidth == 0 || BitWidth > APInt::MaxBitWidth)
+ return makeUnexpected(Code, "APInt bit width is outside the supported range");
+ if (Words.size() != wordCount(BitWidth))
+ return makeUnexpected(Code, "APInt bit pattern has the wrong word count");
+ if ((Words.back() & ~highWordMask(BitWidth)) != 0)
+ return makeUnexpected(Code, "APInt has nonzero bits above its declared width");
+ return {};
+}
+
+[[nodiscard]] bool isHexDigit(char Character) noexcept {
+ return (Character >= '0' && Character <= '9') || (Character >= 'a' && Character <= 'f') ||
+ (Character >= 'A' && Character <= 'F');
+}
+
+[[nodiscard]] unsigned hexDigitValue(char Character) noexcept {
+ if (Character >= '0' && Character <= '9')
+ return static_cast<unsigned>(Character - '0');
+ if (Character >= 'a' && Character <= 'f')
+ return static_cast<unsigned>(Character - 'a') + 10U;
+ return static_cast<unsigned>(Character - 'A') + 10U;
+}
+
+void negateWords(std::vector<std::uint64_t> &Words, std::uint32_t BitWidth) {
+ for (std::uint64_t &Word : Words)
+ Word = ~Word;
+ std::uint64_t Carry = 1;
+ for (std::uint64_t &Word : Words) {
+ const std::uint64_t Previous = Word;
+ Word += Carry;
+ Carry = Carry != 0 && Word < Previous ? 1U : 0U;
+ }
+ Words.back() &= highWordMask(BitWidth);
+}
+
+[[nodiscard]] std::string unsignedDecimal(std::vector<std::uint64_t> Words) {
+ if (std::ranges::all_of(Words, [](std::uint64_t Word) { return Word == 0; }))
+ return "0";
+ std::string Digits;
+ while (!std::ranges::all_of(Words, [](std::uint64_t Word) { return Word == 0; })) {
+ unsigned __int128 Remainder = 0;
+ for (auto Iterator = Words.rbegin(); Iterator != Words.rend(); ++Iterator) {
+ const unsigned __int128 Dividend = (Remainder << 64U) | *Iterator;
+ *Iterator = static_cast<std::uint64_t>(Dividend / 10U);
+ Remainder = Dividend % 10U;
+ }
+ Digits.push_back(static_cast<char>('0' + static_cast<unsigned>(Remainder)));
+ }
+ std::ranges::reverse(Digits);
+ return Digits;
+}
+
+} // namespace
+
+APInt::APInt(std::uint64_t Value) {
+ if (Value == 0)
+ return;
+ Words.push_back(Value);
+ BitWidth = static_cast<std::uint32_t>(std::bit_width(Value));
+}
+
+Expected<APInt> APInt::create(std::uint32_t BitWidth, std::span<const std::uint64_t> Words) {
+ auto Verification = verifyAPInt(BitWidth, Words, ErrorCode::InvalidArgument);
+ if (!Verification)
+ return std::unexpected(Verification.error());
+ return APInt(BitWidth, std::vector<std::uint64_t>(Words.begin(), Words.end()));
+}
+
+Expected<APInt> APInt::fromUnsigned(std::uint32_t BitWidth, std::uint64_t Value) {
+ if (BitWidth == 0 || BitWidth > MaxBitWidth)
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "APInt bit width is outside the supported range");
+ if (BitWidth < 64U && (Value >> BitWidth) != 0)
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "unsigned value does not fit the APInt bit width");
+
+ std::vector<std::uint64_t> Words(wordCount(BitWidth), 0);
+ Words.front() = Value;
+ return create(BitWidth, Words);
+}
+
+Expected<APInt> APInt::fromSigned(std::uint32_t BitWidth, std::int64_t Value) {
+ if (BitWidth == 0 || BitWidth > MaxBitWidth)
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "APInt bit width is outside the supported range");
+ if (BitWidth < 64U) {
+ const std::uint32_t MagnitudeBits = BitWidth - 1U;
+ const std::int64_t Minimum = -(std::int64_t{1} << MagnitudeBits);
+ const std::int64_t Maximum = (std::int64_t{1} << MagnitudeBits) - 1;
+ if (Value < Minimum || Value > Maximum)
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "signed value does not fit the APInt bit width");
+ }
+
+ const std::uint64_t Fill =
+ Value < 0 ? std::numeric_limits<std::uint64_t>::max() : std::uint64_t{0};
+ std::vector<std::uint64_t> Words(wordCount(BitWidth), Fill);
+ Words.front() = static_cast<std::uint64_t>(Value);
+ Words.back() &= highWordMask(BitWidth);
+ return create(BitWidth, Words);
+}
+
+Expected<APInt> APInt::parseDecimal(std::uint32_t BitWidth, std::string_view Text) {
+ if (BitWidth == 0 || BitWidth > MaxBitWidth)
+ return makeUnexpected(ErrorCode::ParseError, "APInt bit width is outside the supported range");
+ const bool Negative = Text.starts_with('-');
+ if (Negative)
+ Text.remove_prefix(1);
+ if (Text.empty())
+ return makeUnexpected(ErrorCode::ParseError, "APInt has no decimal digits");
+
+ std::vector<std::uint64_t> Words(wordCount(BitWidth), 0);
+ for (const char Character : Text) {
+ if (Character < '0' || Character > '9')
+ return makeUnexpected(ErrorCode::ParseError, "APInt contains a non-decimal digit");
+ std::uint64_t Carry = static_cast<unsigned>(Character - '0');
+ for (std::uint64_t &Word : Words) {
+ const unsigned __int128 Product = static_cast<unsigned __int128>(Word) * 10U + Carry;
+ Word = static_cast<std::uint64_t>(Product);
+ Carry = static_cast<std::uint64_t>(Product >> 64U);
+ }
+ }
+
+ Words.back() &= highWordMask(BitWidth);
+ if (Negative)
+ negateWords(Words, BitWidth);
+ return create(BitWidth, Words);
+}
+
+Expected<APInt> APInt::parseLLVMHex(std::uint32_t BitWidth, std::string_view Text) {
+ if (Text.size() < 4 || (Text[0] != 'u' && Text[0] != 's') || Text[1] != '0' || Text[2] != 'x') {
+ return makeUnexpected(ErrorCode::ParseError,
+ "integer hexadecimal spelling must use u0x or s0x");
+ }
+ const std::string_view Digits = Text.substr(3);
+ if (Digits.empty() || !std::ranges::all_of(Digits, isHexDigit)) {
+ return makeUnexpected(ErrorCode::ParseError,
+ "integer hexadecimal spelling contains a non-hexadecimal digit");
+ }
+
+ const auto *const FirstNonZero =
+ std::ranges::find_if(Digits, [](char Character) { return hexDigitValue(Character) != 0; });
+ std::size_t ActiveBits = 0;
+ if (FirstNonZero != Digits.end()) {
+ const unsigned MostSignificantNibble = hexDigitValue(*FirstNonZero);
+ const auto MostSignificantBits = static_cast<unsigned>(std::bit_width(MostSignificantNibble));
+ ActiveBits =
+ static_cast<std::size_t>(Digits.end() - FirstNonZero - 1U) * 4U + MostSignificantBits;
+ }
+
+ if (BitWidth == 0 || BitWidth > MaxBitWidth)
+ return makeUnexpected(ErrorCode::ParseError, "APInt bit width is outside the supported range");
+ std::vector<std::uint64_t> Words(wordCount(BitWidth), 0);
+ std::size_t Nibble = 0;
+ for (auto Iterator = Digits.rbegin(); Iterator != Digits.rend(); ++Iterator, ++Nibble) {
+ const std::size_t BitOffset = Nibble * 4U;
+ if (BitOffset >= BitWidth)
+ break;
+ Words[BitOffset / 64U] |= static_cast<std::uint64_t>(hexDigitValue(*Iterator))
+ << (BitOffset % 64U);
+ }
+
+ if (Text[0] == 's' && ActiveBits != 0 && ActiveBits < BitWidth) {
+ const std::size_t FirstWord = ActiveBits / 64U;
+ const unsigned FirstBit = static_cast<unsigned>(ActiveBits % 64U);
+ Words[FirstWord] |= std::numeric_limits<std::uint64_t>::max() << FirstBit;
+ for (std::size_t Index = FirstWord + 1U; Index < Words.size(); ++Index)
+ Words[Index] = std::numeric_limits<std::uint64_t>::max();
+ }
+ Words.back() &= highWordMask(BitWidth);
+ return create(BitWidth, Words);
+}
+
+bool APInt::isZero() const noexcept {
+ return std::ranges::all_of(Words, [](std::uint64_t Word) { return Word == 0; });
+}
+
+bool APInt::isNegative() const noexcept {
+ if (BitWidth == 0 || Words.empty())
+ return false;
+ const std::uint32_t SignBit = BitWidth - 1U;
+ return (Words[SignBit / 64U] & (std::uint64_t{1} << (SignBit % 64U))) != 0;
+}
+
+std::size_t APInt::activeBitWidth() const noexcept {
+ const std::size_t Count = significantWordCount(Words);
+ if (Count == 0)
+ return 0;
+ return (Count - 1U) * 64U + static_cast<std::size_t>(std::bit_width(Words[Count - 1U]));
+}
+
+std::size_t APInt::countrZero() const noexcept {
+ std::size_t Result = 0;
+ for (const std::uint64_t Word : Words) {
+ if (Word == 0) {
+ Result += 64U;
+ continue;
+ }
+ return Result + static_cast<std::size_t>(std::countr_zero(Word));
+ }
+ return Result;
+}
+
+std::uint64_t APInt::word(std::size_t Index) const noexcept {
+ return Index < Words.size() ? Words[Index] : 0;
+}
+
+int APInt::compare(const APInt &Other) const noexcept {
+ const std::size_t LeftCount = significantWordCount(Words);
+ const std::size_t RightCount = significantWordCount(Other.Words);
+ if (LeftCount != RightCount)
+ return LeftCount < RightCount ? -1 : 1;
+ for (std::size_t Index = LeftCount; Index != 0; --Index) {
+ if (Words[Index - 1U] != Other.Words[Index - 1U])
+ return Words[Index - 1U] < Other.Words[Index - 1U] ? -1 : 1;
+ }
+ return 0;
+}
+
+int APInt::compareToShifted(const APInt &Other, std::size_t OtherShift) const noexcept {
+ if (Other.isZero())
+ return isZero() ? 0 : 1;
+ if (isZero())
+ return -1;
+ const std::size_t LeftBits = activeBitWidth();
+ const std::size_t RightBits = Other.activeBitWidth();
+ if (OtherShift > std::numeric_limits<std::size_t>::max() - RightBits)
+ return -1;
+ const std::size_t ShiftedBits = RightBits + OtherShift;
+ if (LeftBits != ShiftedBits)
+ return LeftBits < ShiftedBits ? -1 : 1;
+ return compare(Other.shiftedLeft(OtherShift));
+}
+
+void APInt::multiplySmall(std::uint32_t Multiplier) {
+ if (Multiplier == 0 || isZero()) {
+ Words.clear();
+ BitWidth = 0;
+ return;
+ }
+ unsigned __int128 Carry = 0;
+ for (std::uint64_t &Word : Words) {
+ const unsigned __int128 Product = static_cast<unsigned __int128>(Word) * Multiplier + Carry;
+ Word = static_cast<std::uint64_t>(Product);
+ Carry = Product >> 64U;
+ }
+ if (Carry != 0)
+ Words.push_back(static_cast<std::uint64_t>(Carry));
+ normalizeMagnitude();
+}
+
+void APInt::addSmall(std::uint32_t Value) {
+ unsigned __int128 Carry = Value;
+ std::size_t Index = 0;
+ while (Carry != 0 && Index < Words.size()) {
+ const unsigned __int128 Sum = static_cast<unsigned __int128>(Words[Index]) + Carry;
+ Words[Index] = static_cast<std::uint64_t>(Sum);
+ Carry = Sum >> 64U;
+ ++Index;
+ }
+ if (Carry != 0)
+ Words.push_back(static_cast<std::uint64_t>(Carry));
+ normalizeMagnitude();
+}
+
+void APInt::setBit(std::size_t Bit) {
+ const std::size_t Index = Bit / 64U;
+ if (Index >= Words.size())
+ Words.resize(Index + 1U, 0);
+ Words[Index] |= std::uint64_t{1} << (Bit % 64U);
+ normalizeMagnitude();
+}
+
+void APInt::clearBit(std::size_t Bit) noexcept {
+ const std::size_t Index = Bit / 64U;
+ if (Index >= Words.size())
+ return;
+ Words[Index] &= ~(std::uint64_t{1} << (Bit % 64U));
+ normalizeMagnitude();
+}
+
+void APInt::shiftRight(std::size_t Amount) noexcept {
+ if (Amount == 0 || isZero())
+ return;
+ const std::size_t WordOffset = Amount / 64U;
+ if (WordOffset >= Words.size()) {
+ Words.clear();
+ BitWidth = 0;
+ return;
+ }
+ const unsigned BitOffset = static_cast<unsigned>(Amount % 64U);
+ const std::size_t NewSize = Words.size() - WordOffset;
+ for (std::size_t Index = 0; Index < NewSize; ++Index) {
+ std::uint64_t Value = Words[Index + WordOffset] >> BitOffset;
+ if (BitOffset != 0 && Index + WordOffset + 1U < Words.size())
+ Value |= Words[Index + WordOffset + 1U] << (64U - BitOffset);
+ Words[Index] = Value;
+ }
+ Words.resize(NewSize);
+ normalizeMagnitude();
+}
+
+APInt APInt::shiftedLeft(std::size_t Amount) const {
+ if (isZero() || Amount == 0)
+ return *this;
+ const std::size_t WordOffset = Amount / 64U;
+ const unsigned BitOffset = static_cast<unsigned>(Amount % 64U);
+ APInt Result;
+ Result.Words.assign(Words.size() + WordOffset + (BitOffset == 0 ? 0U : 1U), 0);
+ for (std::size_t Index = 0; Index < Words.size(); ++Index) {
+ const unsigned __int128 Shifted = static_cast<unsigned __int128>(Words[Index]) << BitOffset;
+ Result.Words[Index + WordOffset] |= static_cast<std::uint64_t>(Shifted);
+ if (BitOffset != 0)
+ Result.Words[Index + WordOffset + 1U] |= static_cast<std::uint64_t>(Shifted >> 64U);
+ }
+ Result.normalizeMagnitude();
+ return Result;
+}
+
+void APInt::subtract(const APInt &Other) noexcept {
+ std::uint64_t Borrow = 0;
+ for (std::size_t Index = 0; Index < Words.size(); ++Index) {
+ const unsigned __int128 Subtrahend =
+ (Index < Other.Words.size() ? static_cast<unsigned __int128>(Other.Words[Index]) : 0) +
+ Borrow;
+ const unsigned __int128 Current = Words[Index];
+ Words[Index] = static_cast<std::uint64_t>(Current - Subtrahend);
+ Borrow = Current < Subtrahend ? 1U : 0U;
+ }
+ normalizeMagnitude();
+}
+
+std::string APInt::toUnsignedDecimal() const {
+ return unsignedDecimal(Words);
+}
+
+std::string APInt::toSignedDecimal() const {
+ if (!isNegative())
+ return toUnsignedDecimal();
+
+ std::vector<std::uint64_t> Magnitude = Words;
+ negateWords(Magnitude, BitWidth);
+ return "-" + unsignedDecimal(std::move(Magnitude));
+}
+
+Expected<void> APInt::verify() const {
+ return verifyAPInt(BitWidth, Words, ErrorCode::VerificationError);
+}
+
+void APInt::normalizeMagnitude() noexcept {
+ while (!Words.empty() && Words.back() == 0)
+ Words.pop_back();
+ const std::size_t ActiveBits = activeBitWidth();
+ BitWidth = static_cast<std::uint32_t>(ActiveBits);
+}
+
+} // namespace rcc