1 //===-- SerialSnippetGenerator.cpp ------------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "SerialSnippetGenerator.h"
11 #include "CodeTemplate.h"
12 #include "MCInstrDescView.h"
21 struct ExecutionClass
{
23 const char *Description
;
24 } static const kExecutionClasses
[] = {
25 {ExecutionMode::ALWAYS_SERIAL_IMPLICIT_REGS_ALIAS
|
26 ExecutionMode::ALWAYS_SERIAL_TIED_REGS_ALIAS
,
27 "Repeating a single implicitly serial instruction"},
28 {ExecutionMode::SERIAL_VIA_EXPLICIT_REGS
,
29 "Repeating a single explicitly serial instruction"},
30 {ExecutionMode::SERIAL_VIA_MEMORY_INSTR
|
31 ExecutionMode::SERIAL_VIA_NON_MEMORY_INSTR
,
32 "Repeating two instructions"},
35 static constexpr size_t kMaxAliasingInstructions
= 10;
37 static std::vector
<const Instruction
*>
38 computeAliasingInstructions(const LLVMState
&State
, const Instruction
*Instr
,
39 size_t MaxAliasingInstructions
,
40 const BitVector
&ForbiddenRegisters
) {
41 const auto &ET
= State
.getExegesisTarget();
42 const auto AvailableFeatures
= State
.getSubtargetInfo().getFeatureBits();
43 // Randomly iterate the set of instructions.
44 std::vector
<unsigned> Opcodes
;
45 Opcodes
.resize(State
.getInstrInfo().getNumOpcodes());
46 std::iota(Opcodes
.begin(), Opcodes
.end(), 0U);
47 llvm::shuffle(Opcodes
.begin(), Opcodes
.end(), randomGenerator());
49 std::vector
<const Instruction
*> AliasingInstructions
;
50 for (const unsigned OtherOpcode
: Opcodes
) {
51 if (!ET
.isOpcodeAvailable(OtherOpcode
, AvailableFeatures
))
53 if (OtherOpcode
== Instr
->Description
.getOpcode())
55 const Instruction
&OtherInstr
= State
.getIC().getInstr(OtherOpcode
);
56 const MCInstrDesc
&OtherInstrDesc
= OtherInstr
.Description
;
57 // Ignore instructions that we cannot run.
58 if (OtherInstrDesc
.isPseudo() || OtherInstrDesc
.usesCustomInsertionHook() ||
59 OtherInstrDesc
.isBranch() || OtherInstrDesc
.isIndirectBranch() ||
60 OtherInstrDesc
.isCall() || OtherInstrDesc
.isReturn()) {
63 if (OtherInstr
.hasMemoryOperands())
65 if (!ET
.allowAsBackToBack(OtherInstr
))
67 if (Instr
->hasAliasingRegistersThrough(OtherInstr
, ForbiddenRegisters
))
68 AliasingInstructions
.push_back(&OtherInstr
);
69 if (AliasingInstructions
.size() >= MaxAliasingInstructions
)
72 return AliasingInstructions
;
75 static ExecutionMode
getExecutionModes(const Instruction
&Instr
,
76 const BitVector
&ForbiddenRegisters
) {
77 ExecutionMode EM
= ExecutionMode::UNKNOWN
;
78 if (Instr
.hasAliasingImplicitRegisters())
79 EM
|= ExecutionMode::ALWAYS_SERIAL_IMPLICIT_REGS_ALIAS
;
80 if (Instr
.hasTiedRegisters())
81 EM
|= ExecutionMode::ALWAYS_SERIAL_TIED_REGS_ALIAS
;
82 if (Instr
.hasMemoryOperands())
83 EM
|= ExecutionMode::SERIAL_VIA_MEMORY_INSTR
;
85 if (Instr
.hasAliasingRegisters(ForbiddenRegisters
))
86 EM
|= ExecutionMode::SERIAL_VIA_EXPLICIT_REGS
;
87 if (Instr
.hasOneUseOrOneDef())
88 EM
|= ExecutionMode::SERIAL_VIA_NON_MEMORY_INSTR
;
93 static void appendCodeTemplates(const LLVMState
&State
,
94 InstructionTemplate Variant
,
95 const BitVector
&ForbiddenRegisters
,
96 ExecutionMode ExecutionModeBit
,
97 StringRef ExecutionClassDescription
,
98 std::vector
<CodeTemplate
> &CodeTemplates
) {
99 assert(isEnumValue(ExecutionModeBit
) && "Bit must be a power of two");
100 switch (ExecutionModeBit
) {
101 case ExecutionMode::ALWAYS_SERIAL_IMPLICIT_REGS_ALIAS
:
102 // Nothing to do, the instruction is always serial.
104 case ExecutionMode::ALWAYS_SERIAL_TIED_REGS_ALIAS
: {
105 // Picking whatever value for the tied variable will make the instruction
108 CT
.Execution
= ExecutionModeBit
;
109 CT
.Info
= std::string(ExecutionClassDescription
);
110 CT
.Instructions
.push_back(std::move(Variant
));
111 CodeTemplates
.push_back(std::move(CT
));
114 case ExecutionMode::SERIAL_VIA_MEMORY_INSTR
: {
115 // Select back-to-back memory instruction.
116 // TODO: Implement me.
119 case ExecutionMode::SERIAL_VIA_EXPLICIT_REGS
: {
120 // Making the execution of this instruction serial by selecting one def
121 // register to alias with one use register.
122 const AliasingConfigurations
SelfAliasing(
123 Variant
.getInstr(), Variant
.getInstr(), ForbiddenRegisters
);
124 assert(!SelfAliasing
.empty() && !SelfAliasing
.hasImplicitAliasing() &&
125 "Instr must alias itself explicitly");
126 // This is a self aliasing instruction so defs and uses are from the same
127 // instance, hence twice Variant in the following call.
128 setRandomAliasing(SelfAliasing
, Variant
, Variant
);
130 CT
.Execution
= ExecutionModeBit
;
131 CT
.Info
= std::string(ExecutionClassDescription
);
132 CT
.Instructions
.push_back(std::move(Variant
));
133 CodeTemplates
.push_back(std::move(CT
));
136 case ExecutionMode::SERIAL_VIA_NON_MEMORY_INSTR
: {
137 const Instruction
&Instr
= Variant
.getInstr();
138 // Select back-to-back non-memory instruction.
139 for (const auto *OtherInstr
: computeAliasingInstructions(
140 State
, &Instr
, kMaxAliasingInstructions
, ForbiddenRegisters
)) {
141 const AliasingConfigurations
Forward(Instr
, *OtherInstr
,
143 const AliasingConfigurations
Back(*OtherInstr
, Instr
, ForbiddenRegisters
);
144 InstructionTemplate
ThisIT(Variant
);
145 InstructionTemplate
OtherIT(OtherInstr
);
146 if (!Forward
.hasImplicitAliasing())
147 setRandomAliasing(Forward
, ThisIT
, OtherIT
);
148 else if (!Back
.hasImplicitAliasing())
149 setRandomAliasing(Back
, OtherIT
, ThisIT
);
151 CT
.Execution
= ExecutionModeBit
;
152 CT
.Info
= std::string(ExecutionClassDescription
);
153 CT
.Instructions
.push_back(std::move(ThisIT
));
154 CT
.Instructions
.push_back(std::move(OtherIT
));
155 CodeTemplates
.push_back(std::move(CT
));
160 llvm_unreachable("Unhandled enum value");
164 SerialSnippetGenerator::~SerialSnippetGenerator() = default;
166 Expected
<std::vector
<CodeTemplate
>>
167 SerialSnippetGenerator::generateCodeTemplates(
168 InstructionTemplate Variant
, const BitVector
&ForbiddenRegisters
) const {
169 std::vector
<CodeTemplate
> Results
;
170 const ExecutionMode EM
=
171 getExecutionModes(Variant
.getInstr(), ForbiddenRegisters
);
172 for (const auto EC
: kExecutionClasses
) {
173 for (const auto ExecutionModeBit
: getExecutionModeBits(EM
& EC
.Mask
))
174 appendCodeTemplates(State
, Variant
, ForbiddenRegisters
, ExecutionModeBit
,
175 EC
.Description
, Results
);
176 if (!Results
.empty())
180 return make_error
<Failure
>(
181 "No strategy found to make the execution serial");
182 return std::move(Results
);
185 } // namespace exegesis