aboutsummaryrefslogtreecommitdiff
path: root/backend/lib/MC/MCContext.cpp
blob: 2aa4c0ecdfb98de1de79dd8d60a26f3de91bb0d9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// SPDX-License-Identifier: GPL-3.0-or-later

#include "rcc/MC/MCContext.h"

#include <cstdint>
#include <limits>
#include <memory>
#include <string>
#include <string_view>
#include <utility>

namespace rcc::mc {
namespace {

[[nodiscard]] bool isValidName(std::string_view Name) noexcept {
  if (Name.empty())
    return false;
  for (const char RawCharacter : Name) {
    const auto Character = static_cast<unsigned char>(RawCharacter);
    if (Character == 0 || Character == '\n' || Character == '\r' || Character == 0x7fU)
      return false;
  }
  return true;
}

} // namespace

Expected<MCSymbolRef> MCContext::getOrCreateSymbol(std::string Name, MCSymbolKind Kind) {
  if (!isValidName(Name))
    return makeUnexpected(ErrorCode::InvalidArgument, "MC symbol has an invalid name");

  const auto Position = Symbols.find(Name);
  if (Position != Symbols.end()) {
    const MCSymbolKind ExistingKind = Position->second->kind();
    if (Kind != MCSymbolKind::Generic && ExistingKind != MCSymbolKind::Generic &&
        ExistingKind != Kind) {
      return makeUnexpected(ErrorCode::InvalidArgument,
                            "MC symbol name is already used by a different symbol kind");
    }
    return Position->second;
  }

  MCSymbolRef Result(new MCSymbol(std::move(Name), Kind));
  Symbols.emplace(std::string(Result->name()), Result);
  return Result;
}

Expected<MCSymbolRef> MCContext::createTemporarySymbol(std::string_view Prefix) {
  if (!isValidName(Prefix))
    return makeUnexpected(ErrorCode::InvalidArgument, "temporary MC symbol prefix is invalid");
  if (NextTemporarySymbol == std::numeric_limits<std::uint64_t>::max()) {
    return makeUnexpected(ErrorCode::InternalError, "temporary MC symbol sequence is exhausted");
  }

  while (true) {
    std::string Name(Prefix);
    Name += std::to_string(NextTemporarySymbol++);
    if (Symbols.contains(Name))
      continue;
    return getOrCreateSymbol(std::move(Name), MCSymbolKind::Temporary);
  }
}

MCSymbolRef MCContext::symbol(std::string_view Name) const noexcept {
  const auto Position = Symbols.find(Name);
  return Position == Symbols.end() ? MCSymbolRef{} : Position->second;
}

Expected<MCSectionRef> MCContext::getOrCreateSection(MCSectionDesc Description) {
  auto Verification = Description.verify();
  if (!Verification)
    return std::unexpected(Verification.error());

  const auto Position = Sections.find(Description.Name);
  if (Position != Sections.end()) {
    MCSectionDesc ExistingDescription = Position->second->description();
    ExistingDescription.Alignment = Description.Alignment;
    if (ExistingDescription != Description) {
      return makeUnexpected(ErrorCode::InvalidArgument,
                            "MC section name is already used by a different description");
    }
    return Position->second;
  }

  MCSectionRef Result(new MCSection(std::move(Description)));
  Sections.emplace(std::string(Result->name()), Result);
  return Result;
}

MCSectionRef MCContext::section(std::string_view Name) const noexcept {
  const auto Position = Sections.find(Name);
  return Position == Sections.end() ? MCSectionRef{} : Position->second;
}

} // namespace rcc::mc