aboutsummaryrefslogtreecommitdiff
path: root/backend/lib
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
parentd62f022c92fcc3ebe2269273628943a0089683fd (diff)
downloadrcc-project-aa7c85ca71859aab15bdf1e6dc1ea3a5aa5d1e28.tar.gz
rcc-project-aa7c85ca71859aab15bdf1e6dc1ea3a5aa5d1e28.tar.xz
[Support] Split APInt and APFloat ownership
Diffstat (limited to 'backend/lib')
-rw-r--r--backend/lib/CodeGen/GenericConstant.cpp15
-rw-r--r--backend/lib/CodeGen/GlobalObject.cpp8
-rw-r--r--backend/lib/CodeGen/LowLevelType.cpp62
-rw-r--r--backend/lib/CodeGen/MIRParser/MIParser.cpp10
-rw-r--r--backend/lib/CodeGen/MIRPrinter.cpp4
-rw-r--r--backend/lib/CodeGen/MachineIRBuilder.cpp6
-rw-r--r--backend/lib/CodeGen/MachineOperand.cpp213
-rw-r--r--backend/lib/MIR/LLVMConstantSyntax.cpp1548
-rw-r--r--backend/lib/Support/APFloat.cpp1336
-rw-r--r--backend/lib/Support/APInt.cpp395
-rw-r--r--backend/lib/Support/CMakeLists.txt8
-rw-r--r--backend/lib/Target/RISCV/GISel/RISCVCallLowering.cpp2
-rw-r--r--backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp2
-rw-r--r--backend/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp18
-rw-r--r--backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp10
15 files changed, 1785 insertions, 1852 deletions
diff --git a/backend/lib/CodeGen/GenericConstant.cpp b/backend/lib/CodeGen/GenericConstant.cpp
index d9d9233..afcdd44 100644
--- a/backend/lib/CodeGen/GenericConstant.cpp
+++ b/backend/lib/CodeGen/GenericConstant.cpp
@@ -203,8 +203,7 @@ nonPointerFixedBitWidth(const GenericConstantType &Type) noexcept {
return false;
}
-[[nodiscard]] bool signedIntegerLess(const IntegerImmediate &Left,
- const IntegerImmediate &Right) noexcept {
+[[nodiscard]] bool signedIntegerLess(const APInt &Left, const APInt &Right) noexcept {
if (Left.bitWidth() != Right.bitWidth())
return false;
if (Left.isNegative() != Right.isNegative())
@@ -249,7 +248,7 @@ nonPointerFixedBitWidth(const GenericConstantType &Type) noexcept {
case GenericConstantTypeKind::Metadata:
return RequireNoElements();
case GenericConstantTypeKind::Integer:
- if (Type.BitWidth == 0 || Type.BitWidth > IntegerImmediate::MaxBitWidth) {
+ if (Type.BitWidth == 0 || Type.BitWidth > APInt::MaxBitWidth) {
return makeUnexpected(ErrorCode::VerificationError,
"generic integer type has an invalid bit width");
}
@@ -257,7 +256,7 @@ nonPointerFixedBitWidth(const GenericConstantType &Type) noexcept {
case GenericConstantTypeKind::Byte:
return RequireNoElements();
case GenericConstantTypeKind::Floating:
- if (!isKnownFloatSemantics(Type.Semantics)) {
+ if (!getFloatSemanticsBitWidth(Type.Semantics)) {
return makeUnexpected(ErrorCode::VerificationError,
"generic floating type has unknown semantics");
}
@@ -702,7 +701,7 @@ nonPointerFixedBitWidth(const GenericConstantType &Type) noexcept {
} // namespace
Expected<GenericConstantType> GenericConstantType::integer(std::uint32_t Width) {
- if (Width == 0 || Width > IntegerImmediate::MaxBitWidth)
+ if (Width == 0 || Width > APInt::MaxBitWidth)
return makeUnexpected(ErrorCode::InvalidArgument, "generic integer type width is invalid");
GenericConstantType Type;
Type.Kind = GenericConstantTypeKind::Integer;
@@ -724,7 +723,7 @@ GenericConstantType GenericConstantType::byte() noexcept {
}
Expected<GenericConstantType> GenericConstantType::floating(FloatSemantics ValueSemantics) {
- if (!isKnownFloatSemantics(ValueSemantics))
+ if (!getFloatSemanticsBitWidth(ValueSemantics))
return makeUnexpected(ErrorCode::InvalidArgument, "generic floating semantics is unknown");
GenericConstantType Type;
Type.Kind = GenericConstantTypeKind::Floating;
@@ -810,7 +809,7 @@ Expected<void> GenericConstantType::verify() const {
return verifyType(*this, 0, Nodes);
}
-Expected<GenericConstantData> GenericConstantData::integer(IntegerImmediate Value) {
+Expected<GenericConstantData> GenericConstantData::integer(APInt Value) {
auto Type = GenericConstantType::integer(Value.bitWidth());
if (!Type)
return std::unexpected(Type.error());
@@ -821,7 +820,7 @@ Expected<GenericConstantData> GenericConstantData::integer(IntegerImmediate Valu
return Result;
}
-Expected<GenericConstantData> GenericConstantData::floating(FloatingPointBits Value) {
+Expected<GenericConstantData> GenericConstantData::floating(APFloat Value) {
auto Type = GenericConstantType::floating(Value.semantics());
if (!Type)
return std::unexpected(Type.error());
diff --git a/backend/lib/CodeGen/GlobalObject.cpp b/backend/lib/CodeGen/GlobalObject.cpp
index cda28bd..aa8fd15 100644
--- a/backend/lib/CodeGen/GlobalObject.cpp
+++ b/backend/lib/CodeGen/GlobalObject.cpp
@@ -45,7 +45,7 @@ namespace {
case GlobalInitializer::Kind::Invalid:
return makeUnexpected(ErrorCode::VerificationError, "global initializer is invalid");
case GlobalInitializer::Kind::Integer: {
- const auto *Value = Initializer.getIf<IntegerImmediate>();
+ const auto *Value = Initializer.getIf<APInt>();
if (Value == nullptr)
return makeUnexpected(ErrorCode::InternalError, "integer initializer storage is invalid");
auto Verified = Value->verify();
@@ -54,7 +54,7 @@ namespace {
return (static_cast<std::uint64_t>(Value->bitWidth()) + 7U) / 8U;
}
case GlobalInitializer::Kind::Floating: {
- const auto *Value = Initializer.getIf<FloatingPointBits>();
+ const auto *Value = Initializer.getIf<APFloat>();
if (Value == nullptr)
return makeUnexpected(ErrorCode::InternalError, "floating initializer storage is invalid");
return (static_cast<std::uint64_t>(Value->bitWidth()) + 7U) / 8U;
@@ -141,11 +141,11 @@ namespace {
} // namespace
-GlobalInitializer GlobalInitializer::integer(IntegerImmediate Value) {
+GlobalInitializer GlobalInitializer::integer(APInt Value) {
return GlobalInitializer(std::move(Value));
}
-GlobalInitializer GlobalInitializer::floating(FloatingPointBits Value) {
+GlobalInitializer GlobalInitializer::floating(APFloat Value) {
return GlobalInitializer(Value);
}
diff --git a/backend/lib/CodeGen/LowLevelType.cpp b/backend/lib/CodeGen/LowLevelType.cpp
index b124765..b50ea6b 100644
--- a/backend/lib/CodeGen/LowLevelType.cpp
+++ b/backend/lib/CodeGen/LowLevelType.cpp
@@ -8,43 +8,6 @@
namespace rcc {
namespace {
-struct FloatSemanticsInfo final {
- std::uint32_t BitWidth;
- std::string_view Name;
- std::string_view Spelling;
-};
-
-constexpr std::array FloatSemanticsTable{
- FloatSemanticsInfo{16, "IEEE half", "f16"},
- FloatSemanticsInfo{16, "bfloat", "bf16"},
- FloatSemanticsInfo{32, "IEEE single", "f32"},
- FloatSemanticsInfo{64, "IEEE double", "f64"},
- FloatSemanticsInfo{128, "IEEE quad", "f128"},
- FloatSemanticsInfo{128, "PPC double-double", "ppcf128"},
- FloatSemanticsInfo{8, "float8 E5M2", "f8e5m2"},
- FloatSemanticsInfo{8, "float8 E5M2 FNUZ", "f8e5m2fnuz"},
- FloatSemanticsInfo{8, "float8 E4M3", "f8e4m3"},
- FloatSemanticsInfo{8, "float8 E4M3 FN", "f8e4m3fn"},
- FloatSemanticsInfo{8, "float8 E4M3 FNUZ", "f8e4m3fnuz"},
- FloatSemanticsInfo{8, "float8 E4M3 B11 FNUZ", "f8e4m3b11fnuz"},
- FloatSemanticsInfo{8, "float8 E3M4", "f8e3m4"},
- FloatSemanticsInfo{19, "TensorFloat-32", "tf32"},
- FloatSemanticsInfo{8, "float8 E8M0 FNU", "f8e8m0fnu"},
- FloatSemanticsInfo{6, "float6 E3M2 FN", "f6e3m2fn"},
- FloatSemanticsInfo{6, "float6 E2M3 FN", "f6e2m3fn"},
- FloatSemanticsInfo{4, "float4 E2M1 FN", "f4e2m1fn"},
- FloatSemanticsInfo{80, "x87 double-extended", "x86fp80"},
-};
-
-static_assert(FloatSemanticsTable.size() == static_cast<std::size_t>(FloatSemantics::Count));
-
-[[nodiscard]] const FloatSemanticsInfo *getFloatSemanticsInfo(FloatSemantics Semantics) noexcept {
- const auto Index = static_cast<std::size_t>(Semantics);
- if (Index >= FloatSemanticsTable.size())
- return nullptr;
- return &FloatSemanticsTable[Index];
-}
-
[[nodiscard]] LLT::Kind getVectorKind(LLT ElementType) noexcept {
switch (ElementType.kind()) {
case LLT::Kind::AnyScalar:
@@ -69,31 +32,6 @@ static_assert(FloatSemanticsTable.size() == static_cast<std::size_t>(FloatSemant
} // namespace
-bool isKnownFloatSemantics(FloatSemantics Semantics) noexcept {
- return getFloatSemanticsInfo(Semantics) != nullptr;
-}
-
-std::optional<std::uint32_t> getFloatSemanticsBitWidth(FloatSemantics Semantics) noexcept {
- const auto *Info = getFloatSemanticsInfo(Semantics);
- if (Info == nullptr)
- return std::nullopt;
- return Info->BitWidth;
-}
-
-std::string_view getFloatSemanticsName(FloatSemantics Semantics) noexcept {
- const auto *Info = getFloatSemanticsInfo(Semantics);
- if (Info == nullptr)
- return "unknown";
- return Info->Name;
-}
-
-std::string_view getFloatSemanticsSpelling(FloatSemantics Semantics) noexcept {
- const auto *Info = getFloatSemanticsInfo(Semantics);
- if (Info == nullptr)
- return "invalid-float";
- return Info->Spelling;
-}
-
Expected<LLT> LLT::makeScalar(Kind TypeKind, std::uint64_t BitWidth) {
if (BitWidth == 0 || BitWidth > MaxBitWidth) {
return makeUnexpected(ErrorCode::InvalidArgument,
diff --git a/backend/lib/CodeGen/MIRParser/MIParser.cpp b/backend/lib/CodeGen/MIRParser/MIParser.cpp
index e38b9f1..183e6b3 100644
--- a/backend/lib/CodeGen/MIRParser/MIParser.cpp
+++ b/backend/lib/CodeGen/MIRParser/MIParser.cpp
@@ -116,9 +116,9 @@ namespace {
Token.isKeyword("llvm_vector_register_mask");
}
-[[nodiscard]] Expected<IntegerImmediate> parseIntegerImmediateValue(std::uint32_t BitWidth,
- std::string_view Spelling) {
- if (BitWidth == 0 || BitWidth > IntegerImmediate::MaxBitWidth)
+[[nodiscard]] Expected<APInt> parseIntegerImmediateValue(std::uint32_t BitWidth,
+ std::string_view Spelling) {
+ if (BitWidth == 0 || BitWidth > APInt::MaxBitWidth)
return makeUnexpected(ErrorCode::ParseError, "typed integer width is out of range");
const bool Negative = Spelling.starts_with('-');
@@ -155,7 +155,7 @@ namespace {
if (BitWidth % 64U != 0)
Words.back() &= (std::uint64_t{1} << (BitWidth % 64U)) - 1U;
}
- return IntegerImmediate::create(BitWidth, Words);
+ return APInt::create(BitWidth, Words);
}
[[nodiscard]] std::optional<std::uint64_t> minimumTypeSizeInBits(LLT Type) noexcept {
@@ -1244,7 +1244,7 @@ bool MIParser::Impl::parseTypedIntegerOperand(ParsedOperand &Result) {
return fail(Begin, "typed integer operand must use an 'iN' type");
std::uint64_t WideBitWidth = 0;
if (!parseUnsignedDigits(TypeSpelling.substr(1), WideBitWidth) ||
- WideBitWidth > IntegerImmediate::MaxBitWidth) {
+ WideBitWidth > APInt::MaxBitWidth) {
return fail(Begin, "typed integer operand has an invalid bit width");
}
const auto BitWidth = static_cast<std::uint32_t>(WideBitWidth);
diff --git a/backend/lib/CodeGen/MIRPrinter.cpp b/backend/lib/CodeGen/MIRPrinter.cpp
index d510c83..ea201b9 100644
--- a/backend/lib/CodeGen/MIRPrinter.cpp
+++ b/backend/lib/CodeGen/MIRPrinter.cpp
@@ -2249,7 +2249,7 @@ Expected<void> BodyPrinter::printOperand(const MachineOperand &Operand, bool IsE
Output.append(std::to_string(*Operand.getIf<std::int64_t>()));
return {};
case MachineOperand::Kind::IntegerImmediate: {
- const IntegerImmediate &Value = Operand.getIf<IntegerImmediateOperand>()->Value;
+ const APInt &Value = Operand.getIf<IntegerImmediateOperand>()->Value;
Output.push_back('i');
Output.append(std::to_string(Value.bitWidth()));
Output.push_back(' ');
@@ -2260,7 +2260,7 @@ Expected<void> BodyPrinter::printOperand(const MachineOperand &Operand, bool IsE
return {};
}
case MachineOperand::Kind::FloatingImmediate: {
- const FloatingPointBits &Bits = Operand.getIf<FloatingImmediateOperand>()->Bits;
+ const APFloat &Bits = Operand.getIf<FloatingImmediateOperand>()->Bits;
auto Constant = GenericConstantData::floating(Bits);
if (!Constant)
return std::unexpected(Constant.error());
diff --git a/backend/lib/CodeGen/MachineIRBuilder.cpp b/backend/lib/CodeGen/MachineIRBuilder.cpp
index 6887804..e59f613 100644
--- a/backend/lib/CodeGen/MachineIRBuilder.cpp
+++ b/backend/lib/CodeGen/MachineIRBuilder.cpp
@@ -162,13 +162,11 @@ Expected<void> MachineInstrBuilder::addImmediate(std::int64_t Value, std::uint32
return addOperand(MachineOperand::immediate(Value, TargetFlags));
}
-Expected<void> MachineInstrBuilder::addIntegerImmediate(IntegerImmediate Value,
- std::uint32_t TargetFlags) {
+Expected<void> MachineInstrBuilder::addIntegerImmediate(APInt Value, std::uint32_t TargetFlags) {
return addOperand(MachineOperand::integerImmediate(std::move(Value), TargetFlags));
}
-Expected<void> MachineInstrBuilder::addFloatingImmediate(FloatingPointBits Bits,
- std::uint32_t TargetFlags) {
+Expected<void> MachineInstrBuilder::addFloatingImmediate(APFloat Bits, std::uint32_t TargetFlags) {
return addOperand(MachineOperand::floatingImmediate(Bits, TargetFlags));
}
diff --git a/backend/lib/CodeGen/MachineOperand.cpp b/backend/lib/CodeGen/MachineOperand.cpp
index c81a7c3..44ad8b6 100644
--- a/backend/lib/CodeGen/MachineOperand.cpp
+++ b/backend/lib/CodeGen/MachineOperand.cpp
@@ -8,222 +8,14 @@
#include "rcc/CodeGen/MachineRegisterInfo.h"
#include <algorithm>
-#include <array>
#include <cstdint>
#include <limits>
#include <memory>
-#include <span>
#include <string>
-#include <string_view>
#include <utility>
#include <vector>
namespace rcc {
-namespace {
-
-[[nodiscard]] constexpr std::size_t integerWordCount(std::uint32_t BitWidth) noexcept {
- return (static_cast<std::size_t>(BitWidth) + 63U) / 64U;
-}
-
-[[nodiscard]] constexpr std::uint64_t integerHighWordMask(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]] Expected<void> verifyIntegerImmediate(std::uint32_t BitWidth,
- std::span<const std::uint64_t> Words,
- ErrorCode Code) {
- if (BitWidth == 0 || BitWidth > IntegerImmediate::MaxBitWidth) {
- return makeUnexpected(Code, "integer immediate bit width is outside the supported range");
- }
- if (Words.size() != integerWordCount(BitWidth)) {
- return makeUnexpected(Code, "integer immediate bit pattern has the wrong word count");
- }
- if ((Words.back() & ~integerHighWordMask(BitWidth)) != 0) {
- return makeUnexpected(Code, "integer immediate has nonzero bits above its declared width");
- }
- return {};
-}
-
-} // namespace
-
-Expected<IntegerImmediate> IntegerImmediate::create(std::uint32_t BitWidth,
- std::span<const std::uint64_t> Words) {
- auto Verification = verifyIntegerImmediate(BitWidth, Words, ErrorCode::InvalidArgument);
- if (!Verification)
- return std::unexpected(Verification.error());
- return IntegerImmediate(BitWidth, std::vector<std::uint64_t>(Words.begin(), Words.end()));
-}
-
-Expected<IntegerImmediate> IntegerImmediate::fromUnsigned(std::uint32_t BitWidth,
- std::uint64_t Value) {
- if (BitWidth == 0 || BitWidth > MaxBitWidth) {
- return makeUnexpected(ErrorCode::InvalidArgument,
- "integer immediate bit width is outside the supported range");
- }
- if (BitWidth < 64U && (Value >> BitWidth) != 0) {
- return makeUnexpected(ErrorCode::InvalidArgument,
- "unsigned value does not fit the integer immediate bit width");
- }
-
- std::vector<std::uint64_t> Words(integerWordCount(BitWidth), 0);
- Words.front() = Value;
- return create(BitWidth, Words);
-}
-
-Expected<IntegerImmediate> IntegerImmediate::fromSigned(std::uint32_t BitWidth,
- std::int64_t Value) {
- if (BitWidth == 0 || BitWidth > MaxBitWidth) {
- return makeUnexpected(ErrorCode::InvalidArgument,
- "integer immediate 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 integer immediate 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(integerWordCount(BitWidth), Fill);
- Words.front() = static_cast<std::uint64_t>(Value);
- Words.back() &= integerHighWordMask(BitWidth);
- return create(BitWidth, Words);
-}
-
-Expected<IntegerImmediate> IntegerImmediate::parseDecimal(std::uint32_t BitWidth,
- std::string_view Text) {
- if (BitWidth == 0 || BitWidth > MaxBitWidth) {
- return makeUnexpected(ErrorCode::ParseError,
- "integer immediate 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, "integer immediate has no decimal digits");
-
- std::vector<std::uint64_t> Words(integerWordCount(BitWidth), 0);
- for (const char Character : Text) {
- if (Character < '0' || Character > '9') {
- return makeUnexpected(ErrorCode::ParseError,
- "integer immediate 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);
- }
- }
-
- // LLVM integer literals are arbitrary precision and are extended or
- // truncated to the declared bit width before becoming a constant.
- Words.back() &= integerHighWordMask(BitWidth);
- if (Negative) {
- 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 ? 1 : 0;
- }
- Words.back() &= integerHighWordMask(BitWidth);
- }
- return create(BitWidth, Words);
-}
-
-bool IntegerImmediate::isZero() const noexcept {
- return std::ranges::all_of(Words, [](std::uint64_t Word) { return Word == 0; });
-}
-
-bool IntegerImmediate::isNegative() const noexcept {
- const std::uint32_t SignBit = BitWidth - 1U;
- return (Words[SignBit / 64U] & (std::uint64_t{1} << (SignBit % 64U))) != 0;
-}
-
-std::string IntegerImmediate::toUnsignedDecimal() const {
- if (isZero())
- return "0";
- std::vector<std::uint64_t> Remaining = Words;
- std::string Digits;
- while (!std::ranges::all_of(Remaining, [](std::uint64_t Word) { return Word == 0; })) {
- unsigned __int128 Remainder = 0;
- for (auto Iterator = Remaining.rbegin(); Iterator != Remaining.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;
-}
-
-std::string IntegerImmediate::toSignedDecimal() const {
- if (!isNegative())
- return toUnsignedDecimal();
-
- std::vector<std::uint64_t> Magnitude = Words;
- for (std::uint64_t &Word : Magnitude)
- Word = ~Word;
- std::uint64_t Carry = 1;
- for (std::uint64_t &Word : Magnitude) {
- const std::uint64_t Previous = Word;
- Word += Carry;
- Carry = Carry != 0 && Word < Previous ? 1 : 0;
- }
- Magnitude.back() &= integerHighWordMask(BitWidth);
-
- std::string Digits;
- while (!std::ranges::all_of(Magnitude, [](std::uint64_t Word) { return Word == 0; })) {
- unsigned __int128 Remainder = 0;
- for (auto Iterator = Magnitude.rbegin(); Iterator != Magnitude.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);
- Digits.insert(Digits.begin(), '-');
- return Digits;
-}
-
-Expected<void> IntegerImmediate::verify() const {
- return verifyIntegerImmediate(BitWidth, Words, ErrorCode::VerificationError);
-}
-
-Expected<FloatingPointBits> FloatingPointBits::create(FloatSemantics Semantics,
- std::span<const std::uint64_t> Words) {
- const auto BitWidth = getFloatSemanticsBitWidth(Semantics);
- if (!BitWidth) {
- return makeUnexpected(ErrorCode::InvalidArgument, "floating immediate has unknown semantics");
- }
-
- const std::size_t RequiredWords = (*BitWidth + 63U) / 64U;
- if (RequiredWords > 2 || Words.size() != RequiredWords) {
- return makeUnexpected(ErrorCode::InvalidArgument,
- "floating immediate bit pattern has the wrong word count");
- }
-
- const std::uint32_t UsedBitsInLastWord = *BitWidth % 64U;
- if (UsedBitsInLastWord != 0 && (Words.back() >> UsedBitsInLastWord) != 0) {
- return makeUnexpected(ErrorCode::InvalidArgument,
- "floating immediate has nonzero bits above its semantics width");
- }
-
- std::array<std::uint64_t, 2> StoredWords{};
- std::ranges::copy(Words, StoredWords.begin());
- return FloatingPointBits(Semantics, StoredWords, static_cast<std::uint8_t>(RequiredWords));
-}
RegisterOperandFlags::RegisterOperandFlags(
std::initializer_list<RegisterOperandFlag> Flags) noexcept {
@@ -296,13 +88,12 @@ MachineOperand MachineOperand::immediate(std::int64_t Value, std::uint32_t Targe
return MachineOperand(Kind::Immediate, Value, TargetFlags);
}
-MachineOperand MachineOperand::integerImmediate(IntegerImmediate Value, std::uint32_t TargetFlags) {
+MachineOperand MachineOperand::integerImmediate(APInt Value, std::uint32_t TargetFlags) {
return MachineOperand(Kind::IntegerImmediate, IntegerImmediateOperand{std::move(Value)},
TargetFlags);
}
-MachineOperand MachineOperand::floatingImmediate(FloatingPointBits Bits,
- std::uint32_t TargetFlags) {
+MachineOperand MachineOperand::floatingImmediate(APFloat Bits, std::uint32_t TargetFlags) {
return MachineOperand(Kind::FloatingImmediate, FloatingImmediateOperand{Bits}, TargetFlags);
}
diff --git a/backend/lib/MIR/LLVMConstantSyntax.cpp b/backend/lib/MIR/LLVMConstantSyntax.cpp
index a687f80..4ee231d 100644
--- a/backend/lib/MIR/LLVMConstantSyntax.cpp
+++ b/backend/lib/MIR/LLVMConstantSyntax.cpp
@@ -2,6 +2,9 @@
#include "rcc/MIR/LLVMConstantSyntax.h"
+#include "rcc/ADT/APFloat.h"
+#include "rcc/ADT/APInt.h"
+
#include <algorithm>
#include <array>
#include <bit>
@@ -52,1215 +55,6 @@ struct ParsedName final {
return static_cast<unsigned>(Character - 'A') + 10U;
}
-class BigUnsigned final {
-public:
- BigUnsigned() = default;
-
- explicit BigUnsigned(std::uint64_t Value) {
- if (Value == 0)
- return;
- Limbs.push_back(static_cast<std::uint32_t>(Value));
- if ((Value >> 32U) != 0)
- Limbs.push_back(static_cast<std::uint32_t>(Value >> 32U));
- }
-
- [[nodiscard]] bool isZero() const noexcept {
- return Limbs.empty();
- }
-
- [[nodiscard]] bool isOdd() const noexcept {
- return !Limbs.empty() && (Limbs.front() & 1U) != 0;
- }
-
- [[nodiscard]] std::size_t bitWidth() const noexcept {
- if (Limbs.empty())
- return 0;
- std::uint32_t MostSignificant = Limbs.back();
- std::size_t Bits = 0;
- while (MostSignificant != 0) {
- ++Bits;
- MostSignificant >>= 1U;
- }
- return (Limbs.size() - 1U) * 32U + Bits;
- }
-
- [[nodiscard]] std::uint64_t word(std::size_t Index) const noexcept {
- const std::size_t First = Index * 2U;
- if (First >= Limbs.size())
- return 0;
- std::uint64_t Result = Limbs[First];
- if (First + 1U < Limbs.size())
- Result |= static_cast<std::uint64_t>(Limbs[First + 1U]) << 32U;
- return Result;
- }
-
- [[nodiscard]] int compare(const BigUnsigned &Other) const noexcept {
- if (Limbs.size() != Other.Limbs.size())
- return Limbs.size() < Other.Limbs.size() ? -1 : 1;
- for (std::size_t Index = Limbs.size(); Index != 0; --Index) {
- const std::uint32_t Left = Limbs[Index - 1U];
- const std::uint32_t Right = Other.Limbs[Index - 1U];
- if (Left != Right)
- return Left < Right ? -1 : 1;
- }
- return 0;
- }
-
- void multiplySmall(std::uint32_t Multiplier) {
- if (Multiplier == 0 || isZero()) {
- Limbs.clear();
- return;
- }
- std::uint64_t Carry = 0;
- for (std::uint32_t &Limb : Limbs) {
- const std::uint64_t Product = static_cast<std::uint64_t>(Limb) * Multiplier + Carry;
- Limb = static_cast<std::uint32_t>(Product);
- Carry = Product >> 32U;
- }
- if (Carry != 0)
- Limbs.push_back(static_cast<std::uint32_t>(Carry));
- }
-
- [[nodiscard]] std::uint32_t divideSmall(std::uint32_t Divisor) {
- std::uint64_t Remainder = 0;
- for (std::size_t Index = Limbs.size(); Index != 0; --Index) {
- const std::uint64_t Dividend = (Remainder << 32U) | Limbs[Index - 1U];
- Limbs[Index - 1U] = static_cast<std::uint32_t>(Dividend / Divisor);
- Remainder = Dividend % Divisor;
- }
- normalize();
- return static_cast<std::uint32_t>(Remainder);
- }
-
- void addSmall(std::uint32_t Value) {
- std::uint64_t Carry = Value;
- std::size_t Index = 0;
- while (Carry != 0 && Index < Limbs.size()) {
- const std::uint64_t Sum = static_cast<std::uint64_t>(Limbs[Index]) + Carry;
- Limbs[Index] = static_cast<std::uint32_t>(Sum);
- Carry = Sum >> 32U;
- ++Index;
- }
- if (Carry != 0)
- Limbs.push_back(static_cast<std::uint32_t>(Carry));
- }
-
- void setBit(std::size_t Bit) {
- const std::size_t Limb = Bit / 32U;
- if (Limb >= Limbs.size())
- Limbs.resize(Limb + 1U, 0);
- Limbs[Limb] |= std::uint32_t{1} << (Bit % 32U);
- }
-
- void clearBit(std::size_t Bit) noexcept {
- const std::size_t Limb = Bit / 32U;
- if (Limb >= Limbs.size())
- return;
- Limbs[Limb] &= ~(std::uint32_t{1} << (Bit % 32U));
- normalize();
- }
-
- void shiftRightOne() noexcept {
- std::uint32_t Carry = 0;
- for (std::size_t Index = Limbs.size(); Index != 0; --Index) {
- const std::uint32_t Current = Limbs[Index - 1U];
- Limbs[Index - 1U] = (Current >> 1U) | (Carry << 31U);
- Carry = Current & 1U;
- }
- normalize();
- }
-
- [[nodiscard]] std::size_t countrZero() const noexcept {
- std::size_t Result = 0;
- for (const std::uint32_t Limb : Limbs) {
- if (Limb == 0) {
- Result += 32U;
- continue;
- }
- return Result + static_cast<std::size_t>(std::countr_zero(Limb));
- }
- return Result;
- }
-
- void shiftRight(std::size_t Amount) noexcept {
- if (Amount == 0 || isZero())
- return;
- const std::size_t LimbOffset = Amount / 32U;
- if (LimbOffset >= Limbs.size()) {
- Limbs.clear();
- return;
- }
- if (LimbOffset != 0)
- Limbs.erase(Limbs.begin(), Limbs.begin() + static_cast<std::ptrdiff_t>(LimbOffset));
- const unsigned BitOffset = static_cast<unsigned>(Amount % 32U);
- if (BitOffset != 0) {
- std::uint32_t Carry = 0;
- for (std::size_t Index = Limbs.size(); Index != 0; --Index) {
- const std::uint32_t Current = Limbs[Index - 1U];
- Limbs[Index - 1U] = (Current >> BitOffset) | Carry;
- Carry = Current << (32U - BitOffset);
- }
- }
- normalize();
- }
-
- [[nodiscard]] std::string toDecimal() const {
- if (isZero())
- return "0";
- BigUnsigned Remaining = *this;
- std::string Digits;
- while (!Remaining.isZero())
- Digits.push_back(static_cast<char>('0' + Remaining.divideSmall(10)));
- std::ranges::reverse(Digits);
- return Digits;
- }
-
- [[nodiscard]] BigUnsigned shiftedLeft(std::size_t Amount) const {
- if (isZero() || Amount == 0)
- return *this;
- const std::size_t LimbOffset = Amount / 32U;
- const unsigned BitOffset = static_cast<unsigned>(Amount % 32U);
- BigUnsigned Result;
- Result.Limbs.assign(Limbs.size() + LimbOffset + (BitOffset == 0 ? 0U : 1U), 0);
- for (std::size_t Index = 0; Index < Limbs.size(); ++Index) {
- const std::uint64_t Shifted = static_cast<std::uint64_t>(Limbs[Index]) << BitOffset;
- Result.Limbs[Index + LimbOffset] |= static_cast<std::uint32_t>(Shifted);
- if (BitOffset != 0)
- Result.Limbs[Index + LimbOffset + 1U] |= static_cast<std::uint32_t>(Shifted >> 32U);
- }
- Result.normalize();
- return Result;
- }
-
- void subtract(const BigUnsigned &Other) noexcept {
- std::uint64_t Borrow = 0;
- for (std::size_t Index = 0; Index < Limbs.size(); ++Index) {
- const std::uint64_t Subtrahend =
- (Index < Other.Limbs.size() ? static_cast<std::uint64_t>(Other.Limbs[Index]) : 0) +
- Borrow;
- const std::uint64_t Current = Limbs[Index];
- Limbs[Index] = static_cast<std::uint32_t>(Current - Subtrahend);
- Borrow = Current < Subtrahend ? 1U : 0U;
- }
- normalize();
- }
-
-private:
- friend int compareToShifted(const BigUnsigned &Left, const BigUnsigned &Right,
- std::size_t RightShift) noexcept;
-
- void normalize() noexcept {
- while (!Limbs.empty() && Limbs.back() == 0)
- Limbs.pop_back();
- }
-
- std::vector<std::uint32_t> Limbs;
-};
-
-[[nodiscard]] int compareToShifted(const BigUnsigned &Left, const BigUnsigned &Right,
- std::size_t RightShift) noexcept {
- if (Right.isZero())
- return Left.isZero() ? 0 : 1;
- if (Left.isZero())
- return -1;
-
- const std::size_t LeftBits = Left.bitWidth();
- const std::size_t RightBits = Right.bitWidth();
- if (RightShift > std::numeric_limits<std::size_t>::max() - RightBits)
- return -1;
- const std::size_t ShiftedBits = RightBits + RightShift;
- if (LeftBits != ShiftedBits)
- return LeftBits < ShiftedBits ? -1 : 1;
-
- const std::size_t LimbOffset = RightShift / 32U;
- const unsigned BitOffset = static_cast<unsigned>(RightShift % 32U);
- const std::size_t WordCount = (ShiftedBits + 31U) / 32U;
- for (std::size_t Index = WordCount; Index != 0; --Index) {
- const std::size_t Destination = Index - 1U;
- std::uint32_t ShiftedWord = 0;
- if (Destination >= LimbOffset) {
- const std::size_t Source = Destination - LimbOffset;
- if (Source < Right.Limbs.size())
- ShiftedWord = static_cast<std::uint32_t>(Right.Limbs[Source] << BitOffset);
- if (BitOffset != 0 && Source != 0 && Source - 1U < Right.Limbs.size())
- ShiftedWord |= Right.Limbs[Source - 1U] >> (32U - BitOffset);
- }
- const std::uint32_t LeftWord = Destination < Left.Limbs.size() ? Left.Limbs[Destination] : 0;
- if (LeftWord != ShiftedWord)
- return LeftWord < ShiftedWord ? -1 : 1;
- }
- return 0;
-}
-
-[[nodiscard]] bool parseHexWords(std::string_view Digits, std::uint32_t BitWidth,
- std::vector<std::uint64_t> &Words) {
- if (Digits.empty() || Digits.size() > (static_cast<std::size_t>(BitWidth) + 3U) / 4U)
- return false;
- Words.assign((BitWidth + 63U) / 64U, 0);
- std::size_t Nibble = 0;
- for (auto Iterator = Digits.rbegin(); Iterator != Digits.rend(); ++Iterator, ++Nibble) {
- if (!isHexDigit(*Iterator))
- return false;
- Words[Nibble / 16U] |= static_cast<std::uint64_t>(hexDigitValue(*Iterator))
- << ((Nibble % 16U) * 4U);
- }
- return (BitWidth % 64U) == 0 || (Words.back() >> (BitWidth % 64U)) == 0;
-}
-
-[[nodiscard]] bool parseWideFloatHexWords(std::string_view Digits,
- std::vector<std::uint64_t> &Words) {
- if (Digits.empty() || Digits.size() > 32U || !std::ranges::all_of(Digits, isHexDigit))
- return false;
- Words.assign(2, 0);
- const auto ParseWord = [](std::string_view Text, std::uint64_t &Word) {
- const auto Parsed = std::from_chars(Text.data(), Text.data() + Text.size(), Word, 16);
- return Parsed.ec == std::errc{} && Parsed.ptr == Text.data() + Text.size();
- };
- const std::size_t FirstWordLength = std::min<std::size_t>(Digits.size(), 16U);
- if (!ParseWord(Digits.substr(0, FirstWordLength), Words[0]))
- return false;
- if (Digits.size() == FirstWordLength)
- return true;
- return ParseWord(Digits.substr(FirstWordLength), Words[1]);
-}
-
-enum class SpecialFloatLiteralKind : std::uint8_t {
- Infinity,
- QuietNaN,
- SignalingNaN,
-};
-
-struct SpecialFloatLiteral final {
- SpecialFloatLiteralKind Kind = SpecialFloatLiteralKind::Infinity;
- bool Negative = false;
- std::array<std::uint64_t, 2> Payload{};
-};
-
-[[nodiscard]] Expected<std::optional<SpecialFloatLiteral>>
-parseSpecialFloatLiteral(std::string_view Token) {
- if (!Token.starts_with('+') && !Token.starts_with('-'))
- return std::optional<SpecialFloatLiteral>{};
-
- SpecialFloatLiteral Result;
- Result.Negative = Token.front() == '-';
- Token.remove_prefix(1);
- if (Token == "inf")
- return Result;
- if (Token == "qnan") {
- Result.Kind = SpecialFloatLiteralKind::QuietNaN;
- return Result;
- }
-
- if (!Token.starts_with("nan") && !Token.starts_with("snan"))
- return std::optional<SpecialFloatLiteral>{};
-
- const bool IsSignaling = Token.starts_with("snan");
- const std::size_t NameLength = IsSignaling ? 4U : 3U;
- const std::string_view Suffix = Token.substr(NameLength);
- Result.Kind =
- IsSignaling ? SpecialFloatLiteralKind::SignalingNaN : SpecialFloatLiteralKind::QuietNaN;
- if (Suffix.size() < 5 || Suffix.front() != '(' || Suffix.back() != ')' ||
- !Suffix.substr(1).starts_with("0x")) {
- return makeUnexpected(ErrorCode::ParseError, "invalid floating-point NaN payload");
- }
-
- const std::string_view Digits = Suffix.substr(3, Suffix.size() - 4U);
- if (Digits.empty() || !std::ranges::all_of(Digits, isHexDigit)) {
- return makeUnexpected(ErrorCode::ParseError, "invalid floating-point NaN payload");
- }
- std::size_t Nibble = 0;
- for (auto Iterator = Digits.rbegin(); Iterator != Digits.rend(); ++Iterator, ++Nibble) {
- if (Nibble >= 32U)
- break;
- Result.Payload[Nibble / 16U] |= static_cast<std::uint64_t>(hexDigitValue(*Iterator))
- << ((Nibble % 16U) * 4U);
- }
- return Result;
-}
-
-void setFloatBit(std::vector<std::uint64_t> &Words, std::uint32_t Bit) {
- Words[Bit / 64U] |= std::uint64_t{1} << (Bit % 64U);
-}
-
-void clearFloatBit(std::vector<std::uint64_t> &Words, std::uint32_t Bit) {
- Words[Bit / 64U] &= ~(std::uint64_t{1} << (Bit % 64U));
-}
-
-[[nodiscard]] bool hasFloatBit(std::span<const std::uint64_t> Words, std::uint32_t Bit) noexcept {
- return (Words[Bit / 64U] & (std::uint64_t{1} << (Bit % 64U))) != 0;
-}
-
-void copyNaNPayload(std::vector<std::uint64_t> &Words, const std::array<std::uint64_t, 2> &Payload,
- std::uint32_t PayloadBitWidth) {
- for (std::uint32_t Bit = 0; Bit < PayloadBitWidth; ++Bit) {
- if ((Payload[Bit / 64U] & (std::uint64_t{1} << (Bit % 64U))) != 0)
- setFloatBit(Words, Bit);
- }
-}
-
-void makeBinarySpecialFloat(std::vector<std::uint64_t> &Words, std::uint32_t BitWidth,
- std::uint32_t ExponentBitWidth, const SpecialFloatLiteral &Literal) {
- const std::uint32_t FractionBitWidth = BitWidth - ExponentBitWidth - 1U;
- if (Literal.Negative)
- setFloatBit(Words, BitWidth - 1U);
- for (std::uint32_t Bit = FractionBitWidth; Bit < FractionBitWidth + ExponentBitWidth; ++Bit) {
- setFloatBit(Words, Bit);
- }
- if (Literal.Kind == SpecialFloatLiteralKind::Infinity)
- return;
-
- copyNaNPayload(Words, Literal.Payload, FractionBitWidth);
- const std::uint32_t QuietNaNBit = FractionBitWidth - 1U;
- if (Literal.Kind == SpecialFloatLiteralKind::QuietNaN) {
- setFloatBit(Words, QuietNaNBit);
- return;
- }
- clearFloatBit(Words, QuietNaNBit);
- bool HasPayload = false;
- for (std::uint32_t Bit = 0; Bit < FractionBitWidth; ++Bit)
- HasPayload = HasPayload || hasFloatBit(Words, Bit);
- if (!HasPayload)
- setFloatBit(Words, QuietNaNBit - 1U);
-}
-
-[[nodiscard]] Expected<std::vector<std::uint64_t>>
-makeSpecialFloatWords(FloatSemantics Semantics, const SpecialFloatLiteral &Literal) {
- const auto BitWidth = getFloatSemanticsBitWidth(Semantics);
- if (!BitWidth)
- return makeUnexpected(ErrorCode::InvalidArgument, "floating-point semantics is unknown");
- std::vector<std::uint64_t> Words((*BitWidth + 63U) / 64U, 0);
- switch (Semantics) {
- case FloatSemantics::IEEEHalf:
- makeBinarySpecialFloat(Words, *BitWidth, 5, Literal);
- return Words;
- case FloatSemantics::BFloat:
- case FloatSemantics::IEEESingle:
- makeBinarySpecialFloat(Words, *BitWidth, 8, Literal);
- return Words;
- case FloatSemantics::IEEEDouble:
- makeBinarySpecialFloat(Words, *BitWidth, 11, Literal);
- return Words;
- case FloatSemantics::IEEEQuad:
- makeBinarySpecialFloat(Words, *BitWidth, 15, Literal);
- return Words;
- case FloatSemantics::X87DoubleExtended: {
- if (Literal.Negative)
- setFloatBit(Words, 79);
- for (std::uint32_t Bit = 64; Bit < 79; ++Bit)
- setFloatBit(Words, Bit);
- if (Literal.Kind == SpecialFloatLiteralKind::Infinity) {
- setFloatBit(Words, 63);
- return Words;
- }
- copyNaNPayload(Words, Literal.Payload, 63);
- setFloatBit(Words, 63);
- if (Literal.Kind == SpecialFloatLiteralKind::QuietNaN) {
- setFloatBit(Words, 62);
- return Words;
- }
- clearFloatBit(Words, 62);
- bool HasPayload = false;
- for (std::uint32_t Bit = 0; Bit < 63; ++Bit)
- HasPayload = HasPayload || hasFloatBit(Words, Bit);
- if (!HasPayload)
- setFloatBit(Words, 61);
- return Words;
- }
- case FloatSemantics::PPCDoubleDouble: {
- std::vector<std::uint64_t> HighPart(1, 0);
- makeBinarySpecialFloat(HighPart, 64, 11, Literal);
- Words[0] = HighPart.front();
- return Words;
- }
- case FloatSemantics::Float8E5M2:
- case FloatSemantics::Float8E5M2FNUZ:
- case FloatSemantics::Float8E4M3:
- case FloatSemantics::Float8E4M3FN:
- case FloatSemantics::Float8E4M3FNUZ:
- case FloatSemantics::Float8E4M3B11FNUZ:
- case FloatSemantics::Float8E3M4:
- case FloatSemantics::FloatTF32:
- case FloatSemantics::Float8E8M0FNU:
- case FloatSemantics::Float6E3M2FN:
- case FloatSemantics::Float6E2M3FN:
- case FloatSemantics::Float4E2M1FN:
- case FloatSemantics::Count:
- break;
- }
- return makeUnexpected(ErrorCode::Unsupported,
- "floating-point special literal uses unsupported semantics");
-}
-
-struct BinaryFloatFormat final {
- std::uint32_t Precision = 0;
- std::int32_t MinExponent = 0;
- std::int32_t MaxExponent = 0;
- std::uint32_t ExponentBitWidth = 0;
- std::uint32_t StorageBitWidth = 0;
- bool HasExplicitIntegerBit = false;
-};
-
-[[nodiscard]] std::optional<BinaryFloatFormat>
-binaryFloatFormat(FloatSemantics Semantics) noexcept {
- switch (Semantics) {
- case FloatSemantics::IEEEHalf:
- return BinaryFloatFormat{.Precision = 11,
- .MinExponent = -14,
- .MaxExponent = 15,
- .ExponentBitWidth = 5,
- .StorageBitWidth = 16};
- case FloatSemantics::BFloat:
- return BinaryFloatFormat{.Precision = 8,
- .MinExponent = -126,
- .MaxExponent = 127,
- .ExponentBitWidth = 8,
- .StorageBitWidth = 16};
- case FloatSemantics::IEEESingle:
- return BinaryFloatFormat{.Precision = 24,
- .MinExponent = -126,
- .MaxExponent = 127,
- .ExponentBitWidth = 8,
- .StorageBitWidth = 32};
- case FloatSemantics::IEEEDouble:
- return BinaryFloatFormat{.Precision = 53,
- .MinExponent = -1022,
- .MaxExponent = 1023,
- .ExponentBitWidth = 11,
- .StorageBitWidth = 64};
- case FloatSemantics::IEEEQuad:
- return BinaryFloatFormat{.Precision = 113,
- .MinExponent = -16382,
- .MaxExponent = 16383,
- .ExponentBitWidth = 15,
- .StorageBitWidth = 128};
- case FloatSemantics::X87DoubleExtended:
- return BinaryFloatFormat{.Precision = 64,
- .MinExponent = -16382,
- .MaxExponent = 16383,
- .ExponentBitWidth = 15,
- .StorageBitWidth = 80,
- .HasExplicitIntegerBit = true};
- case FloatSemantics::PPCDoubleDouble:
- // Decimal PPC double-double literals use 106 bits of precision and are
- // materialized as a canonical pair of doubles.
- return BinaryFloatFormat{.Precision = 106,
- .MinExponent = -969,
- .MaxExponent = 1023,
- .ExponentBitWidth = 0,
- .StorageBitWidth = 128};
- case FloatSemantics::Float8E5M2:
- case FloatSemantics::Float8E5M2FNUZ:
- case FloatSemantics::Float8E4M3:
- case FloatSemantics::Float8E4M3FN:
- case FloatSemantics::Float8E4M3FNUZ:
- case FloatSemantics::Float8E4M3B11FNUZ:
- case FloatSemantics::Float8E3M4:
- case FloatSemantics::FloatTF32:
- case FloatSemantics::Float8E8M0FNU:
- case FloatSemantics::Float6E3M2FN:
- case FloatSemantics::Float6E2M3FN:
- case FloatSemantics::Float4E2M1FN:
- case FloatSemantics::Count:
- return std::nullopt;
- }
- return std::nullopt;
-}
-
-struct RoundedBinaryFloat final {
- bool IsZero = false;
- bool IsSubnormal = false;
- std::int64_t Exponent = 0;
- std::int64_t Scale = 0;
- BigUnsigned Significand;
-};
-
-[[nodiscard]] RoundedBinaryFloat makeZeroRoundedBinaryFloat() {
- RoundedBinaryFloat Result;
- Result.IsZero = true;
- return Result;
-}
-
-[[nodiscard]] bool checkedAddExponent(std::int64_t Left, std::int64_t Right,
- std::int64_t &Result) noexcept {
- if (Right > 0 && Left > std::numeric_limits<std::int64_t>::max() - Right)
- return false;
- if (Right < 0 && Left < std::numeric_limits<std::int64_t>::min() - Right)
- return false;
- Result = Left + Right;
- return true;
-}
-
-[[nodiscard]] bool checkedSubtractExponent(std::int64_t Left, std::int64_t Right,
- std::int64_t &Result) noexcept {
- if (Right == std::numeric_limits<std::int64_t>::min()) {
- if (Left >= 0)
- return false;
- Result = Left - Right;
- return true;
- }
- return checkedAddExponent(Left, -Right, Result);
-}
-
-[[nodiscard]] Expected<BigUnsigned> divideAndRoundNearest(BigUnsigned Numerator,
- const BigUnsigned &Denominator) {
- if (Denominator.isZero())
- return makeUnexpected(ErrorCode::VerificationError,
- "floating-point conversion has a zero denominator");
-
- BigUnsigned Quotient;
- const std::size_t NumeratorBits = Numerator.bitWidth();
- const std::size_t DenominatorBits = Denominator.bitWidth();
- if (NumeratorBits >= DenominatorBits) {
- for (std::size_t Shift = NumeratorBits - DenominatorBits + 1U; Shift != 0; --Shift) {
- const std::size_t ActualShift = Shift - 1U;
- if (compareToShifted(Numerator, Denominator, ActualShift) < 0)
- continue;
- Numerator.subtract(Denominator.shiftedLeft(ActualShift));
- Quotient.setBit(ActualShift);
- }
- }
-
- const int HalfComparison = Numerator.shiftedLeft(1).compare(Denominator);
- if (HalfComparison > 0 || (HalfComparison == 0 && Quotient.isOdd()))
- Quotient.addSmall(1);
- return Quotient;
-}
-
-[[nodiscard]] Expected<BigUnsigned>
-roundScaledRational(BigUnsigned Numerator, BigUnsigned Denominator, std::int64_t Shift) {
- const auto AbsoluteShift = [Shift]() -> std::uint64_t {
- if (Shift >= 0)
- return static_cast<std::uint64_t>(Shift);
- return static_cast<std::uint64_t>(-(Shift + 1)) + 1U;
- }();
- if (AbsoluteShift > std::numeric_limits<std::size_t>::max()) {
- return makeUnexpected(ErrorCode::ParseError,
- "floating-point literal has an unrepresentable binary exponent");
- }
- if (Shift >= 0)
- Numerator = Numerator.shiftedLeft(static_cast<std::size_t>(AbsoluteShift));
- else
- Denominator = Denominator.shiftedLeft(static_cast<std::size_t>(AbsoluteShift));
- return divideAndRoundNearest(std::move(Numerator), Denominator);
-}
-
-[[nodiscard]] Expected<std::int64_t> floorLog2OfRational(const BigUnsigned &Numerator,
- const BigUnsigned &Denominator,
- std::int64_t BinaryScale) {
- if (Numerator.isZero() || Denominator.isZero()) {
- return makeUnexpected(ErrorCode::VerificationError,
- "floating-point conversion requires a nonzero rational value");
- }
- const std::size_t NumeratorBits = Numerator.bitWidth();
- const std::size_t DenominatorBits = Denominator.bitWidth();
- if (NumeratorBits > static_cast<std::size_t>(std::numeric_limits<std::int64_t>::max()) ||
- DenominatorBits > static_cast<std::size_t>(std::numeric_limits<std::int64_t>::max())) {
- return makeUnexpected(ErrorCode::Unsupported,
- "floating-point literal significand is too large");
- }
- const std::int64_t BitDelta =
- static_cast<std::int64_t>(NumeratorBits) - static_cast<std::int64_t>(DenominatorBits);
- std::int64_t Candidate = 0;
- if (!checkedAddExponent(BinaryScale, BitDelta, Candidate)) {
- return makeUnexpected(BinaryScale >= 0 ? ErrorCode::ParseError : ErrorCode::Unsupported,
- BinaryScale >= 0 ? "floating-point constant overflowed type"
- : "floating-point constant underflowed type");
- }
-
- const std::int64_t RelativeShift = -BitDelta;
- int Comparison = 0;
- if (RelativeShift >= 0) {
- if (static_cast<std::uint64_t>(RelativeShift) > std::numeric_limits<std::size_t>::max()) {
- Comparison = -1;
- } else {
- Comparison =
- -compareToShifted(Denominator, Numerator, static_cast<std::size_t>(RelativeShift));
- }
- } else {
- const std::uint64_t AbsoluteShift = static_cast<std::uint64_t>(-(RelativeShift + 1)) + 1U;
- if (AbsoluteShift > std::numeric_limits<std::size_t>::max())
- Comparison = 1;
- else
- Comparison =
- compareToShifted(Numerator, Denominator, static_cast<std::size_t>(AbsoluteShift));
- }
- if (Comparison >= 0)
- return Candidate;
- if (Candidate == std::numeric_limits<std::int64_t>::min()) {
- return makeUnexpected(ErrorCode::ParseError, "floating-point constant underflowed type");
- }
- return Candidate - 1;
-}
-
-[[nodiscard]] Expected<RoundedBinaryFloat> roundBinaryRational(const BinaryFloatFormat &Format,
- const BigUnsigned &Numerator,
- const BigUnsigned &Denominator,
- std::int64_t BinaryScale,
- bool PermitZeroResult = false) {
- if (Numerator.isZero())
- return makeZeroRoundedBinaryFloat();
-
- auto FloorExponent = floorLog2OfRational(Numerator, Denominator, BinaryScale);
- if (!FloorExponent)
- return std::unexpected(FloorExponent.error());
- if (*FloorExponent > Format.MaxExponent) {
- return makeUnexpected(ErrorCode::ParseError, "floating-point constant overflowed type");
- }
-
- const std::int64_t SmallestUnit =
- static_cast<std::int64_t>(Format.MinExponent) - (Format.Precision - 1U);
- if (*FloorExponent < SmallestUnit - 1) {
- if (PermitZeroResult)
- return makeZeroRoundedBinaryFloat();
- return makeUnexpected(ErrorCode::ParseError, "floating-point constant underflowed type");
- }
-
- const bool StartsNormal = *FloorExponent >= Format.MinExponent;
- const std::int64_t Unit = StartsNormal ? *FloorExponent - (Format.Precision - 1U) : SmallestUnit;
- std::int64_t Shift = 0;
- if (!checkedSubtractExponent(BinaryScale, Unit, Shift)) {
- return makeUnexpected(BinaryScale >= 0 ? ErrorCode::ParseError : ErrorCode::Unsupported,
- BinaryScale >= 0 ? "floating-point constant overflowed type"
- : "floating-point constant underflowed type");
- }
- auto Significand = roundScaledRational(Numerator, Denominator, Shift);
- if (!Significand)
- return std::unexpected(Significand.error());
- if (Significand->isZero()) {
- if (PermitZeroResult)
- return makeZeroRoundedBinaryFloat();
- return makeUnexpected(ErrorCode::ParseError, "floating-point constant underflowed type");
- }
-
- RoundedBinaryFloat Result;
- Result.Significand = std::move(*Significand);
- if (StartsNormal) {
- Result.Exponent = *FloorExponent;
- if (Result.Significand.bitWidth() > Format.Precision) {
- Result.Significand.shiftRightOne();
- if (Result.Exponent == Format.MaxExponent) {
- return makeUnexpected(ErrorCode::ParseError, "floating-point constant overflowed type");
- }
- ++Result.Exponent;
- }
- Result.Scale = Result.Exponent - (Format.Precision - 1U);
- return Result;
- }
-
- if (Result.Significand.bitWidth() >= Format.Precision) {
- Result.IsSubnormal = false;
- Result.Exponent = Format.MinExponent;
- Result.Scale = Result.Exponent - (Format.Precision - 1U);
- return Result;
- }
- Result.IsSubnormal = true;
- Result.Exponent = Format.MinExponent;
- Result.Scale = SmallestUnit;
- return Result;
-}
-
-void appendSignificandWords(std::vector<std::uint64_t> &Words, const BigUnsigned &Significand) {
- for (std::size_t Index = 0; Index < Words.size(); ++Index)
- Words[Index] = Significand.word(Index);
-}
-
-[[nodiscard]] Expected<std::vector<std::uint64_t>>
-packIEEEBinaryFloat(const BinaryFloatFormat &Format, const RoundedBinaryFloat &Value,
- bool Negative) {
- if (Format.HasExplicitIntegerBit || Format.ExponentBitWidth == 0 || Format.StorageBitWidth == 0) {
- return makeUnexpected(ErrorCode::VerificationError,
- "floating-point format does not use IEEE binary storage");
- }
- std::vector<std::uint64_t> Words((Format.StorageBitWidth + 63U) / 64U, 0);
- if (Value.IsZero) {
- if (Negative)
- setFloatBit(Words, Format.StorageBitWidth - 1U);
- return Words;
- }
-
- appendSignificandWords(Words, Value.Significand);
- const std::uint32_t FractionBitWidth = Format.Precision - 1U;
- if (!Value.IsSubnormal)
- clearFloatBit(Words, FractionBitWidth);
- const std::int64_t Bias = 1 - static_cast<std::int64_t>(Format.MinExponent);
- const std::uint64_t Exponent =
- Value.IsSubnormal ? 0 : static_cast<std::uint64_t>(Value.Exponent + Bias);
- for (std::uint32_t Bit = 0; Bit < Format.ExponentBitWidth; ++Bit) {
- if ((Exponent & (std::uint64_t{1} << Bit)) != 0)
- setFloatBit(Words, FractionBitWidth + Bit);
- }
- if (Negative)
- setFloatBit(Words, Format.StorageBitWidth - 1U);
- return Words;
-}
-
-[[nodiscard]] Expected<std::vector<std::uint64_t>>
-packX87Float(const BinaryFloatFormat &Format, const RoundedBinaryFloat &Value, bool Negative) {
- if (!Format.HasExplicitIntegerBit || Format.StorageBitWidth != 80 || Format.Precision != 64) {
- return makeUnexpected(ErrorCode::VerificationError, "x87 floating-point format is invalid");
- }
- std::vector<std::uint64_t> Words(2, 0);
- if (Value.IsZero) {
- if (Negative)
- setFloatBit(Words, 79);
- return Words;
- }
- Words[0] = Value.Significand.word(0);
- if (!Value.IsSubnormal) {
- const std::int64_t Bias = 1 - static_cast<std::int64_t>(Format.MinExponent);
- Words[1] = static_cast<std::uint64_t>(Value.Exponent + Bias);
- }
- if (Negative)
- setFloatBit(Words, 79);
- return Words;
-}
-
-[[nodiscard]] Expected<std::vector<std::uint64_t>>
-packPPCDoubleDouble(const RoundedBinaryFloat &Value, bool Negative) {
- const auto DoubleFormat = binaryFloatFormat(FloatSemantics::IEEEDouble);
- if (!DoubleFormat)
- return makeUnexpected(ErrorCode::VerificationError, "IEEE double format is unavailable");
- if (Value.IsZero) {
- RoundedBinaryFloat Zero = makeZeroRoundedBinaryFloat();
- auto High = packIEEEBinaryFloat(*DoubleFormat, Zero, Negative);
- if (!High)
- return std::unexpected(High.error());
- return std::vector<std::uint64_t>{High->front(), 0};
- }
-
- BigUnsigned One(1);
- auto High = roundBinaryRational(*DoubleFormat, Value.Significand, One, Value.Scale, true);
- if (!High)
- return std::unexpected(High.error());
- auto HighWords = packIEEEBinaryFloat(*DoubleFormat, *High, Negative);
- if (!HighWords)
- return std::unexpected(HighWords.error());
-
- BigUnsigned SourceMagnitude = Value.Significand;
- BigUnsigned HighMagnitude = High->Significand;
- const std::int64_t CommonScale = std::min(Value.Scale, High->Scale);
- if (!SourceMagnitude.isZero()) {
- const std::int64_t SourceShift = Value.Scale - CommonScale;
- if (SourceShift > 0)
- SourceMagnitude = SourceMagnitude.shiftedLeft(static_cast<std::size_t>(SourceShift));
- }
- if (!HighMagnitude.isZero()) {
- const std::int64_t HighShift = High->Scale - CommonScale;
- if (HighShift > 0)
- HighMagnitude = HighMagnitude.shiftedLeft(static_cast<std::size_t>(HighShift));
- }
-
- bool LowNegative = false;
- BigUnsigned LowMagnitude;
- if (SourceMagnitude.compare(HighMagnitude) >= 0) {
- LowMagnitude = std::move(SourceMagnitude);
- LowMagnitude.subtract(HighMagnitude);
- LowNegative = Negative;
- } else {
- LowMagnitude = std::move(HighMagnitude);
- LowMagnitude.subtract(SourceMagnitude);
- LowNegative = !Negative;
- }
-
- auto Low = roundBinaryRational(*DoubleFormat, LowMagnitude, One, CommonScale, true);
- if (!Low)
- return std::unexpected(Low.error());
- auto LowWords = packIEEEBinaryFloat(*DoubleFormat, *Low, LowNegative);
- if (!LowWords)
- return std::unexpected(LowWords.error());
- return std::vector<std::uint64_t>{HighWords->front(), LowWords->front()};
-}
-
-[[nodiscard]] Expected<std::vector<std::uint64_t>>
-convertRationalToFloatWords(FloatSemantics Semantics, bool Negative, const BigUnsigned &Numerator,
- const BigUnsigned &Denominator, std::int64_t BinaryScale) {
- const auto Format = binaryFloatFormat(Semantics);
- if (!Format) {
- return makeUnexpected(ErrorCode::Unsupported,
- "floating-point literal uses unsupported semantics");
- }
- auto Rounded = roundBinaryRational(*Format, Numerator, Denominator, BinaryScale);
- if (!Rounded)
- return std::unexpected(Rounded.error());
- if (Semantics == FloatSemantics::PPCDoubleDouble) {
- return packPPCDoubleDouble(*Rounded, Negative);
- }
- if (Format->HasExplicitIntegerBit)
- return packX87Float(*Format, *Rounded, Negative);
- return packIEEEBinaryFloat(*Format, *Rounded, Negative);
-}
-
-[[nodiscard]] bool isDecimalDigit(char Character) noexcept {
- return Character >= '0' && Character <= '9';
-}
-
-[[nodiscard]] Expected<std::int32_t> parseFloatingExponent(std::string_view Text,
- std::int32_t Limit) {
- if (Text.empty())
- return makeUnexpected(ErrorCode::ParseError, "floating-point exponent has no digits");
- bool Negative = false;
- if (Text.front() == '+' || Text.front() == '-') {
- Negative = Text.front() == '-';
- Text.remove_prefix(1);
- }
- if (Text.empty())
- return makeUnexpected(ErrorCode::ParseError, "floating-point exponent has no digits");
-
- std::int32_t Value = 0;
- for (const char Character : Text) {
- if (!isDecimalDigit(Character)) {
- return makeUnexpected(ErrorCode::ParseError,
- "floating-point exponent contains a non-decimal digit");
- }
- const std::int32_t Digit = Character - '0';
- if (Value >= Limit || Value > (Limit - Digit) / 10) {
- Value = Limit;
- continue;
- }
- Value = Value * 10 + Digit;
- }
- return Negative ? -Value : Value;
-}
-
-[[nodiscard]] BigUnsigned parseDecimalSignificand(std::string_view Digits) {
- BigUnsigned Result;
- std::size_t Position = 0;
- std::size_t FirstChunkLength = Digits.size() % 9U;
- if (FirstChunkLength == 0)
- FirstChunkLength = std::min<std::size_t>(Digits.size(), 9U);
- while (Position < Digits.size()) {
- const std::size_t Length = Position == 0 ? FirstChunkLength : 9U;
- std::uint32_t Chunk = 0;
- for (std::size_t Index = 0; Index < Length; ++Index)
- Chunk = Chunk * 10U + static_cast<std::uint32_t>(Digits[Position + Index] - '0');
- Result.multiplySmall(Position == 0 ? 1U : 1000000000U);
- Result.addSmall(Chunk);
- Position += Length;
- }
- return Result;
-}
-
-[[nodiscard]] BigUnsigned parseHexSignificand(std::string_view Digits) {
- BigUnsigned Result;
- for (const char Character : Digits) {
- Result.multiplySmall(16U);
- Result.addSmall(hexDigitValue(Character));
- }
- return Result;
-}
-
-void multiplyByPowerOfFive(BigUnsigned &Value, std::uint64_t Exponent) {
- for (std::uint64_t Index = 0; Index < Exponent; ++Index)
- Value.multiplySmall(5U);
-}
-
-[[nodiscard]] BigUnsigned powerOfFive(std::uint64_t Exponent) {
- BigUnsigned Result(1);
- multiplyByPowerOfFive(Result, Exponent);
- return Result;
-}
-
-[[nodiscard]] bool decimalDefinitelyOverflows(const BinaryFloatFormat &Format,
- std::int64_t NormalizedExponent) noexcept {
- const __int128 Left = (static_cast<__int128>(NormalizedExponent) - 1) * 42039;
- const __int128 Right = static_cast<__int128>(12655) * Format.MaxExponent;
- return Left >= Right;
-}
-
-[[nodiscard]] bool decimalDefinitelyUnderflows(const BinaryFloatFormat &Format,
- std::int64_t NormalizedExponent) noexcept {
- const __int128 Left = (static_cast<__int128>(NormalizedExponent) + 1) * 28738;
- const __int128 Right = static_cast<__int128>(8651) *
- (static_cast<std::int64_t>(Format.MinExponent) - Format.Precision);
- return Left <= Right;
-}
-
-struct ParsedFiniteFloatLiteral final {
- bool Negative = false;
- BigUnsigned Numerator;
- BigUnsigned Denominator{1};
- std::int64_t BinaryScale = 0;
-};
-
-[[nodiscard]] Expected<ParsedFiniteFloatLiteral>
-parseDecimalFloatLiteral(std::string_view Token, const BinaryFloatFormat &Format) {
- ParsedFiniteFloatLiteral Result;
- if (Token.starts_with('+') || Token.starts_with('-')) {
- Result.Negative = Token.front() == '-';
- Token.remove_prefix(1);
- }
- if (Token.empty())
- return makeUnexpected(ErrorCode::ParseError, "floating-point literal has no digits");
-
- std::size_t Position = 0;
- const std::size_t IntegerBegin = Position;
- while (Position < Token.size() && isDecimalDigit(Token[Position]))
- ++Position;
- if (IntegerBegin == Position || Position == Token.size() || Token[Position] != '.') {
- return makeUnexpected(ErrorCode::ParseError,
- "decimal floating-point literal requires a decimal point");
- }
-
- std::string Digits(Token.substr(IntegerBegin, Position - IntegerBegin));
- ++Position;
- const std::size_t FractionBegin = Position;
- while (Position < Token.size() && isDecimalDigit(Token[Position]))
- ++Position;
- Digits.append(Token.substr(FractionBegin, Position - FractionBegin));
- const std::size_t FractionDigits = Position - FractionBegin;
-
- std::int32_t Exponent = 0;
- if (Position < Token.size() && (Token[Position] == 'e' || Token[Position] == 'E')) {
- auto ParsedExponent = parseFloatingExponent(Token.substr(Position + 1U), 24000);
- if (!ParsedExponent)
- return std::unexpected(ParsedExponent.error());
- Exponent = *ParsedExponent;
- Position = Token.size();
- }
- if (Position != Token.size()) {
- return makeUnexpected(ErrorCode::ParseError,
- "decimal floating-point literal has an invalid suffix");
- }
-
- const std::size_t FirstSignificant = Digits.find_first_not_of('0');
- if (FirstSignificant == std::string::npos)
- return Result;
- const std::size_t LastSignificant = Digits.find_last_not_of('0');
- const std::string_view Significant(Digits.data() + FirstSignificant,
- LastSignificant - FirstSignificant + 1U);
- const std::size_t TrailingZeroCount = Digits.size() - LastSignificant - 1U;
- std::int64_t DecimalScale = static_cast<std::int64_t>(Exponent) -
- static_cast<std::int64_t>(FractionDigits) +
- static_cast<std::int64_t>(TrailingZeroCount);
- const std::int64_t NormalizedExponent =
- DecimalScale + static_cast<std::int64_t>(Significant.size() - 1U);
- if (decimalDefinitelyOverflows(Format, NormalizedExponent)) {
- return makeUnexpected(ErrorCode::ParseError, "floating-point constant overflowed type");
- }
- if (decimalDefinitelyUnderflows(Format, NormalizedExponent)) {
- return makeUnexpected(ErrorCode::ParseError, "floating-point constant underflowed type");
- }
-
- Result.Numerator = parseDecimalSignificand(Significant);
- Result.BinaryScale = DecimalScale;
- if (DecimalScale >= 0) {
- multiplyByPowerOfFive(Result.Numerator, static_cast<std::uint64_t>(DecimalScale));
- } else {
- Result.Denominator = powerOfFive(static_cast<std::uint64_t>(-(DecimalScale + 1)) + 1U);
- }
- return Result;
-}
-
-[[nodiscard]] Expected<ParsedFiniteFloatLiteral> parseHexFloatLiteral(std::string_view Token) {
- ParsedFiniteFloatLiteral Result;
- if (Token.starts_with('+') || Token.starts_with('-')) {
- Result.Negative = Token.front() == '-';
- Token.remove_prefix(1);
- }
- if (!Token.starts_with("0x")) {
- return makeUnexpected(ErrorCode::ParseError,
- "hexadecimal floating-point literal must use the 0x prefix");
- }
- std::size_t Position = 2;
- const std::size_t IntegerBegin = Position;
- while (Position < Token.size() && isHexDigit(Token[Position]))
- ++Position;
- if (IntegerBegin == Position || Position == Token.size() || Token[Position] != '.') {
- return makeUnexpected(ErrorCode::ParseError,
- "hexadecimal floating-point literal requires a hexadecimal point");
- }
- std::string Digits(Token.substr(IntegerBegin, Position - IntegerBegin));
- ++Position;
- const std::size_t FractionBegin = Position;
- while (Position < Token.size() && isHexDigit(Token[Position]))
- ++Position;
- Digits.append(Token.substr(FractionBegin, Position - FractionBegin));
- const std::size_t FractionDigits = Position - FractionBegin;
- if (Position == Token.size() || (Token[Position] != 'p' && Token[Position] != 'P')) {
- return makeUnexpected(ErrorCode::ParseError,
- "hexadecimal floating-point literal requires a binary exponent");
- }
- auto Exponent = parseFloatingExponent(Token.substr(Position + 1U), 32767);
- if (!Exponent)
- return std::unexpected(Exponent.error());
-
- const std::size_t FirstSignificant = Digits.find_first_not_of('0');
- if (FirstSignificant == std::string::npos)
- return Result;
- const std::string_view Significant(Digits.data() + FirstSignificant,
- Digits.size() - FirstSignificant);
- Result.Numerator = parseHexSignificand(Significant);
- Result.BinaryScale =
- static_cast<std::int64_t>(*Exponent) - static_cast<std::int64_t>(FractionDigits) * 4;
- return Result;
-}
-
-[[nodiscard]] Expected<std::uint64_t> parseRawDoubleBits(std::string_view Digits) {
- if (Digits.empty())
- return makeUnexpected(ErrorCode::ParseError,
- "hexadecimal floating-point literal has no digits");
- std::uint64_t Result = 0;
- for (const char Character : Digits) {
- if (!isHexDigit(Character)) {
- return makeUnexpected(ErrorCode::ParseError,
- "hexadecimal floating-point literal contains a non-hexadecimal digit");
- }
- const std::uint64_t Digit = hexDigitValue(Character);
- if (Result > (std::numeric_limits<std::uint64_t>::max() - Digit) / 16U) {
- return makeUnexpected(ErrorCode::ParseError,
- "hexadecimal floating-point literal does not fit IEEE double");
- }
- Result = Result * 16U + Digit;
- }
- return Result;
-}
-
-[[nodiscard]] int compareScaledBinaryIntegers(const BigUnsigned &Left, std::int64_t LeftScale,
- const BigUnsigned &Right, std::int64_t RightScale) {
- if (Left.isZero())
- return Right.isZero() ? 0 : -1;
- if (Right.isZero())
- return 1;
- if (LeftScale == RightScale)
- return Left.compare(Right);
- if (LeftScale > RightScale)
- return -compareToShifted(Right, Left, static_cast<std::size_t>(LeftScale - RightScale));
- return compareToShifted(Left, Right, static_cast<std::size_t>(RightScale - LeftScale));
-}
-
-[[nodiscard]] Expected<std::vector<std::uint64_t>>
-convertRawDoubleNaN(FloatSemantics Semantics, bool Negative, std::uint64_t Fraction) {
- if (Semantics == FloatSemantics::IEEEDouble) {
- return std::vector<std::uint64_t>{(Negative ? std::uint64_t{1} << 63U : 0) |
- 0x7ff0000000000000ULL | Fraction};
- }
- const auto Format = binaryFloatFormat(Semantics);
- if (!Format || Format->HasExplicitIntegerBit || Format->StorageBitWidth > 64 ||
- (Semantics != FloatSemantics::IEEEHalf && Semantics != FloatSemantics::BFloat &&
- Semantics != FloatSemantics::IEEESingle)) {
- return makeUnexpected(ErrorCode::ParseError,
- "unprefixed hexadecimal literal is invalid for type");
- }
- const std::uint32_t TargetFractionBits = Format->Precision - 1U;
- const std::uint32_t DroppedBits = 53U - Format->Precision;
- const std::uint64_t DroppedMask = (std::uint64_t{1} << DroppedBits) - 1U;
- if ((Fraction & DroppedMask) != 0) {
- return makeUnexpected(
- ErrorCode::ParseError,
- "hexadecimal floating-point literal is not exactly representable by its type");
- }
-
- const bool IsSignaling = (Fraction & (std::uint64_t{1} << 51U)) == 0;
- std::uint64_t TargetFraction = Fraction >> DroppedBits;
- const std::uint64_t QuietBit = std::uint64_t{1} << (TargetFractionBits - 1U);
- if (IsSignaling) {
- TargetFraction &= ~QuietBit;
- if ((TargetFraction & (QuietBit - 1U)) == 0)
- TargetFraction |= QuietBit >> 1U;
- } else {
- TargetFraction |= QuietBit;
- }
- const std::uint64_t Sign = Negative ? std::uint64_t{1} << (Format->StorageBitWidth - 1U) : 0;
- const std::uint64_t Exponent = (std::uint64_t{1} << Format->ExponentBitWidth) - 1U;
- return std::vector<std::uint64_t>{Sign | (Exponent << TargetFractionBits) | TargetFraction};
-}
-
-[[nodiscard]] Expected<std::vector<std::uint64_t>> convertRawDoubleLiteral(FloatSemantics Semantics,
- std::uint64_t Bits) {
- if (Semantics != FloatSemantics::IEEEHalf && Semantics != FloatSemantics::BFloat &&
- Semantics != FloatSemantics::IEEESingle && Semantics != FloatSemantics::IEEEDouble) {
- return makeUnexpected(ErrorCode::ParseError,
- "unprefixed hexadecimal literal is invalid for type");
- }
- if (Semantics == FloatSemantics::IEEEDouble)
- return std::vector<std::uint64_t>{Bits};
-
- const bool Negative = (Bits >> 63U) != 0;
- const std::uint64_t Exponent = (Bits >> 52U) & 0x7ffU;
- const std::uint64_t Fraction = Bits & 0x000fffffffffffffULL;
- if (Exponent == 0x7ffU) {
- if (Fraction != 0)
- return convertRawDoubleNaN(Semantics, Negative, Fraction);
- SpecialFloatLiteral Infinity{.Kind = SpecialFloatLiteralKind::Infinity, .Negative = Negative};
- return makeSpecialFloatWords(Semantics, Infinity);
- }
-
- const auto Format = binaryFloatFormat(Semantics);
- if (!Format)
- return makeUnexpected(ErrorCode::VerificationError, "IEEE target format is unavailable");
- if (Exponent == 0 && Fraction == 0) {
- RoundedBinaryFloat Zero = makeZeroRoundedBinaryFloat();
- return packIEEEBinaryFloat(*Format, Zero, Negative);
- }
-
- const bool IsSubnormal = Exponent == 0;
- const std::uint64_t Significand = IsSubnormal ? Fraction : (std::uint64_t{1} << 52U) | Fraction;
- const std::int64_t SourceScale =
- (IsSubnormal ? -1022 : static_cast<std::int64_t>(Exponent) - 1023) - 52;
- const BigUnsigned Source(Significand);
- const BigUnsigned One(1);
- auto Rounded = roundBinaryRational(*Format, Source, One, SourceScale);
- if (!Rounded)
- return std::unexpected(Rounded.error());
- if (compareScaledBinaryIntegers(Source, SourceScale, Rounded->Significand, Rounded->Scale) != 0) {
- return makeUnexpected(
- ErrorCode::ParseError,
- "hexadecimal floating-point literal is not exactly representable by its type");
- }
- return packIEEEBinaryFloat(*Format, *Rounded, Negative);
-}
-
-[[nodiscard]] Expected<IntegerImmediate> parseExplicitHexInteger(std::uint32_t BitWidth,
- std::string_view Spelling) {
- if (Spelling.size() < 4 || (Spelling[0] != 'u' && Spelling[0] != 's') || Spelling[1] != '0' ||
- Spelling[2] != 'x') {
- return makeUnexpected(ErrorCode::ParseError,
- "integer hexadecimal spelling must use u0x or s0x");
- }
- const std::string_view Digits = Spelling.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);
- unsigned MostSignificantBits = 0;
- for (unsigned Value = MostSignificantNibble; Value != 0; Value >>= 1U)
- ++MostSignificantBits;
- ActiveBits =
- static_cast<std::size_t>(Digits.end() - FirstNonZero - 1U) * 4U + MostSignificantBits;
- }
-
- std::vector<std::uint64_t> Words((BitWidth + 63U) / 64U, 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);
- }
-
- // LLVM discards leading zero bits before it assigns signedness to an s0x
- // literal. A nonzero signed spelling is therefore sign-extended from its
- // active width, rather than from the number of written hexadecimal digits.
- if (Spelling[0] == 's' && ActiveBits != 0 && ActiveBits < BitWidth) {
- const std::size_t FirstExtendedBit = ActiveBits;
- const std::size_t FirstWord = FirstExtendedBit / 64U;
- const unsigned FirstBit = static_cast<unsigned>(FirstExtendedBit % 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();
- }
- if ((BitWidth % 64U) != 0)
- Words.back() &= (std::uint64_t{1} << (BitWidth % 64U)) - 1U;
- return IntegerImmediate::create(BitWidth, Words);
-}
-
[[nodiscard]] std::optional<FloatSemantics> floatingSemantics(std::string_view Name) noexcept {
if (Name == "half")
return FloatSemantics::IEEEHalf;
@@ -1751,98 +545,9 @@ Expected<GenericConstantData> ConstantParser::parseFloatingValue(GenericConstant
auto Token = parseValueToken();
if (!Token)
return std::unexpected(Token.error());
- const std::uint32_t BitWidth = getFloatSemanticsBitWidth(EffectiveType.Semantics).value_or(0);
- const auto Format = binaryFloatFormat(EffectiveType.Semantics);
- if (!Format)
- return fail<GenericConstantData>("floating-point type has unsupported semantics");
- std::vector<std::uint64_t> Words;
-
- auto SpecialLiteral = parseSpecialFloatLiteral(*Token);
- if (!SpecialLiteral)
- return fail<GenericConstantData>(SpecialLiteral.error().message());
- if (*SpecialLiteral) {
- auto SpecialWords = makeSpecialFloatWords(EffectiveType.Semantics, **SpecialLiteral);
- if (!SpecialWords)
- return fail<GenericConstantData>(SpecialWords.error().message());
- Words = std::move(*SpecialWords);
- } else if (Token->starts_with("f0x")) {
- const std::string_view Digits = Token->substr(3);
- if (Digits.size() != (static_cast<std::size_t>(BitWidth) + 3U) / 4U ||
- !parseHexWords(Digits, BitWidth, Words)) {
- return fail<GenericConstantData>("exact floating-point bit pattern does not fit its type");
- }
- } else if (Token->starts_with("0x") && Token->find('.') != std::string_view::npos) {
- auto Literal = parseHexFloatLiteral(*Token);
- if (!Literal)
- return fail<GenericConstantData>(Literal.error().message());
- auto Converted =
- convertRationalToFloatWords(EffectiveType.Semantics, Literal->Negative, Literal->Numerator,
- Literal->Denominator, Literal->BinaryScale);
- if (!Converted)
- return fail<GenericConstantData>(Converted.error().message());
- Words = std::move(*Converted);
- } else if (Token->starts_with("0x")) {
- std::string_view Digits = Token->substr(2);
- char Prefix = '\0';
- if (!Digits.empty() && !isHexDigit(Digits.front())) {
- Prefix = Digits.front();
- Digits.remove_prefix(1);
- }
- char ExpectedPrefix = '\0';
- switch (EffectiveType.Semantics) {
- case FloatSemantics::IEEEHalf:
- ExpectedPrefix = 'H';
- break;
- case FloatSemantics::BFloat:
- ExpectedPrefix = 'R';
- break;
- case FloatSemantics::X87DoubleExtended:
- ExpectedPrefix = 'K';
- break;
- case FloatSemantics::IEEEQuad:
- ExpectedPrefix = 'L';
- break;
- case FloatSemantics::PPCDoubleDouble:
- ExpectedPrefix = 'M';
- break;
- default:
- break;
- }
- if (ExpectedPrefix != '\0') {
- const bool HasWideHexWords = EffectiveType.Semantics == FloatSemantics::IEEEQuad ||
- EffectiveType.Semantics == FloatSemantics::PPCDoubleDouble;
- const bool Parsed = HasWideHexWords ? parseWideFloatHexWords(Digits, Words)
- : parseHexWords(Digits, BitWidth, Words);
- if (Prefix != ExpectedPrefix || !Parsed) {
- return fail<GenericConstantData>(
- "floating-point hexadecimal prefix does not match its type");
- }
- } else if (Prefix != '\0') {
- return fail<GenericConstantData>("unexpected floating-point hexadecimal prefix");
- } else {
- auto DoubleBits = parseRawDoubleBits(Digits);
- if (!DoubleBits)
- return fail<GenericConstantData>(DoubleBits.error().message());
- auto Converted = convertRawDoubleLiteral(EffectiveType.Semantics, *DoubleBits);
- if (!Converted)
- return fail<GenericConstantData>(Converted.error().message());
- Words = std::move(*Converted);
- }
- } else {
- auto Literal = parseDecimalFloatLiteral(*Token, *Format);
- if (!Literal)
- return fail<GenericConstantData>(Literal.error().message());
- auto Converted =
- convertRationalToFloatWords(EffectiveType.Semantics, Literal->Negative, Literal->Numerator,
- Literal->Denominator, Literal->BinaryScale);
- if (!Converted)
- return fail<GenericConstantData>(Converted.error().message());
- Words = std::move(*Converted);
- }
-
- auto Bits = FloatingPointBits::create(EffectiveType.Semantics, Words);
+ auto Bits = APFloat::parse(EffectiveType.Semantics, *Token);
if (!Bits)
- return std::unexpected(Bits.error());
+ return fail<GenericConstantData>(Bits.error().message());
GenericConstantData Value;
Value.Type = std::move(Type);
Value.Kind = GenericConstantKind::Floating;
@@ -1979,7 +684,7 @@ Expected<GenericConstantData> ConstantParser::parseExpression(GenericConstantTyp
auto StartToken = parseValueToken();
if (!StartToken)
return std::unexpected(StartToken.error());
- auto Start = IntegerImmediate::parseDecimal(64, *StartToken);
+ auto Start = APInt::parseDecimal(64, *StartToken);
if (!Start)
return fail<GenericConstantData>("invalid inrange start");
if (auto Comma = expect(',', "',' in inrange interval"); !Comma)
@@ -1987,7 +692,7 @@ Expected<GenericConstantData> ConstantParser::parseExpression(GenericConstantTyp
auto EndToken = parseValueToken();
if (!EndToken)
return std::unexpected(EndToken.error());
- auto End = IntegerImmediate::parseDecimal(64, *EndToken);
+ auto End = APInt::parseDecimal(64, *EndToken);
if (!End)
return fail<GenericConstantData>("invalid inrange end");
if (auto Close = expect(')', "')' after inrange interval"); !Close)
@@ -2239,8 +944,8 @@ Expected<GenericConstantData> ConstantParser::parseValue(GenericConstantType Typ
const std::uint32_t BitWidth =
EffectiveType.Kind == GenericConstantTypeKind::Byte ? 8U : EffectiveType.BitWidth;
const bool IsExplicitHex = Spelling.starts_with("u0x") || Spelling.starts_with("s0x");
- auto Integer = IsExplicitHex ? parseExplicitHexInteger(BitWidth, Spelling)
- : IntegerImmediate::parseDecimal(BitWidth, Spelling);
+ auto Integer = IsExplicitHex ? APInt::parseLLVMHex(BitWidth, Spelling)
+ : APInt::parseDecimal(BitWidth, Spelling);
if (!Integer)
return fail<GenericConstantData>(Integer.error().message());
GenericConstantData Value;
@@ -2280,21 +985,6 @@ Expected<GenericConstantType> ConstantParser::parseTypeOnly() {
return Type;
}
-[[nodiscard]] std::string hexadecimalWords(std::span<const std::uint64_t> Words,
- std::uint32_t BitWidth) {
- static constexpr std::string_view Digits = "0123456789ABCDEF";
- const std::size_t DigitCount = std::max<std::size_t>((BitWidth + 3U) / 4U, 1);
- std::string Result(DigitCount, '0');
- for (std::size_t DigitIndex = 0; DigitIndex < DigitCount; ++DigitIndex) {
- const std::size_t SourceNibble = DigitCount - 1U - DigitIndex;
- const std::size_t WordIndex = SourceNibble / 16U;
- const unsigned Shift = static_cast<unsigned>((SourceNibble % 16U) * 4U);
- if (WordIndex < Words.size())
- Result[DigitIndex] = Digits[(Words[WordIndex] >> Shift) & 0xfU];
- }
- return Result;
-}
-
[[nodiscard]] bool canUseBareName(std::string_view Name) noexcept {
if (Name.empty() || !isIdentifierStart(Name.front()))
return false;
@@ -2431,224 +1121,6 @@ Expected<std::string> printType(const GenericConstantType &Type) {
return makeUnexpected(ErrorCode::VerificationError, "generic constant type is invalid");
}
-enum class PrintedFloatCategory : std::uint8_t {
- Zero,
- Finite,
- Infinity,
- QuietNaN,
- SignalingNaN,
-};
-
-struct PrintedBinaryFloat final {
- PrintedFloatCategory Category = PrintedFloatCategory::Zero;
- bool Negative = false;
- BigUnsigned Significand;
- std::int32_t BinaryExponent = 0;
- BigUnsigned NaNPayload;
- std::uint32_t QuietNaNBit = 0;
-};
-
-[[nodiscard]] std::uint64_t extractFloatField(std::span<const std::uint64_t> Words,
- std::uint32_t Begin, std::uint32_t Width) noexcept {
- std::uint64_t Result = 0;
- for (std::uint32_t Bit = 0; Bit < Width; ++Bit) {
- if (hasFloatBit(Words, Begin + Bit))
- Result |= std::uint64_t{1} << Bit;
- }
- return Result;
-}
-
-[[nodiscard]] BigUnsigned extractFloatBits(std::span<const std::uint64_t> Words,
- std::uint32_t Begin, std::uint32_t Width) {
- BigUnsigned Result;
- for (std::uint32_t Bit = 0; Bit < Width; ++Bit) {
- if (hasFloatBit(Words, Begin + Bit))
- Result.setBit(Bit);
- }
- return Result;
-}
-
-[[nodiscard]] std::optional<PrintedBinaryFloat> decodePrintedFloat(const FloatingPointBits &Bits) {
- std::optional<BinaryFloatFormat> Format = binaryFloatFormat(Bits.semantics());
- std::span<const std::uint64_t> Words = Bits.words();
- if (!Format)
- return std::nullopt;
-
- if (Bits.semantics() == FloatSemantics::PPCDoubleDouble) {
- if (Words.size() != 2 || Words[1] != 0)
- return std::nullopt;
- Format = binaryFloatFormat(FloatSemantics::IEEEDouble);
- Words = Words.first(1);
- }
- if (!Format || Format->ExponentBitWidth == 0)
- return std::nullopt;
-
- PrintedBinaryFloat Result;
- Result.Negative = hasFloatBit(Words, Format->StorageBitWidth - 1U);
- const std::uint32_t StoredSignificandWidth =
- Format->HasExplicitIntegerBit ? Format->Precision : Format->Precision - 1U;
- const std::uint64_t Exponent =
- extractFloatField(Words, StoredSignificandWidth, Format->ExponentBitWidth);
- const std::uint64_t MaximumExponent = (std::uint64_t{1} << Format->ExponentBitWidth) - 1U;
-
- if (Exponent == MaximumExponent) {
- const std::uint32_t PayloadWidth = Format->Precision - 1U;
- Result.NaNPayload = extractFloatBits(Words, 0, PayloadWidth);
- if (Result.NaNPayload.isZero()) {
- Result.Category = PrintedFloatCategory::Infinity;
- return Result;
- }
- Result.QuietNaNBit = PayloadWidth - 1U;
- Result.Category = hasFloatBit(Words, Result.QuietNaNBit) ? PrintedFloatCategory::QuietNaN
- : PrintedFloatCategory::SignalingNaN;
- return Result;
- }
-
- Result.Significand = extractFloatBits(Words, 0, StoredSignificandWidth);
- if (Exponent != 0 && !Format->HasExplicitIntegerBit)
- Result.Significand.setBit(Format->Precision - 1U);
- if (Result.Significand.isZero()) {
- Result.Category = PrintedFloatCategory::Zero;
- return Result;
- }
-
- const std::int64_t Bias = 1 - static_cast<std::int64_t>(Format->MinExponent);
- const std::int64_t UnbiasedExponent =
- Exponent == 0 ? Format->MinExponent : static_cast<std::int64_t>(Exponent) - Bias;
- Result.BinaryExponent = static_cast<std::int32_t>(UnbiasedExponent - (Format->Precision - 1U));
- Result.Category = PrintedFloatCategory::Finite;
- return Result;
-}
-
-[[nodiscard]] std::string printNaNPayload(BigUnsigned Payload, std::uint32_t QuietNaNBit) {
- Payload.clearBit(QuietNaNBit);
- const auto Width = static_cast<std::uint32_t>(std::max<std::size_t>(Payload.bitWidth(), 1U));
- std::array<std::uint64_t, 2> Words{Payload.word(0), Payload.word(1)};
- std::string Digits = hexadecimalWords(Words, Width);
- const std::size_t FirstNonzero = Digits.find_first_not_of('0');
- if (FirstNonzero == std::string::npos)
- return "0x0";
- Digits.erase(0, FirstNonzero);
- return "0x" + Digits;
-}
-
-[[nodiscard]] std::string formatFiniteFloat(PrintedBinaryFloat Value) {
- std::string Result;
- if (Value.Negative)
- Result.push_back('-');
- if (Value.Category == PrintedFloatCategory::Zero) {
- Result.append("0.000000e+00");
- return Result;
- }
-
- const std::size_t TrailingZeros = Value.Significand.countrZero();
- Value.Significand.shiftRight(TrailingZeros);
- Value.BinaryExponent += static_cast<std::int32_t>(TrailingZeros);
-
- std::int32_t DecimalExponent = 0;
- if (Value.BinaryExponent >= 0) {
- Value.Significand =
- Value.Significand.shiftedLeft(static_cast<std::size_t>(Value.BinaryExponent));
- } else {
- DecimalExponent = Value.BinaryExponent;
- for (std::int32_t Power = 0; Power < -Value.BinaryExponent; ++Power)
- Value.Significand.multiplySmall(5);
- }
-
- std::string Digits = Value.Significand.toDecimal();
- while (Digits.size() > 1U && Digits.back() == '0') {
- Digits.pop_back();
- ++DecimalExponent;
- }
-
- constexpr std::size_t FormatPrecision = 6;
- if (Digits.size() > FormatPrecision) {
- std::size_t Removed = Digits.size() - FormatPrecision;
- const bool RoundUp = Digits[FormatPrecision] >= '5';
- Digits.resize(FormatPrecision);
- if (RoundUp) {
- std::size_t Position = Digits.size();
- while (Position != 0 && Digits[Position - 1U] == '9') {
- Digits[Position - 1U] = '0';
- --Position;
- }
- if (Position == 0)
- Digits.insert(Digits.begin(), '1');
- else
- ++Digits[Position - 1U];
- }
- while (Digits.size() > 1U && Digits.back() == '0') {
- Digits.pop_back();
- ++Removed;
- }
- DecimalExponent += static_cast<std::int32_t>(Removed);
- }
-
- DecimalExponent += static_cast<std::int32_t>(Digits.size() - 1U);
- Result.push_back(Digits.front());
- Result.push_back('.');
- Result.append(Digits.substr(1));
- Result.append(7U - Digits.size(), '0');
- Result.push_back('e');
- Result.push_back(DecimalExponent < 0 ? '-' : '+');
- const std::uint32_t Magnitude = static_cast<std::uint32_t>(
- DecimalExponent < 0 ? -static_cast<std::int64_t>(DecimalExponent) : DecimalExponent);
- std::string Exponent = std::to_string(Magnitude);
- if (Exponent.size() < 2U)
- Result.push_back('0');
- Result.append(Exponent);
- return Result;
-}
-
-[[nodiscard]] std::string exactFloatingText(const FloatingPointBits &Bits) {
- return "f0x" + hexadecimalWords(Bits.words(), Bits.bitWidth());
-}
-
-[[nodiscard]] std::string canonicalFloatingText(const FloatingPointBits &Bits) {
- auto Decoded = decodePrintedFloat(Bits);
- if (!Decoded)
- return exactFloatingText(Bits);
-
- std::string Candidate;
- switch (Decoded->Category) {
- case PrintedFloatCategory::Zero:
- case PrintedFloatCategory::Finite:
- Candidate = formatFiniteFloat(std::move(*Decoded));
- break;
- case PrintedFloatCategory::Infinity:
- Candidate = Decoded->Negative ? "-inf" : "+inf";
- break;
- case PrintedFloatCategory::QuietNaN: {
- BigUnsigned Payload = Decoded->NaNPayload;
- Payload.clearBit(Decoded->QuietNaNBit);
- if (Payload.isZero()) {
- Candidate = Decoded->Negative ? "-qnan" : "+qnan";
- break;
- }
- Candidate = Decoded->Negative ? "-nan(" : "+nan(";
- Candidate.append(printNaNPayload(Decoded->NaNPayload, Decoded->QuietNaNBit));
- Candidate.push_back(')');
- break;
- }
- case PrintedFloatCategory::SignalingNaN:
- Candidate = Decoded->Negative ? "-snan(" : "+snan(";
- Candidate.append(printNaNPayload(Decoded->NaNPayload, Decoded->QuietNaNBit));
- Candidate.push_back(')');
- break;
- }
-
- auto Type = GenericConstantType::floating(Bits.semantics());
- if (!Type)
- return exactFloatingText(Bits);
- auto TypeText = printType(*Type);
- if (!TypeText)
- return exactFloatingText(Bits);
- auto Parsed = parseLLVMConstant(*TypeText + " " + Candidate);
- if (!Parsed || !Parsed->FloatingValue || *Parsed->FloatingValue != Bits)
- return exactFloatingText(Bits);
- return Candidate;
-}
-
[[nodiscard]] std::string_view
expressionOpcodeName(GenericConstantExpressionOpcode Opcode) noexcept {
switch (Opcode) {
@@ -2731,7 +1203,7 @@ Expected<std::string> printValue(const GenericConstantData &Value, bool IncludeT
if (!Value.FloatingValue)
return makeUnexpected(ErrorCode::VerificationError,
"floating constant is missing its floating payload");
- Result.append(canonicalFloatingText(*Value.FloatingValue));
+ Result.append(Value.FloatingValue->toString());
return Result;
case GenericConstantKind::NullPointer:
Result.append("null");
diff --git a/backend/lib/Support/APFloat.cpp b/backend/lib/Support/APFloat.cpp
new file mode 100644
index 0000000..c7b1503
--- /dev/null
+++ b/backend/lib/Support/APFloat.cpp
@@ -0,0 +1,1336 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "rcc/ADT/APFloat.h"
+
+#include "rcc/ADT/APInt.h"
+
+#include <algorithm>
+#include <array>
+#include <charconv>
+#include <cstddef>
+#include <cstdint>
+#include <limits>
+#include <optional>
+#include <ranges>
+#include <span>
+#include <string>
+#include <string_view>
+#include <utility>
+#include <vector>
+
+namespace rcc {
+namespace {
+
+struct FloatSemanticsInfo final {
+ std::uint32_t BitWidth;
+ std::string_view Spelling;
+};
+
+constexpr std::array FloatSemanticsTable{
+ FloatSemanticsInfo{16, "f16"}, FloatSemanticsInfo{16, "bf16"},
+ FloatSemanticsInfo{32, "f32"}, FloatSemanticsInfo{64, "f64"},
+ FloatSemanticsInfo{128, "f128"}, FloatSemanticsInfo{128, "ppcf128"},
+ FloatSemanticsInfo{8, "f8e5m2"}, FloatSemanticsInfo{8, "f8e5m2fnuz"},
+ FloatSemanticsInfo{8, "f8e4m3"}, FloatSemanticsInfo{8, "f8e4m3fn"},
+ FloatSemanticsInfo{8, "f8e4m3fnuz"}, FloatSemanticsInfo{8, "f8e4m3b11fnuz"},
+ FloatSemanticsInfo{8, "f8e3m4"}, FloatSemanticsInfo{19, "tf32"},
+ FloatSemanticsInfo{8, "f8e8m0fnu"}, FloatSemanticsInfo{6, "f6e3m2fn"},
+ FloatSemanticsInfo{6, "f6e2m3fn"}, FloatSemanticsInfo{4, "f4e2m1fn"},
+ FloatSemanticsInfo{80, "x86fp80"},
+};
+
+static_assert(FloatSemanticsTable.size() == static_cast<std::size_t>(FloatSemantics::Count));
+
+[[nodiscard]] const FloatSemanticsInfo *getFloatSemanticsInfo(FloatSemantics Semantics) noexcept {
+ const auto Index = static_cast<std::size_t>(Semantics);
+ if (Index >= FloatSemanticsTable.size())
+ return nullptr;
+ return &FloatSemanticsTable[Index];
+}
+
+[[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;
+}
+
+[[nodiscard]] bool parseHexWords(std::string_view Digits, std::uint32_t BitWidth,
+ std::vector<std::uint64_t> &Words) {
+ if (Digits.empty() || Digits.size() > (static_cast<std::size_t>(BitWidth) + 3U) / 4U)
+ return false;
+ Words.assign((BitWidth + 63U) / 64U, 0);
+ std::size_t Nibble = 0;
+ for (auto Iterator = Digits.rbegin(); Iterator != Digits.rend(); ++Iterator, ++Nibble) {
+ if (!isHexDigit(*Iterator))
+ return false;
+ Words[Nibble / 16U] |= static_cast<std::uint64_t>(hexDigitValue(*Iterator))
+ << ((Nibble % 16U) * 4U);
+ }
+ return (BitWidth % 64U) == 0 || (Words.back() >> (BitWidth % 64U)) == 0;
+}
+
+[[nodiscard]] bool parseWideFloatHexWords(std::string_view Digits,
+ std::vector<std::uint64_t> &Words) {
+ if (Digits.empty() || Digits.size() > 32U || !std::ranges::all_of(Digits, isHexDigit))
+ return false;
+ Words.assign(2, 0);
+ const auto ParseWord = [](std::string_view Text, std::uint64_t &Word) {
+ const auto Parsed = std::from_chars(Text.data(), Text.data() + Text.size(), Word, 16);
+ return Parsed.ec == std::errc{} && Parsed.ptr == Text.data() + Text.size();
+ };
+ const std::size_t FirstWordLength = std::min<std::size_t>(Digits.size(), 16U);
+ if (!ParseWord(Digits.substr(0, FirstWordLength), Words[0]))
+ return false;
+ if (Digits.size() == FirstWordLength)
+ return true;
+ return ParseWord(Digits.substr(FirstWordLength), Words[1]);
+}
+
+enum class SpecialFloatLiteralKind : std::uint8_t {
+ Infinity,
+ QuietNaN,
+ SignalingNaN,
+};
+
+struct SpecialFloatLiteral final {
+ SpecialFloatLiteralKind Kind = SpecialFloatLiteralKind::Infinity;
+ bool Negative = false;
+ std::array<std::uint64_t, 2> Payload{};
+};
+
+[[nodiscard]] Expected<std::optional<SpecialFloatLiteral>>
+parseSpecialFloatLiteral(std::string_view Token) {
+ if (!Token.starts_with('+') && !Token.starts_with('-'))
+ return std::optional<SpecialFloatLiteral>{};
+
+ SpecialFloatLiteral Result;
+ Result.Negative = Token.front() == '-';
+ Token.remove_prefix(1);
+ if (Token == "inf")
+ return Result;
+ if (Token == "qnan") {
+ Result.Kind = SpecialFloatLiteralKind::QuietNaN;
+ return Result;
+ }
+
+ if (!Token.starts_with("nan") && !Token.starts_with("snan"))
+ return std::optional<SpecialFloatLiteral>{};
+
+ const bool IsSignaling = Token.starts_with("snan");
+ const std::size_t NameLength = IsSignaling ? 4U : 3U;
+ const std::string_view Suffix = Token.substr(NameLength);
+ Result.Kind =
+ IsSignaling ? SpecialFloatLiteralKind::SignalingNaN : SpecialFloatLiteralKind::QuietNaN;
+ if (Suffix.size() < 5 || Suffix.front() != '(' || Suffix.back() != ')' ||
+ !Suffix.substr(1).starts_with("0x")) {
+ return makeUnexpected(ErrorCode::ParseError, "invalid floating-point NaN payload");
+ }
+
+ const std::string_view Digits = Suffix.substr(3, Suffix.size() - 4U);
+ if (Digits.empty() || !std::ranges::all_of(Digits, isHexDigit)) {
+ return makeUnexpected(ErrorCode::ParseError, "invalid floating-point NaN payload");
+ }
+ std::size_t Nibble = 0;
+ for (auto Iterator = Digits.rbegin(); Iterator != Digits.rend(); ++Iterator, ++Nibble) {
+ if (Nibble >= 32U)
+ break;
+ Result.Payload[Nibble / 16U] |= static_cast<std::uint64_t>(hexDigitValue(*Iterator))
+ << ((Nibble % 16U) * 4U);
+ }
+ return Result;
+}
+
+void setFloatBit(std::vector<std::uint64_t> &Words, std::uint32_t Bit) {
+ Words[Bit / 64U] |= std::uint64_t{1} << (Bit % 64U);
+}
+
+void clearFloatBit(std::vector<std::uint64_t> &Words, std::uint32_t Bit) {
+ Words[Bit / 64U] &= ~(std::uint64_t{1} << (Bit % 64U));
+}
+
+[[nodiscard]] bool hasFloatBit(std::span<const std::uint64_t> Words, std::uint32_t Bit) noexcept {
+ return (Words[Bit / 64U] & (std::uint64_t{1} << (Bit % 64U))) != 0;
+}
+
+void copyNaNPayload(std::vector<std::uint64_t> &Words, const std::array<std::uint64_t, 2> &Payload,
+ std::uint32_t PayloadBitWidth) {
+ for (std::uint32_t Bit = 0; Bit < PayloadBitWidth; ++Bit) {
+ if ((Payload[Bit / 64U] & (std::uint64_t{1} << (Bit % 64U))) != 0)
+ setFloatBit(Words, Bit);
+ }
+}
+
+void makeBinarySpecialFloat(std::vector<std::uint64_t> &Words, std::uint32_t BitWidth,
+ std::uint32_t ExponentBitWidth, const SpecialFloatLiteral &Literal) {
+ const std::uint32_t FractionBitWidth = BitWidth - ExponentBitWidth - 1U;
+ if (Literal.Negative)
+ setFloatBit(Words, BitWidth - 1U);
+ for (std::uint32_t Bit = FractionBitWidth; Bit < FractionBitWidth + ExponentBitWidth; ++Bit) {
+ setFloatBit(Words, Bit);
+ }
+ if (Literal.Kind == SpecialFloatLiteralKind::Infinity)
+ return;
+
+ copyNaNPayload(Words, Literal.Payload, FractionBitWidth);
+ const std::uint32_t QuietNaNBit = FractionBitWidth - 1U;
+ if (Literal.Kind == SpecialFloatLiteralKind::QuietNaN) {
+ setFloatBit(Words, QuietNaNBit);
+ return;
+ }
+ clearFloatBit(Words, QuietNaNBit);
+ bool HasPayload = false;
+ for (std::uint32_t Bit = 0; Bit < FractionBitWidth; ++Bit)
+ HasPayload = HasPayload || hasFloatBit(Words, Bit);
+ if (!HasPayload)
+ setFloatBit(Words, QuietNaNBit - 1U);
+}
+
+[[nodiscard]] Expected<std::vector<std::uint64_t>>
+makeSpecialFloatWords(FloatSemantics Semantics, const SpecialFloatLiteral &Literal) {
+ const auto BitWidth = getFloatSemanticsBitWidth(Semantics);
+ if (!BitWidth)
+ return makeUnexpected(ErrorCode::InvalidArgument, "floating-point semantics is unknown");
+ std::vector<std::uint64_t> Words((*BitWidth + 63U) / 64U, 0);
+ switch (Semantics) {
+ case FloatSemantics::IEEEHalf:
+ makeBinarySpecialFloat(Words, *BitWidth, 5, Literal);
+ return Words;
+ case FloatSemantics::BFloat:
+ case FloatSemantics::IEEESingle:
+ makeBinarySpecialFloat(Words, *BitWidth, 8, Literal);
+ return Words;
+ case FloatSemantics::IEEEDouble:
+ makeBinarySpecialFloat(Words, *BitWidth, 11, Literal);
+ return Words;
+ case FloatSemantics::IEEEQuad:
+ makeBinarySpecialFloat(Words, *BitWidth, 15, Literal);
+ return Words;
+ case FloatSemantics::X87DoubleExtended: {
+ if (Literal.Negative)
+ setFloatBit(Words, 79);
+ for (std::uint32_t Bit = 64; Bit < 79; ++Bit)
+ setFloatBit(Words, Bit);
+ if (Literal.Kind == SpecialFloatLiteralKind::Infinity) {
+ setFloatBit(Words, 63);
+ return Words;
+ }
+ copyNaNPayload(Words, Literal.Payload, 63);
+ setFloatBit(Words, 63);
+ if (Literal.Kind == SpecialFloatLiteralKind::QuietNaN) {
+ setFloatBit(Words, 62);
+ return Words;
+ }
+ clearFloatBit(Words, 62);
+ bool HasPayload = false;
+ for (std::uint32_t Bit = 0; Bit < 63; ++Bit)
+ HasPayload = HasPayload || hasFloatBit(Words, Bit);
+ if (!HasPayload)
+ setFloatBit(Words, 61);
+ return Words;
+ }
+ case FloatSemantics::PPCDoubleDouble: {
+ std::vector<std::uint64_t> HighPart(1, 0);
+ makeBinarySpecialFloat(HighPart, 64, 11, Literal);
+ Words[0] = HighPart.front();
+ return Words;
+ }
+ case FloatSemantics::Float8E5M2:
+ case FloatSemantics::Float8E5M2FNUZ:
+ case FloatSemantics::Float8E4M3:
+ case FloatSemantics::Float8E4M3FN:
+ case FloatSemantics::Float8E4M3FNUZ:
+ case FloatSemantics::Float8E4M3B11FNUZ:
+ case FloatSemantics::Float8E3M4:
+ case FloatSemantics::FloatTF32:
+ case FloatSemantics::Float8E8M0FNU:
+ case FloatSemantics::Float6E3M2FN:
+ case FloatSemantics::Float6E2M3FN:
+ case FloatSemantics::Float4E2M1FN:
+ case FloatSemantics::Count:
+ break;
+ }
+ return makeUnexpected(ErrorCode::Unsupported,
+ "floating-point special literal uses unsupported semantics");
+}
+
+struct BinaryFloatFormat final {
+ std::uint32_t Precision = 0;
+ std::int32_t MinExponent = 0;
+ std::int32_t MaxExponent = 0;
+ std::uint32_t ExponentBitWidth = 0;
+ std::uint32_t StorageBitWidth = 0;
+ bool HasExplicitIntegerBit = false;
+};
+
+[[nodiscard]] std::optional<BinaryFloatFormat>
+binaryFloatFormat(FloatSemantics Semantics) noexcept {
+ switch (Semantics) {
+ case FloatSemantics::IEEEHalf:
+ return BinaryFloatFormat{.Precision = 11,
+ .MinExponent = -14,
+ .MaxExponent = 15,
+ .ExponentBitWidth = 5,
+ .StorageBitWidth = 16};
+ case FloatSemantics::BFloat:
+ return BinaryFloatFormat{.Precision = 8,
+ .MinExponent = -126,
+ .MaxExponent = 127,
+ .ExponentBitWidth = 8,
+ .StorageBitWidth = 16};
+ case FloatSemantics::IEEESingle:
+ return BinaryFloatFormat{.Precision = 24,
+ .MinExponent = -126,
+ .MaxExponent = 127,
+ .ExponentBitWidth = 8,
+ .StorageBitWidth = 32};
+ case FloatSemantics::IEEEDouble:
+ return BinaryFloatFormat{.Precision = 53,
+ .MinExponent = -1022,
+ .MaxExponent = 1023,
+ .ExponentBitWidth = 11,
+ .StorageBitWidth = 64};
+ case FloatSemantics::IEEEQuad:
+ return BinaryFloatFormat{.Precision = 113,
+ .MinExponent = -16382,
+ .MaxExponent = 16383,
+ .ExponentBitWidth = 15,
+ .StorageBitWidth = 128};
+ case FloatSemantics::X87DoubleExtended:
+ return BinaryFloatFormat{.Precision = 64,
+ .MinExponent = -16382,
+ .MaxExponent = 16383,
+ .ExponentBitWidth = 15,
+ .StorageBitWidth = 80,
+ .HasExplicitIntegerBit = true};
+ case FloatSemantics::PPCDoubleDouble:
+ // Decimal PPC double-double literals use 106 bits of precision and are
+ // materialized as a canonical pair of doubles.
+ return BinaryFloatFormat{.Precision = 106,
+ .MinExponent = -969,
+ .MaxExponent = 1023,
+ .ExponentBitWidth = 0,
+ .StorageBitWidth = 128};
+ case FloatSemantics::Float8E5M2:
+ case FloatSemantics::Float8E5M2FNUZ:
+ case FloatSemantics::Float8E4M3:
+ case FloatSemantics::Float8E4M3FN:
+ case FloatSemantics::Float8E4M3FNUZ:
+ case FloatSemantics::Float8E4M3B11FNUZ:
+ case FloatSemantics::Float8E3M4:
+ case FloatSemantics::FloatTF32:
+ case FloatSemantics::Float8E8M0FNU:
+ case FloatSemantics::Float6E3M2FN:
+ case FloatSemantics::Float6E2M3FN:
+ case FloatSemantics::Float4E2M1FN:
+ case FloatSemantics::Count:
+ return std::nullopt;
+ }
+ return std::nullopt;
+}
+
+struct RoundedBinaryFloat final {
+ bool IsZero = false;
+ bool IsSubnormal = false;
+ std::int64_t Exponent = 0;
+ std::int64_t Scale = 0;
+ APInt Significand;
+};
+
+[[nodiscard]] RoundedBinaryFloat makeZeroRoundedBinaryFloat() {
+ RoundedBinaryFloat Result;
+ Result.IsZero = true;
+ return Result;
+}
+
+[[nodiscard]] bool checkedAddExponent(std::int64_t Left, std::int64_t Right,
+ std::int64_t &Result) noexcept {
+ if (Right > 0 && Left > std::numeric_limits<std::int64_t>::max() - Right)
+ return false;
+ if (Right < 0 && Left < std::numeric_limits<std::int64_t>::min() - Right)
+ return false;
+ Result = Left + Right;
+ return true;
+}
+
+[[nodiscard]] bool checkedSubtractExponent(std::int64_t Left, std::int64_t Right,
+ std::int64_t &Result) noexcept {
+ if (Right == std::numeric_limits<std::int64_t>::min()) {
+ if (Left >= 0)
+ return false;
+ Result = Left - Right;
+ return true;
+ }
+ return checkedAddExponent(Left, -Right, Result);
+}
+
+[[nodiscard]] Expected<APInt> divideAndRoundNearest(APInt Numerator, const APInt &Denominator) {
+ if (Denominator.isZero())
+ return makeUnexpected(ErrorCode::VerificationError,
+ "floating-point conversion has a zero denominator");
+
+ APInt Quotient;
+ const std::size_t NumeratorBits = Numerator.activeBitWidth();
+ const std::size_t DenominatorBits = Denominator.activeBitWidth();
+ if (NumeratorBits >= DenominatorBits) {
+ for (std::size_t Shift = NumeratorBits - DenominatorBits + 1U; Shift != 0; --Shift) {
+ const std::size_t ActualShift = Shift - 1U;
+ if (Numerator.compareToShifted(Denominator, ActualShift) < 0)
+ continue;
+ Numerator.subtract(Denominator.shiftedLeft(ActualShift));
+ Quotient.setBit(ActualShift);
+ }
+ }
+
+ const int HalfComparison = Numerator.shiftedLeft(1).compare(Denominator);
+ if (HalfComparison > 0 || (HalfComparison == 0 && (Quotient.word(0) & 1U) != 0))
+ Quotient.addSmall(1);
+ return Quotient;
+}
+
+[[nodiscard]] Expected<APInt> roundScaledRational(APInt Numerator, APInt Denominator,
+ std::int64_t Shift) {
+ const auto AbsoluteShift = [Shift]() -> std::uint64_t {
+ if (Shift >= 0)
+ return static_cast<std::uint64_t>(Shift);
+ return static_cast<std::uint64_t>(-(Shift + 1)) + 1U;
+ }();
+ if (AbsoluteShift > std::numeric_limits<std::size_t>::max()) {
+ return makeUnexpected(ErrorCode::ParseError,
+ "floating-point literal has an unrepresentable binary exponent");
+ }
+ if (Shift >= 0)
+ Numerator = Numerator.shiftedLeft(static_cast<std::size_t>(AbsoluteShift));
+ else
+ Denominator = Denominator.shiftedLeft(static_cast<std::size_t>(AbsoluteShift));
+ return divideAndRoundNearest(std::move(Numerator), Denominator);
+}
+
+[[nodiscard]] Expected<std::int64_t>
+floorLog2OfRational(const APInt &Numerator, const APInt &Denominator, std::int64_t BinaryScale) {
+ if (Numerator.isZero() || Denominator.isZero()) {
+ return makeUnexpected(ErrorCode::VerificationError,
+ "floating-point conversion requires a nonzero rational value");
+ }
+ const std::size_t NumeratorBits = Numerator.activeBitWidth();
+ const std::size_t DenominatorBits = Denominator.activeBitWidth();
+ if (NumeratorBits > static_cast<std::size_t>(std::numeric_limits<std::int64_t>::max()) ||
+ DenominatorBits > static_cast<std::size_t>(std::numeric_limits<std::int64_t>::max())) {
+ return makeUnexpected(ErrorCode::Unsupported,
+ "floating-point literal significand is too large");
+ }
+ const std::int64_t BitDelta =
+ static_cast<std::int64_t>(NumeratorBits) - static_cast<std::int64_t>(DenominatorBits);
+ std::int64_t Candidate = 0;
+ if (!checkedAddExponent(BinaryScale, BitDelta, Candidate)) {
+ return makeUnexpected(BinaryScale >= 0 ? ErrorCode::ParseError : ErrorCode::Unsupported,
+ BinaryScale >= 0 ? "floating-point constant overflowed type"
+ : "floating-point constant underflowed type");
+ }
+
+ const std::int64_t RelativeShift = -BitDelta;
+ int Comparison = 0;
+ if (RelativeShift >= 0) {
+ if (static_cast<std::uint64_t>(RelativeShift) > std::numeric_limits<std::size_t>::max()) {
+ Comparison = -1;
+ } else {
+ Comparison =
+ -Denominator.compareToShifted(Numerator, static_cast<std::size_t>(RelativeShift));
+ }
+ } else {
+ const std::uint64_t AbsoluteShift = static_cast<std::uint64_t>(-(RelativeShift + 1)) + 1U;
+ if (AbsoluteShift > std::numeric_limits<std::size_t>::max())
+ Comparison = 1;
+ else
+ Comparison = Numerator.compareToShifted(Denominator, static_cast<std::size_t>(AbsoluteShift));
+ }
+ if (Comparison >= 0)
+ return Candidate;
+ if (Candidate == std::numeric_limits<std::int64_t>::min()) {
+ return makeUnexpected(ErrorCode::ParseError, "floating-point constant underflowed type");
+ }
+ return Candidate - 1;
+}
+
+[[nodiscard]] Expected<RoundedBinaryFloat> roundBinaryRational(const BinaryFloatFormat &Format,
+ const APInt &Numerator,
+ const APInt &Denominator,
+ std::int64_t BinaryScale,
+ bool PermitZeroResult = false) {
+ if (Numerator.isZero())
+ return makeZeroRoundedBinaryFloat();
+
+ auto FloorExponent = floorLog2OfRational(Numerator, Denominator, BinaryScale);
+ if (!FloorExponent)
+ return std::unexpected(FloorExponent.error());
+ if (*FloorExponent > Format.MaxExponent) {
+ return makeUnexpected(ErrorCode::ParseError, "floating-point constant overflowed type");
+ }
+
+ const std::int64_t SmallestUnit =
+ static_cast<std::int64_t>(Format.MinExponent) - (Format.Precision - 1U);
+ if (*FloorExponent < SmallestUnit - 1) {
+ if (PermitZeroResult)
+ return makeZeroRoundedBinaryFloat();
+ return makeUnexpected(ErrorCode::ParseError, "floating-point constant underflowed type");
+ }
+
+ const bool StartsNormal = *FloorExponent >= Format.MinExponent;
+ const std::int64_t Unit = StartsNormal ? *FloorExponent - (Format.Precision - 1U) : SmallestUnit;
+ std::int64_t Shift = 0;
+ if (!checkedSubtractExponent(BinaryScale, Unit, Shift)) {
+ return makeUnexpected(BinaryScale >= 0 ? ErrorCode::ParseError : ErrorCode::Unsupported,
+ BinaryScale >= 0 ? "floating-point constant overflowed type"
+ : "floating-point constant underflowed type");
+ }
+ auto Significand = roundScaledRational(Numerator, Denominator, Shift);
+ if (!Significand)
+ return std::unexpected(Significand.error());
+ if (Significand->isZero()) {
+ if (PermitZeroResult)
+ return makeZeroRoundedBinaryFloat();
+ return makeUnexpected(ErrorCode::ParseError, "floating-point constant underflowed type");
+ }
+
+ RoundedBinaryFloat Result;
+ Result.Significand = std::move(*Significand);
+ if (StartsNormal) {
+ Result.Exponent = *FloorExponent;
+ if (Result.Significand.activeBitWidth() > Format.Precision) {
+ Result.Significand.shiftRight(1);
+ if (Result.Exponent == Format.MaxExponent) {
+ return makeUnexpected(ErrorCode::ParseError, "floating-point constant overflowed type");
+ }
+ ++Result.Exponent;
+ }
+ Result.Scale = Result.Exponent - (Format.Precision - 1U);
+ return Result;
+ }
+
+ if (Result.Significand.activeBitWidth() >= Format.Precision) {
+ Result.IsSubnormal = false;
+ Result.Exponent = Format.MinExponent;
+ Result.Scale = Result.Exponent - (Format.Precision - 1U);
+ return Result;
+ }
+ Result.IsSubnormal = true;
+ Result.Exponent = Format.MinExponent;
+ Result.Scale = SmallestUnit;
+ return Result;
+}
+
+void appendSignificandWords(std::vector<std::uint64_t> &Words, const APInt &Significand) {
+ for (std::size_t Index = 0; Index < Words.size(); ++Index)
+ Words[Index] = Significand.word(Index);
+}
+
+[[nodiscard]] Expected<std::vector<std::uint64_t>>
+packIEEEBinaryFloat(const BinaryFloatFormat &Format, const RoundedBinaryFloat &Value,
+ bool Negative) {
+ if (Format.HasExplicitIntegerBit || Format.ExponentBitWidth == 0 || Format.StorageBitWidth == 0) {
+ return makeUnexpected(ErrorCode::VerificationError,
+ "floating-point format does not use IEEE binary storage");
+ }
+ std::vector<std::uint64_t> Words((Format.StorageBitWidth + 63U) / 64U, 0);
+ if (Value.IsZero) {
+ if (Negative)
+ setFloatBit(Words, Format.StorageBitWidth - 1U);
+ return Words;
+ }
+
+ appendSignificandWords(Words, Value.Significand);
+ const std::uint32_t FractionBitWidth = Format.Precision - 1U;
+ if (!Value.IsSubnormal)
+ clearFloatBit(Words, FractionBitWidth);
+ const std::int64_t Bias = 1 - static_cast<std::int64_t>(Format.MinExponent);
+ const std::uint64_t Exponent =
+ Value.IsSubnormal ? 0 : static_cast<std::uint64_t>(Value.Exponent + Bias);
+ for (std::uint32_t Bit = 0; Bit < Format.ExponentBitWidth; ++Bit) {
+ if ((Exponent & (std::uint64_t{1} << Bit)) != 0)
+ setFloatBit(Words, FractionBitWidth + Bit);
+ }
+ if (Negative)
+ setFloatBit(Words, Format.StorageBitWidth - 1U);
+ return Words;
+}
+
+[[nodiscard]] Expected<std::vector<std::uint64_t>>
+packX87Float(const BinaryFloatFormat &Format, const RoundedBinaryFloat &Value, bool Negative) {
+ if (!Format.HasExplicitIntegerBit || Format.StorageBitWidth != 80 || Format.Precision != 64) {
+ return makeUnexpected(ErrorCode::VerificationError, "x87 floating-point format is invalid");
+ }
+ std::vector<std::uint64_t> Words(2, 0);
+ if (Value.IsZero) {
+ if (Negative)
+ setFloatBit(Words, 79);
+ return Words;
+ }
+ Words[0] = Value.Significand.word(0);
+ if (!Value.IsSubnormal) {
+ const std::int64_t Bias = 1 - static_cast<std::int64_t>(Format.MinExponent);
+ Words[1] = static_cast<std::uint64_t>(Value.Exponent + Bias);
+ }
+ if (Negative)
+ setFloatBit(Words, 79);
+ return Words;
+}
+
+[[nodiscard]] Expected<std::vector<std::uint64_t>>
+packPPCDoubleDouble(const RoundedBinaryFloat &Value, bool Negative) {
+ const auto DoubleFormat = binaryFloatFormat(FloatSemantics::IEEEDouble);
+ if (!DoubleFormat)
+ return makeUnexpected(ErrorCode::VerificationError, "IEEE double format is unavailable");
+ if (Value.IsZero) {
+ RoundedBinaryFloat Zero = makeZeroRoundedBinaryFloat();
+ auto High = packIEEEBinaryFloat(*DoubleFormat, Zero, Negative);
+ if (!High)
+ return std::unexpected(High.error());
+ return std::vector<std::uint64_t>{High->front(), 0};
+ }
+
+ APInt One(1);
+ auto High = roundBinaryRational(*DoubleFormat, Value.Significand, One, Value.Scale, true);
+ if (!High)
+ return std::unexpected(High.error());
+ auto HighWords = packIEEEBinaryFloat(*DoubleFormat, *High, Negative);
+ if (!HighWords)
+ return std::unexpected(HighWords.error());
+
+ APInt SourceMagnitude = Value.Significand;
+ APInt HighMagnitude = High->Significand;
+ const std::int64_t CommonScale = std::min(Value.Scale, High->Scale);
+ if (!SourceMagnitude.isZero()) {
+ const std::int64_t SourceShift = Value.Scale - CommonScale;
+ if (SourceShift > 0)
+ SourceMagnitude = SourceMagnitude.shiftedLeft(static_cast<std::size_t>(SourceShift));
+ }
+ if (!HighMagnitude.isZero()) {
+ const std::int64_t HighShift = High->Scale - CommonScale;
+ if (HighShift > 0)
+ HighMagnitude = HighMagnitude.shiftedLeft(static_cast<std::size_t>(HighShift));
+ }
+
+ bool LowNegative = false;
+ APInt LowMagnitude;
+ if (SourceMagnitude.compare(HighMagnitude) >= 0) {
+ LowMagnitude = std::move(SourceMagnitude);
+ LowMagnitude.subtract(HighMagnitude);
+ LowNegative = Negative;
+ } else {
+ LowMagnitude = std::move(HighMagnitude);
+ LowMagnitude.subtract(SourceMagnitude);
+ LowNegative = !Negative;
+ }
+
+ auto Low = roundBinaryRational(*DoubleFormat, LowMagnitude, One, CommonScale, true);
+ if (!Low)
+ return std::unexpected(Low.error());
+ auto LowWords = packIEEEBinaryFloat(*DoubleFormat, *Low, LowNegative);
+ if (!LowWords)
+ return std::unexpected(LowWords.error());
+ return std::vector<std::uint64_t>{HighWords->front(), LowWords->front()};
+}
+
+[[nodiscard]] Expected<std::vector<std::uint64_t>>
+convertRationalToFloatWords(FloatSemantics Semantics, bool Negative, const APInt &Numerator,
+ const APInt &Denominator, std::int64_t BinaryScale) {
+ const auto Format = binaryFloatFormat(Semantics);
+ if (!Format) {
+ return makeUnexpected(ErrorCode::Unsupported,
+ "floating-point literal uses unsupported semantics");
+ }
+ auto Rounded = roundBinaryRational(*Format, Numerator, Denominator, BinaryScale);
+ if (!Rounded)
+ return std::unexpected(Rounded.error());
+ if (Semantics == FloatSemantics::PPCDoubleDouble) {
+ return packPPCDoubleDouble(*Rounded, Negative);
+ }
+ if (Format->HasExplicitIntegerBit)
+ return packX87Float(*Format, *Rounded, Negative);
+ return packIEEEBinaryFloat(*Format, *Rounded, Negative);
+}
+
+[[nodiscard]] bool isDecimalDigit(char Character) noexcept {
+ return Character >= '0' && Character <= '9';
+}
+
+[[nodiscard]] Expected<std::int32_t> parseFloatingExponent(std::string_view Text,
+ std::int32_t Limit) {
+ if (Text.empty())
+ return makeUnexpected(ErrorCode::ParseError, "floating-point exponent has no digits");
+ bool Negative = false;
+ if (Text.front() == '+' || Text.front() == '-') {
+ Negative = Text.front() == '-';
+ Text.remove_prefix(1);
+ }
+ if (Text.empty())
+ return makeUnexpected(ErrorCode::ParseError, "floating-point exponent has no digits");
+
+ std::int32_t Value = 0;
+ for (const char Character : Text) {
+ if (!isDecimalDigit(Character)) {
+ return makeUnexpected(ErrorCode::ParseError,
+ "floating-point exponent contains a non-decimal digit");
+ }
+ const std::int32_t Digit = Character - '0';
+ if (Value >= Limit || Value > (Limit - Digit) / 10) {
+ Value = Limit;
+ continue;
+ }
+ Value = Value * 10 + Digit;
+ }
+ return Negative ? -Value : Value;
+}
+
+[[nodiscard]] APInt parseDecimalSignificand(std::string_view Digits) {
+ APInt Result;
+ std::size_t Position = 0;
+ std::size_t FirstChunkLength = Digits.size() % 9U;
+ if (FirstChunkLength == 0)
+ FirstChunkLength = std::min<std::size_t>(Digits.size(), 9U);
+ while (Position < Digits.size()) {
+ const std::size_t Length = Position == 0 ? FirstChunkLength : 9U;
+ std::uint32_t Chunk = 0;
+ for (std::size_t Index = 0; Index < Length; ++Index)
+ Chunk = Chunk * 10U + static_cast<std::uint32_t>(Digits[Position + Index] - '0');
+ Result.multiplySmall(Position == 0 ? 1U : 1000000000U);
+ Result.addSmall(Chunk);
+ Position += Length;
+ }
+ return Result;
+}
+
+[[nodiscard]] APInt parseHexSignificand(std::string_view Digits) {
+ APInt Result;
+ for (const char Character : Digits) {
+ Result.multiplySmall(16U);
+ Result.addSmall(hexDigitValue(Character));
+ }
+ return Result;
+}
+
+void multiplyByPowerOfFive(APInt &Value, std::uint64_t Exponent) {
+ for (std::uint64_t Index = 0; Index < Exponent; ++Index)
+ Value.multiplySmall(5U);
+}
+
+[[nodiscard]] APInt powerOfFive(std::uint64_t Exponent) {
+ APInt Result(1);
+ multiplyByPowerOfFive(Result, Exponent);
+ return Result;
+}
+
+[[nodiscard]] bool decimalDefinitelyOverflows(const BinaryFloatFormat &Format,
+ std::int64_t NormalizedExponent) noexcept {
+ const __int128 Left = (static_cast<__int128>(NormalizedExponent) - 1) * 42039;
+ const __int128 Right = static_cast<__int128>(12655) * Format.MaxExponent;
+ return Left >= Right;
+}
+
+[[nodiscard]] bool decimalDefinitelyUnderflows(const BinaryFloatFormat &Format,
+ std::int64_t NormalizedExponent) noexcept {
+ const __int128 Left = (static_cast<__int128>(NormalizedExponent) + 1) * 28738;
+ const __int128 Right = static_cast<__int128>(8651) *
+ (static_cast<std::int64_t>(Format.MinExponent) - Format.Precision);
+ return Left <= Right;
+}
+
+struct ParsedFiniteFloatLiteral final {
+ bool Negative = false;
+ APInt Numerator;
+ APInt Denominator{1};
+ std::int64_t BinaryScale = 0;
+};
+
+[[nodiscard]] Expected<ParsedFiniteFloatLiteral>
+parseDecimalFloatLiteral(std::string_view Token, const BinaryFloatFormat &Format) {
+ ParsedFiniteFloatLiteral Result;
+ if (Token.starts_with('+') || Token.starts_with('-')) {
+ Result.Negative = Token.front() == '-';
+ Token.remove_prefix(1);
+ }
+ if (Token.empty())
+ return makeUnexpected(ErrorCode::ParseError, "floating-point literal has no digits");
+
+ std::size_t Position = 0;
+ const std::size_t IntegerBegin = Position;
+ while (Position < Token.size() && isDecimalDigit(Token[Position]))
+ ++Position;
+ if (IntegerBegin == Position || Position == Token.size() || Token[Position] != '.') {
+ return makeUnexpected(ErrorCode::ParseError,
+ "decimal floating-point literal requires a decimal point");
+ }
+
+ std::string Digits(Token.substr(IntegerBegin, Position - IntegerBegin));
+ ++Position;
+ const std::size_t FractionBegin = Position;
+ while (Position < Token.size() && isDecimalDigit(Token[Position]))
+ ++Position;
+ Digits.append(Token.substr(FractionBegin, Position - FractionBegin));
+ const std::size_t FractionDigits = Position - FractionBegin;
+
+ std::int32_t Exponent = 0;
+ if (Position < Token.size() && (Token[Position] == 'e' || Token[Position] == 'E')) {
+ auto ParsedExponent = parseFloatingExponent(Token.substr(Position + 1U), 24000);
+ if (!ParsedExponent)
+ return std::unexpected(ParsedExponent.error());
+ Exponent = *ParsedExponent;
+ Position = Token.size();
+ }
+ if (Position != Token.size()) {
+ return makeUnexpected(ErrorCode::ParseError,
+ "decimal floating-point literal has an invalid suffix");
+ }
+
+ const std::size_t FirstSignificant = Digits.find_first_not_of('0');
+ if (FirstSignificant == std::string::npos)
+ return Result;
+ const std::size_t LastSignificant = Digits.find_last_not_of('0');
+ const std::string_view Significant(Digits.data() + FirstSignificant,
+ LastSignificant - FirstSignificant + 1U);
+ const std::size_t TrailingZeroCount = Digits.size() - LastSignificant - 1U;
+ std::int64_t DecimalScale = static_cast<std::int64_t>(Exponent) -
+ static_cast<std::int64_t>(FractionDigits) +
+ static_cast<std::int64_t>(TrailingZeroCount);
+ const std::int64_t NormalizedExponent =
+ DecimalScale + static_cast<std::int64_t>(Significant.size() - 1U);
+ if (decimalDefinitelyOverflows(Format, NormalizedExponent)) {
+ return makeUnexpected(ErrorCode::ParseError, "floating-point constant overflowed type");
+ }
+ if (decimalDefinitelyUnderflows(Format, NormalizedExponent)) {
+ return makeUnexpected(ErrorCode::ParseError, "floating-point constant underflowed type");
+ }
+
+ Result.Numerator = parseDecimalSignificand(Significant);
+ Result.BinaryScale = DecimalScale;
+ if (DecimalScale >= 0) {
+ multiplyByPowerOfFive(Result.Numerator, static_cast<std::uint64_t>(DecimalScale));
+ } else {
+ Result.Denominator = powerOfFive(static_cast<std::uint64_t>(-(DecimalScale + 1)) + 1U);
+ }
+ return Result;
+}
+
+[[nodiscard]] Expected<ParsedFiniteFloatLiteral> parseHexFloatLiteral(std::string_view Token) {
+ ParsedFiniteFloatLiteral Result;
+ if (Token.starts_with('+') || Token.starts_with('-')) {
+ Result.Negative = Token.front() == '-';
+ Token.remove_prefix(1);
+ }
+ if (!Token.starts_with("0x")) {
+ return makeUnexpected(ErrorCode::ParseError,
+ "hexadecimal floating-point literal must use the 0x prefix");
+ }
+ std::size_t Position = 2;
+ const std::size_t IntegerBegin = Position;
+ while (Position < Token.size() && isHexDigit(Token[Position]))
+ ++Position;
+ if (IntegerBegin == Position || Position == Token.size() || Token[Position] != '.') {
+ return makeUnexpected(ErrorCode::ParseError,
+ "hexadecimal floating-point literal requires a hexadecimal point");
+ }
+ std::string Digits(Token.substr(IntegerBegin, Position - IntegerBegin));
+ ++Position;
+ const std::size_t FractionBegin = Position;
+ while (Position < Token.size() && isHexDigit(Token[Position]))
+ ++Position;
+ Digits.append(Token.substr(FractionBegin, Position - FractionBegin));
+ const std::size_t FractionDigits = Position - FractionBegin;
+ if (Position == Token.size() || (Token[Position] != 'p' && Token[Position] != 'P')) {
+ return makeUnexpected(ErrorCode::ParseError,
+ "hexadecimal floating-point literal requires a binary exponent");
+ }
+ auto Exponent = parseFloatingExponent(Token.substr(Position + 1U), 32767);
+ if (!Exponent)
+ return std::unexpected(Exponent.error());
+
+ const std::size_t FirstSignificant = Digits.find_first_not_of('0');
+ if (FirstSignificant == std::string::npos)
+ return Result;
+ const std::string_view Significant(Digits.data() + FirstSignificant,
+ Digits.size() - FirstSignificant);
+ Result.Numerator = parseHexSignificand(Significant);
+ Result.BinaryScale =
+ static_cast<std::int64_t>(*Exponent) - static_cast<std::int64_t>(FractionDigits) * 4;
+ return Result;
+}
+
+[[nodiscard]] Expected<std::uint64_t> parseRawDoubleBits(std::string_view Digits) {
+ if (Digits.empty())
+ return makeUnexpected(ErrorCode::ParseError,
+ "hexadecimal floating-point literal has no digits");
+ std::uint64_t Result = 0;
+ for (const char Character : Digits) {
+ if (!isHexDigit(Character)) {
+ return makeUnexpected(ErrorCode::ParseError,
+ "hexadecimal floating-point literal contains a non-hexadecimal digit");
+ }
+ const std::uint64_t Digit = hexDigitValue(Character);
+ if (Result > (std::numeric_limits<std::uint64_t>::max() - Digit) / 16U) {
+ return makeUnexpected(ErrorCode::ParseError,
+ "hexadecimal floating-point literal does not fit IEEE double");
+ }
+ Result = Result * 16U + Digit;
+ }
+ return Result;
+}
+
+[[nodiscard]] int compareScaledBinaryIntegers(const APInt &Left, std::int64_t LeftScale,
+ const APInt &Right, std::int64_t RightScale) {
+ if (Left.isZero())
+ return Right.isZero() ? 0 : -1;
+ if (Right.isZero())
+ return 1;
+ if (LeftScale == RightScale)
+ return Left.compare(Right);
+ if (LeftScale > RightScale)
+ return -Right.compareToShifted(Left, static_cast<std::size_t>(LeftScale - RightScale));
+ return Left.compareToShifted(Right, static_cast<std::size_t>(RightScale - LeftScale));
+}
+
+[[nodiscard]] Expected<std::vector<std::uint64_t>>
+convertRawDoubleNaN(FloatSemantics Semantics, bool Negative, std::uint64_t Fraction) {
+ if (Semantics == FloatSemantics::IEEEDouble) {
+ return std::vector<std::uint64_t>{(Negative ? std::uint64_t{1} << 63U : 0) |
+ 0x7ff0000000000000ULL | Fraction};
+ }
+ const auto Format = binaryFloatFormat(Semantics);
+ if (!Format || Format->HasExplicitIntegerBit || Format->StorageBitWidth > 64 ||
+ (Semantics != FloatSemantics::IEEEHalf && Semantics != FloatSemantics::BFloat &&
+ Semantics != FloatSemantics::IEEESingle)) {
+ return makeUnexpected(ErrorCode::ParseError,
+ "unprefixed hexadecimal literal is invalid for type");
+ }
+ const std::uint32_t TargetFractionBits = Format->Precision - 1U;
+ const std::uint32_t DroppedBits = 53U - Format->Precision;
+ const std::uint64_t DroppedMask = (std::uint64_t{1} << DroppedBits) - 1U;
+ if ((Fraction & DroppedMask) != 0) {
+ return makeUnexpected(
+ ErrorCode::ParseError,
+ "hexadecimal floating-point literal is not exactly representable by its type");
+ }
+
+ const bool IsSignaling = (Fraction & (std::uint64_t{1} << 51U)) == 0;
+ std::uint64_t TargetFraction = Fraction >> DroppedBits;
+ const std::uint64_t QuietBit = std::uint64_t{1} << (TargetFractionBits - 1U);
+ if (IsSignaling) {
+ TargetFraction &= ~QuietBit;
+ if ((TargetFraction & (QuietBit - 1U)) == 0)
+ TargetFraction |= QuietBit >> 1U;
+ } else {
+ TargetFraction |= QuietBit;
+ }
+ const std::uint64_t Sign = Negative ? std::uint64_t{1} << (Format->StorageBitWidth - 1U) : 0;
+ const std::uint64_t Exponent = (std::uint64_t{1} << Format->ExponentBitWidth) - 1U;
+ return std::vector<std::uint64_t>{Sign | (Exponent << TargetFractionBits) | TargetFraction};
+}
+
+[[nodiscard]] Expected<std::vector<std::uint64_t>> convertRawDoubleLiteral(FloatSemantics Semantics,
+ std::uint64_t Bits) {
+ if (Semantics != FloatSemantics::IEEEHalf && Semantics != FloatSemantics::BFloat &&
+ Semantics != FloatSemantics::IEEESingle && Semantics != FloatSemantics::IEEEDouble) {
+ return makeUnexpected(ErrorCode::ParseError,
+ "unprefixed hexadecimal literal is invalid for type");
+ }
+ if (Semantics == FloatSemantics::IEEEDouble)
+ return std::vector<std::uint64_t>{Bits};
+
+ const bool Negative = (Bits >> 63U) != 0;
+ const std::uint64_t Exponent = (Bits >> 52U) & 0x7ffU;
+ const std::uint64_t Fraction = Bits & 0x000fffffffffffffULL;
+ if (Exponent == 0x7ffU) {
+ if (Fraction != 0)
+ return convertRawDoubleNaN(Semantics, Negative, Fraction);
+ SpecialFloatLiteral Infinity{.Kind = SpecialFloatLiteralKind::Infinity, .Negative = Negative};
+ return makeSpecialFloatWords(Semantics, Infinity);
+ }
+
+ const auto Format = binaryFloatFormat(Semantics);
+ if (!Format)
+ return makeUnexpected(ErrorCode::VerificationError, "IEEE target format is unavailable");
+ if (Exponent == 0 && Fraction == 0) {
+ RoundedBinaryFloat Zero = makeZeroRoundedBinaryFloat();
+ return packIEEEBinaryFloat(*Format, Zero, Negative);
+ }
+
+ const bool IsSubnormal = Exponent == 0;
+ const std::uint64_t Significand = IsSubnormal ? Fraction : (std::uint64_t{1} << 52U) | Fraction;
+ const std::int64_t SourceScale =
+ (IsSubnormal ? -1022 : static_cast<std::int64_t>(Exponent) - 1023) - 52;
+ const APInt Source(Significand);
+ const APInt One(1);
+ auto Rounded = roundBinaryRational(*Format, Source, One, SourceScale);
+ if (!Rounded)
+ return std::unexpected(Rounded.error());
+ if (compareScaledBinaryIntegers(Source, SourceScale, Rounded->Significand, Rounded->Scale) != 0) {
+ return makeUnexpected(
+ ErrorCode::ParseError,
+ "hexadecimal floating-point literal is not exactly representable by its type");
+ }
+ return packIEEEBinaryFloat(*Format, *Rounded, Negative);
+}
+
+enum class PrintedFloatCategory : std::uint8_t {
+ Zero,
+ Finite,
+ Infinity,
+ QuietNaN,
+ SignalingNaN,
+};
+
+struct PrintedBinaryFloat final {
+ PrintedFloatCategory Category = PrintedFloatCategory::Zero;
+ bool Negative = false;
+ APInt Significand;
+ std::int32_t BinaryExponent = 0;
+ APInt NaNPayload;
+ std::uint32_t QuietNaNBit = 0;
+};
+
+[[nodiscard]] std::string hexadecimalWords(std::span<const std::uint64_t> Words,
+ std::uint32_t BitWidth) {
+ constexpr std::string_view Digits = "0123456789ABCDEF";
+ const std::size_t DigitCount = (static_cast<std::size_t>(BitWidth) + 3U) / 4U;
+ std::string Result(DigitCount, '0');
+ for (std::size_t Index = 0; Index < DigitCount; ++Index) {
+ const std::size_t Bit = Index * 4U;
+ const std::uint64_t Nibble = (Words[Bit / 64U] >> (Bit % 64U)) & 0xFU;
+ Result[DigitCount - Index - 1U] = Digits[static_cast<std::size_t>(Nibble)];
+ }
+ return Result;
+}
+
+[[nodiscard]] std::uint64_t extractFloatField(std::span<const std::uint64_t> Words,
+ std::uint32_t Begin, std::uint32_t Width) noexcept {
+ std::uint64_t Result = 0;
+ for (std::uint32_t Bit = 0; Bit < Width; ++Bit) {
+ if (hasFloatBit(Words, Begin + Bit))
+ Result |= std::uint64_t{1} << Bit;
+ }
+ return Result;
+}
+
+[[nodiscard]] APInt extractFloatBits(std::span<const std::uint64_t> Words, std::uint32_t Begin,
+ std::uint32_t Width) {
+ APInt Result;
+ for (std::uint32_t Bit = 0; Bit < Width; ++Bit) {
+ if (hasFloatBit(Words, Begin + Bit))
+ Result.setBit(Bit);
+ }
+ return Result;
+}
+
+[[nodiscard]] std::optional<PrintedBinaryFloat> decodePrintedFloat(const APFloat &Bits) {
+ std::optional<BinaryFloatFormat> Format = binaryFloatFormat(Bits.semantics());
+ std::span<const std::uint64_t> Words = Bits.words();
+ if (!Format)
+ return std::nullopt;
+
+ if (Bits.semantics() == FloatSemantics::PPCDoubleDouble) {
+ if (Words.size() != 2 || Words[1] != 0)
+ return std::nullopt;
+ Format = binaryFloatFormat(FloatSemantics::IEEEDouble);
+ Words = Words.first(1);
+ }
+ if (!Format || Format->ExponentBitWidth == 0)
+ return std::nullopt;
+
+ PrintedBinaryFloat Result;
+ Result.Negative = hasFloatBit(Words, Format->StorageBitWidth - 1U);
+ const std::uint32_t StoredSignificandWidth =
+ Format->HasExplicitIntegerBit ? Format->Precision : Format->Precision - 1U;
+ const std::uint64_t Exponent =
+ extractFloatField(Words, StoredSignificandWidth, Format->ExponentBitWidth);
+ const std::uint64_t MaximumExponent = (std::uint64_t{1} << Format->ExponentBitWidth) - 1U;
+
+ if (Exponent == MaximumExponent) {
+ const std::uint32_t PayloadWidth = Format->Precision - 1U;
+ Result.NaNPayload = extractFloatBits(Words, 0, PayloadWidth);
+ if (Result.NaNPayload.isZero()) {
+ Result.Category = PrintedFloatCategory::Infinity;
+ return Result;
+ }
+ Result.QuietNaNBit = PayloadWidth - 1U;
+ Result.Category = hasFloatBit(Words, Result.QuietNaNBit) ? PrintedFloatCategory::QuietNaN
+ : PrintedFloatCategory::SignalingNaN;
+ return Result;
+ }
+
+ Result.Significand = extractFloatBits(Words, 0, StoredSignificandWidth);
+ if (Exponent != 0 && !Format->HasExplicitIntegerBit)
+ Result.Significand.setBit(Format->Precision - 1U);
+ if (Result.Significand.isZero()) {
+ Result.Category = PrintedFloatCategory::Zero;
+ return Result;
+ }
+
+ const std::int64_t Bias = 1 - static_cast<std::int64_t>(Format->MinExponent);
+ const std::int64_t UnbiasedExponent =
+ Exponent == 0 ? Format->MinExponent : static_cast<std::int64_t>(Exponent) - Bias;
+ Result.BinaryExponent = static_cast<std::int32_t>(UnbiasedExponent - (Format->Precision - 1U));
+ Result.Category = PrintedFloatCategory::Finite;
+ return Result;
+}
+
+[[nodiscard]] std::string printNaNPayload(APInt Payload, std::uint32_t QuietNaNBit) {
+ Payload.clearBit(QuietNaNBit);
+ const auto Width =
+ static_cast<std::uint32_t>(std::max<std::size_t>(Payload.activeBitWidth(), 1U));
+ std::array<std::uint64_t, 2> Words{Payload.word(0), Payload.word(1)};
+ std::string Digits = hexadecimalWords(Words, Width);
+ const std::size_t FirstNonzero = Digits.find_first_not_of('0');
+ if (FirstNonzero == std::string::npos)
+ return "0x0";
+ Digits.erase(0, FirstNonzero);
+ return "0x" + Digits;
+}
+
+[[nodiscard]] std::string formatFiniteFloat(PrintedBinaryFloat Value) {
+ std::string Result;
+ if (Value.Negative)
+ Result.push_back('-');
+ if (Value.Category == PrintedFloatCategory::Zero) {
+ Result.append("0.000000e+00");
+ return Result;
+ }
+
+ const std::size_t TrailingZeros = Value.Significand.countrZero();
+ Value.Significand.shiftRight(TrailingZeros);
+ Value.BinaryExponent += static_cast<std::int32_t>(TrailingZeros);
+
+ std::int32_t DecimalExponent = 0;
+ if (Value.BinaryExponent >= 0) {
+ Value.Significand =
+ Value.Significand.shiftedLeft(static_cast<std::size_t>(Value.BinaryExponent));
+ } else {
+ DecimalExponent = Value.BinaryExponent;
+ for (std::int32_t Power = 0; Power < -Value.BinaryExponent; ++Power)
+ Value.Significand.multiplySmall(5);
+ }
+
+ std::string Digits = Value.Significand.toUnsignedDecimal();
+ while (Digits.size() > 1U && Digits.back() == '0') {
+ Digits.pop_back();
+ ++DecimalExponent;
+ }
+
+ constexpr std::size_t FormatPrecision = 6;
+ if (Digits.size() > FormatPrecision) {
+ std::size_t Removed = Digits.size() - FormatPrecision;
+ const bool RoundUp = Digits[FormatPrecision] >= '5';
+ Digits.resize(FormatPrecision);
+ if (RoundUp) {
+ std::size_t Position = Digits.size();
+ while (Position != 0 && Digits[Position - 1U] == '9') {
+ Digits[Position - 1U] = '0';
+ --Position;
+ }
+ if (Position == 0)
+ Digits.insert(Digits.begin(), '1');
+ else
+ ++Digits[Position - 1U];
+ }
+ while (Digits.size() > 1U && Digits.back() == '0') {
+ Digits.pop_back();
+ ++Removed;
+ }
+ DecimalExponent += static_cast<std::int32_t>(Removed);
+ }
+
+ DecimalExponent += static_cast<std::int32_t>(Digits.size() - 1U);
+ Result.push_back(Digits.front());
+ Result.push_back('.');
+ Result.append(Digits.substr(1));
+ Result.append(7U - Digits.size(), '0');
+ Result.push_back('e');
+ Result.push_back(DecimalExponent < 0 ? '-' : '+');
+ const std::uint32_t Magnitude = static_cast<std::uint32_t>(
+ DecimalExponent < 0 ? -static_cast<std::int64_t>(DecimalExponent) : DecimalExponent);
+ std::string Exponent = std::to_string(Magnitude);
+ if (Exponent.size() < 2U)
+ Result.push_back('0');
+ Result.append(Exponent);
+ return Result;
+}
+
+[[nodiscard]] std::string exactFloatingText(const APFloat &Bits) {
+ return "f0x" + hexadecimalWords(Bits.words(), Bits.bitWidth());
+}
+
+[[nodiscard]] std::string canonicalFloatingText(const APFloat &Bits) {
+ auto Decoded = decodePrintedFloat(Bits);
+ if (!Decoded)
+ return exactFloatingText(Bits);
+
+ std::string Candidate;
+ switch (Decoded->Category) {
+ case PrintedFloatCategory::Zero:
+ case PrintedFloatCategory::Finite:
+ Candidate = formatFiniteFloat(std::move(*Decoded));
+ break;
+ case PrintedFloatCategory::Infinity:
+ Candidate = Decoded->Negative ? "-inf" : "+inf";
+ break;
+ case PrintedFloatCategory::QuietNaN: {
+ APInt Payload = Decoded->NaNPayload;
+ Payload.clearBit(Decoded->QuietNaNBit);
+ if (Payload.isZero()) {
+ Candidate = Decoded->Negative ? "-qnan" : "+qnan";
+ break;
+ }
+ Candidate = Decoded->Negative ? "-nan(" : "+nan(";
+ Candidate.append(printNaNPayload(Decoded->NaNPayload, Decoded->QuietNaNBit));
+ Candidate.push_back(')');
+ break;
+ }
+ case PrintedFloatCategory::SignalingNaN:
+ Candidate = Decoded->Negative ? "-snan(" : "+snan(";
+ Candidate.append(printNaNPayload(Decoded->NaNPayload, Decoded->QuietNaNBit));
+ Candidate.push_back(')');
+ break;
+ }
+
+ auto Parsed = APFloat::parse(Bits.semantics(), Candidate);
+ if (!Parsed || *Parsed != Bits)
+ return exactFloatingText(Bits);
+ return Candidate;
+}
+
+} // namespace
+
+std::optional<std::uint32_t> getFloatSemanticsBitWidth(FloatSemantics Semantics) noexcept {
+ const auto *Info = getFloatSemanticsInfo(Semantics);
+ if (Info == nullptr)
+ return std::nullopt;
+ return Info->BitWidth;
+}
+
+std::string_view getFloatSemanticsSpelling(FloatSemantics Semantics) noexcept {
+ const auto *Info = getFloatSemanticsInfo(Semantics);
+ return Info == nullptr ? std::string_view{"invalid-float"} : Info->Spelling;
+}
+
+Expected<APFloat> APFloat::create(FloatSemantics Semantics, std::span<const std::uint64_t> Words) {
+ const auto BitWidth = getFloatSemanticsBitWidth(Semantics);
+ if (!BitWidth)
+ return makeUnexpected(ErrorCode::InvalidArgument, "floating value has unknown semantics");
+
+ const std::size_t RequiredWords = (*BitWidth + 63U) / 64U;
+ if (RequiredWords > 2 || Words.size() != RequiredWords) {
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "floating bit pattern has the wrong word count");
+ }
+ const std::uint32_t UsedBitsInLastWord = *BitWidth % 64U;
+ if (UsedBitsInLastWord != 0 && (Words.back() >> UsedBitsInLastWord) != 0) {
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "floating value has nonzero bits above its semantics width");
+ }
+
+ std::array<std::uint64_t, 2> StoredWords{};
+ std::ranges::copy(Words, StoredWords.begin());
+ return APFloat(Semantics, StoredWords, static_cast<std::uint8_t>(RequiredWords));
+}
+
+Expected<APFloat> APFloat::parse(FloatSemantics Semantics, std::string_view Text) {
+ const auto Format = binaryFloatFormat(Semantics);
+ if (!Format)
+ return makeUnexpected(ErrorCode::Unsupported, "floating-point semantics are unsupported");
+
+ std::vector<std::uint64_t> Words;
+ auto SpecialLiteral = parseSpecialFloatLiteral(Text);
+ if (!SpecialLiteral)
+ return std::unexpected(SpecialLiteral.error());
+ if (*SpecialLiteral) {
+ auto SpecialWords = makeSpecialFloatWords(Semantics, **SpecialLiteral);
+ if (!SpecialWords)
+ return std::unexpected(SpecialWords.error());
+ Words = std::move(*SpecialWords);
+ } else if (Text.starts_with("f0x")) {
+ const std::uint32_t BitWidth = getFloatSemanticsBitWidth(Semantics).value_or(0);
+ const std::string_view Digits = Text.substr(3);
+ if (Digits.size() != (static_cast<std::size_t>(BitWidth) + 3U) / 4U ||
+ !parseHexWords(Digits, BitWidth, Words)) {
+ return makeUnexpected(ErrorCode::ParseError,
+ "exact floating-point bit pattern does not fit its type");
+ }
+ } else if (Text.starts_with("0x") && Text.find('.') != std::string_view::npos) {
+ auto Literal = parseHexFloatLiteral(Text);
+ if (!Literal)
+ return std::unexpected(Literal.error());
+ auto Converted = convertRationalToFloatWords(Semantics, Literal->Negative, Literal->Numerator,
+ Literal->Denominator, Literal->BinaryScale);
+ if (!Converted)
+ return std::unexpected(Converted.error());
+ Words = std::move(*Converted);
+ } else if (Text.starts_with("0x")) {
+ const std::uint32_t BitWidth = getFloatSemanticsBitWidth(Semantics).value_or(0);
+ std::string_view Digits = Text.substr(2);
+ char Prefix = '\0';
+ if (!Digits.empty() && !isHexDigit(Digits.front())) {
+ Prefix = Digits.front();
+ Digits.remove_prefix(1);
+ }
+ char ExpectedPrefix = '\0';
+ switch (Semantics) {
+ case FloatSemantics::IEEEHalf:
+ ExpectedPrefix = 'H';
+ break;
+ case FloatSemantics::BFloat:
+ ExpectedPrefix = 'R';
+ break;
+ case FloatSemantics::X87DoubleExtended:
+ ExpectedPrefix = 'K';
+ break;
+ case FloatSemantics::IEEEQuad:
+ ExpectedPrefix = 'L';
+ break;
+ case FloatSemantics::PPCDoubleDouble:
+ ExpectedPrefix = 'M';
+ break;
+ default:
+ break;
+ }
+ if (ExpectedPrefix != '\0') {
+ const bool HasWideWords =
+ Semantics == FloatSemantics::IEEEQuad || Semantics == FloatSemantics::PPCDoubleDouble;
+ const bool Parsed = HasWideWords ? parseWideFloatHexWords(Digits, Words)
+ : parseHexWords(Digits, BitWidth, Words);
+ if (Prefix != ExpectedPrefix || !Parsed) {
+ return makeUnexpected(ErrorCode::ParseError,
+ "floating-point hexadecimal prefix does not match its type");
+ }
+ } else if (Prefix != '\0') {
+ return makeUnexpected(ErrorCode::ParseError, "unexpected floating-point hexadecimal prefix");
+ } else {
+ auto DoubleBits = parseRawDoubleBits(Digits);
+ if (!DoubleBits)
+ return std::unexpected(DoubleBits.error());
+ auto Converted = convertRawDoubleLiteral(Semantics, *DoubleBits);
+ if (!Converted)
+ return std::unexpected(Converted.error());
+ Words = std::move(*Converted);
+ }
+ } else {
+ auto Literal = parseDecimalFloatLiteral(Text, *Format);
+ if (!Literal)
+ return std::unexpected(Literal.error());
+ auto Converted = convertRationalToFloatWords(Semantics, Literal->Negative, Literal->Numerator,
+ Literal->Denominator, Literal->BinaryScale);
+ if (!Converted)
+ return std::unexpected(Converted.error());
+ Words = std::move(*Converted);
+ }
+ return create(Semantics, Words);
+}
+
+std::string APFloat::toString() const {
+ return canonicalFloatingText(*this);
+}
+
+} // namespace rcc
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
diff --git a/backend/lib/Support/CMakeLists.txt b/backend/lib/Support/CMakeLists.txt
index c081106..48bcb09 100644
--- a/backend/lib/Support/CMakeLists.txt
+++ b/backend/lib/Support/CMakeLists.txt
@@ -1,8 +1,10 @@
# SPDX-License-Identifier: GPL-3.0-or-later
-set(RCCBackendSupportSources Error.cpp SHA256.cpp TextDiagnostic.cpp YAML.cpp)
+set(RCCBackendSupportSources APFloat.cpp APInt.cpp Error.cpp SHA256.cpp TextDiagnostic.cpp YAML.cpp)
set(
RCCBackendSupportHeaders
+ "${RCC_BACKEND_SOURCE_DIR}/include/rcc/ADT/APFloat.h"
+ "${RCC_BACKEND_SOURCE_DIR}/include/rcc/ADT/APInt.h"
"${RCC_BACKEND_SOURCE_DIR}/include/rcc/Support/Error.h"
"${RCC_BACKEND_SOURCE_DIR}/include/rcc/Support/SHA256.h"
"${RCC_BACKEND_SOURCE_DIR}/include/rcc/Support/TextDiagnostic.h"
@@ -37,6 +39,8 @@ install(
)
rcc_backend_register_format_files(
+ "${CMAKE_CURRENT_SOURCE_DIR}/APFloat.cpp"
+ "${CMAKE_CURRENT_SOURCE_DIR}/APInt.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Error.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/SHA256.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/TextDiagnostic.cpp"
@@ -44,6 +48,8 @@ rcc_backend_register_format_files(
${RCCBackendSupportHeaders}
)
rcc_backend_register_tidy_files(
+ "${CMAKE_CURRENT_SOURCE_DIR}/APFloat.cpp"
+ "${CMAKE_CURRENT_SOURCE_DIR}/APInt.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Error.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/SHA256.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/TextDiagnostic.cpp"
diff --git a/backend/lib/Target/RISCV/GISel/RISCVCallLowering.cpp b/backend/lib/Target/RISCV/GISel/RISCVCallLowering.cpp
index cfe8bb6..71c7251 100644
--- a/backend/lib/Target/RISCV/GISel/RISCVCallLowering.cpp
+++ b/backend/lib/Target/RISCV/GISel/RISCVCallLowering.cpp
@@ -781,7 +781,7 @@ RISCVCallLowering::planReturn(const ReturnLoweringRequest &Request) const {
[[nodiscard]] Expected<void> addUnsignedImmediate(MachineInstrBuilder &Builder,
std::uint64_t Value) {
- auto Immediate = IntegerImmediate::fromUnsigned(64, Value);
+ auto Immediate = APInt::fromUnsigned(64, Value);
if (!Immediate)
return std::unexpected(Immediate.error());
return Builder.addIntegerImmediate(std::move(*Immediate));
diff --git a/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index a2c7194..2090496 100644
--- a/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
+++ b/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
@@ -2512,7 +2512,7 @@ private:
const std::uint32_t BitWidth = Type->scalarBitWidth();
const std::uint64_t Bits = Floating->Bits.words().empty() ? 0 : Floating->Bits.words().front();
- auto Integer = IntegerImmediate::fromUnsigned(64, Bits);
+ auto Integer = APInt::fromUnsigned(64, Bits);
if (!Integer)
return std::unexpected(Integer.error());
auto IntegerType = LLT::makeInteger(64);
diff --git a/backend/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp b/backend/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
index e9d72fd..da8d687 100644
--- a/backend/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
+++ b/backend/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
@@ -99,9 +99,8 @@ namespace {
Destination.scalarBitWidth() <= 64;
}
-[[nodiscard]] Expected<IntegerImmediate> extendIntegerImmediate(const IntegerImmediate &Value,
- std::uint32_t DestinationWidth,
- bool SignExtend) {
+[[nodiscard]] Expected<APInt>
+extendIntegerImmediate(const APInt &Value, std::uint32_t DestinationWidth, bool SignExtend) {
if (DestinationWidth == 0 || DestinationWidth > 64)
return makeUnexpected(ErrorCode::Unsupported,
"RISC-V constant extension requires a destination no wider than 64 bits");
@@ -112,7 +111,7 @@ namespace {
Raw |= ~std::uint64_t{0} << SourceWidth;
if (DestinationWidth < 64)
Raw &= (std::uint64_t{1} << DestinationWidth) - 1U;
- return IntegerImmediate::create(DestinationWidth, std::span<const std::uint64_t>(&Raw, 1));
+ return APInt::create(DestinationWidth, std::span<const std::uint64_t>(&Raw, 1));
}
[[nodiscard]] Expected<void>
@@ -271,9 +270,8 @@ wideConstantUnmergePlan(const MachineInstr &Constant, const MachineFunction &Fun
return Plan;
}
-[[nodiscard]] Expected<IntegerImmediate> wideConstantWord(const IntegerImmediate &Value,
- std::size_t WordIndex,
- std::uint32_t Width, bool SignExtend) {
+[[nodiscard]] Expected<APInt> wideConstantWord(const APInt &Value, std::size_t WordIndex,
+ std::uint32_t Width, bool SignExtend) {
std::uint64_t Raw = 0;
if (WordIndex < Value.words().size())
Raw = Value.words()[WordIndex];
@@ -287,7 +285,7 @@ wideConstantUnmergePlan(const MachineInstr &Constant, const MachineFunction &Fun
}
if (Width < 64)
Raw &= (std::uint64_t{1} << Width) - 1U;
- return IntegerImmediate::create(Width, std::span<const std::uint64_t>(&Raw, 1));
+ return APInt::create(Width, std::span<const std::uint64_t>(&Raw, 1));
}
[[nodiscard]] Expected<void> foldWideConstant(MachineInstr &Instruction, MachineFunction &Function,
@@ -303,7 +301,7 @@ wideConstantUnmergePlan(const MachineInstr &Constant, const MachineFunction &Fun
return makeUnexpected(ErrorCode::VerificationError,
"RISC-V wide constant has no integer immediate");
- std::vector<IntegerImmediate> Words;
+ std::vector<APInt> Words;
Words.reserve(Plan->Outputs.size());
for (std::size_t Index = 0; Index < Plan->Outputs.size(); ++Index) {
const auto Info = Function.registerInfo().virtualRegisterInfo(Plan->Outputs[Index]);
@@ -1240,7 +1238,7 @@ void eraseDeadArtifacts(std::span<MachineInstr *const> Candidates,
auto Result = Builder.function().registerInfo().createVirtualRegister(*Type);
if (!Result)
return std::unexpected(Result.error());
- auto Immediate = IntegerImmediate::fromUnsigned(Width, Value);
+ auto Immediate = APInt::fromUnsigned(Width, Value);
if (!Immediate)
return std::unexpected(Immediate.error());
auto Point = Builder.setInsertPointBefore(Anchor);
diff --git a/backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp b/backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp
index ee41d47..0db51f0 100644
--- a/backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp
+++ b/backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp
@@ -252,7 +252,7 @@ struct TypeLayout final {
return mc::MCOperand::expression(std::move(*TargetExpression));
}
-[[nodiscard]] Expected<std::int64_t> lowerIntegerImmediate(const IntegerImmediate &Value) {
+[[nodiscard]] Expected<std::int64_t> lowerIntegerImmediate(const APInt &Value) {
if (Value.bitWidth() > 64 || Value.words().size() != 1) {
return makeUnexpected(ErrorCode::AssemblyLoweringFailed,
"RISC-V instruction has an integer immediate wider than 64 bits");
@@ -714,14 +714,14 @@ struct TypeLayout final {
}
switch (Initializer.kind()) {
case GlobalInitializer::Kind::Integer: {
- const auto *Value = Initializer.getIf<IntegerImmediate>();
+ const auto *Value = Initializer.getIf<APInt>();
if (Value == nullptr)
return makeUnexpected(ErrorCode::InternalError, "integer initializer has no value");
const std::uint64_t Size = (static_cast<std::uint64_t>(Value->bitWidth()) + 7U) / 8U;
return Streamer.emitBytes(bytesFromWords(Value->words(), Size));
}
case GlobalInitializer::Kind::Floating: {
- const auto *Value = Initializer.getIf<FloatingPointBits>();
+ const auto *Value = Initializer.getIf<APFloat>();
if (Value == nullptr)
return makeUnexpected(ErrorCode::InternalError, "floating initializer has no value");
const std::uint64_t Size = (static_cast<std::uint64_t>(Value->bitWidth()) + 7U) / 8U;
@@ -839,12 +839,12 @@ struct TypeLayout final {
return false;
switch (Initializer.kind()) {
case GlobalInitializer::Kind::Integer: {
- const auto *Value = Initializer.getIf<IntegerImmediate>();
+ const auto *Value = Initializer.getIf<APInt>();
return Value != nullptr &&
std::ranges::all_of(Value->words(), [](std::uint64_t Word) { return Word == 0; });
}
case GlobalInitializer::Kind::Floating: {
- const auto *Value = Initializer.getIf<FloatingPointBits>();
+ const auto *Value = Initializer.getIf<APFloat>();
return Value != nullptr &&
std::ranges::all_of(Value->words(), [](std::uint64_t Word) { return Word == 0; });
}