aboutsummaryrefslogtreecommitdiff
path: root/backend/lib/MIR
diff options
context:
space:
mode:
Diffstat (limited to 'backend/lib/MIR')
-rw-r--r--backend/lib/MIR/CMakeLists.txt71
-rw-r--r--backend/lib/MIR/MIDebugSyntax.cpp264
-rw-r--r--backend/lib/MIR/MILexer.cpp964
-rw-r--r--backend/lib/MIR/MIParser.cpp2967
-rw-r--r--backend/lib/MIR/MIPrinter.cpp1694
-rw-r--r--backend/lib/MIR/MIRDataParser.cpp287
-rw-r--r--backend/lib/MIR/MIRDocument.cpp29
-rw-r--r--backend/lib/MIR/MIRDocumentParser.cpp398
-rw-r--r--backend/lib/MIR/MIRDocumentParser.h132
-rw-r--r--backend/lib/MIR/MIRDocumentPrinter.cpp1499
-rw-r--r--backend/lib/MIR/MIRDocumentReferenceValidation.cpp426
-rw-r--r--backend/lib/MIR/MIRDocumentReferenceValidation.h25
-rw-r--r--backend/lib/MIR/MIRFrameParser.cpp467
-rw-r--r--backend/lib/MIR/MIRFunctionParser.cpp552
-rw-r--r--backend/lib/MIR/MIRFunctionRecordsParser.cpp341
-rw-r--r--backend/lib/MIR/MIRMetadataParser.cpp333
-rw-r--r--backend/lib/MIR/MIRMetadataTextParser.cpp259
-rw-r--r--backend/lib/MIR/MIRMetadataTextParser.h74
-rw-r--r--backend/lib/MIR/MIRParserUtilities.h85
19 files changed, 20 insertions, 10847 deletions
diff --git a/backend/lib/MIR/CMakeLists.txt b/backend/lib/MIR/CMakeLists.txt
index f227390..cf5dbcd 100644
--- a/backend/lib/MIR/CMakeLists.txt
+++ b/backend/lib/MIR/CMakeLists.txt
@@ -4,30 +4,20 @@ set(
RCCBackendMIRSources
EmbeddedIR.cpp
LLVMConstantSyntax.cpp
- MIDebugSyntax.cpp
- MILexer.cpp
- MIRDataParser.cpp
- MIRDocument.cpp
- MIRDocumentParser.cpp
- MIRDocumentReferenceValidation.cpp
- MIRDocumentPrinter.cpp
- MIRFrameParser.cpp
- MIRFunctionParser.cpp
- MIRFunctionRecordsParser.cpp
- MIRMetadataParser.cpp
- MIRMetadataTextParser.cpp
- MIParser.cpp
- MIPrinter.cpp
+ "${RCC_BACKEND_SOURCE_DIR}/lib/CodeGen/MIRParser/MILexer.cpp"
+ "${RCC_BACKEND_SOURCE_DIR}/lib/CodeGen/MIRParser/MIParser.cpp"
+ "${RCC_BACKEND_SOURCE_DIR}/lib/CodeGen/MIRParser/MIRParser.cpp"
+ "${RCC_BACKEND_SOURCE_DIR}/lib/CodeGen/MIRPrinter.cpp"
+ "${RCC_BACKEND_SOURCE_DIR}/lib/CodeGen/MIRYamlMapping.cpp"
)
set(
RCCBackendMIRHeaders
+ "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MIRParser/MIParser.h"
+ "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MIRParser/MIRParser.h"
+ "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MIRPrinter.h"
+ "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MIRYamlMapping.h"
"${RCC_BACKEND_SOURCE_DIR}/include/rcc/MIR/EmbeddedIR.h"
"${RCC_BACKEND_SOURCE_DIR}/include/rcc/MIR/LLVMConstantSyntax.h"
- "${RCC_BACKEND_SOURCE_DIR}/include/rcc/MIR/MIDebugSyntax.h"
- "${RCC_BACKEND_SOURCE_DIR}/include/rcc/MIR/MILexer.h"
- "${RCC_BACKEND_SOURCE_DIR}/include/rcc/MIR/MIRDocument.h"
- "${RCC_BACKEND_SOURCE_DIR}/include/rcc/MIR/MIParser.h"
- "${RCC_BACKEND_SOURCE_DIR}/include/rcc/MIR/MIPrinter.h"
)
add_library(RCCBackendMIR ${RCCBackendMIRSources})
@@ -61,41 +51,20 @@ install(
rcc_backend_register_format_files(
"${CMAKE_CURRENT_SOURCE_DIR}/EmbeddedIR.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/LLVMConstantSyntax.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIDebugSyntax.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/MILexer.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIRDataParser.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIRDocument.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIRDocumentParser.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIRDocumentParser.h"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIRDocumentReferenceValidation.h"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIRDocumentReferenceValidation.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIRDocumentPrinter.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIRFrameParser.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIRFunctionParser.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIRFunctionRecordsParser.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIRMetadataParser.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIRMetadataTextParser.h"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIRMetadataTextParser.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIRParserUtilities.h"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIParser.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIPrinter.cpp"
+ "${RCC_BACKEND_SOURCE_DIR}/lib/CodeGen/MIRParser/MILexer.cpp"
+ "${RCC_BACKEND_SOURCE_DIR}/lib/CodeGen/MIRParser/MILexer.h"
+ "${RCC_BACKEND_SOURCE_DIR}/lib/CodeGen/MIRParser/MIParser.cpp"
+ "${RCC_BACKEND_SOURCE_DIR}/lib/CodeGen/MIRParser/MIRParser.cpp"
+ "${RCC_BACKEND_SOURCE_DIR}/lib/CodeGen/MIRPrinter.cpp"
+ "${RCC_BACKEND_SOURCE_DIR}/lib/CodeGen/MIRYamlMapping.cpp"
${RCCBackendMIRHeaders}
)
rcc_backend_register_tidy_files(
"${CMAKE_CURRENT_SOURCE_DIR}/EmbeddedIR.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/LLVMConstantSyntax.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIDebugSyntax.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/MILexer.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIRDataParser.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIRDocument.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIRDocumentParser.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIRDocumentReferenceValidation.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIRDocumentPrinter.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIRFrameParser.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIRFunctionParser.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIRFunctionRecordsParser.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIRMetadataParser.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIRMetadataTextParser.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIParser.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/MIPrinter.cpp"
+ "${RCC_BACKEND_SOURCE_DIR}/lib/CodeGen/MIRParser/MILexer.cpp"
+ "${RCC_BACKEND_SOURCE_DIR}/lib/CodeGen/MIRParser/MIParser.cpp"
+ "${RCC_BACKEND_SOURCE_DIR}/lib/CodeGen/MIRParser/MIRParser.cpp"
+ "${RCC_BACKEND_SOURCE_DIR}/lib/CodeGen/MIRPrinter.cpp"
+ "${RCC_BACKEND_SOURCE_DIR}/lib/CodeGen/MIRYamlMapping.cpp"
)
diff --git a/backend/lib/MIR/MIDebugSyntax.cpp b/backend/lib/MIR/MIDebugSyntax.cpp
deleted file mode 100644
index e614a21..0000000
--- a/backend/lib/MIR/MIDebugSyntax.cpp
+++ /dev/null
@@ -1,264 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include "rcc/MIR/MIDebugSyntax.h"
-
-#include <array>
-#include <charconv>
-#include <cstdint>
-#include <optional>
-#include <ranges>
-#include <span>
-#include <string>
-#include <string_view>
-#include <system_error>
-#include <utility>
-
-namespace rcc::mir {
-namespace {
-
-[[nodiscard]] bool parseIndex(std::string_view Text, std::uint64_t &Value) noexcept {
- if (Text.empty())
- return false;
- const auto [End, Error] = std::from_chars(Text.data(), Text.data() + Text.size(), Value, 10);
- return Error == std::errc{} && End == Text.data() + Text.size();
-}
-
-[[nodiscard]] const auto &namedOpcodes() {
- static constexpr auto Opcodes = std::to_array<std::pair<std::string_view, std::uint64_t>>({
- {"DW_OP_addr", 0x03},
- {"DW_OP_deref", 0x06},
- {"DW_OP_const1u", 0x08},
- {"DW_OP_const1s", 0x09},
- {"DW_OP_const2u", 0x0A},
- {"DW_OP_const2s", 0x0B},
- {"DW_OP_const4u", 0x0C},
- {"DW_OP_const4s", 0x0D},
- {"DW_OP_const8u", 0x0E},
- {"DW_OP_const8s", 0x0F},
- {"DW_OP_constu", 0x10},
- {"DW_OP_consts", 0x11},
- {"DW_OP_dup", 0x12},
- {"DW_OP_drop", 0x13},
- {"DW_OP_over", 0x14},
- {"DW_OP_pick", 0x15},
- {"DW_OP_swap", 0x16},
- {"DW_OP_rot", 0x17},
- {"DW_OP_xderef", 0x18},
- {"DW_OP_abs", 0x19},
- {"DW_OP_and", 0x1A},
- {"DW_OP_div", 0x1B},
- {"DW_OP_minus", 0x1C},
- {"DW_OP_mod", 0x1D},
- {"DW_OP_mul", 0x1E},
- {"DW_OP_neg", 0x1F},
- {"DW_OP_not", 0x20},
- {"DW_OP_or", 0x21},
- {"DW_OP_plus", 0x22},
- {"DW_OP_plus_uconst", 0x23},
- {"DW_OP_shl", 0x24},
- {"DW_OP_shr", 0x25},
- {"DW_OP_shra", 0x26},
- {"DW_OP_xor", 0x27},
- {"DW_OP_bra", 0x28},
- {"DW_OP_eq", 0x29},
- {"DW_OP_ge", 0x2A},
- {"DW_OP_gt", 0x2B},
- {"DW_OP_le", 0x2C},
- {"DW_OP_lt", 0x2D},
- {"DW_OP_ne", 0x2E},
- {"DW_OP_skip", 0x2F},
- {"DW_OP_regx", 0x90},
- {"DW_OP_fbreg", 0x91},
- {"DW_OP_bregx", 0x92},
- {"DW_OP_piece", 0x93},
- {"DW_OP_deref_size", 0x94},
- {"DW_OP_xderef_size", 0x95},
- {"DW_OP_nop", 0x96},
- {"DW_OP_push_object_address", 0x97},
- {"DW_OP_call2", 0x98},
- {"DW_OP_call4", 0x99},
- {"DW_OP_call_ref", 0x9A},
- {"DW_OP_form_tls_address", 0x9B},
- {"DW_OP_call_frame_cfa", 0x9C},
- {"DW_OP_bit_piece", 0x9D},
- {"DW_OP_implicit_value", 0x9E},
- {"DW_OP_stack_value", 0x9F},
- {"DW_OP_implicit_pointer", 0xA0},
- {"DW_OP_addrx", 0xA1},
- {"DW_OP_constx", 0xA2},
- {"DW_OP_entry_value", 0xA3},
- {"DW_OP_const_type", 0xA4},
- {"DW_OP_regval_type", 0xA5},
- {"DW_OP_deref_type", 0xA6},
- {"DW_OP_xderef_type", 0xA7},
- {"DW_OP_convert", 0xA8},
- {"DW_OP_reinterpret", 0xA9},
- {"DW_OP_LLVM_fragment", 0x1000},
- {"DW_OP_LLVM_convert", 0x1001},
- {"DW_OP_LLVM_tag_offset", 0x1002},
- {"DW_OP_LLVM_entry_value", 0x1003},
- {"DW_OP_LLVM_implicit_pointer", 0x1004},
- {"DW_OP_LLVM_arg", 0x1005},
- {"DW_OP_LLVM_extract_bits_sext", 0x1006},
- {"DW_OP_LLVM_extract_bits_zext", 0x1007},
- });
- return Opcodes;
-}
-
-[[nodiscard]] const auto &attributeEncodings() {
- static constexpr auto Encodings = std::to_array<std::pair<std::string_view, std::uint64_t>>({
- {"DW_ATE_address", 0x01},
- {"DW_ATE_boolean", 0x02},
- {"DW_ATE_complex_float", 0x03},
- {"DW_ATE_float", 0x04},
- {"DW_ATE_signed", 0x05},
- {"DW_ATE_signed_char", 0x06},
- {"DW_ATE_unsigned", 0x07},
- {"DW_ATE_unsigned_char", 0x08},
- {"DW_ATE_imaginary_float", 0x09},
- {"DW_ATE_packed_decimal", 0x0A},
- {"DW_ATE_numeric_string", 0x0B},
- {"DW_ATE_edited", 0x0C},
- {"DW_ATE_signed_fixed", 0x0D},
- {"DW_ATE_unsigned_fixed", 0x0E},
- {"DW_ATE_decimal_float", 0x0F},
- {"DW_ATE_UTF", 0x10},
- {"DW_ATE_UCS", 0x11},
- {"DW_ATE_ASCII", 0x12},
- });
- return Encodings;
-}
-
-[[nodiscard]] std::optional<std::string> opcodeName(std::uint64_t Opcode) {
- if (Opcode >= 0x30U && Opcode <= 0x4FU)
- return "DW_OP_lit" + std::to_string(Opcode - 0x30U);
- if (Opcode >= 0x50U && Opcode <= 0x6FU)
- return "DW_OP_reg" + std::to_string(Opcode - 0x50U);
- if (Opcode >= 0x70U && Opcode <= 0x8FU)
- return "DW_OP_breg" + std::to_string(Opcode - 0x70U);
- const auto &Opcodes = namedOpcodes();
- const auto Found =
- std::ranges::find_if(Opcodes, [Opcode](const auto &Entry) { return Entry.second == Opcode; });
- if (Found == Opcodes.end())
- return std::nullopt;
- return std::string(Found->first);
-}
-
-[[nodiscard]] std::size_t opcodeSize(std::uint64_t Opcode) noexcept {
- if (Opcode >= 0x70U && Opcode <= 0x8FU)
- return 2;
- switch (Opcode) {
- case 0x92:
- case 0x1000:
- case 0x1001:
- case 0x1006:
- case 0x1007:
- return 3;
- case 0x10:
- case 0x11:
- case 0x23:
- case 0x90:
- case 0x94:
- case 0x1002:
- case 0x1003:
- case 0x1005:
- return 2;
- default:
- return 1;
- }
-}
-
-[[nodiscard]] std::optional<std::string_view> attributeName(std::uint64_t Encoding) noexcept {
- const auto &Encodings = attributeEncodings();
- const auto Found = std::ranges::find_if(
- Encodings, [Encoding](const auto &Entry) { return Entry.second == Encoding; });
- if (Found == Encodings.end())
- return std::nullopt;
- return Found->first;
-}
-
-} // namespace
-
-std::optional<std::uint64_t> parseDIExpressionOpcodeName(std::string_view Name) noexcept {
- const auto NumberedOpcode = [Name](std::string_view Prefix,
- std::uint64_t Base) -> std::optional<std::uint64_t> {
- if (!Name.starts_with(Prefix))
- return std::nullopt;
- std::uint64_t Index = 0;
- if (!parseIndex(Name.substr(Prefix.size()), Index) || Index > 31)
- return std::nullopt;
- return Base + Index;
- };
- if (auto Opcode = NumberedOpcode("DW_OP_lit", 0x30U))
- return Opcode;
- if (auto Opcode = NumberedOpcode("DW_OP_reg", 0x50U))
- return Opcode;
- if (auto Opcode = NumberedOpcode("DW_OP_breg", 0x70U))
- return Opcode;
-
- const auto &NamedOpcodes = namedOpcodes();
- const auto *const Found =
- std::ranges::find_if(NamedOpcodes, [Name](const auto &Entry) { return Entry.first == Name; });
- if (Found == NamedOpcodes.end())
- return std::nullopt;
- return Found->second;
-}
-
-std::optional<std::uint64_t>
-parseDIExpressionAttributeEncodingName(std::string_view Name) noexcept {
- const auto &Encodings = attributeEncodings();
- const auto Found =
- std::ranges::find_if(Encodings, [Name](const auto &Entry) { return Entry.first == Name; });
- if (Found == Encodings.end())
- return std::nullopt;
- return Found->second;
-}
-
-std::string invalidDIExpressionElementMessage(std::string_view Name) {
- if (Name.starts_with("DW_OP_"))
- return "invalid DWARF op '" + std::string(Name) + "'";
- if (Name.starts_with("DW_ATE_"))
- return "invalid DWARF attribute encoding '" + std::string(Name) + "'";
- return "expected unsigned integer";
-}
-
-std::string formatDIExpression(std::span<const std::uint64_t> Elements) {
- std::string Result = "!DIExpression(";
- std::size_t Position = 0;
- bool First = true;
- while (Position < Elements.size()) {
- const std::uint64_t Opcode = Elements[Position];
- const auto Name = opcodeName(Opcode);
- const std::size_t Size = opcodeSize(Opcode);
- if (!Name || Position + Size > Elements.size()) {
- Result = "!DIExpression(";
- for (std::size_t Index = 0; Index < Elements.size(); ++Index) {
- if (Index != 0)
- Result.append(", ");
- Result.append(std::to_string(Elements[Index]));
- }
- Result.push_back(')');
- return Result;
- }
-
- if (!First)
- Result.append(", ");
- First = false;
- Result.append(*Name);
- for (std::size_t Argument = 1; Argument < Size; ++Argument) {
- Result.append(", ");
- if (Opcode == 0x1001U && Argument == 2U) {
- if (const auto Encoding = attributeName(Elements[Position + Argument])) {
- Result.append(*Encoding);
- continue;
- }
- }
- Result.append(std::to_string(Elements[Position + Argument]));
- }
- Position += Size;
- }
- Result.push_back(')');
- return Result;
-}
-
-} // namespace rcc::mir
diff --git a/backend/lib/MIR/MILexer.cpp b/backend/lib/MIR/MILexer.cpp
deleted file mode 100644
index f568cef..0000000
--- a/backend/lib/MIR/MILexer.cpp
+++ /dev/null
@@ -1,964 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include "rcc/MIR/MILexer.h"
-
-#include <algorithm>
-#include <array>
-#include <cassert>
-#include <cstddef>
-#include <cstdint>
-#include <iomanip>
-#include <optional>
-#include <ranges>
-#include <sstream>
-#include <string>
-#include <string_view>
-#include <utility>
-#include <vector>
-
-namespace rcc::mir {
-namespace {
-
-template <std::size_t Size>
-[[nodiscard]] consteval std::array<std::string_view, Size>
-sortSpellings(std::array<std::string_view, Size> Spellings) {
- for (std::size_t Left = 0; Left < Spellings.size(); ++Left) {
- for (std::size_t Right = Left + 1; Right < Spellings.size(); ++Right) {
- if (Spellings[Right] < Spellings[Left])
- std::swap(Spellings[Left], Spellings[Right]);
- }
- }
- return Spellings;
-}
-
-template <std::size_t Size>
-[[nodiscard]] consteval bool
-hasUniqueSpellings(const std::array<std::string_view, Size> &Spellings) {
- for (std::size_t Index = 1; Index < Spellings.size(); ++Index) {
- if (Spellings[Index - 1] == Spellings[Index])
- return false;
- }
- return true;
-}
-
-constexpr auto Keywords = sortSpellings(std::array{
- std::string_view{"addrspace"},
- std::string_view{"adjust_cfa_offset"},
- std::string_view{"afn"},
- std::string_view{"align"},
- std::string_view{"arcp"},
- std::string_view{"basealign"},
- std::string_view{"bb_id"},
- std::string_view{"bbsections"},
- std::string_view{"bfloat"},
- std::string_view{"blockaddress"},
- std::string_view{"call-entry"},
- std::string_view{"call-frame-size"},
- std::string_view{"cfi-type"},
- std::string_view{"constant-pool"},
- std::string_view{"contract"},
- std::string_view{"custom"},
- std::string_view{"dead"},
- std::string_view{"deactivation-symbol"},
- std::string_view{"debug-instr-number"},
- std::string_view{"debug-location"},
- std::string_view{"debug-use"},
- std::string_view{"dbg-instr-ref"},
- std::string_view{"def"},
- std::string_view{"def_cfa"},
- std::string_view{"def_cfa_offset"},
- std::string_view{"def_cfa_register"},
- std::string_view{"dereferenceable"},
- std::string_view{"disjoint"},
- std::string_view{"distinct"},
- std::string_view{"double"},
- std::string_view{"early-clobber"},
- std::string_view{"ehfunclet-entry"},
- std::string_view{"ehscope-entry"},
- std::string_view{"escape"},
- std::string_view{"exact"},
- std::string_view{"float"},
- std::string_view{"floatpred"},
- std::string_view{"fp128"},
- std::string_view{"frame-destroy"},
- std::string_view{"frame-setup"},
- std::string_view{"got"},
- std::string_view{"half"},
- std::string_view{"heap-alloc-marker"},
- std::string_view{"implicit"},
- std::string_view{"implicit-def"},
- std::string_view{"inbounds"},
- std::string_view{"inlineasm-br-indirect-target"},
- std::string_view{"internal"},
- std::string_view{"intpred"},
- std::string_view{"intrinsic"},
- std::string_view{"invariant"},
- std::string_view{"ir-block-address-taken"},
- std::string_view{"jump-table"},
- std::string_view{"killed"},
- std::string_view{"landing-pad"},
- std::string_view{"lanemask"},
- std::string_view{"liveins"},
- std::string_view{"liveout"},
- std::string_view{"llvm_def_aspace_cfa"},
- std::string_view{"llvm_register_pair"},
- std::string_view{"llvm_vector_offset"},
- std::string_view{"llvm_vector_register_mask"},
- std::string_view{"llvm_vector_registers"},
- std::string_view{"machine-block-address-taken"},
- std::string_view{"mmra"},
- std::string_view{"negate_ra_sign_state"},
- std::string_view{"negate_ra_sign_state_with_pc"},
- std::string_view{"ninf"},
- std::string_view{"nnan"},
- std::string_view{"noconvergent"},
- std::string_view{"nofpexcept"},
- std::string_view{"non-temporal"},
- std::string_view{"nneg"},
- std::string_view{"nsw"},
- std::string_view{"nsz"},
- std::string_view{"nusw"},
- std::string_view{"nuw"},
- std::string_view{"offset"},
- std::string_view{"pcsections"},
- std::string_view{"post-instr-symbol"},
- std::string_view{"ppc_fp128"},
- std::string_view{"pre-instr-symbol"},
- std::string_view{"reassoc"},
- std::string_view{"rel_offset"},
- std::string_view{"remember_state"},
- std::string_view{"renamable"},
- std::string_view{"register"},
- std::string_view{"restore"},
- std::string_view{"restore_state"},
- std::string_view{"same_value"},
- std::string_view{"samesign"},
- std::string_view{"shufflemask"},
- std::string_view{"stack"},
- std::string_view{"successors"},
- std::string_view{"target-flags"},
- std::string_view{"target-index"},
- std::string_view{"tied-def"},
- std::string_view{"undef"},
- std::string_view{"undefined"},
- std::string_view{"unknown-address"},
- std::string_view{"unknown-size"},
- std::string_view{"unpredictable"},
- std::string_view{"volatile"},
- std::string_view{"window_save"},
- std::string_view{"x86_fp80"},
-});
-
-constexpr auto MetadataKeywords = sortSpellings(std::array{
- std::string_view{"!DIExpression"},
- std::string_view{"!DILocation"},
- std::string_view{"!alias.scope"},
- std::string_view{"!noalias"},
- std::string_view{"!noalias.addrspace"},
- std::string_view{"!range"},
- std::string_view{"!tbaa"},
-});
-
-static_assert(hasUniqueSpellings(Keywords));
-static_assert(hasUniqueSpellings(MetadataKeywords));
-
-[[nodiscard]] constexpr bool isASCIIAlpha(char Character) noexcept {
- return (Character >= 'a' && Character <= 'z') || (Character >= 'A' && Character <= 'Z');
-}
-
-[[nodiscard]] constexpr bool isASCIIDigit(char Character) noexcept {
- return Character >= '0' && Character <= '9';
-}
-
-[[nodiscard]] constexpr bool isASCIIHexDigit(char Character) noexcept {
- return isASCIIDigit(Character) || (Character >= 'a' && Character <= 'f') ||
- (Character >= 'A' && Character <= 'F');
-}
-
-[[nodiscard]] constexpr unsigned hexDigitValue(char Character) noexcept {
- if (isASCIIDigit(Character))
- return static_cast<unsigned>(Character - '0');
- if (Character >= 'a' && Character <= 'f')
- return static_cast<unsigned>(Character - 'a' + 10);
- return static_cast<unsigned>(Character - 'A' + 10);
-}
-
-[[nodiscard]] constexpr bool isIdentifierCharacter(char Character) noexcept {
- return isASCIIAlpha(Character) || isASCIIDigit(Character) || Character == '_' ||
- Character == '-' || Character == '.' || Character == '$';
-}
-
-[[nodiscard]] constexpr bool isRegisterCharacter(char Character) noexcept {
- return isIdentifierCharacter(Character) && Character != '.';
-}
-
-[[nodiscard]] constexpr bool isHorizontalWhitespace(char Character) noexcept {
- return Character == ' ' || Character == '\t';
-}
-
-[[nodiscard]] constexpr bool isNewlineCharacter(char Character) noexcept {
- return Character == '\n' || Character == '\r';
-}
-
-[[nodiscard]] constexpr bool isHexFloatingPointPrefix(char Character) noexcept {
- return Character == 'H' || Character == 'K' || Character == 'L' || Character == 'M' ||
- Character == 'R';
-}
-
-[[nodiscard]] std::string unexpectedCharacterMessage(unsigned char Character) {
- if (Character >= 0x20U && Character <= 0x7EU) {
- return "unexpected character '" + std::string(1, static_cast<char>(Character)) + "'";
- }
- std::ostringstream Message;
- Message << "unexpected byte 0x" << std::uppercase << std::hex << std::setw(2) << std::setfill('0')
- << static_cast<unsigned>(Character);
- return Message.str();
-}
-
-} // namespace
-
-std::string_view getMITokenKindName(MITokenKind Kind) noexcept {
- switch (Kind) {
- case MITokenKind::EndOfFile:
- return "end-of-file";
- case MITokenKind::Error:
- return "error";
- case MITokenKind::Newline:
- return "newline";
- case MITokenKind::Comma:
- return "comma";
- case MITokenKind::Equal:
- return "equal";
- case MITokenKind::Underscore:
- return "underscore";
- case MITokenKind::Colon:
- return "colon";
- case MITokenKind::DoubleColon:
- return "double-colon";
- case MITokenKind::Dot:
- return "dot";
- case MITokenKind::Exclaim:
- return "exclaim";
- case MITokenKind::LeftParen:
- return "left-paren";
- case MITokenKind::RightParen:
- return "right-paren";
- case MITokenKind::LeftBrace:
- return "left-brace";
- case MITokenKind::RightBrace:
- return "right-brace";
- case MITokenKind::Plus:
- return "plus";
- case MITokenKind::Minus:
- return "minus";
- case MITokenKind::Less:
- return "less";
- case MITokenKind::Greater:
- return "greater";
- case MITokenKind::Keyword:
- return "keyword";
- case MITokenKind::MetadataKeyword:
- return "metadata-keyword";
- case MITokenKind::Identifier:
- return "identifier";
- case MITokenKind::NamedRegister:
- return "named-register";
- case MITokenKind::NamedVirtualRegister:
- return "named-virtual-register";
- case MITokenKind::MachineBasicBlockLabel:
- return "machine-basic-block-label";
- case MITokenKind::MachineBasicBlock:
- return "machine-basic-block";
- case MITokenKind::StackObject:
- return "stack-object";
- case MITokenKind::FixedStackObject:
- return "fixed-stack-object";
- case MITokenKind::NamedGlobalValue:
- return "named-global-value";
- case MITokenKind::GlobalValue:
- return "global-value";
- case MITokenKind::ExternalSymbol:
- return "external-symbol";
- case MITokenKind::MCSymbol:
- return "mc-symbol";
- case MITokenKind::IntegerLiteral:
- return "integer-literal";
- case MITokenKind::FloatingPointLiteral:
- return "floating-point-literal";
- case MITokenKind::HexLiteral:
- return "hex-literal";
- case MITokenKind::VirtualRegister:
- return "virtual-register";
- case MITokenKind::ConstantPoolItem:
- return "constant-pool-item";
- case MITokenKind::JumpTableIndex:
- return "jump-table-index";
- case MITokenKind::NamedIRBlock:
- return "named-ir-block";
- case MITokenKind::IRBlock:
- return "ir-block";
- case MITokenKind::NamedIRValue:
- return "named-ir-value";
- case MITokenKind::IRValue:
- return "ir-value";
- case MITokenKind::QuotedIRValue:
- return "quoted-ir-value";
- case MITokenKind::SubRegisterIndex:
- return "subregister-index";
- case MITokenKind::StringConstant:
- return "string-constant";
- }
- return "unknown";
-}
-
-bool isMIKeyword(std::string_view Spelling) noexcept {
- return std::ranges::binary_search(Keywords, Spelling);
-}
-
-bool isMIMetadataKeyword(std::string_view Spelling) noexcept {
- return std::ranges::binary_search(MetadataKeywords, Spelling);
-}
-
-std::string_view MIToken::stringValue() const noexcept {
- if (const auto *View = std::get_if<std::string_view>(&StringValue))
- return *View;
- if (const auto *Owned = std::get_if<std::string>(&StringValue))
- return *Owned;
- return {};
-}
-
-bool MIToken::isRegister() const noexcept {
- return Kind == MITokenKind::NamedRegister || Kind == MITokenKind::NamedVirtualRegister ||
- Kind == MITokenKind::VirtualRegister || Kind == MITokenKind::Underscore;
-}
-
-bool MIToken::isRegisterFlag() const noexcept {
- return isKeyword("implicit") || isKeyword("implicit-def") || isKeyword("def") ||
- isKeyword("dead") || isKeyword("killed") || isKeyword("undef") || isKeyword("internal") ||
- isKeyword("early-clobber") || isKeyword("debug-use") || isKeyword("renamable");
-}
-
-bool MIToken::isMemoryOperandFlag() const noexcept {
- return isKeyword("volatile") || isKeyword("non-temporal") || isKeyword("dereferenceable") ||
- isKeyword("invariant") || Kind == MITokenKind::StringConstant;
-}
-
-MIToken MILexer::makeToken(MITokenKind Kind, TextRange Range, std::string_view Spelling,
- std::string_view IntegerValue) {
- return MIToken(Kind, Range, Spelling, {}, IntegerValue);
-}
-
-MIToken MILexer::makeStringToken(MITokenKind Kind, TextRange Range, std::string_view Spelling,
- std::string_view StringValue, std::string_view IntegerValue) {
- return MIToken(Kind, Range, Spelling, StringValue, IntegerValue);
-}
-
-MIToken MILexer::makeOwnedStringToken(MITokenKind Kind, TextRange Range, std::string_view Spelling,
- std::string StringValue, std::string_view IntegerValue) {
- return MIToken(Kind, Range, Spelling, std::move(StringValue), IntegerValue);
-}
-
-class MILexer::Impl final {
-public:
- Impl(std::string SourceName, std::string SourceText, MILexerOptions Options)
- : Source(std::move(SourceName), std::move(SourceText)), Options(Options) {}
-
- [[nodiscard]] MIToken next() {
- if (Failed)
- return token(MITokenKind::EndOfFile, Offset, Offset);
-
- if (auto TriviaError = skipTrivia())
- return std::move(*TriviaError);
-
- if (atEnd())
- return token(MITokenKind::EndOfFile, Offset, Offset);
-
- const std::size_t Begin = Offset;
- MIToken Result = lexToken();
- if (Result.kind() == MITokenKind::Error)
- return Result;
-
- if (Options.MaximumTokenLength != 0 &&
- Result.range().End.Offset - Result.range().Begin.Offset > Options.MaximumTokenLength) {
- return fail(Begin, Offset, "machine instruction token exceeds the configured length limit");
- }
- if (Options.MaximumTokens != 0 && TokenCount >= Options.MaximumTokens) {
- return fail(Begin, Offset, "machine instruction token count exceeds the configured limit");
- }
- ++TokenCount;
- return Result;
- }
-
- [[nodiscard]] const TextSource &source() const noexcept {
- return Source;
- }
-
- [[nodiscard]] std::span<const TextDiagnostic> diagnostics() const noexcept {
- return Diagnostics;
- }
-
- [[nodiscard]] bool failed() const noexcept {
- return Failed;
- }
-
- [[nodiscard]] std::size_t tokenCount() const noexcept {
- return TokenCount;
- }
-
-private:
- struct QuotedValue final {
- std::size_t End = 0;
- std::string Value;
- };
-
- [[nodiscard]] std::string_view text() const noexcept {
- return Source.text();
- }
-
- [[nodiscard]] bool atEnd(std::size_t Lookahead = 0) const noexcept {
- return Offset >= text().size() || Lookahead >= text().size() - Offset;
- }
-
- [[nodiscard]] char peek(std::size_t Lookahead = 0) const noexcept {
- if (Offset >= text().size() || Lookahead >= text().size() - Offset)
- return '\0';
- return text()[Offset + Lookahead];
- }
-
- [[nodiscard]] bool startsWith(std::string_view Prefix) const noexcept {
- return text().substr(Offset).starts_with(Prefix);
- }
-
- [[nodiscard]] std::string_view slice(std::size_t Begin, std::size_t End) const noexcept {
- assert(Begin <= End && End <= text().size());
- return text().substr(Begin, End - Begin);
- }
-
- [[nodiscard]] MIToken token(MITokenKind Kind, std::size_t Begin, std::size_t End,
- std::string_view IntegerValue = {}) const {
- return MILexer::makeToken(Kind, Source.range(Begin, End), slice(Begin, End), IntegerValue);
- }
-
- [[nodiscard]] MIToken stringToken(MITokenKind Kind, std::size_t Begin, std::size_t End,
- std::string_view Value,
- std::string_view IntegerValue = {}) const {
- return MILexer::makeStringToken(Kind, Source.range(Begin, End), slice(Begin, End), Value,
- IntegerValue);
- }
-
- [[nodiscard]] MIToken ownedStringToken(MITokenKind Kind, std::size_t Begin, std::size_t End,
- std::string Value,
- std::string_view IntegerValue = {}) const {
- return MILexer::makeOwnedStringToken(Kind, Source.range(Begin, End), slice(Begin, End),
- std::move(Value), IntegerValue);
- }
-
- [[nodiscard]] MIToken fail(std::size_t Begin, std::size_t End, std::string Message) {
- End = std::clamp(End, Begin, text().size());
- Diagnostics.push_back(TextDiagnostic{
- .Severity = DiagnosticSeverity::Error,
- .Category = "mir-lexer",
- .Message = std::move(Message),
- .SourceName = std::string(Source.name()),
- .Range = Source.range(Begin, End),
- });
- Failed = true;
- return token(MITokenKind::Error, Begin, End);
- }
-
- [[nodiscard]] std::optional<MIToken> skipTrivia() {
- while (true) {
- while (!atEnd() && isHorizontalWhitespace(peek()))
- ++Offset;
-
- if (peek() == ';') {
- while (!atEnd() && !isNewlineCharacter(peek()))
- ++Offset;
- continue;
- }
-
- if (!startsWith("/*"))
- return std::nullopt;
-
- const std::size_t Begin = Offset;
- Offset += 2;
- while (!atEnd() && !startsWith("*/"))
- ++Offset;
- if (atEnd()) {
- return fail(Begin, Offset,
- "end of machine instruction input reached before the closing '*/'");
- }
- Offset += 2;
- }
- }
-
- [[nodiscard]] std::optional<QuotedValue> scanQuotedString(std::size_t QuoteOffset) {
- assert(QuoteOffset < text().size() && text()[QuoteOffset] == '"');
- std::size_t Cursor = QuoteOffset + 1;
- while (Cursor < text().size() && text()[Cursor] != '"') {
- if (isNewlineCharacter(text()[Cursor])) {
- Offset = Cursor;
- static_cast<void>(fail(QuoteOffset, Cursor,
- "end of machine instruction reached before the closing '\"'"));
- return std::nullopt;
- }
- ++Cursor;
- }
- if (Cursor == text().size()) {
- Offset = Cursor;
- static_cast<void>(
- fail(QuoteOffset, Cursor, "end of machine instruction reached before the closing '\"'"));
- return std::nullopt;
- }
-
- std::string Value;
- Value.reserve(Cursor - QuoteOffset - 1);
- for (std::size_t Index = QuoteOffset + 1; Index < Cursor; ++Index) {
- const char Character = text()[Index];
- if (Character == '\\' && Index + 1 < Cursor && text()[Index + 1] == '\\') {
- Value.push_back('\\');
- ++Index;
- continue;
- }
- if (Character == '\\' && Index + 2 < Cursor && isASCIIHexDigit(text()[Index + 1]) &&
- isASCIIHexDigit(text()[Index + 2])) {
- const unsigned Decoded =
- hexDigitValue(text()[Index + 1]) * 16U + hexDigitValue(text()[Index + 2]);
- Value.push_back(static_cast<char>(Decoded));
- Index += 2;
- continue;
- }
- Value.push_back(Character);
- }
- return QuotedValue{.End = Cursor + 1, .Value = std::move(Value)};
- }
-
- [[nodiscard]] MIToken lexName(MITokenKind Kind, std::size_t PrefixLength) {
- const std::size_t Begin = Offset;
- Offset += PrefixLength;
- if (peek() == '"') {
- auto Quoted = scanQuotedString(Offset);
- if (!Quoted)
- return token(MITokenKind::Error, Begin, Offset);
- Offset = Quoted->End;
- return ownedStringToken(Kind, Begin, Offset, std::move(Quoted->Value));
- }
-
- const std::size_t ValueBegin = Offset;
- while (!atEnd() && isIdentifierCharacter(peek()))
- ++Offset;
- return stringToken(Kind, Begin, Offset, slice(ValueBegin, Offset));
- }
-
- [[nodiscard]] std::optional<MIToken> lexMachineBasicBlock() {
- const bool IsReference = startsWith("%bb.");
- if (!IsReference && !startsWith("bb."))
- return std::nullopt;
-
- const std::size_t Begin = Offset;
- const std::size_t PrefixLength = IsReference ? 4 : 3;
- Offset += PrefixLength;
- if (!isASCIIDigit(peek())) {
- return fail(Offset, std::min(Offset + 1, text().size()),
- "expected a decimal block number after '" +
- std::string(IsReference ? "%bb.'" : "bb.'"));
- }
-
- const std::size_t NumberBegin = Offset;
- while (!atEnd() && isASCIIDigit(peek()))
- ++Offset;
- const std::string_view Number = slice(NumberBegin, Offset);
-
- if (peek() != '.') {
- return stringToken(IsReference ? MITokenKind::MachineBasicBlock
- : MITokenKind::MachineBasicBlockLabel,
- Begin, Offset, {}, Number);
- }
-
- ++Offset;
- const std::size_t NameBegin = Offset;
- if (peek() == '"') {
- auto Quoted = scanQuotedString(Offset);
- if (!Quoted)
- return token(MITokenKind::Error, Begin, Offset);
- Offset = Quoted->End;
- return ownedStringToken(IsReference ? MITokenKind::MachineBasicBlock
- : MITokenKind::MachineBasicBlockLabel,
- Begin, Offset, std::move(Quoted->Value), Number);
- }
- while (!atEnd() && isIdentifierCharacter(peek()))
- ++Offset;
- return stringToken(IsReference ? MITokenKind::MachineBasicBlock
- : MITokenKind::MachineBasicBlockLabel,
- Begin, Offset, slice(NameBegin, Offset), Number);
- }
-
- [[nodiscard]] std::optional<MIToken> lexIndex(std::string_view Prefix, MITokenKind Kind,
- bool HasOptionalName) {
- if (!startsWith(Prefix) || !isASCIIDigit(peek(Prefix.size())))
- return std::nullopt;
-
- const std::size_t Begin = Offset;
- Offset += Prefix.size();
- const std::size_t NumberBegin = Offset;
- while (!atEnd() && isASCIIDigit(peek()))
- ++Offset;
- const std::string_view Number = slice(NumberBegin, Offset);
-
- if (!HasOptionalName)
- return token(Kind, Begin, Offset, Number);
-
- if (peek() != '.')
- return stringToken(Kind, Begin, Offset, {}, Number);
-
- ++Offset;
- const std::size_t NameBegin = Offset;
- if (peek() == '"') {
- auto Quoted = scanQuotedString(Offset);
- if (!Quoted)
- return token(MITokenKind::Error, Begin, Offset);
- Offset = Quoted->End;
- return ownedStringToken(Kind, Begin, Offset, std::move(Quoted->Value), Number);
- }
- while (!atEnd() && isIdentifierCharacter(peek()))
- ++Offset;
- return stringToken(Kind, Begin, Offset, slice(NameBegin, Offset), Number);
- }
-
- [[nodiscard]] std::optional<MIToken>
- lexIRReference(std::string_view Prefix, MITokenKind NumericKind, MITokenKind NamedKind) {
- if (!startsWith(Prefix))
- return std::nullopt;
- if (isASCIIDigit(peek(Prefix.size())))
- return lexIndex(Prefix, NumericKind, false);
- return lexName(NamedKind, Prefix.size());
- }
-
- [[nodiscard]] std::optional<MIToken> lexRegister() {
- if (peek() != '%' && peek() != '$')
- return std::nullopt;
-
- const std::size_t Begin = Offset;
- const char Prefix = peek();
- ++Offset;
- if (Prefix == '%' && isASCIIDigit(peek())) {
- const std::size_t NumberBegin = Offset;
- while (!atEnd() && isASCIIDigit(peek()))
- ++Offset;
- return token(MITokenKind::VirtualRegister, Begin, Offset, slice(NumberBegin, Offset));
- }
-
- if (Prefix == '%' && !isRegisterCharacter(peek())) {
- Offset = Begin;
- return std::nullopt;
- }
-
- const std::size_t NameBegin = Offset;
- while (!atEnd() && isRegisterCharacter(peek()))
- ++Offset;
- return stringToken(Prefix == '%' ? MITokenKind::NamedVirtualRegister
- : MITokenKind::NamedRegister,
- Begin, Offset, slice(NameBegin, Offset));
- }
-
- [[nodiscard]] std::optional<MIToken> lexGlobalValue() {
- if (peek() != '@')
- return std::nullopt;
- if (!isASCIIDigit(peek(1)))
- return lexName(MITokenKind::NamedGlobalValue, 1);
-
- const std::size_t Begin = Offset++;
- const std::size_t NumberBegin = Offset;
- while (!atEnd() && isASCIIDigit(peek()))
- ++Offset;
- return token(MITokenKind::GlobalValue, Begin, Offset, slice(NumberBegin, Offset));
- }
-
- [[nodiscard]] std::optional<MIToken> lexMCSymbol() {
- constexpr std::string_view Prefix = "<mcsymbol ";
- if (!startsWith(Prefix))
- return std::nullopt;
-
- const std::size_t Begin = Offset;
- Offset += Prefix.size();
- if (peek() != '"') {
- const std::size_t NameBegin = Offset;
- while (!atEnd() && isIdentifierCharacter(peek()))
- ++Offset;
- const std::string_view Name = slice(NameBegin, Offset);
- if (peek() != '>') {
- return fail(Begin, Offset, "expected the '<mcsymbol ...' operand to be closed by '>'");
- }
- ++Offset;
- return stringToken(MITokenKind::MCSymbol, Begin, Offset, Name);
- }
-
- auto Quoted = scanQuotedString(Offset);
- if (!Quoted)
- return token(MITokenKind::Error, Begin, Offset);
- Offset = Quoted->End;
- if (peek() != '>') {
- return fail(Begin, Offset, "expected the '<mcsymbol ...' operand to be closed by '>'");
- }
- ++Offset;
- return ownedStringToken(MITokenKind::MCSymbol, Begin, Offset, std::move(Quoted->Value));
- }
-
- [[nodiscard]] std::optional<MIToken> lexFloatHexBits() {
- if (!startsWith("f0x") && !startsWith("f0X"))
- return std::nullopt;
- std::size_t End = Offset + 3;
- while (End < text().size() && isASCIIHexDigit(text()[End]))
- ++End;
- if (End == Offset + 3)
- return std::nullopt;
- const std::size_t Begin = Offset;
- Offset = End;
- return token(MITokenKind::FloatingPointLiteral, Begin, Offset);
- }
-
- [[nodiscard]] std::optional<MIToken> lexHexadecimalLiteral() {
- if (peek() != '0' || (peek(1) != 'x' && peek(1) != 'X'))
- return std::nullopt;
-
- std::size_t End = Offset + 2;
- bool IsFloatingPoint = false;
- if (End < text().size() && isHexFloatingPointPrefix(text()[End])) {
- IsFloatingPoint = true;
- ++End;
- }
- const std::size_t DigitsBegin = End;
- while (End < text().size() && isASCIIHexDigit(text()[End]))
- ++End;
- if (End == DigitsBegin)
- return std::nullopt;
-
- const std::size_t Begin = Offset;
- Offset = End;
- return token(IsFloatingPoint ? MITokenKind::FloatingPointLiteral : MITokenKind::HexLiteral,
- Begin, Offset);
- }
-
- [[nodiscard]] std::optional<MIToken> lexNumericalLiteral() {
- if (!isASCIIDigit(peek()) && (peek() != '-' || !isASCIIDigit(peek(1)))) {
- return std::nullopt;
- }
-
- const std::size_t Begin = Offset;
- if (peek() == '-')
- ++Offset;
- while (!atEnd() && isASCIIDigit(peek()))
- ++Offset;
-
- if (peek() != '.') {
- return token(MITokenKind::IntegerLiteral, Begin, Offset, slice(Begin, Offset));
- }
-
- ++Offset;
- while (!atEnd() && isASCIIDigit(peek()))
- ++Offset;
- if ((peek() == 'e' || peek() == 'E') &&
- (isASCIIDigit(peek(1)) || ((peek(1) == '-' || peek(1) == '+') && isASCIIDigit(peek(2))))) {
- ++Offset;
- if (peek() == '-' || peek() == '+')
- ++Offset;
- while (!atEnd() && isASCIIDigit(peek()))
- ++Offset;
- }
- return token(MITokenKind::FloatingPointLiteral, Begin, Offset);
- }
-
- [[nodiscard]] std::optional<MIToken> lexExclaim() {
- if (peek() != '!')
- return std::nullopt;
-
- const std::size_t Begin = Offset++;
- if (isASCIIDigit(peek()) || !isIdentifierCharacter(peek()))
- return token(MITokenKind::Exclaim, Begin, Offset);
-
- while (!atEnd() && isIdentifierCharacter(peek()))
- ++Offset;
- const std::string_view Spelling = slice(Begin, Offset);
- if (!isMIMetadataKeyword(Spelling)) {
- return fail(Begin, Offset, "use of unknown metadata keyword '" + std::string(Spelling) + "'");
- }
- return stringToken(MITokenKind::MetadataKeyword, Begin, Offset, Spelling);
- }
-
- [[nodiscard]] std::optional<MIToken> lexSymbol() {
- const std::size_t Begin = Offset;
- if (startsWith("::")) {
- Offset += 2;
- return token(MITokenKind::DoubleColon, Begin, Offset);
- }
-
- MITokenKind Kind = MITokenKind::Error;
- switch (peek()) {
- case ',':
- Kind = MITokenKind::Comma;
- break;
- case '=':
- Kind = MITokenKind::Equal;
- break;
- case ':':
- Kind = MITokenKind::Colon;
- break;
- case '.':
- Kind = MITokenKind::Dot;
- break;
- case '(':
- Kind = MITokenKind::LeftParen;
- break;
- case ')':
- Kind = MITokenKind::RightParen;
- break;
- case '{':
- Kind = MITokenKind::LeftBrace;
- break;
- case '}':
- Kind = MITokenKind::RightBrace;
- break;
- case '+':
- Kind = MITokenKind::Plus;
- break;
- case '-':
- Kind = MITokenKind::Minus;
- break;
- case '<':
- Kind = MITokenKind::Less;
- break;
- case '>':
- Kind = MITokenKind::Greater;
- break;
- default:
- return std::nullopt;
- }
- ++Offset;
- return token(Kind, Begin, Offset);
- }
-
- [[nodiscard]] std::optional<MIToken> lexNewline() {
- if (!isNewlineCharacter(peek()))
- return std::nullopt;
- const std::size_t Begin = Offset++;
- if (text()[Begin] == '\r' && peek() == '\n')
- ++Offset;
- return token(MITokenKind::Newline, Begin, Offset);
- }
-
- [[nodiscard]] std::optional<MIToken> lexQuotedIRValue() {
- if (peek() != '`')
- return std::nullopt;
-
- const std::size_t Begin = Offset++;
- const std::size_t ValueBegin = Offset;
- while (!atEnd() && peek() != '`' && !isNewlineCharacter(peek()))
- ++Offset;
- if (atEnd() || isNewlineCharacter(peek())) {
- return fail(Begin, Offset, "end of machine instruction reached before the closing '`'");
- }
- const std::size_t ValueEnd = Offset++;
- return stringToken(MITokenKind::QuotedIRValue, Begin, Offset, slice(ValueBegin, ValueEnd));
- }
-
- [[nodiscard]] MIToken lexToken() {
- if (auto Result = lexMachineBasicBlock())
- return std::move(*Result);
- if (auto Result = lexFloatHexBits())
- return std::move(*Result);
-
- if (isASCIIAlpha(peek()) || peek() == '_') {
- const std::size_t Begin = Offset;
- while (!atEnd() && isIdentifierCharacter(peek()))
- ++Offset;
- const std::string_view Value = slice(Begin, Offset);
- if (Value == "_")
- return token(MITokenKind::Underscore, Begin, Offset);
- return stringToken(isMIKeyword(Value) ? MITokenKind::Keyword : MITokenKind::Identifier, Begin,
- Offset, Value);
- }
-
- if (auto Result = lexIndex("%jump-table.", MITokenKind::JumpTableIndex, false))
- return std::move(*Result);
- if (auto Result = lexIndex("%stack.", MITokenKind::StackObject, true))
- return std::move(*Result);
- if (auto Result = lexIndex("%fixed-stack.", MITokenKind::FixedStackObject, false))
- return std::move(*Result);
- if (auto Result = lexIndex("%const.", MITokenKind::ConstantPoolItem, false))
- return std::move(*Result);
- if (startsWith("%subreg."))
- return lexName(MITokenKind::SubRegisterIndex, 8);
- if (auto Result = lexIRReference("%ir-block.", MITokenKind::IRBlock, MITokenKind::NamedIRBlock))
- return std::move(*Result);
- if (auto Result = lexIRReference("%ir.", MITokenKind::IRValue, MITokenKind::NamedIRValue))
- return std::move(*Result);
- if (auto Result = lexRegister())
- return std::move(*Result);
- if (auto Result = lexGlobalValue())
- return std::move(*Result);
- if (peek() == '&')
- return lexName(MITokenKind::ExternalSymbol, 1);
- if (auto Result = lexMCSymbol())
- return std::move(*Result);
- if (auto Result = lexHexadecimalLiteral())
- return std::move(*Result);
- if (auto Result = lexNumericalLiteral())
- return std::move(*Result);
- if (auto Result = lexExclaim())
- return std::move(*Result);
- if (auto Result = lexSymbol())
- return std::move(*Result);
- if (auto Result = lexNewline())
- return std::move(*Result);
- if (auto Result = lexQuotedIRValue())
- return std::move(*Result);
- if (peek() == '"')
- return lexName(MITokenKind::StringConstant, 0);
-
- const std::size_t Begin = Offset++;
- return fail(Begin, Offset,
- unexpectedCharacterMessage(static_cast<unsigned char>(text()[Begin])));
- }
-
- TextSource Source;
- MILexerOptions Options;
- std::size_t Offset = 0;
- std::size_t TokenCount = 0;
- bool Failed = false;
- std::vector<TextDiagnostic> Diagnostics;
-};
-
-MILexer::MILexer(std::string SourceName, std::string SourceText, MILexerOptions Options)
- : Implementation(
- std::make_unique<Impl>(std::move(SourceName), std::move(SourceText), Options)) {}
-
-MILexer::MILexer(MILexer &&) noexcept = default;
-MILexer &MILexer::operator=(MILexer &&) noexcept = default;
-MILexer::~MILexer() = default;
-
-MIToken MILexer::next() {
- assert(Implementation != nullptr);
- return Implementation->next();
-}
-
-const TextSource &MILexer::source() const noexcept {
- assert(Implementation != nullptr);
- return Implementation->source();
-}
-
-std::span<const TextDiagnostic> MILexer::diagnostics() const noexcept {
- assert(Implementation != nullptr);
- return Implementation->diagnostics();
-}
-
-bool MILexer::failed() const noexcept {
- assert(Implementation != nullptr);
- return Implementation->failed();
-}
-
-std::size_t MILexer::tokenCount() const noexcept {
- assert(Implementation != nullptr);
- return Implementation->tokenCount();
-}
-
-} // namespace rcc::mir
diff --git a/backend/lib/MIR/MIParser.cpp b/backend/lib/MIR/MIParser.cpp
deleted file mode 100644
index 3748187..0000000
--- a/backend/lib/MIR/MIParser.cpp
+++ /dev/null
@@ -1,2967 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include "rcc/MIR/MIParser.h"
-
-#include "rcc/CodeGen/GenericOpcodes.h"
-#include "rcc/CodeGen/InlineAsm.h"
-#include "rcc/CodeGen/InstructionDescriptor.h"
-#include "rcc/CodeGen/MachineBasicBlock.h"
-#include "rcc/CodeGen/MachineCFGUpdater.h"
-#include "rcc/CodeGen/MachineFunction.h"
-#include "rcc/CodeGen/MachineInstr.h"
-#include "rcc/CodeGen/MachineOperand.h"
-#include "rcc/CodeGen/MachineRegisterInfo.h"
-#include "rcc/CodeGen/MachineVerifier.h"
-#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"
-
-#include <algorithm>
-#include <array>
-#include <bit>
-#include <charconv>
-#include <cmath>
-#include <cstddef>
-#include <cstdint>
-#include <cstring>
-#include <iterator>
-#include <limits>
-#include <memory>
-#include <optional>
-#include <span>
-#include <string>
-#include <string_view>
-#include <system_error>
-#include <unordered_map>
-#include <unordered_set>
-#include <utility>
-#include <vector>
-
-namespace rcc::mir {
-namespace {
-
-[[nodiscard]] bool parseUnsignedDecimal(std::string_view Spelling, std::uint64_t &Value) {
- if (Spelling.empty() || Spelling.front() == '-')
- return false;
- const char *Begin = Spelling.data();
- const char *End = Begin + Spelling.size();
- const auto Result = std::from_chars(Begin, End, Value, 10);
- return Result.ec == std::errc{} && Result.ptr == End;
-}
-
-[[nodiscard]] bool parseSignedDecimal(std::string_view Spelling, std::int64_t &Value) {
- if (Spelling.empty())
- return false;
- const char *Begin = Spelling.data();
- const char *End = Begin + Spelling.size();
- const auto Result = std::from_chars(Begin, End, Value, 10);
- return Result.ec == std::errc{} && Result.ptr == End;
-}
-
-[[nodiscard]] bool parseHexadecimal(std::string_view Spelling, std::uint64_t &Value) {
- if (Spelling.size() < 3 || Spelling[0] != '0' || (Spelling[1] != 'x' && Spelling[1] != 'X'))
- return false;
- const char *Begin = Spelling.data() + 2;
- const char *End = Spelling.data() + Spelling.size();
- const auto Result = std::from_chars(Begin, End, Value, 16);
- return Result.ec == std::errc{} && Result.ptr == End;
-}
-
-[[nodiscard]] bool parseUnsignedDigits(std::string_view Spelling, std::uint64_t &Value) {
- if (Spelling.empty())
- return false;
- const char *Begin = Spelling.data();
- const char *End = Begin + Spelling.size();
- const auto Result = std::from_chars(Begin, End, Value, 10);
- return Result.ec == std::errc{} && Result.ptr == End;
-}
-
-[[nodiscard]] std::optional<FloatSemantics> floatSemanticsForKeyword(std::string_view Keyword) {
- if (Keyword == "half")
- return FloatSemantics::IEEEHalf;
- if (Keyword == "bfloat")
- return FloatSemantics::BFloat;
- if (Keyword == "float")
- return FloatSemantics::IEEESingle;
- if (Keyword == "double")
- return FloatSemantics::IEEEDouble;
- if (Keyword == "x86_fp80")
- return FloatSemantics::X87DoubleExtended;
- if (Keyword == "fp128")
- return FloatSemantics::IEEEQuad;
- if (Keyword == "ppc_fp128")
- return FloatSemantics::PPCDoubleDouble;
- return std::nullopt;
-}
-
-[[nodiscard]] bool isFloatingSemanticsKeyword(const MIToken &Token) {
- return Token.kind() == MITokenKind::Keyword &&
- floatSemanticsForKeyword(Token.stringValue()).has_value();
-}
-
-[[nodiscard]] bool isCFIOperationToken(const MIToken &Token) {
- return Token.isKeyword("same_value") || Token.isKeyword("remember_state") ||
- Token.isKeyword("restore_state") || Token.isKeyword("offset") ||
- Token.isKeyword("llvm_def_aspace_cfa") || Token.isKeyword("def_cfa_register") ||
- Token.isKeyword("def_cfa_offset") || Token.isKeyword("def_cfa") ||
- Token.isKeyword("rel_offset") || Token.isKeyword("adjust_cfa_offset") ||
- Token.isKeyword("escape") || Token.isKeyword("restore") || Token.isKeyword("undefined") ||
- Token.isKeyword("register") || Token.isKeyword("window_save") ||
- Token.isKeyword("negate_ra_sign_state") ||
- Token.isKeyword("negate_ra_sign_state_with_pc") || Token.isKeyword("llvm_register_pair") ||
- Token.isKeyword("llvm_vector_registers") || Token.isKeyword("llvm_vector_offset") ||
- Token.isKeyword("llvm_vector_register_mask");
-}
-
-[[nodiscard]] Expected<IntegerImmediate> parseIntegerImmediateValue(std::uint32_t BitWidth,
- std::string_view Spelling) {
- if (BitWidth == 0 || BitWidth > IntegerImmediate::MaxBitWidth)
- return makeUnexpected(ErrorCode::ParseError, "typed integer width is out of range");
-
- const bool Negative = Spelling.starts_with('-');
- if (Negative)
- Spelling.remove_prefix(1);
- if (Spelling.empty())
- return makeUnexpected(ErrorCode::ParseError, "typed integer has no digits");
-
- std::vector<std::uint64_t> Words((static_cast<std::size_t>(BitWidth) + 63U) / 64U, 0);
- for (char Character : Spelling) {
- if (Character < '0' || Character > '9')
- return makeUnexpected(ErrorCode::ParseError, "typed integer 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 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) {
- 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;
- }
- if (BitWidth % 64U != 0)
- Words.back() &= (std::uint64_t{1} << (BitWidth % 64U)) - 1U;
- }
- return IntegerImmediate::create(BitWidth, Words);
-}
-
-[[nodiscard]] std::optional<std::uint64_t> minimumTypeSizeInBits(LLT Type) noexcept {
- if (!Type.isValid() || Type.isToken())
- return std::nullopt;
- const std::uint64_t ScalarSize = Type.scalarBitWidth();
- if (!Type.isVector())
- return ScalarSize;
- const std::uint64_t ElementCount = Type.minimumElementCount();
- if (ScalarSize != 0 && ElementCount > std::numeric_limits<std::uint64_t>::max() / ScalarSize)
- return std::nullopt;
- return ScalarSize * ElementCount;
-}
-
-[[nodiscard]] std::optional<AtomicOrdering> atomicOrdering(std::string_view Name) noexcept {
- if (Name == "unordered")
- return AtomicOrdering::Unordered;
- if (Name == "monotonic")
- return AtomicOrdering::Monotonic;
- if (Name == "acquire")
- return AtomicOrdering::Acquire;
- if (Name == "release")
- return AtomicOrdering::Release;
- if (Name == "acq_rel")
- return AtomicOrdering::AcquireRelease;
- if (Name == "seq_cst")
- return AtomicOrdering::SequentiallyConsistent;
- return std::nullopt;
-}
-
-[[nodiscard]] bool isInstructionFlag(const MIToken &Token) {
- return Token.isKeyword("frame-setup") || Token.isKeyword("frame-destroy") ||
- Token.isKeyword("nnan") || Token.isKeyword("ninf") || Token.isKeyword("nsz") ||
- Token.isKeyword("arcp") || Token.isKeyword("contract") || Token.isKeyword("afn") ||
- Token.isKeyword("reassoc") || Token.isKeyword("nuw") || Token.isKeyword("nsw") ||
- Token.isKeyword("nusw") || Token.isKeyword("exact") || Token.isKeyword("nofpexcept") ||
- Token.isKeyword("unpredictable") || Token.isKeyword("noconvergent") ||
- Token.isKeyword("nneg") || Token.isKeyword("disjoint") || Token.isKeyword("samesign") ||
- Token.isKeyword("inbounds");
-}
-
-[[nodiscard]] std::optional<MachineInstrFlag> instructionFlag(std::string_view Name) {
- if (Name == "frame-setup")
- return MachineInstrFlag::FrameSetup;
- if (Name == "frame-destroy")
- return MachineInstrFlag::FrameDestroy;
- if (Name == "nnan")
- return MachineInstrFlag::FastMathNoNaNs;
- if (Name == "ninf")
- return MachineInstrFlag::FastMathNoInfs;
- if (Name == "nsz")
- return MachineInstrFlag::FastMathNoSignedZeros;
- if (Name == "arcp")
- return MachineInstrFlag::FastMathAllowReciprocal;
- if (Name == "contract")
- return MachineInstrFlag::FastMathAllowContract;
- if (Name == "afn")
- return MachineInstrFlag::FastMathApproxFunc;
- if (Name == "reassoc")
- return MachineInstrFlag::FastMathAllowReassoc;
- if (Name == "nuw")
- return MachineInstrFlag::NoUnsignedWrap;
- if (Name == "nsw")
- return MachineInstrFlag::NoSignedWrap;
- if (Name == "nusw")
- return MachineInstrFlag::NoUSWrap;
- if (Name == "exact")
- return MachineInstrFlag::Exact;
- if (Name == "nofpexcept")
- return MachineInstrFlag::NoFPExcept;
- if (Name == "unpredictable")
- return MachineInstrFlag::Unpredictable;
- if (Name == "noconvergent")
- return MachineInstrFlag::NoConvergent;
- if (Name == "nneg")
- return MachineInstrFlag::NonNeg;
- if (Name == "disjoint")
- return MachineInstrFlag::Disjoint;
- if (Name == "samesign")
- return MachineInstrFlag::SameSign;
- if (Name == "inbounds")
- return MachineInstrFlag::InBounds;
- return std::nullopt;
-}
-
-[[nodiscard]] std::optional<IntegerPredicate> integerPredicate(std::string_view Name) {
- if (Name == "eq")
- return IntegerPredicate::Equal;
- if (Name == "ne")
- return IntegerPredicate::NotEqual;
- if (Name == "sgt")
- return IntegerPredicate::SignedGreaterThan;
- if (Name == "sge")
- return IntegerPredicate::SignedGreaterEqual;
- if (Name == "slt")
- return IntegerPredicate::SignedLessThan;
- if (Name == "sle")
- return IntegerPredicate::SignedLessEqual;
- if (Name == "ugt")
- return IntegerPredicate::UnsignedGreaterThan;
- if (Name == "uge")
- return IntegerPredicate::UnsignedGreaterEqual;
- if (Name == "ult")
- return IntegerPredicate::UnsignedLessThan;
- if (Name == "ule")
- return IntegerPredicate::UnsignedLessEqual;
- return std::nullopt;
-}
-
-[[nodiscard]] std::optional<FloatingPredicate> floatingPredicate(std::string_view Name) {
- if (Name == "false")
- return FloatingPredicate::AlwaysFalse;
- if (Name == "oeq")
- return FloatingPredicate::OrderedEqual;
- if (Name == "ogt")
- return FloatingPredicate::OrderedGreaterThan;
- if (Name == "oge")
- return FloatingPredicate::OrderedGreaterEqual;
- if (Name == "olt")
- return FloatingPredicate::OrderedLessThan;
- if (Name == "ole")
- return FloatingPredicate::OrderedLessEqual;
- if (Name == "one")
- return FloatingPredicate::OrderedNotEqual;
- if (Name == "ord")
- return FloatingPredicate::Ordered;
- if (Name == "uno")
- return FloatingPredicate::Unordered;
- if (Name == "ueq")
- return FloatingPredicate::UnorderedEqual;
- if (Name == "ugt")
- return FloatingPredicate::UnorderedGreaterThan;
- if (Name == "uge")
- return FloatingPredicate::UnorderedGreaterEqual;
- if (Name == "ult")
- return FloatingPredicate::UnorderedLessThan;
- if (Name == "ule")
- return FloatingPredicate::UnorderedLessEqual;
- if (Name == "une")
- return FloatingPredicate::UnorderedNotEqual;
- if (Name == "true")
- return FloatingPredicate::AlwaysTrue;
- return std::nullopt;
-}
-
-} // namespace
-
-class MIParser::Impl final {
-public:
- Impl(MachineFunction &Function, const TargetDescription &Target, std::string SourceName,
- std::string SourceText, MIParserContext Context, MIParserOptions Options)
- : Function(Function), Target(Target),
- Lexer(std::move(SourceName), std::move(SourceText),
- MILexerOptions{.MaximumTokenLength = Options.MaximumTokenLength,
- .MaximumTokens = Options.MaximumTokens}),
- Context(std::move(Context)), Options(Options) {}
-
- [[nodiscard]] Expected<void> parse();
-
- [[nodiscard]] const TextSource &source() const noexcept {
- return Lexer.source();
- }
-
- [[nodiscard]] std::span<const TextDiagnostic> diagnostics() const noexcept {
- return Diagnostics;
- }
-
- [[nodiscard]] bool failed() const noexcept {
- return !Diagnostics.empty();
- }
-
-private:
- struct ParsedOperand final {
- MachineOperand Operand;
- std::optional<std::size_t> TiedDef;
- TextRange Range;
- };
-
- [[nodiscard]] const MIToken &token() const noexcept {
- return Tokens[Position];
- }
-
- [[nodiscard]] bool at(MITokenKind Kind) const noexcept {
- return token().is(Kind);
- }
-
- [[nodiscard]] bool nextIs(MITokenKind Kind) const noexcept {
- return Position + 1U < Tokens.size() && Tokens[Position + 1U].is(Kind);
- }
-
- [[nodiscard]] bool atKeyword(std::string_view Keyword) const noexcept {
- return token().isKeyword(Keyword);
- }
-
- void advance() noexcept {
- if (!at(MITokenKind::EndOfFile))
- ++Position;
- }
-
- [[nodiscard]] bool consume(MITokenKind Kind) noexcept {
- if (!at(Kind))
- return false;
- advance();
- return true;
- }
-
- [[nodiscard]] bool expect(MITokenKind Kind, std::string_view Description);
- [[nodiscard]] bool fail(const MIToken &At, std::string Message);
- [[nodiscard]] bool fail(std::string Message) {
- return fail(token(), std::move(Message));
- }
- [[nodiscard]] Expected<void> failureResult() const;
- [[nodiscard]] bool importError(const MIToken &At, const Error &Failure);
- [[nodiscard]] bool tokenize();
-
- [[nodiscard]] bool parseUnsigned(const MIToken &Token, std::uint64_t &Value);
- [[nodiscard]] bool parseUnsigned32(const MIToken &Token, std::uint32_t &Value);
- [[nodiscard]] bool parseSigned64(const MIToken &Token, std::int64_t &Value);
- [[nodiscard]] bool parseOptionalOffset(std::int64_t &Offset);
- [[nodiscard]] bool parseAlignment(Alignment &Result);
- [[nodiscard]] bool parseLowLevelType(LLT &Result);
- [[nodiscard]] bool parseScalarLowLevelType(const MIToken &Token, LLT &Result);
-
- [[nodiscard]] bool parseFirstPass();
- [[nodiscard]] bool parseSecondPass();
- [[nodiscard]] bool parseBlockDefinition(bool Create, std::uint32_t &ID);
- [[nodiscard]] bool parseBlockAttributes(MachineBasicBlock *Block);
- [[nodiscard]] bool parseBlockLiveIns(MachineBasicBlock &Block);
- [[nodiscard]] bool parseBlockSuccessors(MachineBasicBlock &Block);
- [[nodiscard]] bool parseInstruction(MachineBasicBlock &Block, bool InBundle,
- MachineInstr *PreviousInstruction, MachineInstr *&Result);
- [[nodiscard]] bool inferSuccessors();
-
- [[nodiscard]] bool parseRegister(Register &Result);
- [[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);
- [[nodiscard]] bool parseMetadataOperand(ParsedOperand &Result);
- [[nodiscard]] bool
- parseInlineDILocation(std::vector<MachineDILocationFrame> &InlineChain,
- std::optional<MachineMetadataReference> &TerminalInlinedAt);
- [[nodiscard]] bool parseCFIRegister(DwarfRegisterNumber &Result);
- [[nodiscard]] bool parseCFISigned(std::int64_t &Result);
- [[nodiscard]] bool parseCFIUnsigned(std::uint32_t &Result);
- [[nodiscard]] bool parseCFIOperand(ParsedOperand &Result);
- [[nodiscard]] bool parseMemoryBase(MemoryBase &Result, std::int64_t &Offset);
- [[nodiscard]] bool parseMemoryOperand(const MachineMemOperand *&Result, Opcode InstructionOpcode);
- [[nodiscard]] bool parsePredicateOperand(ParsedOperand &Result, bool IsFloating);
- [[nodiscard]] bool parseShuffleMaskOperand(ParsedOperand &Result);
- [[nodiscard]] bool parseDebugInstrRefOperand(ParsedOperand &Result);
- [[nodiscard]] bool parseLaneMaskOperand(ParsedOperand &Result);
- [[nodiscard]] bool parseIntrinsicOperand(ParsedOperand &Result);
- [[nodiscard]] bool parseTargetIndexOperand(ParsedOperand &Result);
- [[nodiscard]] bool parseLiveOutMaskOperand(ParsedOperand &Result);
- [[nodiscard]] bool parseCustomMaskOperand(ParsedOperand &Result);
- [[nodiscard]] bool parseBlockAddressOperand(ParsedOperand &Result);
-
- [[nodiscard]] Register getOrCreateVirtualRegister(const MIToken &Token);
- [[nodiscard]] MachineBasicBlock *blockFor(const MIToken &Token);
- [[nodiscard]] std::optional<FrameIndex> frameIndexFor(const MIToken &Token, bool Fixed);
- [[nodiscard]] std::optional<ConstantPoolIndex> constantPoolIndexFor(const MIToken &Token);
- [[nodiscard]] std::optional<JumpTableIndex> jumpTableIndexFor(const MIToken &Token);
- [[nodiscard]] std::string symbolName(const MIToken &Token) const;
-
- MachineFunction &Function;
- const TargetDescription &Target;
- MILexer Lexer;
- MIParserContext Context;
- MIParserOptions Options;
- std::vector<MIToken> Tokens;
- std::size_t Position = 0;
- std::vector<TextDiagnostic> Diagnostics;
- std::unordered_map<std::uint32_t, MachineBasicBlock *> Blocks;
- std::unordered_map<std::uint32_t, Register> NumericVirtualRegisters;
- std::unordered_map<std::string, Register> NamedVirtualRegisters;
- std::unordered_set<MachineBasicBlock *> ExplicitSuccessorBlocks;
- std::size_t ParsedInstructionCount = 0;
- bool ParseAttempted = false;
-};
-
-bool MIParser::Impl::expect(MITokenKind Kind, std::string_view Description) {
- if (consume(Kind))
- return false;
- return fail("expected " + std::string(Description) + ", found " +
- std::string(getMITokenKindName(token().kind())));
-}
-
-bool MIParser::Impl::fail(const MIToken &At, std::string Message) {
- if (Diagnostics.empty()) {
- Diagnostics.push_back(TextDiagnostic{
- .Severity = DiagnosticSeverity::Error,
- .Category = "mir-parser",
- .Message = std::move(Message),
- .SourceName = std::string(Lexer.source().name()),
- .Range = At.range(),
- });
- }
- return true;
-}
-
-Expected<void> MIParser::Impl::failureResult() const {
- const std::string Message =
- Diagnostics.empty() ? "machine instruction parsing failed" : Diagnostics.front().Message;
- return makeUnexpected(ErrorCode::ParseError, Message);
-}
-
-bool MIParser::Impl::importError(const MIToken &At, const Error &Failure) {
- return fail(At, std::string(Failure.message()));
-}
-
-bool MIParser::Impl::tokenize() {
- while (true) {
- MIToken Token = Lexer.next();
- const MITokenKind Kind = Token.kind();
- Tokens.push_back(std::move(Token));
- if (Kind == MITokenKind::Error) {
- const auto LexerDiagnostics = Lexer.diagnostics();
- Diagnostics.assign(LexerDiagnostics.begin(), LexerDiagnostics.end());
- return true;
- }
- if (Kind == MITokenKind::EndOfFile)
- return false;
- }
-}
-
-bool MIParser::Impl::parseUnsigned(const MIToken &Token, std::uint64_t &Value) {
- if (Token.kind() == MITokenKind::HexLiteral)
- return !parseHexadecimal(Token.spelling(), Value);
- if (Token.hasIntegerValue())
- return !parseUnsignedDecimal(Token.integerValue(), Value);
- return true;
-}
-
-bool MIParser::Impl::parseUnsigned32(const MIToken &Token, std::uint32_t &Value) {
- std::uint64_t Wide = 0;
- if (parseUnsigned(Token, Wide) || Wide > std::numeric_limits<std::uint32_t>::max())
- return true;
- Value = static_cast<std::uint32_t>(Wide);
- return false;
-}
-
-bool MIParser::Impl::parseSigned64(const MIToken &Token, std::int64_t &Value) {
- if (Token.kind() != MITokenKind::IntegerLiteral)
- return true;
- if (parseSignedDecimal(Token.integerValue(), Value))
- return false;
- std::uint64_t Unsigned = 0;
- if (!parseUnsignedDecimal(Token.integerValue(), Unsigned))
- return true;
- Value = std::bit_cast<std::int64_t>(Unsigned);
- return false;
-}
-
-bool MIParser::Impl::parseOptionalOffset(std::int64_t &Offset) {
- Offset = 0;
- if (!at(MITokenKind::Plus) && !at(MITokenKind::Minus))
- return false;
- const bool Negative = at(MITokenKind::Minus);
- advance();
- std::uint64_t Magnitude = 0;
- if (!at(MITokenKind::IntegerLiteral) || parseUnsigned(token(), Magnitude) ||
- Magnitude > (std::uint64_t{1} << 63U)) {
- return fail("expected a 64-bit integer offset");
- }
- if (Negative) {
- if (Magnitude == (std::uint64_t{1} << 63U))
- Offset = std::numeric_limits<std::int64_t>::min();
- else
- Offset = -static_cast<std::int64_t>(Magnitude);
- } else {
- if (Magnitude > static_cast<std::uint64_t>(std::numeric_limits<std::int64_t>::max()))
- return fail("positive offset exceeds signed 64-bit range");
- Offset = static_cast<std::int64_t>(Magnitude);
- }
- advance();
- return false;
-}
-
-bool MIParser::Impl::parseAlignment(Alignment &Result) {
- advance();
- std::uint64_t Bytes = 0;
- if (!at(MITokenKind::IntegerLiteral) || parseUnsigned(token(), Bytes))
- return fail("expected an unsigned alignment");
- auto Parsed = Alignment::create(Bytes);
- if (!Parsed)
- return importError(token(), Parsed.error());
- Result = *Parsed;
- advance();
- return false;
-}
-
-bool MIParser::Impl::parseScalarLowLevelType(const MIToken &TypeToken, LLT &Result) {
- if (TypeToken.kind() != MITokenKind::Identifier)
- return fail(TypeToken, "expected a scalar low-level type");
- std::string_view Spelling = TypeToken.stringValue();
- enum class ScalarKind : std::uint8_t {
- Any,
- Integer,
- Float,
- BFloat,
- Pointer,
- };
- ScalarKind Kind = ScalarKind::Any;
- std::string_view Digits;
- if (Spelling.starts_with("bf")) {
- Kind = ScalarKind::BFloat;
- Digits = Spelling.substr(2);
- } else if (Spelling.starts_with('s')) {
- Kind = ScalarKind::Any;
- Digits = Spelling.substr(1);
- } else if (Spelling.starts_with('i')) {
- Kind = ScalarKind::Integer;
- Digits = Spelling.substr(1);
- } else if (Spelling.starts_with('f')) {
- Kind = ScalarKind::Float;
- Digits = Spelling.substr(1);
- } else if (Spelling.starts_with('p')) {
- Kind = ScalarKind::Pointer;
- Digits = Spelling.substr(1);
- } else {
- return fail(TypeToken, "unknown scalar low-level type '" + std::string(Spelling) + "'");
- }
-
- std::uint64_t Value = 0;
- if (!parseUnsignedDigits(Digits, Value))
- 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) {
- case ScalarKind::Any:
- if (Value == 0) {
- Result = LLT::token();
- return false;
- }
- Created = LLT::makeAnyScalar(Value);
- break;
- case ScalarKind::Integer:
- Created = LLT::makeInteger(Value);
- break;
- case ScalarKind::Float: {
- std::optional<FloatSemantics> Semantics;
- if (Value == 16)
- Semantics = FloatSemantics::IEEEHalf;
- else if (Value == 32)
- Semantics = FloatSemantics::IEEESingle;
- else if (Value == 64)
- Semantics = FloatSemantics::IEEEDouble;
- else if (Value == 128)
- Semantics = FloatSemantics::IEEEQuad;
- if (!Semantics)
- return fail(TypeToken, "unsupported IEEE floating low-level type width");
- Created = LLT::makeFloat(*Semantics);
- break;
- }
- case ScalarKind::BFloat:
- if (Value != 16)
- return fail(TypeToken, "bfloat low-level type must have width 16");
- Created = LLT::makeFloat(FloatSemantics::BFloat);
- break;
- case ScalarKind::Pointer:
- if (!Context.PointerSizeInBits)
- return fail(TypeToken, "pointer low-level type requires an explicit pointer size");
- if (auto PointerSize = Context.PointerSizeInBits(static_cast<std::uint32_t>(Value)))
- Created = LLT::makePointer(Value, *PointerSize);
- else
- return importError(TypeToken, PointerSize.error());
- break;
- }
- if (!Created)
- return importError(TypeToken, Created.error());
- Result = *Created;
- return false;
-}
-
-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 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 <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 VectorError();
- advance();
- if (!at(MITokenKind::Identifier) || token().stringValue() != "x")
- 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 (!consume(MITokenKind::Greater))
- return VectorError();
-
- Expected<LLT> Created = Scalable ? LLT::makeScalableVector(ElementCount, ElementType)
- : LLT::makeFixedVector(ElementCount, ElementType);
- if (!Created)
- return importError(Begin, Created.error());
- Result = *Created;
- return false;
-}
-
-bool MIParser::Impl::parseBlockAttributes(MachineBasicBlock *Block) {
- std::unordered_set<std::string> Seen;
- while (!at(MITokenKind::RightParen)) {
- const MIToken AttributeToken = token();
- if (atKeyword("machine-block-address-taken") || atKeyword("landing-pad") ||
- atKeyword("inlineasm-br-indirect-target") || atKeyword("ehfunclet-entry") ||
- atKeyword("ehscope-entry")) {
- const std::string Name(AttributeToken.stringValue());
- if (!Seen.insert(Name).second)
- return fail("duplicate basic block attribute '" + Name + "'");
- if (Block != nullptr) {
- if (Name == "machine-block-address-taken")
- Block->attributes().set(MachineBasicBlockAttribute::MachineBlockAddressTaken);
- else if (Name == "landing-pad")
- Block->attributes().set(MachineBasicBlockAttribute::LandingPad);
- else if (Name == "inlineasm-br-indirect-target")
- Block->attributes().set(MachineBasicBlockAttribute::InlineAsmBrIndirectTarget);
- else if (Name == "ehfunclet-entry")
- Block->attributes().set(MachineBasicBlockAttribute::EHFuncletEntry);
- else
- Block->attributes().set(MachineBasicBlockAttribute::EHScopeEntry);
- }
- advance();
- } else if (atKeyword("ir-block-address-taken")) {
- if (!Seen.insert("ir-block-address-taken").second)
- return fail("duplicate basic block attribute 'ir-block-address-taken'");
- advance();
- if (!at(MITokenKind::IRBlock) && !at(MITokenKind::NamedIRBlock))
- return fail("expected an IR block after 'ir-block-address-taken'");
- if (Block != nullptr) {
- Block->attributes().set(MachineBasicBlockAttribute::IRBlockAddressTaken);
- auto SetName = Block->attributes().setIRBlockName(symbolName(token()));
- if (!SetName)
- return importError(token(), SetName.error());
- }
- advance();
- } 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)
- return importError(token(), SetName.error());
- }
- advance();
- } else if (atKeyword("align")) {
- if (!Seen.insert("align").second)
- return fail("duplicate basic block alignment");
- Alignment Align;
- if (parseAlignment(Align))
- return true;
- if (Block != nullptr)
- Block->attributes().setAlignment(Align);
- } else if (atKeyword("bbsections")) {
- if (!Seen.insert("bbsections").second)
- return fail("duplicate basic block section");
- advance();
- MachineBasicBlockSectionID Section;
- std::uint32_t Number = 0;
- if (at(MITokenKind::IntegerLiteral) && !parseUnsigned32(token(), Number))
- Section = MachineBasicBlockSectionID::numbered(Number);
- else if (at(MITokenKind::Identifier) && token().stringValue() == "Exception")
- Section = MachineBasicBlockSectionID::exception();
- else if (at(MITokenKind::Identifier) && token().stringValue() == "Cold")
- Section = MachineBasicBlockSectionID::cold();
- else
- return fail("unknown basic block section ID");
- if (Block != nullptr)
- Block->attributes().setSectionID(Section);
- advance();
- } else if (atKeyword("bb_id")) {
- if (!Seen.insert("bb_id").second)
- return fail("duplicate basic block profile ID");
- advance();
- std::uint32_t BaseID = 0;
- std::uint32_t CloneID = 0;
- if (at(MITokenKind::FloatingPointLiteral)) {
- const std::string_view Spelling = token().spelling();
- const std::size_t Dot = Spelling.find('.');
- std::uint64_t Base = 0;
- std::uint64_t Clone = 0;
- if (Dot == std::string_view::npos || !parseUnsignedDecimal(Spelling.substr(0, Dot), Base) ||
- !parseUnsignedDecimal(Spelling.substr(Dot + 1), Clone) ||
- Base > std::numeric_limits<std::uint32_t>::max() ||
- Clone > std::numeric_limits<std::uint32_t>::max()) {
- return fail("invalid basic block profile ID");
- }
- BaseID = static_cast<std::uint32_t>(Base);
- CloneID = static_cast<std::uint32_t>(Clone);
- advance();
- } else {
- if (!at(MITokenKind::IntegerLiteral) || parseUnsigned32(token(), BaseID))
- return fail("invalid basic block base ID");
- advance();
- if (consume(MITokenKind::Dot) || consume(MITokenKind::Comma)) {
- if (!at(MITokenKind::IntegerLiteral) || parseUnsigned32(token(), CloneID))
- return fail("invalid basic block clone ID");
- advance();
- }
- }
- if (Block != nullptr)
- Block->attributes().setProfileID({BaseID, CloneID});
- } else if (atKeyword("call-frame-size")) {
- if (!Seen.insert("call-frame-size").second)
- return fail("duplicate basic block call frame size");
- advance();
- std::uint32_t Size = 0;
- if (!at(MITokenKind::IntegerLiteral) || parseUnsigned32(token(), Size))
- return fail("invalid basic block call frame size");
- if (Block != nullptr)
- Block->attributes().setCallFrameSize(Size);
- advance();
- } else {
- return fail("unknown basic block attribute '" + std::string(token().spelling()) + "'");
- }
-
- if (!consume(MITokenKind::Comma))
- break;
- }
- return expect(MITokenKind::RightParen, "')'");
-}
-
-bool MIParser::Impl::parseBlockDefinition(bool Create, std::uint32_t &ID) {
- const MIToken Label = token();
- if (!at(MITokenKind::MachineBasicBlockLabel) || parseUnsigned32(Label, ID))
- return fail("invalid machine basic block label");
- advance();
-
- MachineBasicBlock *Block = nullptr;
- if (Create) {
- 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 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());
- Block = *Created;
- auto Appended = Function.appendBlock(*Block);
- if (!Appended)
- return importError(Label, Appended.error());
- if (!Label.stringValue().empty()) {
- auto SetName = Block->attributes().setName(std::string(Label.stringValue()));
- if (!SetName)
- return importError(Label, SetName.error());
- }
- Blocks.emplace(ID, Block);
- } else {
- const auto Found = Blocks.find(ID);
- if (Found == Blocks.end())
- return fail(Label, "use of undefined machine basic block #" + std::to_string(ID));
- Block = Found->second;
- }
-
- if (consume(MITokenKind::LeftParen) && parseBlockAttributes(Create ? Block : nullptr))
- return true;
- return expect(MITokenKind::Colon, "':' after the basic block definition");
-}
-
-bool MIParser::Impl::parseFirstPass() {
- Position = 0;
- bool AtLineStart = true;
- std::size_t BraceDepth = 0;
- while (!at(MITokenKind::EndOfFile)) {
- if (consume(MITokenKind::Newline)) {
- AtLineStart = true;
- continue;
- }
- if (at(MITokenKind::MachineBasicBlockLabel)) {
- if (!AtLineStart || token().range().Begin.Column != 1)
- return fail("basic block definition must be at the start of a line");
- std::uint32_t ID = 0;
- if (parseBlockDefinition(true, ID))
- return true;
- AtLineStart = false;
- continue;
- }
- if (at(MITokenKind::LeftBrace))
- ++BraceDepth;
- else if (at(MITokenKind::RightBrace)) {
- if (BraceDepth == 0)
- return fail("extraneous closing instruction bundle brace");
- --BraceDepth;
- }
- AtLineStart = false;
- advance();
- }
- if (BraceDepth != 0)
- return fail("unterminated instruction bundle");
- return false;
-}
-
-Register MIParser::Impl::getOrCreateVirtualRegister(const MIToken &Token) {
- if (Token.kind() == MITokenKind::VirtualRegister) {
- std::uint32_t ID = 0;
- if (parseUnsigned32(Token, ID))
- return {};
- if (const auto Found = NumericVirtualRegisters.find(ID);
- Found != NumericVirtualRegisters.end()) {
- return Found->second;
- }
- auto Created = Function.registerInfo().createVirtualRegister();
- if (!Created) {
- static_cast<void>(importError(Token, Created.error()));
- return {};
- }
- NumericVirtualRegisters.emplace(ID, *Created);
- return *Created;
- }
-
- const std::string Name(Token.stringValue());
- if (const auto Found = NamedVirtualRegisters.find(Name); Found != NamedVirtualRegisters.end())
- return Found->second;
- auto Created = Function.registerInfo().createVirtualRegister();
- if (!Created) {
- 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;
-}
-
-bool MIParser::Impl::parseRegister(Register &Result) {
- const MIToken RegisterToken = token();
- if (consume(MITokenKind::Underscore)) {
- Result = {};
- return false;
- }
- if (at(MITokenKind::NamedRegister)) {
- if (RegisterToken.stringValue() == "noreg") {
- Result = {};
- advance();
- return false;
- }
- const PhysicalRegisterDesc *Description =
- Target.registers().physicalRegister(RegisterToken.stringValue());
- if (Description == nullptr)
- return fail("unknown physical register '$" + std::string(RegisterToken.stringValue()) + "'");
- Result = Register::fromPhysical(Description->Reg);
- advance();
- return false;
- }
- if (at(MITokenKind::VirtualRegister) || at(MITokenKind::NamedVirtualRegister)) {
- Result = getOrCreateVirtualRegister(RegisterToken);
- if (Result.isNoRegister())
- return true;
- advance();
- return false;
- }
- return fail("expected a machine register");
-}
-
-bool MIParser::Impl::parseRegisterOperand(bool IsDef, ParsedOperand &Result) {
- const MIToken Begin = token();
- RegisterOperandFlags Flags{IsDef ? RegisterOperandFlag::Define : RegisterOperandFlag::Use};
- std::unordered_set<std::string> SeenFlags;
- while (token().isRegisterFlag()) {
- const std::string Name(token().stringValue());
- if (!SeenFlags.insert(Name).second)
- return fail("duplicate '" + Name + "' register flag");
- if (Name == "implicit")
- Flags.set(RegisterOperandFlag::Implicit);
- else if (Name == "implicit-def") {
- Flags.clear(RegisterOperandFlag::Use);
- Flags.set(RegisterOperandFlag::Define);
- Flags.set(RegisterOperandFlag::Implicit);
- IsDef = true;
- } else if (Name == "def") {
- Flags.clear(RegisterOperandFlag::Use);
- Flags.set(RegisterOperandFlag::Define);
- IsDef = true;
- } else if (Name == "dead")
- Flags.set(RegisterOperandFlag::Dead);
- else if (Name == "killed")
- Flags.set(RegisterOperandFlag::Kill);
- else if (Name == "undef")
- Flags.set(RegisterOperandFlag::Undef);
- else if (Name == "internal")
- Flags.set(RegisterOperandFlag::InternalRead);
- else if (Name == "early-clobber")
- Flags.set(RegisterOperandFlag::EarlyClobber);
- else if (Name == "debug-use")
- Flags.set(RegisterOperandFlag::Debug);
- else if (Name == "renamable")
- Flags.set(RegisterOperandFlag::Renamable);
- advance();
- }
-
- Register Reg;
- if (parseRegister(Reg))
- return true;
-
- SubRegIndex SubReg;
- if (consume(MITokenKind::Dot)) {
- if (!Reg.isVirtual() || !at(MITokenKind::Identifier))
- return fail("subregister index requires a virtual register");
- const SubRegIndexDesc *Description = Target.registers().subRegIndex(token().stringValue());
- if (Description == nullptr)
- return fail("unknown subregister index '" + std::string(token().stringValue()) + "'");
- SubReg = Description->ID;
- advance();
- }
-
- if (consume(MITokenKind::Colon)) {
- if (!Reg.isVirtual())
- return fail("register class or bank requires a virtual register");
- auto InfoResult = Function.registerInfo().virtualRegisterInfo(Reg);
- if (!InfoResult)
- return importError(Begin, InfoResult.error());
- VirtualRegisterInfo &Info = InfoResult->get();
- if (consume(MITokenKind::Underscore)) {
- if (Info.RegClass || Info.Bank)
- return fail("conflicting generic virtual register constraint");
- } else if (at(MITokenKind::Identifier)) {
- if (const RegisterClassDesc *Class =
- Target.registers().registerClass(token().stringValue())) {
- if ((Info.RegClass && *Info.RegClass != Class->ID) ||
- (Info.Bank && *Info.Bank != Class->DefaultBank))
- return fail("conflicting virtual register class");
- auto SetClass = Function.registerInfo().setRegisterClass(Reg, Class->ID);
- if (!SetClass)
- return importError(token(), SetClass.error());
- auto SetBank = Function.registerInfo().setRegisterBank(Reg, Class->DefaultBank);
- if (!SetBank)
- return importError(token(), SetBank.error());
- } else if (const RegisterBankDesc *Bank =
- Target.registers().registerBank(token().stringValue())) {
- const RegisterClassDesc *ExistingClass =
- Info.RegClass ? Target.registers().registerClass(*Info.RegClass) : nullptr;
- if ((Info.Bank && *Info.Bank != Bank->ID) ||
- (Info.RegClass && (ExistingClass == nullptr || ExistingClass->DefaultBank != Bank->ID)))
- return fail("conflicting virtual register bank");
- auto SetBank = Function.registerInfo().setRegisterBank(Reg, Bank->ID);
- if (!SetBank)
- return importError(token(), SetBank.error());
- } else {
- return fail("unknown register class or bank '" + std::string(token().stringValue()) + "'");
- }
- advance();
- } else {
- return fail("expected '_', register class, or register bank name");
- }
- }
-
- std::optional<std::size_t> TiedDef;
- if (consume(MITokenKind::LeftParen)) {
- if (atKeyword("tied-def")) {
- if (IsDef)
- return fail("'tied-def' is only valid on register uses");
- advance();
- std::uint64_t Index = 0;
- if (!at(MITokenKind::IntegerLiteral) || parseUnsigned(token(), Index) ||
- Index > std::numeric_limits<std::size_t>::max()) {
- return fail("invalid tied-def operand index");
- }
- TiedDef = static_cast<std::size_t>(Index);
- advance();
- if (expect(MITokenKind::RightParen, "')' after tied-def"))
- return true;
- } else {
- if (!Reg.isVirtual())
- return fail("low-level type is only valid on a virtual register");
- LLT Type;
- if (parseLowLevelType(Type))
- return true;
- if (expect(MITokenKind::RightParen, "')' after the low-level type"))
- return true;
- auto InfoResult = Function.registerInfo().virtualRegisterInfo(Reg);
- if (!InfoResult)
- return importError(Begin, InfoResult.error());
- VirtualRegisterInfo &Info = InfoResult->get();
- if (Info.Type && *Info.Type != Type)
- return fail(Begin, "conflicting virtual register low-level type");
- auto SetType = Function.registerInfo().setType(Reg, Type);
- if (!SetType)
- return importError(Begin, SetType.error());
- }
- }
-
- if (IsDef && Reg.isVirtual()) {
- auto InfoResult = Function.registerInfo().virtualRegisterInfo(Reg);
- if (!InfoResult)
- return importError(Begin, InfoResult.error());
- const VirtualRegisterInfo &Info = InfoResult->get();
- if (!Info.RegClass && !Info.Type)
- return fail(Begin, "generic virtual register definition requires a low-level type");
- }
-
- if (Flags.has(RegisterOperandFlag::Define) && Flags.has(RegisterOperandFlag::Kill))
- return fail(Begin, "defined register operand cannot be killed");
- if (!Flags.has(RegisterOperandFlag::Define) && Flags.has(RegisterOperandFlag::Dead))
- return fail(Begin, "register use cannot be dead");
-
- auto Operand = MachineOperand::registerOperand(Reg, Flags, SubReg);
- if (!Operand)
- return importError(Begin, Operand.error());
- Result =
- ParsedOperand{std::move(*Operand), TiedDef, {Begin.range().Begin, token().range().Begin}};
- return false;
-}
-
-MachineBasicBlock *MIParser::Impl::blockFor(const MIToken &Token) {
- std::uint32_t ID = 0;
- if (parseUnsigned32(Token, ID)) {
- static_cast<void>(fail(Token, "invalid machine basic block reference"));
- return nullptr;
- }
- const auto Found = Blocks.find(ID);
- if (Found == Blocks.end()) {
- static_cast<void>(fail(Token, "use of undefined machine basic block #" + std::to_string(ID)));
- return nullptr;
- }
- if (!Token.stringValue().empty()) {
- const std::optional<std::string_view> Name = Found->second->attributes().name();
- if (!Name || *Name != Token.stringValue()) {
- static_cast<void>(fail(Token, "machine basic block reference has a mismatched name"));
- return nullptr;
- }
- }
- return Found->second;
-}
-
-std::optional<FrameIndex> MIParser::Impl::frameIndexFor(const MIToken &Token, bool Fixed) {
- std::uint32_t ID = 0;
- if (parseUnsigned32(Token, ID)) {
- static_cast<void>(fail(Token, "invalid stack object reference"));
- return std::nullopt;
- }
- const auto &Slots = Fixed ? Context.FixedStackObjects : Context.StackObjects;
- for (const MIFrameObjectSlot &Slot : Slots) {
- if (Slot.TextID != ID)
- continue;
- if (!Token.stringValue().empty() && (!Slot.Name || *Slot.Name != Token.stringValue())) {
- static_cast<void>(fail(Token, "stack object reference has a mismatched name"));
- return std::nullopt;
- }
- if (Function.frameInfo().object(Slot.Index) == nullptr) {
- static_cast<void>(fail(Token, "stack object slot maps to a missing frame object"));
- return std::nullopt;
- }
- return Slot.Index;
- }
- static_cast<void>(fail(Token, std::string("use of undefined ") +
- (Fixed ? "fixed stack" : "stack") + " object #" +
- std::to_string(ID)));
- return std::nullopt;
-}
-
-std::optional<ConstantPoolIndex> MIParser::Impl::constantPoolIndexFor(const MIToken &Token) {
- std::uint32_t ID = 0;
- if (parseUnsigned32(Token, ID)) {
- static_cast<void>(fail(Token, "invalid constant pool reference"));
- return std::nullopt;
- }
- for (const MIConstantPoolSlot &Slot : Context.ConstantPoolItems) {
- if (Slot.TextID == ID && Function.constantPool().entry(Slot.Index) != nullptr)
- return Slot.Index;
- }
- static_cast<void>(fail(Token, "use of undefined constant pool item #" + std::to_string(ID)));
- return std::nullopt;
-}
-
-std::optional<JumpTableIndex> MIParser::Impl::jumpTableIndexFor(const MIToken &Token) {
- std::uint32_t ID = 0;
- if (parseUnsigned32(Token, ID)) {
- static_cast<void>(fail(Token, "invalid jump table reference"));
- return std::nullopt;
- }
- for (const MIJumpTableSlot &Slot : Context.JumpTables) {
- if (Slot.TextID == ID && (Function.jumpTableInfo().table(Slot.Index) != nullptr ||
- (Slot.Index.value() < Function.jumpTableInfo().tables().size() &&
- Function.jumpTableInfo().tables()[Slot.Index.value()].isPending())))
- return Slot.Index;
- }
- static_cast<void>(fail(Token, "use of undefined jump table #" + std::to_string(ID)));
- return std::nullopt;
-}
-
-std::string MIParser::Impl::symbolName(const MIToken &Token) const {
- if (Token.hasStringValue())
- return std::string(Token.stringValue());
- return std::string(Token.integerValue());
-}
-
-bool MIParser::Impl::parseTargetFlags(std::uint32_t &Flags) {
- Flags = 0;
- if (!atKeyword("target-flags"))
- return false;
- advance();
- if (expect(MITokenKind::LeftParen, "'(' after target-flags"))
- return true;
- if (!at(MITokenKind::Identifier))
- return fail("expected a target flag name");
-
- const std::string First(token().stringValue());
- if (const auto Direct = Target.mirText().directOperandFlag(First))
- Flags = *Direct;
- else if (const auto Bit = Target.mirText().bitmaskOperandFlag(First))
- Flags = *Bit;
- else
- return fail("unknown target operand flag '" + First + "'");
- advance();
-
- std::unordered_set<std::string> Seen{First};
- while (consume(MITokenKind::Comma)) {
- if (!at(MITokenKind::Identifier))
- return fail("expected a target bit flag name");
- const std::string Name(token().stringValue());
- const auto Bit = Target.mirText().bitmaskOperandFlag(Name);
- if (!Bit)
- return fail("unknown target bit operand flag '" + Name + "'");
- if (!Seen.insert(Name).second || (Flags & *Bit) == *Bit)
- return fail("duplicate target operand flag '" + Name + "'");
- Flags |= *Bit;
- advance();
- }
- if (expect(MITokenKind::RightParen, "')' after target flags"))
- return true;
- const auto Valid = Target.mirText().validateOperandFlags(Flags);
- return !Valid && importError(token(), Valid.error());
-}
-
-bool MIParser::Impl::parseTypedIntegerOperand(ParsedOperand &Result) {
- const MIToken Begin = token();
- const std::string_view TypeSpelling = Begin.stringValue();
- if (!TypeSpelling.starts_with('i'))
- 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) {
- return fail(Begin, "typed integer operand has an invalid bit width");
- }
- const auto BitWidth = static_cast<std::uint32_t>(WideBitWidth);
- advance();
-
- std::string_view ValueSpelling;
- if (at(MITokenKind::IntegerLiteral)) {
- ValueSpelling = token().integerValue();
- } else if (at(MITokenKind::Identifier) && token().stringValue() == "true") {
- ValueSpelling = "1";
- } else if (at(MITokenKind::Identifier) && token().stringValue() == "false") {
- ValueSpelling = "0";
- } else {
- return fail("expected a decimal integer, true, or false after the typed integer type");
- }
-
- auto Value = parseIntegerImmediateValue(BitWidth, ValueSpelling);
- if (!Value)
- return importError(token(), Value.error());
- advance();
- Result = ParsedOperand{
- MachineOperand::integerImmediate(std::move(*Value)),
- std::nullopt,
- {Begin.range().Begin, token().range().Begin},
- };
- return false;
-}
-
-bool MIParser::Impl::parseFloatingImmediateOperand(ParsedOperand &Result) {
- const MIToken Begin = token();
- const auto Semantics = floatSemanticsForKeyword(Begin.stringValue());
- if (!Semantics)
- return fail(Begin, "unknown floating-point immediate type");
- advance();
- if (!at(MITokenKind::FloatingPointLiteral) && !at(MITokenKind::HexLiteral))
- return fail("expected a floating-point literal");
-
- const MIToken Literal = token();
- 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(*Constant->FloatingValue),
- std::nullopt,
- {Begin.range().Begin, token().range().Begin},
- };
- return false;
-}
-
-bool MIParser::Impl::parseMetadataReference(MachineMetadataReference &Result) {
- const MIToken Begin = token();
- if (expect(MITokenKind::Exclaim, "'!' before a metadata slot"))
- return true;
- std::uint32_t TextID = 0;
- if (!at(MITokenKind::IntegerLiteral) || parseUnsigned32(token(), TextID))
- return fail("expected a 32-bit metadata slot number");
-
- for (const MIMetadataSlot &Slot : Context.Metadata) {
- if (Slot.TextID != TextID)
- continue;
- if (!Slot.Reference.isValid())
- return fail(Begin, "metadata slot maps to an invalid reference");
- Result = Slot.Reference;
- advance();
- return false;
- }
- if (Function.metadata().node(TextID) != nullptr) {
- Result = MachineMetadataReference::machineFunction(TextID);
- advance();
- return false;
- }
- return fail(Begin, "use of undefined metadata slot !" + std::to_string(TextID));
-}
-
-bool MIParser::Impl::parseMetadataOperand(ParsedOperand &Result) {
- const MIToken Begin = token();
- MachineMetadataValue Value;
- if (at(MITokenKind::Exclaim)) {
- MachineMetadataReference Reference;
- if (parseMetadataReference(Reference))
- return true;
- auto Created = MachineMetadataValue::reference(Reference);
- if (!Created)
- return importError(Begin, Created.error());
- Value = std::move(*Created);
- } else if (at(MITokenKind::MetadataKeyword) && token().isMetadataKeyword("!DIExpression")) {
- advance();
- if (expect(MITokenKind::LeftParen, "'(' after !DIExpression"))
- return true;
- std::vector<std::uint64_t> Elements;
- while (!at(MITokenKind::RightParen)) {
- if (at(MITokenKind::Identifier)) {
- const auto Opcode = parseDIExpressionOpcodeName(token().stringValue());
- 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;
- if (parseSigned64(token(), Signed))
- return fail("debug expression element exceeds 64 bits");
- Elements.push_back(std::bit_cast<std::uint64_t>(Signed));
- advance();
- } else {
- return fail("expected a debug expression opcode or integer");
- }
- if (!consume(MITokenKind::Comma))
- break;
- }
- if (expect(MITokenKind::RightParen, "')' after !DIExpression"))
- return true;
- Value = MachineMetadataValue::expression(MachineDIExpression(std::move(Elements)));
- } else {
- return fail("expected a metadata reference or !DIExpression");
- }
-
- auto Operand = MachineOperand::metadata(std::move(Value));
- if (!Operand)
- return importError(Begin, Operand.error());
- Result = ParsedOperand{
- std::move(*Operand),
- std::nullopt,
- {Begin.range().Begin, token().range().Begin},
- };
- return false;
-}
-
-bool MIParser::Impl::parseInlineDILocation(
- std::vector<MachineDILocationFrame> &InlineChain,
- std::optional<MachineMetadataReference> &TerminalInlinedAt) {
- if (!at(MITokenKind::MetadataKeyword) || !token().isMetadataKeyword("!DILocation")) {
- return fail("expected an inline !DILocation");
- }
- advance();
- if (expect(MITokenKind::LeftParen, "'(' after !DILocation"))
- return true;
-
- MachineDILocationFrame Frame;
- bool HasLine = false;
- bool HasScope = false;
- std::vector<MachineDILocationFrame> NestedChain;
- std::optional<MachineMetadataReference> NestedTerminal;
- std::unordered_set<std::string> SeenFields;
- while (!at(MITokenKind::RightParen)) {
- if (!at(MITokenKind::Identifier))
- return fail("expected a DILocation field name");
- const MIToken FieldToken = token();
- const std::string Field(token().stringValue());
- if (!SeenFields.insert(Field).second)
- return fail("duplicate DILocation field '" + Field + "'");
- advance();
- if (expect(MITokenKind::Colon, "':' after a DILocation field name"))
- return true;
-
- if (Field == "line") {
- std::uint32_t Line = 0;
- if (!at(MITokenKind::IntegerLiteral) || parseUnsigned32(token(), Line))
- return fail("expected an unsigned 32-bit DILocation line");
- Frame.Line = Line;
- HasLine = true;
- advance();
- } else if (Field == "column") {
- std::uint64_t Column = 0;
- if (!at(MITokenKind::IntegerLiteral) || parseUnsigned(token(), Column) ||
- Column > std::numeric_limits<std::uint16_t>::max()) {
- return fail("expected an unsigned 16-bit DILocation column");
- }
- Frame.Column = static_cast<std::uint16_t>(Column);
- advance();
- } else if (Field == "scope") {
- MachineMetadataReference Scope;
- if (parseMetadataReference(Scope))
- return true;
- if (Scope.scope() != MachineMetadataScope::EmbeddedIR)
- return fail(FieldToken, "DILocation scope must reference embedded IR metadata");
- Frame.Scope = Scope;
- HasScope = true;
- } else if (Field == "inlinedAt") {
- if (at(MITokenKind::MetadataKeyword) && token().isMetadataKeyword("!DILocation")) {
- if (parseInlineDILocation(NestedChain, NestedTerminal))
- return true;
- } else {
- MachineMetadataReference Reference;
- if (parseMetadataReference(Reference))
- return true;
- if (Reference.scope() != MachineMetadataScope::EmbeddedIR) {
- return fail(FieldToken, "DILocation inlinedAt must reference embedded IR metadata");
- }
- NestedTerminal = Reference;
- }
- } else if (Field == "isImplicitCode") {
- if (!at(MITokenKind::Identifier) ||
- (token().stringValue() != "true" && token().stringValue() != "false")) {
- return fail("expected 'true' or 'false' for DILocation isImplicitCode");
- }
- Frame.IsImplicitCode = token().stringValue() == "true";
- advance();
- } else if (Field == "atomGroup") {
- std::uint64_t Group = 0;
- if (!at(MITokenKind::IntegerLiteral) || parseUnsigned(token(), Group) ||
- Group > MachineDILocation::MaxAtomGroup) {
- return fail("DILocation atomGroup exceeds 61 bits");
- }
- Frame.AtomGroup = Group;
- advance();
- } else if (Field == "atomRank") {
- std::uint64_t Rank = 0;
- if (!at(MITokenKind::IntegerLiteral) || parseUnsigned(token(), Rank) || Rank > 7) {
- return fail("DILocation atomRank exceeds three bits");
- }
- Frame.AtomRank = static_cast<std::uint8_t>(Rank);
- advance();
- } else {
- return fail(FieldToken, "unknown DILocation field '" + Field + "'");
- }
-
- if (!consume(MITokenKind::Comma))
- break;
- }
- if (expect(MITokenKind::RightParen, "')' after !DILocation"))
- return true;
- if (!HasLine)
- return fail("DILocation requires a line field");
- if (!HasScope)
- return fail("DILocation requires a scope field");
-
- InlineChain.push_back(Frame);
- InlineChain.insert(InlineChain.end(), NestedChain.begin(), NestedChain.end());
- TerminalInlinedAt = NestedTerminal;
- return false;
-}
-
-bool MIParser::Impl::parseCFIRegister(DwarfRegisterNumber &Result) {
- if (!at(MITokenKind::NamedRegister))
- return fail("expected a physical register in the CFI instruction");
- const MIToken RegisterToken = token();
- Register Reg;
- if (parseRegister(Reg) || !Reg.isPhysical())
- return true;
- const auto Physical = Reg.physicalRegister();
- if (!Physical)
- return fail(RegisterToken, "CFI register is not a physical register");
- const auto Dwarf = Target.mirText().dwarfRegister(*Physical);
- if (!Dwarf)
- return fail(RegisterToken, "physical register has no canonical DWARF register number");
- Result = DwarfRegisterNumber::fromValue(*Dwarf);
- return false;
-}
-
-bool MIParser::Impl::parseCFISigned(std::int64_t &Result) {
- if (!at(MITokenKind::IntegerLiteral) || parseSigned64(token(), Result))
- return fail("expected a signed 64-bit CFI integer");
- advance();
- return false;
-}
-
-bool MIParser::Impl::parseCFIUnsigned(std::uint32_t &Result) {
- if (!at(MITokenKind::IntegerLiteral) || parseUnsigned32(token(), Result))
- return fail("expected an unsigned 32-bit CFI integer");
- advance();
- return false;
-}
-
-bool MIParser::Impl::parseCFIOperand(ParsedOperand &Result) {
- const MIToken Begin = token();
- const std::string Operation(token().stringValue());
- advance();
-
- const auto Comma = [this]() { return expect(MITokenKind::Comma, "',' in CFI instruction"); };
- DwarfRegisterNumber Register;
- DwarfRegisterNumber OtherRegister;
- std::int64_t Offset = 0;
- std::optional<MachineCFIInstruction> Instruction;
- if (Operation == "same_value") {
- if (parseCFIRegister(Register))
- return true;
- Instruction = MachineCFIInstruction::sameValue(Register);
- } else if (Operation == "remember_state") {
- Instruction = MachineCFIInstruction::rememberState();
- } else if (Operation == "restore_state") {
- Instruction = MachineCFIInstruction::restoreState();
- } else if (Operation == "offset" || Operation == "rel_offset") {
- if (parseCFIRegister(Register) || Comma() || parseCFISigned(Offset))
- return true;
- Instruction = Operation == "offset" ? MachineCFIInstruction::offset(Register, Offset)
- : MachineCFIInstruction::relativeOffset(Register, Offset);
- } else if (Operation == "def_cfa_register") {
- if (parseCFIRegister(Register))
- return true;
- Instruction = MachineCFIInstruction::defCFARegister(Register);
- } else if (Operation == "def_cfa_offset" || Operation == "adjust_cfa_offset") {
- if (parseCFISigned(Offset))
- return true;
- Instruction = Operation == "def_cfa_offset" ? MachineCFIInstruction::defCFAOffset(Offset)
- : MachineCFIInstruction::adjustCFAOffset(Offset);
- } else if (Operation == "def_cfa") {
- if (parseCFIRegister(Register) || Comma() || parseCFISigned(Offset))
- return true;
- Instruction = MachineCFIInstruction::defCFA(Register, Offset);
- } else if (Operation == "llvm_def_aspace_cfa") {
- std::uint32_t AddressSpace = 0;
- if (parseCFIRegister(Register) || Comma() || parseCFISigned(Offset) || Comma() ||
- parseCFIUnsigned(AddressSpace)) {
- return true;
- }
- Instruction = MachineCFIInstruction::llvmDefAddressSpaceCFA(Register, Offset, AddressSpace);
- } else if (Operation == "restore" || Operation == "undefined") {
- if (parseCFIRegister(Register))
- return true;
- Instruction = Operation == "restore" ? MachineCFIInstruction::restore(Register)
- : MachineCFIInstruction::undefined(Register);
- } else if (Operation == "register") {
- if (parseCFIRegister(Register) || Comma() || parseCFIRegister(OtherRegister))
- return true;
- Instruction = MachineCFIInstruction::registerRule(Register, OtherRegister);
- } else if (Operation == "window_save") {
- Instruction = MachineCFIInstruction::windowSave();
- } else if (Operation == "negate_ra_sign_state") {
- Instruction = MachineCFIInstruction::negateReturnAddressState();
- } else if (Operation == "negate_ra_sign_state_with_pc") {
- Instruction = MachineCFIInstruction::negateReturnAddressStateWithPC();
- } else if (Operation == "llvm_register_pair") {
- DwarfRegisterNumber First;
- DwarfRegisterNumber Second;
- std::uint32_t FirstSize = 0;
- std::uint32_t SecondSize = 0;
- if (parseCFIRegister(Register) || Comma() || parseCFIRegister(First) || Comma() ||
- parseCFIUnsigned(FirstSize) || Comma() || parseCFIRegister(Second) || Comma() ||
- parseCFIUnsigned(SecondSize)) {
- return true;
- }
- Instruction = MachineCFIInstruction::llvmRegisterPair({.Register = Register,
- .FirstRegister = First,
- .FirstSizeInBits = FirstSize,
- .SecondRegister = Second,
- .SecondSizeInBits = SecondSize});
- } else if (Operation == "llvm_vector_registers") {
- if (parseCFIRegister(Register) || Comma())
- return true;
- std::vector<MachineCFIVectorRegisterLane> Registers;
- do {
- DwarfRegisterNumber VectorRegister;
- std::uint32_t Lane = 0;
- std::uint32_t Size = 0;
- if (parseCFIRegister(VectorRegister) || Comma() || parseCFIUnsigned(Lane) || Comma() ||
- parseCFIUnsigned(Size)) {
- return true;
- }
- Registers.push_back({.Register = VectorRegister, .Lane = Lane, .SizeInBits = Size});
- if (!at(MITokenKind::Comma))
- break;
- advance();
- if (!at(MITokenKind::NamedRegister))
- return fail("expected another vector CFI register tuple");
- } while (true);
- auto Created = MachineCFIInstruction::llvmVectorRegisters(
- {.Register = Register, .VectorRegisters = std::move(Registers)});
- if (!Created)
- return importError(Begin, Created.error());
- Instruction = std::move(*Created);
- } else if (Operation == "llvm_vector_offset") {
- DwarfRegisterNumber MaskRegister;
- std::uint32_t RegisterSize = 0;
- std::uint32_t MaskSize = 0;
- if (parseCFIRegister(Register) || Comma() || parseCFIUnsigned(RegisterSize) || Comma() ||
- parseCFIRegister(MaskRegister) || Comma() || parseCFIUnsigned(MaskSize) || Comma() ||
- parseCFISigned(Offset)) {
- return true;
- }
- Instruction = MachineCFIInstruction::llvmVectorOffset({.Register = Register,
- .RegisterSizeInBits = RegisterSize,
- .MaskRegister = MaskRegister,
- .MaskRegisterSizeInBits = MaskSize,
- .Offset = Offset});
- } else if (Operation == "llvm_vector_register_mask") {
- DwarfRegisterNumber SpillRegister;
- DwarfRegisterNumber MaskRegister;
- std::uint32_t SpillLaneSize = 0;
- std::uint32_t MaskSize = 0;
- if (parseCFIRegister(Register) || Comma() || parseCFIRegister(SpillRegister) || Comma() ||
- parseCFIUnsigned(SpillLaneSize) || Comma() || parseCFIRegister(MaskRegister) || Comma() ||
- parseCFIUnsigned(MaskSize)) {
- return true;
- }
- Instruction =
- MachineCFIInstruction::llvmVectorRegisterMask({.Register = Register,
- .SpillRegister = SpillRegister,
- .SpillRegisterLaneSizeInBits = SpillLaneSize,
- .MaskRegister = MaskRegister,
- .MaskRegisterSizeInBits = MaskSize});
- } else if (Operation == "escape") {
- std::vector<std::uint8_t> Bytes;
- while (true) {
- std::uint64_t Byte = 0;
- if (!at(MITokenKind::HexLiteral) || parseUnsigned(token(), Byte) ||
- Byte > std::numeric_limits<std::uint8_t>::max()) {
- return fail("CFI escape element must be an 8-bit hexadecimal literal");
- }
- Bytes.push_back(static_cast<std::uint8_t>(Byte));
- advance();
- if (!at(MITokenKind::Comma) || !nextIs(MITokenKind::HexLiteral))
- break;
- advance();
- }
- auto Created = MachineCFIInstruction::escape(std::move(Bytes));
- if (!Created)
- return importError(Begin, Created.error());
- Instruction = std::move(*Created);
- } else {
- return fail(Begin, "unsupported CFI operation '" + Operation + "'");
- }
-
- auto Index = Function.cfiInfo().addInstruction(std::move(*Instruction));
- if (!Index)
- return importError(Begin, Index.error());
- Result = ParsedOperand{
- MachineOperand::cfiIndex(*Index),
- std::nullopt,
- {Begin.range().Begin, token().range().Begin},
- };
- return false;
-}
-
-bool MIParser::Impl::parseMemoryBase(MemoryBase &Result, std::int64_t &Offset) {
- const MIToken BaseToken = token();
- switch (BaseToken.kind()) {
- case MITokenKind::StackObject:
- case MITokenKind::FixedStackObject: {
- const auto Index = frameIndexFor(BaseToken, BaseToken.kind() == MITokenKind::FixedStackObject);
- if (!Index)
- return true;
- Result = MemoryBase::frameIndex(*Index);
- advance();
- break;
- }
- case MITokenKind::ConstantPoolItem: {
- const auto Index = constantPoolIndexFor(BaseToken);
- if (!Index)
- return true;
- Result = MemoryBase::constantPool(*Index);
- advance();
- break;
- }
- case MITokenKind::JumpTableIndex: {
- const auto Index = jumpTableIndexFor(BaseToken);
- if (!Index)
- return true;
- Result = MemoryBase::jumpTable(*Index);
- advance();
- break;
- }
- case MITokenKind::GlobalValue:
- case MITokenKind::NamedGlobalValue:
- Result = MemoryBase::globalSymbol(symbolName(BaseToken));
- advance();
- break;
- case MITokenKind::ExternalSymbol:
- Result = MemoryBase::externalSymbol(symbolName(BaseToken));
- advance();
- break;
- case MITokenKind::IRValue:
- case MITokenKind::NamedIRValue:
- Result = MemoryBase::irValue(symbolName(BaseToken));
- advance();
- break;
- case MITokenKind::QuotedIRValue: {
- auto Constant = parseLLVMConstant(BaseToken.stringValue());
- 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();
- advance();
- } else if (BaseToken.isKeyword("stack")) {
- Result = MemoryBase::stack();
- advance();
- } else if (BaseToken.isKeyword("got")) {
- Result = MemoryBase::got();
- advance();
- } else if (BaseToken.isKeyword("constant-pool")) {
- Result = MemoryBase::constantPoolPseudo();
- advance();
- } else if (BaseToken.isKeyword("jump-table")) {
- Result = MemoryBase::jumpTablePseudo();
- advance();
- } else if (BaseToken.isKeyword("call-entry")) {
- advance();
- if (at(MITokenKind::GlobalValue) || at(MITokenKind::NamedGlobalValue)) {
- Result = MemoryBase::callEntryGlobal(symbolName(token()));
- } else if (at(MITokenKind::ExternalSymbol)) {
- Result = MemoryBase::callEntryExternal(symbolName(token()));
- } else {
- return fail("call-entry memory base requires a global or external symbol");
- }
- advance();
- } else if (BaseToken.isKeyword("custom")) {
- advance();
- if (!at(MITokenKind::Identifier) && !at(MITokenKind::StringConstant))
- return fail("custom memory base requires a target spelling");
- Result = MemoryBase::custom(std::string(token().stringValue()));
- advance();
- } else {
- return fail(BaseToken, "unsupported machine memory base");
- }
- break;
- default:
- return fail(BaseToken, "expected a machine memory base");
- }
- return parseOptionalOffset(Offset);
-}
-
-bool MIParser::Impl::parseMemoryOperand(const MachineMemOperand *&Result,
- Opcode InstructionOpcode) {
- const MIToken Begin = token();
- if (expect(MITokenKind::LeftParen, "'(' before a machine memory operand"))
- return true;
-
- MachineMemOperandDesc Description;
- std::unordered_set<std::string> SeenFlags;
- while (token().isMemoryOperandFlag()) {
- const std::string Name(token().stringValue());
- if (!SeenFlags.insert(Name).second)
- return fail("duplicate machine memory operand flag '" + Name + "'");
- if (atKeyword("volatile"))
- Description.Accesses.set(MemoryAccessFlag::Volatile);
- else if (atKeyword("non-temporal"))
- Description.Accesses.set(MemoryAccessFlag::NonTemporal);
- else if (atKeyword("dereferenceable"))
- Description.Accesses.set(MemoryAccessFlag::Dereferenceable);
- else if (atKeyword("invariant"))
- Description.Accesses.set(MemoryAccessFlag::Invariant);
- else {
- const auto Flag = Target.mirText().machineMemOperandFlag(token().stringValue());
- if (!Flag)
- return fail("unknown target machine memory operand flag '" + Name + "'");
- if ((Description.TargetFlags & *Flag) != 0)
- return fail("overlapping target machine memory operand flag '" + Name + "'");
- Description.TargetFlags |= *Flag;
- }
- advance();
- }
-
- if (!at(MITokenKind::Identifier) ||
- (token().stringValue() != "load" && token().stringValue() != "store")) {
- return fail("expected load or store in a machine memory operand");
- }
- if (token().stringValue() == "load")
- Description.Accesses.set(MemoryAccessFlag::Load);
- else
- Description.Accesses.set(MemoryAccessFlag::Store);
- advance();
- if (at(MITokenKind::Identifier) && token().stringValue() == "store") {
- if (Description.Accesses.has(MemoryAccessFlag::Store))
- return fail("duplicate store memory operation");
- Description.Accesses.set(MemoryAccessFlag::Store);
- advance();
- }
-
- if (at(MITokenKind::Identifier) && token().stringValue() == "syncscope") {
- advance();
- if (expect(MITokenKind::LeftParen, "'(' after syncscope"))
- return true;
- if (!at(MITokenKind::StringConstant))
- return fail("syncscope requires a quoted scope name");
- const std::string_view Name = token().stringValue();
- auto Scope = std::ranges::find_if(
- Context.SyncScopes, [Name](const MISyncScopeSlot &Slot) { return Slot.Name == Name; });
- if (Scope == Context.SyncScopes.end() && Context.InternSyncScope) {
- const MIToken NameToken = token();
- auto ID = Context.InternSyncScope(Name);
- if (!ID)
- return importError(NameToken, ID.error());
- Context.SyncScopes.push_back({.Name = std::string(Name), .ID = *ID});
- Scope = std::prev(Context.SyncScopes.end());
- }
- if (Scope == Context.SyncScopes.end())
- return fail("unknown synchronization scope '" + std::string(Name) + "'");
- Description.SyncScope = Scope->ID;
- advance();
- if (expect(MITokenKind::RightParen, "')' after syncscope"))
- return true;
- }
-
- std::size_t OrderingCount = 0;
- while (at(MITokenKind::Identifier)) {
- const auto Ordering = atomicOrdering(token().stringValue());
- if (!Ordering)
- break;
- if (OrderingCount == 0)
- Description.SuccessOrdering = *Ordering;
- else if (OrderingCount == 1)
- Description.FailureOrdering = *Ordering;
- else
- return fail("machine memory operand has more than two atomic orderings");
- ++OrderingCount;
- advance();
- }
- const bool IsLoad = Description.Accesses.has(MemoryAccessFlag::Load);
- const bool IsStore = Description.Accesses.has(MemoryAccessFlag::Store);
- if (OrderingCount == 1) {
- if (InstructionOpcode == opcode(GenericOpcode::G_ATOMIC_CMPXCHG) ||
- InstructionOpcode == opcode(GenericOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS)) {
- Description.AtomicKind = AtomicOperation::CompareExchange;
- } else {
- Description.AtomicKind = IsLoad && IsStore
- ? AtomicOperation::ReadModifyWrite
- : (IsLoad ? AtomicOperation::Load : AtomicOperation::Store);
- }
- } else if (OrderingCount == 2)
- Description.AtomicKind = AtomicOperation::CompareExchange;
-
- std::uint64_t MinimumBytes = 0;
- if (at(MITokenKind::IntegerLiteral)) {
- if (parseUnsigned(token(), MinimumBytes) || MinimumBytes == 0)
- return fail("machine memory operand size must be a nonzero byte count");
- auto Size = MemorySize::fixed(MinimumBytes);
- if (!Size)
- return importError(token(), Size.error());
- Description.Size = *Size;
- advance();
- } else if (atKeyword("unknown-size")) {
- advance();
- } else if (consume(MITokenKind::LeftParen)) {
- LLT Type;
- if (parseLowLevelType(Type))
- return true;
- if (expect(MITokenKind::RightParen, "')' after the memory low-level type"))
- return true;
- const auto MinimumBits = minimumTypeSizeInBits(Type);
- if (!MinimumBits || *MinimumBits == 0)
- return fail(Begin, "memory low-level type has no representable size");
- MinimumBytes = (*MinimumBits + 7U) / 8U;
- auto Size = Type.isScalableVector() ? MemorySize::scalable(MinimumBytes)
- : MemorySize::fixed(MinimumBytes);
- 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");
- }
-
- if (MinimumBytes != 0) {
- if (MinimumBytes > (std::uint64_t{1} << 63U))
- return fail(Begin, "machine memory operand size has no representable default alignment");
- auto DefaultAlignment = Alignment::create(std::bit_ceil(MinimumBytes));
- if (!DefaultAlignment)
- return importError(Begin, DefaultAlignment.error());
- Description.Align = *DefaultAlignment;
- }
-
- if (at(MITokenKind::Identifier)) {
- const std::string_view ExpectedPreposition =
- IsLoad && IsStore ? "on" : (IsLoad ? "from" : "into");
- if (token().stringValue() != ExpectedPreposition) {
- return fail("expected '" + std::string(ExpectedPreposition) +
- "' before the machine memory base");
- }
- 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")) {
- 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")) {
- if (parseAlignment(BaseAlignment))
- return true;
- } else if (atKeyword("addrspace")) {
- advance();
- if (!at(MITokenKind::IntegerLiteral) || parseUnsigned32(token(), Description.AddressSpace) ||
- Description.AddressSpace > LLT::MaxAddressSpace) {
- return fail("invalid machine memory operand address space");
- }
- advance();
- } else if (at(MITokenKind::MetadataKeyword)) {
- const std::string MetadataKind(token().stringValue());
- advance();
- MachineMetadataReference Reference;
- if (parseMetadataReference(Reference))
- return true;
- if (MetadataKind == "!tbaa")
- Description.TBAA = Reference;
- else if (MetadataKind == "!alias.scope")
- Description.AliasScope = Reference;
- else if (MetadataKind == "!noalias")
- Description.NoAlias = Reference;
- else if (MetadataKind == "!noalias.addrspace")
- Description.NoAliasAddressSpace = Reference;
- else if (MetadataKind == "!range")
- Description.RangeMetadata = Reference;
- else
- return fail("unsupported machine memory operand metadata attachment");
- } else {
- 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;
-
- auto Created = Function.createMemOperand(std::move(Description));
- if (!Created)
- return importError(Begin, Created.error());
- Result = *Created;
- return false;
-}
-
-bool MIParser::Impl::parsePredicateOperand(ParsedOperand &Result, bool IsFloating) {
- const MIToken Begin = token();
- advance();
- if (expect(MITokenKind::LeftParen, "'(' after predicate kind"))
- return true;
- if (!at(MITokenKind::Identifier))
- return fail("expected a predicate spelling");
-
- Expected<MachineOperand> Operand = IsFloating ? [&]() -> Expected<MachineOperand> {
- const auto Predicate = floatingPredicate(token().stringValue());
- if (!Predicate) {
- return makeUnexpected(ErrorCode::ParseError, "invalid floating-point predicate");
- }
- return MachineOperand::floatingPredicate(*Predicate);
- }()
- : [&]() -> Expected<MachineOperand> {
- const auto Predicate = integerPredicate(token().stringValue());
- if (!Predicate) {
- return makeUnexpected(ErrorCode::ParseError, "invalid integer predicate");
- }
- return MachineOperand::integerPredicate(*Predicate);
- }();
- if (!Operand)
- return importError(token(), Operand.error());
- advance();
- if (expect(MITokenKind::RightParen, "')' after predicate"))
- return true;
- Result = ParsedOperand{
- std::move(*Operand), std::nullopt, {Begin.range().Begin, token().range().Begin}};
- return false;
-}
-
-bool MIParser::Impl::parseShuffleMaskOperand(ParsedOperand &Result) {
- const MIToken Begin = token();
- advance();
- if (expect(MITokenKind::LeftParen, "'(' after shufflemask"))
- return true;
- std::vector<std::int32_t> Elements;
- while (!at(MITokenKind::RightParen)) {
- if (atKeyword("undef")) {
- Elements.push_back(ShuffleMaskOperand::Undef);
- advance();
- } else {
- std::int64_t Value = 0;
- if (!at(MITokenKind::IntegerLiteral) || parseSigned64(token(), Value) ||
- Value < std::numeric_limits<std::int32_t>::min() ||
- Value > std::numeric_limits<std::int32_t>::max()) {
- return fail("shuffle mask element must be a 32-bit integer or undef");
- }
- Elements.push_back(static_cast<std::int32_t>(Value));
- advance();
- }
- if (!consume(MITokenKind::Comma))
- break;
- }
- if (expect(MITokenKind::RightParen, "')' after shufflemask"))
- return true;
- auto Operand = MachineOperand::shuffleMask(std::move(Elements));
- if (!Operand)
- return importError(Begin, Operand.error());
- Result = ParsedOperand{
- std::move(*Operand), std::nullopt, {Begin.range().Begin, token().range().Begin}};
- return false;
-}
-
-bool MIParser::Impl::parseDebugInstrRefOperand(ParsedOperand &Result) {
- const MIToken Begin = token();
- advance();
- if (expect(MITokenKind::LeftParen, "'(' after dbg-instr-ref"))
- return true;
- std::uint64_t Instruction = 0;
- if (!at(MITokenKind::IntegerLiteral) || parseUnsigned(token(), Instruction))
- return fail("invalid debug instruction number");
- advance();
- if (expect(MITokenKind::Comma, "',' in dbg-instr-ref"))
- return true;
- std::uint64_t OperandNumber = 0;
- if (!at(MITokenKind::IntegerLiteral) || parseUnsigned(token(), OperandNumber))
- return fail("invalid debug operand number");
- advance();
- if (expect(MITokenKind::RightParen, "')' after dbg-instr-ref"))
- return true;
- auto Operand = MachineOperand::debugInstrRef(Instruction, OperandNumber);
- if (!Operand)
- return importError(Begin, Operand.error());
- Result = ParsedOperand{
- std::move(*Operand), std::nullopt, {Begin.range().Begin, token().range().Begin}};
- return false;
-}
-
-bool MIParser::Impl::parseLaneMaskOperand(ParsedOperand &Result) {
- const MIToken Begin = token();
- advance();
- if (expect(MITokenKind::LeftParen, "'(' after lanemask"))
- return true;
- std::uint64_t Value = 0;
- if (parseUnsigned(token(), Value))
- return fail("invalid 64-bit lane mask");
- advance();
- if (expect(MITokenKind::RightParen, "')' after lanemask"))
- return true;
- Result = ParsedOperand{MachineOperand::laneMask(LaneMask::fromRaw(Value)),
- std::nullopt,
- {Begin.range().Begin, token().range().Begin}};
- return false;
-}
-
-bool MIParser::Impl::parseIntrinsicOperand(ParsedOperand &Result) {
- const MIToken Begin = token();
- advance();
- if (expect(MITokenKind::LeftParen, "'(' after intrinsic"))
- return true;
- if (!at(MITokenKind::NamedGlobalValue))
- return fail("expected a named intrinsic");
- const auto ID = Target.mirText().intrinsic(token().stringValue());
- if (!ID)
- return fail("unknown intrinsic '" + std::string(token().stringValue()) + "'");
- advance();
- if (expect(MITokenKind::RightParen, "')' after intrinsic"))
- return true;
- auto Operand = MachineOperand::intrinsic(*ID);
- if (!Operand)
- return importError(Begin, Operand.error());
- Result = ParsedOperand{
- std::move(*Operand), std::nullopt, {Begin.range().Begin, token().range().Begin}};
- return false;
-}
-
-bool MIParser::Impl::parseTargetIndexOperand(ParsedOperand &Result) {
- const MIToken Begin = token();
- advance();
- if (expect(MITokenKind::LeftParen, "'(' after target-index"))
- return true;
- if (!at(MITokenKind::Identifier))
- return fail("expected a target index name");
- const auto Index = Target.mirText().targetIndex(token().stringValue());
- if (!Index)
- return fail("unknown target index '" + std::string(token().stringValue()) + "'");
- advance();
- if (expect(MITokenKind::RightParen, "')' after target index"))
- return true;
- std::int64_t Offset = 0;
- if (parseOptionalOffset(Offset))
- return true;
- Result = ParsedOperand{MachineOperand::targetIndex(*Index, Offset),
- std::nullopt,
- {Begin.range().Begin, token().range().Begin}};
- return false;
-}
-
-bool MIParser::Impl::parseCustomMaskOperand(ParsedOperand &Result) {
- const MIToken Begin = token();
- advance();
- if (expect(MITokenKind::LeftParen, "'(' after CustomRegMask"))
- return true;
- std::uint32_t MaximumRegister = 0;
- for (const PhysicalRegisterDesc &Register : Target.registers().physicalRegisters())
- MaximumRegister = std::max(MaximumRegister, Register.Reg.number());
- std::vector<std::uint64_t> Words(MaximumRegister / 64U + 1U, 0);
- if (!at(MITokenKind::RightParen)) {
- do {
- Register Reg;
- if (!at(MITokenKind::NamedRegister) || parseRegister(Reg) || !Reg.isPhysical())
- return fail("CustomRegMask requires physical registers");
- const auto Physical = Reg.physicalRegister();
- if (!Physical)
- return fail("CustomRegMask requires physical registers");
- const std::uint32_t Number = Physical->number();
- Words[Number / 64U] |= std::uint64_t{1} << (Number % 64U);
- } while (consume(MITokenKind::Comma));
- }
- if (expect(MITokenKind::RightParen, "')' after CustomRegMask"))
- return true;
- auto Operand =
- MachineOperand::registerMask(std::make_shared<const RegisterMask>(std::move(Words)));
- if (!Operand)
- return importError(Begin, Operand.error());
- Result = ParsedOperand{
- std::move(*Operand), std::nullopt, {Begin.range().Begin, token().range().Begin}};
- return false;
-}
-
-bool MIParser::Impl::parseLiveOutMaskOperand(ParsedOperand &Result) {
- const MIToken Begin = token();
- advance();
- if (expect(MITokenKind::LeftParen, "'(' after liveout"))
- return true;
- std::uint32_t MaximumRegister = 0;
- for (const PhysicalRegisterDesc &Register : Target.registers().physicalRegisters())
- MaximumRegister = std::max(MaximumRegister, Register.Reg.number());
- std::vector<std::uint64_t> Words(MaximumRegister / 64U + 1U, 0);
- do {
- Register Reg;
- if (!at(MITokenKind::NamedRegister) || parseRegister(Reg) || !Reg.isPhysical())
- return fail("liveout requires physical registers");
- const auto Physical = Reg.physicalRegister();
- if (!Physical)
- return fail("liveout requires physical registers");
- const std::uint32_t Number = Physical->number();
- Words[Number / 64U] |= std::uint64_t{1} << (Number % 64U);
- } while (consume(MITokenKind::Comma));
- if (expect(MITokenKind::RightParen, "')' after liveout"))
- return true;
- auto Operand =
- MachineOperand::liveOutRegisterMask(std::make_shared<const RegisterMask>(std::move(Words)));
- if (!Operand)
- return importError(Begin, Operand.error());
- Result = ParsedOperand{
- std::move(*Operand), std::nullopt, {Begin.range().Begin, token().range().Begin}};
- return false;
-}
-
-bool MIParser::Impl::parseBlockAddressOperand(ParsedOperand &Result) {
- const MIToken Begin = token();
- advance();
- if (expect(MITokenKind::LeftParen, "'(' after blockaddress"))
- return true;
- if (!at(MITokenKind::GlobalValue) && !at(MITokenKind::NamedGlobalValue))
- return fail("blockaddress requires a function reference");
- const std::string FunctionName = symbolName(token());
- advance();
- if (expect(MITokenKind::Comma, "',' in blockaddress"))
- return true;
- if (!at(MITokenKind::IRBlock) && !at(MITokenKind::NamedIRBlock))
- return fail("blockaddress requires an IR block reference");
- const std::string BlockName = symbolName(token());
- advance();
- if (expect(MITokenKind::RightParen, "')' after blockaddress"))
- return true;
- std::int64_t Offset = 0;
- if (parseOptionalOffset(Offset))
- return true;
- auto Operand = MachineOperand::blockAddress(FunctionName, BlockName, Offset);
- if (!Operand)
- return importError(Begin, Operand.error());
- Result = ParsedOperand{
- std::move(*Operand), std::nullopt, {Begin.range().Begin, token().range().Begin}};
- return false;
-}
-
-bool MIParser::Impl::parseOperand(bool IsDef, ParsedOperand &Result) {
- const MIToken Begin = token();
- if (token().isRegister() || token().isRegisterFlag())
- return parseRegisterOperand(IsDef, Result);
-
- std::uint32_t TargetFlags = 0;
- if (parseTargetFlags(TargetFlags))
- return true;
- const MIToken OperandToken = token();
- if (isFloatingSemanticsKeyword(OperandToken)) {
- if (parseFloatingImmediateOperand(Result))
- return true;
- Result.Operand.setTargetFlags(TargetFlags);
- return false;
- }
- if (OperandToken.kind() == MITokenKind::Exclaim ||
- (OperandToken.kind() == MITokenKind::MetadataKeyword &&
- OperandToken.isMetadataKeyword("!DIExpression"))) {
- if (parseMetadataOperand(Result))
- return true;
- Result.Operand.setTargetFlags(TargetFlags);
- return false;
- }
- if (isCFIOperationToken(OperandToken)) {
- if (parseCFIOperand(Result))
- return true;
- Result.Operand.setTargetFlags(TargetFlags);
- return false;
- }
- MachineOperand Operand = MachineOperand::immediate(0);
- bool HasOperand = true;
-
- switch (OperandToken.kind()) {
- case MITokenKind::IntegerLiteral: {
- std::int64_t Value = 0;
- if (parseSigned64(OperandToken, Value))
- return fail("integer literal is too large for a machine immediate");
- Operand = MachineOperand::immediate(Value, TargetFlags);
- advance();
- break;
- }
- case MITokenKind::MachineBasicBlock: {
- MachineBasicBlock *Block = blockFor(OperandToken);
- if (Block == nullptr)
- return true;
- Operand = MachineOperand::basicBlock(*Block, TargetFlags);
- advance();
- break;
- }
- case MITokenKind::StackObject:
- case MITokenKind::FixedStackObject: {
- const bool Fixed = OperandToken.kind() == MITokenKind::FixedStackObject;
- const auto Index = frameIndexFor(OperandToken, Fixed);
- if (!Index)
- return true;
- advance();
- std::int64_t Offset = 0;
- if (parseOptionalOffset(Offset))
- return true;
- Operand = MachineOperand::frameIndex(*Index, Offset, TargetFlags);
- break;
- }
- case MITokenKind::ConstantPoolItem: {
- const auto Index = constantPoolIndexFor(OperandToken);
- if (!Index)
- return true;
- advance();
- std::int64_t Offset = 0;
- if (parseOptionalOffset(Offset))
- return true;
- Operand = MachineOperand::constantPool(*Index, Offset, TargetFlags);
- break;
- }
- case MITokenKind::JumpTableIndex: {
- const auto Index = jumpTableIndexFor(OperandToken);
- if (!Index)
- return true;
- Operand = MachineOperand::jumpTable(*Index, TargetFlags);
- advance();
- break;
- }
- case MITokenKind::NamedGlobalValue:
- case MITokenKind::GlobalValue: {
- const std::string Name = symbolName(OperandToken);
- advance();
- std::int64_t Offset = 0;
- if (parseOptionalOffset(Offset))
- return true;
- auto Created = MachineOperand::globalSymbol(Name, Offset, TargetFlags);
- if (!Created)
- return importError(OperandToken, Created.error());
- Operand = std::move(*Created);
- break;
- }
- case MITokenKind::ExternalSymbol: {
- const std::string Name = symbolName(OperandToken);
- advance();
- std::int64_t Offset = 0;
- if (parseOptionalOffset(Offset))
- return true;
- auto Created = MachineOperand::externalSymbol(Name, Offset, TargetFlags);
- if (!Created)
- return importError(OperandToken, Created.error());
- Operand = std::move(*Created);
- break;
- }
- case MITokenKind::MCSymbol: {
- const std::string Name = symbolName(OperandToken);
- advance();
- std::int64_t Offset = 0;
- if (parseOptionalOffset(Offset))
- return true;
- auto Created = MachineOperand::mcSymbol(Name, Offset, TargetFlags);
- if (!Created)
- return importError(OperandToken, Created.error());
- Operand = std::move(*Created);
- break;
- }
- case MITokenKind::SubRegisterIndex: {
- const SubRegIndexDesc *Description = Target.registers().subRegIndex(OperandToken.stringValue());
- if (Description == nullptr)
- return fail("unknown subregister index '" + std::string(OperandToken.stringValue()) + "'");
- Operand =
- MachineOperand::immediate(static_cast<std::int64_t>(Description->ID.value()), TargetFlags);
- advance();
- break;
- }
- case MITokenKind::Identifier: {
- if (const auto Mask = Target.mirText().registerMask(OperandToken.stringValue())) {
- auto Created = MachineOperand::registerMask(Mask, TargetFlags);
- if (!Created)
- return importError(OperandToken, Created.error());
- Operand = std::move(*Created);
- advance();
- } else if (OperandToken.stringValue() == "CustomRegMask") {
- if (TargetFlags != 0)
- return fail("custom register masks cannot have target flags");
- return parseCustomMaskOperand(Result);
- } else if (OperandToken.stringValue().starts_with('i')) {
- if (parseTypedIntegerOperand(Result))
- return true;
- Result.Operand.setTargetFlags(TargetFlags);
- return false;
- } else {
- return fail("unknown named machine operand '" + std::string(OperandToken.stringValue()) +
- "'");
- }
- break;
- }
- case MITokenKind::Keyword:
- HasOperand = false;
- break;
- default:
- return fail("expected a machine operand");
- }
-
- if (!HasOperand) {
- bool Failed = false;
- if (OperandToken.isKeyword("intpred"))
- Failed = parsePredicateOperand(Result, false);
- else if (OperandToken.isKeyword("floatpred"))
- Failed = parsePredicateOperand(Result, true);
- else if (OperandToken.isKeyword("shufflemask"))
- Failed = parseShuffleMaskOperand(Result);
- else if (OperandToken.isKeyword("dbg-instr-ref"))
- Failed = parseDebugInstrRefOperand(Result);
- else if (OperandToken.isKeyword("lanemask"))
- Failed = parseLaneMaskOperand(Result);
- else if (OperandToken.isKeyword("intrinsic"))
- Failed = parseIntrinsicOperand(Result);
- else if (OperandToken.isKeyword("target-index"))
- Failed = parseTargetIndexOperand(Result);
- else if (OperandToken.isKeyword("liveout"))
- Failed = parseLiveOutMaskOperand(Result);
- else if (OperandToken.isKeyword("blockaddress"))
- Failed = parseBlockAddressOperand(Result);
- else
- return fail("unsupported machine operand spelling '" + std::string(OperandToken.spelling()) +
- "'");
- if (!Failed)
- Result.Operand.setTargetFlags(TargetFlags);
- return Failed;
- }
-
- Result =
- ParsedOperand{std::move(Operand), std::nullopt, {Begin.range().Begin, token().range().Begin}};
- 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"))
- return true;
- if (token().isNewlineOrEnd())
- return false;
- do {
- if (!at(MITokenKind::NamedRegister))
- return fail("expected a physical register in liveins");
- Register Reg;
- if (parseRegister(Reg) || !Reg.isPhysical())
- return true;
- const auto Physical = Reg.physicalRegister();
- if (!Physical)
- return fail("expected a physical register in liveins");
- LaneMask Lanes = LaneMask::all();
- if (consume(MITokenKind::Colon)) {
- std::uint64_t Raw = 0;
- if (parseUnsigned(token(), Raw))
- return fail("invalid live-in lane mask");
- Lanes = LaneMask::fromRaw(Raw);
- advance();
- }
- auto Added = Block.addLiveIn(*Physical, Lanes);
- if (!Added)
- return importError(token(), Added.error());
- } while (consume(MITokenKind::Comma));
- return false;
-}
-
-bool MIParser::Impl::parseBlockSuccessors(MachineBasicBlock &Block) {
- advance();
- if (expect(MITokenKind::Colon, "':' after successors"))
- return true;
- ExplicitSuccessorBlocks.insert(&Block);
- if (token().isNewlineOrEnd())
- return false;
- do {
- if (!at(MITokenKind::MachineBasicBlock))
- return fail("expected a machine basic block reference");
- MachineBasicBlock *Successor = blockFor(token());
- if (Successor == nullptr)
- return true;
- advance();
- BranchProbability Probability = BranchProbability::zero();
- if (consume(MITokenKind::LeftParen)) {
- std::uint32_t Weight = 0;
- if (parseUnsigned32(token(), Weight))
- return fail("expected unsigned integer");
- Probability = BranchProbability::fromRaw(Weight);
- advance();
- if (expect(MITokenKind::RightParen, "')' after successor weight"))
- return true;
- }
- auto Added = Function.cfgUpdater().addSuccessor(Block, *Successor, Probability);
- if (!Added)
- return importError(token(), Added.error());
- } while (consume(MITokenKind::Comma));
- return false;
-}
-
-bool MIParser::Impl::parseInstruction(MachineBasicBlock &Block, bool InBundle,
- MachineInstr *PreviousInstruction, MachineInstr *&Result) {
- if (ParsedInstructionCount >= Options.MaximumInstructions)
- return fail("machine instruction count exceeds parser limit");
-
- std::vector<ParsedOperand> Operands;
- while (token().isRegister() || token().isRegisterFlag()) {
- ParsedOperand Operand{MachineOperand::immediate(0), std::nullopt, {}};
- if (parseRegisterOperand(true, Operand))
- return true;
- Operands.push_back(std::move(Operand));
- if (!consume(MITokenKind::Comma))
- break;
- }
- if (!Operands.empty() && expect(MITokenKind::Equal, "'=' after register definitions"))
- return true;
-
- MachineInstrFlags Flags;
- while (isInstructionFlag(token())) {
- const auto Flag = instructionFlag(token().stringValue());
- if (!Flag)
- return fail("unknown instruction flag");
- if (Flags.has(*Flag))
- return fail("duplicate instruction flag '" + std::string(token().stringValue()) + "'");
- Flags.set(*Flag);
- advance();
- }
- if (!at(MITokenKind::Identifier))
- return fail("expected a machine instruction name");
- const MIToken OpcodeToken = token();
- const InstructionDescriptor *Descriptor =
- Target.instructions().descriptor(OpcodeToken.stringValue());
- 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") &&
- !atKeyword("debug-location") && !atKeyword("pre-instr-symbol") &&
- !atKeyword("post-instr-symbol") && !atKeyword("heap-alloc-marker") &&
- !atKeyword("pcsections") && !atKeyword("mmra") && !atKeyword("cfi-type") &&
- !atKeyword("deactivation-symbol")) {
- if (Operands.size() >= Options.MaximumOperandsPerInstruction)
- return fail("instruction operand count exceeds parser limit");
- ParsedOperand Operand{MachineOperand::immediate(0), std::nullopt, {}};
- 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) ||
- atKeyword("debug-instr-number") || atKeyword("debug-location"))
- break;
- if (expect(MITokenKind::Comma, "',' before the next machine operand"))
- return true;
- }
-
- std::uint32_t DebugNumber = 0;
- std::optional<MachineDebugLocation> DebugLocation;
- std::optional<std::string> PreInstrSymbol;
- std::optional<std::string> PostInstrSymbol;
- std::optional<MachineMetadataReference> HeapAllocMarker;
- std::optional<MachineMetadataReference> PCSections;
- std::optional<MachineMetadataReference> MMRA;
- std::optional<std::uint32_t> CFIType;
- std::optional<std::string> DeactivationSymbol;
- std::unordered_set<std::string> SeenAttachments;
- while (atKeyword("debug-instr-number") || atKeyword("debug-location") ||
- atKeyword("pre-instr-symbol") || atKeyword("post-instr-symbol") ||
- atKeyword("heap-alloc-marker") || atKeyword("pcsections") || atKeyword("mmra") ||
- atKeyword("cfi-type") || atKeyword("deactivation-symbol")) {
- const std::string Name(token().stringValue());
- if (!SeenAttachments.insert(Name).second)
- return fail("duplicate instruction attachment '" + Name + "'");
- advance();
- if (Name == "debug-instr-number") {
- if (!at(MITokenKind::IntegerLiteral) || parseUnsigned32(token(), DebugNumber) ||
- DebugNumber == 0) {
- return fail("invalid debug instruction number");
- }
- advance();
- } else if (Name == "debug-location") {
- if (at(MITokenKind::MetadataKeyword) && token().isMetadataKeyword("!DILocation")) {
- std::vector<MachineDILocationFrame> InlineChain;
- std::optional<MachineMetadataReference> TerminalInlinedAt;
- if (parseInlineDILocation(InlineChain, TerminalInlinedAt))
- return true;
- auto Location = MachineDILocation::create(std::move(InlineChain), TerminalInlinedAt);
- if (!Location)
- return importError(OpcodeToken, Location.error());
- DebugLocation = MachineDebugLocation::inlineLocation(std::move(*Location));
- } else {
- MachineMetadataReference Reference;
- if (parseMetadataReference(Reference))
- return true;
- auto Created = MachineDebugLocation::reference(Reference);
- if (!Created)
- return importError(OpcodeToken, Created.error());
- DebugLocation = std::move(*Created);
- }
- } else if (Name == "pre-instr-symbol" || Name == "post-instr-symbol") {
- if (!at(MITokenKind::MCSymbol))
- return fail("expected an MC symbol after '" + Name + "'");
- if (Name == "pre-instr-symbol")
- PreInstrSymbol = symbolName(token());
- else
- PostInstrSymbol = symbolName(token());
- advance();
- } else if (Name == "heap-alloc-marker" || Name == "pcsections" || Name == "mmra") {
- MachineMetadataReference Reference;
- if (parseMetadataReference(Reference))
- return true;
- if (Name == "heap-alloc-marker")
- HeapAllocMarker = Reference;
- else if (Name == "pcsections")
- PCSections = Reference;
- else
- MMRA = Reference;
- } else if (Name == "cfi-type") {
- std::uint32_t Type = 0;
- if (!at(MITokenKind::IntegerLiteral) || parseUnsigned32(token(), Type) || Type == 0)
- return fail("invalid nonzero CFI type");
- CFIType = Type;
- advance();
- } else {
- if (!at(MITokenKind::GlobalValue) && !at(MITokenKind::NamedGlobalValue))
- return fail("expected a global value after 'deactivation-symbol'");
- DeactivationSymbol = symbolName(token());
- advance();
- }
- static_cast<void>(consume(MITokenKind::Comma));
- }
- std::vector<const MachineMemOperand *> MemOperands;
- if (consume(MITokenKind::DoubleColon)) {
- while (!token().isNewlineOrEnd() && !at(MITokenKind::LeftBrace)) {
- if (MemOperands.size() >= Options.MaximumMemoryOperandsPerInstruction)
- return fail("machine memory operand count exceeds parser limit");
- const MachineMemOperand *MemOperand = nullptr;
- if (parseMemoryOperand(MemOperand, Descriptor->InstructionOpcode))
- return true;
- MemOperands.push_back(MemOperand);
- if (token().isNewlineOrEnd() || at(MITokenKind::LeftBrace))
- break;
- if (expect(MITokenKind::Comma, "',' before the next machine memory operand"))
- return true;
- }
- }
-
- auto Created = Function.createInstruction(Descriptor->InstructionOpcode);
- if (!Created)
- return importError(OpcodeToken, Created.error());
- MachineInstr *Instruction = *Created;
- Instruction->setFlags(Flags);
- for (ParsedOperand &Parsed : Operands) {
- auto Added = Instruction->addOperand(std::move(Parsed.Operand));
- if (!Added)
- return importError(OpcodeToken, Added.error());
- }
- for (std::size_t Index = 0; Index < Operands.size(); ++Index) {
- if (!Operands[Index].TiedDef)
- continue;
- if (*Operands[Index].TiedDef >= Operands.size())
- return fail(OpcodeToken, "tied-def operand index is out of range");
- auto Tied = Instruction->tieOperands(*Operands[Index].TiedDef, Index);
- if (!Tied)
- return importError(OpcodeToken, Tied.error());
- }
- for (const MachineMemOperand *MemOperand : MemOperands) {
- auto Added = Instruction->addMemOperand(*MemOperand);
- if (!Added)
- return importError(OpcodeToken, Added.error());
- }
- if (DebugNumber != 0) {
- auto SetNumber = Instruction->setDebugInstrNumber(DebugNumber);
- if (!SetNumber)
- return importError(OpcodeToken, SetNumber.error());
- }
- if (DebugLocation) {
- auto SetLocation = Instruction->setDebugLocation(std::move(*DebugLocation));
- if (!SetLocation)
- return importError(OpcodeToken, SetLocation.error());
- }
- if (PreInstrSymbol) {
- auto SetSymbol = Instruction->setPreInstrSymbol(std::move(*PreInstrSymbol));
- if (!SetSymbol)
- return importError(OpcodeToken, SetSymbol.error());
- }
- if (PostInstrSymbol) {
- auto SetSymbol = Instruction->setPostInstrSymbol(std::move(*PostInstrSymbol));
- if (!SetSymbol)
- return importError(OpcodeToken, SetSymbol.error());
- }
- if (HeapAllocMarker) {
- auto SetMarker = Instruction->setHeapAllocMarker(*HeapAllocMarker);
- if (!SetMarker)
- return importError(OpcodeToken, SetMarker.error());
- }
- if (PCSections) {
- auto SetSections = Instruction->setPCSections(*PCSections);
- if (!SetSections)
- return importError(OpcodeToken, SetSections.error());
- }
- if (MMRA) {
- auto SetMMRA = Instruction->setMMRA(*MMRA);
- if (!SetMMRA)
- return importError(OpcodeToken, SetMMRA.error());
- }
- if (CFIType) {
- auto SetType = Instruction->setCFIType(*CFIType);
- if (!SetType)
- return importError(OpcodeToken, SetType.error());
- }
- if (DeactivationSymbol) {
- auto SetSymbol = Instruction->setDeactivationSymbol(std::move(*DeactivationSymbol));
- if (!SetSymbol)
- return importError(OpcodeToken, SetSymbol.error());
- }
- if (InBundle) {
- Flags.set(MachineInstrFlag::BundledWithPred);
- Instruction->setFlags(Flags);
- if (PreviousInstruction != nullptr) {
- MachineInstrFlags PreviousFlags = PreviousInstruction->flags();
- PreviousFlags.set(MachineInstrFlag::BundledWithSucc);
- PreviousInstruction->setFlags(PreviousFlags);
- }
- }
- auto Appended = Block.appendInstruction(*Instruction);
- if (!Appended)
- return importError(OpcodeToken, Appended.error());
-
- ++ParsedInstructionCount;
- Result = Instruction;
- return false;
-}
-
-bool MIParser::Impl::parseSecondPass() {
- Position = 0;
- while (consume(MITokenKind::Newline)) {
- }
- while (!at(MITokenKind::EndOfFile)) {
- if (!at(MITokenKind::MachineBasicBlockLabel))
- return fail("expected a machine basic block definition");
- std::uint32_t ID = 0;
- if (parseBlockDefinition(false, ID))
- return true;
- MachineBasicBlock *Block = Blocks.at(ID);
-
- while (consume(MITokenKind::Newline)) {
- }
- while (atKeyword("liveins") || atKeyword("successors")) {
- if ((atKeyword("liveins") && parseBlockLiveIns(*Block)) ||
- (atKeyword("successors") && parseBlockSuccessors(*Block))) {
- return true;
- }
- if (!token().isNewlineOrEnd())
- return fail("expected a line break after the block list");
- while (consume(MITokenKind::Newline)) {
- }
- }
-
- bool InBundle = false;
- MachineInstr *PreviousInstruction = nullptr;
- while (!at(MITokenKind::MachineBasicBlockLabel) && !at(MITokenKind::EndOfFile)) {
- if (consume(MITokenKind::Newline))
- continue;
- if (consume(MITokenKind::RightBrace)) {
- if (!InBundle)
- return fail("closing brace without an active instruction bundle");
- InBundle = false;
- continue;
- }
-
- MachineInstr *Instruction = nullptr;
- if (parseInstruction(*Block, InBundle, PreviousInstruction, Instruction))
- return true;
- PreviousInstruction = Instruction;
- if (consume(MITokenKind::LeftBrace)) {
- if (InBundle)
- return fail("nested instruction bundles are not allowed");
- MachineInstrFlags BundleFlags = Instruction->flags();
- BundleFlags.set(MachineInstrFlag::BundledWithSucc);
- Instruction->setFlags(BundleFlags);
- InBundle = true;
- }
- if (!token().isNewlineOrEnd() && !at(MITokenKind::RightBrace))
- return fail("expected a line break after the machine instruction");
- }
- if (InBundle)
- return fail("unterminated instruction bundle");
- }
- return false;
-}
-
-bool MIParser::Impl::inferSuccessors() {
- for (MachineBasicBlock *Block = Function.firstBlock(); Block != nullptr; Block = Block->next()) {
- if (ExplicitSuccessorBlocks.contains(Block))
- continue;
-
- bool BlocksFallthrough = true;
- std::vector<MachineBasicBlock *> Successors;
- for (MachineInstr *Instruction = Block->firstInstruction(); Instruction != nullptr;
- Instruction = Instruction->next()) {
- const InstructionDescriptor *Descriptor =
- Target.instructions().descriptor(Instruction->opcode());
- if (Descriptor == nullptr)
- return fail("instruction has no target descriptor while inferring successors");
- if (Descriptor->Flags.has(InstructionFlag::Branch)) {
- for (const MachineOperand &Operand : Instruction->operands()) {
- if (const BasicBlockOperand *TargetBlock = Operand.getIf<BasicBlockOperand>()) {
- 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 &&
- 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());
- }
- }
- return false;
-}
-
-Expected<void> MIParser::Impl::parse() {
- if (ParseAttempted)
- return makeUnexpected(ErrorCode::InvalidArgument, "MI parser can only be run once");
- ParseAttempted = true;
- if (Function.blockCount() != 0 || !Function.allInstructions().empty()) {
- return makeUnexpected(ErrorCode::InvalidArgument,
- "MI parser requires a staging machine function with an empty body");
- }
- for (const MIVirtualRegisterSlot &Slot : Context.VirtualRegisters) {
- if (!Slot.Reg.isVirtual() || !Function.registerInfo().isKnownVirtualRegister(Slot.Reg)) {
- return makeUnexpected(ErrorCode::InvalidArgument,
- "MI parser virtual-register slot maps to an unknown register");
- }
- if (!NumericVirtualRegisters.emplace(Slot.TextID, Slot.Reg).second) {
- return makeUnexpected(ErrorCode::InvalidArgument,
- "MI parser virtual-register text IDs must be unique");
- }
- }
- if (tokenize())
- return failureResult();
- if (parseFirstPass() || parseSecondPass() || inferSuccessors())
- return failureResult();
-
- Function.renumberBlocks();
- if (Options.VerifyAfterParse) {
- auto Verified =
- MachineVerifier::verify(Function, Target,
- MachineVerifierOptions{.Mode = MachineVerifierMode::Generic,
- .Stage = std::nullopt,
- .VerifyProperties = false});
- if (!Verified) {
- static_cast<void>(fail(token(), "parsed machine function failed verification: " +
- std::string(Verified.error().message())));
- return failureResult();
- }
- }
- return {};
-}
-
-MIParser::MIParser(MachineFunction &Function, const TargetDescription &Target,
- std::string SourceName, std::string SourceText, MIParserContext Context,
- MIParserOptions Options)
- : Implementation(std::make_unique<Impl>(Function, Target, std::move(SourceName),
- std::move(SourceText), std::move(Context), Options)) {}
-
-MIParser::MIParser(MIParser &&) noexcept = default;
-
-MIParser &MIParser::operator=(MIParser &&) noexcept = default;
-
-MIParser::~MIParser() = default;
-
-Expected<void> MIParser::parse() {
- return Implementation->parse();
-}
-
-const TextSource &MIParser::source() const noexcept {
- return Implementation->source();
-}
-
-std::span<const TextDiagnostic> MIParser::diagnostics() const noexcept {
- return Implementation->diagnostics();
-}
-
-bool MIParser::failed() const noexcept {
- return Implementation->failed();
-}
-
-} // namespace rcc::mir
diff --git a/backend/lib/MIR/MIPrinter.cpp b/backend/lib/MIR/MIPrinter.cpp
deleted file mode 100644
index 0265564..0000000
--- a/backend/lib/MIR/MIPrinter.cpp
+++ /dev/null
@@ -1,1694 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include "rcc/MIR/MIPrinter.h"
-
-#include "rcc/CodeGen/InlineAsm.h"
-#include "rcc/CodeGen/InstructionDescriptor.h"
-#include "rcc/CodeGen/MachineBasicBlock.h"
-#include "rcc/CodeGen/MachineCFIInfo.h"
-#include "rcc/CodeGen/MachineFunction.h"
-#include "rcc/CodeGen/MachineInstr.h"
-#include "rcc/CodeGen/MachineMemOperand.h"
-#include "rcc/CodeGen/MachineOperand.h"
-#include "rcc/CodeGen/MachineRegisterInfo.h"
-#include "rcc/CodeGen/MachineVerifier.h"
-#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 <algorithm>
-#include <array>
-#include <bit>
-#include <cstddef>
-#include <cstdint>
-#include <limits>
-#include <optional>
-#include <ranges>
-#include <span>
-#include <string>
-#include <string_view>
-#include <unordered_map>
-#include <utility>
-#include <vector>
-
-namespace rcc::mir {
-namespace {
-
-[[nodiscard]] bool isBareNameCharacter(char Character) noexcept {
- return (Character >= 'a' && Character <= 'z') || (Character >= 'A' && Character <= 'Z') ||
- (Character >= '0' && Character <= '9') || Character == '_' || Character == '-' ||
- Character == '.' || Character == '$';
-}
-
-[[nodiscard]] std::string quoteName(std::string_view Name) {
- if (!Name.empty() && std::ranges::all_of(Name, isBareNameCharacter))
- return std::string(Name);
-
- constexpr std::string_view Hex = "0123456789ABCDEF";
- std::string Result;
- Result.reserve(Name.size() + 2U);
- Result.push_back('"');
- for (const char RawCharacter : Name) {
- const auto Character = static_cast<unsigned char>(RawCharacter);
- if (Character >= 0x20U && Character <= 0x7EU && Character != '"' && Character != '\\') {
- Result.push_back(static_cast<char>(Character));
- continue;
- }
- Result.push_back('\\');
- Result.push_back(Hex[Character >> 4U]);
- Result.push_back(Hex[Character & 0xFU]);
- }
- Result.push_back('"');
- return Result;
-}
-
-[[nodiscard]] std::string quoteString(std::string_view Value) {
- std::string Result = quoteName(Value);
- if (!Result.empty() && Result.front() == '"')
- return Result;
- Result.insert(Result.begin(), '"');
- Result.push_back('"');
- return Result;
-}
-
-[[nodiscard]] std::string hexadecimalWords(std::span<const std::uint64_t> Words,
- std::uint32_t BitWidth) {
- constexpr std::string_view Hex = "0123456789ABCDEF";
- const std::size_t DigitCount = (static_cast<std::size_t>(BitWidth) + 3U) / 4U;
- std::string Result(DigitCount, '0');
- for (std::size_t Digit = 0; Digit < DigitCount; ++Digit) {
- const std::size_t BitOffset = Digit * 4U;
- const std::uint64_t Nibble = (Words[BitOffset / 64U] >> (BitOffset % 64U)) & 0xFU;
- Result[DigitCount - Digit - 1U] = Hex[Nibble];
- }
- return Result;
-}
-
-[[nodiscard]] std::string_view integerPredicateName(IntegerPredicate Predicate) noexcept {
- switch (Predicate) {
- case IntegerPredicate::Equal:
- return "eq";
- case IntegerPredicate::NotEqual:
- return "ne";
- case IntegerPredicate::SignedGreaterThan:
- return "sgt";
- case IntegerPredicate::SignedGreaterEqual:
- return "sge";
- case IntegerPredicate::SignedLessThan:
- return "slt";
- case IntegerPredicate::SignedLessEqual:
- return "sle";
- case IntegerPredicate::UnsignedGreaterThan:
- return "ugt";
- case IntegerPredicate::UnsignedGreaterEqual:
- return "uge";
- case IntegerPredicate::UnsignedLessThan:
- return "ult";
- case IntegerPredicate::UnsignedLessEqual:
- return "ule";
- case IntegerPredicate::Count:
- return {};
- }
- return {};
-}
-
-[[nodiscard]] std::string_view floatingPredicateName(FloatingPredicate Predicate) noexcept {
- switch (Predicate) {
- case FloatingPredicate::AlwaysFalse:
- return "false";
- case FloatingPredicate::OrderedEqual:
- return "oeq";
- case FloatingPredicate::OrderedGreaterThan:
- return "ogt";
- case FloatingPredicate::OrderedGreaterEqual:
- return "oge";
- case FloatingPredicate::OrderedLessThan:
- return "olt";
- case FloatingPredicate::OrderedLessEqual:
- return "ole";
- case FloatingPredicate::OrderedNotEqual:
- return "one";
- case FloatingPredicate::Ordered:
- return "ord";
- case FloatingPredicate::Unordered:
- return "uno";
- case FloatingPredicate::UnorderedEqual:
- return "ueq";
- case FloatingPredicate::UnorderedGreaterThan:
- return "ugt";
- case FloatingPredicate::UnorderedGreaterEqual:
- return "uge";
- case FloatingPredicate::UnorderedLessThan:
- return "ult";
- case FloatingPredicate::UnorderedLessEqual:
- return "ule";
- case FloatingPredicate::UnorderedNotEqual:
- return "une";
- case FloatingPredicate::AlwaysTrue:
- return "true";
- case FloatingPredicate::Count:
- return {};
- }
- return {};
-}
-
-[[nodiscard]] std::string_view atomicOrderingName(AtomicOrdering Ordering) noexcept {
- switch (Ordering) {
- case AtomicOrdering::Unordered:
- return "unordered";
- case AtomicOrdering::Monotonic:
- return "monotonic";
- case AtomicOrdering::Acquire:
- return "acquire";
- case AtomicOrdering::Release:
- return "release";
- case AtomicOrdering::AcquireRelease:
- return "acq_rel";
- case AtomicOrdering::SequentiallyConsistent:
- return "seq_cst";
- case AtomicOrdering::NotAtomic:
- return {};
- }
- return {};
-}
-
-[[nodiscard]] Expected<std::string> llvmMIRScalarLowLevelType(LLT Type) {
- if (Type.isToken())
- return "s0";
- if (Type.isAnyScalar())
- return "s" + std::to_string(Type.scalarBitWidth());
- if (Type.isInteger())
- return "i" + std::to_string(Type.scalarBitWidth());
- if (Type.isPointer()) {
- const auto AddressSpace = Type.addressSpace();
- if (!AddressSpace) {
- return makeUnexpected(ErrorCode::VerificationError,
- "pointer low-level type has no address space");
- }
- return "p" + std::to_string(*AddressSpace);
- }
- if (!Type.isFloat()) {
- return makeUnexpected(ErrorCode::VerificationError,
- "invalid scalar low-level type cannot be printed as LLVM MIR");
- }
-
- const auto Semantics = Type.floatSemantics();
- if (!Semantics) {
- return makeUnexpected(ErrorCode::VerificationError,
- "floating low-level type has no floating-point semantics");
- }
- switch (*Semantics) {
- case FloatSemantics::IEEEHalf:
- return "f16";
- case FloatSemantics::BFloat:
- return "bf16";
- case FloatSemantics::IEEESingle:
- return "f32";
- case FloatSemantics::IEEEDouble:
- return "f64";
- case FloatSemantics::IEEEQuad:
- return "f128";
- case FloatSemantics::PPCDoubleDouble:
- 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::X87DoubleExtended:
- case FloatSemantics::Count:
- return makeUnexpected(ErrorCode::Unsupported,
- "fixed LLVM MIR cannot spell this floating low-level type");
- }
- return makeUnexpected(ErrorCode::InternalError, "floating low-level type is unhandled");
-}
-
-[[nodiscard]] Expected<std::string> llvmMIRLowLevelType(LLT Type) {
- if (!Type.isValid()) {
- return makeUnexpected(ErrorCode::VerificationError,
- "invalid low-level type cannot be printed as LLVM MIR");
- }
- if (!Type.isVector())
- return llvmMIRScalarLowLevelType(Type);
-
- const auto ElementType = Type.scalarElementType();
- if (!ElementType) {
- return makeUnexpected(ErrorCode::VerificationError,
- "vector low-level type has no scalar element type");
- }
- auto Scalar = llvmMIRScalarLowLevelType(*ElementType);
- if (!Scalar)
- return std::unexpected(Scalar.error());
-
- std::string Result = "<";
- if (Type.isScalableVector())
- Result.append("vscale x ");
- Result.append(std::to_string(Type.minimumElementCount()));
- Result.append(" x ");
- Result.append(*Scalar);
- Result.push_back('>');
- return Result;
-}
-
-class BodyPrinter final {
-public:
- BodyPrinter(const MachineFunction &Function, const TargetDescription &Target,
- const MIParserContext &Context, MIPrinterOptions Options)
- : Function(Function), Target(Target), Context(Context), Options(Options) {}
-
- [[nodiscard]] Expected<std::string> run();
-
-private:
- [[nodiscard]] Expected<void> initialize();
- [[nodiscard]] Expected<void> printBlock(const MachineBasicBlock &Block);
- [[nodiscard]] Expected<void> printInstruction(const MachineInstr &Instruction);
- [[nodiscard]] Expected<void> printOperand(const MachineOperand &Operand, bool IsExplicitDef,
- bool PrintVirtualType = true);
- [[nodiscard]] Expected<void> printInlineAsmExtraInfo(const MachineOperand &Operand);
- [[nodiscard]] Expected<std::size_t> printInlineAsmOperandFlag(const MachineOperand &Operand);
- [[nodiscard]] Expected<void> printRegisterOperand(const MachineOperand &Operand,
- bool IsExplicitDef, bool PrintVirtualType);
- [[nodiscard]] Expected<void> printTargetFlags(std::uint32_t Flags);
- [[nodiscard]] Expected<void> printMetadataReference(MachineMetadataReference Reference);
- [[nodiscard]] Expected<void> printDILocation(const MachineDILocation &Location,
- std::size_t FrameIndex);
- [[nodiscard]] Expected<void> printCFIInstruction(CFIInstructionIndex Index);
- [[nodiscard]] Expected<void> printMemoryOperand(const MachineMemOperand &Operand);
- [[nodiscard]] Expected<void> printMemoryBase(const MemoryBase &Base, std::int64_t Offset);
-
- [[nodiscard]] Expected<std::uint32_t> blockID(const MachineBasicBlock &Block) const;
- [[nodiscard]] Expected<std::uint32_t> virtualRegisterID(Register Reg) const;
- [[nodiscard]] Expected<std::uint32_t> frameID(FrameIndex Index) const;
- [[nodiscard]] Expected<std::uint32_t> constantPoolID(ConstantPoolIndex Index) const;
- [[nodiscard]] Expected<std::uint32_t> jumpTableID(JumpTableIndex Index) const;
- [[nodiscard]] Expected<std::uint32_t> metadataID(MachineMetadataReference Reference) const;
- [[nodiscard]] Expected<void> appendPhysicalRegister(PhysicalRegister Register);
- void appendBlockReference(const MachineBasicBlock &Block);
- void appendOffset(std::int64_t Offset);
-
- const MachineFunction &Function;
- const TargetDescription &Target;
- const MIParserContext &Context;
- MIPrinterOptions Options;
- std::string Output;
- std::unordered_map<const MachineBasicBlock *, std::uint32_t> BlockIDs;
-};
-
-Expected<void> BodyPrinter::initialize() {
- std::uint64_t NextID = 0;
- for (const MachineBasicBlock *Block = Function.firstBlock(); Block != nullptr;
- Block = Block->next()) {
- if (NextID > std::numeric_limits<std::uint32_t>::max()) {
- return makeUnexpected(ErrorCode::InvalidArgument,
- "machine function has too many blocks to print");
- }
- BlockIDs.emplace(Block, static_cast<std::uint32_t>(NextID));
- ++NextID;
- }
- return {};
-}
-
-Expected<std::uint32_t> BodyPrinter::blockID(const MachineBasicBlock &Block) const {
- const auto Found = BlockIDs.find(&Block);
- if (Found == BlockIDs.end())
- return makeUnexpected(ErrorCode::VerificationError,
- "machine operand references an unlinked basic block");
- return Found->second;
-}
-
-Expected<std::uint32_t> BodyPrinter::virtualRegisterID(Register Reg) const {
- if (!Context.VirtualRegisters.empty()) {
- const auto Found =
- std::ranges::find_if(Context.VirtualRegisters,
- [Reg](const MIVirtualRegisterSlot &Slot) { return Slot.Reg == Reg; });
- if (Found == Context.VirtualRegisters.end()) {
- return makeUnexpected(ErrorCode::VerificationError, "virtual register has no MIR text slot");
- }
- return Found->TextID;
- }
- const auto VirtualIndex = Reg.virtualIndex();
- if (!VirtualIndex)
- return makeUnexpected(ErrorCode::VerificationError, "virtual register has no numeric index");
- return *VirtualIndex;
-}
-
-Expected<std::uint32_t> BodyPrinter::frameID(FrameIndex Index) const {
- const auto InStack = std::ranges::find_if(
- Context.StackObjects, [Index](const MIFrameObjectSlot &Slot) { return Slot.Index == Index; });
- if (InStack != Context.StackObjects.end())
- return InStack->TextID;
- const auto InFixed =
- std::ranges::find_if(Context.FixedStackObjects,
- [Index](const MIFrameObjectSlot &Slot) { return Slot.Index == Index; });
- if (InFixed != Context.FixedStackObjects.end())
- return InFixed->TextID;
- return makeUnexpected(ErrorCode::VerificationError, "frame index has no MIR text slot");
-}
-
-Expected<std::uint32_t> BodyPrinter::constantPoolID(ConstantPoolIndex Index) const {
- const auto Found =
- std::ranges::find_if(Context.ConstantPoolItems,
- [Index](const MIConstantPoolSlot &Slot) { return Slot.Index == Index; });
- if (Found == Context.ConstantPoolItems.end()) {
- return makeUnexpected(ErrorCode::VerificationError, "constant-pool index has no MIR text slot");
- }
- return Found->TextID;
-}
-
-Expected<std::uint32_t> BodyPrinter::jumpTableID(JumpTableIndex Index) const {
- const auto Found = std::ranges::find_if(
- Context.JumpTables, [Index](const MIJumpTableSlot &Slot) { return Slot.Index == Index; });
- if (Found == Context.JumpTables.end())
- return makeUnexpected(ErrorCode::VerificationError, "jump-table index has no MIR text slot");
- return Found->TextID;
-}
-
-Expected<std::uint32_t> BodyPrinter::metadataID(MachineMetadataReference Reference) const {
- const auto Found =
- std::ranges::find_if(Context.Metadata, [Reference](const MIMetadataSlot &Slot) {
- return Slot.Reference == Reference;
- });
- if (Found != Context.Metadata.end())
- return Found->TextID;
- if (Reference.scope() == MachineMetadataScope::MachineFunction)
- return Reference.slot();
- return makeUnexpected(ErrorCode::VerificationError,
- "embedded metadata reference has no MIR text slot");
-}
-
-Expected<void> BodyPrinter::appendPhysicalRegister(PhysicalRegister Register) {
- const auto Name = Target.registers().physicalRegisterMIRName(Register);
- if (!Name)
- return makeUnexpected(ErrorCode::VerificationError, "physical register has no MIR name");
- Output.push_back('$');
- Output.append(*Name);
- return {};
-}
-
-void BodyPrinter::appendBlockReference(const MachineBasicBlock &Block) {
- Output.append("%bb.");
- Output.append(std::to_string(BlockIDs.at(&Block)));
-}
-
-void BodyPrinter::appendOffset(std::int64_t Offset) {
- if (Offset == 0)
- return;
- if (Offset > 0) {
- Output.append(" + ");
- Output.append(std::to_string(Offset));
- return;
- }
- Output.append(" - ");
- const std::uint64_t Magnitude = Offset == std::numeric_limits<std::int64_t>::min()
- ? std::uint64_t{1} << 63U
- : static_cast<std::uint64_t>(-Offset);
- Output.append(std::to_string(Magnitude));
-}
-
-Expected<void> BodyPrinter::printTargetFlags(std::uint32_t Flags) {
- if (Flags == 0)
- return {};
- auto Names = Target.mirText().operandFlagNames(Flags);
- if (!Names)
- return std::unexpected(Names.error());
- Output.append("target-flags(");
- for (std::size_t Index = 0; Index < Names->size(); ++Index) {
- if (Index != 0)
- Output.append(", ");
- Output.append((*Names)[Index]);
- }
- Output.append(") ");
- return {};
-}
-
-Expected<void> BodyPrinter::printMetadataReference(MachineMetadataReference Reference) {
- auto ID = metadataID(Reference);
- if (!ID)
- return std::unexpected(ID.error());
- Output.push_back('!');
- Output.append(std::to_string(*ID));
- return {};
-}
-
-Expected<void> BodyPrinter::printDILocation(const MachineDILocation &Location,
- std::size_t FrameIndex) {
- const auto Frames = Location.inlineChain();
- if (FrameIndex >= Frames.size()) {
- return makeUnexpected(ErrorCode::VerificationError,
- "inline DILocation has an invalid frame index");
- }
- const MachineDILocationFrame &Frame = Frames[FrameIndex];
- Output.append("!DILocation(line: ");
- Output.append(std::to_string(Frame.Line));
- if (Options.Mode == MIPrintMode::Complete || Frame.Column != 0) {
- Output.append(", column: ");
- Output.append(std::to_string(Frame.Column));
- }
- Output.append(", scope: ");
- if (auto Printed = printMetadataReference(Frame.Scope); !Printed)
- return Printed;
- if (FrameIndex + 1U < Frames.size()) {
- Output.append(", inlinedAt: ");
- if (auto Printed = printDILocation(Location, FrameIndex + 1U); !Printed)
- return Printed;
- } else if (Location.terminalInlinedAt()) {
- Output.append(", inlinedAt: ");
- if (auto Printed = printMetadataReference(*Location.terminalInlinedAt()); !Printed) {
- return Printed;
- }
- }
- if (Options.Mode == MIPrintMode::Complete || Frame.IsImplicitCode) {
- Output.append(", isImplicitCode: ");
- Output.append(Frame.IsImplicitCode ? "true" : "false");
- }
- if (Options.Mode == MIPrintMode::Complete || Frame.AtomGroup != 0) {
- Output.append(", atomGroup: ");
- Output.append(std::to_string(Frame.AtomGroup));
- }
- if (Options.Mode == MIPrintMode::Complete || Frame.AtomRank != 0) {
- Output.append(", atomRank: ");
- Output.append(std::to_string(Frame.AtomRank));
- }
- Output.push_back(')');
- return {};
-}
-
-Expected<void> BodyPrinter::printRegisterOperand(const MachineOperand &Operand, bool IsExplicitDef,
- bool PrintVirtualType) {
- const RegisterOperandFlags Flags = Operand.registerFlags();
- if (Flags.has(RegisterOperandFlag::Implicit) && Flags.has(RegisterOperandFlag::Define)) {
- Output.append("implicit-def ");
- } else {
- if (!IsExplicitDef && Flags.has(RegisterOperandFlag::Define))
- Output.append("def ");
- if (Flags.has(RegisterOperandFlag::Implicit))
- Output.append("implicit ");
- }
- if (Flags.has(RegisterOperandFlag::Dead))
- Output.append("dead ");
- if (Flags.has(RegisterOperandFlag::Kill))
- Output.append("killed ");
- if (Flags.has(RegisterOperandFlag::Undef))
- Output.append("undef ");
- if (Flags.has(RegisterOperandFlag::InternalRead))
- Output.append("internal ");
- if (Flags.has(RegisterOperandFlag::EarlyClobber))
- Output.append("early-clobber ");
- if (Flags.has(RegisterOperandFlag::Debug))
- Output.append("debug-use ");
- if (Flags.has(RegisterOperandFlag::Renamable))
- Output.append("renamable ");
-
- const auto RegisterValue = Operand.registerValue();
- if (!RegisterValue) {
- return makeUnexpected(ErrorCode::VerificationError, "register operand has no register value");
- }
- const Register Reg = *RegisterValue;
- if (Reg.isNoRegister()) {
- Output.append("$noreg");
- } else if (Reg.isPhysical()) {
- const auto Physical = Reg.physicalRegister();
- if (!Physical) {
- return makeUnexpected(ErrorCode::VerificationError,
- "physical register has no physical-register value");
- }
- auto Printed = appendPhysicalRegister(*Physical);
- if (!Printed)
- return Printed;
- } else {
- auto Info = Function.registerInfo().virtualRegisterInfo(Reg);
- if (!Info)
- return std::unexpected(Info.error());
- const VirtualRegisterInfo &RegisterInfo = Info->get();
- Output.push_back('%');
- if (RegisterInfo.Name) {
- Output.append(*RegisterInfo.Name);
- } else {
- auto VirtualIndex = virtualRegisterID(Reg);
- if (!VirtualIndex)
- return std::unexpected(VirtualIndex.error());
- Output.append(std::to_string(*VirtualIndex));
- }
- if (Operand.subReg().value() != 0) {
- const SubRegIndexDesc *SubReg = Target.registers().subRegIndex(Operand.subReg());
- if (SubReg == nullptr)
- return makeUnexpected(ErrorCode::VerificationError,
- "virtual register has an unknown subregister");
- Output.push_back('.');
- Output.append(SubReg->Name);
- }
-
- const bool PrintRegisterConstraint =
- IsExplicitDef || Function.registerInfo().getUniqueVRegDef(Reg) == nullptr;
- if (PrintRegisterConstraint && RegisterInfo.RegClass) {
- const auto Name = Target.registers().registerClassMIRName(*RegisterInfo.RegClass);
- if (!Name)
- return makeUnexpected(ErrorCode::VerificationError,
- "virtual register class has no MIR name");
- Output.push_back(':');
- Output.append(*Name);
- } else if (PrintRegisterConstraint && RegisterInfo.Bank) {
- const auto Name = Target.registers().registerBankMIRName(*RegisterInfo.Bank);
- if (!Name)
- return makeUnexpected(ErrorCode::VerificationError,
- "virtual register bank has no MIR name");
- Output.push_back(':');
- Output.append(*Name);
- } else if (PrintRegisterConstraint && RegisterInfo.Type) {
- Output.append(":_");
- }
- if (PrintVirtualType && RegisterInfo.Type) {
- auto Type = llvmMIRLowLevelType(*RegisterInfo.Type);
- if (!Type)
- return std::unexpected(Type.error());
- Output.push_back('(');
- Output.append(*Type);
- Output.push_back(')');
- }
- }
-
- if (Operand.tiedOperandIndex() && Operand.isUse()) {
- Output.append("(tied-def ");
- Output.append(std::to_string(*Operand.tiedOperandIndex()));
- Output.push_back(')');
- }
- return {};
-}
-
-Expected<void> BodyPrinter::printCFIInstruction(CFIInstructionIndex Index) {
- const MachineCFIInstruction *Instruction = Function.cfiInfo().instruction(Index);
- if (Instruction == nullptr)
- return makeUnexpected(ErrorCode::VerificationError,
- "CFI operand references an unknown instruction");
- const auto PrintRegister = [this](DwarfRegisterNumber Dwarf) -> Expected<void> {
- const auto Register = Target.mirText().physicalRegister(Dwarf.value());
- if (!Register) {
- return makeUnexpected(ErrorCode::VerificationError,
- "CFI instruction has no canonical physical register");
- }
- return appendPhysicalRegister(*Register);
- };
- const auto PrintRegisterOffset =
- [this, &PrintRegister](std::string_view Name,
- const MachineCFIRegisterOffsetRule &Rule) -> Expected<void> {
- Output.append(Name);
- Output.push_back(' ');
- if (auto Printed = PrintRegister(Rule.Register); !Printed)
- return Printed;
- Output.append(", ");
- Output.append(std::to_string(Rule.Offset));
- return {};
- };
-
- switch (Instruction->operation()) {
- case MachineCFIOperation::SameValue: {
- Output.append("same_value ");
- return PrintRegister(Instruction->getIf<MachineCFIRegisterRule>()->Register);
- }
- case MachineCFIOperation::RememberState:
- Output.append("remember_state");
- return {};
- case MachineCFIOperation::RestoreState:
- Output.append("restore_state");
- return {};
- case MachineCFIOperation::Offset:
- return PrintRegisterOffset("offset", *Instruction->getIf<MachineCFIRegisterOffsetRule>());
- case MachineCFIOperation::LLVMDefAddressSpaceCFA: {
- const auto &Rule = *Instruction->getIf<MachineCFIAddressSpaceCFARule>();
- Output.append("llvm_def_aspace_cfa ");
- if (auto Printed = PrintRegister(Rule.Register); !Printed)
- return Printed;
- Output.append(", ");
- Output.append(std::to_string(Rule.Offset));
- Output.append(", ");
- Output.append(std::to_string(Rule.AddressSpace));
- return {};
- }
- case MachineCFIOperation::DefCFARegister:
- Output.append("def_cfa_register ");
- return PrintRegister(Instruction->getIf<MachineCFIRegisterRule>()->Register);
- case MachineCFIOperation::DefCFAOffset:
- Output.append("def_cfa_offset ");
- Output.append(std::to_string(Instruction->getIf<MachineCFIOffsetRule>()->Offset));
- return {};
- case MachineCFIOperation::DefCFA:
- return PrintRegisterOffset("def_cfa", *Instruction->getIf<MachineCFIRegisterOffsetRule>());
- case MachineCFIOperation::RelativeOffset:
- return PrintRegisterOffset("rel_offset", *Instruction->getIf<MachineCFIRegisterOffsetRule>());
- case MachineCFIOperation::AdjustCFAOffset:
- Output.append("adjust_cfa_offset ");
- Output.append(std::to_string(Instruction->getIf<MachineCFIOffsetRule>()->Offset));
- return {};
- case MachineCFIOperation::Escape: {
- Output.append("escape ");
- constexpr std::string_view Hex = "0123456789ABCDEF";
- const auto &Bytes = Instruction->getIf<MachineCFIEscapeRule>()->Bytes;
- for (std::size_t ByteIndex = 0; ByteIndex < Bytes.size(); ++ByteIndex) {
- if (ByteIndex != 0)
- Output.append(", ");
- Output.append("0x");
- Output.push_back(Hex[Bytes[ByteIndex] >> 4U]);
- Output.push_back(Hex[Bytes[ByteIndex] & 0xFU]);
- }
- return {};
- }
- case MachineCFIOperation::Restore:
- Output.append("restore ");
- return PrintRegister(Instruction->getIf<MachineCFIRegisterRule>()->Register);
- case MachineCFIOperation::Undefined:
- Output.append("undefined ");
- return PrintRegister(Instruction->getIf<MachineCFIRegisterRule>()->Register);
- case MachineCFIOperation::Register: {
- const auto &Rule = *Instruction->getIf<MachineCFIRegisterRegisterRule>();
- Output.append("register ");
- if (auto Printed = PrintRegister(Rule.Register); !Printed)
- return Printed;
- Output.append(", ");
- return PrintRegister(Rule.SourceRegister);
- }
- case MachineCFIOperation::WindowSave:
- Output.append("window_save");
- return {};
- case MachineCFIOperation::NegateReturnAddressState:
- Output.append("negate_ra_sign_state");
- return {};
- case MachineCFIOperation::NegateReturnAddressStateWithPC:
- Output.append("negate_ra_sign_state_with_pc");
- return {};
- case MachineCFIOperation::GNUArgsSize:
- case MachineCFIOperation::Label:
- case MachineCFIOperation::ValueOffset:
- return makeUnexpected(
- ErrorCode::Unsupported,
- "CFI operation has no textual representation in the fixed LLVM MIR baseline");
- case MachineCFIOperation::LLVMRegisterPair: {
- const auto &Rule = *Instruction->getIf<MachineCFIRegisterPairRule>();
- Output.append("llvm_register_pair ");
- if (auto Printed = PrintRegister(Rule.Register); !Printed)
- return Printed;
- Output.append(", ");
- if (auto Printed = PrintRegister(Rule.FirstRegister); !Printed)
- return Printed;
- Output.append(", ");
- Output.append(std::to_string(Rule.FirstSizeInBits));
- Output.append(", ");
- if (auto Printed = PrintRegister(Rule.SecondRegister); !Printed)
- return Printed;
- Output.append(", ");
- Output.append(std::to_string(Rule.SecondSizeInBits));
- return {};
- }
- case MachineCFIOperation::LLVMVectorRegisters: {
- const auto &Rule = *Instruction->getIf<MachineCFIVectorRegistersRule>();
- Output.append("llvm_vector_registers ");
- if (auto Printed = PrintRegister(Rule.Register); !Printed)
- return Printed;
- for (const MachineCFIVectorRegisterLane &Lane : Rule.VectorRegisters) {
- Output.append(", ");
- if (auto Printed = PrintRegister(Lane.Register); !Printed)
- return Printed;
- Output.append(", ");
- Output.append(std::to_string(Lane.Lane));
- Output.append(", ");
- Output.append(std::to_string(Lane.SizeInBits));
- }
- return {};
- }
- case MachineCFIOperation::LLVMVectorOffset: {
- const auto &Rule = *Instruction->getIf<MachineCFIVectorOffsetRule>();
- Output.append("llvm_vector_offset ");
- if (auto Printed = PrintRegister(Rule.Register); !Printed)
- return Printed;
- Output.append(", ");
- Output.append(std::to_string(Rule.RegisterSizeInBits));
- Output.append(", ");
- if (auto Printed = PrintRegister(Rule.MaskRegister); !Printed)
- return Printed;
- Output.append(", ");
- Output.append(std::to_string(Rule.MaskRegisterSizeInBits));
- Output.append(", ");
- Output.append(std::to_string(Rule.Offset));
- return {};
- }
- case MachineCFIOperation::LLVMVectorRegisterMask: {
- const auto &Rule = *Instruction->getIf<MachineCFIVectorRegisterMaskRule>();
- Output.append("llvm_vector_register_mask ");
- if (auto Printed = PrintRegister(Rule.Register); !Printed)
- return Printed;
- Output.append(", ");
- if (auto Printed = PrintRegister(Rule.SpillRegister); !Printed)
- return Printed;
- Output.append(", ");
- Output.append(std::to_string(Rule.SpillRegisterLaneSizeInBits));
- Output.append(", ");
- if (auto Printed = PrintRegister(Rule.MaskRegister); !Printed)
- return Printed;
- Output.append(", ");
- Output.append(std::to_string(Rule.MaskRegisterSizeInBits));
- return {};
- }
- case MachineCFIOperation::Count:
- return makeUnexpected(ErrorCode::VerificationError, "CFI instruction has an invalid operation");
- }
- return makeUnexpected(ErrorCode::InternalError, "CFI printer did not handle an operation");
-}
-
-Expected<void> BodyPrinter::printOperand(const MachineOperand &Operand, bool IsExplicitDef,
- bool PrintVirtualType) {
- if (Operand.isRegister())
- return printRegisterOperand(Operand, IsExplicitDef, PrintVirtualType);
- if (auto Flags = printTargetFlags(Operand.targetFlags()); !Flags)
- return Flags;
-
- switch (Operand.kind()) {
- case MachineOperand::Kind::Register:
- return makeUnexpected(ErrorCode::InternalError,
- "register operand reached the non-register printer");
- case MachineOperand::Kind::Immediate:
- Output.append(std::to_string(*Operand.getIf<std::int64_t>()));
- return {};
- case MachineOperand::Kind::IntegerImmediate: {
- const IntegerImmediate &Value = Operand.getIf<IntegerImmediateOperand>()->Value;
- Output.push_back('i');
- Output.append(std::to_string(Value.bitWidth()));
- Output.push_back(' ');
- if (Value.bitWidth() == 1U)
- Output.append(Value.isZero() ? "false" : "true");
- else
- Output.append(Value.toSignedDecimal());
- return {};
- }
- case MachineOperand::Kind::FloatingImmediate: {
- const FloatingPointBits &Bits = Operand.getIf<FloatingImmediateOperand>()->Bits;
- auto Constant = GenericConstantData::floating(Bits);
- if (!Constant)
- return std::unexpected(Constant.error());
- auto Text = printLLVMConstant(*Constant);
- if (!Text)
- return std::unexpected(Text.error());
- Output.append(*Text);
- return {};
- }
- case MachineOperand::Kind::BasicBlock: {
- const MachineBasicBlock *Block = Operand.getIf<BasicBlockOperand>()->Block;
- if (Block == nullptr || !BlockIDs.contains(Block)) {
- return makeUnexpected(ErrorCode::VerificationError,
- "basic-block operand references an unlinked block");
- }
- appendBlockReference(*Block);
- return {};
- }
- case MachineOperand::Kind::FrameIndex: {
- const auto &Frame = *Operand.getIf<FrameIndexOperand>();
- auto ID = frameID(Frame.Index);
- if (!ID)
- return std::unexpected(ID.error());
- const auto Stack = std::ranges::find_if(
- Context.StackObjects,
- [Index = Frame.Index](const MIFrameObjectSlot &Slot) { return Slot.Index == Index; });
- if (Stack != Context.StackObjects.end()) {
- Output.append("%stack.");
- Output.append(std::to_string(*ID));
- if (Stack->Name) {
- Output.push_back('.');
- Output.append(quoteName(*Stack->Name));
- }
- } else {
- Output.append("%fixed-stack.");
- Output.append(std::to_string(*ID));
- }
- appendOffset(Frame.Offset);
- return {};
- }
- case MachineOperand::Kind::ConstantPoolIndex: {
- const auto &Constant = *Operand.getIf<ConstantPoolOperand>();
- auto ID = constantPoolID(Constant.Index);
- if (!ID)
- return std::unexpected(ID.error());
- Output.append("%const.");
- Output.append(std::to_string(*ID));
- appendOffset(Constant.Offset);
- return {};
- }
- case MachineOperand::Kind::JumpTableIndex: {
- auto ID = jumpTableID(Operand.getIf<JumpTableOperand>()->Index);
- if (!ID)
- return std::unexpected(ID.error());
- Output.append("%jump-table.");
- Output.append(std::to_string(*ID));
- return {};
- }
- case MachineOperand::Kind::GlobalSymbol: {
- const auto &Global = *Operand.getIf<GlobalSymbolOperand>();
- Output.push_back('@');
- Output.append(quoteName(Global.Name));
- appendOffset(Global.Offset);
- return {};
- }
- case MachineOperand::Kind::ExternalSymbol: {
- const auto &External = *Operand.getIf<ExternalSymbolOperand>();
- Output.push_back('&');
- Output.append(quoteName(External.Name));
- appendOffset(External.Offset);
- return {};
- }
- case MachineOperand::Kind::BlockAddress: {
- const auto &Address = *Operand.getIf<BlockAddressOperand>();
- Output.append("blockaddress(@");
- Output.append(quoteName(Address.FunctionName));
- Output.append(", %ir-block.");
- Output.append(quoteName(Address.BlockName));
- Output.push_back(')');
- appendOffset(Address.Offset);
- return {};
- }
- case MachineOperand::Kind::RegisterMask: {
- const RegisterMask &Mask = *Operand.getIf<RegisterMaskOperand>()->Mask;
- if (const auto Name = Target.mirText().registerMaskName(Mask)) {
- Output.append(*Name);
- return {};
- }
- Output.append("CustomRegMask(");
- bool First = true;
- for (const PhysicalRegisterDesc &Register : Target.registers().physicalRegisters()) {
- if (!Mask.preserves(Register.Reg))
- continue;
- if (!First)
- Output.append(", ");
- First = false;
- if (auto Printed = appendPhysicalRegister(Register.Reg); !Printed)
- return Printed;
- }
- Output.push_back(')');
- return {};
- }
- case MachineOperand::Kind::LiveOutRegisterMask: {
- const RegisterMask &Mask = *Operand.getIf<LiveOutRegisterMaskOperand>()->Mask;
- Output.append("liveout(");
- bool First = true;
- for (const PhysicalRegisterDesc &Register : Target.registers().physicalRegisters()) {
- if (!Mask.preserves(Register.Reg))
- continue;
- if (!First)
- Output.append(", ");
- First = false;
- if (auto Printed = appendPhysicalRegister(Register.Reg); !Printed)
- return Printed;
- }
- Output.push_back(')');
- return {};
- }
- case MachineOperand::Kind::Metadata: {
- const MachineMetadataValue &Value = Operand.getIf<MetadataOperand>()->Value;
- if (const auto *Reference = Value.reference())
- return printMetadataReference(*Reference);
- const MachineDIExpression *Expression = Value.expression();
- if (Expression == nullptr) {
- return makeUnexpected(ErrorCode::VerificationError,
- "metadata operand has no printable value");
- }
- Output.append(formatDIExpression(Expression->elements()));
- return {};
- }
- case MachineOperand::Kind::TargetIndex: {
- const auto &TargetIndexValue = *Operand.getIf<TargetIndexOperand>();
- const auto Name = Target.mirText().targetIndexName(TargetIndexValue.Index);
- if (!Name)
- return makeUnexpected(ErrorCode::VerificationError, "target index has no MIR name");
- Output.append("target-index(");
- Output.append(*Name);
- Output.push_back(')');
- appendOffset(TargetIndexValue.Offset);
- return {};
- }
- case MachineOperand::Kind::MCSymbol: {
- const auto &Symbol = *Operand.getIf<MCSymbolOperand>();
- Output.append("<mcsymbol ");
- Output.append(quoteName(Symbol.Name));
- Output.push_back('>');
- appendOffset(Symbol.Offset);
- return {};
- }
- case MachineOperand::Kind::CFIIndex:
- return printCFIInstruction(Operand.getIf<CFIIndexOperand>()->Index);
- case MachineOperand::Kind::Intrinsic: {
- const auto Name = Target.mirText().intrinsicName(Operand.getIf<IntrinsicOperand>()->ID);
- if (!Name)
- return makeUnexpected(ErrorCode::VerificationError, "intrinsic has no MIR name");
- Output.append("intrinsic(@");
- Output.append(*Name);
- Output.push_back(')');
- return {};
- }
- case MachineOperand::Kind::Predicate: {
- const PredicateOperand &Predicate = *Operand.getIf<PredicateOperand>();
- if (const auto *Integer = Predicate.integerPredicate()) {
- Output.append("intpred(");
- Output.append(integerPredicateName(*Integer));
- } else {
- Output.append("floatpred(");
- Output.append(floatingPredicateName(*Predicate.floatingPredicate()));
- }
- Output.push_back(')');
- return {};
- }
- case MachineOperand::Kind::ShuffleMask: {
- Output.append("shufflemask(");
- const auto &Elements = Operand.getIf<ShuffleMaskOperand>()->Elements;
- for (std::size_t Index = 0; Index < Elements.size(); ++Index) {
- if (Index != 0)
- Output.append(", ");
- if (Elements[Index] == ShuffleMaskOperand::Undef)
- Output.append("undef");
- else
- Output.append(std::to_string(Elements[Index]));
- }
- Output.push_back(')');
- return {};
- }
- case MachineOperand::Kind::DebugInstrRef: {
- const auto &Reference = *Operand.getIf<DebugInstrRefOperand>();
- Output.append("dbg-instr-ref(");
- Output.append(std::to_string(Reference.InstructionNumber));
- Output.append(", ");
- Output.append(std::to_string(Reference.OperandNumber));
- Output.push_back(')');
- return {};
- }
- case MachineOperand::Kind::LaneMask:
- Output.append("lanemask(0x");
- Output.append(
- hexadecimalWords(std::array{Operand.getIf<LaneMaskOperand>()->Mask.rawValue()}, 64));
- Output.push_back(')');
- return {};
- case MachineOperand::Kind::Count:
- return makeUnexpected(ErrorCode::VerificationError, "machine operand has an invalid kind");
- }
- return makeUnexpected(ErrorCode::InternalError, "machine operand printer did not handle a kind");
-}
-
-Expected<void> BodyPrinter::printInlineAsmExtraInfo(const MachineOperand &Operand) {
- const auto *Value = Operand.getIf<std::int64_t>();
- if (Value == nullptr || Operand.targetFlags() != 0) {
- return makeUnexpected(ErrorCode::VerificationError,
- "inline assembly extra info must be an unflagged immediate");
- }
- const InlineAsmExtraInfo ExtraInfo(static_cast<std::uint32_t>(*Value));
- const std::vector<std::string_view> Names = ExtraInfo.names();
- for (std::size_t Index = 0; Index < Names.size(); ++Index) {
- if (Index != 0)
- Output.push_back(' ');
- Output.append(Names[Index]);
- }
- return {};
-}
-
-Expected<std::size_t> BodyPrinter::printInlineAsmOperandFlag(const MachineOperand &Operand) {
- const auto *Value = Operand.getIf<std::int64_t>();
- if (Value == nullptr || *Value < 0 ||
- static_cast<std::uint64_t>(*Value) > std::numeric_limits<std::uint32_t>::max() ||
- Operand.targetFlags() != 0) {
- return makeUnexpected(ErrorCode::VerificationError,
- "inline assembly operand flag must be an unflagged 32-bit immediate");
- }
-
- const InlineAsmOperandFlag Flag(static_cast<std::uint32_t>(*Value));
- const std::string_view KindName = InlineAsmOperandFlag::kindName(Flag.kind());
- if (KindName.empty() || Flag.operandCount() == 0) {
- return makeUnexpected(ErrorCode::VerificationError,
- "inline assembly operand flag has an invalid kind or operand count");
- }
- Output.append(KindName);
-
- if (const auto MatchingOperand = Flag.matchingOperand()) {
- Output.append(" tiedto:$");
- Output.append(std::to_string(*MatchingOperand));
- return Flag.operandCount();
- }
- if (Flag.kind() == InlineAsmOperandKind::Memory ||
- Flag.kind() == InlineAsmOperandKind::Function) {
- const auto Constraint = InlineAsmOperandFlag::memoryConstraintName(Flag.memoryConstraint());
- if (Constraint) {
- Output.push_back(':');
- Output.append(*Constraint);
- }
- return Flag.operandCount();
- }
- if (Flag.isRegisterKind()) {
- if (const auto RegisterClass = Flag.registerClass()) {
- const auto Name =
- Target.registers().registerClassMIRName(RegisterClassID::fromValue(*RegisterClass));
- if (!Name) {
- return makeUnexpected(ErrorCode::VerificationError,
- "inline assembly operand flag references an unknown register class");
- }
- Output.push_back(':');
- Output.append(*Name);
- }
- }
- return Flag.operandCount();
-}
-
-Expected<void> BodyPrinter::printMemoryBase(const MemoryBase &Base, std::int64_t Offset) {
- switch (Base.kind()) {
- case MemoryBase::Kind::Unknown:
- Output.append("unknown-address");
- break;
- case MemoryBase::Kind::FrameIndex: {
- const auto Frame = Base.frameIndex();
- if (!Frame) {
- return makeUnexpected(ErrorCode::VerificationError,
- "frame-index memory base has no frame index");
- }
- const FrameIndex Index = *Frame;
- auto ID = frameID(Index);
- if (!ID)
- return std::unexpected(ID.error());
- const auto Stack =
- std::ranges::find_if(Context.StackObjects, [Index](const MIFrameObjectSlot &Slot) {
- return Slot.Index == Index;
- });
- if (Stack != Context.StackObjects.end()) {
- Output.append("%stack.");
- Output.append(std::to_string(*ID));
- if (Stack->Name) {
- Output.push_back('.');
- Output.append(quoteName(*Stack->Name));
- }
- } else {
- Output.append("%fixed-stack.");
- Output.append(std::to_string(*ID));
- }
- break;
- }
- case MemoryBase::Kind::ConstantPool: {
- const auto Constant = Base.constantPoolIndex();
- if (!Constant) {
- return makeUnexpected(ErrorCode::VerificationError, "constant-pool memory base has no index");
- }
- auto ID = constantPoolID(*Constant);
- if (!ID)
- return std::unexpected(ID.error());
- Output.append("%const.");
- Output.append(std::to_string(*ID));
- break;
- }
- case MemoryBase::Kind::JumpTable: {
- const auto JumpTable = Base.jumpTableIndex();
- if (!JumpTable) {
- return makeUnexpected(ErrorCode::VerificationError, "jump-table memory base has no index");
- }
- auto ID = jumpTableID(*JumpTable);
- if (!ID)
- return std::unexpected(ID.error());
- Output.append("%jump-table.");
- Output.append(std::to_string(*ID));
- break;
- }
- case MemoryBase::Kind::GlobalSymbol: {
- const auto &Name = Base.symbolName();
- if (!Name) {
- return makeUnexpected(ErrorCode::VerificationError, "global memory base has no symbol name");
- }
- Output.push_back('@');
- Output.append(quoteName(*Name));
- break;
- }
- case MemoryBase::Kind::ExternalSymbol: {
- const auto &Name = Base.symbolName();
- if (!Name) {
- return makeUnexpected(ErrorCode::VerificationError,
- "external memory base has no symbol name");
- }
- Output.push_back('&');
- Output.append(quoteName(*Name));
- break;
- }
- case MemoryBase::Kind::IRValue: {
- const auto &Name = Base.symbolName();
- if (!Name) {
- return makeUnexpected(ErrorCode::VerificationError, "IR-value memory base has no value name");
- }
- Output.append("%ir.");
- Output.append(quoteName(*Name));
- break;
- }
- case MemoryBase::Kind::IRConstant: {
- const GenericConstantData *Constant = Base.constantValue();
- if (Constant == nullptr) {
- return makeUnexpected(ErrorCode::VerificationError,
- "IR-constant memory base has no constant value");
- }
- auto Printed = printLLVMConstant(*Constant);
- if (!Printed)
- return std::unexpected(Printed.error());
- Output.push_back('`');
- Output.append(*Printed);
- Output.push_back('`');
- break;
- }
- case MemoryBase::Kind::Stack:
- Output.append("stack");
- break;
- case MemoryBase::Kind::GOT:
- Output.append("got");
- break;
- case MemoryBase::Kind::ConstantPoolPseudo:
- Output.append("constant-pool");
- break;
- case MemoryBase::Kind::JumpTablePseudo:
- Output.append("jump-table");
- break;
- case MemoryBase::Kind::CallEntryGlobal: {
- const auto &Name = Base.symbolName();
- if (!Name) {
- return makeUnexpected(ErrorCode::VerificationError,
- "global call-entry memory base has no symbol name");
- }
- Output.append("call-entry @");
- Output.append(quoteName(*Name));
- break;
- }
- case MemoryBase::Kind::CallEntryExternal: {
- const auto &Name = Base.symbolName();
- if (!Name) {
- return makeUnexpected(ErrorCode::VerificationError,
- "external call-entry memory base has no symbol name");
- }
- Output.append("call-entry &");
- Output.append(quoteName(*Name));
- break;
- }
- case MemoryBase::Kind::Custom: {
- const auto &Name = Base.symbolName();
- if (!Name) {
- return makeUnexpected(ErrorCode::VerificationError, "custom memory base has no name");
- }
- Output.append("custom ");
- Output.append(quoteName(*Name));
- break;
- }
- }
- appendOffset(Offset);
- return {};
-}
-
-Expected<void> BodyPrinter::printMemoryOperand(const MachineMemOperand &Operand) {
- const MachineMemOperandDesc &Description = Operand.description();
- Output.push_back('(');
- if (Description.Accesses.has(MemoryAccessFlag::Volatile))
- Output.append("volatile ");
- if (Description.Accesses.has(MemoryAccessFlag::NonTemporal))
- Output.append("non-temporal ");
- if (Description.Accesses.has(MemoryAccessFlag::Dereferenceable))
- Output.append("dereferenceable ");
- if (Description.Accesses.has(MemoryAccessFlag::Invariant))
- Output.append("invariant ");
- if (Description.TargetFlags != 0) {
- auto Names = Target.mirText().machineMemOperandFlagNames(Description.TargetFlags);
- if (!Names)
- return std::unexpected(Names.error());
- for (std::string_view Name : *Names) {
- Output.append(quoteName(Name));
- Output.push_back(' ');
- }
- }
-
- if (Operand.isLoad())
- Output.append("load");
- else
- Output.append("store");
- if (Operand.isLoad() && Operand.isStore())
- Output.append(" store");
-
- if (Description.SyncScope.value() != 0) {
- const auto Scope =
- std::ranges::find_if(Context.SyncScopes, [&Description](const MISyncScopeSlot &Slot) {
- return Slot.ID == Description.SyncScope;
- });
- if (Scope == Context.SyncScopes.end()) {
- return makeUnexpected(ErrorCode::VerificationError, "synchronization scope has no MIR name");
- }
- Output.append(" syncscope(");
- Output.append(quoteString(Scope->Name));
- Output.push_back(')');
- }
- if (Description.SuccessOrdering != AtomicOrdering::NotAtomic) {
- Output.push_back(' ');
- Output.append(atomicOrderingName(Description.SuccessOrdering));
- }
- if (Description.FailureOrdering != AtomicOrdering::NotAtomic) {
- Output.push_back(' ');
- Output.append(atomicOrderingName(Description.FailureOrdering));
- }
-
- Output.push_back(' ');
- if (Description.MemoryType) {
- auto Type = llvmMIRLowLevelType(*Description.MemoryType);
- if (!Type)
- return std::unexpected(Type.error());
- Output.push_back('(');
- Output.append(*Type);
- Output.push_back(')');
- } else {
- switch (Description.Size.kind()) {
- case MemorySize::Kind::Unknown:
- Output.append("unknown-size");
- break;
- case MemorySize::Kind::Fixed:
- Output.append(std::to_string(Description.Size.minimumBytes()));
- break;
- case MemorySize::Kind::Scalable:
- Output.append("(<vscale x ");
- Output.append(std::to_string(Description.Size.minimumBytes()));
- Output.append(" x s8>)");
- break;
- }
- }
-
- const std::string_view Preposition =
- Operand.isLoad() && Operand.isStore() ? " on " : (Operand.isLoad() ? " from " : " into ");
- if (Description.Base.kind() != MemoryBase::Kind::Unknown || Description.Offset != 0) {
- Output.append(Preposition);
- if (auto Printed = printMemoryBase(Description.Base, Description.Offset); !Printed) {
- return Printed;
- }
- }
-
- if (!Description.Size.isKnown() ||
- (Description.Size.minimumBytes() != 0 &&
- Description.Align.bytes() != Description.Size.minimumBytes())) {
- Output.append(", align ");
- Output.append(std::to_string(Description.Align.bytes()));
- }
- if (Description.BaseAlign && *Description.BaseAlign != Description.Align) {
- Output.append(", basealign ");
- Output.append(std::to_string(Description.BaseAlign->bytes()));
- }
- if (Description.AddressSpace != 0) {
- Output.append(", addrspace ");
- Output.append(std::to_string(Description.AddressSpace));
- }
-
- const auto PrintMetadata =
- [this](std::string_view Name,
- const std::optional<MachineMetadataReference> &Reference) -> Expected<void> {
- if (!Reference)
- return {};
- Output.append(", ");
- Output.append(Name);
- Output.push_back(' ');
- return printMetadataReference(*Reference);
- };
- if (auto Printed = PrintMetadata("!tbaa", Description.TBAA); !Printed)
- return Printed;
- if (auto Printed = PrintMetadata("!alias.scope", Description.AliasScope); !Printed) {
- return Printed;
- }
- if (auto Printed = PrintMetadata("!noalias", Description.NoAlias); !Printed)
- return Printed;
- if (auto Printed = PrintMetadata("!noalias.addrspace", Description.NoAliasAddressSpace);
- !Printed) {
- return Printed;
- }
- if (auto Printed = PrintMetadata("!range", Description.RangeMetadata); !Printed) {
- return Printed;
- }
- Output.push_back(')');
- return {};
-}
-
-Expected<void> BodyPrinter::printInstruction(const MachineInstr &Instruction) {
- const InstructionDescriptor *Descriptor = Target.instructions().descriptor(Instruction.opcode());
- if (Descriptor == nullptr) {
- return makeUnexpected(ErrorCode::VerificationError,
- "machine instruction has no target descriptor");
- }
- std::size_t ExplicitDefs = 0;
- while (ExplicitDefs < Instruction.operandCount()) {
- const MachineOperand *Operand = Instruction.operandAt(ExplicitDefs);
- if (Operand == nullptr || !Operand->isRegister() || Operand->isImplicit() ||
- !Operand->isDef() || Operand->isUse())
- break;
- ++ExplicitDefs;
- }
-
- Output.append(" ");
- for (std::size_t Index = 0; Index < ExplicitDefs; ++Index) {
- if (Index != 0)
- Output.append(", ");
- if (auto Printed = printOperand(*Instruction.operandAt(Index), true); !Printed) {
- return Printed;
- }
- }
- if (ExplicitDefs != 0)
- Output.append(" = ");
-
- const MachineInstrFlags Flags = Instruction.flags();
- constexpr std::array FlagSpellings{
- std::pair{MachineInstrFlag::FrameSetup, std::string_view{"frame-setup"}},
- std::pair{MachineInstrFlag::FrameDestroy, std::string_view{"frame-destroy"}},
- std::pair{MachineInstrFlag::FastMathNoNaNs, std::string_view{"nnan"}},
- std::pair{MachineInstrFlag::FastMathNoInfs, std::string_view{"ninf"}},
- std::pair{MachineInstrFlag::FastMathNoSignedZeros, std::string_view{"nsz"}},
- std::pair{MachineInstrFlag::FastMathAllowReciprocal, std::string_view{"arcp"}},
- std::pair{MachineInstrFlag::FastMathAllowContract, std::string_view{"contract"}},
- std::pair{MachineInstrFlag::FastMathApproxFunc, std::string_view{"afn"}},
- std::pair{MachineInstrFlag::FastMathAllowReassoc, std::string_view{"reassoc"}},
- std::pair{MachineInstrFlag::NoUnsignedWrap, std::string_view{"nuw"}},
- std::pair{MachineInstrFlag::NoSignedWrap, std::string_view{"nsw"}},
- std::pair{MachineInstrFlag::NoUSWrap, std::string_view{"nusw"}},
- std::pair{MachineInstrFlag::Exact, std::string_view{"exact"}},
- std::pair{MachineInstrFlag::NoFPExcept, std::string_view{"nofpexcept"}},
- std::pair{MachineInstrFlag::Unpredictable, std::string_view{"unpredictable"}},
- std::pair{MachineInstrFlag::NoConvergent, std::string_view{"noconvergent"}},
- std::pair{MachineInstrFlag::NonNeg, std::string_view{"nneg"}},
- std::pair{MachineInstrFlag::Disjoint, std::string_view{"disjoint"}},
- std::pair{MachineInstrFlag::SameSign, std::string_view{"samesign"}},
- std::pair{MachineInstrFlag::InBounds, std::string_view{"inbounds"}},
- };
- for (const auto &[Flag, Spelling] : FlagSpellings) {
- if (Flags.has(Flag)) {
- Output.append(Spelling);
- Output.push_back(' ');
- }
- }
- Output.append(Descriptor->Name);
-
- bool HasPrintedTail = false;
- const bool IsInlineAsm = Descriptor->Name == "INLINEASM" || Descriptor->Name == "INLINEASM_BR";
- std::size_t InlineAsmPayloadRemaining = 0;
- for (std::size_t Index = ExplicitDefs; Index < Instruction.operandCount(); ++Index) {
- Output.append(HasPrintedTail ? ", " : " ");
- HasPrintedTail = true;
- const MachineOperand &Operand = *Instruction.operandAt(Index);
- if (IsInlineAsm && Index == InlineAsmExtraInfoOperandIndex) {
- auto Printed = printInlineAsmExtraInfo(Operand);
- if (!Printed)
- return Printed;
- continue;
- }
- if (IsInlineAsm && Index >= InlineAsmFirstConstraintOperandIndex &&
- InlineAsmPayloadRemaining == 0) {
- auto OperandCount = printInlineAsmOperandFlag(Operand);
- if (!OperandCount)
- return std::unexpected(OperandCount.error());
- InlineAsmPayloadRemaining = *OperandCount;
- continue;
- }
- bool PrintVirtualType = true;
- if (Descriptor->Flags.has(InstructionFlag::Generic) &&
- !Descriptor->Flags.has(InstructionFlag::Phi) && Index < Descriptor->Operands.size()) {
- const std::optional<OperandTypeConstraint> &UseConstraint =
- Descriptor->Operands[Index].TypeConstraint;
- if (UseConstraint) {
- for (std::size_t DefIndex = 0; DefIndex < ExplicitDefs; ++DefIndex) {
- if (DefIndex >= Descriptor->Operands.size())
- break;
- const std::optional<OperandTypeConstraint> &DefConstraint =
- Descriptor->Operands[DefIndex].TypeConstraint;
- if (DefConstraint && DefConstraint->EqualityGroup == UseConstraint->EqualityGroup) {
- PrintVirtualType = false;
- break;
- }
- }
- } else if (const Register *UseRegister = Operand.getIf<Register>();
- UseRegister != nullptr && UseRegister->isVirtual()) {
- const auto UseInfo = Function.registerInfo().virtualRegisterInfo(*UseRegister);
- for (std::size_t DefIndex = 0; DefIndex < ExplicitDefs && UseInfo && UseInfo->get().Type;
- ++DefIndex) {
- if (DefIndex >= Descriptor->Operands.size() ||
- Descriptor->Operands[DefIndex].TypeConstraint)
- continue;
- const MachineOperand *DefOperand = Instruction.operandAt(DefIndex);
- const Register *DefRegister =
- DefOperand == nullptr ? nullptr : DefOperand->getIf<Register>();
- if (DefRegister == nullptr || !DefRegister->isVirtual())
- continue;
- const auto DefInfo = Function.registerInfo().virtualRegisterInfo(*DefRegister);
- if (DefInfo && DefInfo->get().Type == UseInfo->get().Type) {
- PrintVirtualType = false;
- break;
- }
- }
- }
- }
- auto Printed = printOperand(Operand, false, PrintVirtualType);
- if (!Printed)
- return Printed;
- if (IsInlineAsm && InlineAsmPayloadRemaining != 0)
- --InlineAsmPayloadRemaining;
- }
- if (InlineAsmPayloadRemaining != 0)
- return makeUnexpected(ErrorCode::VerificationError,
- "inline assembly operand flag has missing payload operands");
-
- const auto BeginAttachment = [this, &HasPrintedTail](std::string_view Name) {
- Output.append(HasPrintedTail ? ", " : " ");
- HasPrintedTail = true;
- Output.append(Name);
- Output.push_back(' ');
- };
- if (Instruction.preInstrSymbol()) {
- BeginAttachment("pre-instr-symbol");
- Output.append("<mcsymbol ");
- Output.append(quoteName(*Instruction.preInstrSymbol()));
- Output.push_back('>');
- }
- if (Instruction.postInstrSymbol()) {
- BeginAttachment("post-instr-symbol");
- Output.append("<mcsymbol ");
- Output.append(quoteName(*Instruction.postInstrSymbol()));
- Output.push_back('>');
- }
- if (Instruction.heapAllocMarker()) {
- BeginAttachment("heap-alloc-marker");
- if (auto Printed = printMetadataReference(*Instruction.heapAllocMarker()); !Printed) {
- return Printed;
- }
- }
- if (Instruction.pcSections()) {
- BeginAttachment("pcsections");
- if (auto Printed = printMetadataReference(*Instruction.pcSections()); !Printed) {
- return Printed;
- }
- }
- if (Instruction.mmra()) {
- BeginAttachment("mmra");
- if (auto Printed = printMetadataReference(*Instruction.mmra()); !Printed)
- return Printed;
- }
- if (Instruction.cfiType()) {
- BeginAttachment("cfi-type");
- Output.append(std::to_string(*Instruction.cfiType()));
- }
- if (Instruction.deactivationSymbol()) {
- BeginAttachment("deactivation-symbol");
- Output.push_back('@');
- Output.append(quoteName(*Instruction.deactivationSymbol()));
- }
- if (Instruction.debugInstrNumber() != 0) {
- BeginAttachment("debug-instr-number");
- Output.append(std::to_string(Instruction.debugInstrNumber()));
- }
- if (Instruction.debugLocation()) {
- BeginAttachment("debug-location");
- if (const MachineMetadataReference *Reference = Instruction.debugLocation()->reference()) {
- if (auto Printed = printMetadataReference(*Reference); !Printed)
- return Printed;
- } else if (const MachineDILocation *Location = Instruction.debugLocation()->inlineLocation()) {
- if (auto Printed = printDILocation(*Location, 0); !Printed)
- return Printed;
- } else {
- return makeUnexpected(ErrorCode::VerificationError,
- "machine debug location has no printable value");
- }
- }
-
- if (!Instruction.memOperands().empty()) {
- Output.append(" :: ");
- for (std::size_t Index = 0; Index < Instruction.memOperands().size(); ++Index) {
- if (Index != 0)
- Output.append(", ");
- if (auto Printed = printMemoryOperand(*Instruction.memOperands()[Index]); !Printed) {
- return Printed;
- }
- }
- }
- return {};
-}
-
-Expected<void> BodyPrinter::printBlock(const MachineBasicBlock &Block) {
- auto ID = blockID(Block);
- if (!ID)
- return std::unexpected(ID.error());
- Output.append("bb.");
- Output.append(std::to_string(*ID));
- const auto &Name = Block.attributes().name();
- if (Name) {
- Output.push_back('.');
- Output.append(quoteName(*Name));
- }
-
- std::vector<std::string> Attributes;
- const auto AddFlag = [&Block, &Attributes](MachineBasicBlockAttribute Attribute,
- std::string_view Spelling) {
- if (Block.attributes().has(Attribute))
- Attributes.emplace_back(Spelling);
- };
- AddFlag(MachineBasicBlockAttribute::MachineBlockAddressTaken, "machine-block-address-taken");
- if (Block.attributes().has(MachineBasicBlockAttribute::IRBlockAddressTaken)) {
- std::string Attribute = "ir-block-address-taken";
- const auto &IRBlockName = Block.attributes().irBlockName();
- if (IRBlockName) {
- Attribute.append(" %ir-block.");
- Attribute.append(quoteName(*IRBlockName));
- }
- Attributes.push_back(std::move(Attribute));
- } else {
- const auto &IRBlockName = Block.attributes().irBlockName();
- if (IRBlockName)
- Attributes.push_back("%ir-block." + quoteName(*IRBlockName));
- }
- AddFlag(MachineBasicBlockAttribute::LandingPad, "landing-pad");
- AddFlag(MachineBasicBlockAttribute::InlineAsmBrIndirectTarget, "inlineasm-br-indirect-target");
- AddFlag(MachineBasicBlockAttribute::EHFuncletEntry, "ehfunclet-entry");
- AddFlag(MachineBasicBlockAttribute::EHScopeEntry, "ehscope-entry");
- if (Block.attributes().alignment().bytes() != 1) {
- Attributes.push_back("align " + std::to_string(Block.attributes().alignment().bytes()));
- }
- const MachineBasicBlockSectionID Section = Block.attributes().sectionID();
- if (!Section.isDefault()) {
- std::string Value;
- if (Section.kind() == MachineBasicBlockSectionKind::Exception)
- Value = "Exception";
- else if (Section.kind() == MachineBasicBlockSectionKind::Cold)
- Value = "Cold";
- else
- Value = std::to_string(Section.number());
- Attributes.push_back("bbsections " + Value);
- }
- const auto &ProfileID = Block.attributes().profileID();
- if (ProfileID) {
- const MachineBasicBlockProfileID Profile = *ProfileID;
- Attributes.push_back("bb_id " + std::to_string(Profile.BaseID) + "." +
- std::to_string(Profile.CloneID));
- }
- if (Block.attributes().callFrameSize() != 0) {
- Attributes.push_back("call-frame-size " + std::to_string(Block.attributes().callFrameSize()));
- }
- if (!Attributes.empty()) {
- Output.append(" (");
- for (std::size_t Index = 0; Index < Attributes.size(); ++Index) {
- if (Index != 0)
- Output.append(", ");
- Output.append(Attributes[Index]);
- }
- Output.push_back(')');
- }
- Output.append(":\n");
-
- bool HasLineAttributes = false;
- if (!Block.successors().empty()) {
- Output.append(" successors: ");
- for (std::size_t Index = 0; Index < Block.successors().size(); ++Index) {
- if (Index != 0)
- Output.append(", ");
- const MachineSuccessor &Successor = Block.successors()[Index];
- if (Successor.Block == nullptr || !BlockIDs.contains(Successor.Block)) {
- return makeUnexpected(ErrorCode::VerificationError,
- "successor references an unlinked block");
- }
- appendBlockReference(*Successor.Block);
- Output.append("(0x");
- Output.append(hexadecimalWords(
- std::array{static_cast<std::uint64_t>(Successor.Probability.rawValue())}, 32));
- Output.push_back(')');
- }
- Output.push_back('\n');
- HasLineAttributes = true;
- }
- if (!Block.liveIns().empty()) {
- Output.append(" liveins: ");
- for (std::size_t Index = 0; Index < Block.liveIns().size(); ++Index) {
- if (Index != 0)
- Output.append(", ");
- const MachineBasicBlockLiveIn &LiveIn = Block.liveIns()[Index];
- if (auto Printed = appendPhysicalRegister(LiveIn.PhysReg); !Printed)
- return Printed;
- if (LiveIn.Lanes != LaneMask::all()) {
- Output.append(": 0x");
- Output.append(hexadecimalWords(std::array{LiveIn.Lanes.rawValue()}, 64));
- }
- }
- Output.push_back('\n');
- HasLineAttributes = true;
- }
-
- if (HasLineAttributes && Block.firstInstruction() != nullptr)
- Output.push_back('\n');
-
- bool InBundle = false;
- for (const MachineInstr *Instruction = Block.firstInstruction(); Instruction != nullptr;
- Instruction = Instruction->next()) {
- if (auto Printed = printInstruction(*Instruction); !Printed)
- return Printed;
- const bool HasPredecessor = Instruction->flags().has(MachineInstrFlag::BundledWithPred);
- const bool HasSuccessor = Instruction->flags().has(MachineInstrFlag::BundledWithSucc);
- if (!InBundle && HasSuccessor && !HasPredecessor) {
- Output.append(" {");
- InBundle = true;
- }
- Output.push_back('\n');
- if (InBundle && !HasSuccessor) {
- Output.append(" }\n");
- InBundle = false;
- }
- }
- if (InBundle) {
- return makeUnexpected(ErrorCode::VerificationError,
- "unterminated instruction bundle cannot be printed");
- }
- return {};
-}
-
-Expected<std::string> BodyPrinter::run() {
- auto Verification = MachineVerifier::verify(
- Function, Target,
- MachineVerifierOptions{
- .Mode = MachineVerifierMode::Generic, .Stage = std::nullopt, .VerifyProperties = false});
- if (!Verification)
- return std::unexpected(Verification.error());
- if (auto Initialized = initialize(); !Initialized)
- return std::unexpected(Initialized.error());
-
- bool First = true;
- for (const MachineBasicBlock *Block = Function.firstBlock(); Block != nullptr;
- Block = Block->next()) {
- if (!First)
- Output.push_back('\n');
- First = false;
- if (auto Printed = printBlock(*Block); !Printed)
- return std::unexpected(Printed.error());
- }
- return std::move(Output);
-}
-
-} // namespace
-
-Expected<std::string> printMachineFunctionBody(const MachineFunction &Function,
- const TargetDescription &Target,
- const MIParserContext &Context,
- MIPrinterOptions Options) {
- return BodyPrinter(Function, Target, Context, Options).run();
-}
-
-} // namespace rcc::mir
diff --git a/backend/lib/MIR/MIRDataParser.cpp b/backend/lib/MIR/MIRDataParser.cpp
deleted file mode 100644
index 2ac1f2d..0000000
--- a/backend/lib/MIR/MIRDataParser.cpp
+++ /dev/null
@@ -1,287 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include "MIRDocumentParser.h"
-#include "MIRDocumentReferenceValidation.h"
-#include "MIRMetadataTextParser.h"
-#include "MIRParserUtilities.h"
-#include "rcc/CodeGen/MachineBasicBlock.h"
-#include "rcc/CodeGen/MachineConstantPool.h"
-#include "rcc/CodeGen/MachineFrameInfo.h"
-#include "rcc/CodeGen/MachineFunction.h"
-#include "rcc/CodeGen/MachineFunctionAttributes.h"
-#include "rcc/CodeGen/MachineFunctionProperties.h"
-#include "rcc/CodeGen/MachineFunctionRecords.h"
-#include "rcc/CodeGen/MachineInstr.h"
-#include "rcc/CodeGen/MachineJumpTableInfo.h"
-#include "rcc/CodeGen/MachineMetadata.h"
-#include "rcc/CodeGen/MachineRegisterInfo.h"
-#include "rcc/CodeGen/MachineVerifier.h"
-#include "rcc/CodeGen/TargetDescription.h"
-#include "rcc/CodeGen/TargetMIRTextInfo.h"
-#include "rcc/CodeGen/TargetRegisterInfo.h"
-#include "rcc/MIR/LLVMConstantSyntax.h"
-
-#include <algorithm>
-#include <array>
-#include <cstddef>
-#include <cstdint>
-#include <initializer_list>
-#include <limits>
-#include <optional>
-#include <ranges>
-#include <span>
-#include <string>
-#include <string_view>
-#include <unordered_map>
-#include <unordered_set>
-#include <utility>
-#include <vector>
-
-namespace rcc::mir {
-
-using parser_detail::parseBool;
-using parser_detail::parsePrefixedID;
-using parser_detail::parseSigned;
-using parser_detail::parseUnsigned;
-using parser_detail::parseUnsigned32;
-using parser_detail::trim;
-
-bool MIRDocumentParser::parseConstants(const yaml::Node &Root, MachineFunction &Function,
- MIParserContext &Context) {
- const yaml::Node *Constants = mappingValue(Root, "constants");
- if (Constants == nullptr)
- return false;
- if (requireKind(*Constants, yaml::NodeKind::Sequence, "constant pool"))
- return true;
- constexpr std::array Keys{
- std::string_view{"id"},
- std::string_view{"value"},
- std::string_view{"alignment"},
- std::string_view{"isTargetSpecific"},
- };
- std::vector<LLVMNamedTypeDefinition> NamedTypes;
- const std::string_view DataLayout = effectiveDataLayout();
- if (ActiveDocument->EmbeddedIR) {
- const auto Definitions = ActiveDocument->EmbeddedIR->typeDefinitions();
- NamedTypes.reserve(Definitions.size());
- for (const EmbeddedIRTypeDefinition &Definition : Definitions) {
- NamedTypes.push_back({.Name = Definition.Name,
- .Definition = Definition.Definition,
- .NumericName = Definition.NumericName});
- }
- }
- std::unordered_set<std::uint32_t> IDs;
- for (const yaml::NodeID ConstantID : Constants->sequence()) {
- const yaml::Node *Constant = node(ConstantID);
- if (Constant == nullptr ||
- requireKind(*Constant, yaml::NodeKind::Mapping, "constant pool entry") ||
- validateKeys(*Constant, Keys, "constant pool entry")) {
- return true;
- }
- const yaml::Node *IDNode = mappingValue(*Constant, "id");
- const yaml::Node *ValueNode = mappingValue(*Constant, "value");
- if (IDNode == nullptr || ValueNode == nullptr)
- return fail(Constant->range(), "constant pool entry requires 'id' and 'value'");
- std::uint64_t WideID = 0;
- if (unsignedValue(*IDNode, WideID, "a 32-bit constant pool ID") ||
- WideID > std::numeric_limits<std::uint32_t>::max()) {
- return true;
- }
- const auto TextID = static_cast<std::uint32_t>(WideID);
- if (!IDs.insert(TextID).second)
- return fail(IDNode->range(), "duplicate constant pool ID");
-
- bool IsTargetSpecific = false;
- if (const yaml::Node *TargetNode = mappingValue(*Constant, "isTargetSpecific")) {
- if (boolean(*TargetNode, IsTargetSpecific))
- return true;
- }
- if (IsTargetSpecific) {
- std::string_view ValueText;
- if (scalar(*ValueNode, ValueText, "target constant"))
- return true;
- auto TargetConstantValue = Target.mirText().parseTargetConstant(ValueText);
- if (!TargetConstantValue)
- return importError(ValueNode->range(), TargetConstantValue.error(), "mir-target-constant");
- auto Emission = TargetConstantValue->emit();
- if (!Emission)
- return importError(ValueNode->range(), Emission.error(), "mir-target-constant");
- auto RequiredAlignment = TargetConstantValue->requiredAlignment();
- if (!RequiredAlignment)
- return importError(ValueNode->range(), RequiredAlignment.error(), "mir-target-constant");
-
- MachineConstantPoolEntryDesc Description;
- Description.Size = Emission->Bytes.size();
- Description.Align = *RequiredAlignment;
- Description.Value = std::move(*TargetConstantValue);
- if (const yaml::Node *AlignmentNode = mappingValue(*Constant, "alignment")) {
- if (alignment(*AlignmentNode, Description.Align, true))
- return true;
- }
- auto Added = Function.constantPool().addEntry(std::move(Description));
- if (!Added)
- return importError(Constant->range(), Added.error());
- Context.ConstantPoolItems.push_back({.TextID = TextID, .Index = *Added});
- continue;
- }
-
- std::string_view ValueText;
- if (scalar(*ValueNode, ValueText, "LLVM constant"))
- return true;
- const LLVMConstantSyntaxOptions ConstantOptions{
- .DataLayout = DataLayout,
- .NamedTypes = NamedTypes,
- };
- auto Data = parseLLVMConstant(trim(ValueText), ConstantOptions);
- if (!Data)
- return importError(ValueNode->range(), Data.error(), "mir-llvm-constant");
- auto Size = llvmConstantStorageSize(Data->Type, ConstantOptions);
- if (!Size)
- return importError(ValueNode->range(), Size.error(), "mir-llvm-constant");
-
- MachineConstantPoolEntryDesc Description;
- Description.Size = *Size;
- Description.Value = std::move(*Data);
- if (const yaml::Node *AlignmentNode = mappingValue(*Constant, "alignment")) {
- if (alignment(*AlignmentNode, Description.Align, true))
- return true;
- } else {
- auto Preferred = llvmConstantPreferredAlignment(
- std::get<GenericConstantData>(Description.Value).Type, ConstantOptions);
- if (!Preferred)
- return importError(ValueNode->range(), Preferred.error(), "mir-llvm-constant");
- Description.Align = *Preferred;
- }
- auto Added = Function.constantPool().addEntry(std::move(Description));
- if (!Added)
- return importError(Constant->range(), Added.error());
- Context.ConstantPoolItems.push_back({.TextID = TextID, .Index = *Added});
- }
- return false;
-}
-
-bool MIRDocumentParser::reserveJumpTables(const yaml::Node &Root, MachineFunction &Function,
- MIParserContext &Context,
- std::vector<PendingJumpTable> &Pending) {
- const yaml::Node *JumpTable = mappingValue(Root, "jumpTable");
- if (JumpTable == nullptr)
- return false;
- if (requireKind(*JumpTable, yaml::NodeKind::Mapping, "jump table"))
- return true;
- constexpr std::array JumpTableKeys{
- std::string_view{"kind"},
- std::string_view{"entries"},
- };
- if (validateKeys(*JumpTable, JumpTableKeys, "jump table"))
- return true;
- const yaml::Node *KindNode = mappingValue(*JumpTable, "kind");
- if (KindNode == nullptr)
- return fail(JumpTable->range(), "jump table requires 'kind'");
- std::string_view KindName;
- if (scalar(*KindNode, KindName, "jump table kind"))
- return true;
-
- JumpTableEntryEncoding Encoding;
- std::uint8_t EntrySize = 8;
- if (KindName == "block-address")
- Encoding = JumpTableEntryEncoding::BlockAddress;
- else if (KindName == "gp-rel64-block-address")
- Encoding = JumpTableEntryEncoding::GPRelative64BlockAddress;
- else if (KindName == "gp-rel32-block-address") {
- Encoding = JumpTableEntryEncoding::GPRelative32BlockAddress;
- EntrySize = 4;
- } else if (KindName == "label-difference32") {
- Encoding = JumpTableEntryEncoding::LabelDifference32;
- EntrySize = 4;
- } else if (KindName == "label-difference64")
- Encoding = JumpTableEntryEncoding::LabelDifference64;
- else if (KindName == "inline") {
- Encoding = JumpTableEntryEncoding::Inline;
- EntrySize = 4;
- } else if (KindName == "custom32") {
- Encoding = JumpTableEntryEncoding::Custom32;
- EntrySize = 4;
- } else {
- return fail(KindNode->range(), "unknown enumerated scalar");
- }
-
- const yaml::Node *Entries = mappingValue(*JumpTable, "entries");
- if (Entries == nullptr)
- return false;
- if (requireKind(*Entries, yaml::NodeKind::Sequence, "jump table entries"))
- return true;
- constexpr std::array EntryKeys{
- std::string_view{"id"},
- std::string_view{"blocks"},
- };
- std::unordered_set<std::uint32_t> IDs;
- for (const yaml::NodeID EntryID : Entries->sequence()) {
- const yaml::Node *Entry = node(EntryID);
- if (Entry == nullptr || requireKind(*Entry, yaml::NodeKind::Mapping, "jump table entry") ||
- validateKeys(*Entry, EntryKeys, "jump table entry")) {
- return true;
- }
- const yaml::Node *IDNode = mappingValue(*Entry, "id");
- if (IDNode == nullptr)
- return fail(Entry->range(), "jump table entry requires 'id'");
- std::uint64_t WideID = 0;
- if (unsignedValue(*IDNode, WideID, "a 32-bit jump table ID") ||
- WideID > std::numeric_limits<std::uint32_t>::max()) {
- return true;
- }
- const auto TextID = static_cast<std::uint32_t>(WideID);
- if (!IDs.insert(TextID).second)
- return fail(IDNode->range(), "duplicate jump table ID");
- auto Reserved = Function.jumpTableInfo().reserveTable();
- if (!Reserved)
- return importError(Entry->range(), Reserved.error());
- PendingJumpTable NewPending{
- .Index = *Reserved,
- .TextID = TextID,
- .Encoding = Encoding,
- .EntrySize = EntrySize,
- .Blocks = {},
- };
- if (const yaml::Node *Blocks = mappingValue(*Entry, "blocks")) {
- if (requireKind(*Blocks, yaml::NodeKind::Sequence, "jump table blocks"))
- return true;
- for (const yaml::NodeID BlockID : Blocks->sequence()) {
- const yaml::Node *BlockNode = node(BlockID);
- std::string_view Text;
- if (BlockNode == nullptr || scalar(*BlockNode, Text, "basic block reference"))
- return true;
- NewPending.Blocks.emplace_back(Text);
- }
- }
- if (NewPending.Blocks.empty())
- return fail(Entry->range(), "jump table entry must contain at least one block");
- Context.JumpTables.push_back({.TextID = TextID, .Index = *Reserved});
- Pending.push_back(std::move(NewPending));
- }
- return false;
-}
-
-bool MIRDocumentParser::defineJumpTables(MachineFunction &Function,
- std::span<const PendingJumpTable> Pending) {
- for (const PendingJumpTable &Table : Pending) {
- MachineJumpTableDesc Description;
- Description.Encoding = Table.Encoding;
- Description.EntrySize = Table.EntrySize;
- Description.Align = *Alignment::create(Table.EntrySize);
- for (const std::string &Text : Table.Blocks) {
- MachineBasicBlock *Block = nullptr;
- if (parseBlockReference(Text, Result.Source.range(0, 0), Function, Block))
- return true;
- if (Block == nullptr)
- return fail(Result.Source.range(0, 0), "reference to undefined machine basic block");
- Description.Targets.push_back(Block);
- }
- auto DefineResult =
- Function.jumpTableInfo().defineReservedTable(Table.Index, std::move(Description));
- if (!DefineResult)
- return importError(Result.Source.range(0, 0), DefineResult.error());
- }
- return false;
-}
-
-} // namespace rcc::mir
diff --git a/backend/lib/MIR/MIRDocument.cpp b/backend/lib/MIR/MIRDocument.cpp
deleted file mode 100644
index ad9ec40..0000000
--- a/backend/lib/MIR/MIRDocument.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include "rcc/MIR/MIRDocument.h"
-
-#include "MIRDocumentParser.h"
-
-#include <string>
-#include <utility>
-
-namespace rcc::mir {
-
-MIRDocument::MIRDocument() = default;
-MIRDocument::MIRDocument(CompilationUnit Unit) : Unit(std::move(Unit)) {}
-MIRDocument::MIRDocument(MIRDocument &&) noexcept = default;
-MIRDocument &MIRDocument::operator=(MIRDocument &&) noexcept = default;
-MIRDocument::~MIRDocument() = default;
-
-MIRDocumentParseResult::MIRDocumentParseResult(MIRDocumentParseResult &&) noexcept = default;
-MIRDocumentParseResult &
-MIRDocumentParseResult::operator=(MIRDocumentParseResult &&) noexcept = default;
-MIRDocumentParseResult::~MIRDocumentParseResult() = default;
-
-MIRDocumentParseResult parseMIRDocument(const TargetDescription &Target, std::string SourceName,
- std::string SourceText, MIRDocumentParserOptions Options) {
- return MIRDocumentParser(Target, std::move(SourceName), std::move(SourceText), std::move(Options))
- .run();
-}
-
-} // namespace rcc::mir
diff --git a/backend/lib/MIR/MIRDocumentParser.cpp b/backend/lib/MIR/MIRDocumentParser.cpp
deleted file mode 100644
index 08627d5..0000000
--- a/backend/lib/MIR/MIRDocumentParser.cpp
+++ /dev/null
@@ -1,398 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include "MIRDocumentParser.h"
-
-#include "MIRDocumentReferenceValidation.h"
-#include "MIRMetadataTextParser.h"
-#include "MIRParserUtilities.h"
-#include "rcc/CodeGen/MachineBasicBlock.h"
-#include "rcc/CodeGen/MachineConstantPool.h"
-#include "rcc/CodeGen/MachineFrameInfo.h"
-#include "rcc/CodeGen/MachineFunction.h"
-#include "rcc/CodeGen/MachineFunctionAttributes.h"
-#include "rcc/CodeGen/MachineFunctionProperties.h"
-#include "rcc/CodeGen/MachineFunctionRecords.h"
-#include "rcc/CodeGen/MachineInstr.h"
-#include "rcc/CodeGen/MachineJumpTableInfo.h"
-#include "rcc/CodeGen/MachineMetadata.h"
-#include "rcc/CodeGen/MachineRegisterInfo.h"
-#include "rcc/CodeGen/MachineVerifier.h"
-#include "rcc/CodeGen/TargetDescription.h"
-#include "rcc/CodeGen/TargetMIRTextInfo.h"
-#include "rcc/CodeGen/TargetRegisterInfo.h"
-#include "rcc/MIR/LLVMConstantSyntax.h"
-
-#include <algorithm>
-#include <array>
-#include <cstddef>
-#include <cstdint>
-#include <initializer_list>
-#include <limits>
-#include <optional>
-#include <ranges>
-#include <span>
-#include <string>
-#include <string_view>
-#include <unordered_map>
-#include <unordered_set>
-#include <utility>
-#include <vector>
-
-namespace rcc::mir {
-
-using parser_detail::parseBool;
-using parser_detail::parsePrefixedID;
-using parser_detail::parseSigned;
-using parser_detail::parseUnsigned;
-using parser_detail::parseUnsigned32;
-using parser_detail::trim;
-
-bool MIRDocumentParser::fail(const TextRange &Range, std::string Message, std::string Category) {
- if (Result.Diagnostics.empty()) {
- Result.Diagnostics.push_back(TextDiagnostic{
- .Severity = DiagnosticSeverity::Error,
- .Category = std::move(Category),
- .Message = std::move(Message),
- .SourceName = std::string(Result.Source.name()),
- .Range = Range,
- });
- }
- return true;
-}
-
-bool MIRDocumentParser::importError(const TextRange &Range, const Error &Failure,
- std::string Category) {
- return fail(Range, std::string(Failure.message()), std::move(Category));
-}
-
-const yaml::Node *MIRDocumentParser::mappingValue(const yaml::Node &Mapping,
- std::string_view Key) const noexcept {
- const auto Value = Mapping.mappingValue(Key);
- return Value ? node(*Value) : nullptr;
-}
-
-std::string_view MIRDocumentParser::effectiveDataLayout() const noexcept {
- if (!Options.DataLayout.empty())
- return Options.DataLayout;
- if (ActiveDocument != nullptr) {
- if (const EmbeddedIRReferenceIndex *Embedded = ActiveDocument->embeddedIR()) {
- if (const auto DataLayout = Embedded->dataLayout())
- return *DataLayout;
- }
- }
- return {};
-}
-
-LLVMConstantSyntaxOptions MIRDocumentParser::pointerLayoutOptions() const noexcept {
- return {
- .DataLayout = effectiveDataLayout(),
- .NamedTypes = {},
- };
-}
-
-bool MIRDocumentParser::requireKind(const yaml::Node &Node, yaml::NodeKind Kind,
- std::string_view Description) {
- if (Node.kind() == Kind)
- return false;
- return fail(Node.range(), std::string(Description) + " has the wrong YAML node kind");
-}
-
-bool MIRDocumentParser::validateKeys(const yaml::Node &Mapping,
- std::span<const std::string_view> Keys,
- std::string_view Description) {
- for (const yaml::MappingEntry &Entry : Mapping.mapping()) {
- if (std::ranges::find(Keys, Entry.Key) == Keys.end()) {
- return fail(Entry.KeyRange,
- "unknown " + std::string(Description) + " key '" + Entry.Key + "'");
- }
- }
- return false;
-}
-
-bool MIRDocumentParser::scalar(const yaml::Node &Node, std::string_view &Value,
- std::string_view Description) {
- if (requireKind(Node, yaml::NodeKind::Scalar, Description))
- return true;
- Value = Node.scalar();
- return false;
-}
-
-bool MIRDocumentParser::boolean(const yaml::Node &Node, bool &Value) {
- std::string_view Text;
- if (scalar(Node, Text, "boolean") || !parseBool(Text, Value))
- return fail(Node.range(), "expected 'true' or 'false'");
- return false;
-}
-
-bool MIRDocumentParser::unsignedValue(const yaml::Node &Node, std::uint64_t &Value,
- std::string_view Description) {
- std::string_view Text;
- if (scalar(Node, Text, Description) || !parseUnsigned(Text, Value))
- return fail(Node.range(), "expected " + std::string(Description));
- return false;
-}
-
-bool MIRDocumentParser::signedValue(const yaml::Node &Node, std::int64_t &Value,
- std::string_view Description) {
- std::string_view Text;
- if (scalar(Node, Text, Description) || !parseSigned(Text, Value))
- return fail(Node.range(), "expected " + std::string(Description));
- return false;
-}
-
-bool MIRDocumentParser::alignment(const yaml::Node &Node, Alignment &Value, bool AllowZero) {
- std::uint64_t Bytes = 0;
- if (unsignedValue(Node, Bytes, "an unsigned alignment"))
- return true;
- if (Bytes == 0 && AllowZero) {
- Value = Alignment{};
- return false;
- }
- auto Parsed = Alignment::create(Bytes);
- if (!Parsed)
- return importError(Node.range(), Parsed.error());
- Value = *Parsed;
- return false;
-}
-
-bool MIRDocumentParser::physicalRegister(std::string_view Text, const TextRange &Range,
- PhysicalRegister &Reg) {
- Text = trim(Text);
- if (!Text.starts_with('$') || Text.size() == 1)
- return fail(Range, "physical register must use the '$name' MIR spelling");
- const PhysicalRegisterDesc *Description = Target.registers().physicalRegister(Text.substr(1));
- if (Description == nullptr)
- return fail(Range, "unknown physical register '" + std::string(Text) + "'");
- Reg = Description->Reg;
- return false;
-}
-
-bool MIRDocumentParser::physicalRegister(const yaml::Node &Node, PhysicalRegister &Reg) {
- std::string_view Text;
- return scalar(Node, Text, "physical register") || physicalRegister(Text, Node.range(), Reg);
-}
-
-bool MIRDocumentParser::virtualRegister(std::string_view Text, const TextRange &Range,
- MachineFunction &Function, MIParserContext &Context,
- Register &Reg) {
- const auto ID = parsePrefixedID(Text, "%");
- if (!ID)
- return fail(Range, "virtual register must use the '%N' MIR spelling");
- auto Found =
- std::ranges::find_if(Context.VirtualRegisters,
- [ID](const MIVirtualRegisterSlot &Slot) { return Slot.TextID == *ID; });
- if (Found == Context.VirtualRegisters.end()) {
- auto Created = Function.registerInfo().createVirtualRegister();
- if (!Created)
- return importError(Range, Created.error());
- Context.VirtualRegisters.push_back({*ID, *Created});
- Reg = *Created;
- return false;
- }
- Reg = Found->Reg;
- return false;
-}
-
-MIRDocumentParseResult MIRDocumentParser::run() {
- yaml::ParseResult YAMLResult = yaml::parse(std::string(Result.Source.name()),
- std::string(Result.Source.text()), Options.YAML);
- if (!YAMLResult.succeeded()) {
- const auto Diagnostics = YAMLResult.diagnostics();
- Result.Diagnostics.assign(Diagnostics.begin(), Diagnostics.end());
- return std::move(Result);
- }
- Stream = YAMLResult.stream();
- if (Stream == nullptr || Stream->documents().empty()) {
- static_cast<void>(fail(Result.Source.range(0, 0), "MIR stream contains no YAML documents"));
- return std::move(Result);
- }
-
- MIRDocument Staging;
- ActiveDocument = &Staging;
- const auto IsEmptyDocument = [this](std::size_t Index) {
- const yaml::Node *Root = node(Stream->documents()[Index].Root);
- return Root != nullptr && Root->kind() == yaml::NodeKind::Null &&
- Root->range().Begin.Offset == Root->range().End.Offset;
- };
- std::size_t FirstContent = 0;
- while (FirstContent < Stream->documents().size() && IsEmptyDocument(FirstContent))
- ++FirstContent;
- if (FirstContent == Stream->documents().size()) {
- static_cast<void>(fail(Stream->documents().front().Range,
- "MIR stream must contain at least one machine function document"));
- return std::move(Result);
- }
-
- std::size_t FirstFunction = FirstContent;
- const yaml::Node *FirstRoot = node(Stream->documents()[FirstContent].Root);
- if (FirstRoot != nullptr && FirstRoot->kind() == yaml::NodeKind::Scalar) {
- EmbeddedIRIndexResult Embedded = indexEmbeddedIR(
- std::string(Result.Source.name()) + ":embedded-ir", std::string(FirstRoot->scalar()));
- if (!Embedded.succeeded()) {
- const auto Diagnostics = Embedded.diagnostics();
- if (Diagnostics.empty()) {
- static_cast<void>(
- fail(FirstRoot->range(), "embedded LLVM IR indexing failed", "mir-embedded-ir"));
- } else {
- const TextDiagnostic &Diagnostic = Diagnostics.front();
- const TextRange Range = scalarDiagnosticRange(*FirstRoot, Diagnostic.Range);
- static_cast<void>(fail(Range, Diagnostic.Message, Diagnostic.Category));
- }
- return std::move(Result);
- }
- Staging.EmbeddedIR = std::move(Embedded).takeIndex();
- FirstFunction = FirstContent + 1;
- }
-
- if (!effectiveDataLayout().empty()) {
- auto PointerSize = llvmPointerSizeInBits(0, pointerLayoutOptions());
- if (!PointerSize) {
- static_cast<void>(importError(Stream->documents()[FirstContent].Range, PointerSize.error(),
- "mir-data-layout"));
- return std::move(Result);
- }
- }
-
- bool SawFunction = false;
- for (std::size_t Index = FirstFunction; Index < Stream->documents().size(); ++Index) {
- if (IsEmptyDocument(Index))
- continue;
- const yaml::Node *Root = node(Stream->documents()[Index].Root);
- if (Root == nullptr || requireKind(*Root, yaml::NodeKind::Mapping, "machine function") ||
- parseFunction(*Root, Staging)) {
- return std::move(Result);
- }
- SawFunction = true;
- }
- if (!SawFunction) {
- static_cast<void>(fail(Stream->documents()[FirstContent].Range,
- "MIR stream must contain at least one machine function document"));
- return std::move(Result);
- }
-
- auto UnitResult = Staging.Unit.verify();
- if (!UnitResult) {
- static_cast<void>(
- fail(Stream->documents().back().Range, "parsed compilation unit failed verification: " +
- std::string(UnitResult.error().message())));
- return std::move(Result);
- }
- ActiveDocument = nullptr;
- Result.Document = std::move(Staging);
- return std::move(Result);
-}
-
-bool MIRDocumentParser::parseFunction(const yaml::Node &Root, MIRDocument &Document) {
- constexpr std::array Keys{
- std::string_view{"name"},
- std::string_view{"alignment"},
- std::string_view{"exposesReturnsTwice"},
- std::string_view{"legalized"},
- std::string_view{"regBankSelected"},
- std::string_view{"selected"},
- std::string_view{"failedISel"},
- std::string_view{"tracksRegLiveness"},
- std::string_view{"hasWinCFI"},
- std::string_view{"noPhis"},
- std::string_view{"isSSA"},
- std::string_view{"noVRegs"},
- std::string_view{"hasFakeUses"},
- std::string_view{"callsEHReturn"},
- std::string_view{"callsUnwindInit"},
- std::string_view{"hasEHContTarget"},
- std::string_view{"hasEHScopes"},
- std::string_view{"hasEHFunclets"},
- std::string_view{"isOutlined"},
- std::string_view{"debugInstrRef"},
- std::string_view{"failsVerification"},
- std::string_view{"tracksDebugUserValues"},
- std::string_view{"registers"},
- std::string_view{"liveins"},
- std::string_view{"calleeSavedRegisters"},
- std::string_view{"frameInfo"},
- std::string_view{"fixedStack"},
- std::string_view{"stack"},
- std::string_view{"entry_values"},
- std::string_view{"callSites"},
- std::string_view{"debugValueSubstitutions"},
- std::string_view{"constants"},
- std::string_view{"machineFunctionInfo"},
- std::string_view{"jumpTable"},
- std::string_view{"machineMetadataNodes"},
- std::string_view{"calledGlobals"},
- std::string_view{"prefetch-targets"},
- std::string_view{"body"},
- };
- const yaml::Node *NameNode = mappingValue(Root, "name");
- if (NameNode == nullptr)
- return fail(Root.range(), "missing required key 'name'");
- if (validateKeys(Root, Keys, "machine function"))
- return true;
- std::string_view Name;
- if (scalar(*NameNode, Name, "machine function name"))
- return true;
-
- const EmbeddedIRFunction *IRFunction = nullptr;
- if (Document.EmbeddedIR) {
- if (Name.empty()) {
- std::size_t AnonymousOrdinal = 0;
- for (std::size_t Index = 0; Index < Document.Unit.functionCount(); ++Index) {
- const MachineFunction *Existing = Document.Unit.functionAt(Index);
- if (Existing != nullptr && Existing->name().empty())
- ++AnonymousOrdinal;
- }
- IRFunction = Document.EmbeddedIR->unnamedFunction(AnonymousOrdinal);
- } else {
- IRFunction = Document.EmbeddedIR->function(Name);
- }
- if (IRFunction == nullptr)
- return fail(NameNode->range(),
- "function '" + std::string(Name) + "' isn't defined in the provided LLVM IR");
- }
-
- if (!Name.empty() && Document.Unit.function(Name) != nullptr)
- return fail(NameNode->range(), "redefinition of machine function '" + std::string(Name) + "'");
-
- auto Created = Document.Unit.createMachineFunction(std::string(Name));
- if (!Created)
- return importError(NameNode->range(), Created.error());
- MachineFunction &Function = **Created;
- ActiveFunction = &Function;
-
- MIRFunctionDocumentInfo DocumentInfo{
- .Function = Function.stableID(),
- .NoPHIs = std::nullopt,
- .IsSSA = std::nullopt,
- .NoVRegs = std::nullopt,
- .HasFakeUses = std::nullopt,
- };
- MIParserContext Context;
- if (IRFunction != nullptr) {
- Context.HasIRBlock = [IRFunction](std::string_view BlockName) {
- return IRFunction->block(BlockName) != nullptr;
- };
- }
-
- std::vector<PendingJumpTable> PendingJumpTables;
- if (parseFunctionScalars(Root, Function, DocumentInfo) ||
- parseMetadata(Root, Function, Context) || parseRegisters(Root, Function, Context) ||
- parseStackObjects(Root, Function, Context) || parseConstants(Root, Function, Context) ||
- reserveJumpTables(Root, Function, Context, PendingJumpTables) ||
- parseBody(Root, Function, Context) || defineJumpTables(Function, PendingJumpTables) ||
- parseFrameState(Root, Function, Context) ||
- recomputeProperties(Root, Function, DocumentInfo) || parseTargetState(Root, Function) ||
- parseFunctionRecords(Root, Function) || validateDocumentReferences(Function)) {
- return true;
- }
-
- if (Options.VerifyMachineFunctions) {
- auto Verified = MachineVerifier::verify(Function, Target);
- if (!Verified)
- return importError(Root.range(), Verified.error(), "mir-verifier");
- }
- Document.FunctionInfo.push_back(DocumentInfo);
- ActiveFunction = nullptr;
- return false;
-}
-
-} // namespace rcc::mir
diff --git a/backend/lib/MIR/MIRDocumentParser.h b/backend/lib/MIR/MIRDocumentParser.h
deleted file mode 100644
index 4d1d1ea..0000000
--- a/backend/lib/MIR/MIRDocumentParser.h
+++ /dev/null
@@ -1,132 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-// NOLINTNEXTLINE(llvm-header-guard)
-#ifndef RCC_LIB_MIR_MIRDOCUMENTPARSER_H
-#define RCC_LIB_MIR_MIRDOCUMENTPARSER_H
-
-#include "rcc/CodeGen/MachineDebugInfo.h"
-#include "rcc/CodeGen/MachineFrameInfo.h"
-#include "rcc/CodeGen/MachineJumpTableInfo.h"
-#include "rcc/CodeGen/MachineMetadata.h"
-#include "rcc/CodeGen/TargetMIRTextInfo.h"
-#include "rcc/MIR/LLVMConstantSyntax.h"
-#include "rcc/MIR/MIRDocument.h"
-
-#include <cstdint>
-#include <span>
-#include <string>
-#include <string_view>
-#include <utility>
-#include <vector>
-
-namespace rcc {
-
-class MachineBasicBlock;
-class MachineFunction;
-class MachineInstr;
-
-namespace mir {
-
-struct PendingJumpTable final {
- JumpTableIndex Index;
- std::uint32_t TextID = 0;
- JumpTableEntryEncoding Encoding = JumpTableEntryEncoding::BlockAddress;
- std::uint8_t EntrySize = 8;
- std::vector<std::string> Blocks;
-};
-
-class MIRDocumentParser final {
-public:
- MIRDocumentParser(const TargetDescription &Target, std::string SourceName, std::string SourceText,
- MIRDocumentParserOptions Options)
- : Target(Target), Options(std::move(Options)),
- Result(std::move(SourceName), std::move(SourceText)) {}
-
- [[nodiscard]] MIRDocumentParseResult run();
-
-private:
- [[nodiscard]] bool fail(const TextRange &Range, std::string Message,
- std::string Category = "mir-yaml");
- [[nodiscard]] bool importError(const TextRange &Range, const Error &Failure,
- std::string Category = "mir-yaml");
- [[nodiscard]] const yaml::Node *node(yaml::NodeID ID) const noexcept {
- return Stream->node(ID);
- }
- [[nodiscard]] const yaml::Node *mappingValue(const yaml::Node &Mapping,
- std::string_view Key) const noexcept;
- [[nodiscard]] bool requireKind(const yaml::Node &Node, yaml::NodeKind Kind,
- std::string_view Description);
- [[nodiscard]] bool validateKeys(const yaml::Node &Mapping, std::span<const std::string_view> Keys,
- std::string_view Description);
- [[nodiscard]] bool scalar(const yaml::Node &Node, std::string_view &Value,
- std::string_view Description);
- [[nodiscard]] bool boolean(const yaml::Node &Node, bool &Value);
- [[nodiscard]] bool unsignedValue(const yaml::Node &Node, std::uint64_t &Value,
- std::string_view Description);
- [[nodiscard]] bool signedValue(const yaml::Node &Node, std::int64_t &Value,
- std::string_view Description);
- [[nodiscard]] bool alignment(const yaml::Node &Node, Alignment &Value, bool AllowZero);
- [[nodiscard]] bool physicalRegister(const yaml::Node &Node, PhysicalRegister &Reg);
- [[nodiscard]] bool physicalRegister(std::string_view Text, const TextRange &Range,
- PhysicalRegister &Reg);
- [[nodiscard]] bool virtualRegister(std::string_view Text, const TextRange &Range,
- MachineFunction &Function, MIParserContext &Context,
- Register &Reg);
- [[nodiscard]] Expected<MachineMetadataReference>
- resolveMetadataReference(const MachineFunction &Function, std::uint32_t Slot) const;
- [[nodiscard]] bool parseVariableDebugInfo(const yaml::Node &Entry, MachineFunction &Function,
- MachineVariableDebugInfo &DebugInfo);
- [[nodiscard]] bool parseFunction(const yaml::Node &Root, MIRDocument &Document);
- [[nodiscard]] bool parseFunctionScalars(const yaml::Node &Root, MachineFunction &Function,
- MIRFunctionDocumentInfo &DocumentInfo);
- [[nodiscard]] bool recomputeProperties(const yaml::Node &Root, MachineFunction &Function,
- const MIRFunctionDocumentInfo &DocumentInfo);
- [[nodiscard]] bool parseRegisters(const yaml::Node &Root, MachineFunction &Function,
- MIParserContext &Context);
- [[nodiscard]] bool parseMetadata(const yaml::Node &Root, MachineFunction &Function,
- MIParserContext &Context);
- [[nodiscard]] bool parseStackObjects(const yaml::Node &Root, MachineFunction &Function,
- MIParserContext &Context);
- [[nodiscard]] bool parseConstants(const yaml::Node &Root, MachineFunction &Function,
- MIParserContext &Context);
- [[nodiscard]] bool parseFrameState(const yaml::Node &Root, MachineFunction &Function,
- const MIParserContext &Context);
- [[nodiscard]] bool reserveJumpTables(const yaml::Node &Root, MachineFunction &Function,
- MIParserContext &Context,
- std::vector<PendingJumpTable> &Pending);
- [[nodiscard]] bool defineJumpTables(MachineFunction &Function,
- std::span<const PendingJumpTable> Pending);
- [[nodiscard]] bool parseBody(const yaml::Node &Root, MachineFunction &Function,
- MIParserContext &Context);
- [[nodiscard]] TextRange scalarDiagnosticRange(const yaml::Node &Scalar,
- const TextRange &ScalarRange) const noexcept;
- [[nodiscard]] bool parseFunctionRecords(const yaml::Node &Root, MachineFunction &Function);
- [[nodiscard]] bool parseTargetState(const yaml::Node &Root, MachineFunction &Function);
- [[nodiscard]] bool convertTargetNode(const yaml::Node &Source, MIRTargetNode &Destination);
- [[nodiscard]] bool validateDocumentReferences(const MachineFunction &Function);
- [[nodiscard]] std::string_view effectiveDataLayout() const noexcept;
- [[nodiscard]] LLVMConstantSyntaxOptions pointerLayoutOptions() const noexcept;
-
- [[nodiscard]] MachineBasicBlock *blockAt(MachineFunction &Function,
- std::uint32_t Number) const noexcept;
- [[nodiscard]] MachineInstr *instructionAt(MachineFunction &Function, std::uint32_t Block,
- std::uint32_t Offset) const noexcept;
- [[nodiscard]] bool parseBlockReference(std::string_view Text, const TextRange &Range,
- MachineFunction &Function, MachineBasicBlock *&Block);
- [[nodiscard]] bool parseFrameReference(const yaml::Node &Node, const MIParserContext &Context,
- FrameIndex &Index);
- [[nodiscard]] bool parseSaveRestorePoints(const yaml::Node &Node, MachineFunction &Function,
- std::vector<MachineFrameSaveRestorePoint> &Points);
-
- const TargetDescription &Target;
- MIRDocumentParserOptions Options;
- MIRDocumentParseResult Result;
- const yaml::Stream *Stream = nullptr;
- MIRDocument *ActiveDocument = nullptr;
- MachineFunction *ActiveFunction = nullptr;
-};
-
-} // namespace mir
-} // namespace rcc
-
-#endif // RCC_LIB_MIR_MIRDOCUMENTPARSER_H
diff --git a/backend/lib/MIR/MIRDocumentPrinter.cpp b/backend/lib/MIR/MIRDocumentPrinter.cpp
deleted file mode 100644
index 06998bb..0000000
--- a/backend/lib/MIR/MIRDocumentPrinter.cpp
+++ /dev/null
@@ -1,1499 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include "MIRDocumentReferenceValidation.h"
-#include "rcc/CodeGen/MachineBasicBlock.h"
-#include "rcc/CodeGen/MachineCompilationStatus.h"
-#include "rcc/CodeGen/MachineConstantPool.h"
-#include "rcc/CodeGen/MachineFrameInfo.h"
-#include "rcc/CodeGen/MachineFunction.h"
-#include "rcc/CodeGen/MachineFunctionAttributes.h"
-#include "rcc/CodeGen/MachineFunctionProperties.h"
-#include "rcc/CodeGen/MachineFunctionRecords.h"
-#include "rcc/CodeGen/MachineInstr.h"
-#include "rcc/CodeGen/MachineJumpTableInfo.h"
-#include "rcc/CodeGen/MachineMetadata.h"
-#include "rcc/CodeGen/MachineRegisterInfo.h"
-#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/MIRDocument.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 <unordered_set>
-#include <utility>
-#include <variant>
-#include <vector>
-
-namespace rcc::mir {
-namespace {
-
-enum class YAMLQuoting : std::uint8_t {
- None,
- Single,
- Double,
-};
-
-[[nodiscard]] bool isASCIIAlphanumeric(unsigned char Character) noexcept {
- return (Character >= '0' && Character <= '9') || (Character >= 'A' && Character <= 'Z') ||
- (Character >= 'a' && Character <= 'z');
-}
-
-[[nodiscard]] bool isYAMLNumeric(std::string_view Value) noexcept {
- if (Value.empty() || Value == "+" || Value == "-")
- return false;
- if (Value == ".nan" || Value == ".NaN" || Value == ".NAN")
- return true;
-
- std::string_view Tail = Value;
- if (Tail.front() == '+' || Tail.front() == '-')
- Tail.remove_prefix(1);
- if (Tail == ".inf" || Tail == ".Inf" || Tail == ".INF")
- return true;
- if (Value.starts_with("0o")) {
- return Value.size() > 2U &&
- Value.substr(2).find_first_not_of("01234567") == std::string_view::npos;
- }
- if (Value.starts_with("0x")) {
- return Value.size() > 2U &&
- Value.substr(2).find_first_not_of("0123456789abcdefABCDEF") == std::string_view::npos;
- }
-
- if (Tail.empty() || Tail.front() == 'e' || Tail.front() == 'E')
- return false;
- std::size_t Position = 0;
- if (Tail.front() == '.') {
- ++Position;
- if (Position == Tail.size() || Tail[Position] < '0' || Tail[Position] > '9')
- return false;
- while (Position < Tail.size() && Tail[Position] >= '0' && Tail[Position] <= '9')
- ++Position;
- } else {
- while (Position < Tail.size() && Tail[Position] >= '0' && Tail[Position] <= '9')
- ++Position;
- if (Position == 0)
- return false;
- }
-
- if (Position < Tail.size() && Tail[Position] == '.') {
- ++Position;
- while (Position < Tail.size() && Tail[Position] >= '0' && Tail[Position] <= '9')
- ++Position;
- }
- if (Position == Tail.size())
- return true;
- if (Tail[Position] != 'e' && Tail[Position] != 'E')
- return false;
- ++Position;
- if (Position < Tail.size() && (Tail[Position] == '+' || Tail[Position] == '-'))
- ++Position;
- const std::size_t ExponentBegin = Position;
- while (Position < Tail.size() && Tail[Position] >= '0' && Tail[Position] <= '9')
- ++Position;
- return Position == Tail.size() && Position != ExponentBegin;
-}
-
-[[nodiscard]] YAMLQuoting yamlQuoting(std::string_view Value) noexcept {
- if (Value.empty())
- return YAMLQuoting::Single;
-
- YAMLQuoting Result = YAMLQuoting::None;
- const auto IsSpace = [](unsigned char Character) {
- return Character == ' ' || Character == '\t' || Character == '\r' || Character == '\n' ||
- Character == '\f' || Character == '\v';
- };
- if (IsSpace(static_cast<unsigned char>(Value.front())) ||
- IsSpace(static_cast<unsigned char>(Value.back())) || Value == "null" || Value == "Null" ||
- Value == "NULL" || Value == "~" || Value == "true" || Value == "True" || Value == "TRUE" ||
- Value == "false" || Value == "False" || Value == "FALSE" || isYAMLNumeric(Value)) {
- Result = YAMLQuoting::Single;
- }
-
- switch (Value.front()) {
- case '-':
- case '?':
- case ':':
- case '\\':
- case ',':
- case '[':
- case ']':
- case '{':
- case '}':
- case '#':
- case '&':
- case '*':
- case '!':
- case '|':
- case '>':
- case '\'':
- case '"':
- case '%':
- case '@':
- case '`':
- Result = YAMLQuoting::Single;
- break;
- default:
- break;
- }
-
- for (const char RawCharacter : Value) {
- const auto Character = static_cast<unsigned char>(RawCharacter);
- if (isASCIIAlphanumeric(Character))
- continue;
- switch (Character) {
- case '_':
- case '-':
- case '^':
- case '.':
- case ',':
- case ' ':
- case '\t':
- continue;
- case '\n':
- case '\r':
- case 0x7f:
- return YAMLQuoting::Double;
- default:
- if (Character <= 0x1fU || (Character & 0x80U) != 0)
- return YAMLQuoting::Double;
- Result = YAMLQuoting::Single;
- break;
- }
- }
- return Result;
-}
-
-[[nodiscard]] std::string yamlScalar(std::string_view Value) {
- const YAMLQuoting Quoting = yamlQuoting(Value);
- if (Quoting == YAMLQuoting::None)
- return std::string(Value);
-
- std::string Result;
- Result.reserve(Value.size() + 2U);
- const char Quote = Quoting == YAMLQuoting::Single ? '\'' : '"';
- Result.push_back(Quote);
- for (const char Character : Value) {
- if (Quoting == YAMLQuoting::Single) {
- Result.push_back(Character);
- if (Character == '\'')
- Result.push_back('\'');
- continue;
- }
- switch (Character) {
- case '\\':
- Result.append("\\\\");
- break;
- case '"':
- Result.append("\\\"");
- break;
- case '\0':
- Result.append("\\0");
- break;
- case '\a':
- Result.append("\\a");
- break;
- case '\b':
- Result.append("\\b");
- break;
- case '\t':
- Result.append("\\t");
- break;
- case '\n':
- Result.append("\\n");
- break;
- case '\v':
- Result.append("\\v");
- break;
- case '\f':
- Result.append("\\f");
- break;
- case '\r':
- Result.append("\\r");
- break;
- case '\x1b':
- Result.append("\\e");
- break;
- default: {
- const auto Byte = static_cast<unsigned char>(Character);
- if (Byte < 0x20U || Byte == 0x7fU) {
- static constexpr std::string_view Hex = "0123456789ABCDEF";
- Result.append("\\x");
- Result.push_back(Hex[Byte >> 4U]);
- Result.push_back(Hex[Byte & 0xfU]);
- } else {
- Result.push_back(Character);
- }
- break;
- }
- }
- }
- Result.push_back(Quote);
- return Result;
-}
-
-void appendBlockScalar(std::string &Output, std::string_view Text, std::size_t Indent) {
- std::size_t Position = 0;
- do {
- Output.append(Indent, ' ');
- const std::size_t End = Text.find('\n', Position);
- if (End == std::string_view::npos) {
- Output.append(Text.substr(Position));
- Output.push_back('\n');
- return;
- }
- Output.append(Text.substr(Position, End - Position));
- Output.push_back('\n');
- Position = End + 1U;
- } while (Position < Text.size());
-}
-
-[[nodiscard]] std::optional<std::uint32_t> parseDecimal32(std::string_view Text) noexcept {
- std::uint32_t Value = 0;
- if (Text.empty())
- return std::nullopt;
- const auto [End, Error] = std::from_chars(Text.data(), Text.data() + Text.size(), Value, 10);
- if (Error != std::errc{} || End != Text.data() + Text.size())
- return std::nullopt;
- return Value;
-}
-
-[[nodiscard]] bool isDefaultFrameState(const MachineFrameState &State) {
- return State == MachineFrameState{};
-}
-
-class MIRDocumentPrinter final {
-public:
- MIRDocumentPrinter(const MIRDocument &Document, const TargetDescription &Target,
- MIRDocumentPrinterOptions Options)
- : Document(Document), Target(Target), Options(std::move(Options)) {}
-
- [[nodiscard]] Expected<std::string> run();
-
-private:
- struct InstructionLocation final {
- std::uint32_t Block = 0;
- std::uint32_t Offset = 0;
- };
-
- [[nodiscard]] Expected<void> printFunction(const MachineFunction &Function,
- const MIRFunctionDocumentInfo *DocumentInfo);
- [[nodiscard]] Expected<MIParserContext> createBodyContext(const MachineFunction &Function) const;
- [[nodiscard]] Expected<void> printRegisters(const MachineFunction &Function,
- const MIParserContext &Context);
- [[nodiscard]] Expected<void> printFrameInfo(const MachineFunction &Function,
- const MIParserContext &Context);
- [[nodiscard]] Expected<void> printStackObjects(const MachineFunction &Function,
- const MIParserContext &Context, bool Fixed);
- [[nodiscard]] Expected<void> printConstants(const MachineFunction &Function,
- const MIParserContext &Context);
- [[nodiscard]] Expected<void> printJumpTable(const MachineFunction &Function,
- const MIParserContext &Context);
- [[nodiscard]] Expected<void> printMetadata(const MachineFunction &Function,
- const MIParserContext &Context);
- [[nodiscard]] Expected<void> printTargetState(const MachineFunction &Function);
- [[nodiscard]] Expected<void> printFunctionRecords(const MachineFunction &Function,
- const MIParserContext &Context);
- [[nodiscard]] Expected<void> verifyOmittedEmbeddedIRLayout(const MachineFunction &Function) const;
-
- [[nodiscard]] Expected<std::string> physicalRegister(PhysicalRegister Register) const;
- [[nodiscard]] Expected<std::string> frameReference(FrameIndex Index,
- const MIParserContext &Context) const;
- [[nodiscard]] Expected<std::string> metadataReference(MachineMetadataReference Reference,
- const MIParserContext &Context) const;
- [[nodiscard]] Expected<std::string> metadataValue(const MachineMetadataValue &Value,
- const MIParserContext &Context) const;
- [[nodiscard]] Expected<std::string> debugLocation(const MachineDebugLocation &Location,
- const MIParserContext &Context) const;
- [[nodiscard]] Expected<std::string> diLocation(const MachineDILocation &Location,
- std::size_t FrameIndex,
- const MIParserContext &Context) const;
- [[nodiscard]] Expected<InstructionLocation> instructionLocation(const MachineFunction &Function,
- MachineInstrStableID ID) const;
- [[nodiscard]] Expected<std::string> blockReference(const MachineFunction &Function,
- MachineBlockStableID ID) const;
- [[nodiscard]] Expected<std::string> targetNode(const MIRTargetNode &Node) const;
- [[nodiscard]] const MIRFunctionDocumentInfo *
- documentInfo(const MachineFunction &Function) const noexcept;
-
- void printBoolean(std::string_view Key, bool Value, bool Always = false);
- void printUnsigned(std::string_view Key, std::uint64_t Value, bool Always = false);
- void printSigned(std::string_view Key, std::int64_t Value, bool Always = false);
-
- const MIRDocument &Document;
- const TargetDescription &Target;
- MIRDocumentPrinterOptions Options;
- std::string Output;
-};
-
-void MIRDocumentPrinter::printBoolean(std::string_view Key, bool Value, bool Always) {
- if (!Always && Options.Mode == MIPrintMode::Readable && !Value)
- return;
- Output.append(Key);
- Output.append(Value ? ": true\n" : ": false\n");
-}
-
-void MIRDocumentPrinter::printUnsigned(std::string_view Key, std::uint64_t Value, bool Always) {
- if (!Always && Options.Mode == MIPrintMode::Readable && Value == 0)
- return;
- Output.append(Key);
- Output.append(": ");
- Output.append(std::to_string(Value));
- Output.push_back('\n');
-}
-
-void MIRDocumentPrinter::printSigned(std::string_view Key, std::int64_t Value, bool Always) {
- if (!Always && Options.Mode == MIPrintMode::Readable && Value == 0)
- return;
- Output.append(Key);
- Output.append(": ");
- Output.append(std::to_string(Value));
- Output.push_back('\n');
-}
-
-Expected<std::string> MIRDocumentPrinter::physicalRegister(PhysicalRegister Register) const {
- const auto Name = Target.registers().physicalRegisterMIRName(Register);
- if (!Name) {
- return makeUnexpected(ErrorCode::VerificationError,
- "physical register has no canonical MIR name");
- }
- return "$" + std::string(*Name);
-}
-
-const MIRFunctionDocumentInfo *
-MIRDocumentPrinter::documentInfo(const MachineFunction &Function) const noexcept {
- const auto Infos = Document.functionDocumentInfo();
- const auto Found = std::ranges::find_if(Infos, [&Function](const MIRFunctionDocumentInfo &Info) {
- return Info.Function == Function.stableID();
- });
- return Found == Infos.end() ? nullptr : &*Found;
-}
-
-Expected<void>
-MIRDocumentPrinter::verifyOmittedEmbeddedIRLayout(const MachineFunction &Function) const {
- if (Options.EmitEmbeddedIR)
- return {};
-
- const EmbeddedIRReferenceIndex *Embedded = Document.embeddedIR();
- if (Embedded == nullptr)
- return {};
-
- bool HasLayoutDependentContent = false;
- for (const VirtualRegisterInfo &RegisterInfo : Function.registerInfo().virtualRegisters()) {
- if (!RegisterInfo.IsTombstone && RegisterInfo.Type &&
- RegisterInfo.Type->isPointerOrPointerVector()) {
- HasLayoutDependentContent = true;
- break;
- }
- }
- if (!HasLayoutDependentContent) {
- for (const MachineConstantPoolEntry &Entry : Function.constantPool().entries()) {
- const MachineConstantPoolEntryDesc *Description = Entry.description();
- if (Description != nullptr &&
- std::holds_alternative<GenericConstantData>(Description->Value)) {
- HasLayoutDependentContent = true;
- break;
- }
- }
- }
- if (!HasLayoutDependentContent)
- return {};
-
- if (Options.DataLayout.empty()) {
- return makeUnexpected(
- ErrorCode::InvalidArgument,
- "omitting embedded LLVM IR with layout-dependent MIR requires an explicit printer "
- "DataLayout");
- }
-
- const LLVMConstantSyntaxOptions LayoutOptions{
- .DataLayout = Options.DataLayout,
- .NamedTypes = {},
- };
- for (const VirtualRegisterInfo &RegisterInfo : Function.registerInfo().virtualRegisters()) {
- if (RegisterInfo.IsTombstone || !RegisterInfo.Type ||
- !RegisterInfo.Type->isPointerOrPointerVector()) {
- continue;
- }
- const auto AddressSpace = RegisterInfo.Type->addressSpace();
- if (!AddressSpace) {
- return makeUnexpected(ErrorCode::VerificationError,
- "pointer virtual register has no address space");
- }
- auto PointerSize = llvmPointerSizeInBits(*AddressSpace, LayoutOptions);
- if (!PointerSize) {
- return makeUnexpected(ErrorCode::InvalidArgument,
- "printer DataLayout cannot determine pointer width: " +
- std::string(PointerSize.error().message()));
- }
- if (*PointerSize != RegisterInfo.Type->scalarBitWidth()) {
- return makeUnexpected(ErrorCode::VerificationError,
- "printer DataLayout does not match pointer virtual-register width");
- }
- }
-
- for (const MachineConstantPoolEntry &Entry : Function.constantPool().entries()) {
- const MachineConstantPoolEntryDesc *Description = Entry.description();
- if (Description == nullptr)
- continue;
- const auto *Generic = std::get_if<GenericConstantData>(&Description->Value);
- if (Generic == nullptr)
- continue;
- auto StorageSize = llvmConstantStorageSize(Generic->Type, LayoutOptions);
- if (!StorageSize) {
- return makeUnexpected(ErrorCode::InvalidArgument,
- "printer DataLayout cannot lay out generic constant: " +
- std::string(StorageSize.error().message()));
- }
- if (*StorageSize != Description->Size) {
- return makeUnexpected(ErrorCode::VerificationError,
- "printer DataLayout does not match generic constant storage size");
- }
- }
- return {};
-}
-
-Expected<MIParserContext>
-MIRDocumentPrinter::createBodyContext(const MachineFunction &Function) const {
- MIParserContext Context;
- Context.SyncScopes.assign(Document.syncScopes().begin(), Document.syncScopes().end());
- const auto VirtualRegisters = Function.registerInfo().virtualRegisters();
- for (std::size_t Index = 0; Index < VirtualRegisters.size(); ++Index) {
- if (VirtualRegisters[Index].IsTombstone)
- continue;
- auto Reg = Register::makeVirtual(Index);
- if (!Reg)
- return std::unexpected(Reg.error());
- if (Index > std::numeric_limits<std::uint32_t>::max()) {
- return makeUnexpected(ErrorCode::Unsupported,
- "MIR cannot represent more than 2^32 virtual registers");
- }
- Context.VirtualRegisters.push_back({.TextID = static_cast<std::uint32_t>(Index), .Reg = *Reg});
- }
-
- std::uint32_t StackID = 0;
- std::uint32_t FixedID = 0;
- for (const StackObject &Object : Function.frameInfo().objects()) {
- const StackObjectDesc *Description = Object.description();
- if (Description == nullptr)
- continue;
- MIFrameObjectSlot Slot{
- .TextID = Object.isFixed() ? FixedID++ : StackID++,
- .Index = Object.index(),
- .Name = Description->AllocaName,
- };
- (Object.isFixed() ? Context.FixedStackObjects : Context.StackObjects)
- .push_back(std::move(Slot));
- }
-
- std::uint32_t ConstantID = 0;
- for (const MachineConstantPoolEntry &Entry : Function.constantPool().entries()) {
- if (Entry.description() != nullptr)
- Context.ConstantPoolItems.push_back({.TextID = ConstantID++, .Index = Entry.index()});
- }
- std::uint32_t JumpTableID = 0;
- for (const MachineJumpTableEntry &Entry : Function.jumpTableInfo().tables()) {
- if (Entry.description() != nullptr)
- Context.JumpTables.push_back({.TextID = JumpTableID++, .Index = Entry.index()});
- }
-
- std::unordered_set<std::uint32_t> EmbeddedMetadataSlots;
- if (const EmbeddedIRReferenceIndex *Embedded = Document.embeddedIR()) {
- for (const EmbeddedIRMetadataDefinition &Definition : Embedded->metadataDefinitions()) {
- const auto Slot = parseDecimal32(Definition.Name);
- if (Slot) {
- if (!EmbeddedMetadataSlots.insert(*Slot).second) {
- return makeUnexpected(ErrorCode::VerificationError,
- "embedded LLVM IR metadata slots are not unique");
- }
- Context.Metadata.push_back(
- {.TextID = *Slot, .Reference = MachineMetadataReference::embeddedIR(*Slot)});
- }
- }
- }
-
- std::unordered_set<std::uint32_t> UsedMetadataSlots = EmbeddedMetadataSlots;
- for (const MachineMetadataNode &Node : Function.metadata().nodes()) {
- if (!EmbeddedMetadataSlots.contains(Node.Slot))
- UsedMetadataSlots.insert(Node.Slot);
- }
- std::uint64_t NextMetadataSlot = 0;
- for (const MachineMetadataNode &Node : Function.metadata().nodes()) {
- std::uint32_t TextID = Node.Slot;
- if (EmbeddedMetadataSlots.contains(TextID)) {
- while (NextMetadataSlot <= std::numeric_limits<std::uint32_t>::max() &&
- UsedMetadataSlots.contains(static_cast<std::uint32_t>(NextMetadataSlot))) {
- ++NextMetadataSlot;
- }
- if (NextMetadataSlot > std::numeric_limits<std::uint32_t>::max()) {
- return makeUnexpected(ErrorCode::Unsupported, "MIR metadata text slot space is exhausted");
- }
- TextID = static_cast<std::uint32_t>(NextMetadataSlot);
- UsedMetadataSlots.insert(TextID);
- ++NextMetadataSlot;
- }
- Context.Metadata.push_back(
- {.TextID = TextID, .Reference = MachineMetadataReference::machineFunction(Node.Slot)});
- }
- return Context;
-}
-
-Expected<std::string> MIRDocumentPrinter::frameReference(FrameIndex Index,
- const MIParserContext &Context) const {
- const auto Stack = std::ranges::find_if(
- Context.StackObjects, [Index](const MIFrameObjectSlot &Slot) { return Slot.Index == Index; });
- if (Stack != Context.StackObjects.end())
- return "%stack." + std::to_string(Stack->TextID);
- const auto Fixed =
- std::ranges::find_if(Context.FixedStackObjects,
- [Index](const MIFrameObjectSlot &Slot) { return Slot.Index == Index; });
- if (Fixed != Context.FixedStackObjects.end())
- return "%fixed-stack." + std::to_string(Fixed->TextID);
- return makeUnexpected(ErrorCode::VerificationError,
- "frame state references an unknown stack object");
-}
-
-Expected<std::string> MIRDocumentPrinter::metadataReference(MachineMetadataReference Reference,
- const MIParserContext &Context) const {
- if (!Reference.isValid())
- return makeUnexpected(ErrorCode::VerificationError, "invalid metadata reference");
- const auto Slot =
- std::ranges::find_if(Context.Metadata, [Reference](const MIMetadataSlot &Candidate) {
- return Candidate.Reference == Reference;
- });
- if (Slot == Context.Metadata.end()) {
- return makeUnexpected(ErrorCode::VerificationError, "metadata reference has no MIR text slot");
- }
- return "!" + std::to_string(Slot->TextID);
-}
-
-Expected<std::string> MIRDocumentPrinter::metadataValue(const MachineMetadataValue &Value,
- const MIParserContext &Context) const {
- if (const MachineMetadataReference *Reference = Value.reference())
- return metadataReference(*Reference, Context);
- const MachineDIExpression *Expression = Value.expression();
- if (Expression == nullptr)
- return makeUnexpected(ErrorCode::VerificationError, "metadata value is not printable");
- return formatDIExpression(Expression->elements());
-}
-
-Expected<std::string> MIRDocumentPrinter::diLocation(const MachineDILocation &Location,
- std::size_t FrameIndex,
- const MIParserContext &Context) const {
- if (FrameIndex >= Location.inlineChain().size()) {
- return makeUnexpected(ErrorCode::VerificationError,
- "inline DILocation has an invalid frame chain");
- }
- const MachineDILocationFrame &Frame = Location.inlineChain()[FrameIndex];
- auto Scope = metadataReference(Frame.Scope, Context);
- if (!Scope)
- return std::unexpected(Scope.error());
- std::string Text = "!DILocation(line: " + std::to_string(Frame.Line);
- if (Options.Mode == MIPrintMode::Complete || Frame.Column != 0)
- Text.append(", column: " + std::to_string(Frame.Column));
- Text.append(", scope: " + *Scope);
- if (FrameIndex + 1U < Location.inlineChain().size()) {
- auto Nested = diLocation(Location, FrameIndex + 1U, Context);
- if (!Nested)
- return std::unexpected(Nested.error());
- Text.append(", inlinedAt: " + *Nested);
- } else if (Location.terminalInlinedAt()) {
- auto Terminal = metadataReference(*Location.terminalInlinedAt(), Context);
- if (!Terminal)
- return std::unexpected(Terminal.error());
- Text.append(", inlinedAt: " + *Terminal);
- }
- if (Options.Mode == MIPrintMode::Complete || Frame.IsImplicitCode)
- Text.append(Frame.IsImplicitCode ? ", isImplicitCode: true" : ", isImplicitCode: false");
- if (Options.Mode == MIPrintMode::Complete || Frame.AtomGroup != 0)
- Text.append(", atomGroup: " + std::to_string(Frame.AtomGroup));
- if (Options.Mode == MIPrintMode::Complete || Frame.AtomRank != 0)
- Text.append(", atomRank: " + std::to_string(Frame.AtomRank));
- Text.push_back(')');
- return Text;
-}
-
-Expected<std::string> MIRDocumentPrinter::debugLocation(const MachineDebugLocation &Location,
- const MIParserContext &Context) const {
- if (const MachineMetadataReference *Reference = Location.reference())
- return metadataReference(*Reference, Context);
- if (const MachineDILocation *Inline = Location.inlineLocation())
- return diLocation(*Inline, 0, Context);
- return makeUnexpected(ErrorCode::VerificationError, "debug location is not printable");
-}
-
-Expected<MIRDocumentPrinter::InstructionLocation>
-MIRDocumentPrinter::instructionLocation(const MachineFunction &Function,
- MachineInstrStableID ID) const {
- std::uint64_t BlockNumber = 0;
- for (const MachineBasicBlock *Block = Function.firstBlock(); Block != nullptr;
- Block = Block->next(), ++BlockNumber) {
- if (BlockNumber > std::numeric_limits<std::uint32_t>::max())
- break;
- std::uint64_t Offset = 0;
- for (const MachineInstr *Instruction = Block->firstInstruction(); Instruction != nullptr;
- Instruction = Instruction->next(), ++Offset) {
- if (Instruction->stableID() != ID)
- continue;
- if (Offset > std::numeric_limits<std::uint32_t>::max()) {
- return makeUnexpected(ErrorCode::Unsupported, "MIR instruction offset exceeds 32 bits");
- }
- return InstructionLocation{static_cast<std::uint32_t>(BlockNumber),
- static_cast<std::uint32_t>(Offset)};
- }
- }
- return makeUnexpected(ErrorCode::VerificationError,
- "function record references an unlinked instruction");
-}
-
-Expected<std::string> MIRDocumentPrinter::blockReference(const MachineFunction &Function,
- MachineBlockStableID ID) const {
- std::uint64_t Number = 0;
- for (const MachineBasicBlock *Block = Function.firstBlock(); Block != nullptr;
- Block = Block->next(), ++Number) {
- if (Block->stableID() == ID) {
- if (Number > std::numeric_limits<std::uint32_t>::max())
- break;
- return "%bb." + std::to_string(Number);
- }
- }
- return makeUnexpected(ErrorCode::VerificationError,
- "frame record references an unlinked basic block");
-}
-
-Expected<std::string> MIRDocumentPrinter::targetNode(const MIRTargetNode &Node) const {
- switch (Node.Kind) {
- case MIRTargetNodeKind::Null:
- return std::string("null");
- case MIRTargetNodeKind::Scalar:
- return yamlScalar(Node.Scalar);
- case MIRTargetNodeKind::Sequence: {
- std::string Text = "[ ";
- for (std::size_t Index = 0; Index < Node.Sequence.size(); ++Index) {
- if (Index != 0)
- Text.append(", ");
- auto Element = targetNode(Node.Sequence[Index]);
- if (!Element)
- return std::unexpected(Element.error());
- Text.append(*Element);
- }
- Text.append(" ]");
- return Text;
- }
- case MIRTargetNodeKind::Mapping: {
- std::string Text = "{ ";
- for (std::size_t Index = 0; Index < Node.Mapping.size(); ++Index) {
- if (Index != 0)
- Text.append(", ");
- Text.append(yamlScalar(Node.Mapping[Index].Key));
- Text.append(": ");
- auto Value = targetNode(Node.Mapping[Index].Value);
- if (!Value)
- return std::unexpected(Value.error());
- Text.append(*Value);
- }
- Text.append(" }");
- return Text;
- }
- case MIRTargetNodeKind::Count:
- break;
- }
- return makeUnexpected(ErrorCode::VerificationError, "target MIR node has an invalid kind");
-}
-
-Expected<void> MIRDocumentPrinter::printRegisters(const MachineFunction &Function,
- const MIParserContext &Context) {
- if (Context.VirtualRegisters.empty()) {
- if (Options.Mode == MIPrintMode::Complete)
- Output.append("registers: []\n");
- } else {
- Output.append("registers:\n");
- for (const MIVirtualRegisterSlot &Slot : Context.VirtualRegisters) {
- auto InfoResult = Function.registerInfo().virtualRegisterInfo(Slot.Reg);
- if (!InfoResult)
- return std::unexpected(InfoResult.error());
- const VirtualRegisterInfo &Info = InfoResult->get();
- std::string Class = "_";
- if (Info.RegClass) {
- const auto Name = Target.registers().registerClassMIRName(*Info.RegClass);
- if (!Name)
- return makeUnexpected(ErrorCode::VerificationError,
- "virtual register class has no canonical MIR name");
- Class = *Name;
- } else if (Info.Bank) {
- const auto Name = Target.registers().registerBankMIRName(*Info.Bank);
- if (!Name)
- return makeUnexpected(ErrorCode::VerificationError,
- "virtual register bank has no canonical MIR name");
- Class = *Name;
- }
- if (Info.AllocationHints.size() > 1) {
- return makeUnexpected(
- ErrorCode::Unsupported,
- "fixed LLVM MIR can serialize only one simple preferred-register hint");
- }
-
- Output.append(" - { id: ");
- Output.append(std::to_string(Slot.TextID));
- Output.append(", class: ");
- Output.append(yamlScalar(Class));
- if (!Info.AllocationHints.empty()) {
- auto Preferred = physicalRegister(Info.AllocationHints.front());
- if (!Preferred)
- return std::unexpected(Preferred.error());
- Output.append(", preferred-register: ");
- Output.append(yamlScalar(*Preferred));
- }
- if (Info.TargetFlags != 0) {
- auto Names = Target.mirText().virtualRegisterFlagNames(Info.TargetFlags);
- if (!Names)
- return std::unexpected(Names.error());
- Output.append(", flags: [ ");
- for (std::size_t Index = 0; Index < Names->size(); ++Index) {
- if (Index != 0)
- Output.append(", ");
- Output.append(yamlScalar((*Names)[Index]));
- }
- Output.append(" ]");
- }
- Output.append(" }\n");
- }
- }
-
- if (Function.registerInfo().liveIns().empty()) {
- if (Options.Mode == MIPrintMode::Complete)
- Output.append("liveins: []\n");
- } else {
- Output.append("liveins:\n");
- for (const PhysicalRegisterLiveIn &LiveIn : Function.registerInfo().liveIns()) {
- auto Name = physicalRegister(LiveIn.PhysReg);
- if (!Name)
- return std::unexpected(Name.error());
- Output.append(" - { reg: ");
- Output.append(yamlScalar(*Name));
- if (LiveIn.InitialVirtualRegister) {
- const auto Slot = std::ranges::find_if(
- Context.VirtualRegisters, [&LiveIn](const MIVirtualRegisterSlot &Candidate) {
- return Candidate.Reg == *LiveIn.InitialVirtualRegister;
- });
- if (Slot == Context.VirtualRegisters.end()) {
- return makeUnexpected(ErrorCode::VerificationError,
- "live-in references an unknown virtual register");
- }
- Output.append(", virtual-reg: ");
- Output.append(yamlScalar("%" + std::to_string(Slot->TextID)));
- }
- Output.append(" }\n");
- }
- }
-
- if (Function.records().hasCalleeSavedRegisters()) {
- Output.append("calleeSavedRegisters: [ ");
- const auto Registers = Function.records().calleeSavedRegisters();
- for (std::size_t Index = 0; Index < Registers.size(); ++Index) {
- if (Index != 0)
- Output.append(", ");
- auto Name = physicalRegister(Registers[Index]);
- if (!Name)
- return std::unexpected(Name.error());
- Output.append(yamlScalar(*Name));
- }
- Output.append(" ]\n");
- }
- return {};
-}
-
-Expected<void> MIRDocumentPrinter::printFrameInfo(const MachineFunction &Function,
- const MIParserContext &Context) {
- const MachineFrameState &State = Function.frameInfo().state();
- if (Options.Mode == MIPrintMode::Readable && isDefaultFrameState(State))
- return {};
- if (State.MaxCallFrameSize &&
- *State.MaxCallFrameSize > std::numeric_limits<std::uint32_t>::max()) {
- return makeUnexpected(ErrorCode::Unsupported,
- "fixed LLVM MIR maxCallFrameSize is limited to 32 bits");
- }
- Output.append("frameInfo:\n");
- const auto Bool = [this](std::string_view Key, bool Value) {
- if (Options.Mode == MIPrintMode::Readable && !Value)
- return;
- Output.append(" ");
- Output.append(Key);
- Output.append(Value ? ": true\n" : ": false\n");
- };
- const auto Unsigned = [this](std::string_view Key, std::uint64_t Value) {
- if (Options.Mode == MIPrintMode::Readable && Value == 0)
- return;
- Output.append(" ");
- Output.append(Key);
- Output.append(": ");
- Output.append(std::to_string(Value));
- Output.push_back('\n');
- };
-
- Bool("isFrameAddressTaken", State.IsFrameAddressTaken);
- Bool("isReturnAddressTaken", State.IsReturnAddressTaken);
- Bool("hasStackMap", State.HasStackMap);
- Bool("hasPatchPoint", State.HasPatchPoint);
- Unsigned("stackSize", State.StackSize);
- if (Options.Mode == MIPrintMode::Complete || State.OffsetAdjustment != 0) {
- Output.append(" offsetAdjustment: ");
- Output.append(std::to_string(State.OffsetAdjustment));
- Output.push_back('\n');
- }
- Unsigned("maxAlignment", State.MaxAlignment ? State.MaxAlignment->bytes() : 0);
- Bool("adjustsStack", State.AdjustsStack);
- Bool("hasCalls", State.HasCalls);
- if (Options.Mode == MIPrintMode::Complete ||
- State.FramePointerPolicy != MachineFramePointerPolicy::None) {
- Output.append(" framePointerPolicy: ");
- Output.append(getMachineFramePointerPolicyName(State.FramePointerPolicy));
- Output.push_back('\n');
- }
- if (Options.Mode == MIPrintMode::Complete || State.StackProtector) {
- std::string Reference;
- if (State.StackProtector) {
- auto PrintedReference = frameReference(*State.StackProtector, Context);
- if (!PrintedReference)
- return std::unexpected(PrintedReference.error());
- Reference = std::move(*PrintedReference);
- }
- Output.append(" stackProtector: ");
- Output.append(yamlScalar(Reference));
- Output.push_back('\n');
- }
- if (Options.Mode == MIPrintMode::Complete || State.FunctionContext) {
- std::string Reference;
- if (State.FunctionContext) {
- auto PrintedReference = frameReference(*State.FunctionContext, Context);
- if (!PrintedReference)
- return std::unexpected(PrintedReference.error());
- Reference = std::move(*PrintedReference);
- }
- Output.append(" functionContext: ");
- Output.append(yamlScalar(Reference));
- Output.push_back('\n');
- }
- if (Options.Mode == MIPrintMode::Complete || State.MaxCallFrameSize) {
- Unsigned("maxCallFrameSize",
- State.MaxCallFrameSize.value_or(std::numeric_limits<std::uint32_t>::max()));
- }
- Unsigned("cvBytesOfCalleeSavedRegisters", State.CVBytesOfCalleeSavedRegisters);
- Bool("hasOpaqueSPAdjustment", State.HasOpaqueSPAdjustment);
- Bool("hasVAStart", State.HasVAStart);
- Bool("hasMustTailInVarArgFunc", State.HasMustTailInVarArgFunc);
- Bool("hasTailCall", State.HasTailCall);
- Bool("isCalleeSavedInfoValid", State.IsCalleeSavedInfoValid);
- Unsigned("localFrameSize", State.LocalFrameSize);
-
- const auto PrintPoints =
- [this, &Function](std::string_view Key,
- std::span<const MachineFrameSaveRestorePoint> Points) -> Expected<void> {
- if (Points.empty())
- return {};
- Output.append(" ");
- Output.append(Key);
- Output.append(":\n");
- for (const MachineFrameSaveRestorePoint &Point : Points) {
- auto Block = blockReference(Function, Point.Block);
- if (!Block)
- return std::unexpected(Block.error());
- Output.append(" - { point: ");
- Output.append(yamlScalar(*Block));
- if (!Point.Registers.empty()) {
- Output.append(", registers: [ ");
- for (std::size_t Index = 0; Index < Point.Registers.size(); ++Index) {
- if (Index != 0)
- Output.append(", ");
- auto Name = physicalRegister(Point.Registers[Index]);
- if (!Name)
- return std::unexpected(Name.error());
- Output.append(yamlScalar(*Name));
- }
- Output.append(" ]");
- }
- Output.append(" }\n");
- }
- return {};
- };
- if (auto Printed = PrintPoints("savePoint", State.SavePoints); !Printed)
- return Printed;
- return PrintPoints("restorePoint", State.RestorePoints);
-}
-
-Expected<void> MIRDocumentPrinter::printStackObjects(const MachineFunction &Function,
- const MIParserContext &Context, bool Fixed) {
- const auto &Slots = Fixed ? Context.FixedStackObjects : Context.StackObjects;
- if (Slots.empty()) {
- if (Options.Mode == MIPrintMode::Complete)
- Output.append(Fixed ? "fixedStack: []\n" : "stack: []\n");
- return {};
- }
- Output.append(Fixed ? "fixedStack:\n" : "stack:\n");
- for (const MIFrameObjectSlot &Slot : Slots) {
- const StackObject *Object = Function.frameInfo().object(Slot.Index);
- const StackObjectDesc *Description = Object == nullptr ? nullptr : Object->description();
- if (Description == nullptr)
- return makeUnexpected(ErrorCode::VerificationError, "MIR stack slot is a tombstone");
- if (Description->IsDead || Description->AddressTaken || !Description->Lifetime.empty() ||
- Description->TargetFlags != 0) {
- return makeUnexpected(ErrorCode::Unsupported,
- "stack object contains state not represented by fixed LLVM MIR");
- }
-
- std::string_view Type;
- switch (Description->Kind) {
- case StackObjectKind::Default:
- case StackObjectKind::FixedABI:
- Type = "default";
- break;
- case StackObjectKind::FixedSpillSlot:
- case StackObjectKind::SpillSlot:
- Type = "spill-slot";
- break;
- case StackObjectKind::VariableSized:
- Type = "variable-sized";
- break;
- case StackObjectKind::DynamicAlloca:
- case StackObjectKind::CalleeSaved:
- case StackObjectKind::EmergencySpill:
- case StackObjectKind::Target:
- case StackObjectKind::Count:
- return makeUnexpected(ErrorCode::Unsupported,
- "stack object kind has no fixed LLVM MIR representation");
- }
-
- Output.append(" - { id: ");
- Output.append(std::to_string(Slot.TextID));
- if (!Fixed && Description->AllocaName) {
- Output.append(", name: ");
- Output.append(yamlScalar(*Description->AllocaName));
- }
- if (Options.Mode == MIPrintMode::Complete || Type != "default") {
- Output.append(", type: ");
- Output.append(Type);
- }
- if (Options.Mode == MIPrintMode::Complete || Description->Offset.value_or(0) != 0) {
- Output.append(", offset: ");
- Output.append(std::to_string(Description->Offset.value_or(0)));
- }
- if (Description->Kind != StackObjectKind::VariableSized) {
- Output.append(", size: ");
- Output.append(std::to_string(Description->Size.value_or(0)));
- }
- if (Options.Mode == MIPrintMode::Complete || Description->Align.bytes() != 1) {
- Output.append(", alignment: ");
- Output.append(std::to_string(Description->Align.bytes()));
- }
- if (Options.Mode == MIPrintMode::Complete || Description->Stack != StackID::defaultStack()) {
- Output.append(", stack-id: ");
- Output.append(getStackIDName(Description->Stack));
- }
- if (Fixed && Description->Kind != StackObjectKind::FixedSpillSlot) {
- if (Options.Mode == MIPrintMode::Complete || Description->IsImmutable)
- Output.append(Description->IsImmutable ? ", isImmutable: true" : ", isImmutable: false");
- if (Options.Mode == MIPrintMode::Complete || Description->IsAliased)
- Output.append(Description->IsAliased ? ", isAliased: true" : ", isAliased: false");
- } else if (!Fixed && (Description->IsImmutable || Description->IsAliased)) {
- return makeUnexpected(ErrorCode::Unsupported,
- "ordinary stack object immutable/aliased state is not serialized");
- }
- if (Description->CalleeSavedRegister) {
- auto Name = physicalRegister(*Description->CalleeSavedRegister);
- if (!Name)
- return std::unexpected(Name.error());
- Output.append(", callee-saved-register: ");
- Output.append(yamlScalar(*Name));
- }
- if (Options.Mode == MIPrintMode::Complete || !Description->CalleeSavedRestored) {
- Output.append(Description->CalleeSavedRestored ? ", callee-saved-restored: true"
- : ", callee-saved-restored: false");
- }
- if (!Fixed && Description->LocalOffset) {
- Output.append(", local-offset: ");
- Output.append(std::to_string(*Description->LocalOffset));
- }
- if (Description->DebugInfo) {
- const MachineVariableDebugInfo &Debug = *Description->DebugInfo;
- if (Debug.Variable) {
- auto Value = metadataReference(*Debug.Variable, Context);
- if (!Value)
- return std::unexpected(Value.error());
- Output.append(", debug-info-variable: ");
- Output.append(yamlScalar(*Value));
- }
- if (Debug.Expression) {
- auto Value = metadataValue(*Debug.Expression, Context);
- if (!Value)
- return std::unexpected(Value.error());
- Output.append(", debug-info-expression: ");
- Output.append(yamlScalar(*Value));
- }
- if (Debug.Location) {
- auto Value = debugLocation(*Debug.Location, Context);
- if (!Value)
- return std::unexpected(Value.error());
- Output.append(", debug-info-location: ");
- Output.append(yamlScalar(*Value));
- }
- }
- Output.append(" }\n");
- }
- return {};
-}
-
-Expected<void> MIRDocumentPrinter::printConstants(const MachineFunction &Function,
- const MIParserContext &Context) {
- if (Context.ConstantPoolItems.empty()) {
- if (Options.Mode == MIPrintMode::Complete)
- Output.append("constants: []\n");
- return {};
- }
- Output.append("constants:\n");
- for (const MIConstantPoolSlot &Slot : Context.ConstantPoolItems) {
- const MachineConstantPoolEntry *Entry = Function.constantPool().entry(Slot.Index);
- const MachineConstantPoolEntryDesc *Description =
- Entry == nullptr ? nullptr : Entry->description();
- if (Description == nullptr)
- return makeUnexpected(ErrorCode::VerificationError, "constant-pool slot is a tombstone");
- if (Description->Merge != ConstantPoolMergeKind::Never ||
- Description->Relocation != ConstantPoolRelocationMode::None ||
- Description->Placement != ConstantPoolPlacement{}) {
- return makeUnexpected(ErrorCode::Unsupported,
- "constant-pool placement state is not represented by fixed LLVM MIR");
- }
-
- bool IsTargetSpecific = false;
- Expected<std::string> Value =
- makeUnexpected(ErrorCode::Unsupported, "constant-pool kind is not MIR serializable");
- if (const auto *Generic = std::get_if<GenericConstantData>(&Description->Value)) {
- Value = printLLVMConstant(*Generic);
- } else if (const auto *TargetConstantValue = std::get_if<TargetConstant>(&Description->Value)) {
- IsTargetSpecific = true;
- Value = Target.mirText().printTargetConstant(*TargetConstantValue);
- }
- if (!Value)
- return std::unexpected(Value.error());
-
- Output.append(" - id: ");
- Output.append(std::to_string(Slot.TextID));
- Output.append("\n value: ");
- Output.append(yamlScalar(*Value));
- Output.append("\n alignment: ");
- Output.append(std::to_string(Description->Align.bytes()));
- Output.push_back('\n');
- if (IsTargetSpecific)
- Output.append(" isTargetSpecific: true\n");
- }
- return {};
-}
-
-Expected<void> MIRDocumentPrinter::printJumpTable(const MachineFunction &Function,
- const MIParserContext &Context) {
- if (Context.JumpTables.empty())
- return {};
- const MachineJumpTableEntry *FirstEntry =
- Function.jumpTableInfo().table(Context.JumpTables.front().Index);
- const MachineJumpTableDesc *First = FirstEntry == nullptr ? nullptr : FirstEntry->description();
- if (First == nullptr)
- return makeUnexpected(ErrorCode::VerificationError, "jump-table slot is not defined");
-
- std::string_view Kind;
- std::uint8_t ExpectedSize = 8;
- switch (First->Encoding) {
- case JumpTableEntryEncoding::BlockAddress:
- Kind = "block-address";
- break;
- case JumpTableEntryEncoding::GPRelative64BlockAddress:
- Kind = "gp-rel64-block-address";
- break;
- case JumpTableEntryEncoding::GPRelative32BlockAddress:
- Kind = "gp-rel32-block-address";
- ExpectedSize = 4;
- break;
- case JumpTableEntryEncoding::LabelDifference32:
- Kind = "label-difference32";
- ExpectedSize = 4;
- break;
- case JumpTableEntryEncoding::LabelDifference64:
- Kind = "label-difference64";
- break;
- case JumpTableEntryEncoding::Inline:
- Kind = "inline";
- ExpectedSize = 4;
- break;
- case JumpTableEntryEncoding::Custom32:
- Kind = "custom32";
- ExpectedSize = 4;
- break;
- case JumpTableEntryEncoding::Target:
- case JumpTableEntryEncoding::Count:
- return makeUnexpected(ErrorCode::Unsupported,
- "target jump-table encoding has no fixed LLVM MIR spelling");
- }
-
- Output.append("jumpTable:\n kind: ");
- Output.append(Kind);
- Output.append("\n entries:\n");
- for (const MIJumpTableSlot &Slot : Context.JumpTables) {
- const MachineJumpTableEntry *Entry = Function.jumpTableInfo().table(Slot.Index);
- const MachineJumpTableDesc *Description = Entry == nullptr ? nullptr : Entry->description();
- if (Description == nullptr)
- return makeUnexpected(ErrorCode::VerificationError, "jump-table slot is not defined");
- if (Description->Encoding != First->Encoding || Description->EntrySize != ExpectedSize ||
- Description->Align.bytes() != ExpectedSize ||
- Description->Placement != JumpTablePlacement{} || Description->TargetEncoding != 0) {
- return makeUnexpected(ErrorCode::Unsupported,
- "jump-table entries cannot share one fixed LLVM MIR kind");
- }
- Output.append(" - { id: ");
- Output.append(std::to_string(Slot.TextID));
- Output.append(", blocks: [ ");
- for (std::size_t Index = 0; Index < Description->Targets.size(); ++Index) {
- if (Index != 0)
- Output.append(", ");
- if (Description->Targets[Index] == nullptr)
- return makeUnexpected(ErrorCode::VerificationError,
- "jump-table entry contains a null block");
- auto Block = blockReference(Function, Description->Targets[Index]->stableID());
- if (!Block)
- return std::unexpected(Block.error());
- Output.append(yamlScalar(*Block));
- }
- Output.append(" ] }\n");
- }
- return {};
-}
-
-Expected<void> MIRDocumentPrinter::printMetadata(const MachineFunction &Function,
- const MIParserContext &Context) {
- if (Function.metadata().nodes().empty())
- return {};
- Output.append("machineMetadataNodes:\n");
- for (const MachineMetadataNode &Node : Function.metadata().nodes()) {
- auto NodeReference =
- metadataReference(MachineMetadataReference::machineFunction(Node.Slot), Context);
- if (!NodeReference)
- return std::unexpected(NodeReference.error());
- std::string Text = *NodeReference + " = ";
- if (Node.IsDistinct)
- Text.append("distinct ");
- Text.append("!{");
- for (std::size_t Index = 0; Index < Node.Elements.size(); ++Index) {
- if (Index != 0)
- Text.append(", ");
- const MachineMetadataElement &Element = Node.Elements[Index];
- if (Element.isNull()) {
- Text.append("null");
- } else if (const MachineMetadataReference *Reference = Element.reference()) {
- auto Printed = metadataReference(*Reference, Context);
- if (!Printed)
- return std::unexpected(Printed.error());
- Text.append(*Printed);
- } else if (const std::string *String = Element.string()) {
- Text.append("!\"");
- for (const char Character : *String) {
- if (Character == '\\' || Character == '"')
- Text.push_back('\\');
- Text.push_back(Character);
- }
- Text.push_back('"');
- } else {
- return makeUnexpected(ErrorCode::VerificationError,
- "machine metadata tuple contains an invalid element");
- }
- }
- Text.push_back('}');
- Output.append(" - ");
- Output.append(yamlScalar(Text));
- Output.push_back('\n');
- }
- return {};
-}
-
-Expected<void> MIRDocumentPrinter::printTargetState(const MachineFunction &Function) {
- if (!Function.targetState().hasValue())
- return {};
- auto Node = Target.mirText().printFunctionState(Function.targetState());
- if (!Node)
- return std::unexpected(Node.error());
- auto Text = targetNode(*Node);
- if (!Text)
- return std::unexpected(Text.error());
- Output.append("machineFunctionInfo: ");
- Output.append(*Text);
- Output.push_back('\n');
- return {};
-}
-
-Expected<void> MIRDocumentPrinter::printFunctionRecords(const MachineFunction &Function,
- const MIParserContext &Context) {
- const MachineFunctionRecords &Records = Function.records();
- if (!Records.entryValues().empty()) {
- Output.append("entry_values:\n");
- for (const MachineEntryValueInfo &Entry : Records.entryValues()) {
- auto RegisterName = physicalRegister(Entry.Reg);
- if (!RegisterName)
- return std::unexpected(RegisterName.error());
- if (!Entry.DebugInfo.Variable || !Entry.DebugInfo.Expression || !Entry.DebugInfo.Location) {
- return makeUnexpected(ErrorCode::Unsupported,
- "MIR entry value requires complete debug metadata");
- }
- auto Variable = metadataReference(*Entry.DebugInfo.Variable, Context);
- auto Expression = metadataValue(*Entry.DebugInfo.Expression, Context);
- auto Location = debugLocation(*Entry.DebugInfo.Location, Context);
- if (!Variable)
- return std::unexpected(Variable.error());
- if (!Expression)
- return std::unexpected(Expression.error());
- if (!Location)
- return std::unexpected(Location.error());
- Output.append(" - { entry-value-register: ");
- Output.append(yamlScalar(*RegisterName));
- Output.append(", debug-info-variable: ");
- Output.append(yamlScalar(*Variable));
- Output.append(", debug-info-expression: ");
- Output.append(yamlScalar(*Expression));
- Output.append(", debug-info-location: ");
- Output.append(yamlScalar(*Location));
- Output.append(" }\n");
- }
- } else if (Options.Mode == MIPrintMode::Complete) {
- Output.append("entry_values: []\n");
- }
-
- if (!Records.callSites().empty()) {
- Output.append("callSites:\n");
- for (const MachineCallSiteInfo &CallSite : Records.callSites()) {
- auto Location = instructionLocation(Function, CallSite.CallInstruction);
- if (!Location)
- return std::unexpected(Location.error());
- Output.append(" - { bb: ");
- Output.append(std::to_string(Location->Block));
- Output.append(", offset: ");
- Output.append(std::to_string(Location->Offset));
- if (!CallSite.ForwardedArguments.empty()) {
- Output.append(", fwdArgRegs: [ ");
- for (std::size_t Index = 0; Index < CallSite.ForwardedArguments.size(); ++Index) {
- if (Index != 0)
- Output.append(", ");
- const MachineCallSiteArgument &Argument = CallSite.ForwardedArguments[Index];
- auto RegisterName = physicalRegister(Argument.Reg);
- if (!RegisterName)
- return std::unexpected(RegisterName.error());
- Output.append("{ arg: ");
- Output.append(std::to_string(Argument.ArgumentNumber));
- Output.append(", reg: ");
- Output.append(yamlScalar(*RegisterName));
- Output.append(" }");
- }
- Output.append(" ]");
- }
- if (!CallSite.CalleeTypeIDs.empty()) {
- Output.append(", calleeTypeIds: [ ");
- for (std::size_t Index = 0; Index < CallSite.CalleeTypeIDs.size(); ++Index) {
- if (Index != 0)
- Output.append(", ");
- Output.append(std::to_string(CallSite.CalleeTypeIDs[Index]));
- }
- Output.append(" ]");
- }
- Output.append(" }\n");
- }
- } else if (Options.Mode == MIPrintMode::Complete) {
- Output.append("callSites: []\n");
- }
-
- if (!Records.debugValueSubstitutions().empty()) {
- Output.append("debugValueSubstitutions:\n");
- for (const MachineDebugValueSubstitution &Substitution : Records.debugValueSubstitutions()) {
- Output.append(" - { srcinst: ");
- Output.append(std::to_string(Substitution.Source.InstructionNumber));
- Output.append(", srcop: ");
- Output.append(std::to_string(Substitution.Source.OperandNumber));
- Output.append(", dstinst: ");
- Output.append(std::to_string(Substitution.Destination.InstructionNumber));
- Output.append(", dstop: ");
- Output.append(std::to_string(Substitution.Destination.OperandNumber));
- Output.append(", subreg: ");
- Output.append(std::to_string(Substitution.Subregister.value()));
- Output.append(" }\n");
- }
- } else if (Options.Mode == MIPrintMode::Complete) {
- Output.append("debugValueSubstitutions: []\n");
- }
-
- if (!Records.calledGlobals().empty()) {
- Output.append("calledGlobals:\n");
- for (const MachineCalledGlobal &Called : Records.calledGlobals()) {
- auto Location = instructionLocation(Function, Called.CallInstruction);
- if (!Location)
- return std::unexpected(Location.error());
- Output.append(" - { bb: ");
- Output.append(std::to_string(Location->Block));
- Output.append(", offset: ");
- Output.append(std::to_string(Location->Offset));
- Output.append(", callee: ");
- Output.append(yamlScalar(Called.Callee));
- Output.append(", flags: ");
- Output.append(std::to_string(Called.Flags));
- Output.append(" }\n");
- }
- }
-
- if (!Records.prefetchTargets().empty()) {
- Output.append("prefetch-targets: [ ");
- const auto Targets = Records.prefetchTargets();
- for (std::size_t Index = 0; Index < Targets.size(); ++Index) {
- if (Index != 0)
- Output.append(", ");
- const MachinePrefetchTarget &TargetValue = Targets[Index];
- std::string Text = "bb_id " + std::to_string(TargetValue.Block.BaseID) + ", " +
- std::to_string(TargetValue.Block.CloneID) + ", " +
- std::to_string(TargetValue.CallsiteIndex);
- Output.append(yamlScalar(Text));
- }
- Output.append(" ]\n");
- }
- return {};
-}
-
-Expected<void> MIRDocumentPrinter::printFunction(const MachineFunction &Function,
- const MIRFunctionDocumentInfo *) {
- if (Function.compilationStatus().state() != MachineCompilationState::Success) {
- return makeUnexpected(ErrorCode::Unsupported,
- "fixed LLVM MIR cannot serialize this compilation failure state");
- }
- auto Context = createBodyContext(Function);
- if (!Context)
- return std::unexpected(Context.error());
-
- Output.append("---\nname: ");
- Output.append(yamlScalar(Function.name()));
- Output.push_back('\n');
- const auto Alignment = Function.attributes().alignment();
- if (Options.Mode == MIPrintMode::Complete || Alignment) {
- Output.append("alignment: ");
- Output.append(std::to_string(Alignment ? Alignment->bytes() : 1U));
- Output.push_back('\n');
- }
-
- const MachineFunctionProperties &Properties = Function.properties();
- const MachineFunctionAttributes &Attributes = Function.attributes();
- printBoolean("exposesReturnsTwice",
- Attributes.has(MachineFunctionAttribute::ExposesReturnsTwice));
- printBoolean("legalized", Properties.has(MachineFunctionProperty::Legalized));
- printBoolean("regBankSelected", Properties.has(MachineFunctionProperty::RegBankSelected));
- printBoolean("selected", Properties.has(MachineFunctionProperty::Selected));
- printBoolean("failedISel", Properties.has(MachineFunctionProperty::FailedISel));
- printBoolean("tracksRegLiveness", Properties.has(MachineFunctionProperty::TracksLiveness));
- printBoolean("hasWinCFI", Attributes.has(MachineFunctionAttribute::HasWinCFI));
- printBoolean("noPhis", Properties.has(MachineFunctionProperty::NoPHIs), true);
- printBoolean("isSSA", Properties.has(MachineFunctionProperty::IsSSA), true);
- printBoolean("noVRegs", Properties.has(MachineFunctionProperty::NoVRegs), true);
- printBoolean("hasFakeUses", Attributes.has(MachineFunctionAttribute::HasFakeUses), true);
- printBoolean("callsEHReturn", Attributes.has(MachineFunctionAttribute::CallsEHReturn));
- printBoolean("callsUnwindInit", Attributes.has(MachineFunctionAttribute::CallsUnwindInit));
- printBoolean("hasEHContTarget", Attributes.has(MachineFunctionAttribute::HasEHContTarget));
- printBoolean("hasEHScopes", Attributes.has(MachineFunctionAttribute::HasEHScopes));
- printBoolean("hasEHFunclets", Attributes.has(MachineFunctionAttribute::HasEHFunclets));
- printBoolean("isOutlined", Attributes.has(MachineFunctionAttribute::IsOutlined));
- printBoolean("debugInstrRef", Attributes.has(MachineFunctionAttribute::DebugInstrRef));
- printBoolean("failsVerification", Properties.has(MachineFunctionProperty::FailsVerification));
- printBoolean("tracksDebugUserValues",
- Attributes.has(MachineFunctionAttribute::TracksDebugUserValues));
-
- if (auto Printed = printRegisters(Function, *Context); !Printed)
- return Printed;
- if (auto Printed = printFrameInfo(Function, *Context); !Printed)
- return Printed;
- if (auto Printed = printStackObjects(Function, *Context, true); !Printed)
- return Printed;
- if (auto Printed = printStackObjects(Function, *Context, false); !Printed)
- return Printed;
- if (auto Printed = printFunctionRecords(Function, *Context); !Printed)
- return Printed;
- if (auto Printed = printConstants(Function, *Context); !Printed)
- return Printed;
- if (auto Printed = printTargetState(Function); !Printed)
- return Printed;
- if (auto Printed = printJumpTable(Function, *Context); !Printed)
- return Printed;
- if (auto Printed = printMetadata(Function, *Context); !Printed)
- return Printed;
-
- auto Body =
- printMachineFunctionBody(Function, Target, *Context, MIPrinterOptions{.Mode = Options.Mode});
- if (!Body)
- return std::unexpected(Body.error());
- Output.append("body: |\n");
- appendBlockScalar(Output, *Body, 2);
- Output.append("...\n");
- return {};
-}
-
-Expected<std::string> MIRDocumentPrinter::run() {
- auto UnitVerification = Document.unit().verify();
- if (!UnitVerification)
- return std::unexpected(UnitVerification.error());
- if (Document.unit().functionCount() == 0) {
- return makeUnexpected(ErrorCode::InvalidArgument,
- "MIR document must contain at least one machine function");
- }
-
- for (const MIRFunctionDocumentInfo &Info : Document.functionDocumentInfo()) {
- if (Document.unit().function(Info.Function) == nullptr) {
- return makeUnexpected(ErrorCode::VerificationError,
- "MIR document info references an unknown machine function");
- }
- }
-
- for (std::size_t Index = 0; Index < Document.unit().functionCount(); ++Index) {
- const MachineFunction *Function = Document.unit().functionAt(Index);
- if (Function == nullptr) {
- return makeUnexpected(ErrorCode::VerificationError,
- "compilation unit contains a null machine function");
- }
- auto ReferenceVerification =
- verifyMIRDocumentReferences(Document, *Function, Options.EmitEmbeddedIR);
- if (!ReferenceVerification)
- return std::unexpected(ReferenceVerification.error());
- auto LayoutVerification = verifyOmittedEmbeddedIRLayout(*Function);
- if (!LayoutVerification)
- return std::unexpected(LayoutVerification.error());
- }
-
- if (Options.EmitEmbeddedIR && Document.embeddedIR() != nullptr) {
- Output.append("--- |\n");
- appendBlockScalar(Output, Document.embeddedIR()->source().text(), 2);
- Output.append("...\n");
- }
- for (std::size_t Index = 0; Index < Document.unit().functionCount(); ++Index) {
- const MachineFunction *Function = Document.unit().functionAt(Index);
- if (Function == nullptr)
- return makeUnexpected(ErrorCode::VerificationError,
- "compilation unit contains a null machine function");
- if (auto Printed = printFunction(*Function, documentInfo(*Function)); !Printed)
- return std::unexpected(Printed.error());
- }
- return std::move(Output);
-}
-
-} // namespace
-
-Expected<std::string> printMIRDocument(const MIRDocument &Document, const TargetDescription &Target,
- MIRDocumentPrinterOptions Options) {
- return MIRDocumentPrinter(Document, Target, std::move(Options)).run();
-}
-
-} // namespace rcc::mir
diff --git a/backend/lib/MIR/MIRDocumentReferenceValidation.cpp b/backend/lib/MIR/MIRDocumentReferenceValidation.cpp
deleted file mode 100644
index 69b0dd1..0000000
--- a/backend/lib/MIR/MIRDocumentReferenceValidation.cpp
+++ /dev/null
@@ -1,426 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include "MIRDocumentReferenceValidation.h"
-
-#include "rcc/CodeGen/MachineBasicBlock.h"
-#include "rcc/CodeGen/MachineConstantPool.h"
-#include "rcc/CodeGen/MachineFrameInfo.h"
-#include "rcc/CodeGen/MachineFunction.h"
-#include "rcc/CodeGen/MachineFunctionRecords.h"
-#include "rcc/CodeGen/MachineInstr.h"
-#include "rcc/CodeGen/MachineMetadata.h"
-#include "rcc/MIR/MIRDocument.h"
-
-#include <algorithm>
-#include <array>
-#include <initializer_list>
-#include <optional>
-#include <ranges>
-#include <string>
-#include <string_view>
-#include <variant>
-
-namespace rcc::mir {
-
-Expected<void> verifyMIRDocumentReferences(const MIRDocument &Document,
- const MachineFunction &Function, bool UseEmbeddedIR) {
- const EmbeddedIRReferenceIndex *Embedded = UseEmbeddedIR ? Document.embeddedIR() : nullptr;
- const EmbeddedIRFunction *IRFunction = nullptr;
- if (Embedded != nullptr) {
- if (Function.name().empty()) {
- std::size_t AnonymousOrdinal = 0;
- bool FoundFunction = false;
- for (std::size_t Index = 0; Index < Document.unit().functionCount(); ++Index) {
- const MachineFunction *Candidate = Document.unit().functionAt(Index);
- if (Candidate == &Function) {
- FoundFunction = true;
- break;
- }
- if (Candidate != nullptr && Candidate->name().empty())
- ++AnonymousOrdinal;
- }
- if (FoundFunction)
- IRFunction = Embedded->unnamedFunction(AnonymousOrdinal);
- } else {
- IRFunction = Embedded->function(Function.name());
- }
- if (IRFunction == nullptr) {
- return makeUnexpected(ErrorCode::VerificationError,
- "machine function has no matching embedded LLVM IR function");
- }
- }
-
- const auto ValidateGlobal = [Embedded](std::string_view Name,
- std::string_view Description) -> Expected<void> {
- if (Embedded == nullptr) {
- return makeUnexpected(ErrorCode::VerificationError,
- std::string(Description) +
- " requires embedded LLVM IR to resolve global '" +
- std::string(Name) + "'");
- }
- if (Embedded->hasGlobalValue(Name))
- return {};
- return makeUnexpected(ErrorCode::VerificationError,
- std::string(Description) +
- " references an undefined embedded LLVM IR global '" +
- std::string(Name) + "'");
- };
- const auto ValidateBlockAddress = [Embedded](std::string_view FunctionName,
- std::string_view BlockName,
- std::string_view Description) -> Expected<void> {
- if (Embedded == nullptr) {
- return makeUnexpected(ErrorCode::VerificationError,
- std::string(Description) +
- " requires embedded LLVM IR to resolve a block address");
- }
- const EmbeddedIRFunction *AddressFunction = Embedded->function(FunctionName);
- if (AddressFunction == nullptr) {
- return makeUnexpected(ErrorCode::VerificationError,
- std::string(Description) +
- " references an undefined embedded LLVM IR function '" +
- std::string(FunctionName) + "'");
- }
- if (AddressFunction->block(BlockName) == nullptr) {
- return makeUnexpected(
- ErrorCode::VerificationError,
- std::string(Description) + " references an undefined embedded LLVM IR block '" +
- std::string(BlockName) + "' in function '" + std::string(FunctionName) + "'");
- }
- return {};
- };
- const auto ValidateIRValue = [IRFunction](std::string_view Name,
- std::string_view Description) -> Expected<void> {
- if (IRFunction == nullptr) {
- return makeUnexpected(ErrorCode::VerificationError,
- std::string(Description) +
- " requires embedded LLVM IR to resolve IR value '%" +
- std::string(Name) + "'");
- }
- if (IRFunction->value(Name) != nullptr)
- return {};
- return makeUnexpected(ErrorCode::VerificationError,
- std::string(Description) +
- " references an undefined embedded LLVM IR value '%" +
- std::string(Name) + "'");
- };
- const auto ValidateMetadata = [Embedded](MachineMetadataReference Reference,
- std::initializer_list<std::string_view> ExpectedTypes,
- std::string_view Description) -> Expected<void> {
- if (!Reference.isValid()) {
- return makeUnexpected(ErrorCode::VerificationError,
- std::string(Description) + " has an invalid metadata reference");
- }
- if (Reference.scope() != MachineMetadataScope::EmbeddedIR)
- return {};
- if (Embedded == nullptr) {
- return makeUnexpected(ErrorCode::VerificationError,
- std::string(Description) + " requires embedded LLVM IR metadata !" +
- std::to_string(Reference.slot()));
- }
- const EmbeddedIRMetadataDefinition *Definition =
- Embedded->metadata(std::to_string(Reference.slot()));
- if (Definition == nullptr) {
- return makeUnexpected(ErrorCode::VerificationError,
- std::string(Description) +
- " references undefined embedded LLVM IR metadata !" +
- std::to_string(Reference.slot()));
- }
- if (ExpectedTypes.size() == 0 ||
- std::ranges::find(ExpectedTypes, Definition->DynamicType) != ExpectedTypes.end()) {
- return {};
- }
- std::string Expected;
- for (const std::string_view Type : ExpectedTypes) {
- if (!Expected.empty())
- Expected.append(" or ");
- Expected.append(Type);
- }
- return makeUnexpected(ErrorCode::VerificationError,
- std::string(Description) + " requires " + Expected + " metadata, but !" +
- std::to_string(Reference.slot()) + " is " +
- (Definition->DynamicType.empty()
- ? std::string("an unclassified metadata node")
- : Definition->DynamicType));
- };
- const auto ValidateMetadataValue =
- [&ValidateMetadata](const MachineMetadataValue &Value,
- std::string_view Description) -> Expected<void> {
- const MachineMetadataReference *Reference = Value.reference();
- return Reference == nullptr ? Expected<void>{} : ValidateMetadata(*Reference, {}, Description);
- };
- const auto ValidateLocation =
- [&ValidateMetadata](const MachineDebugLocation &Location,
- std::string_view Description) -> Expected<void> {
- if (const MachineMetadataReference *Reference = Location.reference())
- return ValidateMetadata(*Reference, {"DILocation"}, Description);
- const MachineDILocation *Inline = Location.inlineLocation();
- if (Inline == nullptr)
- return {};
- for (const MachineDILocationFrame &Frame : Inline->inlineChain()) {
- auto Verification =
- ValidateMetadata(Frame.Scope, {"DISubprogram", "DILexicalBlock", "DILexicalBlockFile"},
- "inline DILocation scope");
- if (!Verification)
- return Verification;
- }
- if (Inline->terminalInlinedAt()) {
- return ValidateMetadata(*Inline->terminalInlinedAt(), {"DILocation"},
- "inline DILocation inlinedAt");
- }
- return {};
- };
- const auto ValidateVariableDebugInfo =
- [&ValidateMetadata, &ValidateMetadataValue,
- &ValidateLocation](const MachineVariableDebugInfo &DebugInfo) -> Expected<void> {
- if (DebugInfo.Variable) {
- auto Verification =
- ValidateMetadata(*DebugInfo.Variable, {"DILocalVariable"}, "debug variable");
- if (!Verification)
- return Verification;
- }
- if (DebugInfo.Expression) {
- if (const MachineMetadataReference *Reference = DebugInfo.Expression->reference();
- Reference != nullptr) {
- auto Verification = ValidateMetadata(*Reference, {"DIExpression"}, "debug expression");
- if (!Verification)
- return Verification;
- }
- auto Verification = ValidateMetadataValue(*DebugInfo.Expression, "debug expression");
- if (!Verification)
- return Verification;
- }
- if (DebugInfo.Location)
- return ValidateLocation(*DebugInfo.Location, "debug location");
- return {};
- };
- const auto ValidateGenericType = [Embedded](const auto &Self,
- const GenericConstantType &Type) -> Expected<void> {
- if (Type.Kind == GenericConstantTypeKind::Named) {
- if (Embedded == nullptr) {
- return makeUnexpected(
- ErrorCode::VerificationError,
- "generic constant type requires embedded LLVM IR to resolve named type '%" + Type.Name +
- "'");
- }
- if (Embedded->typeDefinition(Type.Name) == nullptr) {
- return makeUnexpected(
- ErrorCode::VerificationError,
- "generic constant type references an undefined embedded LLVM IR named type '%" +
- Type.Name + "'");
- }
- }
- for (const GenericConstantType &Element : Type.Elements) {
- auto Verification = Self(Self, Element);
- if (!Verification)
- return Verification;
- }
- return {};
- };
- const auto ValidateGenericConstant =
- [&ValidateBlockAddress, &ValidateGenericType,
- &ValidateGlobal](const auto &Self, const GenericConstantData &Constant) -> Expected<void> {
- auto TypeVerification = ValidateGenericType(ValidateGenericType, Constant.Type);
- if (!TypeVerification)
- return TypeVerification;
- if (Constant.SourceElementType) {
- TypeVerification = ValidateGenericType(ValidateGenericType, *Constant.SourceElementType);
- if (!TypeVerification)
- return TypeVerification;
- }
- switch (Constant.Kind) {
- case GenericConstantKind::GlobalAddress:
- case GenericConstantKind::DSOLocalEquivalent:
- case GenericConstantKind::NoCFI:
- if (auto Verification = ValidateGlobal(Constant.Symbol, "generic constant"); !Verification)
- return Verification;
- break;
- case GenericConstantKind::BlockAddress:
- if (auto Verification = ValidateBlockAddress(Constant.Symbol, Constant.Block,
- "generic constant blockaddress");
- !Verification) {
- return Verification;
- }
- break;
- default:
- break;
- }
- for (const GenericConstantData &Element : Constant.Elements) {
- auto Verification = Self(Self, Element);
- if (!Verification)
- return Verification;
- }
- return {};
- };
-
- for (const MachineBasicBlock *Block = Function.firstBlock(); Block != nullptr;
- Block = Block->next()) {
- if (const auto Name = Block->attributes().irBlockName(); Name) {
- if (IRFunction == nullptr) {
- return makeUnexpected(ErrorCode::VerificationError,
- "machine basic block requires embedded LLVM IR to resolve block '" +
- std::string(*Name) + "'");
- }
- if (IRFunction->block(*Name) == nullptr) {
- return makeUnexpected(
- ErrorCode::VerificationError,
- "machine basic block references an undefined embedded LLVM IR block '" +
- std::string(*Name) + "'");
- }
- }
- }
- for (const StackObject &Object : Function.frameInfo().objects()) {
- const StackObjectDesc *Description = Object.description();
- if (Description == nullptr || !Description->AllocaName)
- continue;
- if (IRFunction == nullptr) {
- return makeUnexpected(ErrorCode::VerificationError,
- "stack object requires embedded LLVM IR to resolve alloca '" +
- *Description->AllocaName + "'");
- }
- if (IRFunction->alloca(*Description->AllocaName) == nullptr) {
- return makeUnexpected(ErrorCode::VerificationError,
- "stack object references an undefined embedded LLVM IR alloca '" +
- *Description->AllocaName + "'");
- }
- }
-
- for (const MachineConstantPoolEntry &Entry : Function.constantPool().entries()) {
- const MachineConstantPoolEntryDesc *Description = Entry.description();
- if (Description == nullptr)
- continue;
- if (const auto *Generic = std::get_if<GenericConstantData>(&Description->Value)) {
- auto Verification = ValidateGenericConstant(ValidateGenericConstant, *Generic);
- if (!Verification)
- return Verification;
- } else if (const auto *Address = std::get_if<BlockAddressConstant>(&Description->Value)) {
- auto Verification = ValidateBlockAddress(Address->FunctionName, Address->BlockName,
- "constant-pool block address");
- if (!Verification)
- return Verification;
- }
- }
-
- for (const MachineMetadataNode &Node : Function.metadata().nodes()) {
- for (const MachineMetadataElement &Element : Node.Elements) {
- const MachineMetadataReference *Reference = Element.reference();
- if (Reference == nullptr)
- continue;
- auto Verification = ValidateMetadata(*Reference, {}, "machine metadata node");
- if (!Verification)
- return Verification;
- }
- }
-
- for (const StackObject &Object : Function.frameInfo().objects()) {
- const StackObjectDesc *Description = Object.description();
- if (Description == nullptr || !Description->DebugInfo)
- continue;
- auto Verification = ValidateVariableDebugInfo(*Description->DebugInfo);
- if (!Verification)
- return Verification;
- }
- for (const MachineEntryValueInfo &Entry : Function.records().entryValues()) {
- auto Verification = ValidateVariableDebugInfo(Entry.DebugInfo);
- if (!Verification)
- return Verification;
- }
- for (const MachineCalledGlobal &Called : Function.records().calledGlobals()) {
- auto Verification = ValidateGlobal(Called.Callee, "called-global record");
- if (!Verification)
- return Verification;
- }
-
- for (const MachineBasicBlock *Block = Function.firstBlock(); Block != nullptr;
- Block = Block->next()) {
- for (const MachineInstr *Instruction = Block->firstInstruction(); Instruction != nullptr;
- Instruction = Instruction->next()) {
- if (Instruction->debugLocation()) {
- auto Verification =
- ValidateLocation(*Instruction->debugLocation(), "instruction debug location");
- if (!Verification)
- return Verification;
- }
- const std::array InstructionMetadata{
- Instruction->heapAllocMarker(),
- Instruction->pcSections(),
- Instruction->mmra(),
- };
- for (const auto &Reference : InstructionMetadata) {
- if (!Reference)
- continue;
- auto Verification = ValidateMetadata(*Reference, {}, "instruction metadata attachment");
- if (!Verification)
- return Verification;
- }
-
- for (const MachineOperand &Operand : Instruction->operands()) {
- if (const auto *Global = Operand.getIf<GlobalSymbolOperand>(); Global != nullptr) {
- auto Verification = ValidateGlobal(Global->Name, "global-symbol operand");
- if (!Verification)
- return Verification;
- }
- if (const auto *Address = Operand.getIf<BlockAddressOperand>(); Address != nullptr) {
- auto Verification = ValidateBlockAddress(Address->FunctionName, Address->BlockName,
- "block-address operand");
- if (!Verification)
- return Verification;
- }
- if (const auto *Metadata = Operand.getIf<MetadataOperand>(); Metadata != nullptr) {
- auto Verification = ValidateMetadataValue(Metadata->Value, "metadata operand");
- if (!Verification)
- return Verification;
- }
- }
-
- for (const MachineMemOperand *Memory : Instruction->memOperands()) {
- const MachineMemOperandDesc &Description = Memory->description();
- const std::optional<std::string_view> BaseName = Description.Base.symbolName();
- switch (Description.Base.kind()) {
- case MemoryBase::Kind::GlobalSymbol:
- case MemoryBase::Kind::CallEntryGlobal:
- if (BaseName) {
- auto Verification = ValidateGlobal(*BaseName, "machine memory base");
- if (!Verification)
- return Verification;
- }
- break;
- case MemoryBase::Kind::IRValue:
- if (BaseName) {
- auto Verification = ValidateIRValue(*BaseName, "machine memory base");
- if (!Verification)
- return Verification;
- }
- break;
- default:
- break;
- }
- const std::array MetadataReferences{
- Description.TBAA, Description.AliasScope,
- Description.NoAlias, Description.NoAliasAddressSpace,
- Description.RangeMetadata,
- };
- for (const auto &Reference : MetadataReferences) {
- if (!Reference)
- continue;
- auto Verification = ValidateMetadata(*Reference, {}, "machine memory operand metadata");
- if (!Verification)
- return Verification;
- }
- if (Description.SyncScope.value() == 0)
- continue;
- const auto Scope =
- std::ranges::find_if(Document.syncScopes(), [&Description](const auto &Slot) {
- return Slot.ID == Description.SyncScope;
- });
- if (Scope == Document.syncScopes().end()) {
- return makeUnexpected(
- ErrorCode::VerificationError,
- "machine memory operand synchronization scope has no document name");
- }
- }
- }
- }
- return {};
-}
-
-} // namespace rcc::mir
diff --git a/backend/lib/MIR/MIRDocumentReferenceValidation.h b/backend/lib/MIR/MIRDocumentReferenceValidation.h
deleted file mode 100644
index 2ab6291..0000000
--- a/backend/lib/MIR/MIRDocumentReferenceValidation.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-// The private header has no stable include-root-relative guard name.
-// NOLINTNEXTLINE(llvm-header-guard)
-#ifndef RCC_LIB_MIR_MIRDOCUMENTREFERENCEVALIDATION_H
-#define RCC_LIB_MIR_MIRDOCUMENTREFERENCEVALIDATION_H
-
-#include "rcc/Support/Error.h"
-
-namespace rcc {
-
-class MachineFunction;
-
-namespace mir {
-
-class MIRDocument;
-
-[[nodiscard]] Expected<void> verifyMIRDocumentReferences(const MIRDocument &Document,
- const MachineFunction &Function,
- bool UseEmbeddedIR);
-
-} // namespace mir
-} // namespace rcc
-
-#endif // RCC_LIB_MIR_MIRDOCUMENTREFERENCEVALIDATION_H
diff --git a/backend/lib/MIR/MIRFrameParser.cpp b/backend/lib/MIR/MIRFrameParser.cpp
deleted file mode 100644
index 4367fbd..0000000
--- a/backend/lib/MIR/MIRFrameParser.cpp
+++ /dev/null
@@ -1,467 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include "MIRDocumentParser.h"
-#include "MIRDocumentReferenceValidation.h"
-#include "MIRMetadataTextParser.h"
-#include "MIRParserUtilities.h"
-#include "rcc/CodeGen/MachineBasicBlock.h"
-#include "rcc/CodeGen/MachineConstantPool.h"
-#include "rcc/CodeGen/MachineFrameInfo.h"
-#include "rcc/CodeGen/MachineFunction.h"
-#include "rcc/CodeGen/MachineFunctionAttributes.h"
-#include "rcc/CodeGen/MachineFunctionProperties.h"
-#include "rcc/CodeGen/MachineFunctionRecords.h"
-#include "rcc/CodeGen/MachineInstr.h"
-#include "rcc/CodeGen/MachineJumpTableInfo.h"
-#include "rcc/CodeGen/MachineMetadata.h"
-#include "rcc/CodeGen/MachineRegisterInfo.h"
-#include "rcc/CodeGen/MachineVerifier.h"
-#include "rcc/CodeGen/TargetDescription.h"
-#include "rcc/CodeGen/TargetMIRTextInfo.h"
-#include "rcc/CodeGen/TargetRegisterInfo.h"
-#include "rcc/MIR/LLVMConstantSyntax.h"
-
-#include <algorithm>
-#include <array>
-#include <cstddef>
-#include <cstdint>
-#include <initializer_list>
-#include <limits>
-#include <optional>
-#include <ranges>
-#include <span>
-#include <string>
-#include <string_view>
-#include <unordered_map>
-#include <unordered_set>
-#include <utility>
-#include <vector>
-
-namespace rcc::mir {
-
-using parser_detail::parseBool;
-using parser_detail::parsePrefixedID;
-using parser_detail::parseSigned;
-using parser_detail::parseUnsigned;
-using parser_detail::parseUnsigned32;
-using parser_detail::trim;
-
-bool MIRDocumentParser::parseStackObjects(const yaml::Node &Root, MachineFunction &Function,
- MIParserContext &Context) {
- auto ParseList = [this, &Function, &Context](const yaml::Node &List, bool Fixed) -> bool {
- if (requireKind(List, yaml::NodeKind::Sequence,
- Fixed ? "fixed stack objects" : "stack objects")) {
- return true;
- }
- constexpr std::array FixedKeys{
- std::string_view{"id"},
- std::string_view{"type"},
- std::string_view{"offset"},
- std::string_view{"size"},
- std::string_view{"alignment"},
- std::string_view{"stack-id"},
- std::string_view{"isImmutable"},
- std::string_view{"isAliased"},
- std::string_view{"callee-saved-register"},
- std::string_view{"callee-saved-restored"},
- std::string_view{"debug-info-variable"},
- std::string_view{"debug-info-expression"},
- std::string_view{"debug-info-location"},
- };
- constexpr std::array StackKeys{
- std::string_view{"id"},
- std::string_view{"name"},
- std::string_view{"type"},
- std::string_view{"offset"},
- std::string_view{"size"},
- std::string_view{"alignment"},
- std::string_view{"stack-id"},
- std::string_view{"callee-saved-register"},
- std::string_view{"callee-saved-restored"},
- std::string_view{"local-offset"},
- std::string_view{"debug-info-variable"},
- std::string_view{"debug-info-expression"},
- std::string_view{"debug-info-location"},
- };
- std::unordered_set<std::uint32_t> IDs;
- for (const yaml::NodeID ElementID : List.sequence()) {
- const yaml::Node *Element = node(ElementID);
- if (Element == nullptr || requireKind(*Element, yaml::NodeKind::Mapping, "stack object") ||
- (Fixed ? validateKeys(*Element, FixedKeys, "fixed stack object")
- : validateKeys(*Element, StackKeys, "stack object"))) {
- return true;
- }
- const yaml::Node *IDNode = mappingValue(*Element, "id");
- if (IDNode == nullptr)
- return fail(Element->range(), "stack object requires 'id'");
- std::uint64_t WideID = 0;
- if (unsignedValue(*IDNode, WideID, "a 32-bit stack object ID") ||
- WideID > std::numeric_limits<std::uint32_t>::max()) {
- return true;
- }
- const auto TextID = static_cast<std::uint32_t>(WideID);
- if (!IDs.insert(TextID).second)
- return fail(IDNode->range(), "duplicate stack object ID");
-
- StackObjectDesc Description;
- Description.Kind = Fixed ? StackObjectKind::FixedABI : StackObjectKind::Default;
- Description.Offset = 0;
- if (const yaml::Node *NameNode = mappingValue(*Element, "name")) {
- std::string_view Name;
- if (scalar(*NameNode, Name, "stack object name"))
- return true;
- if (!Name.empty())
- Description.AllocaName = std::string(Name);
- }
- if (const yaml::Node *TypeNode = mappingValue(*Element, "type")) {
- std::string_view Type;
- if (scalar(*TypeNode, Type, "stack object type"))
- return true;
- if (Type == "default")
- Description.Kind = Fixed ? StackObjectKind::FixedABI : StackObjectKind::Default;
- else if (Type == "spill-slot")
- Description.Kind = Fixed ? StackObjectKind::FixedSpillSlot : StackObjectKind::SpillSlot;
- else if (!Fixed && Type == "variable-sized")
- Description.Kind = StackObjectKind::VariableSized;
- else
- return fail(TypeNode->range(), "unknown stack object type '" + std::string(Type) + "'");
- }
- if (const yaml::Node *OffsetNode = mappingValue(*Element, "offset")) {
- std::int64_t Offset = 0;
- if (signedValue(*OffsetNode, Offset, "a signed stack object offset"))
- return true;
- Description.Offset = Offset;
- } else if (Fixed) {
- Description.Offset = 0;
- }
- if (Description.Kind != StackObjectKind::VariableSized) {
- const yaml::Node *SizeNode = mappingValue(*Element, "size");
- if (SizeNode == nullptr) {
- if (!Fixed)
- return fail(Element->range(), "fixed-size stack object requires 'size'");
- Description.Size = 0;
- } else {
- std::uint64_t Size = 0;
- if (unsignedValue(*SizeNode, Size, "an unsigned stack object size"))
- return true;
- Description.Size = Size;
- }
- }
- if (const yaml::Node *AlignmentNode = mappingValue(*Element, "alignment")) {
- if (alignment(*AlignmentNode, Description.Align, true))
- return true;
- }
- if (const yaml::Node *StackIDNode = mappingValue(*Element, "stack-id")) {
- std::string_view Name;
- if (scalar(*StackIDNode, Name, "stack ID"))
- return true;
- const auto Stack = parseStackIDName(Name);
- if (!Stack)
- return fail(StackIDNode->range(), "unknown stack ID '" + std::string(Name) + "'");
- Description.Stack = *Stack;
- }
- if (const yaml::Node *ImmutableNode = mappingValue(*Element, "isImmutable")) {
- if (boolean(*ImmutableNode, Description.IsImmutable))
- return true;
- }
- if (const yaml::Node *AliasedNode = mappingValue(*Element, "isAliased")) {
- if (boolean(*AliasedNode, Description.IsAliased))
- return true;
- }
- if (const yaml::Node *SavedNode = mappingValue(*Element, "callee-saved-register")) {
- std::string_view SavedName;
- if (scalar(*SavedNode, SavedName, "physical register"))
- return true;
- if (!trim(SavedName).empty()) {
- PhysicalRegister Reg;
- if (physicalRegister(SavedName, SavedNode->range(), Reg))
- return true;
- Description.CalleeSavedRegister = Reg;
- }
- }
- if (const yaml::Node *RestoredNode = mappingValue(*Element, "callee-saved-restored")) {
- if (boolean(*RestoredNode, Description.CalleeSavedRestored))
- return true;
- }
- if (const yaml::Node *LocalNode = mappingValue(*Element, "local-offset")) {
- std::int64_t Offset = 0;
- if (signedValue(*LocalNode, Offset, "a signed local frame offset"))
- return true;
- Description.LocalOffset = Offset;
- }
- MachineVariableDebugInfo DebugInfo;
- if (parseVariableDebugInfo(*Element, Function, DebugInfo))
- return true;
- if (DebugInfo.Variable || DebugInfo.Expression || DebugInfo.Location)
- Description.DebugInfo = std::move(DebugInfo);
-
- auto Created = Function.frameInfo().createObject(std::move(Description));
- if (!Created)
- return importError(Element->range(), Created.error());
- MIFrameObjectSlot Slot{
- .TextID = TextID,
- .Index = *Created,
- .Name = std::nullopt,
- };
- if (const StackObjectDesc *CreatedDescription =
- Function.frameInfo().object(*Created)->description();
- CreatedDescription != nullptr && CreatedDescription->AllocaName) {
- Slot.Name = *CreatedDescription->AllocaName;
- }
- (Fixed ? Context.FixedStackObjects : Context.StackObjects).push_back(std::move(Slot));
- }
- return false;
- };
-
- if (const yaml::Node *Fixed = mappingValue(Root, "fixedStack")) {
- if (ParseList(*Fixed, true))
- return true;
- }
- if (const yaml::Node *Stack = mappingValue(Root, "stack")) {
- if (ParseList(*Stack, false))
- return true;
- }
- return false;
-}
-
-bool MIRDocumentParser::parseFrameReference(const yaml::Node &Node, const MIParserContext &Context,
- FrameIndex &Index) {
- std::string_view Text;
- if (scalar(Node, Text, "frame index"))
- return true;
- bool Fixed = false;
- std::optional<std::uint32_t> ID = parsePrefixedID(Text, "%stack.");
- if (!ID) {
- ID = parsePrefixedID(Text, "%fixed-stack.");
- Fixed = true;
- }
- if (!ID)
- return fail(Node.range(), "frame index must use '%stack.N' or '%fixed-stack.N'");
- const auto &Slots = Fixed ? Context.FixedStackObjects : Context.StackObjects;
- const auto Found = std::ranges::find_if(
- Slots, [ID](const MIFrameObjectSlot &Slot) { return Slot.TextID == *ID; });
- if (Found == Slots.end())
- return fail(Node.range(), "reference to undefined frame object");
- Index = Found->Index;
- return false;
-}
-
-MachineBasicBlock *MIRDocumentParser::blockAt(MachineFunction &Function,
- std::uint32_t Number) const noexcept {
- for (MachineBasicBlock *Block = Function.firstBlock(); Block != nullptr; Block = Block->next()) {
- if (Block->denseNumber() == Number)
- return Block;
- }
- return nullptr;
-}
-
-MachineInstr *MIRDocumentParser::instructionAt(MachineFunction &Function, std::uint32_t BlockNumber,
- std::uint32_t Offset) const noexcept {
- MachineBasicBlock *Block = blockAt(Function, BlockNumber);
- if (Block == nullptr)
- return nullptr;
- MachineInstr *Instruction = Block->firstInstruction();
- for (std::uint32_t Index = 0; Instruction != nullptr && Index < Offset; ++Index)
- Instruction = Instruction->next();
- return Instruction;
-}
-
-bool MIRDocumentParser::parseBlockReference(std::string_view Text, const TextRange &Range,
- MachineFunction &Function, MachineBasicBlock *&Block) {
- const auto Number = parsePrefixedID(Text, "%bb.");
- if (!Number)
- return fail(Range, "basic block reference must use the '%bb.N' MIR spelling");
- Block = blockAt(Function, *Number);
- if (Block == nullptr)
- return fail(Range, "reference to undefined machine basic block");
- return false;
-}
-
-bool MIRDocumentParser::parseSaveRestorePoints(const yaml::Node &Node, MachineFunction &Function,
- std::vector<MachineFrameSaveRestorePoint> &Points) {
- if (requireKind(Node, yaml::NodeKind::Sequence, "frame save/restore points"))
- return true;
- constexpr std::array Keys{
- std::string_view{"point"},
- std::string_view{"registers"},
- };
- for (const yaml::NodeID PointID : Node.sequence()) {
- const yaml::Node *PointNode = node(PointID);
- if (PointNode == nullptr ||
- requireKind(*PointNode, yaml::NodeKind::Mapping, "frame save/restore point") ||
- validateKeys(*PointNode, Keys, "frame save/restore point")) {
- return true;
- }
- const yaml::Node *BlockNode = mappingValue(*PointNode, "point");
- if (BlockNode == nullptr)
- return fail(PointNode->range(), "frame save/restore point requires 'point'");
- std::string_view BlockText;
- MachineBasicBlock *Block = nullptr;
- if (scalar(*BlockNode, BlockText, "basic block reference") ||
- parseBlockReference(BlockText, BlockNode->range(), Function, Block)) {
- return true;
- }
- if (Block == nullptr)
- return fail(BlockNode->range(), "reference to undefined machine basic block");
- MachineFrameSaveRestorePoint Point{.Block = Block->stableID(), .Registers = {}};
- if (const yaml::Node *RegistersNode = mappingValue(*PointNode, "registers")) {
- if (requireKind(*RegistersNode, yaml::NodeKind::Sequence, "save/restore point registers")) {
- return true;
- }
- for (const yaml::NodeID RegID : RegistersNode->sequence()) {
- const yaml::Node *RegNode = node(RegID);
- PhysicalRegister Reg;
- if (RegNode == nullptr || physicalRegister(*RegNode, Reg))
- return true;
- Point.Registers.push_back(Reg);
- }
- }
- Points.push_back(std::move(Point));
- }
- return false;
-}
-
-bool MIRDocumentParser::parseFrameState(const yaml::Node &Root, MachineFunction &Function,
- const MIParserContext &Context) {
- const yaml::Node *Frame = mappingValue(Root, "frameInfo");
- if (Frame == nullptr)
- return false;
- if (requireKind(*Frame, yaml::NodeKind::Mapping, "frameInfo"))
- return true;
- constexpr std::array Keys{
- std::string_view{"isFrameAddressTaken"},
- std::string_view{"isReturnAddressTaken"},
- std::string_view{"hasStackMap"},
- std::string_view{"hasPatchPoint"},
- std::string_view{"stackSize"},
- std::string_view{"offsetAdjustment"},
- std::string_view{"maxAlignment"},
- std::string_view{"adjustsStack"},
- std::string_view{"hasCalls"},
- std::string_view{"framePointerPolicy"},
- std::string_view{"stackProtector"},
- std::string_view{"functionContext"},
- std::string_view{"maxCallFrameSize"},
- std::string_view{"cvBytesOfCalleeSavedRegisters"},
- std::string_view{"hasOpaqueSPAdjustment"},
- std::string_view{"hasVAStart"},
- std::string_view{"hasMustTailInVarArgFunc"},
- std::string_view{"hasTailCall"},
- std::string_view{"isCalleeSavedInfoValid"},
- std::string_view{"localFrameSize"},
- std::string_view{"savePoint"},
- std::string_view{"restorePoint"},
- };
- if (validateKeys(*Frame, Keys, "frameInfo"))
- return true;
-
- MachineFrameState State = Function.frameInfo().state();
- const std::array BoolBindings{
- std::pair{"isFrameAddressTaken", &State.IsFrameAddressTaken},
- std::pair{"isReturnAddressTaken", &State.IsReturnAddressTaken},
- std::pair{"hasStackMap", &State.HasStackMap},
- std::pair{"hasPatchPoint", &State.HasPatchPoint},
- std::pair{"adjustsStack", &State.AdjustsStack},
- std::pair{"hasCalls", &State.HasCalls},
- std::pair{"hasOpaqueSPAdjustment", &State.HasOpaqueSPAdjustment},
- std::pair{"hasVAStart", &State.HasVAStart},
- std::pair{"hasMustTailInVarArgFunc", &State.HasMustTailInVarArgFunc},
- std::pair{"hasTailCall", &State.HasTailCall},
- std::pair{"isCalleeSavedInfoValid", &State.IsCalleeSavedInfoValid},
- };
- for (const auto &[Key, Destination] : BoolBindings) {
- if (const yaml::Node *Value = mappingValue(*Frame, Key)) {
- if (boolean(*Value, *Destination))
- return true;
- }
- }
-
- if (const yaml::Node *Value = mappingValue(*Frame, "stackSize")) {
- if (unsignedValue(*Value, State.StackSize, "an unsigned stack size"))
- return true;
- }
- if (const yaml::Node *Value = mappingValue(*Frame, "offsetAdjustment")) {
- std::int64_t Wide = 0;
- if (signedValue(*Value, Wide, "a 32-bit signed offset adjustment") ||
- Wide < std::numeric_limits<std::int32_t>::min() ||
- Wide > std::numeric_limits<std::int32_t>::max()) {
- return fail(Value->range(), "offset adjustment is outside the 32-bit signed range");
- }
- State.OffsetAdjustment = static_cast<std::int32_t>(Wide);
- }
- if (const yaml::Node *Value = mappingValue(*Frame, "maxAlignment")) {
- std::uint64_t Bytes = 0;
- if (unsignedValue(*Value, Bytes, "an unsigned maximum alignment"))
- return true;
- if (Bytes == 0) {
- State.MaxAlignment.reset();
- } else {
- auto Parsed = Alignment::create(Bytes);
- if (!Parsed)
- return importError(Value->range(), Parsed.error());
- State.MaxAlignment = *Parsed;
- }
- }
- if (const yaml::Node *Value = mappingValue(*Frame, "framePointerPolicy")) {
- std::string_view Name;
- if (scalar(*Value, Name, "frame-pointer policy"))
- return true;
- const auto Policy = parseMachineFramePointerPolicy(Name);
- if (!Policy)
- return fail(Value->range(), "unknown frame-pointer policy '" + std::string(Name) + "'");
- State.FramePointerPolicy = *Policy;
- }
- for (const auto &[Key, Destination] : {std::pair{"stackProtector", &State.StackProtector},
- std::pair{"functionContext", &State.FunctionContext}}) {
- if (const yaml::Node *Value = mappingValue(*Frame, Key)) {
- std::string_view Reference;
- if (scalar(*Value, Reference, "frame index"))
- return true;
- if (Reference.empty()) {
- Destination->reset();
- continue;
- }
- FrameIndex Index;
- if (parseFrameReference(*Value, Context, Index))
- return true;
- *Destination = Index;
- }
- }
- if (const yaml::Node *Value = mappingValue(*Frame, "maxCallFrameSize")) {
- std::uint64_t Size = 0;
- if (unsignedValue(*Value, Size, "a 32-bit unsigned maximum call-frame size") ||
- Size > std::numeric_limits<std::uint32_t>::max()) {
- return fail(Value->range(), "maximum call-frame size is outside the 32-bit unsigned range");
- }
- if (Size == std::numeric_limits<std::uint32_t>::max())
- State.MaxCallFrameSize.reset();
- else
- State.MaxCallFrameSize = Size;
- }
- for (const auto &[Key, Destination] :
- {std::pair{"cvBytesOfCalleeSavedRegisters", &State.CVBytesOfCalleeSavedRegisters},
- std::pair{"localFrameSize", &State.LocalFrameSize}}) {
- if (const yaml::Node *Value = mappingValue(*Frame, Key)) {
- std::uint64_t Wide = 0;
- if (unsignedValue(*Value, Wide, "a 32-bit unsigned frame value") ||
- Wide > std::numeric_limits<std::uint32_t>::max()) {
- return fail(Value->range(), "frame value is outside the 32-bit unsigned range");
- }
- *Destination = static_cast<std::uint32_t>(Wide);
- }
- }
- if (const yaml::Node *Value = mappingValue(*Frame, "savePoint")) {
- if (parseSaveRestorePoints(*Value, Function, State.SavePoints))
- return true;
- }
- if (const yaml::Node *Value = mappingValue(*Frame, "restorePoint")) {
- if (parseSaveRestorePoints(*Value, Function, State.RestorePoints))
- return true;
- }
- auto StateResult = Function.frameInfo().setState(std::move(State));
- if (!StateResult)
- return importError(Frame->range(), StateResult.error());
- return false;
-}
-
-} // namespace rcc::mir
diff --git a/backend/lib/MIR/MIRFunctionParser.cpp b/backend/lib/MIR/MIRFunctionParser.cpp
deleted file mode 100644
index 6acf774..0000000
--- a/backend/lib/MIR/MIRFunctionParser.cpp
+++ /dev/null
@@ -1,552 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include "MIRDocumentParser.h"
-#include "MIRDocumentReferenceValidation.h"
-#include "MIRMetadataTextParser.h"
-#include "MIRParserUtilities.h"
-#include "rcc/CodeGen/MachineBasicBlock.h"
-#include "rcc/CodeGen/MachineConstantPool.h"
-#include "rcc/CodeGen/MachineFrameInfo.h"
-#include "rcc/CodeGen/MachineFunction.h"
-#include "rcc/CodeGen/MachineFunctionAttributes.h"
-#include "rcc/CodeGen/MachineFunctionProperties.h"
-#include "rcc/CodeGen/MachineFunctionRecords.h"
-#include "rcc/CodeGen/MachineInstr.h"
-#include "rcc/CodeGen/MachineJumpTableInfo.h"
-#include "rcc/CodeGen/MachineMetadata.h"
-#include "rcc/CodeGen/MachineRegisterInfo.h"
-#include "rcc/CodeGen/MachineVerifier.h"
-#include "rcc/CodeGen/TargetDescription.h"
-#include "rcc/CodeGen/TargetMIRTextInfo.h"
-#include "rcc/CodeGen/TargetRegisterInfo.h"
-#include "rcc/MIR/LLVMConstantSyntax.h"
-
-#include <algorithm>
-#include <array>
-#include <cstddef>
-#include <cstdint>
-#include <initializer_list>
-#include <limits>
-#include <optional>
-#include <ranges>
-#include <span>
-#include <string>
-#include <string_view>
-#include <unordered_map>
-#include <unordered_set>
-#include <utility>
-#include <vector>
-
-namespace rcc::mir {
-
-using parser_detail::parseBool;
-using parser_detail::parsePrefixedID;
-using parser_detail::parseSigned;
-using parser_detail::parseUnsigned;
-using parser_detail::parseUnsigned32;
-using parser_detail::trim;
-
-bool MIRDocumentParser::parseFunctionScalars(const yaml::Node &Root, MachineFunction &Function,
- MIRFunctionDocumentInfo &DocumentInfo) {
- if (const yaml::Node *AlignNode = mappingValue(Root, "alignment")) {
- Alignment Align;
- if (alignment(*AlignNode, Align, true))
- return true;
- if (Align.bytes() != 1 || AlignNode->scalar() != "0")
- Function.attributes().setAlignment(Align);
- }
-
- constexpr std::array PropertyBindings{
- std::pair{"legalized", MachineFunctionProperty::Legalized},
- std::pair{"regBankSelected", MachineFunctionProperty::RegBankSelected},
- std::pair{"selected", MachineFunctionProperty::Selected},
- std::pair{"failedISel", MachineFunctionProperty::FailedISel},
- std::pair{"tracksRegLiveness", MachineFunctionProperty::TracksLiveness},
- std::pair{"noPhis", MachineFunctionProperty::NoPHIs},
- std::pair{"isSSA", MachineFunctionProperty::IsSSA},
- std::pair{"noVRegs", MachineFunctionProperty::NoVRegs},
- std::pair{"failsVerification", MachineFunctionProperty::FailsVerification},
- };
- for (const auto &[Key, Property] : PropertyBindings) {
- const yaml::Node *ValueNode = mappingValue(Root, Key);
- if (ValueNode == nullptr)
- continue;
- bool Value = false;
- if (boolean(*ValueNode, Value))
- return true;
- if (Value)
- Function.properties().set(Property);
- else
- Function.properties().clear(Property);
- if (Key == std::string_view("noPhis"))
- DocumentInfo.NoPHIs = Value;
- else if (Key == std::string_view("isSSA"))
- DocumentInfo.IsSSA = Value;
- else if (Key == std::string_view("noVRegs"))
- DocumentInfo.NoVRegs = Value;
- }
-
- constexpr std::array AttributeBindings{
- std::pair{"exposesReturnsTwice", MachineFunctionAttribute::ExposesReturnsTwice},
- std::pair{"hasWinCFI", MachineFunctionAttribute::HasWinCFI},
- std::pair{"hasFakeUses", MachineFunctionAttribute::HasFakeUses},
- std::pair{"callsEHReturn", MachineFunctionAttribute::CallsEHReturn},
- std::pair{"callsUnwindInit", MachineFunctionAttribute::CallsUnwindInit},
- std::pair{"hasEHContTarget", MachineFunctionAttribute::HasEHContTarget},
- std::pair{"hasEHScopes", MachineFunctionAttribute::HasEHScopes},
- std::pair{"hasEHFunclets", MachineFunctionAttribute::HasEHFunclets},
- std::pair{"isOutlined", MachineFunctionAttribute::IsOutlined},
- std::pair{"debugInstrRef", MachineFunctionAttribute::DebugInstrRef},
- std::pair{"tracksDebugUserValues", MachineFunctionAttribute::TracksDebugUserValues},
- };
- for (const auto &[Key, Attribute] : AttributeBindings) {
- const yaml::Node *ValueNode = mappingValue(Root, Key);
- if (ValueNode == nullptr)
- continue;
- bool Value = false;
- if (boolean(*ValueNode, Value))
- return true;
- if (Value)
- Function.attributes().set(Attribute);
- else
- Function.attributes().clear(Attribute);
- if (Key == std::string_view("hasFakeUses"))
- DocumentInfo.HasFakeUses = Value;
- }
-
- return false;
-}
-
-bool MIRDocumentParser::recomputeProperties(const yaml::Node &Root, MachineFunction &Function,
- const MIRFunctionDocumentInfo &DocumentInfo) {
- bool HasPHI = false;
- bool HasFakeUse = false;
- bool IsSSA = true;
- bool HasTiedOperands = false;
- bool AllTiedOperandsRewritten = true;
- bool HasFrameIndex = false;
- bool HasExecutablePseudo = false;
- std::unordered_set<Register> Definitions;
- for (const MachineBasicBlock *Block = Function.firstBlock(); Block != nullptr;
- Block = Block->next()) {
- for (const MachineInstr *Instruction = Block->firstInstruction(); Instruction != nullptr;
- Instruction = Instruction->next()) {
- const InstructionDescriptor *Descriptor = Target.instructionDescriptor(Instruction->opcode());
- if (Descriptor == nullptr)
- return fail(Root.range(), "instruction has no target descriptor");
- HasPHI |= Descriptor->Flags.has(InstructionFlag::Phi);
- HasFakeUse |= Descriptor->Flags.has(InstructionFlag::FakeUse);
- HasExecutablePseudo |= Descriptor->Flags.has(InstructionFlag::Pseudo) &&
- !Descriptor->Flags.has(InstructionFlag::Meta) &&
- !Descriptor->Flags.has(InstructionFlag::TerminalEmission);
- const auto Operands = Instruction->operands();
- for (std::size_t Index = 0; Index < Operands.size(); ++Index) {
- const MachineOperand &Operand = Operands[Index];
- HasFrameIndex |= Operand.getIf<FrameIndexOperand>() != nullptr;
- const auto Reg = Operand.registerValue();
- if (Reg && Reg->isVirtual() && Operand.isDef() && !Definitions.insert(*Reg).second) {
- IsSSA = false;
- }
- if (!Operand.tiedOperandIndex() || !Operand.isUse())
- continue;
- HasTiedOperands = true;
- const MachineOperand *Definition = Instruction->operandAt(*Operand.tiedOperandIndex());
- if (Definition == nullptr || Definition->registerValue() != Reg)
- AllTiedOperandsRewritten = false;
- }
- for (const MachineMemOperand *Memory : Instruction->memOperands())
- HasFrameIndex |= Memory->description().Base.frameIndex().has_value();
- }
- }
- const bool NoPHIs = !HasPHI;
- const bool NoVRegs =
- std::ranges::none_of(Function.registerInfo().virtualRegisters(),
- [](const VirtualRegisterInfo &Info) { return !Info.IsTombstone; });
-
- const auto ApplyComputed = [this, &Root, &Function](std::optional<bool> Explicit, bool Computed,
- MachineFunctionProperty Property,
- std::string_view Conflict) -> bool {
- if (Explicit && *Explicit && !Computed) {
- return fail(Root.range(), std::string(Function.name()) + std::string(Conflict));
- }
- if (Explicit.value_or(Computed))
- Function.properties().set(Property);
- else
- Function.properties().clear(Property);
- return false;
- };
- if (ApplyComputed(DocumentInfo.NoPHIs, NoPHIs, MachineFunctionProperty::NoPHIs,
- " has explicit property NoPhi, but contains at least one PHI") ||
- ApplyComputed(DocumentInfo.IsSSA, IsSSA, MachineFunctionProperty::IsSSA,
- " has explicit property IsSSA, but is not valid SSA") ||
- ApplyComputed(DocumentInfo.NoVRegs, NoVRegs, MachineFunctionProperty::NoVRegs,
- " has explicit property NoVRegs, but contains virtual registers")) {
- return true;
- }
-
- if (DocumentInfo.HasFakeUses && !*DocumentInfo.HasFakeUses && HasFakeUse) {
- return fail(Root.range(),
- std::string(Function.name()) +
- " has explicit property hasFakeUses=false, but contains fake uses");
- }
- if (DocumentInfo.HasFakeUses.value_or(HasFakeUse))
- Function.attributes().set(MachineFunctionAttribute::HasFakeUses);
- else
- Function.attributes().clear(MachineFunctionAttribute::HasFakeUses);
-
- const bool Selected = Function.properties().has(MachineFunctionProperty::Selected);
- const bool StructurallyPostSSA =
- Selected && NoPHIs && !Function.properties().has(MachineFunctionProperty::IsSSA);
- if (AllTiedOperandsRewritten && (HasTiedOperands || StructurallyPostSSA))
- Function.properties().set(MachineFunctionProperty::TiedOpsRewritten);
- else
- Function.properties().clear(MachineFunctionProperty::TiedOpsRewritten);
-
- if (HasFrameIndex)
- Function.properties().clear(MachineFunctionProperty::NoFrameIndices);
- else
- Function.properties().set(MachineFunctionProperty::NoFrameIndices);
-
- const MachineFrameState &FrameState = Function.frameInfo().state();
- const bool StructurallyFinalizedFrame = Selected && NoVRegs && !HasFrameIndex &&
- FrameState.IsCalleeSavedInfoValid &&
- FrameState.MaxAlignment.has_value();
- if (StructurallyFinalizedFrame) {
- if (!Function.frameInfo().isFrozen()) {
- auto Frozen = Function.frameInfo().freeze(FrameState.StackSize, *FrameState.MaxAlignment);
- if (!Frozen)
- return importError(Root.range(), Frozen.error(), "mir-frame-finalization");
- }
- Function.properties().set(MachineFunctionProperty::FrameFinalized);
- } else {
- Function.properties().clear(MachineFunctionProperty::FrameFinalized);
- }
-
- if (StructurallyFinalizedFrame && !HasExecutablePseudo)
- Function.properties().set(MachineFunctionProperty::NoExecutablePseudos);
- else
- Function.properties().clear(MachineFunctionProperty::NoExecutablePseudos);
- return false;
-}
-
-bool MIRDocumentParser::parseRegisters(const yaml::Node &Root, MachineFunction &Function,
- MIParserContext &Context) {
- const yaml::Node *Registers = mappingValue(Root, "registers");
- if (Registers != nullptr) {
- if (requireKind(*Registers, yaml::NodeKind::Sequence, "registers"))
- return true;
- constexpr std::array RegisterKeys{
- std::string_view{"id"},
- std::string_view{"class"},
- std::string_view{"preferred-register"},
- std::string_view{"flags"},
- };
- std::unordered_set<std::uint32_t> IDs;
- for (const yaml::NodeID ElementID : Registers->sequence()) {
- const yaml::Node *Element = node(ElementID);
- if (Element == nullptr || requireKind(*Element, yaml::NodeKind::Mapping, "register entry") ||
- validateKeys(*Element, RegisterKeys, "register")) {
- return true;
- }
- const yaml::Node *IDNode = mappingValue(*Element, "id");
- const yaml::Node *ClassNode = mappingValue(*Element, "class");
- if (IDNode == nullptr || ClassNode == nullptr)
- return fail(Element->range(), "register entry requires 'id' and 'class'");
- std::uint64_t WideID = 0;
- std::string_view ClassName;
- if (unsignedValue(*IDNode, WideID, "a 32-bit virtual-register ID") ||
- WideID > std::numeric_limits<std::uint32_t>::max() ||
- scalar(*ClassNode, ClassName, "register class or bank")) {
- return true;
- }
- const auto TextID = static_cast<std::uint32_t>(WideID);
- if (!IDs.insert(TextID).second)
- return fail(IDNode->range(), "duplicate virtual register ID");
- auto Created = Function.registerInfo().createVirtualRegister();
- if (!Created)
- return importError(IDNode->range(), Created.error());
- Context.VirtualRegisters.push_back({TextID, *Created});
-
- if (ClassName != "_") {
- if (const RegisterClassDesc *Class = Target.registers().registerClass(ClassName)) {
- auto SetResult = Function.registerInfo().setRegisterClass(*Created, Class->ID);
- if (!SetResult)
- return importError(ClassNode->range(), SetResult.error());
- SetResult = Function.registerInfo().setRegisterBank(*Created, Class->DefaultBank);
- if (!SetResult)
- return importError(ClassNode->range(), SetResult.error());
- } else if (const RegisterBankDesc *Bank = Target.registers().registerBank(ClassName)) {
- auto SetResult = Function.registerInfo().setRegisterBank(*Created, Bank->ID);
- if (!SetResult)
- return importError(ClassNode->range(), SetResult.error());
- } else {
- return fail(ClassNode->range(),
- "unknown register class or bank '" + std::string(ClassName) + "'");
- }
- }
-
- if (const yaml::Node *Preferred = mappingValue(*Element, "preferred-register")) {
- std::string_view PreferredName;
- PhysicalRegister Reg;
- if (scalar(*Preferred, PreferredName, "physical register"))
- return true;
- if (!trim(PreferredName).empty()) {
- if (physicalRegister(PreferredName, Preferred->range(), Reg))
- return true;
- auto AddResult = Function.registerInfo().addAllocationHint(*Created, Reg);
- if (!AddResult)
- return importError(Preferred->range(), AddResult.error());
- }
- }
- if (const yaml::Node *Flags = mappingValue(*Element, "flags")) {
- if (requireKind(*Flags, yaml::NodeKind::Sequence, "virtual-register flags"))
- return true;
- std::uint8_t Mask = 0;
- for (const yaml::NodeID FlagID : Flags->sequence()) {
- const yaml::Node *FlagNode = node(FlagID);
- std::string_view Name;
- if (FlagNode == nullptr || scalar(*FlagNode, Name, "virtual-register flag"))
- return true;
- const auto Flag = Target.mirText().virtualRegisterFlag(Name);
- if (!Flag)
- return fail(FlagNode->range(),
- "use of undefined register flag '" + std::string(Name) + "'");
- if ((Mask & *Flag) != 0)
- return fail(FlagNode->range(), "duplicate virtual-register flag");
- Mask = static_cast<std::uint8_t>(Mask | *Flag);
- }
- auto SetResult = Function.registerInfo().setTargetRegisterFlags(*Created, Mask);
- if (!SetResult)
- return importError(Flags->range(), SetResult.error());
- }
- }
- }
-
- const yaml::Node *LiveIns = mappingValue(Root, "liveins");
- if (LiveIns != nullptr) {
- if (requireKind(*LiveIns, yaml::NodeKind::Sequence, "liveins"))
- return true;
- constexpr std::array LiveInKeys{
- std::string_view{"reg"},
- std::string_view{"virtual-reg"},
- };
- for (const yaml::NodeID ElementID : LiveIns->sequence()) {
- const yaml::Node *Element = node(ElementID);
- if (Element == nullptr || requireKind(*Element, yaml::NodeKind::Mapping, "live-in entry") ||
- validateKeys(*Element, LiveInKeys, "live-in")) {
- return true;
- }
- const yaml::Node *RegNode = mappingValue(*Element, "reg");
- if (RegNode == nullptr)
- return fail(Element->range(), "live-in entry requires 'reg'");
- PhysicalRegister Reg;
- if (physicalRegister(*RegNode, Reg))
- return true;
- std::optional<Register> Initial;
- if (const yaml::Node *VirtualNode = mappingValue(*Element, "virtual-reg")) {
- std::string_view Text;
- if (scalar(*VirtualNode, Text, "virtual register"))
- return true;
- if (!trim(Text).empty()) {
- Register Virtual;
- if (virtualRegister(Text, VirtualNode->range(), Function, Context, Virtual))
- return true;
- Initial = Virtual;
- }
- }
- auto AddResult = Function.registerInfo().addLiveIn(Reg, Initial);
- if (!AddResult)
- return importError(Element->range(), AddResult.error());
- }
- }
-
- if (const yaml::Node *CalleeSaved = mappingValue(Root, "calleeSavedRegisters")) {
- if (requireKind(*CalleeSaved, yaml::NodeKind::Sequence, "callee-saved registers"))
- return true;
- std::vector<PhysicalRegister> RegistersValue;
- for (const yaml::NodeID RegID : CalleeSaved->sequence()) {
- const yaml::Node *RegNode = node(RegID);
- PhysicalRegister Reg;
- if (RegNode == nullptr || physicalRegister(*RegNode, Reg))
- return true;
- RegistersValue.push_back(Reg);
- }
- auto SetResult = Function.records().setCalleeSavedRegisters(std::move(RegistersValue));
- if (!SetResult)
- return importError(CalleeSaved->range(), SetResult.error());
- }
- return false;
-}
-
-TextRange MIRDocumentParser::scalarDiagnosticRange(const yaml::Node &Scalar,
- const TextRange &ScalarRange) const noexcept {
- if (Scalar.scalarStyle() != yaml::ScalarStyle::Literal &&
- Scalar.scalarStyle() != yaml::ScalarStyle::Folded) {
- std::size_t ContentOffset = Scalar.range().Begin.Offset;
- if (Scalar.scalarStyle() == yaml::ScalarStyle::SingleQuoted ||
- Scalar.scalarStyle() == yaml::ScalarStyle::DoubleQuoted) {
- ++ContentOffset;
- }
- return Result.Source.range(ContentOffset + ScalarRange.Begin.Offset,
- ContentOffset + ScalarRange.End.Offset);
- }
-
- const std::size_t FirstBodyLine = Scalar.range().Begin.Line + 1U;
- const std::size_t LastBodyLine = Scalar.range().End.Line;
- if (FirstBodyLine > LastBodyLine || FirstBodyLine == 0)
- return Scalar.range();
-
- std::size_t Indent = 0;
- bool FoundContent = false;
- for (std::size_t Line = FirstBodyLine; Line <= LastBodyLine; ++Line) {
- const std::string_view Text = Result.Source.line(Line);
- std::size_t CurrentIndent = 0;
- while (CurrentIndent < Text.size() && Text[CurrentIndent] == ' ')
- ++CurrentIndent;
- if (CurrentIndent == Text.size())
- continue;
- Indent = CurrentIndent;
- FoundContent = true;
- break;
- }
- if (!FoundContent)
- return Scalar.range();
-
- const TextPosition DefaultPosition = Scalar.range().Begin;
- const auto MapPosition = [this, FirstBodyLine, LastBodyLine, Indent,
- DefaultPosition](TextPosition Position) {
- const std::size_t SourceLine = FirstBodyLine + Position.Line - 1U;
- if (Position.Line == 0 || SourceLine > LastBodyLine || SourceLine > Result.Source.lineCount()) {
- return DefaultPosition;
- }
- const std::string_view SourceLineText = Result.Source.line(SourceLine);
- const std::size_t BodyColumn = Position.Column == 0 ? 0 : Position.Column - 1U;
- const std::size_t SourceColumn = std::min(Indent + BodyColumn, SourceLineText.size());
- const std::size_t Offset = Result.Source.lineOffsets()[SourceLine - 1U] + SourceColumn;
- return Result.Source.positionAt(Offset);
- };
- return {.Begin = MapPosition(ScalarRange.Begin), .End = MapPosition(ScalarRange.End)};
-}
-
-bool MIRDocumentParser::parseBody(const yaml::Node &Root, MachineFunction &Function,
- MIParserContext &Context) {
- const yaml::Node *Body = mappingValue(Root, "body");
- std::string BodyText;
- TextRange BodyRange = Root.range();
- if (Body != nullptr) {
- std::string_view Text;
- if (scalar(*Body, Text, "machine function body"))
- return true;
- BodyText = Text;
- BodyRange = Body->range();
- }
-
- if (!effectiveDataLayout().empty()) {
- const LLVMConstantSyntaxOptions PointerOptions = pointerLayoutOptions();
- Context.PointerSizeInBits = [PointerOptions](std::uint32_t AddressSpace) {
- return llvmPointerSizeInBits(AddressSpace, PointerOptions);
- };
- }
- Context.SyncScopes = ActiveDocument->SyncScopes;
- Context.InternSyncScope = [this](std::string_view Name) -> Expected<SyncScopeID> {
- if (Name.empty())
- return makeUnexpected(ErrorCode::ParseError, "synchronization scope name cannot be empty");
- const auto Existing =
- std::ranges::find_if(ActiveDocument->SyncScopes,
- [Name](const MISyncScopeSlot &Slot) { return Slot.Name == Name; });
- if (Existing != ActiveDocument->SyncScopes.end())
- return Existing->ID;
- if (ActiveDocument->SyncScopes.size() >=
- static_cast<std::size_t>(std::numeric_limits<std::uint32_t>::max())) {
- return makeUnexpected(ErrorCode::Unsupported,
- "MIR document contains too many synchronization scopes");
- }
- const auto ID =
- SyncScopeID::fromValue(static_cast<std::uint32_t>(ActiveDocument->SyncScopes.size() + 1U));
- ActiveDocument->SyncScopes.push_back({.Name = std::string(Name), .ID = ID});
- return ID;
- };
- MIParserOptions BodyOptions = Options.MachineInstructions;
- BodyOptions.VerifyAfterParse = false;
- MIParser Parser(Function, Target,
- std::string(Result.Source.name()) + ":" + std::string(Function.name()),
- std::move(BodyText), Context, BodyOptions);
- auto Parsed = Parser.parse();
- if (!Parsed) {
- if (!Parser.diagnostics().empty()) {
- const TextRange Range =
- Body == nullptr ? BodyRange
- : scalarDiagnosticRange(*Body, Parser.diagnostics().front().Range);
- return fail(Range, Parser.diagnostics().front().Message, "mir-body");
- }
- return importError(BodyRange, Parsed.error(), "mir-body");
- }
- return false;
-}
-
-bool MIRDocumentParser::convertTargetNode(const yaml::Node &Source, MIRTargetNode &Destination) {
- switch (Source.kind()) {
- case yaml::NodeKind::Null:
- Destination = MIRTargetNode::null();
- return false;
- case yaml::NodeKind::Scalar:
- Destination = MIRTargetNode::scalar(std::string(Source.scalar()));
- return false;
- case yaml::NodeKind::Sequence: {
- std::vector<MIRTargetNode> Values;
- Values.reserve(Source.sequence().size());
- for (const yaml::NodeID ElementID : Source.sequence()) {
- const yaml::Node *Element = node(ElementID);
- if (Element == nullptr)
- return fail(Source.range(), "target MIR sequence contains an invalid node");
- MIRTargetNode Value;
- if (convertTargetNode(*Element, Value))
- return true;
- Values.push_back(std::move(Value));
- }
- Destination = MIRTargetNode::sequence(std::move(Values));
- return false;
- }
- case yaml::NodeKind::Mapping: {
- std::vector<MIRTargetMappingEntry> Entries;
- Entries.reserve(Source.mapping().size());
- for (const yaml::MappingEntry &SourceEntry : Source.mapping()) {
- const yaml::Node *ValueNode = node(SourceEntry.Value);
- if (ValueNode == nullptr)
- return fail(SourceEntry.KeyRange, "target MIR mapping contains an invalid node");
- MIRTargetNode Value;
- if (convertTargetNode(*ValueNode, Value))
- return true;
- Entries.push_back({SourceEntry.Key, std::move(Value)});
- }
- Destination = MIRTargetNode::mapping(std::move(Entries));
- return false;
- }
- }
- return fail(Source.range(), "target MIR node has an unknown kind");
-}
-
-bool MIRDocumentParser::parseTargetState(const yaml::Node &Root, MachineFunction &Function) {
- const yaml::Node *StateNode = mappingValue(Root, "machineFunctionInfo");
- if (StateNode == nullptr)
- return false;
- MIRTargetNode TargetNode;
- if (convertTargetNode(*StateNode, TargetNode))
- return true;
- auto State = Target.mirText().parseFunctionState(TargetNode);
- if (!State)
- return importError(StateNode->range(), State.error(), "mir-target-state");
- auto SetResult = Function.setTargetState(std::move(*State));
- if (!SetResult)
- return importError(StateNode->range(), SetResult.error(), "mir-target-state");
- return false;
-}
-
-bool MIRDocumentParser::validateDocumentReferences(const MachineFunction &Function) {
- auto Verification = verifyMIRDocumentReferences(*ActiveDocument, Function, true);
- if (Verification)
- return false;
- return importError(Result.Source.range(0, 0), Verification.error());
-}
-
-} // namespace rcc::mir
diff --git a/backend/lib/MIR/MIRFunctionRecordsParser.cpp b/backend/lib/MIR/MIRFunctionRecordsParser.cpp
deleted file mode 100644
index 04857bb..0000000
--- a/backend/lib/MIR/MIRFunctionRecordsParser.cpp
+++ /dev/null
@@ -1,341 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include "MIRDocumentParser.h"
-#include "MIRDocumentReferenceValidation.h"
-#include "MIRMetadataTextParser.h"
-#include "MIRParserUtilities.h"
-#include "rcc/CodeGen/MachineBasicBlock.h"
-#include "rcc/CodeGen/MachineConstantPool.h"
-#include "rcc/CodeGen/MachineFrameInfo.h"
-#include "rcc/CodeGen/MachineFunction.h"
-#include "rcc/CodeGen/MachineFunctionAttributes.h"
-#include "rcc/CodeGen/MachineFunctionProperties.h"
-#include "rcc/CodeGen/MachineFunctionRecords.h"
-#include "rcc/CodeGen/MachineInstr.h"
-#include "rcc/CodeGen/MachineJumpTableInfo.h"
-#include "rcc/CodeGen/MachineMetadata.h"
-#include "rcc/CodeGen/MachineRegisterInfo.h"
-#include "rcc/CodeGen/MachineVerifier.h"
-#include "rcc/CodeGen/TargetDescription.h"
-#include "rcc/CodeGen/TargetMIRTextInfo.h"
-#include "rcc/CodeGen/TargetRegisterInfo.h"
-#include "rcc/MIR/LLVMConstantSyntax.h"
-
-#include <algorithm>
-#include <array>
-#include <cstddef>
-#include <cstdint>
-#include <initializer_list>
-#include <limits>
-#include <optional>
-#include <ranges>
-#include <span>
-#include <string>
-#include <string_view>
-#include <unordered_map>
-#include <unordered_set>
-#include <utility>
-#include <vector>
-
-namespace rcc::mir {
-
-using parser_detail::parseBool;
-using parser_detail::parsePrefixedID;
-using parser_detail::parseSigned;
-using parser_detail::parseUnsigned;
-using parser_detail::parseUnsigned32;
-using parser_detail::trim;
-
-bool MIRDocumentParser::parseFunctionRecords(const yaml::Node &Root, MachineFunction &Function) {
- auto ParseLocation = [this, &Function](const yaml::Node &Entry,
- MachineInstr *&Instruction) -> bool {
- const yaml::Node *BlockNode = mappingValue(Entry, "bb");
- const yaml::Node *OffsetNode = mappingValue(Entry, "offset");
- if (BlockNode == nullptr || OffsetNode == nullptr)
- return fail(Entry.range(), "instruction location requires 'bb' and 'offset'");
- std::uint64_t Block = 0;
- std::uint64_t Offset = 0;
- if (unsignedValue(*BlockNode, Block, "a 32-bit basic block number") ||
- unsignedValue(*OffsetNode, Offset, "a 32-bit instruction offset") ||
- Block > std::numeric_limits<std::uint32_t>::max() ||
- Offset > std::numeric_limits<std::uint32_t>::max()) {
- return true;
- }
- Instruction = instructionAt(Function, static_cast<std::uint32_t>(Block),
- static_cast<std::uint32_t>(Offset));
- if (Instruction == nullptr)
- return fail(Entry.range(), "instruction location is outside the machine function body");
- return false;
- };
-
- if (const yaml::Node *CallSites = mappingValue(Root, "callSites")) {
- if (requireKind(*CallSites, yaml::NodeKind::Sequence, "call-site records"))
- return true;
- constexpr std::array CallSiteKeys{
- std::string_view{"bb"},
- std::string_view{"offset"},
- std::string_view{"fwdArgRegs"},
- std::string_view{"calleeTypeIds"},
- };
- constexpr std::array ArgumentKeys{
- std::string_view{"arg"},
- std::string_view{"reg"},
- };
- for (const yaml::NodeID CallSiteID : CallSites->sequence()) {
- const yaml::Node *CallSiteNode = node(CallSiteID);
- if (CallSiteNode == nullptr ||
- requireKind(*CallSiteNode, yaml::NodeKind::Mapping, "call-site record") ||
- validateKeys(*CallSiteNode, CallSiteKeys, "call-site record")) {
- return true;
- }
- MachineInstr *Call = nullptr;
- if (ParseLocation(*CallSiteNode, Call))
- return true;
- if (Call == nullptr)
- return fail(CallSiteNode->range(),
- "instruction location is outside the machine function body");
- MachineCallSiteInfo Info{
- .CallInstruction = Call->stableID(),
- .ForwardedArguments = {},
- .CalleeTypeIDs = {},
- };
- if (const yaml::Node *Arguments = mappingValue(*CallSiteNode, "fwdArgRegs")) {
- if (requireKind(*Arguments, yaml::NodeKind::Sequence, "forwarded call arguments")) {
- return true;
- }
- for (const yaml::NodeID ArgumentID : Arguments->sequence()) {
- const yaml::Node *Argument = node(ArgumentID);
- if (Argument == nullptr ||
- requireKind(*Argument, yaml::NodeKind::Mapping, "forwarded call argument") ||
- validateKeys(*Argument, ArgumentKeys, "forwarded call argument")) {
- return true;
- }
- const yaml::Node *NumberNode = mappingValue(*Argument, "arg");
- const yaml::Node *RegNode = mappingValue(*Argument, "reg");
- if (NumberNode == nullptr || RegNode == nullptr)
- return fail(Argument->range(), "forwarded call argument requires 'arg' and 'reg'");
- std::uint16_t Number = 0;
- std::uint64_t WideNumber = 0;
- PhysicalRegister Reg;
- if (unsignedValue(*NumberNode, WideNumber, "a 16-bit argument number") ||
- WideNumber > std::numeric_limits<std::uint16_t>::max() ||
- physicalRegister(*RegNode, Reg)) {
- return true;
- }
- Number = static_cast<std::uint16_t>(WideNumber);
- Info.ForwardedArguments.push_back({Reg, Number});
- }
- }
- if (const yaml::Node *TypeIDs = mappingValue(*CallSiteNode, "calleeTypeIds")) {
- if (requireKind(*TypeIDs, yaml::NodeKind::Sequence, "callee type IDs"))
- return true;
- for (const yaml::NodeID TypeID : TypeIDs->sequence()) {
- const yaml::Node *TypeNode = node(TypeID);
- std::uint64_t Value = 0;
- if (TypeNode == nullptr ||
- unsignedValue(*TypeNode, Value, "an unsigned callee type ID")) {
- return true;
- }
- Info.CalleeTypeIDs.push_back(Value);
- }
- }
- auto AddResult = Function.records().addCallSite(std::move(Info));
- if (!AddResult)
- return importError(CallSiteNode->range(), AddResult.error());
- }
- }
-
- if (const yaml::Node *CalledGlobals = mappingValue(Root, "calledGlobals")) {
- if (requireKind(*CalledGlobals, yaml::NodeKind::Sequence, "called-global records"))
- return true;
- constexpr std::array Keys{
- std::string_view{"bb"},
- std::string_view{"offset"},
- std::string_view{"callee"},
- std::string_view{"flags"},
- };
- for (const yaml::NodeID CalledID : CalledGlobals->sequence()) {
- const yaml::Node *CalledNode = node(CalledID);
- if (CalledNode == nullptr ||
- requireKind(*CalledNode, yaml::NodeKind::Mapping, "called-global record") ||
- validateKeys(*CalledNode, Keys, "called-global record")) {
- return true;
- }
- MachineInstr *Call = nullptr;
- if (ParseLocation(*CalledNode, Call))
- return true;
- if (Call == nullptr)
- return fail(CalledNode->range(),
- "instruction location is outside the machine function body");
- const yaml::Node *CalleeNode = mappingValue(*CalledNode, "callee");
- const yaml::Node *FlagsNode = mappingValue(*CalledNode, "flags");
- if (CalleeNode == nullptr || FlagsNode == nullptr)
- return fail(CalledNode->range(), "called-global record requires 'callee' and 'flags'");
- std::string_view Callee;
- std::uint64_t WideFlags = 0;
- if (scalar(*CalleeNode, Callee, "callee name") ||
- unsignedValue(*FlagsNode, WideFlags, "32-bit called-global flags") ||
- WideFlags > std::numeric_limits<std::uint32_t>::max()) {
- return true;
- }
- if (ActiveDocument->EmbeddedIR && !ActiveDocument->EmbeddedIR->hasGlobalValue(Callee)) {
- return fail(CalleeNode->range(), "called global references an undefined embedded global");
- }
- auto AddResult =
- Function.records().addCalledGlobal({.CallInstruction = Call->stableID(),
- .Callee = std::string(Callee),
- .Flags = static_cast<std::uint32_t>(WideFlags)});
- if (!AddResult)
- return importError(CalledNode->range(), AddResult.error());
- }
- }
-
- if (const yaml::Node *Substitutions = mappingValue(Root, "debugValueSubstitutions")) {
- if (requireKind(*Substitutions, yaml::NodeKind::Sequence, "debug value substitutions")) {
- return true;
- }
- constexpr std::array Keys{
- std::string_view{"srcinst"}, std::string_view{"srcop"}, std::string_view{"dstinst"},
- std::string_view{"dstop"}, std::string_view{"subreg"},
- };
- for (const yaml::NodeID SubstitutionID : Substitutions->sequence()) {
- const yaml::Node *Substitution = node(SubstitutionID);
- if (Substitution == nullptr ||
- requireKind(*Substitution, yaml::NodeKind::Mapping, "debug value substitution") ||
- validateKeys(*Substitution, Keys, "debug value substitution")) {
- return true;
- }
- std::array<std::uint32_t, 5> Values{};
- for (std::size_t Index = 0; Index < Keys.size(); ++Index) {
- const yaml::Node *ValueNode = mappingValue(*Substitution, Keys[Index]);
- if (ValueNode == nullptr)
- return fail(Substitution->range(), "debug value substitution requires every fixed field");
- std::uint64_t Wide = 0;
- if (unsignedValue(*ValueNode, Wide, "a 32-bit debug substitution value") ||
- Wide > std::numeric_limits<std::uint32_t>::max()) {
- return true;
- }
- Values[Index] = static_cast<std::uint32_t>(Wide);
- }
- auto AddResult = Function.records().addDebugValueSubstitution(
- {.Source = {Values[0], Values[1]},
- .Destination = {Values[2], Values[3]},
- .Subregister = SubRegIndex::fromValue(Values[4])});
- if (!AddResult)
- return importError(Substitution->range(), AddResult.error());
- }
- }
-
- if (const yaml::Node *PrefetchTargets = mappingValue(Root, "prefetch-targets")) {
- if (requireKind(*PrefetchTargets, yaml::NodeKind::Sequence, "prefetch targets"))
- return true;
- for (const yaml::NodeID TargetID : PrefetchTargets->sequence()) {
- const yaml::Node *TargetNode = node(TargetID);
- std::string_view Text;
- if (TargetNode == nullptr || scalar(*TargetNode, Text, "prefetch target"))
- return true;
-
- std::size_t ContentOffset = TargetNode->range().Begin.Offset;
- if (TargetNode->scalarStyle() == yaml::ScalarStyle::SingleQuoted ||
- TargetNode->scalarStyle() == yaml::ScalarStyle::DoubleQuoted) {
- ++ContentOffset;
- }
- const auto ErrorRange = [this, ContentOffset](std::size_t Begin, std::size_t End = 1U) {
- return Result.Source.range(ContentOffset + Begin, ContentOffset + Begin + End);
- };
- const auto SkipSpace = [&Text](std::size_t &Cursor) {
- while (Cursor < Text.size() && (Text[Cursor] == ' ' || Text[Cursor] == '\t'))
- ++Cursor;
- };
- const auto ParseNumber = [&Text, &SkipSpace](std::size_t &Cursor, std::uint32_t &Value) {
- SkipSpace(Cursor);
- const std::size_t Begin = Cursor;
- while (Cursor < Text.size() && Text[Cursor] >= '0' && Text[Cursor] <= '9')
- ++Cursor;
- return Begin != Cursor && parseUnsigned32(Text.substr(Begin, Cursor - Begin), Value);
- };
-
- std::size_t Cursor = 0;
- SkipSpace(Cursor);
- if (!Text.substr(Cursor).starts_with("bb_id") ||
- (Cursor + std::string_view("bb_id").size() < Text.size() &&
- Text[Cursor + std::string_view("bb_id").size()] != ' ' &&
- Text[Cursor + std::string_view("bb_id").size()] != '\t')) {
- return fail(ErrorRange(Cursor), "expected 'bb_id'");
- }
- Cursor += std::string_view("bb_id").size();
-
- std::array<std::uint32_t, 3> Values{};
- if (!ParseNumber(Cursor, Values[0]))
- return fail(ErrorRange(0), "expected unsigned integer");
-
- SkipSpace(Cursor);
- if (Cursor < Text.size() && (Text[Cursor] == ',' || Text[Cursor] == '.')) {
- ++Cursor;
- if (!ParseNumber(Cursor, Values[1]))
- return fail(ErrorRange(0), "expected unsigned integer");
- } else if (Cursor < Text.size() && Text[Cursor] >= '0' && Text[Cursor] <= '9') {
- if (!ParseNumber(Cursor, Values[1]))
- return fail(ErrorRange(0), "expected unsigned integer");
- }
-
- SkipSpace(Cursor);
- if (Cursor >= Text.size() || Text[Cursor] != ',')
- return fail(ErrorRange(Cursor), "expected ','");
- ++Cursor;
- if (!ParseNumber(Cursor, Values[2]))
- return fail(ErrorRange(0), "expected unsigned integer");
- SkipSpace(Cursor);
- if (Cursor != Text.size())
- return fail(ErrorRange(0), "unexpected content after prefetch target");
-
- auto AddResult = Function.records().addPrefetchTarget(
- {.Block = {Values[0], Values[1]}, .CallsiteIndex = Values[2]});
- if (!AddResult)
- return importError(TargetNode->range(), AddResult.error());
- }
- }
-
- if (const yaml::Node *EntryValues = mappingValue(Root, "entry_values")) {
- if (requireKind(*EntryValues, yaml::NodeKind::Sequence, "entry values"))
- return true;
- constexpr std::array Keys{
- std::string_view{"entry-value-register"},
- std::string_view{"debug-info-variable"},
- std::string_view{"debug-info-expression"},
- std::string_view{"debug-info-location"},
- };
- for (const yaml::NodeID EntryID : EntryValues->sequence()) {
- const yaml::Node *Entry = node(EntryID);
- if (Entry == nullptr || requireKind(*Entry, yaml::NodeKind::Mapping, "entry value") ||
- validateKeys(*Entry, Keys, "entry value")) {
- return true;
- }
- const yaml::Node *RegNode = mappingValue(*Entry, "entry-value-register");
- const yaml::Node *VariableNode = mappingValue(*Entry, "debug-info-variable");
- const yaml::Node *ExpressionNode = mappingValue(*Entry, "debug-info-expression");
- const yaml::Node *LocationNode = mappingValue(*Entry, "debug-info-location");
- if (RegNode == nullptr || VariableNode == nullptr || ExpressionNode == nullptr ||
- LocationNode == nullptr) {
- return fail(Entry->range(), "entry value requires all four fixed fields");
- }
- PhysicalRegister Reg;
- if (physicalRegister(*RegNode, Reg))
- return true;
- MachineVariableDebugInfo DebugInfo;
- if (parseVariableDebugInfo(*Entry, Function, DebugInfo))
- return true;
- if (!DebugInfo.Variable || !DebugInfo.Expression || !DebugInfo.Location) {
- return fail(Entry->range(), "entry value debug metadata cannot be empty",
- "mir-debug-metadata");
- }
- auto AddResult =
- Function.records().addEntryValue({.Reg = Reg, .DebugInfo = std::move(DebugInfo)});
- if (!AddResult)
- return importError(Entry->range(), AddResult.error());
- }
- }
- return false;
-}
-
-} // namespace rcc::mir
diff --git a/backend/lib/MIR/MIRMetadataParser.cpp b/backend/lib/MIR/MIRMetadataParser.cpp
deleted file mode 100644
index 63727ee..0000000
--- a/backend/lib/MIR/MIRMetadataParser.cpp
+++ /dev/null
@@ -1,333 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include "MIRDocumentParser.h"
-#include "MIRDocumentReferenceValidation.h"
-#include "MIRMetadataTextParser.h"
-#include "MIRParserUtilities.h"
-#include "rcc/CodeGen/MachineBasicBlock.h"
-#include "rcc/CodeGen/MachineConstantPool.h"
-#include "rcc/CodeGen/MachineFrameInfo.h"
-#include "rcc/CodeGen/MachineFunction.h"
-#include "rcc/CodeGen/MachineFunctionAttributes.h"
-#include "rcc/CodeGen/MachineFunctionProperties.h"
-#include "rcc/CodeGen/MachineFunctionRecords.h"
-#include "rcc/CodeGen/MachineInstr.h"
-#include "rcc/CodeGen/MachineJumpTableInfo.h"
-#include "rcc/CodeGen/MachineMetadata.h"
-#include "rcc/CodeGen/MachineRegisterInfo.h"
-#include "rcc/CodeGen/MachineVerifier.h"
-#include "rcc/CodeGen/TargetDescription.h"
-#include "rcc/CodeGen/TargetMIRTextInfo.h"
-#include "rcc/CodeGen/TargetRegisterInfo.h"
-#include "rcc/MIR/LLVMConstantSyntax.h"
-#include "rcc/MIR/MILexer.h"
-
-#include <algorithm>
-#include <array>
-#include <cstddef>
-#include <cstdint>
-#include <initializer_list>
-#include <limits>
-#include <optional>
-#include <ranges>
-#include <span>
-#include <string>
-#include <string_view>
-#include <unordered_map>
-#include <unordered_set>
-#include <utility>
-#include <vector>
-
-namespace rcc::mir {
-
-using parser_detail::parseBool;
-using parser_detail::parsePrefixedID;
-using parser_detail::parseSigned;
-using parser_detail::parseUnsigned;
-using parser_detail::parseUnsigned32;
-using parser_detail::trim;
-
-Expected<MachineMetadataReference>
-MIRDocumentParser::resolveMetadataReference(const MachineFunction &Function,
- std::uint32_t Slot) const {
- if (ActiveDocument != nullptr && ActiveDocument->EmbeddedIR &&
- ActiveDocument->EmbeddedIR->metadata(std::to_string(Slot)) != nullptr) {
- return MachineMetadataReference::embeddedIR(Slot);
- }
- if (Function.metadata().node(Slot) != nullptr)
- return MachineMetadataReference::machineFunction(Slot);
- return makeUnexpected(ErrorCode::ParseError,
- "metadata reference uses undefined slot '!" + std::to_string(Slot) + "'");
-}
-
-bool MIRDocumentParser::parseVariableDebugInfo(const yaml::Node &Entry, MachineFunction &Function,
- MachineVariableDebugInfo &DebugInfo) {
- const auto Resolve = [this, &Function](std::uint32_t Slot) {
- return resolveMetadataReference(Function, Slot);
- };
- if (const yaml::Node *VariableNode = mappingValue(Entry, "debug-info-variable")) {
- std::string_view Text;
- if (scalar(*VariableNode, Text, "debug variable"))
- return true;
- if (!Text.empty()) {
- MetadataTextParser Parser(std::string(Text), Resolve);
- auto Reference = Parser.parseReferenceOnly();
- if (!Reference)
- return importError(VariableNode->range(), Reference.error(), "mir-debug-metadata");
- if (Reference->scope() != MachineMetadataScope::EmbeddedIR) {
- return fail(VariableNode->range(),
- "debug variable must reference embedded LLVM IR metadata",
- "mir-debug-metadata");
- }
- DebugInfo.Variable = *Reference;
- }
- }
- if (const yaml::Node *ExpressionNode = mappingValue(Entry, "debug-info-expression")) {
- std::string_view Text;
- if (scalar(*ExpressionNode, Text, "debug expression"))
- return true;
- if (!Text.empty()) {
- MetadataTextParser Parser(std::string(Text), Resolve);
- auto Value = Parser.parseValue();
- if (!Value)
- return importError(scalarDiagnosticRange(*ExpressionNode, Parser.diagnosticRange()),
- Value.error(), "mir-debug-metadata");
- if (Value->reference() != nullptr &&
- Value->reference()->scope() != MachineMetadataScope::EmbeddedIR) {
- return fail(ExpressionNode->range(),
- "debug expression reference must use embedded LLVM IR metadata",
- "mir-debug-metadata");
- }
- DebugInfo.Expression = std::move(*Value);
- }
- }
- if (const yaml::Node *LocationNode = mappingValue(Entry, "debug-info-location")) {
- std::string_view Text;
- if (scalar(*LocationNode, Text, "debug location"))
- return true;
- if (!Text.empty()) {
- MetadataTextParser Parser(std::string(Text), Resolve);
- auto Location = Parser.parseLocation();
- if (!Location)
- return importError(LocationNode->range(), Location.error(), "mir-debug-metadata");
- if (Location->reference() != nullptr &&
- Location->reference()->scope() != MachineMetadataScope::EmbeddedIR) {
- return fail(LocationNode->range(),
- "variable debug location must reference embedded LLVM IR metadata",
- "mir-debug-metadata");
- }
- DebugInfo.Location = std::move(*Location);
- }
- }
- if (!DebugInfo.Variable && !DebugInfo.Expression && !DebugInfo.Location)
- return false;
- auto Verification = DebugInfo.verifyStructure();
- if (!Verification)
- return importError(Entry.range(), Verification.error(), "mir-debug-metadata");
- return false;
-}
-
-bool MIRDocumentParser::parseMetadata(const yaml::Node &Root, MachineFunction &Function,
- MIParserContext &Context) {
- if (ActiveDocument->EmbeddedIR) {
- for (const EmbeddedIRMetadataDefinition &Reference :
- ActiveDocument->EmbeddedIR->metadataDefinitions()) {
- std::uint32_t ID = 0;
- if (!parseUnsigned32(Reference.Name, ID))
- continue;
- if (std::ranges::any_of(Context.Metadata,
- [ID](const MIMetadataSlot &Slot) { return Slot.TextID == ID; })) {
- return fail(Root.range(), "embedded LLVM IR metadata slots are not unique");
- }
- Context.Metadata.push_back(
- {.TextID = ID, .Reference = MachineMetadataReference::embeddedIR(ID)});
- }
- }
-
- const yaml::Node *Metadata = mappingValue(Root, "machineMetadataNodes");
- if (Metadata == nullptr)
- return false;
- if (requireKind(*Metadata, yaml::NodeKind::Sequence, "machine metadata nodes"))
- return true;
-
- enum class ParsedElementKind : std::uint8_t {
- Null,
- Reference,
- String,
- };
- struct ParsedElement final {
- ParsedElementKind Kind = ParsedElementKind::Reference;
- std::uint32_t Reference = 0;
- std::string String;
- TextRange Range;
- };
- struct Definition final {
- const yaml::Node *Node = nullptr;
- std::uint32_t Slot = 0;
- bool IsDistinct = false;
- std::vector<ParsedElement> Elements;
- };
- std::vector<Definition> Definitions;
- std::unordered_set<std::uint32_t> Slots;
-
- const auto TranslateRange = [this](const yaml::Node &Node, const TextRange &Range) {
- std::size_t ContentBegin = Node.range().Begin.Offset;
- if (Node.scalarStyle() == yaml::ScalarStyle::SingleQuoted ||
- Node.scalarStyle() == yaml::ScalarStyle::DoubleQuoted) {
- ++ContentBegin;
- }
- return Result.Source.range(ContentBegin + Range.Begin.Offset, ContentBegin + Range.End.Offset);
- };
-
- for (const yaml::NodeID DefinitionID : Metadata->sequence()) {
- const yaml::Node *DefinitionNode = node(DefinitionID);
- std::string_view Text;
- if (DefinitionNode == nullptr || scalar(*DefinitionNode, Text, "machine metadata definition"))
- return true;
-
- MILexer Lexer("machine-metadata", std::string(Text));
- MIToken Token = Lexer.next();
- const auto LexerFailed = [this, &Lexer, DefinitionNode, &TranslateRange, &Token]() -> bool {
- if (!Token.is(MITokenKind::Error))
- return false;
- const auto Diagnostics = Lexer.diagnostics();
- const TextRange Range = Diagnostics.empty()
- ? TranslateRange(*DefinitionNode, Token.range())
- : TranslateRange(*DefinitionNode, Diagnostics.front().Range);
- return fail(Range, Diagnostics.empty() ? "invalid machine metadata node"
- : Diagnostics.front().Message);
- };
- const auto Advance = [&Lexer, &Token, &LexerFailed]() -> bool {
- Token = Lexer.next();
- return LexerFailed();
- };
- const auto FailAtToken = [this, DefinitionNode, &TranslateRange](const MIToken &At,
- std::string Message) {
- return fail(TranslateRange(*DefinitionNode, At.range()), std::move(Message));
- };
-
- if (LexerFailed())
- return true;
- if (!Token.is(MITokenKind::Exclaim))
- return FailAtToken(Token, "expected a metadata node");
- if (Advance())
- return true;
- std::uint32_t Slot = 0;
- if (!Token.is(MITokenKind::IntegerLiteral) || !parseUnsigned32(Token.integerValue(), Slot)) {
- return FailAtToken(Token, "expected metadata id after '!'");
- }
- if (Advance())
- return true;
- if (!Token.is(MITokenKind::Equal))
- return FailAtToken(Token, "expected '='");
- if (Advance())
- return true;
-
- const bool IsDistinct = Token.isKeyword("distinct");
- if (IsDistinct && Advance())
- return true;
- if (!Token.is(MITokenKind::Exclaim))
- return FailAtToken(Token, "expected a metadata node");
- if (Advance())
- return true;
- if (!Token.is(MITokenKind::LeftBrace))
- return FailAtToken(Token, "expected '{' here");
- if (Advance())
- return true;
-
- std::vector<ParsedElement> Elements;
- if (!Token.is(MITokenKind::RightBrace)) {
- while (true) {
- if (Token.hasStringValue() && Token.stringValue() == "null") {
- Elements.push_back({.Kind = ParsedElementKind::Null,
- .Reference = 0,
- .String = {},
- .Range = TranslateRange(*DefinitionNode, Token.range())});
- } else {
- if (!Token.is(MITokenKind::Exclaim))
- return FailAtToken(Token, "expected '!' here");
- const TextRange ReferenceRange = TranslateRange(*DefinitionNode, Token.range());
- if (Advance())
- return true;
-
- if (Token.is(MITokenKind::StringConstant)) {
- Elements.push_back({.Kind = ParsedElementKind::String,
- .Reference = 0,
- .String = std::string(Token.stringValue()),
- .Range = TranslateRange(*DefinitionNode, Token.range())});
- } else {
- std::uint32_t Reference = 0;
- if (!Token.is(MITokenKind::IntegerLiteral) ||
- !parseUnsigned32(Token.integerValue(), Reference)) {
- return FailAtToken(Token, "expected metadata id after '!'");
- }
- Elements.push_back({.Kind = ParsedElementKind::Reference,
- .Reference = Reference,
- .String = {},
- .Range = ReferenceRange});
- }
- }
- if (Advance())
- return true;
- if (!Token.is(MITokenKind::Comma))
- break;
- if (Advance())
- return true;
- }
- }
- if (!Token.is(MITokenKind::RightBrace))
- return FailAtToken(Token, "expected end of metadata node");
- if (Advance())
- return true;
- if (!Token.is(MITokenKind::EndOfFile))
- return FailAtToken(Token, "expected end of metadata node");
- if (!Slots.insert(Slot).second)
- return FailAtToken(Token, "Metadata id is already used");
-
- Definitions.push_back({.Node = DefinitionNode,
- .Slot = Slot,
- .IsDistinct = IsDistinct,
- .Elements = std::move(Elements)});
- Context.Metadata.push_back(
- {.TextID = Slot, .Reference = MachineMetadataReference::machineFunction(Slot)});
- }
-
- for (const Definition &Definition : Definitions) {
- MachineMetadataNode NewNode{
- .Slot = Definition.Slot,
- .IsDistinct = Definition.IsDistinct,
- .Elements = {},
- };
- for (const ParsedElement &Element : Definition.Elements) {
- if (Element.Kind == ParsedElementKind::Null) {
- NewNode.Elements.push_back(MachineMetadataElement::null());
- continue;
- }
- if (Element.Kind == ParsedElementKind::String) {
- NewNode.Elements.push_back(MachineMetadataElement::string(Element.String));
- continue;
- }
-
- MachineMetadataReference Reference;
- if (ActiveDocument->EmbeddedIR != std::nullopt &&
- ActiveDocument->EmbeddedIR->metadata(std::to_string(Element.Reference)) != nullptr) {
- Reference = MachineMetadataReference::embeddedIR(Element.Reference);
- } else if (Slots.contains(Element.Reference)) {
- Reference = MachineMetadataReference::machineFunction(Element.Reference);
- } else {
- return fail(Element.Range,
- "use of undefined metadata '!" + std::to_string(Element.Reference) + "'");
- }
- auto Resolved = MachineMetadataElement::reference(Reference);
- if (!Resolved)
- return importError(Element.Range, Resolved.error());
- NewNode.Elements.push_back(std::move(*Resolved));
- }
- auto AddResult = Function.metadata().addNode(std::move(NewNode));
- if (!AddResult)
- return importError(Definition.Node->range(), AddResult.error());
- }
- return false;
-}
-
-} // namespace rcc::mir
diff --git a/backend/lib/MIR/MIRMetadataTextParser.cpp b/backend/lib/MIR/MIRMetadataTextParser.cpp
deleted file mode 100644
index 7875b06..0000000
--- a/backend/lib/MIR/MIRMetadataTextParser.cpp
+++ /dev/null
@@ -1,259 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include "MIRMetadataTextParser.h"
-
-#include "MIRParserUtilities.h"
-#include "rcc/MIR/MIDebugSyntax.h"
-
-#include <cstdint>
-#include <limits>
-#include <optional>
-#include <string>
-#include <string_view>
-#include <unordered_set>
-#include <utility>
-#include <vector>
-
-namespace rcc::mir {
-
-using parser_detail::parseSigned;
-using parser_detail::parseUnsigned;
-using parser_detail::parseUnsigned32;
-
-Expected<void> MetadataTextParser::expect(MITokenKind Kind, std::string_view Description) {
- if (consume(Kind))
- return {};
- return makeUnexpected(ErrorCode::ParseError,
- "expected " + std::string(Description) + " in MIR metadata scalar");
-}
-
-Expected<void> MetadataTextParser::finish() {
- while (consume(MITokenKind::Newline)) {
- }
- if (Lexer.failed()) {
- if (!Lexer.diagnostics().empty()) {
- return makeUnexpected(ErrorCode::ParseError,
- std::string(Lexer.diagnostics().front().Message));
- }
- return makeUnexpected(ErrorCode::ParseError, "invalid MIR metadata scalar");
- }
- if (!at(MITokenKind::EndOfFile))
- return makeUnexpected(ErrorCode::ParseError, "unexpected trailing MIR metadata tokens");
- return {};
-}
-
-Expected<MachineMetadataReference> MetadataTextParser::parseReference() {
- if (auto Exclaim = expect(MITokenKind::Exclaim, "'!' before a metadata slot"); !Exclaim)
- return std::unexpected(Exclaim.error());
- if (!at(MITokenKind::IntegerLiteral))
- return makeUnexpected(ErrorCode::ParseError, "expected a 32-bit metadata slot");
- std::uint32_t Slot = 0;
- if (!parseUnsigned32(token().integerValue(), Slot))
- return makeUnexpected(ErrorCode::ParseError, "metadata slot is outside the 32-bit range");
- advance();
- return Resolve(Slot);
-}
-
-Expected<MachineMetadataReference> MetadataTextParser::parseReferenceOnly() {
- auto Reference = parseReference();
- if (!Reference)
- return std::unexpected(Reference.error());
- if (auto Finished = finish(); !Finished)
- return std::unexpected(Finished.error());
- return Reference;
-}
-
-Expected<MachineDIExpression> MetadataTextParser::parseExpression() {
- if (!at(MITokenKind::MetadataKeyword) || !token().isMetadataKeyword("!DIExpression")) {
- return makeUnexpected(ErrorCode::ParseError, "expected an inline !DIExpression");
- }
- advance();
- if (auto Left = expect(MITokenKind::LeftParen, "'(' after !DIExpression"); !Left)
- return std::unexpected(Left.error());
- std::vector<std::uint64_t> Elements;
- while (!at(MITokenKind::RightParen)) {
- if (at(MITokenKind::Identifier)) {
- const auto Opcode = parseDIExpressionOpcodeName(token().stringValue());
- const auto Encoding = parseDIExpressionAttributeEncodingName(token().stringValue());
- if (!Opcode && !Encoding)
- return makeUnexpected(ErrorCode::ParseError,
- invalidDIExpressionElementMessage(token().stringValue()));
- Elements.push_back(Opcode ? *Opcode : *Encoding);
- advance();
- } else if (at(MITokenKind::IntegerLiteral)) {
- std::int64_t Signed = 0;
- std::uint64_t Unsigned = 0;
- if (parseSigned(token().integerValue(), Signed))
- Elements.push_back(static_cast<std::uint64_t>(Signed));
- else if (parseUnsigned(token().integerValue(), Unsigned))
- Elements.push_back(Unsigned);
- else
- return makeUnexpected(ErrorCode::ParseError, "DIExpression integer exceeds 64 bits");
- advance();
- } else {
- return makeUnexpected(ErrorCode::ParseError, "expected a DIExpression opcode or integer");
- }
- if (!consume(MITokenKind::Comma))
- break;
- }
- if (auto Right = expect(MITokenKind::RightParen, "')' after !DIExpression"); !Right)
- return std::unexpected(Right.error());
- return MachineDIExpression(std::move(Elements));
-}
-
-Expected<MachineMetadataValue> MetadataTextParser::parseValue() {
- MachineMetadataValue Value;
- if (at(MITokenKind::Exclaim)) {
- auto Reference = parseReference();
- if (!Reference)
- return std::unexpected(Reference.error());
- auto Created = MachineMetadataValue::reference(*Reference);
- if (!Created)
- return std::unexpected(Created.error());
- Value = std::move(*Created);
- } else {
- auto Expression = parseExpression();
- if (!Expression)
- return std::unexpected(Expression.error());
- Value = MachineMetadataValue::expression(std::move(*Expression));
- }
- if (auto Finished = finish(); !Finished)
- return std::unexpected(Finished.error());
- return Value;
-}
-
-Expected<void>
-MetadataTextParser::parseDILocation(std::vector<MachineDILocationFrame> &Frames,
- std::optional<MachineMetadataReference> &Terminal) {
- if (!at(MITokenKind::MetadataKeyword) || !token().isMetadataKeyword("!DILocation")) {
- return makeUnexpected(ErrorCode::ParseError, "expected an inline !DILocation");
- }
- advance();
- if (auto Left = expect(MITokenKind::LeftParen, "'(' after !DILocation"); !Left)
- return Left;
-
- MachineDILocationFrame Frame;
- bool HasLine = false;
- bool HasScope = false;
- std::vector<MachineDILocationFrame> NestedFrames;
- std::optional<MachineMetadataReference> NestedTerminal;
- std::unordered_set<std::string> Seen;
- while (!at(MITokenKind::RightParen)) {
- if (!at(MITokenKind::Identifier))
- return makeUnexpected(ErrorCode::ParseError, "expected a DILocation field name");
- const std::string Field(token().stringValue());
- if (!Seen.insert(Field).second) {
- return makeUnexpected(ErrorCode::ParseError, "duplicate DILocation field '" + Field + "'");
- }
- advance();
- if (auto Colon = expect(MITokenKind::Colon, "':' after a DILocation field"); !Colon)
- return Colon;
-
- if (Field == "line") {
- std::uint32_t Value = 0;
- if (!at(MITokenKind::IntegerLiteral) || !parseUnsigned32(token().integerValue(), Value)) {
- return makeUnexpected(ErrorCode::ParseError,
- "DILocation line must be an unsigned 32-bit integer");
- }
- Frame.Line = Value;
- HasLine = true;
- advance();
- } else if (Field == "column") {
- std::uint64_t Value = 0;
- if (!at(MITokenKind::IntegerLiteral) || !parseUnsigned(token().integerValue(), Value) ||
- Value > std::numeric_limits<std::uint16_t>::max()) {
- return makeUnexpected(ErrorCode::ParseError,
- "DILocation column must be an unsigned 16-bit integer");
- }
- Frame.Column = static_cast<std::uint16_t>(Value);
- advance();
- } else if (Field == "scope") {
- auto Scope = parseReference();
- if (!Scope)
- return std::unexpected(Scope.error());
- if (Scope->scope() != MachineMetadataScope::EmbeddedIR) {
- return makeUnexpected(ErrorCode::ParseError,
- "DILocation scope must reference embedded LLVM IR metadata");
- }
- Frame.Scope = *Scope;
- HasScope = true;
- } else if (Field == "inlinedAt") {
- if (at(MITokenKind::MetadataKeyword) && token().isMetadataKeyword("!DILocation")) {
- if (auto Nested = parseDILocation(NestedFrames, NestedTerminal); !Nested)
- return Nested;
- } else {
- auto Reference = parseReference();
- if (!Reference)
- return std::unexpected(Reference.error());
- if (Reference->scope() != MachineMetadataScope::EmbeddedIR) {
- return makeUnexpected(ErrorCode::ParseError,
- "DILocation inlinedAt must reference embedded LLVM IR metadata");
- }
- NestedTerminal = *Reference;
- }
- } else if (Field == "isImplicitCode") {
- if (!at(MITokenKind::Identifier) ||
- (token().stringValue() != "true" && token().stringValue() != "false")) {
- return makeUnexpected(ErrorCode::ParseError,
- "DILocation isImplicitCode must be true or false");
- }
- Frame.IsImplicitCode = token().stringValue() == "true";
- advance();
- } else if (Field == "atomGroup") {
- std::uint64_t Value = 0;
- if (!at(MITokenKind::IntegerLiteral) || !parseUnsigned(token().integerValue(), Value) ||
- Value > MachineDILocation::MaxAtomGroup) {
- return makeUnexpected(ErrorCode::ParseError, "DILocation atomGroup exceeds 61 bits");
- }
- Frame.AtomGroup = Value;
- advance();
- } else if (Field == "atomRank") {
- std::uint64_t Value = 0;
- if (!at(MITokenKind::IntegerLiteral) || !parseUnsigned(token().integerValue(), Value) ||
- Value > 7) {
- return makeUnexpected(ErrorCode::ParseError, "DILocation atomRank exceeds three bits");
- }
- Frame.AtomRank = static_cast<std::uint8_t>(Value);
- advance();
- } else {
- return makeUnexpected(ErrorCode::ParseError, "unknown DILocation field '" + Field + "'");
- }
- if (!consume(MITokenKind::Comma))
- break;
- }
- if (auto Right = expect(MITokenKind::RightParen, "')' after !DILocation"); !Right)
- return Right;
- if (!HasLine || !HasScope)
- return makeUnexpected(ErrorCode::ParseError, "DILocation requires line and scope fields");
- Frames.push_back(Frame);
- Frames.insert(Frames.end(), NestedFrames.begin(), NestedFrames.end());
- Terminal = NestedTerminal;
- return {};
-}
-
-Expected<MachineDebugLocation> MetadataTextParser::parseLocation() {
- MachineDebugLocation Location;
- if (at(MITokenKind::Exclaim)) {
- auto Reference = parseReference();
- if (!Reference)
- return std::unexpected(Reference.error());
- auto Created = MachineDebugLocation::reference(*Reference);
- if (!Created)
- return std::unexpected(Created.error());
- Location = std::move(*Created);
- } else {
- std::vector<MachineDILocationFrame> Frames;
- std::optional<MachineMetadataReference> Terminal;
- if (auto Parsed = parseDILocation(Frames, Terminal); !Parsed)
- return std::unexpected(Parsed.error());
- auto Created = MachineDILocation::create(std::move(Frames), Terminal);
- if (!Created)
- return std::unexpected(Created.error());
- Location = MachineDebugLocation::inlineLocation(std::move(*Created));
- }
- if (auto Finished = finish(); !Finished)
- return std::unexpected(Finished.error());
- return Location;
-}
-
-} // namespace rcc::mir
diff --git a/backend/lib/MIR/MIRMetadataTextParser.h b/backend/lib/MIR/MIRMetadataTextParser.h
deleted file mode 100644
index 032523d..0000000
--- a/backend/lib/MIR/MIRMetadataTextParser.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-// NOLINTNEXTLINE(llvm-header-guard)
-#ifndef RCC_LIB_MIR_MIRMETADATATEXTPARSER_H
-#define RCC_LIB_MIR_MIRMETADATATEXTPARSER_H
-
-#include "rcc/CodeGen/MachineDebugInfo.h"
-#include "rcc/CodeGen/MachineMetadata.h"
-#include "rcc/MIR/MILexer.h"
-#include "rcc/Support/Error.h"
-
-#include <cstddef>
-#include <cstdint>
-#include <functional>
-#include <optional>
-#include <string>
-#include <string_view>
-#include <utility>
-#include <vector>
-
-namespace rcc::mir {
-
-class MetadataTextParser final {
-public:
- using Resolver = std::function<Expected<MachineMetadataReference>(std::uint32_t Slot)>;
-
- MetadataTextParser(std::string Text, Resolver Resolve)
- : Lexer("MIR metadata scalar", std::move(Text)), Resolve(std::move(Resolve)) {
- do {
- Tokens.push_back(Lexer.next());
- } while (!Tokens.back().isErrorOrEnd());
- }
-
- [[nodiscard]] Expected<MachineMetadataReference> parseReferenceOnly();
- [[nodiscard]] Expected<MachineMetadataValue> parseValue();
- [[nodiscard]] Expected<MachineDebugLocation> parseLocation();
-
- [[nodiscard]] const TextRange &diagnosticRange() const noexcept {
- return token().range();
- }
-
-private:
- [[nodiscard]] const MIToken &token() const noexcept {
- return Tokens[Position];
- }
- [[nodiscard]] bool at(MITokenKind Kind) const noexcept {
- return token().is(Kind);
- }
- void advance() noexcept {
- if (Position + 1U < Tokens.size())
- ++Position;
- }
- [[nodiscard]] bool consume(MITokenKind Kind) noexcept {
- if (!at(Kind))
- return false;
- advance();
- return true;
- }
- [[nodiscard]] Expected<void> expect(MITokenKind Kind, std::string_view Description);
- [[nodiscard]] Expected<void> finish();
- [[nodiscard]] Expected<MachineMetadataReference> parseReference();
- [[nodiscard]] Expected<MachineDIExpression> parseExpression();
- [[nodiscard]] Expected<void> parseDILocation(std::vector<MachineDILocationFrame> &Frames,
- std::optional<MachineMetadataReference> &Terminal);
-
- MILexer Lexer;
- Resolver Resolve;
- std::vector<MIToken> Tokens;
- std::size_t Position = 0;
-};
-
-} // namespace rcc::mir
-
-#endif // RCC_LIB_MIR_MIRMETADATATEXTPARSER_H
diff --git a/backend/lib/MIR/MIRParserUtilities.h b/backend/lib/MIR/MIRParserUtilities.h
deleted file mode 100644
index 2f69548..0000000
--- a/backend/lib/MIR/MIRParserUtilities.h
+++ /dev/null
@@ -1,85 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-// NOLINTNEXTLINE(llvm-header-guard)
-#ifndef RCC_LIB_MIR_MIRPARSERUTILITIES_H
-#define RCC_LIB_MIR_MIRPARSERUTILITIES_H
-
-#include <charconv>
-#include <cstdint>
-#include <limits>
-#include <optional>
-#include <string_view>
-
-namespace rcc::mir::parser_detail {
-
-[[nodiscard]] inline std::string_view trim(std::string_view Text) noexcept {
- while (!Text.empty() && (Text.front() == ' ' || Text.front() == '\t' || Text.front() == '\r' ||
- Text.front() == '\n')) {
- Text.remove_prefix(1);
- }
- while (!Text.empty() && (Text.back() == ' ' || Text.back() == '\t' || Text.back() == '\r' ||
- Text.back() == '\n')) {
- Text.remove_suffix(1);
- }
- return Text;
-}
-
-[[nodiscard]] inline bool parseUnsigned(std::string_view Text, std::uint64_t &Value) noexcept {
- Text = trim(Text);
- int Base = 10;
- if (Text.starts_with("0x") || Text.starts_with("0X")) {
- Text.remove_prefix(2);
- Base = 16;
- }
- if (Text.empty())
- return false;
- const auto [End, Error] = std::from_chars(Text.data(), Text.data() + Text.size(), Value, Base);
- return Error == std::errc{} && End == Text.data() + Text.size();
-}
-
-[[nodiscard]] inline bool parseSigned(std::string_view Text, std::int64_t &Value) noexcept {
- Text = trim(Text);
- if (Text.empty())
- return false;
- const auto [End, Error] = std::from_chars(Text.data(), Text.data() + Text.size(), Value, 10);
- return Error == std::errc{} && End == Text.data() + Text.size();
-}
-
-[[nodiscard]] inline bool parseUnsigned32(std::string_view Text, std::uint32_t &Value) noexcept {
- std::uint64_t Wide = 0;
- if (!parseUnsigned(Text, Wide) || Wide > std::numeric_limits<std::uint32_t>::max())
- return false;
- Value = static_cast<std::uint32_t>(Wide);
- return true;
-}
-
-[[nodiscard]] inline bool parseBool(std::string_view Text, bool &Value) noexcept {
- if (Text == "true") {
- Value = true;
- return true;
- }
- if (Text == "false") {
- Value = false;
- return true;
- }
- return false;
-}
-
-[[nodiscard]] inline std::optional<std::uint32_t>
-parsePrefixedID(std::string_view Text, std::string_view Prefix) noexcept {
- Text = trim(Text);
- if (!Text.starts_with(Prefix))
- return std::nullopt;
- Text.remove_prefix(Prefix.size());
- const std::size_t Suffix = Text.find_first_of(". \t");
- if (Suffix != std::string_view::npos)
- Text = Text.substr(0, Suffix);
- std::uint32_t ID = 0;
- if (!parseUnsigned32(Text, ID))
- return std::nullopt;
- return ID;
-}
-
-} // namespace rcc::mir::parser_detail
-
-#endif // RCC_LIB_MIR_MIRPARSERUTILITIES_H