1 //===-- 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 
18 namespace exegesis {
19 
Instruction(const llvm::MCInstrDesc & MCInstrDesc,const RegisterAliasingTrackerCache & RATC)20 Instruction::Instruction(const llvm::MCInstrDesc &MCInstrDesc,
21                          const RegisterAliasingTrackerCache &RATC)
22     : Description(&MCInstrDesc) {
23   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);
33     Operand.TiedToIndex =
34         MCInstrDesc.getOperandConstraint(OpIndex, llvm::MCOI::TIED_TO);
35     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   }
58   // 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;
66     }
67   // 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)
74       Variables[Op.VariableIndex].TiedOperands.push_back(Op.Index);
75   // 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 
InstructionInstance(const Instruction & Instr)86 InstructionInstance::InstructionInstance(const Instruction &Instr)
87     : Instr(Instr), VariableValues(Instr.Variables.size()) {}
88 
89 InstructionInstance::InstructionInstance(InstructionInstance &&) = default;
90 
91 InstructionInstance &InstructionInstance::
92 operator=(InstructionInstance &&) = default;
93 
getOpcode() const94 unsigned InstructionInstance::getOpcode() const {
95   return Instr.Description->getOpcode();
96 }
97 
getValueFor(const Variable & Var)98 llvm::MCOperand &InstructionInstance::getValueFor(const Variable &Var) {
99   return VariableValues[Var.Index];
100 }
101 
102 const llvm::MCOperand &
getValueFor(const Variable & Var) const103 InstructionInstance::getValueFor(const Variable &Var) const {
104   return VariableValues[Var.Index];
105 }
106 
getValueFor(const Operand & Op)107 llvm::MCOperand &InstructionInstance::getValueFor(const Operand &Op) {
108   assert(Op.VariableIndex >= 0);
109   return getValueFor(Instr.Variables[Op.VariableIndex]);
110 }
111 
112 const llvm::MCOperand &
getValueFor(const Operand & Op) const113 InstructionInstance::getValueFor(const Operand &Op) const {
114   assert(Op.VariableIndex >= 0);
115   return getValueFor(Instr.Variables[Op.VariableIndex]);
116 }
117 
118 // forward declaration.
119 static void randomize(const Instruction &Instr, const Variable &Var,
120                       llvm::MCOperand &AssignedValue);
121 
hasImmediateVariables() const122 bool InstructionInstance::hasImmediateVariables() const {
123   return llvm::any_of(Instr.Variables, [this](const Variable &Var) {
124     assert(!Var.TiedOperands.empty());
125     const unsigned OpIndex = Var.TiedOperands[0];
126     const Operand &Op = Instr.Operands[OpIndex];
127     assert(Op.Info);
128     return Op.Info->OperandType == llvm::MCOI::OPERAND_IMMEDIATE;
129   });
130 }
131 
randomizeUnsetVariables()132 void InstructionInstance::randomizeUnsetVariables() {
133   for (const Variable &Var : Instr.Variables) {
134     llvm::MCOperand &AssignedValue = getValueFor(Var);
135     if (!AssignedValue.isValid())
136       randomize(Instr, Var, AssignedValue);
137   }
138 }
139 
build() const140 llvm::MCInst InstructionInstance::build() const {
141   llvm::MCInst Result;
142   Result.setOpcode(Instr.Description->Opcode);
143   for (const auto &Op : Instr.Operands)
144     if (Op.IsExplicit)
145       Result.addOperand(getValueFor(Op));
146   return Result;
147 }
148 
149 SnippetPrototype::SnippetPrototype(SnippetPrototype &&) = default;
150 
151 SnippetPrototype &SnippetPrototype::operator=(SnippetPrototype &&) = default;
152 
153 bool RegisterOperandAssignment::
operator ==(const RegisterOperandAssignment & Other) const154 operator==(const RegisterOperandAssignment &Other) const {
155   return std::tie(Op, Reg) == std::tie(Other.Op, Other.Reg);
156 }
157 
158 bool AliasingRegisterOperands::
operator ==(const AliasingRegisterOperands & Other) const159 operator==(const AliasingRegisterOperands &Other) const {
160   return std::tie(Defs, Uses) == std::tie(Other.Defs, Other.Uses);
161 }
162 
addOperandIfAlias(const llvm::MCPhysReg Reg,bool SelectDef,llvm::ArrayRef<Operand> Operands,llvm::SmallVectorImpl<RegisterOperandAssignment> & OperandValues)163 static void addOperandIfAlias(
164     const llvm::MCPhysReg Reg, bool SelectDef, llvm::ArrayRef<Operand> Operands,
165     llvm::SmallVectorImpl<RegisterOperandAssignment> &OperandValues) {
166   for (const auto &Op : Operands) {
167     if (Op.Tracker && Op.IsDef == SelectDef) {
168       const int SourceReg = Op.Tracker->getOrigin(Reg);
169       if (SourceReg >= 0)
170         OperandValues.emplace_back(&Op, SourceReg);
171     }
172   }
173 }
174 
hasImplicitAliasing() const175 bool AliasingRegisterOperands::hasImplicitAliasing() const {
176   const auto HasImplicit = [](const RegisterOperandAssignment &ROV) {
177     return !ROV.Op->IsExplicit;
178   };
179   return llvm::any_of(Defs, HasImplicit) && llvm::any_of(Uses, HasImplicit);
180 }
181 
empty() const182 bool AliasingConfigurations::empty() const { return Configurations.empty(); }
183 
hasImplicitAliasing() const184 bool AliasingConfigurations::hasImplicitAliasing() const {
185   return llvm::any_of(Configurations, [](const AliasingRegisterOperands &ARO) {
186     return ARO.hasImplicitAliasing();
187   });
188 }
189 
AliasingConfigurations(const Instruction & DefInstruction,const Instruction & UseInstruction)190 AliasingConfigurations::AliasingConfigurations(
191     const Instruction &DefInstruction, const Instruction &UseInstruction)
192     : DefInstruction(DefInstruction), UseInstruction(UseInstruction) {
193   if (UseInstruction.UseRegisters.anyCommon(DefInstruction.DefRegisters)) {
194     auto CommonRegisters = UseInstruction.UseRegisters;
195     CommonRegisters &= DefInstruction.DefRegisters;
196     for (const llvm::MCPhysReg Reg : CommonRegisters.set_bits()) {
197       AliasingRegisterOperands ARO;
198       addOperandIfAlias(Reg, true, DefInstruction.Operands, ARO.Defs);
199       addOperandIfAlias(Reg, false, UseInstruction.Operands, ARO.Uses);
200       if (!ARO.Defs.empty() && !ARO.Uses.empty() &&
201           !llvm::is_contained(Configurations, ARO))
202         Configurations.push_back(std::move(ARO));
203     }
204   }
205 }
206 
randomGenerator()207 std::mt19937 &randomGenerator() {
208   static std::random_device RandomDevice;
209   static std::mt19937 RandomGenerator(RandomDevice());
210   return RandomGenerator;
211 }
212 
randomIndex(size_t Size)213 static size_t randomIndex(size_t Size) {
214   assert(Size > 0);
215   std::uniform_int_distribution<> Distribution(0, Size - 1);
216   return Distribution(randomGenerator());
217 }
218 
219 template <typename C>
randomElement(const C & Container)220 static auto randomElement(const C &Container) -> decltype(Container[0]) {
221   return Container[randomIndex(Container.size())];
222 }
223 
randomize(const Instruction & Instr,const Variable & Var,llvm::MCOperand & AssignedValue)224 static void randomize(const Instruction &Instr, const Variable &Var,
225                       llvm::MCOperand &AssignedValue) {
226   assert(!Var.TiedOperands.empty());
227   const Operand &Op = Instr.Operands[Var.TiedOperands.front()];
228   assert(Op.Info != nullptr);
229   const auto &OpInfo = *Op.Info;
230   switch (OpInfo.OperandType) {
231   case llvm::MCOI::OperandType::OPERAND_IMMEDIATE:
232     // FIXME: explore immediate values too.
233     AssignedValue = llvm::MCOperand::createImm(1);
234     break;
235   case llvm::MCOI::OperandType::OPERAND_REGISTER: {
236     assert(Op.Tracker);
237     const auto &Registers = Op.Tracker->sourceBits();
238     AssignedValue = llvm::MCOperand::createReg(randomBit(Registers));
239     break;
240   }
241   default:
242     break;
243   }
244 }
245 
setRegisterOperandValue(const RegisterOperandAssignment & ROV,InstructionInstance & II)246 static void setRegisterOperandValue(const RegisterOperandAssignment &ROV,
247                                     InstructionInstance &II) {
248   assert(ROV.Op);
249   if (ROV.Op->IsExplicit) {
250     auto &AssignedValue = II.getValueFor(*ROV.Op);
251     if (AssignedValue.isValid()) {
252       assert(AssignedValue.isReg() && AssignedValue.getReg() == ROV.Reg);
253       return;
254     }
255     AssignedValue = llvm::MCOperand::createReg(ROV.Reg);
256   } else {
257     assert(ROV.Op->ImplicitReg != nullptr);
258     assert(ROV.Reg == *ROV.Op->ImplicitReg);
259   }
260 }
261 
randomBit(const llvm::BitVector & Vector)262 size_t randomBit(const llvm::BitVector &Vector) {
263   assert(Vector.any());
264   auto Itr = Vector.set_bits_begin();
265   for (size_t I = randomIndex(Vector.count()); I != 0; --I)
266     ++Itr;
267   return *Itr;
268 }
269 
setRandomAliasing(const AliasingConfigurations & AliasingConfigurations,InstructionInstance & DefII,InstructionInstance & UseII)270 void setRandomAliasing(const AliasingConfigurations &AliasingConfigurations,
271                        InstructionInstance &DefII, InstructionInstance &UseII) {
272   assert(!AliasingConfigurations.empty());
273   assert(!AliasingConfigurations.hasImplicitAliasing());
274   const auto &RandomConf = randomElement(AliasingConfigurations.Configurations);
275   setRegisterOperandValue(randomElement(RandomConf.Defs), DefII);
276   setRegisterOperandValue(randomElement(RandomConf.Uses), UseII);
277 }
278 
DumpMCOperand(const llvm::MCRegisterInfo & MCRegisterInfo,const llvm::MCOperand & Op,llvm::raw_ostream & OS)279 void DumpMCOperand(const llvm::MCRegisterInfo &MCRegisterInfo,
280                    const llvm::MCOperand &Op, llvm::raw_ostream &OS) {
281   if (!Op.isValid())
282     OS << "Invalid";
283   else if (Op.isReg())
284     OS << MCRegisterInfo.getName(Op.getReg());
285   else if (Op.isImm())
286     OS << Op.getImm();
287   else if (Op.isFPImm())
288     OS << Op.getFPImm();
289   else if (Op.isExpr())
290     OS << "Expr";
291   else if (Op.isInst())
292     OS << "SubInst";
293 }
294 
DumpMCInst(const llvm::MCRegisterInfo & MCRegisterInfo,const llvm::MCInstrInfo & MCInstrInfo,const llvm::MCInst & MCInst,llvm::raw_ostream & OS)295 void DumpMCInst(const llvm::MCRegisterInfo &MCRegisterInfo,
296                 const llvm::MCInstrInfo &MCInstrInfo,
297                 const llvm::MCInst &MCInst, llvm::raw_ostream &OS) {
298   OS << MCInstrInfo.getName(MCInst.getOpcode());
299   for (unsigned I = 0, E = MCInst.getNumOperands(); I < E; ++I) {
300     if (I > 0)
301       OS << ',';
302     OS << ' ';
303     DumpMCOperand(MCRegisterInfo, MCInst.getOperand(I), OS);
304   }
305 }
306 
307 } // namespace exegesis
308