blob: b6c6a01d5ed6318653c6564da61508a076de296a [file] [log] [blame]
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +00001//===--------------------- InstrBuilder.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/// \file
10///
11/// This file implements the InstrBuilder interface.
12///
13//===----------------------------------------------------------------------===//
14
15#include "InstrBuilder.h"
Andrea Di Biagio2145b132018-06-20 10:08:11 +000016#include "llvm/ADT/APInt.h"
Andrea Di Biagio2008c7c2018-06-04 12:23:07 +000017#include "llvm/ADT/DenseMap.h"
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000018#include "llvm/MC/MCInst.h"
19#include "llvm/Support/Debug.h"
Andrea Di Biagio24fb4fc2018-05-04 13:52:12 +000020#include "llvm/Support/WithColor.h"
Andrea Di Biagio88347792018-07-09 12:30:55 +000021#include "llvm/Support/raw_ostream.h"
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000022
23#define DEBUG_TYPE "llvm-mca"
24
Fangrui Song5a8fd652018-10-30 15:56:08 +000025namespace llvm {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000026namespace mca {
27
Andrea Di Biagio77c26ae2018-10-25 11:51:34 +000028InstrBuilder::InstrBuilder(const llvm::MCSubtargetInfo &sti,
29 const llvm::MCInstrInfo &mcii,
30 const llvm::MCRegisterInfo &mri,
31 const llvm::MCInstrAnalysis &mcia)
32 : STI(sti), MCII(mcii), MRI(mri), MCIA(mcia) {
33 computeProcResourceMasks(STI.getSchedModel(), ProcResourceMasks);
34}
35
Andrea Di Biagio94fafdf2018-03-24 16:05:36 +000036static void initializeUsedResources(InstrDesc &ID,
37 const MCSchedClassDesc &SCDesc,
38 const MCSubtargetInfo &STI,
39 ArrayRef<uint64_t> ProcResourceMasks) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000040 const MCSchedModel &SM = STI.getSchedModel();
41
42 // Populate resources consumed.
43 using ResourcePlusCycles = std::pair<uint64_t, ResourceUsage>;
44 std::vector<ResourcePlusCycles> Worklist;
Andrea Di Biagio2008c7c2018-06-04 12:23:07 +000045
46 // Track cycles contributed by resources that are in a "Super" relationship.
47 // This is required if we want to correctly match the behavior of method
48 // SubtargetEmitter::ExpandProcResource() in Tablegen. When computing the set
49 // of "consumed" processor resources and resource cycles, the logic in
50 // ExpandProcResource() doesn't update the number of resource cycles
51 // contributed by a "Super" resource to a group.
52 // We need to take this into account when we find that a processor resource is
53 // part of a group, and it is also used as the "Super" of other resources.
54 // This map stores the number of cycles contributed by sub-resources that are
55 // part of a "Super" resource. The key value is the "Super" resource mask ID.
56 DenseMap<uint64_t, unsigned> SuperResources;
57
Andrea Di Biagio91bdf242018-11-09 19:30:20 +000058 unsigned NumProcResources = SM.getNumProcResourceKinds();
59 APInt Buffers(NumProcResources, 0);
60
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000061 for (unsigned I = 0, E = SCDesc.NumWriteProcResEntries; I < E; ++I) {
62 const MCWriteProcResEntry *PRE = STI.getWriteProcResBegin(&SCDesc) + I;
63 const MCProcResourceDesc &PR = *SM.getProcResource(PRE->ProcResourceIdx);
64 uint64_t Mask = ProcResourceMasks[PRE->ProcResourceIdx];
65 if (PR.BufferSize != -1)
Andrea Di Biagio91bdf242018-11-09 19:30:20 +000066 Buffers.setBit(PRE->ProcResourceIdx);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000067 CycleSegment RCy(0, PRE->Cycles, false);
68 Worklist.emplace_back(ResourcePlusCycles(Mask, ResourceUsage(RCy)));
Andrea Di Biagio2008c7c2018-06-04 12:23:07 +000069 if (PR.SuperIdx) {
70 uint64_t Super = ProcResourceMasks[PR.SuperIdx];
71 SuperResources[Super] += PRE->Cycles;
72 }
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000073 }
74
75 // Sort elements by mask popcount, so that we prioritize resource units over
76 // resource groups, and smaller groups over larger groups.
Andrea Di Biagioa7699122018-09-28 10:47:24 +000077 sort(Worklist, [](const ResourcePlusCycles &A, const ResourcePlusCycles &B) {
78 unsigned popcntA = countPopulation(A.first);
79 unsigned popcntB = countPopulation(B.first);
80 if (popcntA < popcntB)
81 return true;
82 if (popcntA > popcntB)
83 return false;
84 return A.first < B.first;
85 });
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000086
87 uint64_t UsedResourceUnits = 0;
88
89 // Remove cycles contributed by smaller resources.
90 for (unsigned I = 0, E = Worklist.size(); I < E; ++I) {
91 ResourcePlusCycles &A = Worklist[I];
92 if (!A.second.size()) {
93 A.second.NumUnits = 0;
94 A.second.setReserved();
95 ID.Resources.emplace_back(A);
96 continue;
97 }
98
99 ID.Resources.emplace_back(A);
100 uint64_t NormalizedMask = A.first;
101 if (countPopulation(A.first) == 1) {
102 UsedResourceUnits |= A.first;
103 } else {
104 // Remove the leading 1 from the resource group mask.
105 NormalizedMask ^= PowerOf2Floor(NormalizedMask);
106 }
107
108 for (unsigned J = I + 1; J < E; ++J) {
109 ResourcePlusCycles &B = Worklist[J];
110 if ((NormalizedMask & B.first) == NormalizedMask) {
Matt Davis8e2c7592018-10-01 23:01:45 +0000111 B.second.CS.subtract(A.second.size() - SuperResources[A.first]);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000112 if (countPopulation(B.first) > 1)
113 B.second.NumUnits++;
114 }
115 }
116 }
117
118 // A SchedWrite may specify a number of cycles in which a resource group
119 // is reserved. For example (on target x86; cpu Haswell):
120 //
121 // SchedWriteRes<[HWPort0, HWPort1, HWPort01]> {
122 // let ResourceCycles = [2, 2, 3];
123 // }
124 //
125 // This means:
126 // Resource units HWPort0 and HWPort1 are both used for 2cy.
127 // Resource group HWPort01 is the union of HWPort0 and HWPort1.
128 // Since this write touches both HWPort0 and HWPort1 for 2cy, HWPort01
129 // will not be usable for 2 entire cycles from instruction issue.
130 //
131 // On top of those 2cy, SchedWriteRes explicitly specifies an extra latency
132 // of 3 cycles for HWPort01. This tool assumes that the 3cy latency is an
133 // extra delay on top of the 2 cycles latency.
134 // During those extra cycles, HWPort01 is not usable by other instructions.
135 for (ResourcePlusCycles &RPC : ID.Resources) {
136 if (countPopulation(RPC.first) > 1 && !RPC.second.isReserved()) {
137 // Remove the leading 1 from the resource group mask.
138 uint64_t Mask = RPC.first ^ PowerOf2Floor(RPC.first);
139 if ((Mask & UsedResourceUnits) == Mask)
140 RPC.second.setReserved();
141 }
142 }
143
Andrea Di Biagio91bdf242018-11-09 19:30:20 +0000144 // Identify extra buffers that are consumed through super resources.
145 for (const std::pair<uint64_t, unsigned> &SR : SuperResources) {
146 for (unsigned I = 1, E = NumProcResources; I < E; ++I) {
147 const MCProcResourceDesc &PR = *SM.getProcResource(I);
148 if (PR.BufferSize == -1)
149 continue;
150
151 uint64_t Mask = ProcResourceMasks[I];
152 if (Mask != SR.first && ((Mask & SR.first) == SR.first))
153 Buffers.setBit(I);
154 }
155 }
156
157 // Now set the buffers.
158 if (unsigned NumBuffers = Buffers.countPopulation()) {
159 ID.Buffers.resize(NumBuffers);
160 for (unsigned I = 0, E = NumProcResources; I < E && NumBuffers; ++I) {
161 if (Buffers[I]) {
162 --NumBuffers;
163 ID.Buffers[NumBuffers] = ProcResourceMasks[I];
164 }
165 }
166 }
167
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000168 LLVM_DEBUG({
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000169 for (const std::pair<uint64_t, ResourceUsage> &R : ID.Resources)
170 dbgs() << "\t\tMask=" << R.first << ", cy=" << R.second.size() << '\n';
171 for (const uint64_t R : ID.Buffers)
172 dbgs() << "\t\tBuffer Mask=" << R << '\n';
Andrea Di Biagio7b3d1622018-03-20 12:58:34 +0000173 });
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000174}
175
176static void computeMaxLatency(InstrDesc &ID, const MCInstrDesc &MCDesc,
177 const MCSchedClassDesc &SCDesc,
178 const MCSubtargetInfo &STI) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000179 if (MCDesc.isCall()) {
180 // We cannot estimate how long this call will take.
181 // Artificially set an arbitrarily high latency (100cy).
Andrea Di Biagioc95a1302018-03-13 15:59:59 +0000182 ID.MaxLatency = 100U;
183 return;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000184 }
185
Andrea Di Biagioc95a1302018-03-13 15:59:59 +0000186 int Latency = MCSchedModel::computeInstrLatency(STI, SCDesc);
187 // If latency is unknown, then conservatively assume a MaxLatency of 100cy.
188 ID.MaxLatency = Latency < 0 ? 100U : static_cast<unsigned>(Latency);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000189}
190
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000191static Error verifyOperands(const MCInstrDesc &MCDesc, const MCInst &MCI) {
192 // Variadic opcodes are not correctly supported.
193 if (MCDesc.isVariadic()) {
194 if (MCI.getNumOperands() - MCDesc.getNumOperands()) {
195 return make_error<InstructionError<MCInst>>(
196 "Don't know how to process this variadic opcode.", MCI);
197 }
198 }
199
200 // Count register definitions, and skip non register operands in the process.
201 unsigned I, E;
202 unsigned NumExplicitDefs = MCDesc.getNumDefs();
203 for (I = 0, E = MCI.getNumOperands(); NumExplicitDefs && I < E; ++I) {
204 const MCOperand &Op = MCI.getOperand(I);
205 if (Op.isReg())
206 --NumExplicitDefs;
207 }
208
209 if (NumExplicitDefs) {
210 return make_error<InstructionError<MCInst>>(
211 "Expected more register operand definitions.", MCI);
212 }
213
214 if (MCDesc.hasOptionalDef()) {
215 // Always assume that the optional definition is the last operand.
216 const MCOperand &Op = MCI.getOperand(MCDesc.getNumOperands() - 1);
217 if (I == MCI.getNumOperands() || !Op.isReg()) {
218 std::string Message =
219 "expected a register operand for an optional definition. Instruction "
220 "has not been correctly analyzed.";
221 return make_error<InstructionError<MCInst>>(Message, MCI);
222 }
223 }
224
225 return ErrorSuccess();
226}
227
228void InstrBuilder::populateWrites(InstrDesc &ID, const MCInst &MCI,
229 unsigned SchedClassID) {
Andrea Di Biagio88347792018-07-09 12:30:55 +0000230 const MCInstrDesc &MCDesc = MCII.get(MCI.getOpcode());
231 const MCSchedModel &SM = STI.getSchedModel();
232 const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID);
233
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000234 // Assumptions made by this algorithm:
235 // 1. The number of explicit and implicit register definitions in a MCInst
236 // matches the number of explicit and implicit definitions according to
237 // the opcode descriptor (MCInstrDesc).
238 // 2. Uses start at index #(MCDesc.getNumDefs()).
239 // 3. There can only be a single optional register definition, an it is
240 // always the last operand of the sequence (excluding extra operands
241 // contributed by variadic opcodes).
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000242 //
243 // These assumptions work quite well for most out-of-order in-tree targets
244 // like x86. This is mainly because the vast majority of instructions is
245 // expanded to MCInst using a straightforward lowering logic that preserves
246 // the ordering of the operands.
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000247 //
248 // About assumption 1.
249 // The algorithm allows non-register operands between register operand
250 // definitions. This helps to handle some special ARM instructions with
251 // implicit operand increment (-mtriple=armv7):
252 //
253 // vld1.32 {d18, d19}, [r1]! @ <MCInst #1463 VLD1q32wb_fixed
254 // @ <MCOperand Reg:59>
255 // @ <MCOperand Imm:0> (!!)
256 // @ <MCOperand Reg:67>
257 // @ <MCOperand Imm:0>
258 // @ <MCOperand Imm:14>
259 // @ <MCOperand Reg:0>>
260 //
261 // MCDesc reports:
262 // 6 explicit operands.
263 // 1 optional definition
264 // 2 explicit definitions (!!)
265 //
266 // The presence of an 'Imm' operand between the two register definitions
267 // breaks the assumption that "register definitions are always at the
268 // beginning of the operand sequence".
269 //
270 // To workaround this issue, this algorithm ignores (i.e. skips) any
271 // non-register operands between register definitions. The optional
272 // definition is still at index #(NumOperands-1).
273 //
274 // According to assumption 2. register reads start at #(NumExplicitDefs-1).
275 // That means, register R1 from the example is both read and written.
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000276 unsigned NumExplicitDefs = MCDesc.getNumDefs();
277 unsigned NumImplicitDefs = MCDesc.getNumImplicitDefs();
278 unsigned NumWriteLatencyEntries = SCDesc.NumWriteLatencyEntries;
279 unsigned TotalDefs = NumExplicitDefs + NumImplicitDefs;
280 if (MCDesc.hasOptionalDef())
281 TotalDefs++;
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000282
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000283 ID.Writes.resize(TotalDefs);
284 // Iterate over the operands list, and skip non-register operands.
285 // The first NumExplictDefs register operands are expected to be register
286 // definitions.
287 unsigned CurrentDef = 0;
288 unsigned i = 0;
289 for (; i < MCI.getNumOperands() && CurrentDef < NumExplicitDefs; ++i) {
290 const MCOperand &Op = MCI.getOperand(i);
291 if (!Op.isReg())
292 continue;
293
294 WriteDescriptor &Write = ID.Writes[CurrentDef];
295 Write.OpIndex = i;
296 if (CurrentDef < NumWriteLatencyEntries) {
297 const MCWriteLatencyEntry &WLE =
298 *STI.getWriteLatencyEntry(&SCDesc, CurrentDef);
299 // Conservatively default to MaxLatency.
Andrea Di Biagio88347792018-07-09 12:30:55 +0000300 Write.Latency =
301 WLE.Cycles < 0 ? ID.MaxLatency : static_cast<unsigned>(WLE.Cycles);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000302 Write.SClassOrWriteResourceID = WLE.WriteResourceID;
303 } else {
304 // Assign a default latency for this write.
305 Write.Latency = ID.MaxLatency;
306 Write.SClassOrWriteResourceID = 0;
307 }
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000308 Write.IsOptionalDef = false;
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000309 LLVM_DEBUG({
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000310 dbgs() << "\t\t[Def] OpIdx=" << Write.OpIndex
Andrea Di Biagio23fbe7c2018-07-13 14:55:47 +0000311 << ", Latency=" << Write.Latency
Andrea Di Biagio7b3d1622018-03-20 12:58:34 +0000312 << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n';
313 });
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000314 CurrentDef++;
315 }
316
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000317 assert(CurrentDef == NumExplicitDefs &&
318 "Expected more register operand definitions.");
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000319 for (CurrentDef = 0; CurrentDef < NumImplicitDefs; ++CurrentDef) {
320 unsigned Index = NumExplicitDefs + CurrentDef;
321 WriteDescriptor &Write = ID.Writes[Index];
Andrea Di Biagio21f0fdb2018-06-22 16:37:05 +0000322 Write.OpIndex = ~CurrentDef;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000323 Write.RegisterID = MCDesc.getImplicitDefs()[CurrentDef];
Andrea Di Biagio6fd62fe2018-04-02 13:46:49 +0000324 if (Index < NumWriteLatencyEntries) {
325 const MCWriteLatencyEntry &WLE =
326 *STI.getWriteLatencyEntry(&SCDesc, Index);
327 // Conservatively default to MaxLatency.
Andrea Di Biagio88347792018-07-09 12:30:55 +0000328 Write.Latency =
329 WLE.Cycles < 0 ? ID.MaxLatency : static_cast<unsigned>(WLE.Cycles);
Andrea Di Biagio6fd62fe2018-04-02 13:46:49 +0000330 Write.SClassOrWriteResourceID = WLE.WriteResourceID;
331 } else {
332 // Assign a default latency for this write.
333 Write.Latency = ID.MaxLatency;
334 Write.SClassOrWriteResourceID = 0;
335 }
336
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000337 Write.IsOptionalDef = false;
338 assert(Write.RegisterID != 0 && "Expected a valid phys register!");
Andrea Di Biagio23fbe7c2018-07-13 14:55:47 +0000339 LLVM_DEBUG({
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000340 dbgs() << "\t\t[Def][I] OpIdx=" << ~Write.OpIndex
Andrea Di Biagio23fbe7c2018-07-13 14:55:47 +0000341 << ", PhysReg=" << MRI.getName(Write.RegisterID)
342 << ", Latency=" << Write.Latency
343 << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n';
344 });
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000345 }
346
347 if (MCDesc.hasOptionalDef()) {
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000348 WriteDescriptor &Write = ID.Writes[NumExplicitDefs + NumImplicitDefs];
349 Write.OpIndex = MCDesc.getNumOperands() - 1;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000350 // Assign a default latency for this write.
351 Write.Latency = ID.MaxLatency;
352 Write.SClassOrWriteResourceID = 0;
353 Write.IsOptionalDef = true;
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000354 LLVM_DEBUG({
355 dbgs() << "\t\t[Def][O] OpIdx=" << Write.OpIndex
356 << ", Latency=" << Write.Latency
357 << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n';
358 });
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000359 }
360}
361
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000362void InstrBuilder::populateReads(InstrDesc &ID, const MCInst &MCI,
363 unsigned SchedClassID) {
Andrea Di Biagio88347792018-07-09 12:30:55 +0000364 const MCInstrDesc &MCDesc = MCII.get(MCI.getOpcode());
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000365 unsigned NumExplicitUses = MCDesc.getNumOperands() - MCDesc.getNumDefs();
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000366 unsigned NumImplicitUses = MCDesc.getNumImplicitUses();
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000367 // Remove the optional definition.
368 if (MCDesc.hasOptionalDef())
369 --NumExplicitUses;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000370 unsigned TotalUses = NumExplicitUses + NumImplicitUses;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000371
372 ID.Reads.resize(TotalUses);
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000373 for (unsigned I = 0; I < NumExplicitUses; ++I) {
374 ReadDescriptor &Read = ID.Reads[I];
375 Read.OpIndex = MCDesc.getNumDefs() + I;
376 Read.UseIndex = I;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000377 Read.SchedClassID = SchedClassID;
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000378 LLVM_DEBUG(dbgs() << "\t\t[Use] OpIdx=" << Read.OpIndex
Andrea Di Biagio23fbe7c2018-07-13 14:55:47 +0000379 << ", UseIndex=" << Read.UseIndex << '\n');
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000380 }
381
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000382 // For the purpose of ReadAdvance, implicit uses come directly after explicit
383 // uses. The "UseIndex" must be updated according to that implicit layout.
384 for (unsigned I = 0; I < NumImplicitUses; ++I) {
385 ReadDescriptor &Read = ID.Reads[NumExplicitUses + I];
386 Read.OpIndex = ~I;
387 Read.UseIndex = NumExplicitUses + I;
388 Read.RegisterID = MCDesc.getImplicitUses()[I];
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000389 Read.SchedClassID = SchedClassID;
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000390 LLVM_DEBUG(dbgs() << "\t\t[Use][I] OpIdx=" << ~Read.OpIndex
391 << ", UseIndex=" << Read.UseIndex << ", RegisterID="
Andrea Di Biagio23fbe7c2018-07-13 14:55:47 +0000392 << MRI.getName(Read.RegisterID) << '\n');
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000393 }
394}
395
Andrea Di Biagioaacd5e12018-10-04 10:36:49 +0000396Error InstrBuilder::verifyInstrDesc(const InstrDesc &ID,
397 const MCInst &MCI) const {
398 if (ID.NumMicroOps != 0)
399 return ErrorSuccess();
400
401 bool UsesMemory = ID.MayLoad || ID.MayStore;
402 bool UsesBuffers = !ID.Buffers.empty();
403 bool UsesResources = !ID.Resources.empty();
404 if (!UsesMemory && !UsesBuffers && !UsesResources)
405 return ErrorSuccess();
406
Andrea Di Biagio083addf2018-10-24 10:56:47 +0000407 StringRef Message;
Andrea Di Biagioaacd5e12018-10-04 10:36:49 +0000408 if (UsesMemory) {
Andrea Di Biagio083addf2018-10-24 10:56:47 +0000409 Message = "found an inconsistent instruction that decodes "
410 "into zero opcodes and that consumes load/store "
411 "unit resources.";
Andrea Di Biagioaacd5e12018-10-04 10:36:49 +0000412 } else {
Andrea Di Biagio083addf2018-10-24 10:56:47 +0000413 Message = "found an inconsistent instruction that decodes "
414 "to zero opcodes and that consumes scheduler "
415 "resources.";
Andrea Di Biagioaacd5e12018-10-04 10:36:49 +0000416 }
417
Andrea Di Biagio083addf2018-10-24 10:56:47 +0000418 return make_error<InstructionError<MCInst>>(Message, MCI);
Andrea Di Biagioaacd5e12018-10-04 10:36:49 +0000419}
420
Matt Davis4bcf3692018-08-13 18:11:48 +0000421Expected<const InstrDesc &>
422InstrBuilder::createInstrDescImpl(const MCInst &MCI) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000423 assert(STI.getSchedModel().hasInstrSchedModel() &&
424 "Itineraries are not yet supported!");
425
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000426 // Obtain the instruction descriptor from the opcode.
Andrea Di Biagio88347792018-07-09 12:30:55 +0000427 unsigned short Opcode = MCI.getOpcode();
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000428 const MCInstrDesc &MCDesc = MCII.get(Opcode);
429 const MCSchedModel &SM = STI.getSchedModel();
430
431 // Then obtain the scheduling class information from the instruction.
Andrea Di Biagio49c85912018-05-04 13:10:10 +0000432 unsigned SchedClassID = MCDesc.getSchedClass();
Andrea Di Biagio39e5a562018-06-04 15:43:09 +0000433 unsigned CPUID = SM.getProcessorID();
434
435 // Try to solve variant scheduling classes.
436 if (SchedClassID) {
437 while (SchedClassID && SM.getSchedClassDesc(SchedClassID)->isVariant())
438 SchedClassID = STI.resolveVariantSchedClass(SchedClassID, &MCI, CPUID);
439
Matt Davis4bcf3692018-08-13 18:11:48 +0000440 if (!SchedClassID) {
Andrea Di Biagio083addf2018-10-24 10:56:47 +0000441 return make_error<InstructionError<MCInst>>(
442 "unable to resolve scheduling class for write variant.", MCI);
Matt Davis4bcf3692018-08-13 18:11:48 +0000443 }
Andrea Di Biagio39e5a562018-06-04 15:43:09 +0000444 }
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000445
Matt Davis4bcf3692018-08-13 18:11:48 +0000446 // Check if this instruction is supported. Otherwise, report an error.
Andrea Di Biagio88347792018-07-09 12:30:55 +0000447 const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID);
448 if (SCDesc.NumMicroOps == MCSchedClassDesc::InvalidNumMicroOps) {
Andrea Di Biagio083addf2018-10-24 10:56:47 +0000449 return make_error<InstructionError<MCInst>>(
450 "found an unsupported instruction in the input assembly sequence.",
451 MCI);
Andrea Di Biagio88347792018-07-09 12:30:55 +0000452 }
453
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000454 // Create a new empty descriptor.
Andrea Di Biagio7b3d1622018-03-20 12:58:34 +0000455 std::unique_ptr<InstrDesc> ID = llvm::make_unique<InstrDesc>();
Andrea Di Biagio39e5a562018-06-04 15:43:09 +0000456 ID->NumMicroOps = SCDesc.NumMicroOps;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000457
458 if (MCDesc.isCall()) {
459 // We don't correctly model calls.
Andrea Di Biagio24fb4fc2018-05-04 13:52:12 +0000460 WithColor::warning() << "found a call in the input assembly sequence.\n";
461 WithColor::note() << "call instructions are not correctly modeled. "
462 << "Assume a latency of 100cy.\n";
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000463 }
464
465 if (MCDesc.isReturn()) {
Andrea Di Biagio24fb4fc2018-05-04 13:52:12 +0000466 WithColor::warning() << "found a return instruction in the input"
467 << " assembly sequence.\n";
468 WithColor::note() << "program counter updates are ignored.\n";
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000469 }
470
471 ID->MayLoad = MCDesc.mayLoad();
472 ID->MayStore = MCDesc.mayStore();
473 ID->HasSideEffects = MCDesc.hasUnmodeledSideEffects();
474
475 initializeUsedResources(*ID, SCDesc, STI, ProcResourceMasks);
Andrea Di Biagiodb66efc2018-04-25 09:38:58 +0000476 computeMaxLatency(*ID, MCDesc, SCDesc, STI);
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000477
478 if (Error Err = verifyOperands(MCDesc, MCI))
Matt Davis4bcf3692018-08-13 18:11:48 +0000479 return std::move(Err);
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000480
481 populateWrites(*ID, MCI, SchedClassID);
482 populateReads(*ID, MCI, SchedClassID);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000483
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000484 LLVM_DEBUG(dbgs() << "\t\tMaxLatency=" << ID->MaxLatency << '\n');
485 LLVM_DEBUG(dbgs() << "\t\tNumMicroOps=" << ID->NumMicroOps << '\n');
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000486
Andrea Di Biagioaacd5e12018-10-04 10:36:49 +0000487 // Sanity check on the instruction descriptor.
488 if (Error Err = verifyInstrDesc(*ID, MCI))
489 return std::move(Err);
490
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000491 // Now add the new descriptor.
Andrea Di Biagio39e5a562018-06-04 15:43:09 +0000492 SchedClassID = MCDesc.getSchedClass();
493 if (!SM.getSchedClassDesc(SchedClassID)->isVariant()) {
494 Descriptors[MCI.getOpcode()] = std::move(ID);
495 return *Descriptors[MCI.getOpcode()];
496 }
497
498 VariantDescriptors[&MCI] = std::move(ID);
499 return *VariantDescriptors[&MCI];
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000500}
501
Matt Davis4bcf3692018-08-13 18:11:48 +0000502Expected<const InstrDesc &>
503InstrBuilder::getOrCreateInstrDesc(const MCInst &MCI) {
Andrea Di Biagio39e5a562018-06-04 15:43:09 +0000504 if (Descriptors.find_as(MCI.getOpcode()) != Descriptors.end())
505 return *Descriptors[MCI.getOpcode()];
506
507 if (VariantDescriptors.find(&MCI) != VariantDescriptors.end())
508 return *VariantDescriptors[&MCI];
509
510 return createInstrDescImpl(MCI);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000511}
512
Matt Davis4bcf3692018-08-13 18:11:48 +0000513Expected<std::unique_ptr<Instruction>>
Andrea Di Biagio49c85912018-05-04 13:10:10 +0000514InstrBuilder::createInstruction(const MCInst &MCI) {
Matt Davis4bcf3692018-08-13 18:11:48 +0000515 Expected<const InstrDesc &> DescOrErr = getOrCreateInstrDesc(MCI);
516 if (!DescOrErr)
517 return DescOrErr.takeError();
518 const InstrDesc &D = *DescOrErr;
Andrea Di Biagio7b3d1622018-03-20 12:58:34 +0000519 std::unique_ptr<Instruction> NewIS = llvm::make_unique<Instruction>(D);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000520
Andrea Di Biagio9f9cdd42018-09-18 15:00:06 +0000521 // Check if this is a dependency breaking instruction.
Andrea Di Biagio8b6c3142018-09-19 15:57:45 +0000522 APInt Mask;
523
524 unsigned ProcID = STI.getSchedModel().getProcessorID();
525 bool IsZeroIdiom = MCIA.isZeroIdiom(MCI, Mask, ProcID);
526 bool IsDepBreaking =
527 IsZeroIdiom || MCIA.isDependencyBreaking(MCI, Mask, ProcID);
Andrea Di Biagio6eebbe02018-10-12 11:23:04 +0000528 if (MCIA.isOptimizableRegisterMove(MCI, ProcID))
529 NewIS->setOptimizableMove();
Andrea Di Biagio9f9cdd42018-09-18 15:00:06 +0000530
Andrea Di Biagiodb66efc2018-04-25 09:38:58 +0000531 // Initialize Reads first.
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000532 for (const ReadDescriptor &RD : D.Reads) {
533 int RegID = -1;
Andrea Di Biagio21f0fdb2018-06-22 16:37:05 +0000534 if (!RD.isImplicitRead()) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000535 // explicit read.
536 const MCOperand &Op = MCI.getOperand(RD.OpIndex);
537 // Skip non-register operands.
538 if (!Op.isReg())
539 continue;
540 RegID = Op.getReg();
541 } else {
542 // Implicit read.
543 RegID = RD.RegisterID;
544 }
545
546 // Skip invalid register operands.
547 if (!RegID)
548 continue;
549
550 // Okay, this is a register operand. Create a ReadState for it.
551 assert(RegID > 0 && "Invalid register ID found!");
Andrea Di Biagio1e6d0aa2018-10-25 17:03:51 +0000552 NewIS->getUses().emplace_back(RD, RegID);
553 ReadState &RS = NewIS->getUses().back();
Andrea Di Biagio9f9cdd42018-09-18 15:00:06 +0000554
Andrea Di Biagio8b6c3142018-09-19 15:57:45 +0000555 if (IsDepBreaking) {
556 // A mask of all zeroes means: explicit input operands are not
557 // independent.
558 if (Mask.isNullValue()) {
559 if (!RD.isImplicitRead())
Andrea Di Biagio1e6d0aa2018-10-25 17:03:51 +0000560 RS.setIndependentFromDef();
Andrea Di Biagio8b6c3142018-09-19 15:57:45 +0000561 } else {
562 // Check if this register operand is independent according to `Mask`.
563 // Note that Mask may not have enough bits to describe all explicit and
564 // implicit input operands. If this register operand doesn't have a
565 // corresponding bit in Mask, then conservatively assume that it is
566 // dependent.
567 if (Mask.getBitWidth() > RD.UseIndex) {
568 // Okay. This map describe register use `RD.UseIndex`.
569 if (Mask[RD.UseIndex])
Andrea Di Biagio1e6d0aa2018-10-25 17:03:51 +0000570 RS.setIndependentFromDef();
Andrea Di Biagio8b6c3142018-09-19 15:57:45 +0000571 }
572 }
573 }
Andrea Di Biagio4704f032018-03-20 12:25:54 +0000574 }
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000575
Andrea Di Biagio2145b132018-06-20 10:08:11 +0000576 // Early exit if there are no writes.
577 if (D.Writes.empty())
Matt Davis4bcf3692018-08-13 18:11:48 +0000578 return std::move(NewIS);
Andrea Di Biagio2145b132018-06-20 10:08:11 +0000579
580 // Track register writes that implicitly clear the upper portion of the
581 // underlying super-registers using an APInt.
582 APInt WriteMask(D.Writes.size(), 0);
583
584 // Now query the MCInstrAnalysis object to obtain information about which
585 // register writes implicitly clear the upper portion of a super-register.
586 MCIA.clearsSuperRegisters(MRI, MCI, WriteMask);
587
Andrea Di Biagiodb66efc2018-04-25 09:38:58 +0000588 // Initialize writes.
Andrea Di Biagio2145b132018-06-20 10:08:11 +0000589 unsigned WriteIndex = 0;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000590 for (const WriteDescriptor &WD : D.Writes) {
Andrea Di Biagio88347792018-07-09 12:30:55 +0000591 unsigned RegID = WD.isImplicitWrite() ? WD.RegisterID
592 : MCI.getOperand(WD.OpIndex).getReg();
Andrea Di Biagio35622482018-03-22 10:19:20 +0000593 // Check if this is a optional definition that references NoReg.
Andrea Di Biagio2145b132018-06-20 10:08:11 +0000594 if (WD.IsOptionalDef && !RegID) {
595 ++WriteIndex;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000596 continue;
Andrea Di Biagio2145b132018-06-20 10:08:11 +0000597 }
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000598
Andrea Di Biagio35622482018-03-22 10:19:20 +0000599 assert(RegID && "Expected a valid register ID!");
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000600 NewIS->getDefs().emplace_back(WD, RegID,
601 /* ClearsSuperRegs */ WriteMask[WriteIndex],
602 /* WritesZero */ IsZeroIdiom);
Andrea Di Biagio2145b132018-06-20 10:08:11 +0000603 ++WriteIndex;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000604 }
605
Matt Davis4bcf3692018-08-13 18:11:48 +0000606 return std::move(NewIS);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000607}
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000608} // namespace mca
Fangrui Song5a8fd652018-10-30 15:56:08 +0000609} // namespace llvm