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
|
// SPDX-License-Identifier: GPL-3.0-or-later
#include "rcc/CodeGen/GlobalISel/Combiner.h"
#include "rcc/CodeGen/GlobalISel/Utils.h"
#include "rcc/CodeGen/LiveVariables.h"
#include "rcc/CodeGen/MachineBasicBlock.h"
#include "rcc/CodeGen/MachineFunction.h"
#include "rcc/CodeGen/MachineFunctionCloner.h"
#include "rcc/CodeGen/MachineInstr.h"
#include <optional>
#include <string>
namespace rcc {
const MachinePassContract &GlobalISelCombinerPass::contract() const noexcept {
return Contract;
}
Expected<MachinePassResult> GlobalISelCombinerPass::run(MachineFunction &Function,
const TargetDescription &Target,
MachineFunctionAnalysisManager &Analyses) {
auto Trial = cloneMachineFunction(
Function, Target,
MachineFunctionCloneOptions{.NewStableID = Function.stableID(), .NewName = std::nullopt});
if (!Trial)
return std::unexpected(withErrorContext(Trial.error(), "GlobalISel combiner clone failed: "));
MachineActionReplay Actions(Analyses, Trial->InstructionStableIDs);
auto TrialResult = runImplementation(*Trial->ClonedFunction, Target, Actions);
if (!TrialResult)
return std::unexpected(TrialResult.error());
Actions.beginReplay();
auto Result = runImplementation(Function, Target, Actions);
if (!Result)
return std::unexpected(
withErrorContext(Result.error(), "GlobalISel combiner replay diverged: "));
auto Replayed = Actions.finishReplay();
if (!Replayed)
return std::unexpected(Replayed.error());
return Result;
}
Expected<MachinePassResult>
GlobalISelCombinerPass::runImplementation(MachineFunction &Function,
const TargetDescription &Target,
MachineActionReplay &Actions) const {
if (MaximumRewrites == 0 || MaximumIterations == 0)
return makeUnexpected(ErrorCode::InvalidArgument,
"GlobalISel combiner iteration limits must be nonzero");
MachinePassResult Result;
std::size_t Rewrites = 0;
for (std::size_t Iteration = 0; Iteration < MaximumIterations; ++Iteration) {
bool IterationChanged = false;
for (MachineBasicBlock *Block = Function.firstBlock(); Block != nullptr;
Block = Block->next()) {
for (MachineInstr *Instruction = Block->firstInstruction(); Instruction != nullptr;) {
MachineInstr *Next = Instruction->next();
auto Matches = Executor->match(*Table, *Instruction, Function, Target);
if (!Matches)
return std::unexpected(Matches.error());
if (*Matches && Rewrites < MaximumRewrites) {
auto Accepted = Actions.request("gisel-combiner", Function, Instruction->stableID());
if (!Accepted)
return std::unexpected(Accepted.error());
if (*Accepted) {
auto Combined = Executor->combine(*Table, *Instruction, Function, Target);
if (!Combined)
return std::unexpected(Combined.error());
if (*Combined) {
++Rewrites;
IterationChanged = true;
Result.Changed = true;
}
}
}
Instruction = Next;
}
}
if (!IterationChanged || Rewrites == MaximumRewrites)
break;
}
if (!Result.Changed) {
Result.Preserved = PreservedAnalyses::all();
return Result;
}
if (Function.properties().has(MachineFunctionProperty::TracksLiveness)) {
auto Rebuilt = rebuildMachineLiveness(Function, Target);
if (!Rebuilt)
return std::unexpected(Rebuilt.error());
}
Result.Changes = {MachinePassChange::Instructions, MachinePassChange::Operands,
MachinePassChange::Registers};
Result.Preserved = PreservedAnalyses::none();
return Result;
}
} // namespace rcc
|