aboutsummaryrefslogtreecommitdiff
path: root/backend/lib/CodeGen/LiveRegMatrix.cpp
blob: 64c704626ceb8792a36447e3e37fe5cb95e580f1 (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
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
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
// SPDX-License-Identifier: GPL-3.0-or-later

#include "rcc/CodeGen/LiveRegMatrix.h"

#include "RegAllocInternal.h"
#include "rcc/CodeGen/MachineBasicBlock.h"
#include "rcc/CodeGen/MachineFunction.h"
#include "rcc/CodeGen/MachineInstr.h"
#include "rcc/CodeGen/MachineOperand.h"
#include "rcc/CodeGen/TargetDescription.h"

#include <algorithm>
#include <bit>
#include <cstdint>
#include <optional>
#include <ranges>
#include <span>
#include <tuple>
#include <vector>

namespace rcc {
namespace {

[[nodiscard]] std::optional<LaneMask> relevantLanes(const LiveInterval &Interval,
                                                    RegisterUnitLane Unit) noexcept {
  if (Interval.SubRanges.empty())
    return Unit.Lanes;
  LaneMask Result;
  for (const LiveSubRange &SubRange : Interval.SubRanges) {
    if (SubRange.Lanes.intersects(Unit.Lanes))
      Result = Result | (SubRange.Lanes & Unit.Lanes);
  }
  if (Result.empty())
    return std::nullopt;
  return Result;
}

[[nodiscard]] LaneMask normalizeUnitLanes(LaneMask UnitViewLanes, LaneMask RegisterLanes) noexcept {
  std::uint64_t View = UnitViewLanes.rawValue();
  const std::uint64_t Selected = View & RegisterLanes.rawValue();
  std::uint64_t Normalized = 0;
  std::uint32_t UnitLane = 0;
  while (View != 0) {
    const std::uint64_t RegisterLane = std::uint64_t{1} << std::countr_zero(View);
    if ((Selected & RegisterLane) != 0)
      Normalized |= std::uint64_t{1} << UnitLane;
    View &= View - 1U;
    ++UnitLane;
  }
  return LaneMask::fromRaw(Normalized);
}

[[nodiscard]] LaneMask intervalUnitLanes(const LiveInterval &Interval,
                                         RegisterUnitLane Unit) noexcept {
  if (Interval.SubRanges.empty())
    return normalizeUnitLanes(Unit.Lanes, Unit.Lanes);
  LaneMask Result;
  for (const LiveSubRange &SubRange : Interval.SubRanges)
    Result = Result | normalizeUnitLanes(Unit.Lanes, SubRange.Lanes);
  return Result;
}

[[nodiscard]] bool intervalLiveAtFixedRegister(const LiveInterval &Interval,
                                               const PhysicalRegisterDesc &Candidate,
                                               const PhysicalRegisterDesc &Fixed,
                                               SlotIndex Position) noexcept {
  for (const RegisterUnitLane CandidateUnit : Candidate.Units) {
    const auto FixedUnit =
        std::ranges::find(Fixed.Units, CandidateUnit.Unit, &RegisterUnitLane::Unit);
    if (FixedUnit == Fixed.Units.end())
      continue;
    const LaneMask FixedLanes = normalizeUnitLanes(FixedUnit->Lanes, FixedUnit->Lanes);
    if (Interval.SubRanges.empty()) {
      if (normalizeUnitLanes(CandidateUnit.Lanes, CandidateUnit.Lanes).intersects(FixedLanes) &&
          Interval.MainRange.liveAt(Position)) {
        return true;
      }
      continue;
    }
    for (const LiveSubRange &SubRange : Interval.SubRanges) {
      if (normalizeUnitLanes(CandidateUnit.Lanes, SubRange.Lanes).intersects(FixedLanes) &&
          SubRange.Range.liveAt(Position)) {
        return true;
      }
    }
  }
  return false;
}

[[nodiscard]] bool rangeForUnitOverlaps(const LiveInterval &Interval, RegisterUnitLane Unit,
                                        const LiveRange &Other) noexcept {
  if (!relevantLanes(Interval, Unit))
    return false;
  if (Interval.SubRanges.empty())
    return Interval.MainRange.overlaps(Other);
  for (const LiveSubRange &SubRange : Interval.SubRanges) {
    if (SubRange.Lanes.intersects(Unit.Lanes) && SubRange.Range.overlaps(Other))
      return true;
  }
  return false;
}

} // namespace

bool regalloc_detail::intervalsOverlapOnPhysicalRegisters(
    const LiveInterval &Left, PhysicalRegister LeftReg, const LiveInterval &Right,
    PhysicalRegister RightReg, const TargetRegisterInfo &Registers) noexcept {
  const PhysicalRegisterDesc *LeftDescription = Registers.physicalRegister(LeftReg);
  const PhysicalRegisterDesc *RightDescription = Registers.physicalRegister(RightReg);
  if (LeftDescription == nullptr || RightDescription == nullptr)
    return true;
  for (const RegisterUnitLane LeftUnit : LeftDescription->Units) {
    for (const RegisterUnitLane RightUnit : RightDescription->Units) {
      if (LeftUnit.Unit != RightUnit.Unit)
        continue;
      const LaneMask LeftUnitLanes = intervalUnitLanes(Left, LeftUnit);
      const LaneMask RightUnitLanes = intervalUnitLanes(Right, RightUnit);
      if (!LeftUnitLanes.intersects(RightUnitLanes))
        continue;
      if (Left.SubRanges.empty() && Right.SubRanges.empty())
        return Left.MainRange.overlaps(Right.MainRange);
      const auto LeftRanges = Left.SubRanges.empty()
                                  ? std::span<const LiveSubRange>{}
                                  : std::span<const LiveSubRange>(Left.SubRanges);
      const auto RightRanges = Right.SubRanges.empty()
                                   ? std::span<const LiveSubRange>{}
                                   : std::span<const LiveSubRange>(Right.SubRanges);
      if (LeftRanges.empty()) {
        for (const LiveSubRange &RightRange : RightRanges) {
          const LaneMask RightRangeLanes = normalizeUnitLanes(RightUnit.Lanes, RightRange.Lanes);
          if (LeftUnitLanes.intersects(RightRangeLanes) &&
              Left.MainRange.overlaps(RightRange.Range))
            return true;
        }
        continue;
      }
      if (RightRanges.empty()) {
        for (const LiveSubRange &LeftRange : LeftRanges) {
          const LaneMask LeftRangeLanes = normalizeUnitLanes(LeftUnit.Lanes, LeftRange.Lanes);
          if (LeftRangeLanes.intersects(RightUnitLanes) &&
              LeftRange.Range.overlaps(Right.MainRange))
            return true;
        }
        continue;
      }
      for (const LiveSubRange &LeftRange : LeftRanges) {
        const LaneMask LeftRangeLanes = normalizeUnitLanes(LeftUnit.Lanes, LeftRange.Lanes);
        if (LeftRangeLanes.empty())
          continue;
        for (const LiveSubRange &RightRange : RightRanges) {
          const LaneMask RightRangeLanes = normalizeUnitLanes(RightUnit.Lanes, RightRange.Lanes);
          if (LeftRangeLanes.intersects(RightRangeLanes) &&
              LeftRange.Range.overlaps(RightRange.Range))
            return true;
        }
      }
    }
  }
  return false;
}

bool LiveRegMatrix::intervalOverlapsUnit(const LiveInterval &Interval, RegisterUnitLane Unit,
                                         const LiveRange &UnitRange) const noexcept {
  return rangeForUnitOverlaps(Interval, Unit, UnitRange);
}

bool LiveRegMatrix::intervalsOverlapOnCandidates(const LiveInterval &Left, PhysicalRegister LeftReg,
                                                 const LiveInterval &Right,
                                                 PhysicalRegister RightReg) const noexcept {
  return regalloc_detail::intervalsOverlapOnPhysicalRegisters(Left, LeftReg, Right, RightReg,
                                                              Target->registers());
}

std::vector<RegisterInterference>
LiveRegMatrix::collectInterferences(Register VirtualReg, PhysicalRegister PhysicalReg) const {
  std::vector<RegisterInterference> Result;
  const LiveInterval *Interval = Intervals->interval(VirtualReg);
  const PhysicalRegisterDesc *Candidate = Target->registers().physicalRegister(PhysicalReg);
  if (Interval == nullptr || Candidate == nullptr)
    return Result;

  for (const MachineBasicBlock *Block = Function->firstBlock(); Block != nullptr;
       Block = Block->next()) {
    for (const MachineInstr *Instruction = Block->firstInstruction(); Instruction != nullptr;
         Instruction = Instruction->next()) {
      const SlotIndex Position = Intervals->slot(*Instruction);
      if (!Position.isValid())
        continue;
      for (const MachineOperand &Operand : Instruction->operands()) {
        const Register *Reg = Operand.getIf<Register>();
        if (Reg == nullptr || !Reg->isPhysical())
          continue;
        const auto Fixed = Reg->physicalRegister();
        if (!Fixed)
          continue;
        const PhysicalRegister FixedReg = Fixed.value();
        if (!Target->registers().regsOverlap(FixedReg, PhysicalReg))
          continue;
        const PhysicalRegisterDesc *FixedDescription =
            Target->registers().physicalRegister(FixedReg);
        if (FixedDescription == nullptr)
          continue;
        const SlotIndex OperandPosition =
            Operand.registerFlags().has(RegisterOperandFlag::EarlyClobber)
                ? Position.earlyClobberSlot()
                : Position.registerSlot();
        if (intervalLiveAtFixedRegister(*Interval, *Candidate, *FixedDescription,
                                        OperandPosition)) {
          Result.push_back(RegisterInterference{RegisterInterferenceKind::FixedRegister,
                                                std::nullopt, FixedReg, std::nullopt,
                                                Instruction->stableID()});
        }
      }
    }
  }

  for (const RegMaskPosition &Mask : Intervals->regMaskPositions()) {
    if (Mask.Mask && Mask.Mask->clobbers(PhysicalReg) &&
        Interval->MainRange.liveAt(Mask.Position)) {
      Result.push_back(RegisterInterference{RegisterInterferenceKind::RegisterMask, std::nullopt,
                                            std::nullopt, std::nullopt, Mask.Instruction});
    }
  }

  for (const RegisterUnitLane Unit : Candidate->Units) {
    const LiveRange *FixedRange = Intervals->regUnitRange(Unit.Unit);
    if (FixedRange != nullptr && intervalOverlapsUnit(*Interval, Unit, *FixedRange)) {
      Result.push_back(RegisterInterference{RegisterInterferenceKind::RegisterUnit, std::nullopt,
                                            std::nullopt, Unit.Unit, std::nullopt});
    }
  }

  for (const auto &[OtherReg, OtherPhysical] : OrderedAssignments) {
    if (OtherReg == VirtualReg)
      continue;
    const LiveInterval *OtherInterval = Intervals->interval(OtherReg);
    if (OtherInterval != nullptr &&
        intervalsOverlapOnCandidates(*Interval, PhysicalReg, *OtherInterval, OtherPhysical)) {
      Result.push_back(RegisterInterference{RegisterInterferenceKind::VirtualRegister, OtherReg,
                                            std::nullopt, std::nullopt, std::nullopt});
    }
  }

  std::ranges::sort(
      Result, [](const RegisterInterference &Left, const RegisterInterference &Right) {
        return std::tuple{Left.Kind, Left.VirtualReg.value_or(Register{}).opaqueValue(),
                          Left.FixedReg.value_or(PhysicalRegister{}).number(),
                          Left.Unit ? Left.Unit->value() : 0U,
                          Left.Instruction ? Left.Instruction->value() : 0ULL} <
               std::tuple{Right.Kind, Right.VirtualReg.value_or(Register{}).opaqueValue(),
                          Right.FixedReg.value_or(PhysicalRegister{}).number(),
                          Right.Unit ? Right.Unit->value() : 0U,
                          Right.Instruction ? Right.Instruction->value() : 0ULL};
      });
  Result.erase(std::unique(Result.begin(), Result.end(),
                           [](const RegisterInterference &Left, const RegisterInterference &Right) {
                             return Left.Kind == Right.Kind &&
                                    Left.VirtualReg == Right.VirtualReg &&
                                    Left.FixedReg == Right.FixedReg && Left.Unit == Right.Unit &&
                                    Left.Instruction == Right.Instruction;
                           }),
               Result.end());
  return Result;
}

RegisterInterference LiveRegMatrix::checkInterference(Register VirtualReg,
                                                      PhysicalRegister PhysicalReg) const noexcept {
  const std::vector<RegisterInterference> Values = collectInterferences(VirtualReg, PhysicalReg);
  if (Values.empty())
    return {};
  return Values.front();
}

Expected<void> LiveRegMatrix::assign(Register VirtualReg, PhysicalRegister PhysicalReg) {
  if (!VirtualReg.isVirtual() || Intervals->interval(VirtualReg) == nullptr ||
      Target->registers().physicalRegister(PhysicalReg) == nullptr) {
    return makeUnexpected(
        ErrorCode::InvalidArgument,
        "LiveRegMatrix assignment requires a known interval and physical register");
  }
  if (regalloc_detail::isUnavailablePhysicalRegister(*Function, Target->registers(), PhysicalReg)) {
    return makeUnexpected(ErrorCode::RegisterAllocationFailed,
                          "LiveRegMatrix cannot assign an unavailable physical register");
  }
  auto Info = Function->registerInfo().virtualRegisterInfo(VirtualReg);
  if (!Info)
    return std::unexpected(Info.error());
  const auto ClassID = Info->get().RegClass;
  if (ClassID) {
    if (!Target->registers().registerClassContains(ClassID.value(), PhysicalReg)) {
      return makeUnexpected(ErrorCode::RegisterAllocationFailed,
                            "LiveRegMatrix assignment is outside the virtual register class");
    }
  }
  if (!regalloc_detail::candidateSupportsSubRegisters(*Function, Target->registers(), VirtualReg,
                                                      PhysicalReg)) {
    return makeUnexpected(ErrorCode::RegisterAllocationFailed,
                          "LiveRegMatrix assignment lacks a required subregister view");
  }
  if (Assignments.contains(VirtualReg))
    return makeUnexpected(ErrorCode::InvalidArgument, "virtual register is already assigned");
  const RegisterInterference Interference = checkInterference(VirtualReg, PhysicalReg);
  if (Interference.Kind != RegisterInterferenceKind::Free) {
    return makeUnexpected(ErrorCode::RegisterAllocationFailed,
                          "physical register assignment has live interference");
  }
  Assignments.emplace(VirtualReg, PhysicalReg);
  OrderedAssignments.emplace_back(VirtualReg, PhysicalReg);
  std::ranges::sort(OrderedAssignments, [](const auto &Left, const auto &Right) {
    return Left.first.opaqueValue() < Right.first.opaqueValue();
  });
  return {};
}

Expected<void> LiveRegMatrix::unassign(Register VirtualReg) {
  if (!Assignments.erase(VirtualReg))
    return makeUnexpected(ErrorCode::InvalidArgument, "virtual register is not assigned");
  std::erase_if(OrderedAssignments,
                [VirtualReg](const auto &Entry) { return Entry.first == VirtualReg; });
  return {};
}

std::optional<PhysicalRegister> LiveRegMatrix::assignment(Register VirtualReg) const noexcept {
  const auto Position = Assignments.find(VirtualReg);
  if (Position == Assignments.end())
    return std::nullopt;
  return Position->second;
}

} // namespace rcc