blob: 00283cb200340db491bb73a5dcf2c67a1ece4dc6 [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());
Guillaume Chateletfb943542018-08-01 14:41:45 +000029 Operand.IsMem = OpInfo.OperandType == llvm::MCOI::OPERAND_MEMORY;
Clement Courbet0e69e2d2018-05-17 10:52:18 +000030 Operand.IsExplicit = true;
31 // TODO(gchatelet): Handle isLookupPtrRegClass.
32 if (OpInfo.RegClass >= 0)
33 Operand.Tracker = &RATC.getRegisterClass(OpInfo.RegClass);
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000034 Operand.TiedToIndex =
35 MCInstrDesc.getOperandConstraint(OpIndex, llvm::MCOI::TIED_TO);
Clement Courbet0e69e2d2018-05-17 10:52:18 +000036 Operand.Info = &OpInfo;
37 Operands.push_back(Operand);
38 }
39 for (const llvm::MCPhysReg *MCPhysReg = MCInstrDesc.getImplicitDefs();
40 MCPhysReg && *MCPhysReg; ++MCPhysReg, ++OpIndex) {
41 Operand Operand;
42 Operand.Index = OpIndex;
43 Operand.IsDef = true;
44 Operand.IsExplicit = false;
45 Operand.Tracker = &RATC.getRegister(*MCPhysReg);
46 Operand.ImplicitReg = MCPhysReg;
47 Operands.push_back(Operand);
48 }
49 for (const llvm::MCPhysReg *MCPhysReg = MCInstrDesc.getImplicitUses();
50 MCPhysReg && *MCPhysReg; ++MCPhysReg, ++OpIndex) {
51 Operand Operand;
52 Operand.Index = OpIndex;
53 Operand.IsDef = false;
54 Operand.IsExplicit = false;
55 Operand.Tracker = &RATC.getRegister(*MCPhysReg);
56 Operand.ImplicitReg = MCPhysReg;
57 Operands.push_back(Operand);
58 }
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000059 // Assigning Variables to non tied explicit operands.
60 Variables.reserve(Operands.size()); // Variables.size() <= Operands.size()
61 for (auto &Op : Operands)
62 if (Op.IsExplicit && Op.TiedToIndex < 0) {
63 const size_t VariableIndex = Variables.size();
64 Op.VariableIndex = VariableIndex;
65 Variables.emplace_back();
66 Variables.back().Index = VariableIndex;
Clement Courbet0e69e2d2018-05-17 10:52:18 +000067 }
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000068 // Assigning Variables to tied operands.
69 for (auto &Op : Operands)
70 if (Op.TiedToIndex >= 0)
71 Op.VariableIndex = Operands[Op.TiedToIndex].VariableIndex;
72 // Assigning Operands to Variables.
73 for (auto &Op : Operands)
74 if (Op.VariableIndex >= 0)
Guillaume Chateletef6cef52018-06-20 08:52:30 +000075 Variables[Op.VariableIndex].TiedOperands.push_back(Op.Index);
Clement Courbet0e69e2d2018-05-17 10:52:18 +000076 // Processing Aliasing.
77 DefRegisters = RATC.emptyRegisters();
78 UseRegisters = RATC.emptyRegisters();
79 for (const auto &Op : Operands) {
80 if (Op.Tracker) {
81 auto &Registers = Op.IsDef ? DefRegisters : UseRegisters;
82 Registers |= Op.Tracker->aliasedBits();
83 }
84 }
85}
86
Guillaume Chateletfb943542018-08-01 14:41:45 +000087bool Instruction::hasMemoryOperands() const {
88 return std::any_of(Operands.begin(), Operands.end(),
89 [](const Operand &Op) { return Op.IsMem; });
90}
91
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000092InstructionInstance::InstructionInstance(const Instruction &Instr)
93 : Instr(Instr), VariableValues(Instr.Variables.size()) {}
94
Clement Courbetcff2caa2018-06-25 11:22:23 +000095InstructionInstance::InstructionInstance(InstructionInstance &&) = default;
Guillaume Chateletef6cef52018-06-20 08:52:30 +000096
97InstructionInstance &InstructionInstance::
Clement Courbete4f885b2018-06-20 09:18:37 +000098operator=(InstructionInstance &&) = default;
Guillaume Chateletef6cef52018-06-20 08:52:30 +000099
Guillaume Chateletfb943542018-08-01 14:41:45 +0000100InstructionInstance::InstructionInstance(const InstructionInstance &) = default;
101
102InstructionInstance &InstructionInstance::
103operator=(const InstructionInstance &) = default;
104
Guillaume Chateletef6cef52018-06-20 08:52:30 +0000105unsigned InstructionInstance::getOpcode() const {
106 return Instr.Description->getOpcode();
107}
108
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000109llvm::MCOperand &InstructionInstance::getValueFor(const Variable &Var) {
110 return VariableValues[Var.Index];
111}
112
Clement Courbeta51efc22018-06-25 13:12:02 +0000113const llvm::MCOperand &
114InstructionInstance::getValueFor(const Variable &Var) const {
115 return VariableValues[Var.Index];
116}
117
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000118llvm::MCOperand &InstructionInstance::getValueFor(const Operand &Op) {
119 assert(Op.VariableIndex >= 0);
120 return getValueFor(Instr.Variables[Op.VariableIndex]);
121}
122
Clement Courbeta51efc22018-06-25 13:12:02 +0000123const llvm::MCOperand &
124InstructionInstance::getValueFor(const Operand &Op) const {
125 assert(Op.VariableIndex >= 0);
126 return getValueFor(Instr.Variables[Op.VariableIndex]);
127}
128
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000129// forward declaration.
Guillaume Chateletef6cef52018-06-20 08:52:30 +0000130static void randomize(const Instruction &Instr, const Variable &Var,
Guillaume Chateletfb943542018-08-01 14:41:45 +0000131 llvm::MCOperand &AssignedValue,
132 const llvm::BitVector &ForbiddenRegs);
Guillaume Chateletef6cef52018-06-20 08:52:30 +0000133
134bool InstructionInstance::hasImmediateVariables() const {
135 return llvm::any_of(Instr.Variables, [this](const Variable &Var) {
136 assert(!Var.TiedOperands.empty());
137 const unsigned OpIndex = Var.TiedOperands[0];
138 const Operand &Op = Instr.Operands[OpIndex];
139 assert(Op.Info);
140 return Op.Info->OperandType == llvm::MCOI::OPERAND_IMMEDIATE;
141 });
142}
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000143
Guillaume Chateletfb943542018-08-01 14:41:45 +0000144void InstructionInstance::randomizeUnsetVariables(
145 const llvm::BitVector &ForbiddenRegs) {
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000146 for (const Variable &Var : Instr.Variables) {
147 llvm::MCOperand &AssignedValue = getValueFor(Var);
148 if (!AssignedValue.isValid())
Guillaume Chateletfb943542018-08-01 14:41:45 +0000149 randomize(Instr, Var, AssignedValue, ForbiddenRegs);
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000150 }
Clement Courbeta51efc22018-06-25 13:12:02 +0000151}
152
153llvm::MCInst InstructionInstance::build() const {
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000154 llvm::MCInst Result;
Guillaume Chateletef6cef52018-06-20 08:52:30 +0000155 Result.setOpcode(Instr.Description->Opcode);
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000156 for (const auto &Op : Instr.Operands)
157 if (Op.IsExplicit)
158 Result.addOperand(getValueFor(Op));
159 return Result;
160}
161
Guillaume Chateletef6cef52018-06-20 08:52:30 +0000162SnippetPrototype::SnippetPrototype(SnippetPrototype &&) = default;
163
Clement Courbetcff2caa2018-06-25 11:22:23 +0000164SnippetPrototype &SnippetPrototype::operator=(SnippetPrototype &&) = default;
Guillaume Chateletef6cef52018-06-20 08:52:30 +0000165
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000166bool RegisterOperandAssignment::
167operator==(const RegisterOperandAssignment &Other) const {
168 return std::tie(Op, Reg) == std::tie(Other.Op, Other.Reg);
169}
170
171bool AliasingRegisterOperands::
172operator==(const AliasingRegisterOperands &Other) const {
173 return std::tie(Defs, Uses) == std::tie(Other.Defs, Other.Uses);
174}
175
176static void addOperandIfAlias(
177 const llvm::MCPhysReg Reg, bool SelectDef, llvm::ArrayRef<Operand> Operands,
178 llvm::SmallVectorImpl<RegisterOperandAssignment> &OperandValues) {
179 for (const auto &Op : Operands) {
180 if (Op.Tracker && Op.IsDef == SelectDef) {
181 const int SourceReg = Op.Tracker->getOrigin(Reg);
182 if (SourceReg >= 0)
183 OperandValues.emplace_back(&Op, SourceReg);
184 }
185 }
186}
187
188bool AliasingRegisterOperands::hasImplicitAliasing() const {
189 const auto HasImplicit = [](const RegisterOperandAssignment &ROV) {
190 return !ROV.Op->IsExplicit;
191 };
192 return llvm::any_of(Defs, HasImplicit) && llvm::any_of(Uses, HasImplicit);
193}
194
195bool AliasingConfigurations::empty() const { return Configurations.empty(); }
196
197bool AliasingConfigurations::hasImplicitAliasing() const {
198 return llvm::any_of(Configurations, [](const AliasingRegisterOperands &ARO) {
199 return ARO.hasImplicitAliasing();
200 });
201}
202
203AliasingConfigurations::AliasingConfigurations(
204 const Instruction &DefInstruction, const Instruction &UseInstruction)
205 : DefInstruction(DefInstruction), UseInstruction(UseInstruction) {
206 if (UseInstruction.UseRegisters.anyCommon(DefInstruction.DefRegisters)) {
207 auto CommonRegisters = UseInstruction.UseRegisters;
208 CommonRegisters &= DefInstruction.DefRegisters;
209 for (const llvm::MCPhysReg Reg : CommonRegisters.set_bits()) {
210 AliasingRegisterOperands ARO;
211 addOperandIfAlias(Reg, true, DefInstruction.Operands, ARO.Defs);
212 addOperandIfAlias(Reg, false, UseInstruction.Operands, ARO.Uses);
213 if (!ARO.Defs.empty() && !ARO.Uses.empty() &&
214 !llvm::is_contained(Configurations, ARO))
215 Configurations.push_back(std::move(ARO));
216 }
217 }
218}
219
220std::mt19937 &randomGenerator() {
221 static std::random_device RandomDevice;
222 static std::mt19937 RandomGenerator(RandomDevice());
223 return RandomGenerator;
224}
225
226static size_t randomIndex(size_t Size) {
227 assert(Size > 0);
228 std::uniform_int_distribution<> Distribution(0, Size - 1);
229 return Distribution(randomGenerator());
230}
231
232template <typename C>
233static auto randomElement(const C &Container) -> decltype(Container[0]) {
234 return Container[randomIndex(Container.size())];
235}
236
Guillaume Chateletef6cef52018-06-20 08:52:30 +0000237static void randomize(const Instruction &Instr, const Variable &Var,
Guillaume Chateletfb943542018-08-01 14:41:45 +0000238 llvm::MCOperand &AssignedValue,
239 const llvm::BitVector &ForbiddenRegs) {
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000240 assert(!Var.TiedOperands.empty());
Guillaume Chateletef6cef52018-06-20 08:52:30 +0000241 const Operand &Op = Instr.Operands[Var.TiedOperands.front()];
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000242 assert(Op.Info != nullptr);
243 const auto &OpInfo = *Op.Info;
244 switch (OpInfo.OperandType) {
245 case llvm::MCOI::OperandType::OPERAND_IMMEDIATE:
246 // FIXME: explore immediate values too.
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000247 AssignedValue = llvm::MCOperand::createImm(1);
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000248 break;
249 case llvm::MCOI::OperandType::OPERAND_REGISTER: {
250 assert(Op.Tracker);
Guillaume Chateletfb943542018-08-01 14:41:45 +0000251 auto AllowedRegs = Op.Tracker->sourceBits();
252 assert(AllowedRegs.size() == ForbiddenRegs.size());
253 for (auto I : ForbiddenRegs.set_bits())
254 AllowedRegs.reset(I);
255 AssignedValue = llvm::MCOperand::createReg(randomBit(AllowedRegs));
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000256 break;
257 }
258 default:
259 break;
260 }
261}
262
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000263static void setRegisterOperandValue(const RegisterOperandAssignment &ROV,
264 InstructionInstance &II) {
265 assert(ROV.Op);
Guillaume Chatelet60e3d582018-06-13 13:53:56 +0000266 if (ROV.Op->IsExplicit) {
267 auto &AssignedValue = II.getValueFor(*ROV.Op);
268 if (AssignedValue.isValid()) {
269 assert(AssignedValue.isReg() && AssignedValue.getReg() == ROV.Reg);
270 return;
271 }
272 AssignedValue = llvm::MCOperand::createReg(ROV.Reg);
273 } else {
274 assert(ROV.Op->ImplicitReg != nullptr);
275 assert(ROV.Reg == *ROV.Op->ImplicitReg);
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000276 }
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000277}
278
279size_t randomBit(const llvm::BitVector &Vector) {
280 assert(Vector.any());
281 auto Itr = Vector.set_bits_begin();
282 for (size_t I = randomIndex(Vector.count()); I != 0; --I)
283 ++Itr;
284 return *Itr;
285}
286
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000287void setRandomAliasing(const AliasingConfigurations &AliasingConfigurations,
288 InstructionInstance &DefII, InstructionInstance &UseII) {
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000289 assert(!AliasingConfigurations.empty());
290 assert(!AliasingConfigurations.hasImplicitAliasing());
291 const auto &RandomConf = randomElement(AliasingConfigurations.Configurations);
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000292 setRegisterOperandValue(randomElement(RandomConf.Defs), DefII);
293 setRegisterOperandValue(randomElement(RandomConf.Uses), UseII);
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000294}
295
296void DumpMCOperand(const llvm::MCRegisterInfo &MCRegisterInfo,
297 const llvm::MCOperand &Op, llvm::raw_ostream &OS) {
298 if (!Op.isValid())
299 OS << "Invalid";
300 else if (Op.isReg())
301 OS << MCRegisterInfo.getName(Op.getReg());
302 else if (Op.isImm())
303 OS << Op.getImm();
304 else if (Op.isFPImm())
305 OS << Op.getFPImm();
306 else if (Op.isExpr())
307 OS << "Expr";
308 else if (Op.isInst())
309 OS << "SubInst";
310}
311
312void DumpMCInst(const llvm::MCRegisterInfo &MCRegisterInfo,
313 const llvm::MCInstrInfo &MCInstrInfo,
314 const llvm::MCInst &MCInst, llvm::raw_ostream &OS) {
315 OS << MCInstrInfo.getName(MCInst.getOpcode());
316 for (unsigned I = 0, E = MCInst.getNumOperands(); I < E; ++I) {
317 if (I > 0)
318 OS << ',';
319 OS << ' ';
320 DumpMCOperand(MCRegisterInfo, MCInst.getOperand(I), OS);
321 }
322}
323
324} // namespace exegesis