blob: 2cfe154a90287f8a6f5991c81da0b6bb4d1b574c [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
Clement Courbetcc5e6a72018-12-17 08:08:31 +000015#include "llvm/MCA/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,
Andrea Di Biagio45060672018-12-17 14:00:37 +000031 const llvm::MCInstrAnalysis *mcia)
Andrea Di Biagio42720602018-11-24 18:40:45 +000032 : STI(sti), MCII(mcii), MRI(mri), MCIA(mcia), FirstCallInst(true),
33 FirstReturnInst(true) {
Andrea Di Biagio77c26ae2018-10-25 11:51:34 +000034 computeProcResourceMasks(STI.getSchedModel(), ProcResourceMasks);
35}
36
Andrea Di Biagio94fafdf2018-03-24 16:05:36 +000037static void initializeUsedResources(InstrDesc &ID,
38 const MCSchedClassDesc &SCDesc,
39 const MCSubtargetInfo &STI,
40 ArrayRef<uint64_t> ProcResourceMasks) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000041 const MCSchedModel &SM = STI.getSchedModel();
42
43 // Populate resources consumed.
44 using ResourcePlusCycles = std::pair<uint64_t, ResourceUsage>;
45 std::vector<ResourcePlusCycles> Worklist;
Andrea Di Biagio2008c7c2018-06-04 12:23:07 +000046
47 // Track cycles contributed by resources that are in a "Super" relationship.
48 // This is required if we want to correctly match the behavior of method
49 // SubtargetEmitter::ExpandProcResource() in Tablegen. When computing the set
50 // of "consumed" processor resources and resource cycles, the logic in
51 // ExpandProcResource() doesn't update the number of resource cycles
52 // contributed by a "Super" resource to a group.
53 // We need to take this into account when we find that a processor resource is
54 // part of a group, and it is also used as the "Super" of other resources.
55 // This map stores the number of cycles contributed by sub-resources that are
56 // part of a "Super" resource. The key value is the "Super" resource mask ID.
57 DenseMap<uint64_t, unsigned> SuperResources;
58
Andrea Di Biagio91bdf242018-11-09 19:30:20 +000059 unsigned NumProcResources = SM.getNumProcResourceKinds();
60 APInt Buffers(NumProcResources, 0);
61
Andrea Di Biagio3f4b5482019-01-04 15:08:38 +000062 bool AllInOrderResources = true;
63 bool AnyDispatchHazards = false;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000064 for (unsigned I = 0, E = SCDesc.NumWriteProcResEntries; I < E; ++I) {
65 const MCWriteProcResEntry *PRE = STI.getWriteProcResBegin(&SCDesc) + I;
66 const MCProcResourceDesc &PR = *SM.getProcResource(PRE->ProcResourceIdx);
67 uint64_t Mask = ProcResourceMasks[PRE->ProcResourceIdx];
Andrea Di Biagio3f4b5482019-01-04 15:08:38 +000068 if (PR.BufferSize < 0) {
69 AllInOrderResources = false;
70 } else {
Andrea Di Biagio91bdf242018-11-09 19:30:20 +000071 Buffers.setBit(PRE->ProcResourceIdx);
Andrea Di Biagio3f4b5482019-01-04 15:08:38 +000072 AnyDispatchHazards |= (PR.BufferSize == 0);
73 AllInOrderResources &= (PR.BufferSize <= 1);
74 }
75
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000076 CycleSegment RCy(0, PRE->Cycles, false);
77 Worklist.emplace_back(ResourcePlusCycles(Mask, ResourceUsage(RCy)));
Andrea Di Biagio2008c7c2018-06-04 12:23:07 +000078 if (PR.SuperIdx) {
79 uint64_t Super = ProcResourceMasks[PR.SuperIdx];
80 SuperResources[Super] += PRE->Cycles;
81 }
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000082 }
83
Andrea Di Biagio3f4b5482019-01-04 15:08:38 +000084 ID.MustIssueImmediately = AllInOrderResources && AnyDispatchHazards;
85
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000086 // Sort elements by mask popcount, so that we prioritize resource units over
87 // resource groups, and smaller groups over larger groups.
Andrea Di Biagioa7699122018-09-28 10:47:24 +000088 sort(Worklist, [](const ResourcePlusCycles &A, const ResourcePlusCycles &B) {
89 unsigned popcntA = countPopulation(A.first);
90 unsigned popcntB = countPopulation(B.first);
91 if (popcntA < popcntB)
92 return true;
93 if (popcntA > popcntB)
94 return false;
95 return A.first < B.first;
96 });
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000097
98 uint64_t UsedResourceUnits = 0;
99
100 // Remove cycles contributed by smaller resources.
101 for (unsigned I = 0, E = Worklist.size(); I < E; ++I) {
102 ResourcePlusCycles &A = Worklist[I];
103 if (!A.second.size()) {
104 A.second.NumUnits = 0;
105 A.second.setReserved();
106 ID.Resources.emplace_back(A);
107 continue;
108 }
109
110 ID.Resources.emplace_back(A);
111 uint64_t NormalizedMask = A.first;
112 if (countPopulation(A.first) == 1) {
113 UsedResourceUnits |= A.first;
114 } else {
115 // Remove the leading 1 from the resource group mask.
116 NormalizedMask ^= PowerOf2Floor(NormalizedMask);
117 }
118
119 for (unsigned J = I + 1; J < E; ++J) {
120 ResourcePlusCycles &B = Worklist[J];
121 if ((NormalizedMask & B.first) == NormalizedMask) {
Matt Davis8e2c7592018-10-01 23:01:45 +0000122 B.second.CS.subtract(A.second.size() - SuperResources[A.first]);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000123 if (countPopulation(B.first) > 1)
124 B.second.NumUnits++;
125 }
126 }
127 }
128
129 // A SchedWrite may specify a number of cycles in which a resource group
130 // is reserved. For example (on target x86; cpu Haswell):
131 //
132 // SchedWriteRes<[HWPort0, HWPort1, HWPort01]> {
133 // let ResourceCycles = [2, 2, 3];
134 // }
135 //
136 // This means:
137 // Resource units HWPort0 and HWPort1 are both used for 2cy.
138 // Resource group HWPort01 is the union of HWPort0 and HWPort1.
139 // Since this write touches both HWPort0 and HWPort1 for 2cy, HWPort01
140 // will not be usable for 2 entire cycles from instruction issue.
141 //
142 // On top of those 2cy, SchedWriteRes explicitly specifies an extra latency
143 // of 3 cycles for HWPort01. This tool assumes that the 3cy latency is an
144 // extra delay on top of the 2 cycles latency.
145 // During those extra cycles, HWPort01 is not usable by other instructions.
146 for (ResourcePlusCycles &RPC : ID.Resources) {
147 if (countPopulation(RPC.first) > 1 && !RPC.second.isReserved()) {
148 // Remove the leading 1 from the resource group mask.
149 uint64_t Mask = RPC.first ^ PowerOf2Floor(RPC.first);
150 if ((Mask & UsedResourceUnits) == Mask)
151 RPC.second.setReserved();
152 }
153 }
154
Andrea Di Biagio91bdf242018-11-09 19:30:20 +0000155 // Identify extra buffers that are consumed through super resources.
156 for (const std::pair<uint64_t, unsigned> &SR : SuperResources) {
157 for (unsigned I = 1, E = NumProcResources; I < E; ++I) {
158 const MCProcResourceDesc &PR = *SM.getProcResource(I);
159 if (PR.BufferSize == -1)
160 continue;
161
162 uint64_t Mask = ProcResourceMasks[I];
163 if (Mask != SR.first && ((Mask & SR.first) == SR.first))
164 Buffers.setBit(I);
165 }
166 }
167
168 // Now set the buffers.
169 if (unsigned NumBuffers = Buffers.countPopulation()) {
170 ID.Buffers.resize(NumBuffers);
171 for (unsigned I = 0, E = NumProcResources; I < E && NumBuffers; ++I) {
172 if (Buffers[I]) {
173 --NumBuffers;
174 ID.Buffers[NumBuffers] = ProcResourceMasks[I];
175 }
176 }
177 }
178
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000179 LLVM_DEBUG({
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000180 for (const std::pair<uint64_t, ResourceUsage> &R : ID.Resources)
Evandro Menezes224d8312019-01-09 23:57:15 +0000181 dbgs() << "\t\tMask=" << format_hex(R.first, 16) << ", " <<
182 "cy=" << R.second.size() << '\n';
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000183 for (const uint64_t R : ID.Buffers)
Evandro Menezes224d8312019-01-09 23:57:15 +0000184 dbgs() << "\t\tBuffer Mask=" << format_hex(R, 16) << '\n';
Andrea Di Biagio7b3d1622018-03-20 12:58:34 +0000185 });
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000186}
187
188static void computeMaxLatency(InstrDesc &ID, const MCInstrDesc &MCDesc,
189 const MCSchedClassDesc &SCDesc,
190 const MCSubtargetInfo &STI) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000191 if (MCDesc.isCall()) {
192 // We cannot estimate how long this call will take.
193 // Artificially set an arbitrarily high latency (100cy).
Andrea Di Biagioc95a1302018-03-13 15:59:59 +0000194 ID.MaxLatency = 100U;
195 return;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000196 }
197
Andrea Di Biagioc95a1302018-03-13 15:59:59 +0000198 int Latency = MCSchedModel::computeInstrLatency(STI, SCDesc);
199 // If latency is unknown, then conservatively assume a MaxLatency of 100cy.
200 ID.MaxLatency = Latency < 0 ? 100U : static_cast<unsigned>(Latency);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000201}
202
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000203static Error verifyOperands(const MCInstrDesc &MCDesc, const MCInst &MCI) {
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000204 // Count register definitions, and skip non register operands in the process.
205 unsigned I, E;
206 unsigned NumExplicitDefs = MCDesc.getNumDefs();
207 for (I = 0, E = MCI.getNumOperands(); NumExplicitDefs && I < E; ++I) {
208 const MCOperand &Op = MCI.getOperand(I);
209 if (Op.isReg())
210 --NumExplicitDefs;
211 }
212
213 if (NumExplicitDefs) {
214 return make_error<InstructionError<MCInst>>(
215 "Expected more register operand definitions.", MCI);
216 }
217
218 if (MCDesc.hasOptionalDef()) {
219 // Always assume that the optional definition is the last operand.
220 const MCOperand &Op = MCI.getOperand(MCDesc.getNumOperands() - 1);
221 if (I == MCI.getNumOperands() || !Op.isReg()) {
222 std::string Message =
223 "expected a register operand for an optional definition. Instruction "
224 "has not been correctly analyzed.";
225 return make_error<InstructionError<MCInst>>(Message, MCI);
226 }
227 }
228
229 return ErrorSuccess();
230}
231
232void InstrBuilder::populateWrites(InstrDesc &ID, const MCInst &MCI,
233 unsigned SchedClassID) {
Andrea Di Biagio88347792018-07-09 12:30:55 +0000234 const MCInstrDesc &MCDesc = MCII.get(MCI.getOpcode());
235 const MCSchedModel &SM = STI.getSchedModel();
236 const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID);
237
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000238 // Assumptions made by this algorithm:
239 // 1. The number of explicit and implicit register definitions in a MCInst
240 // matches the number of explicit and implicit definitions according to
241 // the opcode descriptor (MCInstrDesc).
242 // 2. Uses start at index #(MCDesc.getNumDefs()).
243 // 3. There can only be a single optional register definition, an it is
244 // always the last operand of the sequence (excluding extra operands
245 // contributed by variadic opcodes).
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000246 //
247 // These assumptions work quite well for most out-of-order in-tree targets
248 // like x86. This is mainly because the vast majority of instructions is
249 // expanded to MCInst using a straightforward lowering logic that preserves
250 // the ordering of the operands.
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000251 //
252 // About assumption 1.
253 // The algorithm allows non-register operands between register operand
254 // definitions. This helps to handle some special ARM instructions with
255 // implicit operand increment (-mtriple=armv7):
256 //
257 // vld1.32 {d18, d19}, [r1]! @ <MCInst #1463 VLD1q32wb_fixed
258 // @ <MCOperand Reg:59>
259 // @ <MCOperand Imm:0> (!!)
260 // @ <MCOperand Reg:67>
261 // @ <MCOperand Imm:0>
262 // @ <MCOperand Imm:14>
263 // @ <MCOperand Reg:0>>
264 //
265 // MCDesc reports:
266 // 6 explicit operands.
267 // 1 optional definition
268 // 2 explicit definitions (!!)
269 //
270 // The presence of an 'Imm' operand between the two register definitions
271 // breaks the assumption that "register definitions are always at the
272 // beginning of the operand sequence".
273 //
274 // To workaround this issue, this algorithm ignores (i.e. skips) any
275 // non-register operands between register definitions. The optional
276 // definition is still at index #(NumOperands-1).
277 //
278 // According to assumption 2. register reads start at #(NumExplicitDefs-1).
279 // That means, register R1 from the example is both read and written.
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000280 unsigned NumExplicitDefs = MCDesc.getNumDefs();
281 unsigned NumImplicitDefs = MCDesc.getNumImplicitDefs();
282 unsigned NumWriteLatencyEntries = SCDesc.NumWriteLatencyEntries;
283 unsigned TotalDefs = NumExplicitDefs + NumImplicitDefs;
284 if (MCDesc.hasOptionalDef())
285 TotalDefs++;
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000286
Andrea Di Biagio36296c02018-11-25 12:46:24 +0000287 unsigned NumVariadicOps = MCI.getNumOperands() - MCDesc.getNumOperands();
288 ID.Writes.resize(TotalDefs + NumVariadicOps);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000289 // Iterate over the operands list, and skip non-register operands.
290 // The first NumExplictDefs register operands are expected to be register
291 // definitions.
292 unsigned CurrentDef = 0;
293 unsigned i = 0;
294 for (; i < MCI.getNumOperands() && CurrentDef < NumExplicitDefs; ++i) {
295 const MCOperand &Op = MCI.getOperand(i);
296 if (!Op.isReg())
297 continue;
298
299 WriteDescriptor &Write = ID.Writes[CurrentDef];
300 Write.OpIndex = i;
301 if (CurrentDef < NumWriteLatencyEntries) {
302 const MCWriteLatencyEntry &WLE =
303 *STI.getWriteLatencyEntry(&SCDesc, CurrentDef);
304 // Conservatively default to MaxLatency.
Andrea Di Biagio88347792018-07-09 12:30:55 +0000305 Write.Latency =
306 WLE.Cycles < 0 ? ID.MaxLatency : static_cast<unsigned>(WLE.Cycles);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000307 Write.SClassOrWriteResourceID = WLE.WriteResourceID;
308 } else {
309 // Assign a default latency for this write.
310 Write.Latency = ID.MaxLatency;
311 Write.SClassOrWriteResourceID = 0;
312 }
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000313 Write.IsOptionalDef = false;
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000314 LLVM_DEBUG({
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000315 dbgs() << "\t\t[Def] OpIdx=" << Write.OpIndex
Andrea Di Biagio23fbe7c2018-07-13 14:55:47 +0000316 << ", Latency=" << Write.Latency
Andrea Di Biagio7b3d1622018-03-20 12:58:34 +0000317 << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n';
318 });
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000319 CurrentDef++;
320 }
321
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000322 assert(CurrentDef == NumExplicitDefs &&
323 "Expected more register operand definitions.");
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000324 for (CurrentDef = 0; CurrentDef < NumImplicitDefs; ++CurrentDef) {
325 unsigned Index = NumExplicitDefs + CurrentDef;
326 WriteDescriptor &Write = ID.Writes[Index];
Andrea Di Biagio21f0fdb2018-06-22 16:37:05 +0000327 Write.OpIndex = ~CurrentDef;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000328 Write.RegisterID = MCDesc.getImplicitDefs()[CurrentDef];
Andrea Di Biagio6fd62fe2018-04-02 13:46:49 +0000329 if (Index < NumWriteLatencyEntries) {
330 const MCWriteLatencyEntry &WLE =
331 *STI.getWriteLatencyEntry(&SCDesc, Index);
332 // Conservatively default to MaxLatency.
Andrea Di Biagio88347792018-07-09 12:30:55 +0000333 Write.Latency =
334 WLE.Cycles < 0 ? ID.MaxLatency : static_cast<unsigned>(WLE.Cycles);
Andrea Di Biagio6fd62fe2018-04-02 13:46:49 +0000335 Write.SClassOrWriteResourceID = WLE.WriteResourceID;
336 } else {
337 // Assign a default latency for this write.
338 Write.Latency = ID.MaxLatency;
339 Write.SClassOrWriteResourceID = 0;
340 }
341
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000342 Write.IsOptionalDef = false;
343 assert(Write.RegisterID != 0 && "Expected a valid phys register!");
Andrea Di Biagio23fbe7c2018-07-13 14:55:47 +0000344 LLVM_DEBUG({
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000345 dbgs() << "\t\t[Def][I] OpIdx=" << ~Write.OpIndex
Andrea Di Biagio23fbe7c2018-07-13 14:55:47 +0000346 << ", PhysReg=" << MRI.getName(Write.RegisterID)
347 << ", Latency=" << Write.Latency
348 << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n';
349 });
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000350 }
351
352 if (MCDesc.hasOptionalDef()) {
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000353 WriteDescriptor &Write = ID.Writes[NumExplicitDefs + NumImplicitDefs];
354 Write.OpIndex = MCDesc.getNumOperands() - 1;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000355 // Assign a default latency for this write.
356 Write.Latency = ID.MaxLatency;
357 Write.SClassOrWriteResourceID = 0;
358 Write.IsOptionalDef = true;
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000359 LLVM_DEBUG({
360 dbgs() << "\t\t[Def][O] OpIdx=" << Write.OpIndex
361 << ", Latency=" << Write.Latency
362 << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n';
363 });
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000364 }
Andrea Di Biagio36296c02018-11-25 12:46:24 +0000365
366 if (!NumVariadicOps)
367 return;
368
369 // FIXME: if an instruction opcode is flagged 'mayStore', and it has no
370 // "unmodeledSideEffects', then this logic optimistically assumes that any
371 // extra register operands in the variadic sequence is not a register
372 // definition.
373 //
374 // Otherwise, we conservatively assume that any register operand from the
375 // variadic sequence is both a register read and a register write.
376 bool AssumeUsesOnly = MCDesc.mayStore() && !MCDesc.mayLoad() &&
377 !MCDesc.hasUnmodeledSideEffects();
378 CurrentDef = NumExplicitDefs + NumImplicitDefs + MCDesc.hasOptionalDef();
379 for (unsigned I = 0, OpIndex = MCDesc.getNumOperands();
380 I < NumVariadicOps && !AssumeUsesOnly; ++I, ++OpIndex) {
381 const MCOperand &Op = MCI.getOperand(OpIndex);
382 if (!Op.isReg())
383 continue;
384
385 WriteDescriptor &Write = ID.Writes[CurrentDef];
386 Write.OpIndex = OpIndex;
387 // Assign a default latency for this write.
388 Write.Latency = ID.MaxLatency;
389 Write.SClassOrWriteResourceID = 0;
390 Write.IsOptionalDef = false;
391 ++CurrentDef;
392 LLVM_DEBUG({
393 dbgs() << "\t\t[Def][V] OpIdx=" << Write.OpIndex
394 << ", Latency=" << Write.Latency
395 << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n';
396 });
397 }
398
399 ID.Writes.resize(CurrentDef);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000400}
401
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000402void InstrBuilder::populateReads(InstrDesc &ID, const MCInst &MCI,
403 unsigned SchedClassID) {
Andrea Di Biagio88347792018-07-09 12:30:55 +0000404 const MCInstrDesc &MCDesc = MCII.get(MCI.getOpcode());
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000405 unsigned NumExplicitUses = MCDesc.getNumOperands() - MCDesc.getNumDefs();
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000406 unsigned NumImplicitUses = MCDesc.getNumImplicitUses();
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000407 // Remove the optional definition.
408 if (MCDesc.hasOptionalDef())
409 --NumExplicitUses;
Andrea Di Biagio36296c02018-11-25 12:46:24 +0000410 unsigned NumVariadicOps = MCI.getNumOperands() - MCDesc.getNumOperands();
411 unsigned TotalUses = NumExplicitUses + NumImplicitUses + NumVariadicOps;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000412 ID.Reads.resize(TotalUses);
Andrea Di Biagio36296c02018-11-25 12:46:24 +0000413 unsigned CurrentUse = 0;
414 for (unsigned I = 0, OpIndex = MCDesc.getNumDefs(); I < NumExplicitUses;
415 ++I, ++OpIndex) {
416 const MCOperand &Op = MCI.getOperand(OpIndex);
417 if (!Op.isReg())
418 continue;
419
420 ReadDescriptor &Read = ID.Reads[CurrentUse];
421 Read.OpIndex = OpIndex;
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000422 Read.UseIndex = I;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000423 Read.SchedClassID = SchedClassID;
Andrea Di Biagio36296c02018-11-25 12:46:24 +0000424 ++CurrentUse;
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000425 LLVM_DEBUG(dbgs() << "\t\t[Use] OpIdx=" << Read.OpIndex
Andrea Di Biagio23fbe7c2018-07-13 14:55:47 +0000426 << ", UseIndex=" << Read.UseIndex << '\n');
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000427 }
428
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000429 // For the purpose of ReadAdvance, implicit uses come directly after explicit
430 // uses. The "UseIndex" must be updated according to that implicit layout.
431 for (unsigned I = 0; I < NumImplicitUses; ++I) {
Andrea Di Biagio36296c02018-11-25 12:46:24 +0000432 ReadDescriptor &Read = ID.Reads[CurrentUse + I];
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000433 Read.OpIndex = ~I;
434 Read.UseIndex = NumExplicitUses + I;
435 Read.RegisterID = MCDesc.getImplicitUses()[I];
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000436 Read.SchedClassID = SchedClassID;
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000437 LLVM_DEBUG(dbgs() << "\t\t[Use][I] OpIdx=" << ~Read.OpIndex
438 << ", UseIndex=" << Read.UseIndex << ", RegisterID="
Andrea Di Biagio23fbe7c2018-07-13 14:55:47 +0000439 << MRI.getName(Read.RegisterID) << '\n');
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000440 }
Andrea Di Biagio36296c02018-11-25 12:46:24 +0000441
442 CurrentUse += NumImplicitUses;
443
444 // FIXME: If an instruction opcode is marked as 'mayLoad', and it has no
445 // "unmodeledSideEffects", then this logic optimistically assumes that any
446 // extra register operands in the variadic sequence are not register
447 // definition.
448
449 bool AssumeDefsOnly = !MCDesc.mayStore() && MCDesc.mayLoad() &&
450 !MCDesc.hasUnmodeledSideEffects();
451 for (unsigned I = 0, OpIndex = MCDesc.getNumOperands();
452 I < NumVariadicOps && !AssumeDefsOnly; ++I, ++OpIndex) {
453 const MCOperand &Op = MCI.getOperand(OpIndex);
454 if (!Op.isReg())
455 continue;
456
457 ReadDescriptor &Read = ID.Reads[CurrentUse];
458 Read.OpIndex = OpIndex;
459 Read.UseIndex = NumExplicitUses + NumImplicitUses + I;
460 Read.SchedClassID = SchedClassID;
461 ++CurrentUse;
462 LLVM_DEBUG(dbgs() << "\t\t[Use][V] OpIdx=" << Read.OpIndex
463 << ", UseIndex=" << Read.UseIndex << '\n');
464 }
465
466 ID.Reads.resize(CurrentUse);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000467}
468
Andrea Di Biagioaacd5e12018-10-04 10:36:49 +0000469Error InstrBuilder::verifyInstrDesc(const InstrDesc &ID,
470 const MCInst &MCI) const {
471 if (ID.NumMicroOps != 0)
472 return ErrorSuccess();
473
474 bool UsesMemory = ID.MayLoad || ID.MayStore;
475 bool UsesBuffers = !ID.Buffers.empty();
476 bool UsesResources = !ID.Resources.empty();
477 if (!UsesMemory && !UsesBuffers && !UsesResources)
478 return ErrorSuccess();
479
Andrea Di Biagio083addf2018-10-24 10:56:47 +0000480 StringRef Message;
Andrea Di Biagioaacd5e12018-10-04 10:36:49 +0000481 if (UsesMemory) {
Andrea Di Biagio083addf2018-10-24 10:56:47 +0000482 Message = "found an inconsistent instruction that decodes "
483 "into zero opcodes and that consumes load/store "
484 "unit resources.";
Andrea Di Biagioaacd5e12018-10-04 10:36:49 +0000485 } else {
Andrea Di Biagio083addf2018-10-24 10:56:47 +0000486 Message = "found an inconsistent instruction that decodes "
487 "to zero opcodes and that consumes scheduler "
488 "resources.";
Andrea Di Biagioaacd5e12018-10-04 10:36:49 +0000489 }
490
Andrea Di Biagio083addf2018-10-24 10:56:47 +0000491 return make_error<InstructionError<MCInst>>(Message, MCI);
Andrea Di Biagioaacd5e12018-10-04 10:36:49 +0000492}
493
Matt Davis4bcf3692018-08-13 18:11:48 +0000494Expected<const InstrDesc &>
495InstrBuilder::createInstrDescImpl(const MCInst &MCI) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000496 assert(STI.getSchedModel().hasInstrSchedModel() &&
497 "Itineraries are not yet supported!");
498
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000499 // Obtain the instruction descriptor from the opcode.
Andrea Di Biagio88347792018-07-09 12:30:55 +0000500 unsigned short Opcode = MCI.getOpcode();
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000501 const MCInstrDesc &MCDesc = MCII.get(Opcode);
502 const MCSchedModel &SM = STI.getSchedModel();
503
504 // Then obtain the scheduling class information from the instruction.
Andrea Di Biagio49c85912018-05-04 13:10:10 +0000505 unsigned SchedClassID = MCDesc.getSchedClass();
Andrea Di Biagio36296c02018-11-25 12:46:24 +0000506 bool IsVariant = SM.getSchedClassDesc(SchedClassID)->isVariant();
Andrea Di Biagio39e5a562018-06-04 15:43:09 +0000507
508 // Try to solve variant scheduling classes.
Andrea Di Biagio36296c02018-11-25 12:46:24 +0000509 if (IsVariant) {
510 unsigned CPUID = SM.getProcessorID();
Andrea Di Biagio39e5a562018-06-04 15:43:09 +0000511 while (SchedClassID && SM.getSchedClassDesc(SchedClassID)->isVariant())
512 SchedClassID = STI.resolveVariantSchedClass(SchedClassID, &MCI, CPUID);
513
Matt Davis4bcf3692018-08-13 18:11:48 +0000514 if (!SchedClassID) {
Andrea Di Biagio083addf2018-10-24 10:56:47 +0000515 return make_error<InstructionError<MCInst>>(
516 "unable to resolve scheduling class for write variant.", MCI);
Matt Davis4bcf3692018-08-13 18:11:48 +0000517 }
Andrea Di Biagio39e5a562018-06-04 15:43:09 +0000518 }
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000519
Matt Davis4bcf3692018-08-13 18:11:48 +0000520 // Check if this instruction is supported. Otherwise, report an error.
Andrea Di Biagio88347792018-07-09 12:30:55 +0000521 const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID);
522 if (SCDesc.NumMicroOps == MCSchedClassDesc::InvalidNumMicroOps) {
Andrea Di Biagio083addf2018-10-24 10:56:47 +0000523 return make_error<InstructionError<MCInst>>(
524 "found an unsupported instruction in the input assembly sequence.",
525 MCI);
Andrea Di Biagio88347792018-07-09 12:30:55 +0000526 }
527
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000528 // Create a new empty descriptor.
Andrea Di Biagio7b3d1622018-03-20 12:58:34 +0000529 std::unique_ptr<InstrDesc> ID = llvm::make_unique<InstrDesc>();
Andrea Di Biagio39e5a562018-06-04 15:43:09 +0000530 ID->NumMicroOps = SCDesc.NumMicroOps;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000531
Andrea Di Biagio42720602018-11-24 18:40:45 +0000532 if (MCDesc.isCall() && FirstCallInst) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000533 // We don't correctly model calls.
Andrea Di Biagio24fb4fc2018-05-04 13:52:12 +0000534 WithColor::warning() << "found a call in the input assembly sequence.\n";
535 WithColor::note() << "call instructions are not correctly modeled. "
536 << "Assume a latency of 100cy.\n";
Andrea Di Biagio42720602018-11-24 18:40:45 +0000537 FirstCallInst = false;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000538 }
539
Andrea Di Biagio42720602018-11-24 18:40:45 +0000540 if (MCDesc.isReturn() && FirstReturnInst) {
Andrea Di Biagio24fb4fc2018-05-04 13:52:12 +0000541 WithColor::warning() << "found a return instruction in the input"
542 << " assembly sequence.\n";
543 WithColor::note() << "program counter updates are ignored.\n";
Andrea Di Biagio42720602018-11-24 18:40:45 +0000544 FirstReturnInst = false;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000545 }
546
547 ID->MayLoad = MCDesc.mayLoad();
548 ID->MayStore = MCDesc.mayStore();
549 ID->HasSideEffects = MCDesc.hasUnmodeledSideEffects();
Andrea Di Biagio4c737112018-12-17 14:27:33 +0000550 ID->BeginGroup = SCDesc.BeginGroup;
551 ID->EndGroup = SCDesc.EndGroup;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000552
553 initializeUsedResources(*ID, SCDesc, STI, ProcResourceMasks);
Andrea Di Biagiodb66efc2018-04-25 09:38:58 +0000554 computeMaxLatency(*ID, MCDesc, SCDesc, STI);
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000555
556 if (Error Err = verifyOperands(MCDesc, MCI))
Matt Davis4bcf3692018-08-13 18:11:48 +0000557 return std::move(Err);
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000558
559 populateWrites(*ID, MCI, SchedClassID);
560 populateReads(*ID, MCI, SchedClassID);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000561
Evandro Menezes5d780092019-01-08 22:29:38 +0000562#ifndef NDEBUG
563 ID->Name = MCII.getName(Opcode);
564#endif
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000565 LLVM_DEBUG(dbgs() << "\t\tMaxLatency=" << ID->MaxLatency << '\n');
566 LLVM_DEBUG(dbgs() << "\t\tNumMicroOps=" << ID->NumMicroOps << '\n');
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000567
Andrea Di Biagioaacd5e12018-10-04 10:36:49 +0000568 // Sanity check on the instruction descriptor.
569 if (Error Err = verifyInstrDesc(*ID, MCI))
570 return std::move(Err);
571
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000572 // Now add the new descriptor.
Andrea Di Biagio39e5a562018-06-04 15:43:09 +0000573 SchedClassID = MCDesc.getSchedClass();
Andrea Di Biagio36296c02018-11-25 12:46:24 +0000574 bool IsVariadic = MCDesc.isVariadic();
575 if (!IsVariadic && !IsVariant) {
Andrea Di Biagio39e5a562018-06-04 15:43:09 +0000576 Descriptors[MCI.getOpcode()] = std::move(ID);
577 return *Descriptors[MCI.getOpcode()];
578 }
579
580 VariantDescriptors[&MCI] = std::move(ID);
581 return *VariantDescriptors[&MCI];
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000582}
583
Matt Davis4bcf3692018-08-13 18:11:48 +0000584Expected<const InstrDesc &>
585InstrBuilder::getOrCreateInstrDesc(const MCInst &MCI) {
Andrea Di Biagio39e5a562018-06-04 15:43:09 +0000586 if (Descriptors.find_as(MCI.getOpcode()) != Descriptors.end())
587 return *Descriptors[MCI.getOpcode()];
588
589 if (VariantDescriptors.find(&MCI) != VariantDescriptors.end())
590 return *VariantDescriptors[&MCI];
591
592 return createInstrDescImpl(MCI);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000593}
594
Matt Davis4bcf3692018-08-13 18:11:48 +0000595Expected<std::unique_ptr<Instruction>>
Andrea Di Biagio49c85912018-05-04 13:10:10 +0000596InstrBuilder::createInstruction(const MCInst &MCI) {
Matt Davis4bcf3692018-08-13 18:11:48 +0000597 Expected<const InstrDesc &> DescOrErr = getOrCreateInstrDesc(MCI);
598 if (!DescOrErr)
599 return DescOrErr.takeError();
600 const InstrDesc &D = *DescOrErr;
Andrea Di Biagio7b3d1622018-03-20 12:58:34 +0000601 std::unique_ptr<Instruction> NewIS = llvm::make_unique<Instruction>(D);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000602
Andrea Di Biagio9f9cdd42018-09-18 15:00:06 +0000603 // Check if this is a dependency breaking instruction.
Andrea Di Biagio8b6c3142018-09-19 15:57:45 +0000604 APInt Mask;
605
Andrea Di Biagio45060672018-12-17 14:00:37 +0000606 bool IsZeroIdiom = false;
607 bool IsDepBreaking = false;
608 if (MCIA) {
609 unsigned ProcID = STI.getSchedModel().getProcessorID();
610 IsZeroIdiom = MCIA->isZeroIdiom(MCI, Mask, ProcID);
611 IsDepBreaking =
612 IsZeroIdiom || MCIA->isDependencyBreaking(MCI, Mask, ProcID);
613 if (MCIA->isOptimizableRegisterMove(MCI, ProcID))
614 NewIS->setOptimizableMove();
615 }
Andrea Di Biagio9f9cdd42018-09-18 15:00:06 +0000616
Andrea Di Biagiodb66efc2018-04-25 09:38:58 +0000617 // Initialize Reads first.
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000618 for (const ReadDescriptor &RD : D.Reads) {
619 int RegID = -1;
Andrea Di Biagio21f0fdb2018-06-22 16:37:05 +0000620 if (!RD.isImplicitRead()) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000621 // explicit read.
622 const MCOperand &Op = MCI.getOperand(RD.OpIndex);
623 // Skip non-register operands.
624 if (!Op.isReg())
625 continue;
626 RegID = Op.getReg();
627 } else {
628 // Implicit read.
629 RegID = RD.RegisterID;
630 }
631
632 // Skip invalid register operands.
633 if (!RegID)
634 continue;
635
636 // Okay, this is a register operand. Create a ReadState for it.
637 assert(RegID > 0 && "Invalid register ID found!");
Andrea Di Biagio1e6d0aa2018-10-25 17:03:51 +0000638 NewIS->getUses().emplace_back(RD, RegID);
639 ReadState &RS = NewIS->getUses().back();
Andrea Di Biagio9f9cdd42018-09-18 15:00:06 +0000640
Andrea Di Biagio8b6c3142018-09-19 15:57:45 +0000641 if (IsDepBreaking) {
642 // A mask of all zeroes means: explicit input operands are not
643 // independent.
644 if (Mask.isNullValue()) {
645 if (!RD.isImplicitRead())
Andrea Di Biagio1e6d0aa2018-10-25 17:03:51 +0000646 RS.setIndependentFromDef();
Andrea Di Biagio8b6c3142018-09-19 15:57:45 +0000647 } else {
648 // Check if this register operand is independent according to `Mask`.
649 // Note that Mask may not have enough bits to describe all explicit and
650 // implicit input operands. If this register operand doesn't have a
651 // corresponding bit in Mask, then conservatively assume that it is
652 // dependent.
653 if (Mask.getBitWidth() > RD.UseIndex) {
654 // Okay. This map describe register use `RD.UseIndex`.
655 if (Mask[RD.UseIndex])
Andrea Di Biagio1e6d0aa2018-10-25 17:03:51 +0000656 RS.setIndependentFromDef();
Andrea Di Biagio8b6c3142018-09-19 15:57:45 +0000657 }
658 }
659 }
Andrea Di Biagio4704f032018-03-20 12:25:54 +0000660 }
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000661
Andrea Di Biagio2145b132018-06-20 10:08:11 +0000662 // Early exit if there are no writes.
663 if (D.Writes.empty())
Matt Davis4bcf3692018-08-13 18:11:48 +0000664 return std::move(NewIS);
Andrea Di Biagio2145b132018-06-20 10:08:11 +0000665
666 // Track register writes that implicitly clear the upper portion of the
667 // underlying super-registers using an APInt.
668 APInt WriteMask(D.Writes.size(), 0);
669
670 // Now query the MCInstrAnalysis object to obtain information about which
671 // register writes implicitly clear the upper portion of a super-register.
Andrea Di Biagio45060672018-12-17 14:00:37 +0000672 if (MCIA)
673 MCIA->clearsSuperRegisters(MRI, MCI, WriteMask);
Andrea Di Biagio2145b132018-06-20 10:08:11 +0000674
Andrea Di Biagiodb66efc2018-04-25 09:38:58 +0000675 // Initialize writes.
Andrea Di Biagio2145b132018-06-20 10:08:11 +0000676 unsigned WriteIndex = 0;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000677 for (const WriteDescriptor &WD : D.Writes) {
Andrea Di Biagio88347792018-07-09 12:30:55 +0000678 unsigned RegID = WD.isImplicitWrite() ? WD.RegisterID
679 : MCI.getOperand(WD.OpIndex).getReg();
Andrea Di Biagio35622482018-03-22 10:19:20 +0000680 // Check if this is a optional definition that references NoReg.
Andrea Di Biagio2145b132018-06-20 10:08:11 +0000681 if (WD.IsOptionalDef && !RegID) {
682 ++WriteIndex;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000683 continue;
Andrea Di Biagio2145b132018-06-20 10:08:11 +0000684 }
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000685
Andrea Di Biagio35622482018-03-22 10:19:20 +0000686 assert(RegID && "Expected a valid register ID!");
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000687 NewIS->getDefs().emplace_back(WD, RegID,
688 /* ClearsSuperRegs */ WriteMask[WriteIndex],
689 /* WritesZero */ IsZeroIdiom);
Andrea Di Biagio2145b132018-06-20 10:08:11 +0000690 ++WriteIndex;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000691 }
692
Matt Davis4bcf3692018-08-13 18:11:48 +0000693 return std::move(NewIS);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000694}
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000695} // namespace mca
Fangrui Song5a8fd652018-10-30 15:56:08 +0000696} // namespace llvm