llvm-project/llvm/lib/Target/RISCV/RISCVSchedSpacemitX60.td
Min-Yih Hsu e742015f43
[RISCV] Assign separate latencies for vector COPYs in SpacemitX60 scheduling model (#172556)
Currently, we assign the same scheduling info to COPY regardless of
whether it's a scalar or vector one. But this might cause vector COPY
from physical registers to schedule too closed to its consumer,
prolonging the physical register live range and running out of registers
during RA as seen in #167008 .

This patch addresses this issue by creating schedule variants for COPY
instructions of vector register classes so that they can have the same
latency as simple vector arithmetics (WriteVIALUV). It is worth noting
that we _only_ need latency in this case -- keeping processor resources
in (vector) COPYs still causes the aforementioned register shortage
issue, because these COPY might then be blocked by structural hazards
and again, got sunk further down than we want.
2025-12-18 07:04:42 -08:00

1350 lines
55 KiB
TableGen

//=- RISCVSchedSpacemitX60.td - Spacemit X60 Scheduling Defs -*- tablegen -*-=//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
//
// Scheduler model for the SpacemiT-X60 processor based on documentation of the
// C908 and experiments on real hardware (bpi-f3).
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Helpers
// Maps LMUL string to corresponding value from the Values array
// LMUL values map to array indices as follows:
// MF8 -> Values[0], MF4 -> Values[1], MF2 -> Values[2], M1 -> Values[3],
// M2 -> Values[4], M4 -> Values[5], M8 -> Values[6]
// Shorter lists are allowed, e.g., widening instructions don't work on M8
class GetLMULValue<list<int> Values, string LMUL> {
defvar Index = !cond(
!eq(LMUL, "MF8"): 0,
!eq(LMUL, "MF4"): 1,
!eq(LMUL, "MF2"): 2,
!eq(LMUL, "M1"): 3,
!eq(LMUL, "M2"): 4,
!eq(LMUL, "M4"): 5,
!eq(LMUL, "M8"): 6,
);
assert !lt(Index, !size(Values)),
"Missing LMUL value for '" # LMUL # "'. " #
"Expected at least " # !add(Index, 1) # " elements, but got " #
!size(Values) # ".";
int c = Values[Index];
}
// Returns BaseValue for LMUL values before startLMUL, Value for startLMUL,
// then doubles Value for each subsequent LMUL
// Example: ConstValueUntilLMULThenDoubleBase<"M1", 2, 4, "M8"> returns:
// MF8->2, MF4->2, MF2->2, M1->4, M2->8, M4->16, M8->32
// This is useful for modeling scheduling parameters that scale with LMUL.
class ConstValueUntilLMULThenDoubleBase<string startLMUL, int BaseValue, int Value, string currentLMUL> {
assert !le(BaseValue, Value), "BaseValue must be less-equal to Value";
defvar startPos = GetLMULValue<[0, 1, 2, 3, 4, 5, 6], startLMUL>.c;
defvar currentPos = GetLMULValue<[0, 1, 2, 3, 4, 5, 6], currentLMUL>.c;
// Calculate the difference in positions
defvar posDiff = !sub(currentPos, startPos);
// Calculate Value * (2^posDiff)
int c = !cond(
!eq(posDiff, 0) : Value,
!eq(posDiff, 1) : !mul(Value, 2),
!eq(posDiff, 2) : !mul(Value, 4),
!eq(posDiff, 3) : !mul(Value, 8),
!eq(posDiff, 4) : !mul(Value, 16),
!eq(posDiff, 5) : !mul(Value, 32),
!eq(posDiff, 6) : !mul(Value, 64),
true : BaseValue
);
}
// Same as the previous function but BaseValue == Value
class ConstValueUntilLMULThenDouble<string startLMUL, int Value, string currentLMUL> {
int c = ConstValueUntilLMULThenDoubleBase<startLMUL, Value, Value, currentLMUL>.c;
}
// Returns MF8->1, MF4->1, MF2->2, M1->4, M2->8, M4->16, M8->32
class ConstOneUntilMF4ThenDouble<string mx> {
int c = ConstValueUntilLMULThenDouble<"MF4", 1, mx>.c;
}
// Returns MF8->1, MF4->1, MF2->1, M1->2, M2->4, M4->8, M8->16
class ConstOneUntilMF2ThenDouble<string mx> {
int c = ConstValueUntilLMULThenDouble<"MF2", 1, mx>.c;
}
// Returns MF8->1, MF4->1, MF2->1, M1->1, M2->2, M4->4, M8->8
class ConstOneUntilM1ThenDouble<string mx> {
int c = ConstValueUntilLMULThenDouble<"M1", 1, mx>.c;
}
//===----------------------------------------------------------------------===//
// Latency helper classes
// Used for: arithmetic (add/sub/min/max), saturating/averaging, FP add/sub/min/max
class Get4458Latency<string mx> {
int c = GetLMULValue<[/*MF8=*/4, /*MF4=*/4, /*MF2=*/4, /*M1=*/4, /*M2=*/4, /*M4=*/5, /*M8=*/8], mx>.c;
}
// Used for: widening operations (no M8)
class Get4588Latency<string mx> {
int c = GetLMULValue<[/*MF8=*/4, /*MF4=*/4, /*MF2=*/4, /*M1=*/4, /*M2=*/5, /*M4=*/8], mx>.c;
}
// Used for: mask-producing comparisons, carry ops with mask, FP comparisons
class Get461018Latency<string mx> {
int c = GetLMULValue<[/*MF8=*/4, /*MF4=*/4, /*MF2=*/4, /*M1=*/4, /*M2=*/6, /*M4=*/10, /*M8=*/18], mx>.c;
}
// Used for: FP FMA operations, complex FP ops
class Get6678Latency<string mx> {
int c = GetLMULValue<[/*MF8=*/6, /*MF4=*/6, /*MF2=*/6, /*M1=*/6, /*M2=*/6, /*M4=*/7, /*M8=*/8], mx>.c;
}
//===----------------------------------------------------------------------===//
class SMX60IsWorstCaseMX<string mx, list<string> MxList> {
string LLMUL = LargestLMUL<MxList>.r;
bit c = !eq(mx, LLMUL);
}
class SMX60IsWorstCaseMXSEW<string mx, int sew, list<string> MxList, bit isF = 0> {
string LLMUL = LargestLMUL<MxList>.r;
int SSEW = SmallestSEW<mx, isF>.r;
bit c = !and(!eq(mx, LLMUL), !eq(sew, SSEW));
}
defvar SMX60VLEN = 256;
defvar SMX60DLEN = !div(SMX60VLEN, 2);
class SMX60GetLMulCycles<string mx> {
int c = !cond(
!eq(mx, "M1") : 1,
!eq(mx, "M2") : 2,
!eq(mx, "M4") : 4,
!eq(mx, "M8") : 8,
!eq(mx, "MF2") : 1,
!eq(mx, "MF4") : 1,
!eq(mx, "MF8") : 1
);
}
class SMX60GetVLMAX<string mx, int sew> {
defvar LMUL = SMX60GetLMulCycles<mx>.c;
int val = !cond(
!eq(mx, "MF2") : !div(!div(SMX60VLEN, 2), sew),
!eq(mx, "MF4") : !div(!div(SMX60VLEN, 4), sew),
!eq(mx, "MF8") : !div(!div(SMX60VLEN, 8), sew),
true: !div(!mul(SMX60VLEN, LMUL), sew)
);
}
// Latency for segmented loads and stores are calculated as vl * nf.
class SMX60SegmentedLdStCycles<string mx, int sew, int nf> {
int c = !mul(SMX60GetVLMAX<mx, sew>.val, nf);
}
def SpacemitX60Model : SchedMachineModel {
let IssueWidth = 2; // dual-issue
let MicroOpBufferSize = 0; // in-order
let LoadLatency = 3; // worse case: >= 3
let MispredictPenalty = 9; // nine-stage
let CompleteModel = 0;
let UnsupportedFeatures = [HasStdExtZknd, HasStdExtZkne, HasStdExtZknh,
HasStdExtZksed, HasStdExtZksh, HasStdExtZkr];
}
let SchedModel = SpacemitX60Model in {
//===----------------------------------------------------------------------===//
// Define processor resources for Spacemit-X60
// Information gathered from the C908 user manual:
let BufferSize = 0 in {
// The LSU supports dual issue for scalar store/load instructions
def SMX60_LS : ProcResource<2>;
// An IEU can decode and issue two instructions at the same time
def SMX60_IEUA : ProcResource<1>;
def SMX60_IEUB : ProcResource<1>;
def SMX60_IEU : ProcResGroup<[SMX60_IEUA, SMX60_IEUB]>;
// Although the X60 does appear to support multiple issue for at least some
// floating point instructions, this model assumes single issue as
// increasing it reduces the gains we saw in performance
def SMX60_FP : ProcResource<1>;
// Vector pipeline
// Single issue for vector store/load instructions
def SMX60_VLS : ProcResource<1>;
// The C908 user manual says: "Vector floating-point units support vector
// floating-point computation of different bits. In addition, vector integer
// units are added". Developer confirmed it's a separate VIEU
def SMX60_VIEU : ProcResource<1>;
// The C908 user manual says: "The vector execution unit is developed by
// extending the floating-point unit", so let's assume single issue for now
def SMX60_VFP : ProcResource<1>;
}
//===----------------------------------------------------------------------===//
// Branching
def : WriteRes<WriteJmp, [SMX60_IEUA]>;
def : WriteRes<WriteJal, [SMX60_IEUA]>;
def : WriteRes<WriteJalr, [SMX60_IEUA]>;
// Integer arithmetic and logic
// Latency of ALU instructions is 1, but add.uw is 2
def : WriteRes<WriteIALU32, [SMX60_IEU]>;
def : WriteRes<WriteIALU, [SMX60_IEU]>;
def : WriteRes<WriteShiftImm32, [SMX60_IEU]>;
def : WriteRes<WriteShiftImm, [SMX60_IEU]>;
def : WriteRes<WriteShiftReg32, [SMX60_IEU]>;
def : WriteRes<WriteShiftReg, [SMX60_IEU]>;
// Integer multiplication
def : WriteRes<WriteIMul32, [SMX60_IEU]> { let Latency = 3; }
// The latency of mul is 5, while in mulh, mulhsu, mulhu is 6
// Worst case latency is used
def : WriteRes<WriteIMul, [SMX60_IEU]> { let Latency = 6; }
// Integer division/remainder
// TODO: Latency set based on C908 datasheet and hasn't been
// confirmed experimentally.
let Latency = 12, ReleaseAtCycles = [12] in {
def : WriteRes<WriteIDiv32, [SMX60_IEUA]>;
def : WriteRes<WriteIRem32, [SMX60_IEUA]>;
}
let Latency = 20, ReleaseAtCycles = [20] in {
def : WriteRes<WriteIDiv, [SMX60_IEUA]>;
def : WriteRes<WriteIRem, [SMX60_IEUA]>;
}
// Bitmanip
def : WriteRes<WriteRotateImm, [SMX60_IEU]>;
def : WriteRes<WriteRotateImm32, [SMX60_IEU]>;
def : WriteRes<WriteRotateReg, [SMX60_IEU]>;
def : WriteRes<WriteRotateReg32, [SMX60_IEU]>;
def : WriteRes<WriteCLZ, [SMX60_IEU]>;
def : WriteRes<WriteCLZ32, [SMX60_IEU]>;
def : WriteRes<WriteCTZ, [SMX60_IEU]>;
def : WriteRes<WriteCTZ32, [SMX60_IEU]>;
let Latency = 2 in {
def : WriteRes<WriteCPOP, [SMX60_IEU]>;
def : WriteRes<WriteCPOP32, [SMX60_IEU]>;
}
def : WriteRes<WriteORCB, [SMX60_IEU]>;
def : WriteRes<WriteIMinMax, [SMX60_IEU]>;
def : WriteRes<WriteREV8, [SMX60_IEU]>;
let Latency = 2 in {
def : WriteRes<WriteSHXADD, [SMX60_IEU]>;
def : WriteRes<WriteSHXADD32, [SMX60_IEU]>;
def : WriteRes<WriteCLMUL, [SMX60_IEU]>;
}
// Single-bit instructions
def : WriteRes<WriteSingleBit, [SMX60_IEU]>;
def : WriteRes<WriteSingleBitImm, [SMX60_IEU]>;
def : WriteRes<WriteBEXT, [SMX60_IEU]>;
def : WriteRes<WriteBEXTI, [SMX60_IEU]>;
// Memory/Atomic memory
let Latency = 4 in {
def : WriteRes<WriteSTB, [SMX60_LS]>;
def : WriteRes<WriteSTH, [SMX60_LS]>;
def : WriteRes<WriteSTW, [SMX60_LS]>;
def : WriteRes<WriteSTD, [SMX60_LS]>;
def : WriteRes<WriteFST16, [SMX60_LS]>;
def : WriteRes<WriteFST32, [SMX60_LS]>;
def : WriteRes<WriteFST64, [SMX60_LS]>;
def : WriteRes<WriteLDB, [SMX60_LS]>;
def : WriteRes<WriteLDH, [SMX60_LS]>;
def : WriteRes<WriteLDW, [SMX60_LS]>;
def : WriteRes<WriteLDD, [SMX60_LS]>;
def : WriteRes<WriteFLD16, [SMX60_LS]>;
def : WriteRes<WriteFLD32, [SMX60_LS]>;
def : WriteRes<WriteFLD64, [SMX60_LS]>;
}
// Atomics
let Latency = 8 in {
def : WriteRes<WriteAtomicSTW, [SMX60_LS]>;
def : WriteRes<WriteAtomicSTD, [SMX60_LS]>;
def : WriteRes<WriteAtomicLDW, [SMX60_LS]>;
def : WriteRes<WriteAtomicLDD, [SMX60_LS]>;
}
let Latency = 12 in {
def : WriteRes<WriteAtomicW, [SMX60_LS]>;
def : WriteRes<WriteAtomicD, [SMX60_LS]>;
}
// Floating point units Half precision
let Latency = 4 in {
def : WriteRes<WriteFAdd16, [SMX60_FP]>;
def : WriteRes<WriteFMul16, [SMX60_FP]>;
def : WriteRes<WriteFSGNJ16, [SMX60_FP]>;
def : WriteRes<WriteFMinMax16, [SMX60_FP]>;
}
def : WriteRes<WriteFMA16, [SMX60_FP]> { let Latency = 5; }
let Latency = 12, ReleaseAtCycles = [12] in {
def : WriteRes<WriteFDiv16, [SMX60_FP]>;
def : WriteRes<WriteFSqrt16, [SMX60_FP]>;
}
// Single precision
let Latency = 4 in {
def : WriteRes<WriteFAdd32, [SMX60_FP]>;
def : WriteRes<WriteFMul32, [SMX60_FP]>;
def : WriteRes<WriteFSGNJ32, [SMX60_FP]>;
def : WriteRes<WriteFMinMax32, [SMX60_FP]>;
}
def : WriteRes<WriteFMA32, [SMX60_FP]> { let Latency = 5; }
let Latency = 15, ReleaseAtCycles = [15] in {
def : WriteRes<WriteFDiv32, [SMX60_FP]>;
def : WriteRes<WriteFSqrt32, [SMX60_FP]>;
}
// Double precision
let Latency = 5 in {
def : WriteRes<WriteFAdd64, [SMX60_FP]>;
def : WriteRes<WriteFMul64, [SMX60_FP]>;
def : WriteRes<WriteFSGNJ64, [SMX60_FP]>;
}
def : WriteRes<WriteFMinMax64, [SMX60_FP]> { let Latency = 4; }
def : WriteRes<WriteFMA64, [SMX60_FP]> { let Latency = 6; }
let Latency = 22, ReleaseAtCycles = [22] in {
def : WriteRes<WriteFDiv64, [SMX60_FP]>;
def : WriteRes<WriteFSqrt64, [SMX60_FP]>;
}
// Conversions
let Latency = 6 in {
def : WriteRes<WriteFCvtF16ToI32, [SMX60_IEU]>;
def : WriteRes<WriteFCvtF32ToI32, [SMX60_IEU]>;
def : WriteRes<WriteFCvtF32ToI64, [SMX60_IEU]>;
def : WriteRes<WriteFCvtF64ToI64, [SMX60_IEU]>;
def : WriteRes<WriteFCvtF64ToI32, [SMX60_IEU]>;
def : WriteRes<WriteFCvtF16ToI64, [SMX60_IEU]>;
}
let Latency = 4 in {
def : WriteRes<WriteFCvtI32ToF16, [SMX60_IEU]>;
def : WriteRes<WriteFCvtI32ToF32, [SMX60_IEU]>;
def : WriteRes<WriteFCvtI32ToF64, [SMX60_IEU]>;
def : WriteRes<WriteFCvtI64ToF16, [SMX60_IEU]>;
def : WriteRes<WriteFCvtI64ToF32, [SMX60_IEU]>;
def : WriteRes<WriteFCvtI64ToF64, [SMX60_IEU]>;
def : WriteRes<WriteFCvtF16ToF32, [SMX60_FP]>;
def : WriteRes<WriteFCvtF16ToF64, [SMX60_FP]>;
def : WriteRes<WriteFCvtF32ToF16, [SMX60_FP]>;
def : WriteRes<WriteFCvtF32ToF64, [SMX60_FP]>;
def : WriteRes<WriteFCvtF64ToF16, [SMX60_FP]>;
def : WriteRes<WriteFCvtF64ToF32, [SMX60_FP]>;
}
let Latency = 6 in {
def : WriteRes<WriteFClass16, [SMX60_FP]>;
def : WriteRes<WriteFClass32, [SMX60_FP]>;
def : WriteRes<WriteFClass64, [SMX60_FP]>;
def : WriteRes<WriteFCmp16, [SMX60_FP]>;
def : WriteRes<WriteFCmp32, [SMX60_FP]>;
def : WriteRes<WriteFCmp64, [SMX60_FP]>;
def : WriteRes<WriteFMovF32ToI32, [SMX60_IEU]>;
def : WriteRes<WriteFMovF16ToI16, [SMX60_IEU]>;
}
let Latency = 4 in {
def : WriteRes<WriteFMovI16ToF16, [SMX60_IEU]>;
def : WriteRes<WriteFMovF64ToI64, [SMX60_IEU]>;
def : WriteRes<WriteFMovI64ToF64, [SMX60_IEU]>;
def : WriteRes<WriteFMovI32ToF32, [SMX60_IEU]>;
}
// 6. Configuration-Setting Instructions
def : WriteRes<WriteVSETVLI, [SMX60_IEUA]>;
def : WriteRes<WriteVSETIVLI, [SMX60_IEUA]>;
def : WriteRes<WriteVSETVL, [SMX60_IEUA]>;
// 7. Vector Loads and Stores
foreach mx = SchedMxList in {
defvar IsWorstCase = SMX60IsWorstCaseMX<mx, SchedMxList>.c;
// Unit-stride loads and stores
defvar VLDELatAndOcc = ConstValueUntilLMULThenDoubleBase<"M2", 3, 4, mx>.c;
let Latency = VLDELatAndOcc, ReleaseAtCycles = [VLDELatAndOcc] in {
defm "" : LMULWriteResMX<"WriteVLDE", [SMX60_VLS], mx, IsWorstCase>;
}
defvar VSTELatAndOcc = GetLMULValue<[2, 2, 2, 3, 4, 8, 19], mx>.c;
let Latency = VSTELatAndOcc, ReleaseAtCycles = [VSTELatAndOcc] in {
defm "" : LMULWriteResMX<"WriteVSTE", [SMX60_VLS], mx, IsWorstCase>;
}
defvar VLDFFLatAndOcc = GetLMULValue<[4, 4, 4, 5, 7, 11, 19], mx>.c;
let Latency = VLDFFLatAndOcc, ReleaseAtCycles = [VLDFFLatAndOcc] in {
defm "" : LMULWriteResMX<"WriteVLDFF", [SMX60_VLS], mx, IsWorstCase>;
}
// Mask loads and stores
let ReleaseAtCycles = [2] in {
defm "" : LMULWriteResMX<"WriteVLDM", [SMX60_VLS], mx, IsWorstCase>;
}
let Latency = 2, ReleaseAtCycles = [2] in {
defm "" : LMULWriteResMX<"WriteVSTM", [SMX60_VLS], mx, IsWorstCase>;
}
// Strided and indexed loads and stores
foreach eew = [8, 16, 32, 64] in {
defvar StridedLdStLatAndOcc = SMX60GetVLMAX<mx, eew>.val;
let Latency = StridedLdStLatAndOcc, ReleaseAtCycles = [StridedLdStLatAndOcc] in {
defm "" : LMULWriteResMX<"WriteVLDS" # eew, [SMX60_VLS], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVSTS" # eew, [SMX60_VLS], mx, IsWorstCase>;
}
defvar IndexedLdStLatAndOcc = !div(SMX60GetVLMAX<mx, eew>.val, 2);
let Latency = IndexedLdStLatAndOcc, ReleaseAtCycles = [IndexedLdStLatAndOcc] in {
defm "" : LMULWriteResMX<"WriteVLDUX" # eew, [SMX60_VLS], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVLDOX" # eew, [SMX60_VLS], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVSTUX" # eew, [SMX60_VLS], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVSTOX" # eew, [SMX60_VLS], mx, IsWorstCase>;
}
}
}
// Segmented loads and stores
foreach mx = SchedMxList in {
foreach nf=2-8 in {
foreach eew = [8, 16, 32, 64] in {
defvar IsWorstCase = SMX60IsWorstCaseMX<mx, SchedMxList>.c;
defvar SegmentedLdStLatAndOcc = SMX60SegmentedLdStCycles<mx, eew, nf>.c;
let Latency = SegmentedLdStLatAndOcc, ReleaseAtCycles = [SegmentedLdStLatAndOcc] in {
// Unit-stride segmented
defm "" : LMULWriteResMX<"WriteVLSEG" # nf # "e" #eew, [SMX60_VLS], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVLSEGFF" # nf # "e" #eew, [SMX60_VLS], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVSSEG" # nf # "e" #eew, [SMX60_VLS], mx, IsWorstCase>;
// Strided/indexed segmented
defm "" : LMULWriteResMX<"WriteVLSSEG" # nf # "e" #eew, [SMX60_VLS], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVSSSEG" # nf # "e" #eew, [SMX60_VLS], mx, IsWorstCase>;
// Indexed segmented
defm "" : LMULWriteResMX<"WriteVLOXSEG" # nf # "e" #eew, [SMX60_VLS], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVLUXSEG" # nf # "e" #eew, [SMX60_VLS], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVSUXSEG" # nf # "e" #eew, [SMX60_VLS], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVSOXSEG" # nf # "e" #eew, [SMX60_VLS], mx, IsWorstCase>;
}
}
}
}
// Whole register move/load/store
foreach LMul = [1, 2, 4, 8] in {
defvar WholeRegLdStLatAndOcc = !if(!eq(LMul, 1), 3, !mul(LMul, 2));
let Latency = WholeRegLdStLatAndOcc, ReleaseAtCycles = [WholeRegLdStLatAndOcc] in {
def : WriteRes<!cast<SchedWrite>("WriteVLD" # LMul # "R"), [SMX60_VLS]>;
def : WriteRes<!cast<SchedWrite>("WriteVST" # LMul # "R"), [SMX60_VLS]>;
}
defvar VMovLatAndOcc = !if(!eq(LMul, 1), 4, !mul(LMul, 2));
let Latency = VMovLatAndOcc, ReleaseAtCycles = [VMovLatAndOcc] in {
def : WriteRes<!cast<SchedWrite>("WriteVMov" # LMul # "V"), [SMX60_VIEU]>;
}
}
// 11. Vector Integer Arithmetic Instructions
foreach mx = SchedMxList in {
defvar IsWorstCase = SMX60IsWorstCaseMX<mx, SchedMxList>.c;
let Latency = Get4458Latency<mx>.c, ReleaseAtCycles = [ConstOneUntilM1ThenDouble<mx>.c] in {
defm "" : LMULWriteResMX<"WriteVIMinMaxV", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVIMinMaxX", [SMX60_VIEU], mx, IsWorstCase>;
}
// Latency of vadd, vsub, vrsub: 4/4/5/8
// ReleaseAtCycles of vadd, vsub, vrsub: 1/2/4/8
// Latency of vand, vor, vxor: 4/4/8/16
// ReleaseAtCycles of vand, vor, vxor: 2/4/8/16
// They are grouped together, so we used the worst case 4/4/8/16 and 2/4/8/16
// TODO: use InstRW to override individual instructions' scheduling data
defvar VIALULat = ConstValueUntilLMULThenDouble<"M2", 4, mx>.c;
defvar VIALUOcc = ConstOneUntilMF2ThenDouble<mx>.c;
let Latency = VIALULat, ReleaseAtCycles = [VIALUOcc] in {
defm "" : LMULWriteResMX<"WriteVIALUV", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVIALUX", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVIALUI", [SMX60_VIEU], mx, IsWorstCase>;
}
let Latency = VIALULat in
def SMX60WriteVCOPY_ # mx : SchedWriteRes<[]>;
defvar VILogicalLat = ConstValueUntilLMULThenDouble<"M2", 4, mx>.c;
defvar VILogicalOcc = ConstValueUntilLMULThenDouble<"MF2", 1, mx>.c;
let Latency = VILogicalLat, ReleaseAtCycles = [VILogicalOcc] in {
defm "" : LMULWriteResMX<"WriteVExtV", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVIMergeV", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVIMergeX", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVIMergeI", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVIMovV", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVIMovX", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVIMovI", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVShiftV", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVShiftX", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVShiftI", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVICALUV", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVICALUX", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVICALUI", [SMX60_VIEU], mx, IsWorstCase>;
}
// Slightly increase Occ when LMUL == M8
defvar VICmpCarryOcc = GetLMULValue<[1, 1, 1, 2, 4, 8, 18], mx>.c;
let Latency = Get461018Latency<mx>.c, ReleaseAtCycles = [VICmpCarryOcc] in {
defm "" : LMULWriteResMX<"WriteVICALUMV", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVICALUMX", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVICALUMI", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVICmpV", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVICmpX", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVICmpI", [SMX60_VIEU], mx, IsWorstCase>;
}
// Latency of vmacc, vmadd, vmul, vmulh, etc.: e8/e16 = 4/4/5/8, e32 = 5,5,5,8,
// e64 = 7,8,16,32. We use the worst-case until we can split the SEW.
// TODO: change WriteVIMulV, etc to be defined with LMULSEWSchedWrites
defvar VIMulLat = ConstValueUntilLMULThenDoubleBase<"M2", 7, 8, mx>.c;
// ReleaseAtCycles for vnmsac/vnmsub is 1/1/1/1/2/5 but we use the worse case
// here since they are grouped together with vmacc/vmadd/vmul/vmulh.
defvar VIMulOcc = ConstOneUntilM1ThenDouble<mx>.c;
let Latency = VIMulLat, ReleaseAtCycles = [VIMulOcc] in {
defm "" : LMULWriteResMX<"WriteVIMulV", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVIMulX", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVIMulAddV", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVIMulAddX", [SMX60_VIEU], mx, IsWorstCase>;
}
}
// Widening
// Pattern of vwmul, vwmacc, etc: e8/e16 = 4/4/5/8, e32 = 5,5,5,8
// We use the worst-case for all.
foreach mx = SchedMxListW in {
defvar IsWorstCase = SMX60IsWorstCaseMX<mx, SchedMxListW>.c;
defvar VIWideningOcc = ConstOneUntilMF2ThenDouble<mx>.c;
let Latency = Get4588Latency<mx>.c, ReleaseAtCycles = [VIWideningOcc] in {
defm "" : LMULWriteResMX<"WriteVIWALUV", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVIWALUX", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVIWALUI", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVIWMulV", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVIWMulX", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVIWMulAddV", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVIWMulAddX", [SMX60_VIEU], mx, IsWorstCase>;
}
}
// Division and remainder operations
// Pattern of vdivu: 11/11/11/20/40/80/160
// Pattern of vdiv: 12/12/12/22/44/88/176
// Pattern of vremu: 12/12/12/22/44/88/176
// Pattern of vrem: 13/13/13/24/48/96/192
// We use for all: 12/12/12/24/48/96/192
// TODO: Create separate WriteVIRem to more closely match the latencies
foreach mx = SchedMxList in {
foreach sew = SchedSEWSet<mx>.val in {
defvar IsWorstCase = SMX60IsWorstCaseMXSEW<mx, sew, SchedMxList>.c;
// Not pipelined
defvar VIDivLatAndOcc = ConstValueUntilLMULThenDouble<"MF2", 12, mx>.c;
let Latency = VIDivLatAndOcc, ReleaseAtCycles = [VIDivLatAndOcc] in {
defm "" : LMULSEWWriteResMXSEW<"WriteVIDivV", [SMX60_VIEU], mx, sew, IsWorstCase>;
defm "" : LMULSEWWriteResMXSEW<"WriteVIDivX", [SMX60_VIEU], mx, sew, IsWorstCase>;
}
}
}
// Narrowing Shift and Clips
foreach mx = SchedMxListW in {
defvar IsWorstCase = SMX60IsWorstCaseMX<mx, SchedMxListW>.c;
defvar VNarrowingLat = ConstValueUntilLMULThenDouble<"M1", 4, mx>.c;
defvar VNarrowingOcc = ConstValueUntilLMULThenDouble<"MF4", 1, mx>.c;
let Latency = VNarrowingLat, ReleaseAtCycles = [VNarrowingOcc] in {
defm "" : LMULWriteResMX<"WriteVNShiftV", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVNShiftX", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVNShiftI", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVNClipV", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVNClipX", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVNClipI", [SMX60_VIEU], mx, IsWorstCase>;
}
}
// 12. Vector Fixed-Point Arithmetic Instructions
foreach mx = SchedMxList in {
defvar IsWorstCase = SMX60IsWorstCaseMX<mx, SchedMxList>.c;
let Latency = Get4458Latency<mx>.c, ReleaseAtCycles = [ConstOneUntilM1ThenDouble<mx>.c] in {
defm "" : LMULWriteResMX<"WriteVSALUV", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVSALUX", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVSALUI", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVAALUV", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVAALUX", [SMX60_VIEU], mx, IsWorstCase>;
}
// Latency of vsmul: e8/e16 = 4/4/5/8, e32 = 5/5/5/8, e64 = 7/8/16/32
// We use the worst-case until we can split the SEW.
defvar VSMulLat = ConstValueUntilLMULThenDoubleBase<"M2", 7, 8, mx>.c;
// Latency of vsmul: e8/e16/e32 = 1/2/4/8, e64 = 4/8/16/32
// We use the worst-case until we can split the SEW.
defvar VSMulOcc = ConstValueUntilLMULThenDoubleBase<"M1", 1, 4, mx>.c;
// TODO: change WriteVSMulV/X to be defined with LMULSEWSchedWrites
let Latency = VSMulLat, ReleaseAtCycles = [VSMulOcc] in {
defm "" : LMULWriteResMX<"WriteVSMulV", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVSMulX", [SMX60_VIEU], mx, IsWorstCase>;
}
defvar VSShiftLat = ConstValueUntilLMULThenDouble<"M2", 4, mx>.c;
defvar VSShiftOcc = ConstOneUntilMF2ThenDouble<mx>.c;
let Latency = VSShiftLat, ReleaseAtCycles = [VSShiftOcc] in {
defm "" : LMULWriteResMX<"WriteVSShiftV", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVSShiftX", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVSShiftI", [SMX60_VIEU], mx, IsWorstCase>;
}
}
// 13. Vector Floating-Point Instructions
foreach mx = SchedMxListF in {
foreach sew = SchedSEWSet<mx, isF=1>.val in {
defvar IsWorstCase = SMX60IsWorstCaseMXSEW<mx, sew, SchedMxListF, isF=1>.c;
defvar VFALULat = Get4458Latency<mx>.c;
defvar VFALUOcc = ConstOneUntilM1ThenDouble<mx>.c;
let Latency = VFALULat, ReleaseAtCycles = [VFALUOcc] in {
defm "" : LMULSEWWriteResMXSEW<"WriteVFALUV", [SMX60_VFP], mx, sew, IsWorstCase>;
defm "" : LMULSEWWriteResMXSEW<"WriteVFALUF", [SMX60_VFP], mx, sew, IsWorstCase>;
defm "" : LMULSEWWriteResMXSEW<"WriteVFMinMaxV", [SMX60_VFP], mx, sew, IsWorstCase>;
defm "" : LMULSEWWriteResMXSEW<"WriteVFMinMaxF", [SMX60_VFP], mx, sew, IsWorstCase>;
}
// Slightly increased latency for sew == 64
defvar VFMulVLat = !if(!eq(sew, 64), ConstValueUntilLMULThenDoubleBase<"M8", 5, 8, mx>.c,
Get4458Latency<mx>.c);
let Latency = VFMulVLat, ReleaseAtCycles = [ConstOneUntilM1ThenDouble<mx>.c] in {
defm "" : LMULSEWWriteResMXSEW<"WriteVFMulV", [SMX60_VFP], mx, sew, IsWorstCase>;
}
// VFMulF has the same latency as VFMulV, but slighlty lower ReleaseAtCycles
let Latency = VFMulVLat, ReleaseAtCycles = [ConstOneUntilM1ThenDouble<mx>.c] in {
defm "" : LMULSEWWriteResMXSEW<"WriteVFMulF", [SMX60_VFP], mx, sew, IsWorstCase>;
}
defvar VFSgnjLat = ConstValueUntilLMULThenDouble<"M2", 4, mx>.c;
defvar VFSgnjOcc = ConstOneUntilMF2ThenDouble<mx>.c;
let Latency = VFSgnjLat, ReleaseAtCycles = [VFSgnjOcc] in {
defm "" : LMULSEWWriteResMXSEW<"WriteVFRecpV", [SMX60_VFP], mx, sew, IsWorstCase>;
defm "" : LMULSEWWriteResMXSEW<"WriteVFSgnjV", [SMX60_VFP], mx, sew, IsWorstCase>;
defm "" : LMULSEWWriteResMXSEW<"WriteVFSgnjF", [SMX60_VFP], mx, sew, IsWorstCase>;
defm "" : LMULSEWWriteResMXSEW<"WriteVFCvtIToFV", [SMX60_VFP], mx, sew, IsWorstCase>;
}
// The following covers vfmacc, vfmsac, and their vfn* variants in the same group, but the
// ReleaseAtCycles takes one extra cycle for the vfn* variants.
// TODO: Should we split them?
// TODO: for some reason, the following cond is not working, and always use ConstValueUntilLMULThenDoubleBase<"M4", 5, 8, mx>.c
defvar VFMulAddLatency = !if(!eq(sew, 64),
Get6678Latency<mx>.c,
ConstValueUntilLMULThenDoubleBase<"M8", 5, 8, mx>.c
);
let Latency = VFMulAddLatency, ReleaseAtCycles = [ConstOneUntilM1ThenDouble<mx>.c] in {
defm "" : LMULSEWWriteResMXSEW<"WriteVFMulAddV", [SMX60_VFP], mx, sew, IsWorstCase>;
defm "" : LMULSEWWriteResMXSEW<"WriteVFMulAddF", [SMX60_VFP], mx, sew, IsWorstCase>;
}
}
}
foreach mx = SchedMxList in {
defvar IsWorstCase = SMX60IsWorstCaseMX<mx, SchedMxList>.c;
// Slightly increased ReleaseAtCycles for M8: 18
defvar VFCmpOcc = !if(!eq(mx, "M8"),
!add(ConstOneUntilMF2ThenDouble<mx>.c, 2),
ConstOneUntilMF2ThenDouble<mx>.c
);
let Latency = Get461018Latency<mx>.c, ReleaseAtCycles = [VFCmpOcc] in {
defm "" : LMULWriteResMX<"WriteVFCmpV", [SMX60_VFP], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVFCmpF", [SMX60_VFP], mx, IsWorstCase>;
}
defvar VFClassLat = ConstValueUntilLMULThenDouble<"M2", 4, mx>.c;
defvar VFClassOcc = ConstOneUntilMF2ThenDouble<mx>.c;
let Latency = VFClassLat, ReleaseAtCycles = [VFClassOcc] in {
defm "" : LMULWriteResMX<"WriteVFClassV", [SMX60_VFP], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVFMergeV", [SMX60_VFP], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVFMovV", [SMX60_VFP], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVFCvtFToIV", [SMX60_VFP], mx, IsWorstCase>;
}
}
// Widening
foreach mx = SchedMxListW in {
foreach sew = SchedSEWSet<mx, isF=0, isWidening=1>.val in {
defvar IsWorstCase = SMX60IsWorstCaseMXSEW<mx, sew, SchedMxListW>.c;
defvar VFWCvtILat = ConstValueUntilLMULThenDouble<"M1", 4, mx>.c;
defvar VFWCvtIOcc = ConstOneUntilMF4ThenDouble<mx>.c;
let Latency = VFWCvtILat, ReleaseAtCycles = [VFWCvtIOcc] in {
defm "" : LMULSEWWriteResMXSEW<"WriteVFWCvtIToFV", [SMX60_VFP], mx, sew, IsWorstCase>;
}
}
}
foreach mx = SchedMxListFW in {
defvar IsWorstCase = SMX60IsWorstCaseMX<mx, SchedMxListFW>.c;
defvar VFWCvtFToIVLat = ConstValueUntilLMULThenDouble<"M1", 4, mx>.c;
defvar VFWCvtFToIVOcc = ConstOneUntilMF4ThenDouble<mx>.c;
let Latency = VFWCvtFToIVLat, ReleaseAtCycles = [VFWCvtFToIVOcc] in {
defm "" : LMULWriteResMX<"WriteVFWCvtFToIV", [SMX60_VFP], mx, IsWorstCase>;
}
}
foreach mx = SchedMxListFW in {
foreach sew = SchedSEWSet<mx, isF=1, isWidening=1>.val in {
defvar IsWorstCase = SMX60IsWorstCaseMXSEW<mx, sew, SchedMxListFW, isF=1>.c;
defvar VFWCvtFToFVLat = ConstValueUntilLMULThenDouble<"M1", 4, mx>.c;
defvar VFWCvtFToFVOcc = ConstOneUntilMF4ThenDouble<mx>.c;
let Latency = VFWCvtFToFVLat, ReleaseAtCycles = [VFWCvtFToFVOcc] in {
defm "" : LMULSEWWriteResMXSEW<"WriteVFWCvtFToFV", [SMX60_VFP], mx, sew, IsWorstCase>;
}
// Latency for vfwsub/vfwadd.vv, vfwsub/vfwadd.vf: 4/4/4/5/8
// ReleaseAtCycles for vfwsub/vfwadd.vv, vfwsub/vfwadd.vf: 1/1/2/4/8
// Latency for vfwsub/vfwadd.wv, vfwsub/vfwadd.wf: 5/5/5/9/17
// ReleaseAtCycles for vfwsub/vfwadd.wv, vfwsub/vfwadd.wf: 1/2/4/8/17
// We use the worst-case
defvar VFWALULat = !add(ConstValueUntilLMULThenDouble<"M1", 4, mx>.c, 1); // 5/5/9/17
defvar VFWALUOcc = !if(!eq(mx, "M4"),
!add(ConstOneUntilMF4ThenDouble<mx>.c, 1), // 2/4/8/17
ConstOneUntilMF4ThenDouble<mx>.c
);
// TODO: Split .wf/.wv variants into separate scheduling classes
let Latency = VFWALULat, ReleaseAtCycles = [VFWALUOcc] in {
defm "" : LMULSEWWriteResMXSEW<"WriteVFWALUV", [SMX60_VFP], mx, sew, IsWorstCase>;
defm "" : LMULSEWWriteResMXSEW<"WriteVFWALUF", [SMX60_VFP], mx, sew, IsWorstCase>;
}
let Latency = Get4588Latency<mx>.c, ReleaseAtCycles = [ConstOneUntilMF2ThenDouble<mx>.c] in {
defm "" : LMULSEWWriteResMXSEW<"WriteVFWMulF", [SMX60_VFP], mx, sew, IsWorstCase>;
}
// Slightly increased latency for SEW == 32
defvar VFWMullOcc = !if(!eq(sew, 32),
GetLMULValue<[1, 1, 1, 3, 5, 9, 18], mx>.c,
ConstOneUntilMF2ThenDouble<mx>.c
);
defvar VFWMulVLat = ConstValueUntilLMULThenDoubleBase<"M8", 5, 8, mx>.c;
let Latency = VFWMulVLat, ReleaseAtCycles = [VFWMullOcc] in {
defm "" : LMULSEWWriteResMXSEW<"WriteVFWMulV", [SMX60_VFP], mx, sew, IsWorstCase>;
}
// Latency for vfwmacc, vfwnmacc, etc: e16 = 5/5/5/8; e32 = 6/6/7/8
defvar VFWMulAddVLat = !if(!eq(sew, 16),
ConstValueUntilLMULThenDoubleBase<"M4", 5, 8, mx>.c,
Get6678Latency<mx>.c
);
let Latency = VFWMulAddVLat, ReleaseAtCycles = [ConstOneUntilMF2ThenDouble<mx>.c] in {
defm "" : LMULSEWWriteResMXSEW<"WriteVFWMulAddV", [SMX60_VFP], mx, sew, IsWorstCase>;
defm "" : LMULSEWWriteResMXSEW<"WriteVFWMulAddF", [SMX60_VFP], mx, sew, IsWorstCase>;
}
}
}
// Narrowing
foreach mx = SchedMxListW in {
defvar IsWorstCase = SMX60IsWorstCaseMX<mx, SchedMxListW>.c;
defvar VFNCvtFToIVLat = ConstValueUntilLMULThenDouble<"M1", 4, mx>.c;
defvar VFNCvtFToIVOcc = ConstOneUntilMF4ThenDouble<mx>.c;
let Latency = VFNCvtFToIVLat, ReleaseAtCycles = [VFNCvtFToIVOcc] in {
defm "" : LMULWriteResMX<"WriteVFNCvtFToIV", [SMX60_VFP], mx, IsWorstCase>;
}
}
foreach mx = SchedMxListFW in {
foreach sew = SchedSEWSet<mx, isF=1, isWidening=1>.val in {
defvar IsWorstCase = SMX60IsWorstCaseMXSEW<mx, sew, SchedMxListFW, isF=1>.c;
defvar VFNCvtToFVLat = ConstValueUntilLMULThenDouble<"M1", 4, mx>.c;
defvar VFNCvtToFVOcc = ConstOneUntilMF4ThenDouble<mx>.c;
let Latency = VFNCvtToFVLat, ReleaseAtCycles = [VFNCvtToFVOcc] in {
defm "" : LMULSEWWriteResMXSEW<"WriteVFNCvtIToFV", [SMX60_VFP], mx, sew, IsWorstCase>;
defm "" : LMULSEWWriteResMXSEW<"WriteVFNCvtFToFV", [SMX60_VFP], mx, sew, IsWorstCase>;
}
}
}
// Vector Floating-Point Division and Square Root
foreach mx = SchedMxListF in {
foreach sew = SchedSEWSet<mx, 1>.val in {
defvar IsWorstCase = SMX60IsWorstCaseMXSEW<mx, sew, SchedMxListF, 1>.c;
// Compute ReleaseAtCycles based on SEW
// Latency for vfdiv.vf: e16/e32 = 12/24/48/96; e64 = 18/36/72/144
// Latency for vfrdiv.vf: e16/e32 = 12/24/48/96; e64 = 40/80/160/320
// We use the worst-case, vfdiv.vf is penalized in e64
// TODO: split vfdiv.vf and vfrdiv.vf into separate scheduling classes
defvar VFDivFFactor = !if(!eq(sew, 64), 40, 12);
defvar VFDivFLatAndOcc = !mul(ConstOneUntilM1ThenDouble<mx>.c, VFDivFFactor);
let Latency = VFDivFLatAndOcc, ReleaseAtCycles = [VFDivFLatAndOcc] in {
defm "" : LMULSEWWriteResMXSEW<"WriteVFDivF", [SMX60_VFP], mx, sew, IsWorstCase>;
}
defvar VFDivVFactor = !if(!eq(sew, 16), 12, 40);
defvar VFDivVLatAndOcc = !mul(ConstOneUntilM1ThenDouble<mx>.c, VFDivVFactor);
let Latency = VFDivVLatAndOcc, ReleaseAtCycles = [VFDivVLatAndOcc] in {
defm "" : LMULSEWWriteResMXSEW<"WriteVFDivV", [SMX60_VFP], mx, sew, IsWorstCase>;
}
}
}
// Pattern for vfsqrt.v: e16 = 18/36/72/144; e32 = 38/76/152/304; e64 = 40/80/160/320
foreach mx = SchedMxListF in {
foreach sew = SchedSEWSet<mx, 1>.val in {
defvar IsWorstCase = SMX60IsWorstCaseMXSEW<mx, sew, SchedMxListF, 1>.c;
defvar VFSqrtVFactor = !if(!eq(sew, 16), 12, 40);
defvar VFSqrtVLatAndOcc = !mul(ConstOneUntilM1ThenDouble<mx>.c, VFSqrtVFactor);
let Latency = VFSqrtVLatAndOcc, ReleaseAtCycles = [VFSqrtVLatAndOcc] in {
defm "" : LMULSEWWriteResMXSEW<"WriteVFSqrtV", [SMX60_VFP], mx, sew, IsWorstCase>;
}
}
}
// 14. Vector Reduction Operations
foreach mx = SchedMxList in {
foreach sew = SchedSEWSet<mx>.val in {
defvar IsWorstCase = SMX60IsWorstCaseMXSEW<mx, sew, SchedMxList>.c;
defvar VIRedLat = GetLMULValue<[5, 5, 5, 7, 11, 19, 35], mx>.c;
defvar VIRedOcc = GetLMULValue<[1, 1, 2, 2, 4, 10, 35], mx>.c;
let Latency = VIRedLat, ReleaseAtCycles = [VIRedOcc] in {
defm "" : LMULSEWWriteResMXSEW<"WriteVIRedMinMaxV_From", [SMX60_VIEU], mx, sew, IsWorstCase>;
// Pattern for vredsum: 5/5/5/7/11/19/35
// Pattern for vredand, vredor, vredxor: 4/4/4/6/10/18/34
// They are grouped together, so we use the worst-case vredsum latency.
// TODO: split vredand, vredor, vredxor into separate scheduling classe.
defm "" : LMULSEWWriteResMXSEW<"WriteVIRedV_From", [SMX60_VIEU], mx, sew, IsWorstCase>;
}
}
}
foreach mx = SchedMxListWRed in {
foreach sew = SchedSEWSet<mx, 0, 1>.val in {
defvar IsWorstCase = SMX60IsWorstCaseMXSEW<mx, sew, SchedMxListWRed>.c;
defvar VIRedLat = GetLMULValue<[5, 5, 5, 7, 11, 19, 35], mx>.c;
defvar VIRedOcc = GetLMULValue<[1, 1, 2, 2, 4, 10, 35], mx>.c;
let Latency = VIRedLat, ReleaseAtCycles = [VIRedOcc] in {
defm "" : LMULSEWWriteResMXSEW<"WriteVIWRedV_From", [SMX60_VIEU], mx, sew, IsWorstCase>;
}
}
}
foreach mx = SchedMxListF in {
foreach sew = SchedSEWSet<mx, 1>.val in {
defvar IsWorstCase = SMX60IsWorstCaseMXSEW<mx, sew, SchedMxListF, 1>.c;
// Latency for vfredmax.vs, vfredmin.vs: 12/12/15/21/33/57
// Latency for vfredusum.vs is slightly lower for e16/e32
// We use the worst-case
defvar VFRedLat = GetLMULValue<[12, 12, 12, 15, 21, 33, 57], mx>.c;
defvar VFRedOcc = GetLMULValue<[8, 8, 8, 8, 14, 20, 57], mx>.c;
let Latency = VFRedLat, ReleaseAtCycles = [VFRedOcc] in {
defm "" : LMULSEWWriteResMXSEW<"WriteVFRedV_From", [SMX60_VFP], mx, sew, IsWorstCase>;
defm "" : LMULSEWWriteResMXSEW<"WriteVFRedMinMaxV_From", [SMX60_VFP], mx, sew, IsWorstCase>;
}
}
}
foreach mx = SchedMxListF in {
foreach sew = SchedSEWSet<mx, 1>.val in {
defvar IsWorstCase = SMX60IsWorstCaseMXSEW<mx, sew, SchedMxListF, 1>.c;
// Compute latency based on SEW
defvar VFRedOV_FromLat = !cond(
!eq(sew, 16) : ConstValueUntilLMULThenDouble<"MF4", 12, mx>.c,
!eq(sew, 32) : ConstValueUntilLMULThenDouble<"MF2", 12, mx>.c,
!eq(sew, 64) : ConstValueUntilLMULThenDouble<"M1", 12, mx>.c
);
defvar VFRedOV_FromOcc = !cond(
!eq(sew, 16) : GetLMULValue<[8, 8, 20, 24, 48, 96, 384], mx>.c,
!eq(sew, 32) : GetLMULValue<[8, 8, 8, 12, 24, 48, 192], mx>.c,
!eq(sew, 64) : GetLMULValue<[6, 6, 6, 6, 12, 24, 96], mx>.c
);
let Latency = VFRedOV_FromLat, ReleaseAtCycles = [VFRedOV_FromOcc] in {
defm "" : LMULSEWWriteResMXSEW<"WriteVFRedOV_From", [SMX60_VFP], mx, sew, IsWorstCase>;
}
}
}
foreach mx = SchedMxListFWRed in {
foreach sew = SchedSEWSet<mx, 1, 1>.val in {
defvar IsWorstCase = SMX60IsWorstCaseMXSEW<mx, sew, SchedMxListFWRed, 1>.c;
defvar VFRedOVLat = !cond(
!eq(sew, 16) : ConstValueUntilLMULThenDouble<"MF4", 16, mx>.c,
!eq(sew, 32) : ConstValueUntilLMULThenDouble<"MF2", 16, mx>.c,
);
defvar VFRedOVOcc = !cond(
!eq(sew, 16) : GetLMULValue<[11, 11, 27, 32, 64, 128, 512], mx>.c,
!eq(sew, 32) : GetLMULValue<[11, 11, 11, 16, 32, 64, 256], mx>.c,
);
let Latency = VFRedOVLat, ReleaseAtCycles = [VFRedOVOcc] in {
defm "" : LMULSEWWriteResMXSEW<"WriteVFWRedV_From", [SMX60_VFP], mx, sew, IsWorstCase>;
defm "" : LMULSEWWriteResMXSEW<"WriteVFWRedOV_From", [SMX60_VFP], mx, sew, IsWorstCase>;
}
}
}
// 15. Vector Mask Instructions
foreach mx = SchedMxList in {
defvar IsWorstCase = SMX60IsWorstCaseMX<mx, SchedMxList>.c;
let Latency = 4 in {
defm "" : LMULWriteResMX<"WriteVMALUV", [SMX60_VIEU], mx, IsWorstCase>;
}
let Latency = 4, ReleaseAtCycles = [ConstValueUntilLMULThenDouble<"M2", 1, mx>.c] in {
defm "" : LMULWriteResMX<"WriteVMSFSV", [SMX60_VIEU], mx, IsWorstCase>;
}
let Latency = 6, ReleaseAtCycles = [2] in {
defm "" : LMULWriteResMX<"WriteVMPopV", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVMFFSV", [SMX60_VIEU], mx, IsWorstCase>;
}
defvar VIotaLat = ConstValueUntilLMULThenDouble<"M2", 4, mx>.c;
defvar VIotaOcc = ConstOneUntilMF2ThenDouble<mx>.c;
let Latency = VIotaLat, ReleaseAtCycles = [VIotaOcc] in {
defm "" : LMULWriteResMX<"WriteVIotaV", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVIdxV", [SMX60_VIEU], mx, IsWorstCase>;
}
}
// 16. Vector Permutation Instructions
// Slide
foreach mx = SchedMxList in {
defvar IsWorstCase = SMX60IsWorstCaseMX<mx, SchedMxList>.c;
// Latency for slide up: 4/4/8/16, ReleaseAtCycles is 2/4/8/16
defvar VSlideUpLat = ConstValueUntilLMULThenDouble<"M2", 4, mx>.c;
defvar VSlideUpOcc = ConstOneUntilMF2ThenDouble<mx>.c;
let Latency = VSlideUpLat, ReleaseAtCycles =[VSlideUpOcc] in {
defm "" : LMULWriteResMX<"WriteVSlideUpX", [SMX60_VIEU], mx, IsWorstCase>;
}
// Latency for slide down: 4/5/9/17, ReleaseAtCycles is 3/5/9/17
defvar VSlideDownLat = GetLMULValue<[4, 4, 4, 4, 5, 9, 17], mx>.c;
defvar VSlideDownOcc = GetLMULValue<[1, 1, 1, 3, 5, 9, 17], mx>.c;
let Latency = VSlideDownLat, ReleaseAtCycles =[VSlideDownOcc] in {
defm "" : LMULWriteResMX<"WriteVSlideDownX", [SMX60_VIEU], mx, IsWorstCase>;
}
// The following group slide up and down together, so we use the worst-case
// (slide down) for all.
let Latency = VSlideDownLat, ReleaseAtCycles =[VSlideDownOcc] in {
defm "" : LMULWriteResMX<"WriteVSlideI", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVISlide1X", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVFSlide1F", [SMX60_VFP], mx, IsWorstCase>;
}
}
// ReleaseAtCycles is 2/2/2/2/2/3/6, but we can't set based on MX for now
// TODO: Split this into separate WriteRes for each MX
let Latency = 6, ReleaseAtCycles = [6] in {
def : WriteRes<WriteVMovXS, [SMX60_VIEU]>;
}
// ReleaseAtCycles is 1/1/1/1/1/2/4, but we can't set based on MX for now
// TODO: Split this into separate WriteRes for each MX
let Latency = 4, ReleaseAtCycles = [4] in {
def : WriteRes<WriteVMovSX, [SMX60_VIEU]>;
def : WriteRes<WriteVMovFS, [SMX60_VIEU]>;
def : WriteRes<WriteVMovSF, [SMX60_VIEU]>;
}
// Integer LMUL Gather and Compress
foreach mx = SchedMxList in {
defvar IsWorstCase = SMX60IsWorstCaseMX<mx, SchedMxList>.c;
defvar VRGatherLat = ConstValueUntilLMULThenDouble<"M2", 4, mx>.c;
let Latency = VRGatherLat, ReleaseAtCycles = [ConstOneUntilMF2ThenDouble<mx>.c] in {
defm "" : LMULWriteResMX<"WriteVRGatherVX", [SMX60_VIEU], mx, IsWorstCase>;
defm "" : LMULWriteResMX<"WriteVRGatherVI", [SMX60_VIEU], mx, IsWorstCase>;
}
foreach sew = SchedSEWSet<mx>.val in {
defvar IsWorstCaseSEW = SMX60IsWorstCaseMXSEW<mx, sew, SchedMxList>.c;
defvar VRGatherVVLat = GetLMULValue<[4, 4, 4, 4, 16, 64, 256], mx>.c;
defvar VRGatherVVOcc = GetLMULValue<[1, 1, 1, 4, 16, 64, 256], mx>.c;
let Latency = VRGatherVVLat, ReleaseAtCycles = [VRGatherVVOcc] in {
defm "" : LMULSEWWriteResMXSEW<"WriteVRGatherVV", [SMX60_VIEU], mx, sew, IsWorstCaseSEW>;
}
// For sew == 8, latency is half of the other cases, except for the fractional LMULs (const 4 cycles)
defvar VRGatherEI16Lat = !if(!eq(sew, 8),
GetLMULValue<[4, 4, 4, 8, 32, 128, 256], mx>.c,
GetLMULValue<[4, 4, 4, 4, 16, 64, 256], mx>.c);
defvar VRGatherEI16Occ = !if(!eq(sew, 8),
GetLMULValue<[1, 1, 2, 8, 32, 128, 256], mx>.c,
GetLMULValue<[1, 1, 1, 4, 16, 64, 256], mx>.c);
let Latency = VRGatherEI16Lat, ReleaseAtCycles = [VRGatherEI16Occ] in {
defm "" : LMULSEWWriteResMXSEW<"WriteVRGatherEI16VV", [SMX60_VIEU], mx, sew, IsWorstCaseSEW>;
}
defvar VCompressVLat = GetLMULValue<[4, 4, 4, 4, 10, 36, 136], mx>.c;
defvar VCompressVOcc = GetLMULValue<[1, 1, 1, 3, 10, 36, 136], mx>.c;
let Latency = VCompressVLat, ReleaseAtCycles = [VCompressVOcc] in {
defm "" : LMULSEWWriteResMXSEW<"WriteVCompressV", [SMX60_VIEU], mx, sew, IsWorstCaseSEW>;
}
}
}
// Others
def : WriteRes<WriteCSR, [SMX60_IEU]>;
def : WriteRes<WriteNop, [SMX60_IEU]>;
def : WriteRes<WriteRdVLENB, [SMX60_IEUA]>;
// Assign scheduling info to COPY instructions.
// Note: We try NOT to assign ProcResource but only latency to vector COPY because
// those resources might prevent those COPYs from showing up to the scheulder
// until it's too late.
// Specifically, for a given COPY of live-in (physical) register, ideally we want it
// to be visible to the top available queue as early as possible so that it can be scheduled
// at the beginning of the function. Assigning resource to vector COPYs might risk
// creating structural hazard that prevents those COPYs from even entering the available
// queue and as a consequence, sinking those COPYs.
// I see little difference on assigning ProcResource to scalar COPY or not, so I'm still
// assigning WriteIALU to it.
def SMX60CopySchedWriteVariant : SchedWriteVariant<[
SchedVar<SchedPredicate<[{ TII->isVRegCopy(MI, /*LMUL=*/1) }]>, [SMX60WriteVCOPY_M1]>,
SchedVar<SchedPredicate<[{ TII->isVRegCopy(MI, /*LMUL=*/2) }]>, [SMX60WriteVCOPY_M2]>,
SchedVar<SchedPredicate<[{ TII->isVRegCopy(MI, /*LMUL=*/4) }]>, [SMX60WriteVCOPY_M4]>,
SchedVar<SchedPredicate<[{ TII->isVRegCopy(MI, /*LMUL=*/8) }]>, [SMX60WriteVCOPY_M8]>,
SchedVar<NoSchedPred, [WriteIALU]>
]>;
def : InstRW<[SMX60CopySchedWriteVariant], (instrs COPY)>;
//===----------------------------------------------------------------------===//
// Bypass and advance
def : ReadAdvance<ReadJmp, 0>;
def : ReadAdvance<ReadJalr, 0>;
def : ReadAdvance<ReadCSR, 0>;
def : ReadAdvance<ReadStoreData, 0>;
def : ReadAdvance<ReadMemBase, 0>;
def : ReadAdvance<ReadIALU, 0>;
def : ReadAdvance<ReadIALU32, 0>;
def : ReadAdvance<ReadShiftImm, 0>;
def : ReadAdvance<ReadShiftImm32, 0>;
def : ReadAdvance<ReadShiftReg, 0>;
def : ReadAdvance<ReadShiftReg32, 0>;
def : ReadAdvance<ReadIDiv, 0>;
def : ReadAdvance<ReadIDiv32, 0>;
def : ReadAdvance<ReadIRem, 0>;
def : ReadAdvance<ReadIRem32, 0>;
def : ReadAdvance<ReadIMul, 0>;
def : ReadAdvance<ReadIMul32, 0>;
def : ReadAdvance<ReadAtomicWA, 0>;
def : ReadAdvance<ReadAtomicWD, 0>;
def : ReadAdvance<ReadAtomicDA, 0>;
def : ReadAdvance<ReadAtomicDD, 0>;
def : ReadAdvance<ReadAtomicLDW, 0>;
def : ReadAdvance<ReadAtomicLDD, 0>;
def : ReadAdvance<ReadAtomicSTW, 0>;
def : ReadAdvance<ReadAtomicSTD, 0>;
def : ReadAdvance<ReadFStoreData, 0>;
def : ReadAdvance<ReadFMemBase, 0>;
def : ReadAdvance<ReadFAdd16, 0>;
def : ReadAdvance<ReadFAdd32, 0>;
def : ReadAdvance<ReadFAdd64, 0>;
def : ReadAdvance<ReadFMul16, 0>;
def : ReadAdvance<ReadFMA16, 0>;
def : ReadAdvance<ReadFMA16Addend, 0>;
def : ReadAdvance<ReadFMul32, 0>;
def : ReadAdvance<ReadFMul64, 0>;
def : ReadAdvance<ReadFMA32, 0>;
def : ReadAdvance<ReadFMA32Addend, 0>;
def : ReadAdvance<ReadFMA64, 0>;
def : ReadAdvance<ReadFMA64Addend, 0>;
def : ReadAdvance<ReadFDiv16, 0>;
def : ReadAdvance<ReadFDiv32, 0>;
def : ReadAdvance<ReadFDiv64, 0>;
def : ReadAdvance<ReadFSqrt16, 0>;
def : ReadAdvance<ReadFSqrt32, 0>;
def : ReadAdvance<ReadFSqrt64, 0>;
def : ReadAdvance<ReadFCmp16, 0>;
def : ReadAdvance<ReadFCmp32, 0>;
def : ReadAdvance<ReadFCmp64, 0>;
def : ReadAdvance<ReadFSGNJ16, 0>;
def : ReadAdvance<ReadFSGNJ32, 0>;
def : ReadAdvance<ReadFSGNJ64, 0>;
def : ReadAdvance<ReadFMinMax16, 0>;
def : ReadAdvance<ReadFMinMax32, 0>;
def : ReadAdvance<ReadFMinMax64, 0>;
def : ReadAdvance<ReadFCvtF16ToI32, 0>;
def : ReadAdvance<ReadFCvtF16ToI64, 0>;
def : ReadAdvance<ReadFCvtF32ToI32, 0>;
def : ReadAdvance<ReadFCvtF32ToI64, 0>;
def : ReadAdvance<ReadFCvtF64ToI32, 0>;
def : ReadAdvance<ReadFCvtF64ToI64, 0>;
def : ReadAdvance<ReadFCvtI32ToF16, 0>;
def : ReadAdvance<ReadFCvtI32ToF32, 0>;
def : ReadAdvance<ReadFCvtI32ToF64, 0>;
def : ReadAdvance<ReadFCvtI64ToF16, 0>;
def : ReadAdvance<ReadFCvtI64ToF32, 0>;
def : ReadAdvance<ReadFCvtI64ToF64, 0>;
def : ReadAdvance<ReadFCvtF32ToF64, 0>;
def : ReadAdvance<ReadFCvtF64ToF32, 0>;
def : ReadAdvance<ReadFCvtF16ToF32, 0>;
def : ReadAdvance<ReadFCvtF32ToF16, 0>;
def : ReadAdvance<ReadFCvtF16ToF64, 0>;
def : ReadAdvance<ReadFCvtF64ToF16, 0>;
def : ReadAdvance<ReadFMovF16ToI16, 0>;
def : ReadAdvance<ReadFMovI16ToF16, 0>;
def : ReadAdvance<ReadFMovF32ToI32, 0>;
def : ReadAdvance<ReadFMovI32ToF32, 0>;
def : ReadAdvance<ReadFMovF64ToI64, 0>;
def : ReadAdvance<ReadFMovI64ToF64, 0>;
def : ReadAdvance<ReadFClass16, 0>;
def : ReadAdvance<ReadFClass32, 0>;
def : ReadAdvance<ReadFClass64, 0>;
// Bitmanip
def : ReadAdvance<ReadRotateImm, 0>;
def : ReadAdvance<ReadRotateImm32, 0>;
def : ReadAdvance<ReadRotateReg, 0>;
def : ReadAdvance<ReadRotateReg32, 0>;
def : ReadAdvance<ReadCLZ, 0>;
def : ReadAdvance<ReadCLZ32, 0>;
def : ReadAdvance<ReadCTZ, 0>;
def : ReadAdvance<ReadCTZ32, 0>;
def : ReadAdvance<ReadCPOP, 0>;
def : ReadAdvance<ReadCPOP32, 0>;
def : ReadAdvance<ReadORCB, 0>;
def : ReadAdvance<ReadIMinMax, 0>;
def : ReadAdvance<ReadREV8, 0>;
def : ReadAdvance<ReadSHXADD, 0>;
def : ReadAdvance<ReadSHXADD32, 0>;
def : ReadAdvance<ReadCLMUL, 0>;
// Single-bit instructions
def : ReadAdvance<ReadSingleBit, 0>;
def : ReadAdvance<ReadSingleBitImm, 0>;
// 6. Configuration-Setting Instructions
def : ReadAdvance<ReadVSETVLI, 0>;
def : ReadAdvance<ReadVSETVL, 0>;
// 7. Vector Loads and Stores
def : ReadAdvance<ReadVLDX, 0>;
def : ReadAdvance<ReadVSTX, 0>;
defm "" : LMULReadAdvance<"ReadVSTEV", 0>;
defm "" : LMULReadAdvance<"ReadVSTM", 0>;
def : ReadAdvance<ReadVLDSX, 0>;
def : ReadAdvance<ReadVSTSX, 0>;
defm "" : LMULReadAdvance<"ReadVSTS8V", 0>;
defm "" : LMULReadAdvance<"ReadVSTS16V", 0>;
defm "" : LMULReadAdvance<"ReadVSTS32V", 0>;
defm "" : LMULReadAdvance<"ReadVSTS64V", 0>;
defm "" : LMULReadAdvance<"ReadVLDUXV", 0>;
defm "" : LMULReadAdvance<"ReadVLDOXV", 0>;
defm "" : LMULReadAdvance<"ReadVSTUX8", 0>;
defm "" : LMULReadAdvance<"ReadVSTUX16", 0>;
defm "" : LMULReadAdvance<"ReadVSTUX32", 0>;
defm "" : LMULReadAdvance<"ReadVSTUX64", 0>;
defm "" : LMULReadAdvance<"ReadVSTUXV", 0>;
defm "" : LMULReadAdvance<"ReadVSTUX8V", 0>;
defm "" : LMULReadAdvance<"ReadVSTUX16V", 0>;
defm "" : LMULReadAdvance<"ReadVSTUX32V", 0>;
defm "" : LMULReadAdvance<"ReadVSTUX64V", 0>;
defm "" : LMULReadAdvance<"ReadVSTOX8", 0>;
defm "" : LMULReadAdvance<"ReadVSTOX16", 0>;
defm "" : LMULReadAdvance<"ReadVSTOX32", 0>;
defm "" : LMULReadAdvance<"ReadVSTOX64", 0>;
defm "" : LMULReadAdvance<"ReadVSTOXV", 0>;
defm "" : LMULReadAdvance<"ReadVSTOX8V", 0>;
defm "" : LMULReadAdvance<"ReadVSTOX16V", 0>;
defm "" : LMULReadAdvance<"ReadVSTOX32V", 0>;
defm "" : LMULReadAdvance<"ReadVSTOX64V", 0>;
// LMUL Aware
def : ReadAdvance<ReadVST1R, 0>;
def : ReadAdvance<ReadVST2R, 0>;
def : ReadAdvance<ReadVST4R, 0>;
def : ReadAdvance<ReadVST8R, 0>;
// 11. Vector Integer Arithmetic Instructions
defm : LMULReadAdvance<"ReadVIALUV", 0>;
defm : LMULReadAdvance<"ReadVIALUX", 0>;
defm : LMULReadAdvanceW<"ReadVIWALUV", 0>;
defm : LMULReadAdvanceW<"ReadVIWALUX", 0>;
defm : LMULReadAdvance<"ReadVExtV", 0>;
defm : LMULReadAdvance<"ReadVICALUV", 0>;
defm : LMULReadAdvance<"ReadVICALUX", 0>;
defm : LMULReadAdvance<"ReadVShiftV", 0>;
defm : LMULReadAdvance<"ReadVShiftX", 0>;
defm : LMULReadAdvanceW<"ReadVNShiftV", 0>;
defm : LMULReadAdvanceW<"ReadVNShiftX", 0>;
defm : LMULReadAdvance<"ReadVICmpV", 0>;
defm : LMULReadAdvance<"ReadVICmpX", 0>;
defm : LMULReadAdvance<"ReadVIMinMaxV", 0>;
defm : LMULReadAdvance<"ReadVIMinMaxX", 0>;
defm : LMULReadAdvance<"ReadVIMulV", 0>;
defm : LMULReadAdvance<"ReadVIMulX", 0>;
defm : LMULSEWReadAdvance<"ReadVIDivV", 0>;
defm : LMULSEWReadAdvance<"ReadVIDivX", 0>;
defm : LMULReadAdvanceW<"ReadVIWMulV", 0>;
defm : LMULReadAdvanceW<"ReadVIWMulX", 0>;
defm : LMULReadAdvance<"ReadVIMulAddV", 0>;
defm : LMULReadAdvance<"ReadVIMulAddX", 0>;
defm : LMULReadAdvanceW<"ReadVIWMulAddV", 0>;
defm : LMULReadAdvanceW<"ReadVIWMulAddX", 0>;
defm : LMULReadAdvance<"ReadVIMergeV", 0>;
defm : LMULReadAdvance<"ReadVIMergeX", 0>;
defm : LMULReadAdvance<"ReadVIMovV", 0>;
defm : LMULReadAdvance<"ReadVIMovX", 0>;
// 12. Vector Fixed-Point Arithmetic Instructions
defm "" : LMULReadAdvance<"ReadVSALUV", 0>;
defm "" : LMULReadAdvance<"ReadVSALUX", 0>;
defm "" : LMULReadAdvance<"ReadVAALUV", 0>;
defm "" : LMULReadAdvance<"ReadVAALUX", 0>;
defm "" : LMULReadAdvance<"ReadVSMulV", 0>;
defm "" : LMULReadAdvance<"ReadVSMulX", 0>;
defm "" : LMULReadAdvance<"ReadVSShiftV", 0>;
defm "" : LMULReadAdvance<"ReadVSShiftX", 0>;
defm "" : LMULReadAdvanceW<"ReadVNClipV", 0>;
defm "" : LMULReadAdvanceW<"ReadVNClipX", 0>;
// 13. Vector Floating-Point Instructions
defm "" : LMULSEWReadAdvanceF<"ReadVFALUV", 0>;
defm "" : LMULSEWReadAdvanceF<"ReadVFALUF", 0>;
defm "" : LMULSEWReadAdvanceFW<"ReadVFWALUV", 0>;
defm "" : LMULSEWReadAdvanceFW<"ReadVFWALUF", 0>;
defm "" : LMULSEWReadAdvanceF<"ReadVFMulV", 0>;
defm "" : LMULSEWReadAdvanceF<"ReadVFMulF", 0>;
defm "" : LMULSEWReadAdvanceF<"ReadVFDivV", 0>;
defm "" : LMULSEWReadAdvanceF<"ReadVFDivF", 0>;
defm "" : LMULSEWReadAdvanceFW<"ReadVFWMulV", 0>;
defm "" : LMULSEWReadAdvanceFW<"ReadVFWMulF", 0>;
defm "" : LMULSEWReadAdvanceF<"ReadVFMulAddV", 0>;
defm "" : LMULSEWReadAdvanceF<"ReadVFMulAddF", 0>;
defm "" : LMULSEWReadAdvanceFW<"ReadVFWMulAddV", 0>;
defm "" : LMULSEWReadAdvanceFW<"ReadVFWMulAddF", 0>;
defm "" : LMULSEWReadAdvanceF<"ReadVFSqrtV", 0>;
defm "" : LMULSEWReadAdvanceF<"ReadVFRecpV", 0>;
defm "" : LMULReadAdvance<"ReadVFCmpV", 0>;
defm "" : LMULReadAdvance<"ReadVFCmpF", 0>;
defm "" : LMULSEWReadAdvanceF<"ReadVFMinMaxV", 0>;
defm "" : LMULSEWReadAdvanceF<"ReadVFMinMaxF", 0>;
defm "" : LMULSEWReadAdvanceF<"ReadVFSgnjV", 0>;
defm "" : LMULSEWReadAdvanceF<"ReadVFSgnjF", 0>;
defm "" : LMULReadAdvance<"ReadVFClassV", 0>;
defm "" : LMULReadAdvance<"ReadVFMergeV", 0>;
defm "" : LMULReadAdvance<"ReadVFMergeF", 0>;
defm "" : LMULReadAdvance<"ReadVFMovF", 0>;
defm "" : LMULSEWReadAdvanceF<"ReadVFCvtIToFV", 0>;
defm "" : LMULReadAdvance<"ReadVFCvtFToIV", 0>;
defm "" : LMULSEWReadAdvanceW<"ReadVFWCvtIToFV", 0>;
defm "" : LMULReadAdvanceFW<"ReadVFWCvtFToIV", 0>;
defm "" : LMULSEWReadAdvanceFW<"ReadVFWCvtFToFV", 0>;
defm "" : LMULSEWReadAdvanceFW<"ReadVFNCvtIToFV", 0>;
defm "" : LMULReadAdvanceW<"ReadVFNCvtFToIV", 0>;
defm "" : LMULSEWReadAdvanceFW<"ReadVFNCvtFToFV", 0>;
// 14. Vector Reduction Operations
def : ReadAdvance<ReadVIRedV, 0>;
def : ReadAdvance<ReadVIRedV0, 0>;
def : ReadAdvance<ReadVIWRedV, 0>;
def : ReadAdvance<ReadVIWRedV0, 0>;
def : ReadAdvance<ReadVFRedV, 0>;
def : ReadAdvance<ReadVFRedV0, 0>;
def : ReadAdvance<ReadVFRedOV, 0>;
def : ReadAdvance<ReadVFRedOV0, 0>;
def : ReadAdvance<ReadVFWRedV, 0>;
def : ReadAdvance<ReadVFWRedV0, 0>;
def : ReadAdvance<ReadVFWRedOV, 0>;
def : ReadAdvance<ReadVFWRedOV0, 0>;
// 15. Vector Mask Instructions
defm "" : LMULReadAdvance<"ReadVMALUV", 0>;
defm "" : LMULReadAdvance<"ReadVMPopV", 0>;
defm "" : LMULReadAdvance<"ReadVMFFSV", 0>;
defm "" : LMULReadAdvance<"ReadVMSFSV", 0>;
defm "" : LMULReadAdvance<"ReadVIotaV", 0>;
// 16. Vector Permutation Instructions
def : ReadAdvance<ReadVMovXS, 0>;
def : ReadAdvance<ReadVMovSX_V, 0>;
def : ReadAdvance<ReadVMovSX_X, 0>;
def : ReadAdvance<ReadVMovFS, 0>;
def : ReadAdvance<ReadVMovSF_V, 0>;
def : ReadAdvance<ReadVMovSF_F, 0>;
defm "" : LMULReadAdvance<"ReadVISlideV", 0>;
defm "" : LMULReadAdvance<"ReadVISlideX", 0>;
defm "" : LMULReadAdvance<"ReadVFSlideV", 0>;
defm "" : LMULReadAdvance<"ReadVFSlideF", 0>;
defm "" : LMULSEWReadAdvance<"ReadVRGatherVV_data", 0>;
defm "" : LMULSEWReadAdvance<"ReadVRGatherVV_index", 0>;
defm "" : LMULSEWReadAdvance<"ReadVRGatherEI16VV_data", 0>;
defm "" : LMULSEWReadAdvance<"ReadVRGatherEI16VV_index", 0>;
defm "" : LMULReadAdvance<"ReadVRGatherVX_data", 0>;
defm "" : LMULReadAdvance<"ReadVRGatherVX_index", 0>;
defm "" : LMULReadAdvance<"ReadVRGatherVI_data", 0>;
defm "" : LMULSEWReadAdvance<"ReadVCompressV", 0>;
// LMUL Aware
def : ReadAdvance<ReadVMov1V, 0>;
def : ReadAdvance<ReadVMov2V, 0>;
def : ReadAdvance<ReadVMov4V, 0>;
def : ReadAdvance<ReadVMov8V, 0>;
// Others
def : ReadAdvance<ReadVMask, 0>;
def : ReadAdvance<ReadVPassthru_WorstCase, 0>;
foreach mx = SchedMxList in {
def : ReadAdvance<!cast<SchedRead>("ReadVPassthru_" # mx), 0>;
foreach sew = SchedSEWSet<mx>.val in
def : ReadAdvance<!cast<SchedRead>("ReadVPassthru_" # mx # "_E" # sew), 0>;
}
//===----------------------------------------------------------------------===//
// Unsupported extensions
defm : UnsupportedSchedQ;
defm : UnsupportedSchedZabha;
defm : UnsupportedSchedZbkb;
defm : UnsupportedSchedZbkx;
defm : UnsupportedSchedZfa;
defm : UnsupportedSchedZvk;
defm : UnsupportedSchedSFB;
defm : UnsupportedSchedXsf;
}