xref: /freebsd/contrib/llvm-project/llvm/lib/Target/ARM/ARMScheduleM7.td (revision 0d8fe2373503aeac48492f28073049a8bfa4feb5)
1//=- ARMScheduleM7.td - ARM Cortex-M7 Scheduling Definitions -*- tablegen -*-=//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines the SchedRead/Write data for the ARM Cortex-M7 processor.
10//
11//===----------------------------------------------------------------------===//
12
13def CortexM7Model : SchedMachineModel {
14  let IssueWidth = 2;        // Dual issue for most instructions.
15  let MicroOpBufferSize = 0; // The Cortex-M7 is in-order.
16  let LoadLatency = 2;       // Best case for load-use case.
17  let MispredictPenalty = 4; // Mispredict cost for forward branches is 6,
18                             // but 4 works better
19  let CompleteModel = 0;
20}
21
22//===--------------------------------------------------------------------===//
23// The Cortex-M7 has two ALU, two LOAD, a STORE, a MAC, a BRANCH and a VFP
24// pipe. The stages relevant to scheduling are as follows:
25//
26//   EX1: address generation  shifts
27//   EX2: fast load data      ALUs                  FP operation
28//   EX3: slow load data      integer writeback     FP operation
29//   EX4: store data                                FP writeback
30//
31// There are shifters in both EX1 and EX2, and some instructions can be
32// flexibly allocated between them.  EX2 is used as the "zero" point
33// for scheduling, so simple ALU operations executing in EX2 will have
34// ReadAdvance<0> (the default) for their source operands and Latency = 1.
35
36def M7UnitLoad   : ProcResource<2> { let BufferSize = 0; }
37def M7UnitStore  : ProcResource<1> { let BufferSize = 0; }
38def M7UnitALU    : ProcResource<2>;
39def M7UnitShift1 : ProcResource<1> { let BufferSize = 0; }
40def M7UnitShift2 : ProcResource<1> { let BufferSize = 0; }
41def M7UnitMAC    : ProcResource<1> { let BufferSize = 0; }
42def M7UnitBranch : ProcResource<1> { let BufferSize = 0; }
43def M7UnitVFP    : ProcResource<1> { let BufferSize = 0; }
44def M7UnitVPort  : ProcResource<2> { let BufferSize = 0; }
45def M7UnitSIMD   : ProcResource<1> { let BufferSize = 0; }
46
47//===---------------------------------------------------------------------===//
48// Subtarget-specific SchedWrite types with map ProcResources and set latency.
49
50let SchedModel = CortexM7Model in {
51
52def : WriteRes<WriteALU, [M7UnitALU]> { let Latency = 1; }
53
54// Basic ALU with shifts.
55let Latency = 1 in {
56  def : WriteRes<WriteALUsi,  [M7UnitALU, M7UnitShift1]>;
57  def : WriteRes<WriteALUsr,  [M7UnitALU, M7UnitShift1]>;
58  def : WriteRes<WriteALUSsr, [M7UnitALU, M7UnitShift1]>;
59}
60
61// Compares.
62def : WriteRes<WriteCMP,   [M7UnitALU]> { let Latency = 1; }
63def : WriteRes<WriteCMPsi, [M7UnitALU, M7UnitShift1]> { let Latency = 2; }
64def : WriteRes<WriteCMPsr, [M7UnitALU, M7UnitShift1]> { let Latency = 2; }
65
66// Multiplies.
67let Latency = 2 in {
68  def : WriteRes<WriteMUL16,   [M7UnitMAC]>;
69  def : WriteRes<WriteMUL32,   [M7UnitMAC]>;
70  def : WriteRes<WriteMUL64Lo, [M7UnitMAC]>;
71  def : WriteRes<WriteMUL64Hi, []> { let NumMicroOps = 0; }
72}
73
74// Multiply-accumulates.
75let Latency = 2 in {
76  def : WriteRes<WriteMAC16,   [M7UnitMAC]>;
77  def : WriteRes<WriteMAC32,   [M7UnitMAC]>;
78  def : WriteRes<WriteMAC64Lo, [M7UnitMAC]> { let Latency = 2; }
79  def : WriteRes<WriteMAC64Hi, []> { let NumMicroOps = 0; }
80}
81
82// Divisions.
83// These cannot be dual-issued with any instructions.
84def : WriteRes<WriteDIV, [M7UnitALU]> {
85  let Latency = 7;
86  let SingleIssue = 1;
87}
88
89// Loads/Stores.
90def : WriteRes<WriteLd,    [M7UnitLoad]> { let Latency = 1; }
91def : WriteRes<WritePreLd, [M7UnitLoad]> { let Latency = 2; }
92def : WriteRes<WriteST,    [M7UnitStore]> { let Latency = 2; }
93
94// Branches.
95def : WriteRes<WriteBr,    [M7UnitBranch]> { let Latency = 2; }
96def : WriteRes<WriteBrL,   [M7UnitBranch]> { let Latency = 2; }
97def : WriteRes<WriteBrTbl, [M7UnitBranch]> { let Latency = 2; }
98
99// Noop.
100def : WriteRes<WriteNoop, []> { let Latency = 0; }
101
102//===---------------------------------------------------------------------===//
103// Sched definitions for floating-point instructions
104//
105// Floating point conversions.
106def : WriteRes<WriteFPCVT, [M7UnitVFP, M7UnitVPort]> { let Latency = 3; }
107def : WriteRes<WriteFPMOV, [M7UnitVPort]>            { let Latency = 3; }
108
109// The FP pipeline has a latency of 3 cycles.
110// ALU operations (32/64-bit).  These go down the FP pipeline.
111def : WriteRes<WriteFPALU32, [M7UnitVFP, M7UnitVPort]>  { let Latency = 3; }
112def : WriteRes<WriteFPALU64, [M7UnitVFP, M7UnitVPort, M7UnitVPort]> {
113  let Latency = 4;
114  let BeginGroup = 1;
115}
116
117// Multiplication
118def : WriteRes<WriteFPMUL32, [M7UnitVFP, M7UnitVPort]> { let Latency = 3; }
119def : WriteRes<WriteFPMUL64, [M7UnitVFP, M7UnitVPort, M7UnitVPort]> {
120  let Latency = 7;
121  let BeginGroup = 1;
122}
123
124// Multiply-accumulate.  FPMAC goes down the FP Pipeline.
125def : WriteRes<WriteFPMAC32, [M7UnitVFP, M7UnitVPort]> { let Latency = 6; }
126def : WriteRes<WriteFPMAC64, [M7UnitVFP, M7UnitVPort, M7UnitVPort]> {
127  let Latency = 11;
128  let BeginGroup = 1;
129}
130
131// Division.   Effective scheduling latency is 3, though real latency is larger
132def : WriteRes<WriteFPDIV32, [M7UnitVFP, M7UnitVPort]>  { let Latency = 16; }
133def : WriteRes<WriteFPDIV64, [M7UnitVFP, M7UnitVPort, M7UnitVPort]> {
134  let Latency = 30;
135  let BeginGroup = 1;
136}
137
138// Square-root.  Effective scheduling latency is 3; real latency is larger
139def : WriteRes<WriteFPSQRT32, [M7UnitVFP, M7UnitVPort]> { let Latency = 16; }
140def : WriteRes<WriteFPSQRT64, [M7UnitVFP, M7UnitVPort, M7UnitVPort]> {
141  let Latency = 30;
142  let BeginGroup = 1;
143}
144
145def M7WriteShift2   : SchedWriteRes<[M7UnitALU, M7UnitShift2]> {}
146
147// Not used for M7, but needing definitions anyway
148def : WriteRes<WriteVLD1, []>;
149def : WriteRes<WriteVLD2, []>;
150def : WriteRes<WriteVLD3, []>;
151def : WriteRes<WriteVLD4, []>;
152def : WriteRes<WriteVST1, []>;
153def : WriteRes<WriteVST2, []>;
154def : WriteRes<WriteVST3, []>;
155def : WriteRes<WriteVST4, []>;
156
157def M7SingleIssue : SchedWriteRes<[]> {
158  let SingleIssue = 1;
159  let NumMicroOps = 0;
160}
161def M7Slot0Only   : SchedWriteRes<[]> {
162  let BeginGroup = 1;
163  let NumMicroOps = 0;
164}
165
166// What pipeline stage operands need to be ready for depending on
167// where they come from.
168def : ReadAdvance<ReadALUsr, 0>;
169def : ReadAdvance<ReadMUL, 0>;
170def : ReadAdvance<ReadMAC, 1>;
171def : ReadAdvance<ReadALU, 0>;
172def : ReadAdvance<ReadFPMUL, 0>;
173def : ReadAdvance<ReadFPMAC, 3>;
174def M7Read_ISS : SchedReadAdvance<-1>;     // operands needed at EX1
175def M7Read_EX2   : SchedReadAdvance<1>;    // operands needed at EX3
176def M7Read_EX3   : SchedReadAdvance<2>;    // operands needed at EX4
177
178// Non general purpose instructions may not be dual issued. These
179// use both issue units.
180def M7NonGeneralPurpose : SchedWriteRes<[]> {
181  // Assume that these will go down the main ALU pipeline.
182  // In reality, many look likely to stall the whole pipeline.
183  let Latency = 3;
184  let SingleIssue = 1;
185}
186
187// List the non general purpose instructions.
188def : InstRW<[M7NonGeneralPurpose], (instregex "t2MRS", "tSVC", "tBKPT",
189                                     "t2MSR", "t2DMB", "t2DSB", "t2ISB",
190                                     "t2HVC", "t2SMC", "t2UDF", "ERET",
191                                     "tHINT", "t2HINT", "t2CLREX", "BUNDLE")>;
192
193//===---------------------------------------------------------------------===//
194// Sched definitions for load/store
195//
196// Mark whether the loads/stores must be single-issue
197// Address operands are needed earlier
198// Data operands are needed later
199
200def M7BaseUpdate : SchedWriteRes<[]> {
201    let Latency = 0; // Update is bypassable out of EX1
202    let NumMicroOps = 0;
203}
204def M7LoadLatency1 : SchedWriteRes<[]> {
205    let Latency = 1;
206    let NumMicroOps = 0;
207}
208def M7SlowLoad : SchedWriteRes<[M7UnitLoad]>            { let Latency = 2; }
209
210// Byte and half-word loads should have greater latency than other loads.
211// So should load exclusive.
212
213def : InstRW<[M7SlowLoad],
214      (instregex "t2LDR(B|H|SB|SH)pc")>;
215def : InstRW<[M7SlowLoad, M7Read_ISS],
216      (instregex "t2LDR(B|H|SB|SH)T", "t2LDR(B|H|SB|SH)i",
217                 "tLDR(B|H)i")>;
218def : InstRW<[M7SlowLoad, M7Read_ISS, M7Read_ISS],
219      (instregex "t2LDR(B|H|SB|SH)s", "tLDR(B|H)r", "tLDR(SB|SH)")>;
220def : InstRW<[M7SlowLoad, M7BaseUpdate, M7Read_ISS],
221      (instregex "t2LDR(B|H|SB|SH)_(POST|PRE)")>;
222
223// Exclusive loads/stores cannot be dual-issued
224def : InstRW<[WriteLd, M7Slot0Only, M7Read_ISS],
225      (instregex "t2LDREX$")>;
226def : InstRW<[M7SlowLoad, M7Slot0Only, M7Read_ISS],
227      (instregex "t2LDREX(B|H)")>;
228def : InstRW<[WriteST, M7SingleIssue, M7Read_EX2, M7Read_ISS],
229      (instregex "t2STREX(B|H)?$")>;
230
231// Load/store multiples cannot be dual-issued.  Note that default scheduling
232// occurs around read/write times of individual registers in the list; read
233// time for STM cannot be overridden because it is a variadic source operand.
234
235def : InstRW<[WriteLd, M7SingleIssue, M7Read_ISS],
236      (instregex "(t|t2)LDM(DB|IA)$")>;
237def : InstRW<[WriteST, M7SingleIssue, M7Read_ISS],
238      (instregex "(t|t2)STM(DB|IA)$")>;
239def : InstRW<[M7BaseUpdate, WriteLd, M7SingleIssue, M7Read_ISS],
240      (instregex "(t|t2)LDM(DB|IA)_UPD$", "tPOP")>;
241def : InstRW<[M7BaseUpdate, WriteST, M7SingleIssue, M7Read_ISS],
242      (instregex "(t|t2)STM(DB|IA)_UPD$", "tPUSH")>;
243
244// Load/store doubles cannot be dual-issued.
245
246def : InstRW<[M7BaseUpdate, WriteST, M7SingleIssue,
247              M7Read_EX2, M7Read_EX2, M7Read_ISS],
248      (instregex "t2STRD_(PRE|POST)")>;
249def : InstRW<[WriteST, M7SingleIssue, M7Read_EX2, M7Read_EX2, M7Read_ISS],
250      (instregex "t2STRDi")>;
251def : InstRW<[WriteLd, M7LoadLatency1, M7SingleIssue, M7BaseUpdate, M7Read_ISS],
252      (instregex "t2LDRD_(PRE|POST)")>;
253def : InstRW<[WriteLd, M7LoadLatency1, M7SingleIssue, M7Read_ISS],
254      (instregex "t2LDRDi")>;
255
256// Word load / preload
257def : InstRW<[WriteLd],
258      (instregex "t2LDRpc", "t2PL[DI]pci", "tLDRpci")>;
259def : InstRW<[WriteLd, M7Read_ISS],
260      (instregex "t2LDR(i|T)", "t2PL[DI](W)?i", "tLDRi", "tLDRspi")>;
261def : InstRW<[WriteLd, M7Read_ISS, M7Read_ISS],
262      (instregex "t2LDRs", "t2PL[DI](w)?s", "tLDRr")>;
263def : InstRW<[WriteLd, M7BaseUpdate, M7Read_ISS],
264      (instregex "t2LDR_(POST|PRE)")>;
265
266// Stores
267def : InstRW<[M7BaseUpdate, WriteST, M7Read_EX2, M7Read_ISS],
268      (instregex "t2STR(B|H)?_(POST|PRE)")>;
269def : InstRW<[WriteST, M7Read_EX2, M7Read_ISS, M7Read_ISS],
270      (instregex "t2STR(B|H)?s$", "tSTR(B|H)?r$")>;
271def : InstRW<[WriteST, M7Read_EX2, M7Read_ISS],
272      (instregex "t2STR(B|H)?(i|T)", "tSTR(B|H)?i$", "tSTRspi")>;
273
274// TBB/TBH - single-issue only; takes two cycles to issue
275
276def M7TableLoad : SchedWriteRes<[M7UnitLoad]> {
277  let NumMicroOps = 2;
278  let SingleIssue = 1;
279}
280
281def : InstRW<[M7TableLoad, M7Read_ISS, M7Read_ISS], (instregex "t2TB")>;
282
283// VFP loads and stores
284
285def M7LoadSP  : SchedWriteRes<[M7UnitLoad, M7UnitVPort]> { let Latency = 1; }
286def M7LoadDP  : SchedWriteRes<[M7UnitLoad, M7UnitVPort, M7UnitVPort]> {
287  let Latency = 2;
288  let SingleIssue = 1;
289}
290def M7StoreSP : SchedWriteRes<[M7UnitStore, M7UnitVPort]>;
291def M7StoreDP : SchedWriteRes<[M7UnitStore, M7UnitVPort, M7UnitVPort]> {
292  let SingleIssue = 1;
293}
294
295def : InstRW<[M7LoadSP, M7Read_ISS],                 (instregex "VLDR(S|H)$")>;
296def : InstRW<[M7LoadDP, M7Read_ISS],                 (instregex "VLDRD$")>;
297def : InstRW<[M7StoreSP, M7Read_EX3, M7Read_ISS],    (instregex "VSTR(S|H)$")>;
298def : InstRW<[M7StoreDP, M7Read_EX3, M7Read_ISS],    (instregex "VSTRD$")>;
299
300// Load/store multiples cannot be dual-issued.
301
302def : InstRW<[WriteLd, M7SingleIssue, M7Read_ISS],
303      (instregex "VLDM(S|D|Q)(DB|IA)$")>;
304def : InstRW<[WriteST, M7SingleIssue, M7Read_ISS],
305      (instregex "VSTM(S|D|Q)(DB|IA)$")>;
306def : InstRW<[M7BaseUpdate, WriteLd, M7SingleIssue, M7Read_ISS],
307      (instregex "VLDM(S|D|Q)(DB|IA)_UPD$")>;
308def : InstRW<[M7BaseUpdate, WriteST, M7SingleIssue, M7Read_ISS],
309      (instregex "VSTM(S|D|Q)(DB|IA)_UPD$")>;
310
311//===---------------------------------------------------------------------===//
312// Sched definitions for ALU
313//
314
315// Shifted ALU operands are read a cycle early.
316def M7Ex1ReadNoFastBypass : SchedReadAdvance<-1, [WriteLd, M7LoadLatency1]>;
317
318def : InstRW<[WriteALUsi, M7Ex1ReadNoFastBypass, M7Read_ISS],
319             (instregex "t2(ADC|ADDS|ADD|BIC|EOR|ORN|ORR|RSBS|RSB|SBC|SUBS)rs$",
320                        "t2(SUB|CMP|CMNz|TEQ|TST)rs$",
321                        "t2MOVsr(a|l)")>;
322def : InstRW<[WriteALUsi, M7Read_ISS],
323             (instregex "t2MVNs")>;
324
325// Treat pure shift operations (except for RRX) as if they used the EX1
326// shifter but have timing as if they used the EX2 shifter as they usually
327// can choose the EX2 shifter when needed.  Will miss a few dual-issue cases,
328// but the results prove to be better than trying to get them exact.
329
330def : InstRW<[M7WriteShift2, M7Read_ISS], (instregex "t2RRX$")>;
331def : InstRW<[WriteALUsi], (instregex "(t|t2)(LSL|LSR|ASR|ROR)")>;
332
333// Instructions that use the shifter, but have normal timing.
334
335def : InstRW<[WriteALUsi,M7Slot0Only], (instregex "t2(BFC|BFI)$")>;
336
337// Instructions which are slot zero only but otherwise normal.
338
339def : InstRW<[WriteALU, M7Slot0Only], (instregex "t2CLZ")>;
340
341// MAC operations that don't have SchedRW set.
342
343def : InstRW<[WriteMAC32, ReadMUL, ReadMUL, ReadMAC], (instregex "t2SML[AS]D")>;
344
345// Divides are special because they stall for their latency, and so look like a
346// single-cycle as far as scheduling opportunities go.  By putting WriteALU
347// first, we make the operand latency 1, but keep the instruction latency 7.
348
349def : InstRW<[WriteALU, WriteDIV], (instregex "t2(S|U)DIV")>;
350
351// DSP extension operations
352
353def M7WriteSIMD1   : SchedWriteRes<[M7UnitSIMD, M7UnitALU]> {
354  let Latency = 1;
355  let BeginGroup = 1;
356}
357def M7WriteSIMD2   : SchedWriteRes<[M7UnitSIMD, M7UnitALU]> {
358  let Latency = 2;
359  let BeginGroup = 1;
360}
361def M7WriteShSIMD1 : SchedWriteRes<[M7UnitSIMD, M7UnitALU, M7UnitShift1]> {
362  let Latency = 1;
363  let BeginGroup = 1;
364}
365def M7WriteShSIMD0 : SchedWriteRes<[M7UnitSIMD, M7UnitALU, M7UnitShift1]> {
366  let Latency = 0;      // Bypassable out of EX1
367  let BeginGroup = 1;
368}
369def M7WriteShSIMD2 : SchedWriteRes<[M7UnitSIMD, M7UnitALU, M7UnitShift1]> {
370  let Latency = 2;
371  let BeginGroup = 1;
372}
373
374def : InstRW<[M7WriteShSIMD2, M7Read_ISS],
375             (instregex "t2(S|U)SAT")>;
376def : InstRW<[M7WriteSIMD1, ReadALU],
377             (instregex "(t|t2)(S|U)XT(B|H)")>;
378def : InstRW<[M7WriteSIMD1, ReadALU, ReadALU],
379             (instregex "t2(S|SH|U|UH)(ADD16|ADD8|ASX|SAX|SUB16|SUB8)",
380                        "t2SEL")>;
381def : InstRW<[M7WriteSIMD2, ReadALU, ReadALU],
382             (instregex "t2(Q|UQ)(ADD|ASX|SAX|SUB)", "t2USAD8")>;
383def : InstRW<[M7WriteShSIMD2, M7Read_ISS, M7Read_ISS],
384             (instregex "t2QD(ADD|SUB)")>;
385def : InstRW<[M7WriteShSIMD0, M7Read_ISS],
386             (instregex "t2(RBIT|REV)", "tREV")>;
387def : InstRW<[M7WriteShSIMD1, M7Read_ISS],
388             (instregex "t2(SBFX|UBFX)")>;
389def : InstRW<[M7WriteShSIMD1, ReadALU, M7Read_ISS],
390             (instregex "t2PKH(BT|TB)", "t2(S|U)XTA")>;
391def : InstRW<[M7WriteSIMD2, ReadALU, ReadALU, M7Read_EX2],
392             (instregex "t2USADA8")>;
393
394// MSR/MRS
395def : InstRW<[M7NonGeneralPurpose], (instregex "MSR", "MRS")>;
396
397//===---------------------------------------------------------------------===//
398// Sched definitions for FP operations
399//
400
401// Effective scheduling latency is really 3 for nearly all FP operations,
402// even if their true latency is higher.
403def M7WriteVFPLatOverride : SchedWriteRes<[]> {
404  let Latency = 3;
405  let NumMicroOps = 0;
406}
407def M7WriteVFPExtraVPort  : SchedWriteRes<[M7UnitVPort]> {
408  let Latency = 3;
409  let NumMicroOps = 0;
410}
411
412// Instructions which are missing default schedules.
413def : InstRW<[WriteFPALU32],
414             (instregex "V(ABS|CVT.*|NEG|FP_VMAX.*|FP_VMIN.*|RINT.*)S$")>;
415def : InstRW<[M7WriteVFPLatOverride, WriteFPALU64],
416             (instregex "V(ABS|CVT.*|NEG|FP_VMAX.*|FP_VMIN.*|RINT.*)D$")>;
417
418// VCMP
419def M7WriteVCMPS : SchedWriteRes<[M7UnitVFP, M7UnitVPort]> { let Latency = 0; }
420def M7WriteVCMPD : SchedWriteRes<[M7UnitVFP, M7UnitVPort, M7UnitVPort]> {
421  let Latency = 0;
422  let BeginGroup = 1;
423}
424def : InstRW<[M7WriteVCMPS], (instregex "VCMPS$")>;
425def : InstRW<[M7WriteVCMPD], (instregex "VCMPD$")>;
426
427    // VMRS/VMSR
428def M7VMRS : SchedWriteRes<[M7UnitVFP, M7UnitVPort]> { let SingleIssue = 1; }
429def M7VMSR : SchedWriteRes<[M7UnitVFP, M7UnitVPort]> { let SingleIssue = 1; }
430def : InstRW<[M7VMRS], (instregex "FMSTAT")>;
431def : InstRW<[M7VMSR], (instregex "VMSR")>;
432
433// VSEL cannot bypass in its implied $cpsr operand; model as earlier read
434def : InstRW<[WriteFPALU32, M7Slot0Only, ReadALU, ReadALU, M7Read_ISS],
435             (instregex "VSEL.*S$")>;
436def : InstRW<[M7WriteVFPLatOverride, WriteFPALU64, M7Slot0Only,
437              ReadALU, ReadALU, M7Read_ISS],
438             (instregex "VSEL.*D$")>;
439
440// VMOV
441def : InstRW<[WriteFPMOV],
442             (instregex "VMOV(H|S)$", "FCONST(H|S)")>;
443def : InstRW<[WriteFPMOV, M7WriteVFPExtraVPort, M7Slot0Only],
444             (instregex "VMOVD$")>;
445def : InstRW<[WriteFPMOV, M7WriteVFPExtraVPort, M7Slot0Only],
446             (instregex "FCONSTD")>;
447def : InstRW<[WriteFPMOV, M7WriteVFPExtraVPort, M7SingleIssue],
448             (instregex "VMOV(DRR|RRD|RRS|SRR)")>;
449
450// Larger-latency overrides.
451
452def : InstRW<[M7WriteVFPLatOverride, WriteFPDIV32],  (instregex "VDIVS")>;
453def : InstRW<[M7WriteVFPLatOverride, WriteFPDIV64],  (instregex "VDIVD")>;
454def : InstRW<[M7WriteVFPLatOverride, WriteFPSQRT32], (instregex "VSQRTS")>;
455def : InstRW<[M7WriteVFPLatOverride, WriteFPSQRT64], (instregex "VSQRTD")>;
456def : InstRW<[M7WriteVFPLatOverride, WriteFPMUL64],
457             (instregex "V(MUL|NMUL)D")>;
458def : InstRW<[M7WriteVFPLatOverride, WriteFPALU64],
459             (instregex "V(ADD|SUB)D")>;
460
461// Multiply-accumulate.  Chained SP timing is correct; rest need overrides
462// Double-precision chained MAC stalls the pipeline behind it for 3 cycles,
463// making it appear to have 3 cycle latency for scheduling.
464
465def : InstRW<[M7WriteVFPLatOverride, WriteFPMAC64,
466              ReadFPMAC, ReadFPMUL, ReadFPMUL],
467             (instregex "V(N)?ML(A|S)D$")>;
468
469// Single-precision fused MACs look like latency 5 with advance of 2.
470
471def M7WriteVFPLatOverride5 : SchedWriteRes<[]> {
472  let Latency = 5;
473  let NumMicroOps = 0;
474}
475def M7ReadFPMAC2   : SchedReadAdvance<2>;
476
477def : InstRW<[M7WriteVFPLatOverride5, WriteFPMAC32,
478              M7ReadFPMAC2, ReadFPMUL, ReadFPMUL],
479             (instregex "VF(N)?M(A|S)S$")>;
480
481// Double-precision fused MAC stalls the pipeline behind it for 2 cycles, making
482// it appear to have 3 cycle latency for scheduling.
483
484def : InstRW<[M7WriteVFPLatOverride, WriteFPMAC64,
485              ReadFPMAC, ReadFPMUL, ReadFPMUL],
486             (instregex "VF(N)?M(A|S)D$")>;
487
488}  // SchedModel = CortexM7Model
489