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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
|
// SPDX-License-Identifier: GPL-3.0-or-later
#include "Common/CodeGenTarget.h"
#include <algorithm>
#include <limits>
#include <ranges>
#include <string>
#include <unordered_set>
#include <utility>
namespace rcc::targetgen {
[[nodiscard]] bool CodeGenTarget::normalizeRegisterUnits() {
if (Input.RegisterUnits.empty()) {
fail(Input.Target.Range, "target description requires at least one register unit");
return false;
}
std::unordered_set<std::uint32_t> IDs;
std::unordered_set<std::string> Symbols;
std::unordered_set<std::string> Names;
for (const SourceRegisterUnit &Unit : Input.RegisterUnits) {
if (Unit.ID == 0 || !isIdentifier(Unit.Symbol) || Unit.Name.empty() ||
!IDs.insert(Unit.ID).second || !Symbols.insert(Unit.Symbol).second ||
!Names.insert(lowerASCII(Unit.Name)).second) {
fail(Unit.Range,
"register units require nonzero unique IDs, unique symbols, and unique names");
return false;
}
UnitBySymbol.emplace(Unit.Symbol, Unit.ID);
}
return true;
}
[[nodiscard]] bool CodeGenTarget::normalizeRegisters(NormalizedTargetModel &Result) {
if (Input.Registers.empty()) {
fail(Input.Target.Range, "target description requires at least one physical register");
return false;
}
std::unordered_set<std::uint32_t> IDs;
std::unordered_set<std::string> Symbols;
std::unordered_set<std::string> Names;
for (const SourceRegister &Register : Input.Registers) {
if (Register.ID == 0 || !isIdentifier(Register.Symbol) || Register.Name.empty() ||
!IDs.insert(Register.ID).second || !Symbols.insert(Register.Symbol).second ||
!Names.insert(lowerASCII(Register.Name)).second || Register.Units.empty()) {
fail(Register.Range,
"registers require nonzero unique IDs, symbols, canonical names, and units");
return false;
}
RegisterBySymbol.emplace(Register.Symbol, Register.ID);
NormalizedRegister Normalized{
.ID = Register.ID,
.Symbol = Register.Symbol,
.Name = Register.Name,
.Encoding = Register.Encoding,
.DwarfRegister = Register.DwarfRegister,
.Units = {},
.IsConstant = Register.IsConstant,
.IsArtificial = Register.IsArtificial,
.IsReserved = Register.IsReserved,
.AlternativeNames = Register.AlternativeNames,
};
std::unordered_set<std::uint32_t> Units;
for (const SourceRegisterUnitLane &Unit : Register.Units) {
const auto Position = UnitBySymbol.find(Unit.UnitSymbol);
if (Position == UnitBySymbol.end() || Unit.Lanes == 0 ||
!Units.insert(Position->second).second) {
fail(Unit.Range,
"register units must name distinct declared units with nonzero lane masks");
return false;
}
Normalized.Units.push_back({.UnitID = Position->second, .Lanes = Unit.Lanes});
}
for (const std::string &Alias : Register.AlternativeNames) {
if (Alias.empty() || !Names.insert(lowerASCII(Alias)).second) {
fail(Register.Range,
"register ABI aliases must be nonempty and unique across all register names");
return false;
}
}
Result.Registers.push_back(std::move(Normalized));
}
return true;
}
[[nodiscard]] bool CodeGenTarget::normalizeRegisterBanks(NormalizedTargetModel &Result) {
if (Input.RegisterBanks.empty()) {
fail(Input.Target.Range, "target description requires at least one register bank");
return false;
}
std::unordered_set<std::uint32_t> IDs;
std::unordered_set<std::string> Symbols;
std::unordered_set<std::string> Names;
for (const SourceRegisterBank &Bank : Input.RegisterBanks) {
if (Bank.ID == 0 || !isIdentifier(Bank.Symbol) || Bank.Name.empty() ||
Bank.MaximumSizeInBits == 0 || !IDs.insert(Bank.ID).second ||
!Symbols.insert(Bank.Symbol).second || !Names.insert(lowerASCII(Bank.Name)).second) {
fail(Bank.Range,
"register banks require nonzero unique IDs, symbols, names, and maximum sizes");
return false;
}
BankBySymbol.emplace(Bank.Symbol, Bank.ID);
Result.RegisterBanks.push_back({
.ID = Bank.ID,
.Symbol = Bank.Symbol,
.Name = Bank.Name,
.MaximumSizeInBits = Bank.MaximumSizeInBits,
.RegisterClasses = {},
});
}
return true;
}
[[nodiscard]] bool CodeGenTarget::normalizeRegisterClasses(NormalizedTargetModel &Result) {
if (Input.RegisterClasses.empty()) {
fail(Input.Target.Range, "target description requires at least one register class");
return false;
}
std::unordered_set<std::uint32_t> IDs;
std::unordered_set<std::string> Symbols;
std::unordered_set<std::string> Names;
for (const SourceRegisterClass &Class : Input.RegisterClasses) {
const auto Bank = BankBySymbol.find(Class.BankSymbol);
if (Class.ID == 0 || !isIdentifier(Class.Symbol) || Class.Name.empty() ||
Bank == BankBySymbol.end() || Class.SizeInBits == 0 || Class.SpillSizeInBits == 0 ||
Class.SpillAlignmentInBits == 0 || Class.Lanes == 0 || Class.RegisterSymbols.empty() ||
!IDs.insert(Class.ID).second || !Symbols.insert(Class.Symbol).second ||
!Names.insert(lowerASCII(Class.Name)).second) {
fail(Class.Range, "register classes require unique IDs, symbols, names, a declared bank, "
"sizes, lanes, and members");
return false;
}
ClassBySymbol.emplace(Class.Symbol, Class.ID);
}
for (const SourceRegisterClass &Class : Input.RegisterClasses) {
const auto Bank = BankBySymbol.find(Class.BankSymbol);
NormalizedRegisterClass Normalized{
.ID = Class.ID,
.Symbol = Class.Symbol,
.Name = Class.Name,
.BankID = Bank->second,
.SizeInBits = Class.SizeInBits,
.SpillSizeInBits = Class.SpillSizeInBits,
.SpillAlignmentInBits = Class.SpillAlignmentInBits,
.Lanes = Class.Lanes,
.Registers = {},
.AllocationOrder = {},
.SuperClasses = {},
.Allocatable = Class.Allocatable,
.CopyCost = Class.CopyCost,
};
std::unordered_set<std::uint32_t> Members;
for (const std::string &Symbol : Class.RegisterSymbols) {
const auto Register = RegisterBySymbol.find(Symbol);
if (Register == RegisterBySymbol.end() || !Members.insert(Register->second).second) {
fail(Class.Range, "register class members must reference distinct declared registers");
return false;
}
Normalized.Registers.push_back(Register->second);
}
std::unordered_set<std::uint32_t> Allocation;
for (const std::string &Symbol : Class.AllocationOrderSymbols) {
const auto Register = RegisterBySymbol.find(Symbol);
if (Register == RegisterBySymbol.end() || !Members.contains(Register->second) ||
!Allocation.insert(Register->second).second) {
fail(Class.Range,
"register class allocation order must contain distinct members of the same class");
return false;
}
Normalized.AllocationOrder.push_back(Register->second);
}
std::unordered_set<std::uint32_t> SuperClasses;
for (const std::string &Symbol : Class.SuperClassSymbols) {
const auto SuperClass = ClassBySymbol.find(Symbol);
if (SuperClass == ClassBySymbol.end() || SuperClass->second == Class.ID ||
!SuperClasses.insert(SuperClass->second).second) {
fail(Class.Range,
"register class superclasses must reference distinct declared classes other than "
"the class itself");
return false;
}
Normalized.SuperClasses.push_back(SuperClass->second);
}
if ((Normalized.Allocatable && Normalized.AllocationOrder.empty()) ||
(!Normalized.Allocatable && !Normalized.AllocationOrder.empty())) {
fail(Class.Range, "allocatable register classes require an allocation order and "
"nonallocatable classes forbid one");
return false;
}
Result.RegisterClasses.push_back(std::move(Normalized));
}
for (NormalizedRegisterBank &Bank : Result.RegisterBanks) {
for (const NormalizedRegisterClass &Class : Result.RegisterClasses) {
if (Class.BankID == Bank.ID)
Bank.RegisterClasses.push_back(Class.ID);
}
}
return true;
}
[[nodiscard]] bool CodeGenTarget::normalizeRegisterMasks(NormalizedTargetModel &Result) {
std::unordered_set<std::string> Names;
for (const SourceRegisterMask &Mask : Input.RegisterMasks) {
if (Mask.Name.empty() || !Names.insert(Mask.Name).second) {
fail(Mask.Range, "register mask names must be nonempty and unique");
return false;
}
NormalizedRegisterMask Normalized{.Name = Mask.Name, .PreservedRegisters = {}};
std::unordered_set<std::uint32_t> Preserved;
for (const std::string &Symbol : Mask.PreservedRegisterSymbols) {
const auto Register = RegisterBySymbol.find(Symbol);
if (Register == RegisterBySymbol.end() || !Preserved.insert(Register->second).second) {
fail(Mask.Range, "register mask entries must name distinct declared registers");
return false;
}
Normalized.PreservedRegisters.push_back(Register->second);
}
Result.RegisterMasks.push_back(std::move(Normalized));
}
return true;
}
} // namespace rcc::targetgen
|