blob: d8309b6868e315bc47b110179e3d9b08bf04328c [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)
181 dbgs() << "\t\tMask=" << R.first << ", cy=" << R.second.size() << '\n';
182 for (const uint64_t R : ID.Buffers)
183 dbgs() << "\t\tBuffer Mask=" << R << '\n';
Andrea Di Biagio7b3d1622018-03-20 12:58:34 +0000184 });
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000185}
186
187static void computeMaxLatency(InstrDesc &ID, const MCInstrDesc &MCDesc,
188 const MCSchedClassDesc &SCDesc,
189 const MCSubtargetInfo &STI) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000190 if (MCDesc.isCall()) {
191 // We cannot estimate how long this call will take.
192 // Artificially set an arbitrarily high latency (100cy).
Andrea Di Biagioc95a1302018-03-13 15:59:59 +0000193 ID.MaxLatency = 100U;
194 return;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000195 }
196
Andrea Di Biagioc95a1302018-03-13 15:59:59 +0000197 int Latency = MCSchedModel::computeInstrLatency(STI, SCDesc);
198 // If latency is unknown, then conservatively assume a MaxLatency of 100cy.
199 ID.MaxLatency = Latency < 0 ? 100U : static_cast<unsigned>(Latency);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000200}
201
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000202static Error verifyOperands(const MCInstrDesc &MCDesc, const MCInst &MCI) {
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000203 // Count register definitions, and skip non register operands in the process.
204 unsigned I, E;
205 unsigned NumExplicitDefs = MCDesc.getNumDefs();
206 for (I = 0, E = MCI.getNumOperands(); NumExplicitDefs && I < E; ++I) {
207 const MCOperand &Op = MCI.getOperand(I);
208 if (Op.isReg())
209 --NumExplicitDefs;
210 }
211
212 if (NumExplicitDefs) {
213 return make_error<InstructionError<MCInst>>(
214 "Expected more register operand definitions.", MCI);
215 }
216
217 if (MCDesc.hasOptionalDef()) {
218 // Always assume that the optional definition is the last operand.
219 const MCOperand &Op = MCI.getOperand(MCDesc.getNumOperands() - 1);
220 if (I == MCI.getNumOperands() || !Op.isReg()) {
221 std::string Message =
222 "expected a register operand for an optional definition. Instruction "
223 "has not been correctly analyzed.";
224 return make_error<InstructionError<MCInst>>(Message, MCI);
225 }
226 }
227
228 return ErrorSuccess();
229}
230
231void InstrBuilder::populateWrites(InstrDesc &ID, const MCInst &MCI,
232 unsigned SchedClassID) {
Andrea Di Biagio88347792018-07-09 12:30:55 +0000233 const MCInstrDesc &MCDesc = MCII.get(MCI.getOpcode());
234 const MCSchedModel &SM = STI.getSchedModel();
235 const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID);
236
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000237 // Assumptions made by this algorithm:
238 // 1. The number of explicit and implicit register definitions in a MCInst
239 // matches the number of explicit and implicit definitions according to
240 // the opcode descriptor (MCInstrDesc).
241 // 2. Uses start at index #(MCDesc.getNumDefs()).
242 // 3. There can only be a single optional register definition, an it is
243 // always the last operand of the sequence (excluding extra operands
244 // contributed by variadic opcodes).
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000245 //
246 // These assumptions work quite well for most out-of-order in-tree targets
247 // like x86. This is mainly because the vast majority of instructions is
248 // expanded to MCInst using a straightforward lowering logic that preserves
249 // the ordering of the operands.
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000250 //
251 // About assumption 1.
252 // The algorithm allows non-register operands between register operand
253 // definitions. This helps to handle some special ARM instructions with
254 // implicit operand increment (-mtriple=armv7):
255 //
256 // vld1.32 {d18, d19}, [r1]! @ <MCInst #1463 VLD1q32wb_fixed
257 // @ <MCOperand Reg:59>
258 // @ <MCOperand Imm:0> (!!)
259 // @ <MCOperand Reg:67>
260 // @ <MCOperand Imm:0>
261 // @ <MCOperand Imm:14>
262 // @ <MCOperand Reg:0>>
263 //
264 // MCDesc reports:
265 // 6 explicit operands.
266 // 1 optional definition
267 // 2 explicit definitions (!!)
268 //
269 // The presence of an 'Imm' operand between the two register definitions
270 // breaks the assumption that "register definitions are always at the
271 // beginning of the operand sequence".
272 //
273 // To workaround this issue, this algorithm ignores (i.e. skips) any
274 // non-register operands between register definitions. The optional
275 // definition is still at index #(NumOperands-1).
276 //
277 // According to assumption 2. register reads start at #(NumExplicitDefs-1).
278 // That means, register R1 from the example is both read and written.
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000279 unsigned NumExplicitDefs = MCDesc.getNumDefs();
280 unsigned NumImplicitDefs = MCDesc.getNumImplicitDefs();
281 unsigned NumWriteLatencyEntries = SCDesc.NumWriteLatencyEntries;
282 unsigned TotalDefs = NumExplicitDefs + NumImplicitDefs;
283 if (MCDesc.hasOptionalDef())
284 TotalDefs++;
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000285
Andrea Di Biagio36296c02018-11-25 12:46:24 +0000286 unsigned NumVariadicOps = MCI.getNumOperands() - MCDesc.getNumOperands();
287 ID.Writes.resize(TotalDefs + NumVariadicOps);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000288 // Iterate over the operands list, and skip non-register operands.
289 // The first NumExplictDefs register operands are expected to be register
290 // definitions.
291 unsigned CurrentDef = 0;
292 unsigned i = 0;
293 for (; i < MCI.getNumOperands() && CurrentDef < NumExplicitDefs; ++i) {
294 const MCOperand &Op = MCI.getOperand(i);
295 if (!Op.isReg())
296 continue;
297
298 WriteDescriptor &Write = ID.Writes[CurrentDef];
299 Write.OpIndex = i;
300 if (CurrentDef < NumWriteLatencyEntries) {
301 const MCWriteLatencyEntry &WLE =
302 *STI.getWriteLatencyEntry(&SCDesc, CurrentDef);
303 // Conservatively default to MaxLatency.
Andrea Di Biagio88347792018-07-09 12:30:55 +0000304 Write.Latency =
305 WLE.Cycles < 0 ? ID.MaxLatency : static_cast<unsigned>(WLE.Cycles);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000306 Write.SClassOrWriteResourceID = WLE.WriteResourceID;
307 } else {
308 // Assign a default latency for this write.
309 Write.Latency = ID.MaxLatency;
310 Write.SClassOrWriteResourceID = 0;
311 }
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000312 Write.IsOptionalDef = false;
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000313 LLVM_DEBUG({
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000314 dbgs() << "\t\t[Def] OpIdx=" << Write.OpIndex
Andrea Di Biagio23fbe7c2018-07-13 14:55:47 +0000315 << ", Latency=" << Write.Latency
Andrea Di Biagio7b3d1622018-03-20 12:58:34 +0000316 << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n';
317 });
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000318 CurrentDef++;
319 }
320
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000321 assert(CurrentDef == NumExplicitDefs &&
322 "Expected more register operand definitions.");
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000323 for (CurrentDef = 0; CurrentDef < NumImplicitDefs; ++CurrentDef) {
324 unsigned Index = NumExplicitDefs + CurrentDef;
325 WriteDescriptor &Write = ID.Writes[Index];
Andrea Di Biagio21f0fdb2018-06-22 16:37:05 +0000326 Write.OpIndex = ~CurrentDef;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000327 Write.RegisterID = MCDesc.getImplicitDefs()[CurrentDef];
Andrea Di Biagio6fd62fe2018-04-02 13:46:49 +0000328 if (Index < NumWriteLatencyEntries) {
329 const MCWriteLatencyEntry &WLE =
330 *STI.getWriteLatencyEntry(&SCDesc, Index);
331 // Conservatively default to MaxLatency.
Andrea Di Biagio88347792018-07-09 12:30:55 +0000332 Write.Latency =
333 WLE.Cycles < 0 ? ID.MaxLatency : static_cast<unsigned>(WLE.Cycles);
Andrea Di Biagio6fd62fe2018-04-02 13:46:49 +0000334 Write.SClassOrWriteResourceID = WLE.WriteResourceID;
335 } else {
336 // Assign a default latency for this write.
337 Write.Latency = ID.MaxLatency;
338 Write.SClassOrWriteResourceID = 0;
339 }
340
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000341 Write.IsOptionalDef = false;
342 assert(Write.RegisterID != 0 && "Expected a valid phys register!");
Andrea Di Biagio23fbe7c2018-07-13 14:55:47 +0000343 LLVM_DEBUG({
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000344 dbgs() << "\t\t[Def][I] OpIdx=" << ~Write.OpIndex
Andrea Di Biagio23fbe7c2018-07-13 14:55:47 +0000345 << ", PhysReg=" << MRI.getName(Write.RegisterID)
346 << ", Latency=" << Write.Latency
347 << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n';
348 });
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000349 }
350
351 if (MCDesc.hasOptionalDef()) {
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000352 WriteDescriptor &Write = ID.Writes[NumExplicitDefs + NumImplicitDefs];
353 Write.OpIndex = MCDesc.getNumOperands() - 1;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000354 // Assign a default latency for this write.
355 Write.Latency = ID.MaxLatency;
356 Write.SClassOrWriteResourceID = 0;
357 Write.IsOptionalDef = true;
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000358 LLVM_DEBUG({
359 dbgs() << "\t\t[Def][O] OpIdx=" << Write.OpIndex
360 << ", Latency=" << Write.Latency
361 << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n';
362 });
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000363 }
Andrea Di Biagio36296c02018-11-25 12:46:24 +0000364
365 if (!NumVariadicOps)
366 return;
367
368 // FIXME: if an instruction opcode is flagged 'mayStore', and it has no
369 // "unmodeledSideEffects', then this logic optimistically assumes that any
370 // extra register operands in the variadic sequence is not a register
371 // definition.
372 //
373 // Otherwise, we conservatively assume that any register operand from the
374 // variadic sequence is both a register read and a register write.
375 bool AssumeUsesOnly = MCDesc.mayStore() && !MCDesc.mayLoad() &&
376 !MCDesc.hasUnmodeledSideEffects();
377 CurrentDef = NumExplicitDefs + NumImplicitDefs + MCDesc.hasOptionalDef();
378 for (unsigned I = 0, OpIndex = MCDesc.getNumOperands();
379 I < NumVariadicOps && !AssumeUsesOnly; ++I, ++OpIndex) {
380 const MCOperand &Op = MCI.getOperand(OpIndex);
381 if (!Op.isReg())
382 continue;
383
384 WriteDescriptor &Write = ID.Writes[CurrentDef];
385 Write.OpIndex = OpIndex;
386 // Assign a default latency for this write.
387 Write.Latency = ID.MaxLatency;
388 Write.SClassOrWriteResourceID = 0;
389 Write.IsOptionalDef = false;
390 ++CurrentDef;
391 LLVM_DEBUG({
392 dbgs() << "\t\t[Def][V] OpIdx=" << Write.OpIndex
393 << ", Latency=" << Write.Latency
394 << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n';
395 });
396 }
397
398 ID.Writes.resize(CurrentDef);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000399}
400
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000401void InstrBuilder::populateReads(InstrDesc &ID, const MCInst &MCI,
402 unsigned SchedClassID) {
Andrea Di Biagio88347792018-07-09 12:30:55 +0000403 const MCInstrDesc &MCDesc = MCII.get(MCI.getOpcode());
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000404 unsigned NumExplicitUses = MCDesc.getNumOperands() - MCDesc.getNumDefs();
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000405 unsigned NumImplicitUses = MCDesc.getNumImplicitUses();
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000406 // Remove the optional definition.
407 if (MCDesc.hasOptionalDef())
408 --NumExplicitUses;
Andrea Di Biagio36296c02018-11-25 12:46:24 +0000409 unsigned NumVariadicOps = MCI.getNumOperands() - MCDesc.getNumOperands();
410 unsigned TotalUses = NumExplicitUses + NumImplicitUses + NumVariadicOps;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000411 ID.Reads.resize(TotalUses);
Andrea Di Biagio36296c02018-11-25 12:46:24 +0000412 unsigned CurrentUse = 0;
413 for (unsigned I = 0, OpIndex = MCDesc.getNumDefs(); I < NumExplicitUses;
414 ++I, ++OpIndex) {
415 const MCOperand &Op = MCI.getOperand(OpIndex);
416 if (!Op.isReg())
417 continue;
418
419 ReadDescriptor &Read = ID.Reads[CurrentUse];
420 Read.OpIndex = OpIndex;
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000421 Read.UseIndex = I;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000422 Read.SchedClassID = SchedClassID;
Andrea Di Biagio36296c02018-11-25 12:46:24 +0000423 ++CurrentUse;
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000424 LLVM_DEBUG(dbgs() << "\t\t[Use] OpIdx=" << Read.OpIndex
Andrea Di Biagio23fbe7c2018-07-13 14:55:47 +0000425 << ", UseIndex=" << Read.UseIndex << '\n');
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000426 }
427
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000428 // For the purpose of ReadAdvance, implicit uses come directly after explicit
429 // uses. The "UseIndex" must be updated according to that implicit layout.
430 for (unsigned I = 0; I < NumImplicitUses; ++I) {
Andrea Di Biagio36296c02018-11-25 12:46:24 +0000431 ReadDescriptor &Read = ID.Reads[CurrentUse + I];
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000432 Read.OpIndex = ~I;
433 Read.UseIndex = NumExplicitUses + I;
434 Read.RegisterID = MCDesc.getImplicitUses()[I];
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000435 Read.SchedClassID = SchedClassID;
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000436 LLVM_DEBUG(dbgs() << "\t\t[Use][I] OpIdx=" << ~Read.OpIndex
437 << ", UseIndex=" << Read.UseIndex << ", RegisterID="
Andrea Di Biagio23fbe7c2018-07-13 14:55:47 +0000438 << MRI.getName(Read.RegisterID) << '\n');
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000439 }
Andrea Di Biagio36296c02018-11-25 12:46:24 +0000440
441 CurrentUse += NumImplicitUses;
442
443 // FIXME: If an instruction opcode is marked as 'mayLoad', and it has no
444 // "unmodeledSideEffects", then this logic optimistically assumes that any
445 // extra register operands in the variadic sequence are not register
446 // definition.
447
448 bool AssumeDefsOnly = !MCDesc.mayStore() && MCDesc.mayLoad() &&
449 !MCDesc.hasUnmodeledSideEffects();
450 for (unsigned I = 0, OpIndex = MCDesc.getNumOperands();
451 I < NumVariadicOps && !AssumeDefsOnly; ++I, ++OpIndex) {
452 const MCOperand &Op = MCI.getOperand(OpIndex);
453 if (!Op.isReg())
454 continue;
455
456 ReadDescriptor &Read = ID.Reads[CurrentUse];
457 Read.OpIndex = OpIndex;
458 Read.UseIndex = NumExplicitUses + NumImplicitUses + I;
459 Read.SchedClassID = SchedClassID;
460 ++CurrentUse;
461 LLVM_DEBUG(dbgs() << "\t\t[Use][V] OpIdx=" << Read.OpIndex
462 << ", UseIndex=" << Read.UseIndex << '\n');
463 }
464
465 ID.Reads.resize(CurrentUse);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000466}
467
Andrea Di Biagioaacd5e12018-10-04 10:36:49 +0000468Error InstrBuilder::verifyInstrDesc(const InstrDesc &ID,
469 const MCInst &MCI) const {
470 if (ID.NumMicroOps != 0)
471 return ErrorSuccess();
472
473 bool UsesMemory = ID.MayLoad || ID.MayStore;
474 bool UsesBuffers = !ID.Buffers.empty();
475 bool UsesResources = !ID.Resources.empty();
476 if (!UsesMemory && !UsesBuffers && !UsesResources)
477 return ErrorSuccess();
478
Andrea Di Biagio083addf2018-10-24 10:56:47 +0000479 StringRef Message;
Andrea Di Biagioaacd5e12018-10-04 10:36:49 +0000480 if (UsesMemory) {
Andrea Di Biagio083addf2018-10-24 10:56:47 +0000481 Message = "found an inconsistent instruction that decodes "
482 "into zero opcodes and that consumes load/store "
483 "unit resources.";
Andrea Di Biagioaacd5e12018-10-04 10:36:49 +0000484 } else {
Andrea Di Biagio083addf2018-10-24 10:56:47 +0000485 Message = "found an inconsistent instruction that decodes "
486 "to zero opcodes and that consumes scheduler "
487 "resources.";
Andrea Di Biagioaacd5e12018-10-04 10:36:49 +0000488 }
489
Andrea Di Biagio083addf2018-10-24 10:56:47 +0000490 return make_error<InstructionError<MCInst>>(Message, MCI);
Andrea Di Biagioaacd5e12018-10-04 10:36:49 +0000491}
492
Matt Davis4bcf3692018-08-13 18:11:48 +0000493Expected<const InstrDesc &>
494InstrBuilder::createInstrDescImpl(const MCInst &MCI) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000495 assert(STI.getSchedModel().hasInstrSchedModel() &&
496 "Itineraries are not yet supported!");
497
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000498 // Obtain the instruction descriptor from the opcode.
Andrea Di Biagio88347792018-07-09 12:30:55 +0000499 unsigned short Opcode = MCI.getOpcode();
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000500 const MCInstrDesc &MCDesc = MCII.get(Opcode);
501 const MCSchedModel &SM = STI.getSchedModel();
502
503 // Then obtain the scheduling class information from the instruction.
Andrea Di Biagio49c85912018-05-04 13:10:10 +0000504 unsigned SchedClassID = MCDesc.getSchedClass();
Andrea Di Biagio36296c02018-11-25 12:46:24 +0000505 bool IsVariant = SM.getSchedClassDesc(SchedClassID)->isVariant();
Andrea Di Biagio39e5a562018-06-04 15:43:09 +0000506
507 // Try to solve variant scheduling classes.
Andrea Di Biagio36296c02018-11-25 12:46:24 +0000508 if (IsVariant) {
509 unsigned CPUID = SM.getProcessorID();
Andrea Di Biagio39e5a562018-06-04 15:43:09 +0000510 while (SchedClassID && SM.getSchedClassDesc(SchedClassID)->isVariant())
511 SchedClassID = STI.resolveVariantSchedClass(SchedClassID, &MCI, CPUID);
512
Matt Davis4bcf3692018-08-13 18:11:48 +0000513 if (!SchedClassID) {
Andrea Di Biagio083addf2018-10-24 10:56:47 +0000514 return make_error<InstructionError<MCInst>>(
515 "unable to resolve scheduling class for write variant.", MCI);
Matt Davis4bcf3692018-08-13 18:11:48 +0000516 }
Andrea Di Biagio39e5a562018-06-04 15:43:09 +0000517 }
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000518
Matt Davis4bcf3692018-08-13 18:11:48 +0000519 // Check if this instruction is supported. Otherwise, report an error.
Andrea Di Biagio88347792018-07-09 12:30:55 +0000520 const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID);
521 if (SCDesc.NumMicroOps == MCSchedClassDesc::InvalidNumMicroOps) {
Andrea Di Biagio083addf2018-10-24 10:56:47 +0000522 return make_error<InstructionError<MCInst>>(
523 "found an unsupported instruction in the input assembly sequence.",
524 MCI);
Andrea Di Biagio88347792018-07-09 12:30:55 +0000525 }
526
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000527 // Create a new empty descriptor.
Andrea Di Biagio7b3d1622018-03-20 12:58:34 +0000528 std::unique_ptr<InstrDesc> ID = llvm::make_unique<InstrDesc>();
Andrea Di Biagio39e5a562018-06-04 15:43:09 +0000529 ID->NumMicroOps = SCDesc.NumMicroOps;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000530
Andrea Di Biagio42720602018-11-24 18:40:45 +0000531 if (MCDesc.isCall() && FirstCallInst) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000532 // We don't correctly model calls.
Andrea Di Biagio24fb4fc2018-05-04 13:52:12 +0000533 WithColor::warning() << "found a call in the input assembly sequence.\n";
534 WithColor::note() << "call instructions are not correctly modeled. "
535 << "Assume a latency of 100cy.\n";
Andrea Di Biagio42720602018-11-24 18:40:45 +0000536 FirstCallInst = false;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000537 }
538
Andrea Di Biagio42720602018-11-24 18:40:45 +0000539 if (MCDesc.isReturn() && FirstReturnInst) {
Andrea Di Biagio24fb4fc2018-05-04 13:52:12 +0000540 WithColor::warning() << "found a return instruction in the input"
541 << " assembly sequence.\n";
542 WithColor::note() << "program counter updates are ignored.\n";
Andrea Di Biagio42720602018-11-24 18:40:45 +0000543 FirstReturnInst = false;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000544 }
545
546 ID->MayLoad = MCDesc.mayLoad();
547 ID->MayStore = MCDesc.mayStore();
548 ID->HasSideEffects = MCDesc.hasUnmodeledSideEffects();
Andrea Di Biagio4c737112018-12-17 14:27:33 +0000549 ID->BeginGroup = SCDesc.BeginGroup;
550 ID->EndGroup = SCDesc.EndGroup;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000551
552 initializeUsedResources(*ID, SCDesc, STI, ProcResourceMasks);
Andrea Di Biagiodb66efc2018-04-25 09:38:58 +0000553 computeMaxLatency(*ID, MCDesc, SCDesc, STI);
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000554
555 if (Error Err = verifyOperands(MCDesc, MCI))
Matt Davis4bcf3692018-08-13 18:11:48 +0000556 return std::move(Err);
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000557
558 populateWrites(*ID, MCI, SchedClassID);
559 populateReads(*ID, MCI, SchedClassID);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000560
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000561 LLVM_DEBUG(dbgs() << "\t\tMaxLatency=" << ID->MaxLatency << '\n');
562 LLVM_DEBUG(dbgs() << "\t\tNumMicroOps=" << ID->NumMicroOps << '\n');
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000563
Andrea Di Biagioaacd5e12018-10-04 10:36:49 +0000564 // Sanity check on the instruction descriptor.
565 if (Error Err = verifyInstrDesc(*ID, MCI))
566 return std::move(Err);
567
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000568 // Now add the new descriptor.
Andrea Di Biagio39e5a562018-06-04 15:43:09 +0000569 SchedClassID = MCDesc.getSchedClass();
Andrea Di Biagio36296c02018-11-25 12:46:24 +0000570 bool IsVariadic = MCDesc.isVariadic();
571 if (!IsVariadic && !IsVariant) {
Andrea Di Biagio39e5a562018-06-04 15:43:09 +0000572 Descriptors[MCI.getOpcode()] = std::move(ID);
573 return *Descriptors[MCI.getOpcode()];
574 }
575
576 VariantDescriptors[&MCI] = std::move(ID);
577 return *VariantDescriptors[&MCI];
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000578}
579
Matt Davis4bcf3692018-08-13 18:11:48 +0000580Expected<const InstrDesc &>
581InstrBuilder::getOrCreateInstrDesc(const MCInst &MCI) {
Andrea Di Biagio39e5a562018-06-04 15:43:09 +0000582 if (Descriptors.find_as(MCI.getOpcode()) != Descriptors.end())
583 return *Descriptors[MCI.getOpcode()];
584
585 if (VariantDescriptors.find(&MCI) != VariantDescriptors.end())
586 return *VariantDescriptors[&MCI];
587
588 return createInstrDescImpl(MCI);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000589}
590
Matt Davis4bcf3692018-08-13 18:11:48 +0000591Expected<std::unique_ptr<Instruction>>
Andrea Di Biagio49c85912018-05-04 13:10:10 +0000592InstrBuilder::createInstruction(const MCInst &MCI) {
Matt Davis4bcf3692018-08-13 18:11:48 +0000593 Expected<const InstrDesc &> DescOrErr = getOrCreateInstrDesc(MCI);
594 if (!DescOrErr)
595 return DescOrErr.takeError();
596 const InstrDesc &D = *DescOrErr;
Andrea Di Biagio7b3d1622018-03-20 12:58:34 +0000597 std::unique_ptr<Instruction> NewIS = llvm::make_unique<Instruction>(D);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000598
Andrea Di Biagio9f9cdd42018-09-18 15:00:06 +0000599 // Check if this is a dependency breaking instruction.
Andrea Di Biagio8b6c3142018-09-19 15:57:45 +0000600 APInt Mask;
601
Andrea Di Biagio45060672018-12-17 14:00:37 +0000602 bool IsZeroIdiom = false;
603 bool IsDepBreaking = false;
604 if (MCIA) {
605 unsigned ProcID = STI.getSchedModel().getProcessorID();
606 IsZeroIdiom = MCIA->isZeroIdiom(MCI, Mask, ProcID);
607 IsDepBreaking =
608 IsZeroIdiom || MCIA->isDependencyBreaking(MCI, Mask, ProcID);
609 if (MCIA->isOptimizableRegisterMove(MCI, ProcID))
610 NewIS->setOptimizableMove();
611 }
Andrea Di Biagio9f9cdd42018-09-18 15:00:06 +0000612
Andrea Di Biagiodb66efc2018-04-25 09:38:58 +0000613 // Initialize Reads first.
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000614 for (const ReadDescriptor &RD : D.Reads) {
615 int RegID = -1;
Andrea Di Biagio21f0fdb2018-06-22 16:37:05 +0000616 if (!RD.isImplicitRead()) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000617 // explicit read.
618 const MCOperand &Op = MCI.getOperand(RD.OpIndex);
619 // Skip non-register operands.
620 if (!Op.isReg())
621 continue;
622 RegID = Op.getReg();
623 } else {
624 // Implicit read.
625 RegID = RD.RegisterID;
626 }
627
628 // Skip invalid register operands.
629 if (!RegID)
630 continue;
631
632 // Okay, this is a register operand. Create a ReadState for it.
633 assert(RegID > 0 && "Invalid register ID found!");
Andrea Di Biagio1e6d0aa2018-10-25 17:03:51 +0000634 NewIS->getUses().emplace_back(RD, RegID);
635 ReadState &RS = NewIS->getUses().back();
Andrea Di Biagio9f9cdd42018-09-18 15:00:06 +0000636
Andrea Di Biagio8b6c3142018-09-19 15:57:45 +0000637 if (IsDepBreaking) {
638 // A mask of all zeroes means: explicit input operands are not
639 // independent.
640 if (Mask.isNullValue()) {
641 if (!RD.isImplicitRead())
Andrea Di Biagio1e6d0aa2018-10-25 17:03:51 +0000642 RS.setIndependentFromDef();
Andrea Di Biagio8b6c3142018-09-19 15:57:45 +0000643 } else {
644 // Check if this register operand is independent according to `Mask`.
645 // Note that Mask may not have enough bits to describe all explicit and
646 // implicit input operands. If this register operand doesn't have a
647 // corresponding bit in Mask, then conservatively assume that it is
648 // dependent.
649 if (Mask.getBitWidth() > RD.UseIndex) {
650 // Okay. This map describe register use `RD.UseIndex`.
651 if (Mask[RD.UseIndex])
Andrea Di Biagio1e6d0aa2018-10-25 17:03:51 +0000652 RS.setIndependentFromDef();
Andrea Di Biagio8b6c3142018-09-19 15:57:45 +0000653 }
654 }
655 }
Andrea Di Biagio4704f032018-03-20 12:25:54 +0000656 }
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000657
Andrea Di Biagio2145b132018-06-20 10:08:11 +0000658 // Early exit if there are no writes.
659 if (D.Writes.empty())
Matt Davis4bcf3692018-08-13 18:11:48 +0000660 return std::move(NewIS);
Andrea Di Biagio2145b132018-06-20 10:08:11 +0000661
662 // Track register writes that implicitly clear the upper portion of the
663 // underlying super-registers using an APInt.
664 APInt WriteMask(D.Writes.size(), 0);
665
666 // Now query the MCInstrAnalysis object to obtain information about which
667 // register writes implicitly clear the upper portion of a super-register.
Andrea Di Biagio45060672018-12-17 14:00:37 +0000668 if (MCIA)
669 MCIA->clearsSuperRegisters(MRI, MCI, WriteMask);
Andrea Di Biagio2145b132018-06-20 10:08:11 +0000670
Andrea Di Biagiodb66efc2018-04-25 09:38:58 +0000671 // Initialize writes.
Andrea Di Biagio2145b132018-06-20 10:08:11 +0000672 unsigned WriteIndex = 0;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000673 for (const WriteDescriptor &WD : D.Writes) {
Andrea Di Biagio88347792018-07-09 12:30:55 +0000674 unsigned RegID = WD.isImplicitWrite() ? WD.RegisterID
675 : MCI.getOperand(WD.OpIndex).getReg();
Andrea Di Biagio35622482018-03-22 10:19:20 +0000676 // Check if this is a optional definition that references NoReg.
Andrea Di Biagio2145b132018-06-20 10:08:11 +0000677 if (WD.IsOptionalDef && !RegID) {
678 ++WriteIndex;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000679 continue;
Andrea Di Biagio2145b132018-06-20 10:08:11 +0000680 }
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000681
Andrea Di Biagio35622482018-03-22 10:19:20 +0000682 assert(RegID && "Expected a valid register ID!");
Andrea Di Biagio7e32cc82018-11-23 20:26:57 +0000683 NewIS->getDefs().emplace_back(WD, RegID,
684 /* ClearsSuperRegs */ WriteMask[WriteIndex],
685 /* WritesZero */ IsZeroIdiom);
Andrea Di Biagio2145b132018-06-20 10:08:11 +0000686 ++WriteIndex;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000687 }
688
Matt Davis4bcf3692018-08-13 18:11:48 +0000689 return std::move(NewIS);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000690}
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000691} // namespace mca
Fangrui Song5a8fd652018-10-30 15:56:08 +0000692} // namespace llvm