aboutsummaryrefslogtreecommitdiff
path: root/backend/lib/CodeGen/LowLevelType.cpp
blob: 50ee0e681d5c91442d6deb25b214ae3e02f90a77 (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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// SPDX-License-Identifier: GPL-3.0-or-later

#include "rcc/CodeGen/LowLevelType.h"

#include <array>
#include <string>

namespace rcc {
namespace {

[[nodiscard]] LowLevelType::Kind getVectorKind(LowLevelType ElementType) noexcept {
  switch (ElementType.kind()) {
  case LowLevelType::Kind::CategoryNeutralScalar:
    return LowLevelType::Kind::Vector;
  case LowLevelType::Kind::Pointer:
    return LowLevelType::Kind::VectorPointer;
  case LowLevelType::Kind::Invalid:
  case LowLevelType::Kind::Token:
  case LowLevelType::Kind::Vector:
  case LowLevelType::Kind::VectorPointer:
    return LowLevelType::Kind::Invalid;
  }

  return LowLevelType::Kind::Invalid;
}

} // namespace

Expected<LowLevelType> LowLevelType::makeCategoryNeutralScalar(std::uint64_t BitWidth) {
  if (BitWidth == 0 || BitWidth > MaxBitWidth) {
    return makeUnexpected(ErrorCode::InvalidArgument,
                          "LowLevelType bit width must be in the range [1, 65535]");
  }

  return LowLevelType(
      encode(Kind::CategoryNeutralScalar, static_cast<std::uint32_t>(BitWidth), 0, 0, false));
}

Expected<LowLevelType> LowLevelType::makePointer(std::uint64_t AddressSpace,
                                                 std::uint64_t BitWidth) {
  if (BitWidth == 0 || BitWidth > MaxBitWidth) {
    return makeUnexpected(ErrorCode::InvalidArgument,
                          "LowLevelType pointer bit width must be in the range [1, 65535]");
  }
  if (AddressSpace > MaxAddressSpace) {
    return makeUnexpected(ErrorCode::InvalidArgument,
                          "LowLevelType address space must fit in 24 bits");
  }

  return LowLevelType(encode(Kind::Pointer, static_cast<std::uint32_t>(BitWidth), 0,
                             static_cast<std::uint32_t>(AddressSpace), false));
}

Expected<LowLevelType> LowLevelType::makeFixedVector(std::uint64_t ElementCount,
                                                     LowLevelType ElementType) {
  return makeVector(ElementCount, false, ElementType);
}

Expected<LowLevelType> LowLevelType::makeScalableVector(std::uint64_t MinimumElementCount,
                                                        LowLevelType ElementType) {
  return makeVector(MinimumElementCount, true, ElementType);
}

Expected<LowLevelType> LowLevelType::makeVector(std::uint64_t ElementCount, bool IsScalable,
                                                LowLevelType ElementType) {
  if (ElementCount == 0 || ElementCount > MaxElementCount) {
    return makeUnexpected(ErrorCode::InvalidArgument,
                          "LowLevelType vector element count must be in the range [1, 65535]");
  }
  if (!IsScalable && ElementCount == 1) {
    return makeUnexpected(ErrorCode::InvalidArgument,
                          "a fixed LowLevelType vector must contain at least two elements");
  }

  const Kind VectorKind = getVectorKind(ElementType);
  if (VectorKind == Kind::Invalid) {
    return makeUnexpected(ErrorCode::InvalidArgument,
                          "LowLevelType vector elements must be non-vector value types");
  }

  std::uint32_t Auxiliary = 0;
  if (ElementType.isPointer())
    Auxiliary = *ElementType.addressSpace();

  return LowLevelType(encode(VectorKind, ElementType.scalarBitWidth(),
                             static_cast<std::uint32_t>(ElementCount), Auxiliary, IsScalable));
}

std::optional<std::uint32_t> LowLevelType::addressSpace() const noexcept {
  if (!isPointerOrPointerVector())
    return std::nullopt;
  return auxiliaryValue();
}

std::optional<LowLevelType> LowLevelType::scalarElementType() const noexcept {
  switch (kind()) {
  case Kind::Vector:
    return LowLevelType(encode(Kind::CategoryNeutralScalar, scalarBitWidth(), 0, 0, false));
  case Kind::VectorPointer:
    return LowLevelType(encode(Kind::Pointer, scalarBitWidth(), 0, auxiliaryValue(), false));
  case Kind::Invalid:
  case Kind::Token:
  case Kind::CategoryNeutralScalar:
  case Kind::Pointer:
    return std::nullopt;
  }

  return std::nullopt;
}

std::string LowLevelType::toString() const {
  if (!isValid())
    return "LLT_invalid";
  if (isToken())
    return "s0";

  std::string ScalarSpelling;
  switch (kind()) {
  case Kind::CategoryNeutralScalar:
  case Kind::Vector:
    ScalarSpelling = "s" + std::to_string(scalarBitWidth());
    break;
  case Kind::Pointer:
  case Kind::VectorPointer:
    ScalarSpelling =
        "p" + std::to_string(auxiliaryValue()) + ":" + std::to_string(scalarBitWidth());
    break;
  case Kind::Invalid:
  case Kind::Token:
    break;
  }

  if (!isVector())
    return ScalarSpelling;

  std::string Result = "<";
  if (isScalableVector())
    Result += "vscale x ";
  Result += std::to_string(minimumElementCount());
  Result += " x ";
  Result += ScalarSpelling;
  Result += ">";
  return Result;
}

} // namespace rcc