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
|
// SPDX-License-Identifier: GPL-3.0-or-later
#include "RISCVRegisterBankInfo.h"
#include "rcc/CodeGen/MachineFunction.h"
#include "rcc/CodeGen/MachineInstr.h"
#include "rcc/CodeGen/TargetDescription.h"
#include "rcc/Target/RISCV/RISCVRegisters.h"
#include <cstdint>
#include <ranges>
#include <utility>
#include <vector>
namespace rcc::riscv {
namespace {
[[nodiscard]] bool isRVFloatType(LLT Type) noexcept {
return Type.isFloat() && (Type.scalarBitWidth() == 32 || Type.scalarBitWidth() == 64);
}
[[nodiscard]] bool isScalarGPRType(LLT Type) noexcept {
return (Type.isPointer() && Type.addressSpace() == 0 && Type.scalarBitWidth() == 64) ||
((Type.isInteger() || Type.isAnyScalar()) && Type.scalarBitWidth() >= 1 &&
Type.scalarBitWidth() <= 64);
}
[[nodiscard]] Expected<RegisterClassID> requiredRegisterClass(const MachineFunction &Function,
Register Reg,
const TargetDescription &Target) {
if (!Reg.isVirtual())
return makeUnexpected(ErrorCode::InvalidArgument,
"RISC-V register-class selection requires a virtual register");
auto Info = Function.registerInfo().virtualRegisterInfo(Reg);
if (!Info)
return std::unexpected(Info.error());
if (!Info->get().Type) {
return makeUnexpected(ErrorCode::VerificationError,
"RISC-V selection requires a type for every virtual register");
}
const VirtualRegisterInfo &RegisterInfo = Info->get();
const LLT Type = RegisterInfo.Type.value_or(LLT{});
RegisterClassID RequiredClass;
if (isScalarGPRType(Type)) {
RequiredClass = RegisterClassID::fromValue(static_cast<std::uint32_t>(RegisterClass::GPR));
} else if (Type.isFloat() && Type.scalarBitWidth() == 32) {
RequiredClass = RegisterClassID::fromValue(static_cast<std::uint32_t>(RegisterClass::FPR32));
} else if (Type.isFloat() && Type.scalarBitWidth() == 64) {
RequiredClass = RegisterClassID::fromValue(static_cast<std::uint32_t>(RegisterClass::FPR64));
} else {
return makeUnexpected(ErrorCode::Unsupported,
"RISC-V RV64GC has no register class for type '" + Type.toString() + "'");
}
if (Target.registers().registerClass(RequiredClass) == nullptr) {
return makeUnexpected(ErrorCode::InternalError,
"RISC-V target description is missing a required register class");
}
if (RegisterInfo.Bank && !Target.registers().bankCoversClass(*RegisterInfo.Bank, RequiredClass)) {
return makeUnexpected(ErrorCode::VerificationError,
"RISC-V virtual register bank cannot cover its required class");
}
if (RegisterInfo.RegClass &&
!Target.registers().isSubclass(*RegisterInfo.RegClass, RequiredClass)) {
return makeUnexpected(ErrorCode::VerificationError,
"RISC-V virtual register has a conflicting register class");
}
return RequiredClass;
}
} // namespace
Expected<RegisterBankID> RISCVRegisterBankInfo::selectBank(const MachineFunction &, Register,
const VirtualRegisterInfo &Info,
const MachineInstr *,
const TargetDescription &) const {
if (!Info.Type) {
return makeUnexpected(ErrorCode::VerificationError,
"RISC-V register-bank selection requires a virtual-register type");
}
if (isScalarGPRType(*Info.Type))
return RegisterBankID::fromValue(static_cast<std::uint32_t>(RegisterBank::GPR));
if (isRVFloatType(*Info.Type))
return RegisterBankID::fromValue(static_cast<std::uint32_t>(RegisterBank::FPR));
return makeUnexpected(ErrorCode::Unsupported,
"RISC-V RV64GC has no register bank for virtual register type '" +
Info.Type->toString() + "'");
}
Expected<void> RISCVRegisterBankInfo::constrainInstruction(MachineInstr &Instruction,
MachineFunction &Function,
const TargetDescription &Target) const {
std::vector<std::pair<Register, RegisterClassID>> PlannedClasses;
for (const MachineOperand &Operand : Instruction.operands()) {
const Register *Reg = Operand.getIf<Register>();
if (Reg == nullptr || !Reg->isVirtual())
continue;
auto Required = requiredRegisterClass(Function, *Reg, Target);
if (!Required)
return std::unexpected(Required.error());
if (std::ranges::find_if(PlannedClasses, [Reg](const auto &Entry) {
return Entry.first == *Reg;
}) == PlannedClasses.end())
PlannedClasses.emplace_back(*Reg, *Required);
}
for (const auto &[Reg, Required] : PlannedClasses) {
auto Info = Function.registerInfo().virtualRegisterInfo(Reg);
if (!Info)
return std::unexpected(Info.error());
if (Info->get().RegClass)
continue;
auto SetClass = Function.registerInfo().setRegisterClass(Reg, Required);
if (!SetClass)
return std::unexpected(SetClass.error());
}
return {};
}
Expected<void> RISCVRegisterBankInfo::constrainRegister(MachineFunction &Function, Register Reg,
const TargetDescription &Target) const {
auto Info = Function.registerInfo().virtualRegisterInfo(Reg);
if (!Info)
return std::unexpected(Info.error());
auto Bank = selectBank(Function, Reg, Info->get(), nullptr, Target);
if (!Bank)
return std::unexpected(Bank.error());
auto RequiredClass = requiredRegisterClass(Function, Reg, Target);
if (!RequiredClass)
return std::unexpected(RequiredClass.error());
if (!Info->get().Bank) {
auto SetBank = Function.registerInfo().setRegisterBank(Reg, *Bank);
if (!SetBank)
return std::unexpected(SetBank.error());
}
if (!Info->get().RegClass) {
auto SetClass = Function.registerInfo().setRegisterClass(Reg, *RequiredClass);
if (!SetClass)
return std::unexpected(SetClass.error());
}
return {};
}
Expected<void> RISCVRegisterBankInfo::validateInstruction(const MachineInstr &Instruction,
const MachineFunction &Function,
const TargetDescription &Target) const {
for (const MachineOperand &Operand : Instruction.operands()) {
const Register *Reg = Operand.getIf<Register>();
if (Reg == nullptr || !Reg->isVirtual())
continue;
auto Required = requiredRegisterClass(Function, *Reg, Target);
if (!Required)
return std::unexpected(Required.error());
}
return {};
}
} // namespace rcc::riscv
|