aboutsummaryrefslogtreecommitdiff
path: root/backend/lib/MIR/MIParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'backend/lib/MIR/MIParser.cpp')
-rw-r--r--backend/lib/MIR/MIParser.cpp425
1 files changed, 209 insertions, 216 deletions
diff --git a/backend/lib/MIR/MIParser.cpp b/backend/lib/MIR/MIParser.cpp
index 483c2f2..01ecbf5 100644
--- a/backend/lib/MIR/MIParser.cpp
+++ b/backend/lib/MIR/MIParser.cpp
@@ -2,6 +2,7 @@
#include "rcc/MIR/MIParser.h"
+#include "rcc/CodeGen/InlineAsm.h"
#include "rcc/CodeGen/InstructionDescriptor.h"
#include "rcc/CodeGen/MachineBasicBlock.h"
#include "rcc/CodeGen/MachineCFGUpdater.h"
@@ -13,6 +14,7 @@
#include "rcc/CodeGen/TargetDescription.h"
#include "rcc/CodeGen/TargetMIRTextInfo.h"
#include "rcc/CodeGen/TargetRegisterInfo.h"
+#include "rcc/MIR/LLVMConstantSyntax.h"
#include "rcc/MIR/MIDebugSyntax.h"
#include "rcc/MIR/MILexer.h"
@@ -113,60 +115,6 @@ namespace {
Token.isKeyword("llvm_vector_register_mask");
}
-[[nodiscard]] std::optional<unsigned> hexDigit(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;
- if (Character >= 'A' && Character <= 'F')
- return static_cast<unsigned>(Character - 'A') + 10U;
- return std::nullopt;
-}
-
-[[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((static_cast<std::size_t>(BitWidth) + 63U) / 64U, 0);
- std::size_t BitOffset = 0;
- for (auto Iterator = Digits.rbegin(); Iterator != Digits.rend(); ++Iterator) {
- const auto Digit = hexDigit(*Iterator);
- if (!Digit)
- return false;
- const std::size_t WordIndex = BitOffset / 64U;
- const unsigned Shift = static_cast<unsigned>(BitOffset % 64U);
- Words[WordIndex] |= static_cast<std::uint64_t>(*Digit) << Shift;
- BitOffset += 4U;
- }
- if (BitWidth % 64U != 0)
- Words.back() &= (std::uint64_t{1} << (BitWidth % 64U)) - 1U;
- return true;
-}
-
-[[nodiscard]] bool isZeroWords(std::span<const std::uint64_t> Words) noexcept {
- return std::ranges::all_of(Words, [](std::uint64_t Word) { return Word == 0; });
-}
-
-[[nodiscard]] bool magnitudeFitsSignedNegative(std::span<const std::uint64_t> Words,
- std::uint32_t BitWidth) noexcept {
- const std::size_t SignWord = (BitWidth - 1U) / 64U;
- const unsigned SignBit = (BitWidth - 1U) % 64U;
- for (std::size_t Index = SignWord + 1U; Index < Words.size(); ++Index) {
- if (Words[Index] != 0)
- return false;
- }
- const std::uint64_t SignMask = std::uint64_t{1} << SignBit;
- if ((Words[SignWord] & ~SignMask) != 0)
- return false;
- if ((Words[SignWord] & SignMask) == 0)
- return true;
- for (std::size_t Index = 0; Index < SignWord; ++Index) {
- if (Words[Index] != 0)
- return false;
- }
- return true;
-}
-
[[nodiscard]] Expected<IntegerImmediate> parseIntegerImmediateValue(std::uint32_t BitWidth,
std::string_view Spelling) {
if (BitWidth == 0 || BitWidth > IntegerImmediate::MaxBitWidth)
@@ -188,17 +136,13 @@ namespace {
Word = static_cast<std::uint64_t>(Product);
Carry = static_cast<std::uint64_t>(Product >> 64U);
}
- if (Carry != 0)
- return makeUnexpected(ErrorCode::ParseError, "typed integer does not fit its bit width");
- if (BitWidth % 64U != 0 && (Words.back() >> (BitWidth % 64U)) != 0) {
- return makeUnexpected(ErrorCode::ParseError, "typed integer does not fit its bit width");
- }
}
+ // LLVM parses the arbitrary-precision literal first and then truncates it to
+ // the declared integer width. Keep exactly that modulo-2^N bit pattern.
+ if (BitWidth % 64U != 0)
+ Words.back() &= (std::uint64_t{1} << (BitWidth % 64U)) - 1U;
if (Negative) {
- if (isZeroWords(Words) || !magnitudeFitsSignedNegative(Words, BitWidth))
- return makeUnexpected(ErrorCode::ParseError,
- "negative typed integer does not fit its bit width");
for (std::uint64_t &Word : Words)
Word = ~Word;
std::uint64_t Carry = 1;
@@ -213,51 +157,6 @@ namespace {
return IntegerImmediate::create(BitWidth, Words);
}
-[[nodiscard]] std::uint16_t floatToHalfBits(float Value) noexcept {
- const std::uint32_t Bits = std::bit_cast<std::uint32_t>(Value);
- const std::uint32_t Sign = (Bits >> 16U) & 0x8000U;
- const std::uint32_t Exponent = (Bits >> 23U) & 0xFFU;
- const std::uint32_t Fraction = Bits & 0x7FFFFFU;
- if (Exponent == 0xFFU) {
- const std::uint32_t Payload = Fraction == 0 ? 0 : std::max(1U, Fraction >> 13U);
- return static_cast<std::uint16_t>(Sign | 0x7C00U | Payload);
- }
-
- const int HalfExponent = static_cast<int>(Exponent) - 127 + 15;
- if (HalfExponent >= 31)
- return static_cast<std::uint16_t>(Sign | 0x7C00U);
- if (HalfExponent <= 0) {
- if (HalfExponent < -10)
- return static_cast<std::uint16_t>(Sign);
- const std::uint32_t Mantissa = Fraction | 0x800000U;
- const unsigned Shift = static_cast<unsigned>(14 - HalfExponent);
- std::uint32_t Rounded = Mantissa >> Shift;
- const std::uint32_t Remainder = Mantissa & ((std::uint32_t{1} << Shift) - 1U);
- const std::uint32_t Halfway = std::uint32_t{1} << (Shift - 1U);
- if (Remainder > Halfway || (Remainder == Halfway && (Rounded & 1U) != 0))
- ++Rounded;
- return static_cast<std::uint16_t>(Sign | Rounded);
- }
-
- std::uint32_t Rounded = Fraction >> 13U;
- const std::uint32_t Remainder = Fraction & 0x1FFFU;
- if (Remainder > 0x1000U || (Remainder == 0x1000U && (Rounded & 1U) != 0)) {
- ++Rounded;
- if (Rounded == 0x400U)
- return static_cast<std::uint16_t>(Sign |
- (static_cast<std::uint32_t>(HalfExponent + 1) << 10U));
- }
- return static_cast<std::uint16_t>(Sign | (static_cast<std::uint32_t>(HalfExponent) << 10U) |
- Rounded);
-}
-
-[[nodiscard]] std::uint16_t floatToBFloatBits(float Value) noexcept {
- std::uint32_t Bits = std::bit_cast<std::uint32_t>(Value);
- const std::uint32_t Bias = 0x7FFFU + ((Bits >> 16U) & 1U);
- Bits += Bias;
- return static_cast<std::uint16_t>(Bits >> 16U);
-}
-
[[nodiscard]] std::optional<std::uint64_t> minimumTypeSizeInBits(LLT Type) noexcept {
if (!Type.isValid() || Type.isToken())
return std::nullopt;
@@ -493,6 +392,8 @@ private:
[[nodiscard]] bool parseRegisterOperand(bool IsDef, ParsedOperand &Result);
[[nodiscard]] bool parseTargetFlags(std::uint32_t &Flags);
[[nodiscard]] bool parseOperand(bool IsDef, ParsedOperand &Result);
+ [[nodiscard]] bool parseInlineAsmExtraInfoOperand(ParsedOperand &Result);
+ [[nodiscard]] bool parseInlineAsmOperandFlag(ParsedOperand &Result);
[[nodiscard]] bool parseTypedIntegerOperand(ParsedOperand &Result);
[[nodiscard]] bool parseFloatingImmediateOperand(ParsedOperand &Result);
[[nodiscard]] bool parseMetadataReference(MachineMetadataReference &Result);
@@ -684,7 +585,8 @@ bool MIParser::Impl::parseScalarLowLevelType(const MIToken &TypeToken, LLT &Resu
std::uint64_t Value = 0;
if (!parseUnsignedDigits(Digits, Value))
- return fail(TypeToken, "low-level type suffix must be an unsigned decimal integer");
+ return fail(TypeToken,
+ "expected integers after 's'/'i'/'f'/'bf'/'p' type identifier");
Expected<LLT> Created = makeUnexpected(ErrorCode::ParseError, "invalid low-level type");
switch (Kind) {
@@ -739,40 +641,67 @@ bool MIParser::Impl::parseScalarLowLevelType(const MIToken &TypeToken, LLT &Resu
bool MIParser::Impl::parseLowLevelType(LLT &Result) {
const MIToken Begin = token();
+ const auto HasScalarPrefix = [](std::string_view Spelling) {
+ return Spelling.starts_with('s') || Spelling.starts_with('i') ||
+ Spelling.starts_with('f') || Spelling.starts_with("bf") ||
+ Spelling.starts_with('p');
+ };
if (at(MITokenKind::Identifier)) {
+ if (!HasScalarPrefix(token().stringValue())) {
+ return fail(Begin,
+ "expected tN, pA, <M x tN>, <M x pA>, <vscale x M x tN>, or "
+ "<vscale x M x pA> for GlobalISel type, where t = {'s', 'i', 'f', 'bf'}");
+ }
if (parseScalarLowLevelType(token(), Result))
return true;
advance();
return false;
}
- if (!consume(MITokenKind::Less))
- return fail(Begin, "expected a scalar, pointer, or vector low-level type");
+ if (!consume(MITokenKind::Less)) {
+ return fail(Begin,
+ "expected tN, pA, <M x tN>, <M x pA>, <vscale x M x tN>, or "
+ "<vscale x M x pA> for GlobalISel type, where t = {'s', 'i', 'f', 'bf'}");
+ }
bool Scalable = false;
if (at(MITokenKind::Identifier) && token().stringValue() == "vscale") {
Scalable = true;
advance();
- if (!at(MITokenKind::Identifier) || token().stringValue() != "x")
- return fail("expected 'x' after 'vscale' in a scalable vector type");
+ if (!at(MITokenKind::Identifier) || token().stringValue() != "x") {
+ return fail(
+ "expected <vscale x M x tN>, where t = {'s', 'i', 'f', 'bf', 'p'}");
+ }
advance();
}
+ const auto VectorError = [this, &Begin, Scalable] {
+ if (Scalable) {
+ return fail(Begin,
+ "expected <vscale x M x tN> for vector type, where t = "
+ "{'s', 'i', 'f', 'bf', 'p'}");
+ }
+ return fail(Begin,
+ "expected <M x tN> for vector type, where t = {'s', 'i', 'f', 'bf', 'p'}");
+ };
+
std::uint64_t ElementCount = 0;
if (!at(MITokenKind::IntegerLiteral) || parseUnsigned(token(), ElementCount))
- return fail("expected an unsigned vector element count");
+ return VectorError();
advance();
if (!at(MITokenKind::Identifier) || token().stringValue() != "x")
- return fail("expected 'x' after the vector element count");
+ return VectorError();
advance();
+ if (!at(MITokenKind::Identifier) || !HasScalarPrefix(token().stringValue()))
+ return VectorError();
LLT ElementType;
if (parseScalarLowLevelType(token(), ElementType))
return true;
if (ElementType.isToken())
return fail("token cannot be a vector element type");
advance();
- if (expect(MITokenKind::Greater, "'>' after the vector low-level type"))
- return true;
+ if (!consume(MITokenKind::Greater))
+ return VectorError();
Expected<LLT> Created = Scalable ? LLT::makeScalableVector(ElementCount, ElementType)
: LLT::makeFixedVector(ElementCount, ElementType);
@@ -821,6 +750,8 @@ bool MIParser::Impl::parseBlockAttributes(MachineBasicBlock *Block) {
} else if (at(MITokenKind::IRBlock) || at(MITokenKind::NamedIRBlock)) {
if (!Seen.insert("ir-block").second)
return fail("duplicate IR block attribute");
+ if (Context.HasIRBlock && !Context.HasIRBlock(symbolName(token())))
+ return fail(token(), "use of undefined IR block '" + std::string(token().spelling()) + "'");
if (Block != nullptr) {
auto SetName = Block->attributes().setIRBlockName(symbolName(token()));
if (!SetName)
@@ -915,7 +846,14 @@ bool MIParser::Impl::parseBlockDefinition(bool Create, std::uint32_t &ID) {
if (Blocks.size() >= Options.MaximumBlocks)
return fail(Label, "machine basic block count exceeds parser limit");
if (Blocks.contains(ID))
- return fail(Label, "redefinition of machine basic block #" + std::to_string(ID));
+ return fail(Label,
+ "redefinition of machine basic block with id #" + std::to_string(ID));
+ if (!Label.stringValue().empty() && Context.HasIRBlock &&
+ !Context.HasIRBlock(Label.stringValue())) {
+ return fail(Label, "basic block '" + std::string(Label.stringValue()) +
+ "' is not defined in the function '" +
+ std::string(Function.name()) + "'");
+ }
auto Created = Function.createBasicBlock();
if (!Created)
return importError(Label, Created.error());
@@ -1000,6 +938,12 @@ Register MIParser::Impl::getOrCreateVirtualRegister(const MIToken &Token) {
static_cast<void>(importError(Token, Created.error()));
return {};
}
+ auto Info = Function.registerInfo().virtualRegisterInfo(*Created);
+ if (!Info) {
+ static_cast<void>(importError(Token, Info.error()));
+ return {};
+ }
+ Info->get().Name = Name;
NamedVirtualRegisters.emplace(Name, *Created);
return *Created;
}
@@ -1345,96 +1289,22 @@ bool MIParser::Impl::parseFloatingImmediateOperand(ParsedOperand &Result) {
const auto Semantics = floatSemanticsForKeyword(Begin.stringValue());
if (!Semantics)
return fail(Begin, "unknown floating-point immediate type");
- const std::uint32_t BitWidth = getFloatSemanticsBitWidth(*Semantics).value_or(0);
advance();
if (!at(MITokenKind::FloatingPointLiteral) && !at(MITokenKind::HexLiteral))
return fail("expected a floating-point literal");
const MIToken Literal = token();
- const std::string_view Spelling = Literal.spelling();
- std::vector<std::uint64_t> Words;
- if (Spelling.starts_with("f0x") || Spelling.starts_with("f0X")) {
- if (!parseHexWords(Spelling.substr(3), BitWidth, Words))
- return fail(Literal, "raw floating-point literal does not fit its semantics");
- } else if (Spelling.starts_with("0x") || Spelling.starts_with("0X")) {
- std::string_view Digits = Spelling.substr(2);
- char Prefix = '\0';
- if (!Digits.empty() && !hexDigit(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:
- case FloatSemantics::PPCDoubleDoubleLegacy:
- ExpectedPrefix = 'M';
- break;
- default:
- break;
- }
- if (ExpectedPrefix != '\0') {
- if (Prefix != ExpectedPrefix || !parseHexWords(Digits, BitWidth, Words))
- return fail(Literal, "floating-point hexadecimal prefix does not match its semantics");
- } else if (Prefix != '\0') {
- return fail(Literal, "unexpected floating-point hexadecimal prefix");
- } else if (*Semantics == FloatSemantics::IEEESingle) {
- std::uint64_t DoubleBits = 0;
- if (!parseHexadecimal(Spelling, DoubleBits))
- return fail(Literal, "invalid IEEE single hexadecimal literal");
- const float Value = static_cast<float>(std::bit_cast<double>(DoubleBits));
- Words = {std::bit_cast<std::uint32_t>(Value)};
- } else if (*Semantics == FloatSemantics::IEEEDouble) {
- std::uint64_t DoubleBits = 0;
- if (!parseHexadecimal(Spelling, DoubleBits))
- return fail(Literal, "invalid IEEE double hexadecimal literal");
- Words = {DoubleBits};
- } else {
- return fail(Literal, "floating-point literal requires its semantics prefix");
- }
- } else {
- const char *First = Spelling.data();
- const char *Last = First + Spelling.size();
- if (*Semantics == FloatSemantics::IEEEDouble) {
- double Value = 0;
- const auto Parsed = std::from_chars(First, Last, Value, std::chars_format::general);
- if (Parsed.ec != std::errc{} || Parsed.ptr != Last)
- return fail(Literal, "invalid IEEE double decimal literal");
- Words = {std::bit_cast<std::uint64_t>(Value)};
- } else if (*Semantics == FloatSemantics::IEEESingle || *Semantics == FloatSemantics::IEEEHalf ||
- *Semantics == FloatSemantics::BFloat) {
- float Value = 0;
- const auto Parsed = std::from_chars(First, Last, Value, std::chars_format::general);
- if (Parsed.ec != std::errc{} || Parsed.ptr != Last)
- return fail(Literal, "invalid floating-point decimal literal");
- if (*Semantics == FloatSemantics::IEEESingle)
- Words = {std::bit_cast<std::uint32_t>(Value)};
- else if (*Semantics == FloatSemantics::IEEEHalf)
- Words = {floatToHalfBits(Value)};
- else
- Words = {floatToBFloatBits(Value)};
- } else {
- return fail(Literal, "this floating-point semantics requires an exact hexadecimal literal");
- }
- }
-
- auto Bits = FloatingPointBits::create(*Semantics, Words);
- if (!Bits)
- return importError(Literal, Bits.error());
+ std::string ConstantText(Begin.stringValue());
+ ConstantText.push_back(' ');
+ ConstantText.append(Literal.spelling());
+ auto Constant = parseLLVMConstant(ConstantText);
+ if (!Constant)
+ return fail(Literal, std::string(Constant.error().message()));
+ if (!Constant->FloatingValue || Constant->FloatingValue->semantics() != *Semantics)
+ return fail(Literal, "floating-point literal produced the wrong semantics");
advance();
Result = ParsedOperand{
- MachineOperand::floatingImmediate(*Bits),
+ MachineOperand::floatingImmediate(*Constant->FloatingValue),
std::nullopt,
{Begin.range().Begin, token().range().Begin},
};
@@ -1485,10 +1355,10 @@ bool MIParser::Impl::parseMetadataOperand(ParsedOperand &Result) {
while (!at(MITokenKind::RightParen)) {
if (at(MITokenKind::Identifier)) {
const auto Opcode = parseDIExpressionOpcodeName(token().stringValue());
- if (!Opcode)
- return fail("unknown debug expression opcode '" + std::string(token().stringValue()) +
- "'");
- Elements.push_back(*Opcode);
+ const auto Encoding = parseDIExpressionAttributeEncodingName(token().stringValue());
+ if (!Opcode && !Encoding)
+ return fail(invalidDIExpressionElementMessage(token().stringValue()));
+ Elements.push_back(Opcode ? *Opcode : *Encoding);
advance();
} else if (at(MITokenKind::IntegerLiteral)) {
std::int64_t Signed = 0;
@@ -1855,10 +1725,22 @@ bool MIParser::Impl::parseMemoryBase(MemoryBase &Result, std::int64_t &Offset) {
break;
case MITokenKind::IRValue:
case MITokenKind::NamedIRValue:
- case MITokenKind::QuotedIRValue:
Result = MemoryBase::irValue(symbolName(BaseToken));
advance();
break;
+ case MITokenKind::QuotedIRValue: {
+ LLVMConstantSyntaxOptions ConstantOptions;
+ ConstantOptions.DefaultPointerSizeInBits = Context.DefaultPointerSizeInBits;
+ auto Constant = parseLLVMConstant(BaseToken.stringValue(), ConstantOptions);
+ if (!Constant)
+ return importError(BaseToken, Constant.error());
+ auto Base = MemoryBase::irConstant(std::move(*Constant));
+ if (!Base)
+ return importError(BaseToken, Base.error());
+ Result = std::move(*Base);
+ advance();
+ break;
+ }
case MITokenKind::Keyword:
if (BaseToken.isKeyword("unknown-address")) {
Result = MemoryBase();
@@ -2021,6 +1903,7 @@ bool MIParser::Impl::parseMemoryOperand(const MachineMemOperand *&Result) {
if (!Size)
return importError(Begin, Size.error());
Description.Size = *Size;
+ Description.MemoryType = Type;
} else {
return fail("expected a memory size, unknown-size, or memory low-level type");
}
@@ -2044,21 +1927,27 @@ bool MIParser::Impl::parseMemoryOperand(const MachineMemOperand *&Result) {
advance();
if (parseMemoryBase(Description.Base, Description.Offset))
return true;
+ if (const GenericConstantData *Constant = Description.Base.constantValue())
+ Description.AddressSpace = Constant->Type.AddressSpace;
}
+ Alignment BaseAlignment = Description.Align;
std::unordered_set<std::string> SeenOptions;
while (consume(MITokenKind::Comma)) {
const std::string Name(token().spelling());
if (!SeenOptions.insert(Name).second)
return fail("duplicate machine memory operand option '" + Name + "'");
if (atKeyword("align")) {
- if (parseAlignment(Description.Align))
+ Alignment ParsedAlignment;
+ if (parseAlignment(ParsedAlignment))
return true;
+ if ((static_cast<std::uint64_t>(Description.Offset) & (ParsedAlignment.bytes() - 1U)) != 0) {
+ return fail("specified alignment is more aligned than offset");
+ }
+ BaseAlignment = ParsedAlignment;
} else if (atKeyword("basealign")) {
- Alignment BaseAlignment;
if (parseAlignment(BaseAlignment))
return true;
- Description.BaseAlign = BaseAlignment;
} else if (atKeyword("addrspace")) {
advance();
if (!at(MITokenKind::IntegerLiteral) || parseUnsigned32(token(), Description.AddressSpace) ||
@@ -2088,6 +1977,19 @@ bool MIParser::Impl::parseMemoryOperand(const MachineMemOperand *&Result) {
return fail("unknown machine memory operand option '" + Name + "'");
}
}
+
+ std::uint64_t EffectiveAlignment = BaseAlignment.bytes();
+ if (Description.Offset != 0) {
+ const auto OffsetBits = static_cast<std::uint64_t>(Description.Offset);
+ const std::uint64_t OffsetAlignment = std::uint64_t{1} << std::countr_zero(OffsetBits);
+ EffectiveAlignment = std::min(EffectiveAlignment, OffsetAlignment);
+ }
+ Description.Align = *Alignment::create(EffectiveAlignment);
+ if (BaseAlignment != Description.Align)
+ Description.BaseAlign = BaseAlignment;
+ else
+ Description.BaseAlign.reset();
+
if (expect(MITokenKind::RightParen, "')' after the machine memory operand"))
return true;
@@ -2527,6 +2429,78 @@ bool MIParser::Impl::parseOperand(bool IsDef, ParsedOperand &Result) {
return false;
}
+bool MIParser::Impl::parseInlineAsmExtraInfoOperand(ParsedOperand &Result) {
+ const MIToken Begin = token();
+ InlineAsmExtraInfo ExtraInfo;
+ while (at(MITokenKind::Identifier)) {
+ const auto Bits = InlineAsmExtraInfo::namedFlagBits(token().stringValue());
+ if (!Bits) {
+ return fail("unknown inline asm extra info flag '" + std::string(token().stringValue()) +
+ "'");
+ }
+ ExtraInfo = InlineAsmExtraInfo(ExtraInfo.rawValue() | *Bits);
+ advance();
+ }
+ Result = ParsedOperand{
+ MachineOperand::immediate(static_cast<std::int64_t>(ExtraInfo.rawValue())),
+ std::nullopt,
+ {Begin.range().Begin, token().range().Begin},
+ };
+ return false;
+}
+
+bool MIParser::Impl::parseInlineAsmOperandFlag(ParsedOperand &Result) {
+ const MIToken Begin = token();
+ const std::string KindName(token().stringValue());
+ const auto Kind = InlineAsmOperandFlag::kindForName(KindName);
+ if (!Kind)
+ return fail("unknown inline asm operand kind '" + KindName + "'");
+ advance();
+
+ InlineAsmOperandFlag Flag(*Kind);
+ if (at(MITokenKind::Identifier) && token().stringValue() == "tiedto") {
+ advance();
+ if (!consume(MITokenKind::Colon))
+ return fail("expected ':' after 'tiedto'");
+ if (!at(MITokenKind::NamedRegister))
+ return fail("expected '$N' operand number after 'tiedto:'");
+ std::uint64_t OperandNumber = 0;
+ if (!parseUnsignedDecimal(token().stringValue(), OperandNumber) ||
+ OperandNumber > std::numeric_limits<std::uint32_t>::max() ||
+ !Flag.setMatchingOperand(static_cast<std::uint32_t>(OperandNumber))) {
+ return fail("invalid operand number in tiedto constraint");
+ }
+ advance();
+ } else if (consume(MITokenKind::Colon)) {
+ if (!at(MITokenKind::Identifier))
+ return fail("expected register class or memory constraint name after ':'");
+ const std::string Constraint(token().stringValue());
+ if (*Kind == InlineAsmOperandKind::Memory) {
+ const auto MemoryConstraint = InlineAsmOperandFlag::memoryConstraintForName(Constraint);
+ if (!MemoryConstraint)
+ return fail("unknown memory constraint '" + Constraint + "'");
+ if (!Flag.setMemoryConstraint(*MemoryConstraint))
+ return fail("invalid memory constraint encoding");
+ } else if (*Kind == InlineAsmOperandKind::RegisterDef ||
+ *Kind == InlineAsmOperandKind::RegisterUse ||
+ *Kind == InlineAsmOperandKind::RegisterDefEarlyClobber) {
+ const RegisterClassDesc *RegisterClass = Target.registers().registerClass(Constraint);
+ if (RegisterClass == nullptr)
+ return fail("unknown register class '" + Constraint + "'");
+ if (!Flag.setRegisterClass(RegisterClass->ID.value()))
+ return fail("register class cannot be encoded in an inline asm operand flag");
+ }
+ advance();
+ }
+
+ Result = ParsedOperand{
+ MachineOperand::immediate(static_cast<std::int64_t>(Flag.rawValue())),
+ std::nullopt,
+ {Begin.range().Begin, token().range().Begin},
+ };
+ return false;
+}
+
bool MIParser::Impl::parseBlockLiveIns(MachineBasicBlock &Block) {
advance();
if (expect(MITokenKind::Colon, "':' after liveins"))
@@ -2566,7 +2540,7 @@ bool MIParser::Impl::parseBlockSuccessors(MachineBasicBlock &Block) {
return false;
do {
if (!at(MITokenKind::MachineBasicBlock))
- return fail("expected a machine basic block successor");
+ return fail("expected a machine basic block reference");
MachineBasicBlock *Successor = blockFor(token());
if (Successor == nullptr)
return true;
@@ -2575,7 +2549,7 @@ bool MIParser::Impl::parseBlockSuccessors(MachineBasicBlock &Block) {
if (consume(MITokenKind::LeftParen)) {
std::uint32_t Weight = 0;
if (parseUnsigned32(token(), Weight))
- return fail("invalid successor probability weight");
+ return fail("expected unsigned integer");
Probability = BranchProbability::fromRaw(Weight);
advance();
if (expect(MITokenKind::RightParen, "')' after successor weight"))
@@ -2623,6 +2597,7 @@ bool MIParser::Impl::parseInstruction(MachineBasicBlock &Block, bool InBundle,
if (Descriptor == nullptr)
return fail("unknown machine instruction '" + std::string(OpcodeToken.stringValue()) + "'");
advance();
+ const bool IsInlineAsm = Descriptor->Name == "INLINEASM" || Descriptor->Name == "INLINEASM_BR";
while (!token().isNewlineOrEnd() && !at(MITokenKind::DoubleColon) &&
!at(MITokenKind::LeftBrace) && !atKeyword("debug-instr-number") &&
@@ -2633,7 +2608,16 @@ bool MIParser::Impl::parseInstruction(MachineBasicBlock &Block, bool InBundle,
if (Operands.size() >= Options.MaximumOperandsPerInstruction)
return fail("instruction operand count exceeds parser limit");
ParsedOperand Operand{MachineOperand::immediate(0), std::nullopt, {}};
- if (parseOperand(false, Operand))
+ const bool IsInlineAsmExtraInfo =
+ IsInlineAsm && Operands.size() == InlineAsmExtraInfoOperandIndex &&
+ at(MITokenKind::Identifier);
+ const bool IsInlineAsmOperandFlag =
+ IsInlineAsm && Operands.size() >= InlineAsmFirstConstraintOperandIndex &&
+ at(MITokenKind::Identifier);
+ if (IsInlineAsmExtraInfo
+ ? parseInlineAsmExtraInfoOperand(Operand)
+ : (IsInlineAsmOperandFlag ? parseInlineAsmOperandFlag(Operand)
+ : parseOperand(false, Operand)))
return true;
Operands.push_back(std::move(Operand));
if (token().isNewlineOrEnd() || at(MITokenKind::DoubleColon) || at(MITokenKind::LeftBrace) ||
@@ -2885,6 +2869,7 @@ bool MIParser::Impl::inferSuccessors() {
continue;
bool BlocksFallthrough = true;
+ std::vector<MachineBasicBlock *> Successors;
for (MachineInstr *Instruction = Block->firstInstruction(); Instruction != nullptr;
Instruction = Instruction->next()) {
const InstructionDescriptor *Descriptor =
@@ -2894,17 +2879,25 @@ bool MIParser::Impl::inferSuccessors() {
if (Descriptor->Flags.has(InstructionFlag::Branch)) {
for (const MachineOperand &Operand : Instruction->operands()) {
if (const BasicBlockOperand *TargetBlock = Operand.getIf<BasicBlockOperand>()) {
- auto Added = Function.cfgUpdater().addSuccessor(*Block, *TargetBlock->Block);
- if (!Added)
- return importError(token(), Added.error());
+ if (std::ranges::find(Successors, TargetBlock->Block) == Successors.end())
+ Successors.push_back(TargetBlock->Block);
}
}
}
if (Descriptor->Flags.has(InstructionFlag::Barrier))
BlocksFallthrough = false;
}
- if (BlocksFallthrough && Block->next() != nullptr) {
- auto Added = Function.cfgUpdater().addSuccessor(*Block, *Block->next());
+ if (BlocksFallthrough && Block->next() != nullptr &&
+ std::ranges::find(Successors, Block->next()) == Successors.end())
+ Successors.push_back(Block->next());
+ if (Successors.empty())
+ continue;
+ const auto Probability =
+ BranchProbability::fromFraction(1U, static_cast<std::uint32_t>(Successors.size()));
+ if (!Probability)
+ return importError(token(), Probability.error());
+ for (MachineBasicBlock *Successor : Successors) {
+ auto Added = Function.cfgUpdater().addSuccessor(*Block, *Successor, *Probability);
if (!Added)
return importError(token(), Added.error());
}