aboutsummaryrefslogtreecommitdiff
path: root/backend/unittests/CodeGen/SlotIndexesTest.cpp
blob: 9d3f54b3b37693c70c646659224e5fb47db3d559 (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
// SPDX-License-Identifier: GPL-3.0-or-later

#include "rcc/CodeGen/SlotIndexes.h"

#include "LiveTestSupport.h"
#include "rcc/CodeGen/LiveVariables.h"

namespace {

using namespace rcc::test::liveness;

void testSlotIndexes(TestContext &Context, const rcc::TargetDescription &Target) {
  auto Fixture = createFunction("slot-indexes", 1, 1);
  if (!Fixture) {
    Context.expect(false, "SlotIndexes fixture creation must succeed");
    return;
  }
  auto Reg = createVReg(*Fixture->Function);
  auto Def = Reg ? buildDef(*Fixture->Function, Target, *Fixture->Blocks[0], *Reg)
                 : rcc::Expected<rcc::MachineInstr *>{std::unexpected(Reg.error())};
  auto Use = Reg ? buildUse(*Fixture->Function, Target, *Fixture->Blocks[0], *Reg)
                 : rcc::Expected<rcc::MachineInstr *>{std::unexpected(Reg.error())};
  if (!Reg || !Def || !Use) {
    Context.expect(false, "SlotIndexes instructions must be built");
    return;
  }

  rcc::MachineFunctionAnalysisManager Analyses;
  auto Registered = rcc::registerStage11MachineAnalyses(Analyses);
  auto Indexes =
      Registered
          ? Analyses.getResult<rcc::SlotIndexesAnalysis>(*Fixture->Function, Target)
          : rcc::Expected<rcc::SlotIndexesAnalysis::Result *>{std::unexpected(Registered.error())};
  if (!Indexes) {
    Context.expect(false, "SlotIndexes analysis must materialize");
    return;
  }
  const rcc::SlotIndex DefIndex = (*Indexes)->instructionIndex(**Def);
  const rcc::SlotIndex UseIndex = (*Indexes)->instructionIndex(**Use);
  Context.expect((*Indexes)->blockStart(*Fixture->Blocks[0]) < DefIndex.earlyClobberSlot() &&
                     DefIndex.earlyClobberSlot() < DefIndex && DefIndex < DefIndex.deadSlot() &&
                     DefIndex.deadSlot() < UseIndex &&
                     UseIndex < (*Indexes)->blockEnd(*Fixture->Blocks[0]),
                 "SlotIndexes must order block, early-clobber, register, and dead slots");
  Context.expect((*Indexes)->instructionFromIndex(DefIndex.deadSlot()) == *Def &&
                     (*Indexes)->blockFromIndex(UseIndex) == Fixture->Blocks[0],
                 "SlotIndexes reverse mappings must accept every instruction subslot");

  auto Inserted = buildUse(*Fixture->Function, Target, *Fixture->Blocks[0], *Reg, {}, *Use);
  Context.expect(Inserted && (*Indexes)->insertInstruction(**Inserted).has_value(),
                 "local SlotIndex insertion must use reserved numbering space");
  if (Inserted) {
    const rcc::SlotIndex InsertedIndex = (*Indexes)->instructionIndex(**Inserted);
    Context.expect(DefIndex < InsertedIndex && InsertedIndex < UseIndex,
                   "locally inserted SlotIndex must lie between adjacent instructions");
    Context.expect((*Indexes)->eraseInstruction(**Inserted).has_value() &&
                       !(*Indexes)->instructionIndex(**Inserted).isValid() &&
                       (*Indexes)->renumber(*Fixture->Function).has_value() &&
                       (*Indexes)->instructionIndex(**Inserted).isValid(),
                   "SlotIndex erasure and full renumbering must rebuild exact mappings");

    auto Second = buildUse(*Fixture->Function, Target, *Fixture->Blocks[0], *Reg, {}, *Inserted);
    auto SecondIndexed = Second ? (*Indexes)->insertInstruction(**Second)
                                : rcc::Expected<void>{std::unexpected(Second.error())};
    auto Third = Second
                     ? buildUse(*Fixture->Function, Target, *Fixture->Blocks[0], *Reg, {}, *Second)
                     : rcc::Expected<rcc::MachineInstr *>{std::unexpected(Second.error())};
    auto ThirdIndexed = Third ? (*Indexes)->insertInstruction(**Third)
                              : rcc::Expected<void>{std::unexpected(Third.error())};
    auto Exhausted =
        Third ? buildUse(*Fixture->Function, Target, *Fixture->Blocks[0], *Reg, {}, *Third)
              : rcc::Expected<rcc::MachineInstr *>{std::unexpected(Third.error())};
    auto ExhaustedIndex = Exhausted ? (*Indexes)->insertInstruction(**Exhausted)
                                    : rcc::Expected<void>{std::unexpected(Exhausted.error())};
    Context.expect(SecondIndexed && ThirdIndexed && Exhausted && !ExhaustedIndex &&
                       ExhaustedIndex.error().code() == rcc::ErrorCode::Unsupported &&
                       (*Indexes)->renumber(*Fixture->Function).has_value() &&
                       (*Indexes)->instructionIndex(**Exhausted).isValid(),
                   "local SlotIndex exhaustion must request and recover through full renumbering");
  }
}

} // namespace

int main() {
  TestContext Context;
  auto Target = createTarget();
  Context.expect(Target.has_value(), "liveness TestTarget must be created");
  if (!Target)
    return Context.result();
  testSlotIndexes(Context, *Target);
  return Context.result();
}