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
|
// SPDX-License-Identifier: GPL-3.0-or-later
#include "rcc/CodeGen/LiveRangeEdit.h"
#include "RegAllocInternal.h"
#include "rcc/CodeGen/MachineRegisterInfo.h"
#include "rcc/CodeGen/TargetDescription.h"
namespace rcc {
Expected<Register> LiveRangeEdit::createFrom(Register Parent, bool Spillable,
std::optional<Register> Origin) {
auto ParentInfo = Function->registerInfo().virtualRegisterInfo(Parent);
if (!ParentInfo)
return std::unexpected(ParentInfo.error());
const VirtualRegisterInfo &Source = ParentInfo->get();
Expected<Register> Created = Source.Type
? Function->registerInfo().createVirtualRegister(*Source.Type)
: Function->registerInfo().createVirtualRegister();
if (!Created)
return std::unexpected(Created.error());
const Register Child = *Created;
auto Fail = [&](const Error &Failure) -> Expected<Register> {
auto Erased = Function->registerInfo().eraseVirtualRegister(Child);
if (!Erased)
return makeUnexpected(ErrorCode::InternalError,
"split virtual-register setup and rollback both failed");
return std::unexpected(Failure);
};
if (Source.Bank) {
auto Set = Function->registerInfo().setRegisterBank(Child, *Source.Bank);
if (!Set)
return Fail(Set.error());
}
if (Source.RegClass) {
auto Set = Function->registerInfo().setRegisterClass(Child, *Source.RegClass);
if (!Set)
return Fail(Set.error());
}
for (const PhysicalRegister Hint : Source.AllocationHints) {
auto Added = Function->registerInfo().addAllocationHint(Child, Hint);
if (!Added)
return Fail(Added.error());
}
if (Source.TargetFlags != 0) {
auto Set = Function->registerInfo().setTargetRegisterFlags(Child, Source.TargetFlags);
if (!Set)
return Fail(Set.error());
}
const VirtRegMapEntry *ParentEntry = Mapping->entry(Parent);
const Register Root = Origin.value_or(
ParentEntry != nullptr && ParentEntry->Origin ? *ParentEntry->Origin : Parent);
const std::optional<FrameIndex> ParentStackSlot =
ParentEntry == nullptr ? std::nullopt : ParentEntry->Spill.StackSlot;
const LaneMask ParentSpillLanes =
ParentEntry == nullptr ? LaneMask::all() : ParentEntry->Spill.Lanes;
auto Added = Mapping->add(Child, Spillable, Parent, Root);
if (!Added)
return Fail(Added.error());
auto Split = Mapping->markSplit(Child, Parent, Root);
if (!Split)
return Fail(Split.error());
if (ParentStackSlot) {
auto SharedSlot = Mapping->assignStackSlot(Child, *ParentStackSlot, ParentSpillLanes);
if (!SharedSlot)
return Fail(SharedSlot.error());
}
return Child;
}
Expected<FrameIndex> LiveRangeEdit::getOrCreateSpillSlot(Register VirtualReg) {
if (const auto Existing = Mapping->stackSlot(VirtualReg))
return *Existing;
const VirtRegMapEntry *Entry = Mapping->entry(VirtualReg);
const Register Original = Entry != nullptr && Entry->Origin ? *Entry->Origin : VirtualReg;
if (Original != VirtualReg) {
if (const auto Existing = Mapping->stackSlot(Original)) {
auto Shared = Mapping->assignStackSlot(VirtualReg, *Existing);
if (!Shared)
return std::unexpected(Shared.error());
return *Existing;
}
}
auto ClassID = regalloc_detail::registerClassFor(*Function, Original);
if (!ClassID)
return std::unexpected(ClassID.error());
const RegisterClassDesc *Class = Target->registers().registerClass(*ClassID);
if (Class == nullptr || Class->SpillSizeInBits == 0 || Class->SpillAlignmentInBits == 0 ||
Class->SpillSizeInBits % 8U != 0 || Class->SpillAlignmentInBits % 8U != 0) {
return makeUnexpected(ErrorCode::InternalError,
"allocatable register class has no valid spill size and alignment");
}
auto Align = Alignment::create(Class->SpillAlignmentInBits / 8U);
if (!Align)
return std::unexpected(Align.error());
StackObjectDesc Description;
Description.Kind = StackObjectKind::SpillSlot;
Description.Size = Class->SpillSizeInBits / 8U;
Description.Align = *Align;
auto Slot = Function->frameInfo().createObject(std::move(Description));
if (!Slot)
return std::unexpected(Slot.error());
auto AssignedOriginal = Mapping->assignStackSlot(Original, *Slot);
if (!AssignedOriginal)
return std::unexpected(AssignedOriginal.error());
if (Original != VirtualReg) {
auto AssignedChild = Mapping->assignStackSlot(VirtualReg, *Slot);
if (!AssignedChild)
return std::unexpected(AssignedChild.error());
}
return *Slot;
}
Expected<void> LiveRangeEdit::eraseVirtualRegister(Register VirtualReg) {
if (!Function->registerInfo().useEmpty(VirtualReg))
return makeUnexpected(ErrorCode::InternalError,
"cannot erase a split virtual register with remaining uses");
for (const MachineOperand &Operand : Function->registerInfo().defOperands(VirtualReg)) {
if (Operand.parent() != nullptr)
return makeUnexpected(ErrorCode::InternalError,
"cannot erase a split virtual register with remaining definitions");
}
return Function->registerInfo().eraseVirtualRegister(VirtualReg);
}
} // namespace rcc
|