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
|
// SPDX-License-Identifier: GPL-3.0-or-later
#include "rcc/Target/RISCV/RISCVSubtarget.h"
#include <array>
#include <cstddef>
#include <string_view>
namespace rcc::riscv {
namespace {
struct ExtensionName final {
std::string_view Name;
RISCVExtension Extension;
};
constexpr std::array ExtensionNames{
ExtensionName{"i", RISCVExtension::I},
ExtensionName{"m", RISCVExtension::M},
ExtensionName{"a", RISCVExtension::A},
ExtensionName{"f", RISCVExtension::F},
ExtensionName{"d", RISCVExtension::D},
ExtensionName{"c", RISCVExtension::C},
ExtensionName{"zicsr", RISCVExtension::Zicsr},
ExtensionName{"zifencei", RISCVExtension::Zifencei},
ExtensionName{"zacas", RISCVExtension::Zacas},
ExtensionName{"zabha", RISCVExtension::Zabha},
};
[[nodiscard]] constexpr std::uint16_t extensionBit(RISCVExtension Extension) noexcept {
return static_cast<std::uint16_t>(std::uint16_t{1} << static_cast<std::uint8_t>(Extension));
}
[[nodiscard]] const ExtensionName *findExtension(std::string_view Name) noexcept {
for (const ExtensionName &Entry : ExtensionNames) {
if (Entry.Name == Name)
return &Entry;
}
return nullptr;
}
} // namespace
Expected<RISCVSubtargetFeatures>
RISCVSubtargetFeatures::fromFeatureList(std::span<const std::string> Features) {
std::uint16_t Enabled = extensionBit(RISCVExtension::I);
for (const std::string &Feature : Features) {
if (Feature.size() < 2 || (Feature.front() != '+' && Feature.front() != '-')) {
return makeUnexpected(ErrorCode::InvalidInvocation,
"RISC-V target feature must use canonical +/- spelling");
}
const ExtensionName *Extension = findExtension(std::string_view(Feature).substr(1));
if (Extension == nullptr) {
return makeUnexpected(ErrorCode::InvalidInvocation,
"RISC-V backend does not support target feature '" + Feature + "'");
}
if (Feature.front() == '+')
Enabled |= extensionBit(Extension->Extension);
else
Enabled &= static_cast<std::uint16_t>(~extensionBit(Extension->Extension));
}
RISCVSubtargetFeatures Result(Enabled);
if (!Result.has(RISCVExtension::I)) {
return makeUnexpected(ErrorCode::InvalidInvocation,
"RV64 target feature configuration cannot disable the base I extension");
}
if (Result.has(RISCVExtension::D) && !Result.has(RISCVExtension::F)) {
return makeUnexpected(ErrorCode::InvalidInvocation,
"RISC-V D extension requires the F extension");
}
if ((Result.has(RISCVExtension::Zacas) || Result.has(RISCVExtension::Zabha)) &&
!Result.has(RISCVExtension::A)) {
return makeUnexpected(ErrorCode::InvalidInvocation,
"RISC-V Zacas and Zabha extensions require the A extension");
}
return Result;
}
RISCVSubtargetFeatures RISCVSubtargetFeatures::rv64gc() noexcept {
return RISCVSubtargetFeatures(extensionBit(RISCVExtension::I) | extensionBit(RISCVExtension::M) |
extensionBit(RISCVExtension::A) | extensionBit(RISCVExtension::F) |
extensionBit(RISCVExtension::D) | extensionBit(RISCVExtension::C) |
extensionBit(RISCVExtension::Zicsr) |
extensionBit(RISCVExtension::Zifencei));
}
bool RISCVSubtargetFeatures::has(RISCVExtension Extension) const noexcept {
if (Extension >= RISCVExtension::Count)
return false;
return (Enabled & extensionBit(Extension)) != 0;
}
} // namespace rcc::riscv
|