blob: 5ea45c9efcbac598d66f930b8778fbedd47cd8cb [file] [log] [blame]
Clement Courbet0e69e2d2018-05-17 10:52:18 +00001//===-- MCInstrDescView.cpp -------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "MCInstrDescView.h"
11
12#include <iterator>
13#include <map>
14#include <tuple>
15
16#include "llvm/ADT/STLExtras.h"
17
18namespace exegesis {
19
Clement Courbet0e69e2d2018-05-17 10:52:18 +000020Instruction::Instruction(const llvm::MCInstrDesc &MCInstrDesc,
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000021 const RegisterAliasingTrackerCache &RATC)
Guillaume Chateletef6cef52018-06-20 08:52:30 +000022 : Description(&MCInstrDesc) {
Clement Courbet0e69e2d2018-05-17 10:52:18 +000023 unsigned OpIndex = 0;
24 for (; OpIndex < MCInstrDesc.getNumOperands(); ++OpIndex) {
25 const auto &OpInfo = MCInstrDesc.opInfo_begin()[OpIndex];
26 Operand Operand;
27 Operand.Index = OpIndex;
28 Operand.IsDef = (OpIndex < MCInstrDesc.getNumDefs());
29 Operand.IsExplicit = true;
30 // TODO(gchatelet): Handle isLookupPtrRegClass.
31 if (OpInfo.RegClass >= 0)
32 Operand.Tracker = &RATC.getRegisterClass(OpInfo.RegClass);
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000033 Operand.TiedToIndex =
34 MCInstrDesc.getOperandConstraint(OpIndex, llvm::MCOI::TIED_TO);
Clement Courbet0e69e2d2018-05-17 10:52:18 +000035 Operand.Info = &OpInfo;
36 Operands.push_back(Operand);
37 }
38 for (const llvm::MCPhysReg *MCPhysReg = MCInstrDesc.getImplicitDefs();
39 MCPhysReg && *MCPhysReg; ++MCPhysReg, ++OpIndex) {
40 Operand Operand;
41 Operand.Index = OpIndex;
42 Operand.IsDef = true;
43 Operand.IsExplicit = false;
44 Operand.Tracker = &RATC.getRegister(*MCPhysReg);
45 Operand.ImplicitReg = MCPhysReg;
46 Operands.push_back(Operand);
47 }
48 for (const llvm::MCPhysReg *MCPhysReg = MCInstrDesc.getImplicitUses();
49 MCPhysReg && *MCPhysReg; ++MCPhysReg, ++OpIndex) {
50 Operand Operand;
51 Operand.Index = OpIndex;
52 Operand.IsDef = false;
53 Operand.IsExplicit = false;
54 Operand.Tracker = &RATC.getRegister(*MCPhysReg);
55 Operand.ImplicitReg = MCPhysReg;
56 Operands.push_back(Operand);
57 }
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000058 // Assigning Variables to non tied explicit operands.
59 Variables.reserve(Operands.size()); // Variables.size() <= Operands.size()
60 for (auto &Op : Operands)
61 if (Op.IsExplicit && Op.TiedToIndex < 0) {
62 const size_t VariableIndex = Variables.size();
63 Op.VariableIndex = VariableIndex;
64 Variables.emplace_back();
65 Variables.back().Index = VariableIndex;
Clement Courbet0e69e2d2018-05-17 10:52:18 +000066 }
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000067 // Assigning Variables to tied operands.
68 for (auto &Op : Operands)
69 if (Op.TiedToIndex >= 0)
70 Op.VariableIndex = Operands[Op.TiedToIndex].VariableIndex;
71 // Assigning Operands to Variables.
72 for (auto &Op : Operands)
73 if (Op.VariableIndex >= 0)
Guillaume Chateletef6cef52018-06-20 08:52:30 +000074 Variables[Op.VariableIndex].TiedOperands.push_back(Op.Index);
Clement Courbet0e69e2d2018-05-17 10:52:18 +000075 // Processing Aliasing.
76 DefRegisters = RATC.emptyRegisters();
77 UseRegisters = RATC.emptyRegisters();
78 for (const auto &Op : Operands) {
79 if (Op.Tracker) {
80 auto &Registers = Op.IsDef ? DefRegisters : UseRegisters;
81 Registers |= Op.Tracker->aliasedBits();
82 }
83 }
84}
85
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000086InstructionInstance::InstructionInstance(const Instruction &Instr)
87 : Instr(Instr), VariableValues(Instr.Variables.size()) {}
88
Guillaume Chateletef6cef52018-06-20 08:52:30 +000089InstructionInstance::InstructionInstance(InstructionInstance &&) noexcept =
90 default;
91
92InstructionInstance &InstructionInstance::
93operator=(InstructionInstance &&) noexcept = default;
94
95unsigned InstructionInstance::getOpcode() const {
96 return Instr.Description->getOpcode();
97}
98
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000099llvm::MCOperand &InstructionInstance::getValueFor(const Variable &Var) {
100 return VariableValues[Var.Index];
101}
102
103llvm::MCOperand &InstructionInstance::getValueFor(const Operand &Op) {
104 assert(Op.VariableIndex >= 0);
105 return getValueFor(Instr.Variables[Op.VariableIndex]);
106}
107
108// forward declaration.
Guillaume Chateletef6cef52018-06-20 08:52:30 +0000109static void randomize(const Instruction &Instr, const Variable &Var,
110 llvm::MCOperand &AssignedValue);
111
112bool InstructionInstance::hasImmediateVariables() const {
113 return llvm::any_of(Instr.Variables, [this](const Variable &Var) {
114 assert(!Var.TiedOperands.empty());
115 const unsigned OpIndex = Var.TiedOperands[0];
116 const Operand &Op = Instr.Operands[OpIndex];
117 assert(Op.Info);
118 return Op.Info->OperandType == llvm::MCOI::OPERAND_IMMEDIATE;
119 });
120}
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000121
122llvm::MCInst InstructionInstance::randomizeUnsetVariablesAndBuild() {
123 for (const Variable &Var : Instr.Variables) {
124 llvm::MCOperand &AssignedValue = getValueFor(Var);
125 if (!AssignedValue.isValid())
Guillaume Chateletef6cef52018-06-20 08:52:30 +0000126 randomize(Instr, Var, AssignedValue);
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000127 }
128 llvm::MCInst Result;
Guillaume Chateletef6cef52018-06-20 08:52:30 +0000129 Result.setOpcode(Instr.Description->Opcode);
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000130 for (const auto &Op : Instr.Operands)
131 if (Op.IsExplicit)
132 Result.addOperand(getValueFor(Op));
133 return Result;
134}
135
Guillaume Chateletef6cef52018-06-20 08:52:30 +0000136SnippetPrototype::SnippetPrototype(SnippetPrototype &&) = default;
137
138SnippetPrototype &SnippetPrototype::operator=(SnippetPrototype &&) = default;
139
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000140bool RegisterOperandAssignment::
141operator==(const RegisterOperandAssignment &Other) const {
142 return std::tie(Op, Reg) == std::tie(Other.Op, Other.Reg);
143}
144
145bool AliasingRegisterOperands::
146operator==(const AliasingRegisterOperands &Other) const {
147 return std::tie(Defs, Uses) == std::tie(Other.Defs, Other.Uses);
148}
149
150static void addOperandIfAlias(
151 const llvm::MCPhysReg Reg, bool SelectDef, llvm::ArrayRef<Operand> Operands,
152 llvm::SmallVectorImpl<RegisterOperandAssignment> &OperandValues) {
153 for (const auto &Op : Operands) {
154 if (Op.Tracker && Op.IsDef == SelectDef) {
155 const int SourceReg = Op.Tracker->getOrigin(Reg);
156 if (SourceReg >= 0)
157 OperandValues.emplace_back(&Op, SourceReg);
158 }
159 }
160}
161
162bool AliasingRegisterOperands::hasImplicitAliasing() const {
163 const auto HasImplicit = [](const RegisterOperandAssignment &ROV) {
164 return !ROV.Op->IsExplicit;
165 };
166 return llvm::any_of(Defs, HasImplicit) && llvm::any_of(Uses, HasImplicit);
167}
168
169bool AliasingConfigurations::empty() const { return Configurations.empty(); }
170
171bool AliasingConfigurations::hasImplicitAliasing() const {
172 return llvm::any_of(Configurations, [](const AliasingRegisterOperands &ARO) {
173 return ARO.hasImplicitAliasing();
174 });
175}
176
177AliasingConfigurations::AliasingConfigurations(
178 const Instruction &DefInstruction, const Instruction &UseInstruction)
179 : DefInstruction(DefInstruction), UseInstruction(UseInstruction) {
180 if (UseInstruction.UseRegisters.anyCommon(DefInstruction.DefRegisters)) {
181 auto CommonRegisters = UseInstruction.UseRegisters;
182 CommonRegisters &= DefInstruction.DefRegisters;
183 for (const llvm::MCPhysReg Reg : CommonRegisters.set_bits()) {
184 AliasingRegisterOperands ARO;
185 addOperandIfAlias(Reg, true, DefInstruction.Operands, ARO.Defs);
186 addOperandIfAlias(Reg, false, UseInstruction.Operands, ARO.Uses);
187 if (!ARO.Defs.empty() && !ARO.Uses.empty() &&
188 !llvm::is_contained(Configurations, ARO))
189 Configurations.push_back(std::move(ARO));
190 }
191 }
192}
193
194std::mt19937 &randomGenerator() {
195 static std::random_device RandomDevice;
196 static std::mt19937 RandomGenerator(RandomDevice());
197 return RandomGenerator;
198}
199
200static size_t randomIndex(size_t Size) {
201 assert(Size > 0);
202 std::uniform_int_distribution<> Distribution(0, Size - 1);
203 return Distribution(randomGenerator());
204}
205
206template <typename C>
207static auto randomElement(const C &Container) -> decltype(Container[0]) {
208 return Container[randomIndex(Container.size())];
209}
210
Guillaume Chateletef6cef52018-06-20 08:52:30 +0000211static void randomize(const Instruction &Instr, const Variable &Var,
212 llvm::MCOperand &AssignedValue) {
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000213 assert(!Var.TiedOperands.empty());
Guillaume Chateletef6cef52018-06-20 08:52:30 +0000214 const Operand &Op = Instr.Operands[Var.TiedOperands.front()];
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000215 assert(Op.Info != nullptr);
216 const auto &OpInfo = *Op.Info;
217 switch (OpInfo.OperandType) {
218 case llvm::MCOI::OperandType::OPERAND_IMMEDIATE:
219 // FIXME: explore immediate values too.
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000220 AssignedValue = llvm::MCOperand::createImm(1);
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000221 break;
222 case llvm::MCOI::OperandType::OPERAND_REGISTER: {
223 assert(Op.Tracker);
224 const auto &Registers = Op.Tracker->sourceBits();
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000225 AssignedValue = llvm::MCOperand::createReg(randomBit(Registers));
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000226 break;
227 }
228 default:
229 break;
230 }
231}
232
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000233static void setRegisterOperandValue(const RegisterOperandAssignment &ROV,
234 InstructionInstance &II) {
235 assert(ROV.Op);
Guillaume Chatelet60e3d582018-06-13 13:53:56 +0000236 if (ROV.Op->IsExplicit) {
237 auto &AssignedValue = II.getValueFor(*ROV.Op);
238 if (AssignedValue.isValid()) {
239 assert(AssignedValue.isReg() && AssignedValue.getReg() == ROV.Reg);
240 return;
241 }
242 AssignedValue = llvm::MCOperand::createReg(ROV.Reg);
243 } else {
244 assert(ROV.Op->ImplicitReg != nullptr);
245 assert(ROV.Reg == *ROV.Op->ImplicitReg);
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000246 }
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000247}
248
249size_t randomBit(const llvm::BitVector &Vector) {
250 assert(Vector.any());
251 auto Itr = Vector.set_bits_begin();
252 for (size_t I = randomIndex(Vector.count()); I != 0; --I)
253 ++Itr;
254 return *Itr;
255}
256
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000257void setRandomAliasing(const AliasingConfigurations &AliasingConfigurations,
258 InstructionInstance &DefII, InstructionInstance &UseII) {
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000259 assert(!AliasingConfigurations.empty());
260 assert(!AliasingConfigurations.hasImplicitAliasing());
261 const auto &RandomConf = randomElement(AliasingConfigurations.Configurations);
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000262 setRegisterOperandValue(randomElement(RandomConf.Defs), DefII);
263 setRegisterOperandValue(randomElement(RandomConf.Uses), UseII);
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000264}
265
266void DumpMCOperand(const llvm::MCRegisterInfo &MCRegisterInfo,
267 const llvm::MCOperand &Op, llvm::raw_ostream &OS) {
268 if (!Op.isValid())
269 OS << "Invalid";
270 else if (Op.isReg())
271 OS << MCRegisterInfo.getName(Op.getReg());
272 else if (Op.isImm())
273 OS << Op.getImm();
274 else if (Op.isFPImm())
275 OS << Op.getFPImm();
276 else if (Op.isExpr())
277 OS << "Expr";
278 else if (Op.isInst())
279 OS << "SubInst";
280}
281
282void DumpMCInst(const llvm::MCRegisterInfo &MCRegisterInfo,
283 const llvm::MCInstrInfo &MCInstrInfo,
284 const llvm::MCInst &MCInst, llvm::raw_ostream &OS) {
285 OS << MCInstrInfo.getName(MCInst.getOpcode());
286 for (unsigned I = 0, E = MCInst.getNumOperands(); I < E; ++I) {
287 if (I > 0)
288 OS << ',';
289 OS << ' ';
290 DumpMCOperand(MCRegisterInfo, MCInst.getOperand(I), OS);
291 }
292}
293
294} // namespace exegesis