This can be reused by #95924. Reviewers: BeMg, topperc, lukel97, preames, mshockwave Reviewed By: mshockwave, topperc Pull Request: https://github.com/llvm/llvm-project/pull/172615
502 lines
18 KiB
C++
502 lines
18 KiB
C++
//===- RISCVVSETVLIInfoAnalysis.cpp - VSETVLI Info Analysis ---------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements an analysis of the vtype/vl information that is needed
|
|
// by RISCVInsertVSETVLI pass and others.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "RISCVVSETVLIInfoAnalysis.h"
|
|
#include "RISCVSubtarget.h"
|
|
#include "llvm/CodeGen/LiveIntervals.h"
|
|
|
|
namespace llvm {
|
|
namespace RISCV {
|
|
|
|
/// Given a virtual register \p Reg, return the corresponding VNInfo for it.
|
|
/// This will return nullptr if the virtual register is an implicit_def or
|
|
/// if LiveIntervals is not available.
|
|
static VNInfo *getVNInfoFromReg(Register Reg, const MachineInstr &MI,
|
|
const LiveIntervals *LIS) {
|
|
assert(Reg.isVirtual());
|
|
if (!LIS)
|
|
return nullptr;
|
|
auto &LI = LIS->getInterval(Reg);
|
|
SlotIndex SI = LIS->getSlotIndexes()->getInstructionIndex(MI);
|
|
return LI.getVNInfoBefore(SI);
|
|
}
|
|
|
|
static unsigned getVLOpNum(const MachineInstr &MI) {
|
|
return RISCVII::getVLOpNum(MI.getDesc());
|
|
}
|
|
|
|
static unsigned getSEWOpNum(const MachineInstr &MI) {
|
|
return RISCVII::getSEWOpNum(MI.getDesc());
|
|
}
|
|
|
|
static unsigned getVecPolicyOpNum(const MachineInstr &MI) {
|
|
return RISCVII::getVecPolicyOpNum(MI.getDesc());
|
|
}
|
|
|
|
/// Get the EEW for a load or store instruction. Return std::nullopt if MI is
|
|
/// not a load or store which ignores SEW.
|
|
static std::optional<unsigned> getEEWForLoadStore(const MachineInstr &MI) {
|
|
switch (RISCV::getRVVMCOpcode(MI.getOpcode())) {
|
|
default:
|
|
return std::nullopt;
|
|
case RISCV::VLE8_V:
|
|
case RISCV::VLSE8_V:
|
|
case RISCV::VSE8_V:
|
|
case RISCV::VSSE8_V:
|
|
return 8;
|
|
case RISCV::VLE16_V:
|
|
case RISCV::VLSE16_V:
|
|
case RISCV::VSE16_V:
|
|
case RISCV::VSSE16_V:
|
|
return 16;
|
|
case RISCV::VLE32_V:
|
|
case RISCV::VLSE32_V:
|
|
case RISCV::VSE32_V:
|
|
case RISCV::VSSE32_V:
|
|
return 32;
|
|
case RISCV::VLE64_V:
|
|
case RISCV::VLSE64_V:
|
|
case RISCV::VSE64_V:
|
|
case RISCV::VSSE64_V:
|
|
return 64;
|
|
}
|
|
}
|
|
|
|
/// Return true if this is an operation on mask registers. Note that
|
|
/// this includes both arithmetic/logical ops and load/store (vlm/vsm).
|
|
static bool isMaskRegOp(const MachineInstr &MI) {
|
|
if (!RISCVII::hasSEWOp(MI.getDesc().TSFlags))
|
|
return false;
|
|
const unsigned Log2SEW = MI.getOperand(getSEWOpNum(MI)).getImm();
|
|
// A Log2SEW of 0 is an operation on mask registers only.
|
|
return Log2SEW == 0;
|
|
}
|
|
|
|
/// Return true if the inactive elements in the result are entirely undefined.
|
|
/// Note that this is different from "agnostic" as defined by the vector
|
|
/// specification. Agnostic requires each lane to either be undisturbed, or
|
|
/// take the value -1; no other value is allowed.
|
|
static bool hasUndefinedPassthru(const MachineInstr &MI) {
|
|
unsigned UseOpIdx;
|
|
if (!MI.isRegTiedToUseOperand(0, &UseOpIdx))
|
|
// If there is no passthrough operand, then the pass through
|
|
// lanes are undefined.
|
|
return true;
|
|
|
|
// All undefined passthrus should be $noreg: see
|
|
// RISCVDAGToDAGISel::doPeepholeNoRegPassThru
|
|
const MachineOperand &UseMO = MI.getOperand(UseOpIdx);
|
|
return !UseMO.getReg().isValid() || UseMO.isUndef();
|
|
}
|
|
|
|
static bool isLMUL1OrSmaller(RISCVVType::VLMUL LMUL) {
|
|
auto [LMul, Fractional] = RISCVVType::decodeVLMUL(LMUL);
|
|
return Fractional || LMul == 1;
|
|
}
|
|
|
|
/// Return true if moving from CurVType to NewVType is
|
|
/// indistinguishable from the perspective of an instruction (or set
|
|
/// of instructions) which use only the Used subfields and properties.
|
|
bool areCompatibleVTYPEs(uint64_t CurVType, uint64_t NewVType,
|
|
const DemandedFields &Used) {
|
|
switch (Used.SEW) {
|
|
case DemandedFields::SEWNone:
|
|
break;
|
|
case DemandedFields::SEWEqual:
|
|
if (RISCVVType::getSEW(CurVType) != RISCVVType::getSEW(NewVType))
|
|
return false;
|
|
break;
|
|
case DemandedFields::SEWGreaterThanOrEqual:
|
|
if (RISCVVType::getSEW(NewVType) < RISCVVType::getSEW(CurVType))
|
|
return false;
|
|
break;
|
|
case DemandedFields::SEWGreaterThanOrEqualAndLessThan64:
|
|
if (RISCVVType::getSEW(NewVType) < RISCVVType::getSEW(CurVType) ||
|
|
RISCVVType::getSEW(NewVType) >= 64)
|
|
return false;
|
|
break;
|
|
}
|
|
|
|
switch (Used.LMUL) {
|
|
case DemandedFields::LMULNone:
|
|
break;
|
|
case DemandedFields::LMULEqual:
|
|
if (RISCVVType::getVLMUL(CurVType) != RISCVVType::getVLMUL(NewVType))
|
|
return false;
|
|
break;
|
|
case DemandedFields::LMULLessThanOrEqualToM1:
|
|
if (!isLMUL1OrSmaller(RISCVVType::getVLMUL(NewVType)))
|
|
return false;
|
|
break;
|
|
}
|
|
|
|
if (Used.SEWLMULRatio) {
|
|
auto Ratio1 = RISCVVType::getSEWLMULRatio(RISCVVType::getSEW(CurVType),
|
|
RISCVVType::getVLMUL(CurVType));
|
|
auto Ratio2 = RISCVVType::getSEWLMULRatio(RISCVVType::getSEW(NewVType),
|
|
RISCVVType::getVLMUL(NewVType));
|
|
if (Ratio1 != Ratio2)
|
|
return false;
|
|
}
|
|
|
|
if (Used.TailPolicy && RISCVVType::isTailAgnostic(CurVType) !=
|
|
RISCVVType::isTailAgnostic(NewVType))
|
|
return false;
|
|
if (Used.MaskPolicy && RISCVVType::isMaskAgnostic(CurVType) !=
|
|
RISCVVType::isMaskAgnostic(NewVType))
|
|
return false;
|
|
if (Used.TWiden && (RISCVVType::hasXSfmmWiden(CurVType) !=
|
|
RISCVVType::hasXSfmmWiden(NewVType) ||
|
|
(RISCVVType::hasXSfmmWiden(CurVType) &&
|
|
RISCVVType::getXSfmmWiden(CurVType) !=
|
|
RISCVVType::getXSfmmWiden(NewVType))))
|
|
return false;
|
|
if (Used.AltFmt &&
|
|
RISCVVType::isAltFmt(CurVType) != RISCVVType::isAltFmt(NewVType))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
/// Return the fields and properties demanded by the provided instruction.
|
|
DemandedFields getDemanded(const MachineInstr &MI, const RISCVSubtarget *ST) {
|
|
// This function works in coalesceVSETVLI too. We can still use the value of a
|
|
// SEW, VL, or Policy operand even though it might not be the exact value in
|
|
// the VL or VTYPE, since we only care about what the instruction originally
|
|
// demanded.
|
|
|
|
// Most instructions don't use any of these subfeilds.
|
|
DemandedFields Res;
|
|
// Start conservative if registers are used
|
|
if (MI.isCall() || MI.isInlineAsm() ||
|
|
MI.readsRegister(RISCV::VL, /*TRI=*/nullptr))
|
|
Res.demandVL();
|
|
if (MI.isCall() || MI.isInlineAsm() ||
|
|
MI.readsRegister(RISCV::VTYPE, /*TRI=*/nullptr))
|
|
Res.demandVTYPE();
|
|
// Start conservative on the unlowered form too
|
|
uint64_t TSFlags = MI.getDesc().TSFlags;
|
|
if (RISCVII::hasSEWOp(TSFlags)) {
|
|
Res.demandVTYPE();
|
|
if (RISCVII::hasVLOp(TSFlags))
|
|
if (const MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI));
|
|
!VLOp.isReg() || !VLOp.isUndef())
|
|
Res.demandVL();
|
|
|
|
// Behavior is independent of mask policy.
|
|
if (!RISCVII::usesMaskPolicy(TSFlags))
|
|
Res.MaskPolicy = false;
|
|
}
|
|
|
|
// Loads and stores with implicit EEW do not demand SEW or LMUL directly.
|
|
// They instead demand the ratio of the two which is used in computing
|
|
// EMUL, but which allows us the flexibility to change SEW and LMUL
|
|
// provided we don't change the ratio.
|
|
// Note: We assume that the instructions initial SEW is the EEW encoded
|
|
// in the opcode. This is asserted when constructing the VSETVLIInfo.
|
|
if (RISCV::getEEWForLoadStore(MI)) {
|
|
Res.SEW = DemandedFields::SEWNone;
|
|
Res.LMUL = DemandedFields::LMULNone;
|
|
}
|
|
|
|
// Store instructions don't use the policy fields.
|
|
if (RISCVII::hasSEWOp(TSFlags) && MI.getNumExplicitDefs() == 0) {
|
|
Res.TailPolicy = false;
|
|
Res.MaskPolicy = false;
|
|
}
|
|
|
|
// If this is a mask reg operation, it only cares about VLMAX.
|
|
// TODO: Possible extensions to this logic
|
|
// * Probably ok if available VLMax is larger than demanded
|
|
// * The policy bits can probably be ignored..
|
|
if (isMaskRegOp(MI)) {
|
|
Res.SEW = DemandedFields::SEWNone;
|
|
Res.LMUL = DemandedFields::LMULNone;
|
|
}
|
|
|
|
// For vmv.s.x and vfmv.s.f, there are only two behaviors, VL = 0 and VL > 0.
|
|
if (RISCVInstrInfo::isScalarInsertInstr(MI)) {
|
|
Res.LMUL = DemandedFields::LMULNone;
|
|
Res.SEWLMULRatio = false;
|
|
Res.VLAny = false;
|
|
// For vmv.s.x and vfmv.s.f, if the passthru is *undefined*, we don't
|
|
// need to preserve any other bits and are thus compatible with any larger,
|
|
// etype and can disregard policy bits. Warning: It's tempting to try doing
|
|
// this for any tail agnostic operation, but we can't as TA requires
|
|
// tail lanes to either be the original value or -1. We are writing
|
|
// unknown bits to the lanes here.
|
|
if (RISCV::hasUndefinedPassthru(MI)) {
|
|
if (RISCVInstrInfo::isFloatScalarMoveOrScalarSplatInstr(MI) &&
|
|
!ST->hasVInstructionsF64())
|
|
Res.SEW = DemandedFields::SEWGreaterThanOrEqualAndLessThan64;
|
|
else
|
|
Res.SEW = DemandedFields::SEWGreaterThanOrEqual;
|
|
Res.TailPolicy = false;
|
|
}
|
|
}
|
|
|
|
// vmv.x.s, and vfmv.f.s are unconditional and ignore everything except SEW.
|
|
if (RISCVInstrInfo::isScalarExtractInstr(MI)) {
|
|
assert(!RISCVII::hasVLOp(TSFlags));
|
|
Res.LMUL = DemandedFields::LMULNone;
|
|
Res.SEWLMULRatio = false;
|
|
Res.TailPolicy = false;
|
|
Res.MaskPolicy = false;
|
|
}
|
|
|
|
if (RISCVII::hasVLOp(MI.getDesc().TSFlags)) {
|
|
const MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI));
|
|
// A slidedown/slideup with an *undefined* passthru can freely clobber
|
|
// elements not copied from the source vector (e.g. masked off, tail, or
|
|
// slideup's prefix). Notes:
|
|
// * We can't modify SEW here since the slide amount is in units of SEW.
|
|
// * VL=1 is special only because we have existing support for zero vs
|
|
// non-zero VL. We could generalize this if we had a VL > C predicate.
|
|
// * The LMUL1 restriction is for machines whose latency may depend on LMUL.
|
|
// * As above, this is only legal for tail "undefined" not "agnostic".
|
|
// * We avoid increasing vl if the subtarget has +vl-dependent-latency
|
|
if (RISCVInstrInfo::isVSlideInstr(MI) && VLOp.isImm() &&
|
|
VLOp.getImm() == 1 && RISCV::hasUndefinedPassthru(MI) &&
|
|
!ST->hasVLDependentLatency()) {
|
|
Res.VLAny = false;
|
|
Res.VLZeroness = true;
|
|
Res.LMUL = DemandedFields::LMULLessThanOrEqualToM1;
|
|
Res.TailPolicy = false;
|
|
}
|
|
|
|
// A tail undefined vmv.v.i/x or vfmv.v.f with VL=1 can be treated in the
|
|
// same semantically as vmv.s.x. This is particularly useful since we don't
|
|
// have an immediate form of vmv.s.x, and thus frequently use vmv.v.i in
|
|
// it's place. Since a splat is non-constant time in LMUL, we do need to be
|
|
// careful to not increase the number of active vector registers (unlike for
|
|
// vmv.s.x.)
|
|
if (RISCVInstrInfo::isScalarSplatInstr(MI) && VLOp.isImm() &&
|
|
VLOp.getImm() == 1 && RISCV::hasUndefinedPassthru(MI) &&
|
|
!ST->hasVLDependentLatency()) {
|
|
Res.LMUL = DemandedFields::LMULLessThanOrEqualToM1;
|
|
Res.SEWLMULRatio = false;
|
|
Res.VLAny = false;
|
|
if (RISCVInstrInfo::isFloatScalarMoveOrScalarSplatInstr(MI) &&
|
|
!ST->hasVInstructionsF64())
|
|
Res.SEW = DemandedFields::SEWGreaterThanOrEqualAndLessThan64;
|
|
else
|
|
Res.SEW = DemandedFields::SEWGreaterThanOrEqual;
|
|
Res.TailPolicy = false;
|
|
}
|
|
}
|
|
|
|
// In §32.16.6, whole vector register moves have a dependency on SEW. At the
|
|
// MIR level though we don't encode the element type, and it gives the same
|
|
// result whatever the SEW may be.
|
|
//
|
|
// However it does need valid SEW, i.e. vill must be cleared. The entry to a
|
|
// function, calls and inline assembly may all set it, so make sure we clear
|
|
// it for whole register copies. Do this by leaving VILL demanded.
|
|
if (RISCV::isVectorCopy(ST->getRegisterInfo(), MI)) {
|
|
Res.LMUL = DemandedFields::LMULNone;
|
|
Res.SEW = DemandedFields::SEWNone;
|
|
Res.SEWLMULRatio = false;
|
|
Res.TailPolicy = false;
|
|
Res.MaskPolicy = false;
|
|
}
|
|
|
|
if (RISCVInstrInfo::isVExtractInstr(MI)) {
|
|
assert(!RISCVII::hasVLOp(TSFlags));
|
|
// TODO: LMUL can be any larger value (without cost)
|
|
Res.TailPolicy = false;
|
|
}
|
|
|
|
Res.AltFmt = RISCVII::getAltFmtType(MI.getDesc().TSFlags) !=
|
|
RISCVII::AltFmtType::DontCare;
|
|
Res.TWiden = RISCVII::hasTWidenOp(MI.getDesc().TSFlags) ||
|
|
RISCVInstrInfo::isXSfmmVectorConfigInstr(MI);
|
|
|
|
return Res;
|
|
}
|
|
|
|
bool VSETVLIInfo::hasCompatibleVTYPE(const DemandedFields &Used,
|
|
const VSETVLIInfo &Require) const {
|
|
return areCompatibleVTYPEs(Require.encodeVTYPE(), encodeVTYPE(), Used);
|
|
}
|
|
|
|
// If the AVL is defined by a vsetvli's output vl with the same VLMAX, we can
|
|
// replace the AVL operand with the AVL of the defining vsetvli. E.g.
|
|
//
|
|
// %vl = PseudoVSETVLI %avl:gpr, SEW=32, LMUL=M1
|
|
// $x0 = PseudoVSETVLI %vl:gpr, SEW=32, LMUL=M1
|
|
// ->
|
|
// %vl = PseudoVSETVLI %avl:gpr, SEW=32, LMUL=M1
|
|
// $x0 = PseudoVSETVLI %avl:gpr, SEW=32, LMUL=M1
|
|
void RISCVVSETVLIInfoAnalysis::forwardVSETVLIAVL(VSETVLIInfo &Info) const {
|
|
if (!Info.hasAVLReg())
|
|
return;
|
|
const MachineInstr *DefMI = Info.getAVLDefMI(LIS);
|
|
if (!DefMI || !RISCVInstrInfo::isVectorConfigInstr(*DefMI))
|
|
return;
|
|
VSETVLIInfo DefInstrInfo = getInfoForVSETVLI(*DefMI);
|
|
if (!DefInstrInfo.hasSameVLMAX(Info))
|
|
return;
|
|
Info.setAVL(DefInstrInfo);
|
|
}
|
|
|
|
// Return a VSETVLIInfo representing the changes made by this VSETVLI or
|
|
// VSETIVLI instruction.
|
|
VSETVLIInfo
|
|
RISCVVSETVLIInfoAnalysis::getInfoForVSETVLI(const MachineInstr &MI) const {
|
|
VSETVLIInfo NewInfo;
|
|
if (MI.getOpcode() == RISCV::PseudoVSETIVLI) {
|
|
NewInfo.setAVLImm(MI.getOperand(1).getImm());
|
|
} else if (RISCVInstrInfo::isXSfmmVectorConfigTNInstr(MI)) {
|
|
assert(MI.getOpcode() == RISCV::PseudoSF_VSETTNT ||
|
|
MI.getOpcode() == RISCV::PseudoSF_VSETTNTX0);
|
|
switch (MI.getOpcode()) {
|
|
case RISCV::PseudoSF_VSETTNTX0:
|
|
NewInfo.setAVLVLMAX();
|
|
break;
|
|
case RISCV::PseudoSF_VSETTNT:
|
|
Register ATNReg = MI.getOperand(1).getReg();
|
|
NewInfo.setAVLRegDef(getVNInfoFromReg(ATNReg, MI, LIS), ATNReg);
|
|
break;
|
|
}
|
|
} else {
|
|
assert(MI.getOpcode() == RISCV::PseudoVSETVLI ||
|
|
MI.getOpcode() == RISCV::PseudoVSETVLIX0);
|
|
if (MI.getOpcode() == RISCV::PseudoVSETVLIX0)
|
|
NewInfo.setAVLVLMAX();
|
|
else if (MI.getOperand(1).isUndef())
|
|
// Otherwise use an AVL of 1 to avoid depending on previous vl.
|
|
NewInfo.setAVLImm(1);
|
|
else {
|
|
Register AVLReg = MI.getOperand(1).getReg();
|
|
VNInfo *VNI = getVNInfoFromReg(AVLReg, MI, LIS);
|
|
NewInfo.setAVLRegDef(VNI, AVLReg);
|
|
}
|
|
}
|
|
NewInfo.setVTYPE(MI.getOperand(2).getImm());
|
|
|
|
forwardVSETVLIAVL(NewInfo);
|
|
|
|
return NewInfo;
|
|
}
|
|
|
|
static unsigned computeVLMAX(unsigned VLEN, unsigned SEW,
|
|
RISCVVType::VLMUL VLMul) {
|
|
auto [LMul, Fractional] = RISCVVType::decodeVLMUL(VLMul);
|
|
if (Fractional)
|
|
VLEN = VLEN / LMul;
|
|
else
|
|
VLEN = VLEN * LMul;
|
|
return VLEN / SEW;
|
|
}
|
|
|
|
VSETVLIInfo
|
|
RISCVVSETVLIInfoAnalysis::computeInfoForInstr(const MachineInstr &MI) const {
|
|
VSETVLIInfo InstrInfo;
|
|
const uint64_t TSFlags = MI.getDesc().TSFlags;
|
|
|
|
bool TailAgnostic = true;
|
|
bool MaskAgnostic = true;
|
|
if (!RISCV::hasUndefinedPassthru(MI)) {
|
|
// Start with undisturbed.
|
|
TailAgnostic = false;
|
|
MaskAgnostic = false;
|
|
|
|
// If there is a policy operand, use it.
|
|
if (RISCVII::hasVecPolicyOp(TSFlags)) {
|
|
const MachineOperand &Op = MI.getOperand(getVecPolicyOpNum(MI));
|
|
uint64_t Policy = Op.getImm();
|
|
assert(Policy <=
|
|
(RISCVVType::TAIL_AGNOSTIC | RISCVVType::MASK_AGNOSTIC) &&
|
|
"Invalid Policy Value");
|
|
TailAgnostic = Policy & RISCVVType::TAIL_AGNOSTIC;
|
|
MaskAgnostic = Policy & RISCVVType::MASK_AGNOSTIC;
|
|
}
|
|
|
|
if (!RISCVII::usesMaskPolicy(TSFlags))
|
|
MaskAgnostic = true;
|
|
}
|
|
|
|
RISCVVType::VLMUL VLMul = RISCVII::getLMul(TSFlags);
|
|
|
|
bool AltFmt = RISCVII::getAltFmtType(TSFlags) == RISCVII::AltFmtType::AltFmt;
|
|
InstrInfo.setAltFmt(AltFmt);
|
|
|
|
unsigned Log2SEW = MI.getOperand(getSEWOpNum(MI)).getImm();
|
|
// A Log2SEW of 0 is an operation on mask registers only.
|
|
unsigned SEW = Log2SEW ? 1 << Log2SEW : 8;
|
|
assert(RISCVVType::isValidSEW(SEW) && "Unexpected SEW");
|
|
|
|
if (RISCVII::hasTWidenOp(TSFlags)) {
|
|
const MachineOperand &TWidenOp =
|
|
MI.getOperand(MI.getNumExplicitOperands() - 1);
|
|
unsigned TWiden = TWidenOp.getImm();
|
|
|
|
InstrInfo.setAVLVLMAX();
|
|
if (RISCVII::hasVLOp(TSFlags)) {
|
|
const MachineOperand &TNOp =
|
|
MI.getOperand(RISCVII::getTNOpNum(MI.getDesc()));
|
|
|
|
if (TNOp.getReg().isVirtual())
|
|
InstrInfo.setAVLRegDef(getVNInfoFromReg(TNOp.getReg(), MI, LIS),
|
|
TNOp.getReg());
|
|
}
|
|
|
|
InstrInfo.setVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic, AltFmt, TWiden);
|
|
|
|
return InstrInfo;
|
|
}
|
|
|
|
if (RISCVII::hasVLOp(TSFlags)) {
|
|
const MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI));
|
|
if (VLOp.isImm()) {
|
|
int64_t Imm = VLOp.getImm();
|
|
// Convert the VLMax sentintel to X0 register.
|
|
if (Imm == RISCV::VLMaxSentinel) {
|
|
// If we know the exact VLEN, see if we can use the constant encoding
|
|
// for the VLMAX instead. This reduces register pressure slightly.
|
|
const unsigned VLMAX = computeVLMAX(ST->getRealMaxVLen(), SEW, VLMul);
|
|
if (ST->getRealMinVLen() == ST->getRealMaxVLen() && VLMAX <= 31)
|
|
InstrInfo.setAVLImm(VLMAX);
|
|
else
|
|
InstrInfo.setAVLVLMAX();
|
|
} else
|
|
InstrInfo.setAVLImm(Imm);
|
|
} else if (VLOp.isUndef()) {
|
|
// Otherwise use an AVL of 1 to avoid depending on previous vl.
|
|
InstrInfo.setAVLImm(1);
|
|
} else {
|
|
VNInfo *VNI = getVNInfoFromReg(VLOp.getReg(), MI, LIS);
|
|
InstrInfo.setAVLRegDef(VNI, VLOp.getReg());
|
|
}
|
|
} else {
|
|
assert(RISCVInstrInfo::isScalarExtractInstr(MI) ||
|
|
RISCVInstrInfo::isVExtractInstr(MI));
|
|
// Pick a random value for state tracking purposes, will be ignored via
|
|
// the demanded fields mechanism
|
|
InstrInfo.setAVLImm(1);
|
|
}
|
|
#ifndef NDEBUG
|
|
if (std::optional<unsigned> EEW = RISCV::getEEWForLoadStore(MI)) {
|
|
assert(SEW == EEW && "Initial SEW doesn't match expected EEW");
|
|
}
|
|
#endif
|
|
// TODO: Propagate the twiden from previous vtype for potential reuse.
|
|
InstrInfo.setVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic, AltFmt,
|
|
/*TWiden*/ 0);
|
|
|
|
forwardVSETVLIAVL(InstrInfo);
|
|
|
|
return InstrInfo;
|
|
}
|
|
} // namespace RISCV
|
|
} // namespace llvm
|