CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
591 lines
18 KiB
C++
591 lines
18 KiB
C++
//===- RISCVVSETVLIInfoAnalysis.h - 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 "RISCV.h"
|
|
#include "RISCVSubtarget.h"
|
|
#include "llvm/ADT/Statistic.h"
|
|
#include "llvm/CodeGen/LiveDebugVariables.h"
|
|
#include "llvm/CodeGen/LiveIntervals.h"
|
|
#include "llvm/CodeGen/LiveStacks.h"
|
|
|
|
namespace llvm {
|
|
namespace RISCV {
|
|
/// Which subfields of VL or VTYPE have values we need to preserve?
|
|
struct DemandedFields {
|
|
// Some unknown property of VL is used. If demanded, must preserve entire
|
|
// value.
|
|
bool VLAny = false;
|
|
// Only zero vs non-zero is used. If demanded, can change non-zero values.
|
|
bool VLZeroness = false;
|
|
// What properties of SEW we need to preserve.
|
|
enum : uint8_t {
|
|
SEWEqual = 3, // The exact value of SEW needs to be preserved.
|
|
SEWGreaterThanOrEqualAndLessThan64 =
|
|
2, // SEW can be changed as long as it's greater
|
|
// than or equal to the original value, but must be less
|
|
// than 64.
|
|
SEWGreaterThanOrEqual = 1, // SEW can be changed as long as it's greater
|
|
// than or equal to the original value.
|
|
SEWNone = 0 // We don't need to preserve SEW at all.
|
|
} SEW = SEWNone;
|
|
enum : uint8_t {
|
|
LMULEqual = 2, // The exact value of LMUL needs to be preserved.
|
|
LMULLessThanOrEqualToM1 = 1, // We can use any LMUL <= M1.
|
|
LMULNone = 0 // We don't need to preserve LMUL at all.
|
|
} LMUL = LMULNone;
|
|
bool SEWLMULRatio = false;
|
|
bool TailPolicy = false;
|
|
bool MaskPolicy = false;
|
|
// If this is true, we demand that VTYPE is set to some legal state, i.e. that
|
|
// vill is unset.
|
|
bool VILL = false;
|
|
bool TWiden = false;
|
|
bool AltFmt = false;
|
|
|
|
// Return true if any part of VTYPE was used
|
|
bool usedVTYPE() const {
|
|
return SEW || LMUL || SEWLMULRatio || TailPolicy || MaskPolicy || VILL ||
|
|
TWiden || AltFmt;
|
|
}
|
|
|
|
// Return true if any property of VL was used
|
|
bool usedVL() { return VLAny || VLZeroness; }
|
|
|
|
// Mark all VTYPE subfields and properties as demanded
|
|
void demandVTYPE() {
|
|
SEW = SEWEqual;
|
|
LMUL = LMULEqual;
|
|
SEWLMULRatio = true;
|
|
TailPolicy = true;
|
|
MaskPolicy = true;
|
|
VILL = true;
|
|
TWiden = true;
|
|
AltFmt = true;
|
|
}
|
|
|
|
// Mark all VL properties as demanded
|
|
void demandVL() {
|
|
VLAny = true;
|
|
VLZeroness = true;
|
|
}
|
|
|
|
static DemandedFields all() {
|
|
DemandedFields DF;
|
|
DF.demandVTYPE();
|
|
DF.demandVL();
|
|
return DF;
|
|
}
|
|
|
|
// Make this the result of demanding both the fields in this and B.
|
|
void doUnion(const DemandedFields &B) {
|
|
VLAny |= B.VLAny;
|
|
VLZeroness |= B.VLZeroness;
|
|
SEW = std::max(SEW, B.SEW);
|
|
LMUL = std::max(LMUL, B.LMUL);
|
|
SEWLMULRatio |= B.SEWLMULRatio;
|
|
TailPolicy |= B.TailPolicy;
|
|
MaskPolicy |= B.MaskPolicy;
|
|
VILL |= B.VILL;
|
|
AltFmt |= B.AltFmt;
|
|
TWiden |= B.TWiden;
|
|
}
|
|
|
|
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
|
/// Support for debugging, callable in GDB: V->dump()
|
|
LLVM_DUMP_METHOD void dump() const {
|
|
print(dbgs());
|
|
dbgs() << "\n";
|
|
}
|
|
|
|
/// Implement operator<<.
|
|
void print(raw_ostream &OS) const {
|
|
OS << "{";
|
|
OS << "VLAny=" << VLAny << ", ";
|
|
OS << "VLZeroness=" << VLZeroness << ", ";
|
|
OS << "SEW=";
|
|
switch (SEW) {
|
|
case SEWEqual:
|
|
OS << "SEWEqual";
|
|
break;
|
|
case SEWGreaterThanOrEqual:
|
|
OS << "SEWGreaterThanOrEqual";
|
|
break;
|
|
case SEWGreaterThanOrEqualAndLessThan64:
|
|
OS << "SEWGreaterThanOrEqualAndLessThan64";
|
|
break;
|
|
case SEWNone:
|
|
OS << "SEWNone";
|
|
break;
|
|
};
|
|
OS << ", ";
|
|
OS << "LMUL=";
|
|
switch (LMUL) {
|
|
case LMULEqual:
|
|
OS << "LMULEqual";
|
|
break;
|
|
case LMULLessThanOrEqualToM1:
|
|
OS << "LMULLessThanOrEqualToM1";
|
|
break;
|
|
case LMULNone:
|
|
OS << "LMULNone";
|
|
break;
|
|
};
|
|
OS << ", ";
|
|
OS << "SEWLMULRatio=" << SEWLMULRatio << ", ";
|
|
OS << "TailPolicy=" << TailPolicy << ", ";
|
|
OS << "MaskPolicy=" << MaskPolicy << ", ";
|
|
OS << "VILL=" << VILL << ", ";
|
|
OS << "AltFmt=" << AltFmt << ", ";
|
|
OS << "TWiden=" << TWiden;
|
|
OS << "}";
|
|
}
|
|
#endif
|
|
};
|
|
|
|
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
|
LLVM_ATTRIBUTE_USED
|
|
inline raw_ostream &operator<<(raw_ostream &OS, const DemandedFields &DF) {
|
|
DF.print(OS);
|
|
return OS;
|
|
}
|
|
#endif
|
|
|
|
bool areCompatibleVTYPEs(uint64_t CurVType, uint64_t NewVType,
|
|
const DemandedFields &Used);
|
|
|
|
/// Return the fields and properties demanded by the provided instruction.
|
|
DemandedFields getDemanded(const MachineInstr &MI, const RISCVSubtarget *ST);
|
|
|
|
/// Defines the abstract state with which the forward dataflow models the
|
|
/// values of the VL and VTYPE registers after insertion.
|
|
class VSETVLIInfo {
|
|
struct AVLDef {
|
|
// Every AVLDef should have a VNInfo, unless we're running without
|
|
// LiveIntervals in which case this will be nullptr.
|
|
const VNInfo *ValNo;
|
|
Register DefReg;
|
|
};
|
|
union {
|
|
AVLDef AVLRegDef;
|
|
unsigned AVLImm;
|
|
};
|
|
|
|
enum class AVLState : uint8_t {
|
|
Uninitialized,
|
|
AVLIsReg,
|
|
AVLIsImm,
|
|
AVLIsVLMAX,
|
|
Unknown, // AVL and VTYPE are fully unknown
|
|
} State = AVLState::Uninitialized;
|
|
|
|
// Fields from VTYPE.
|
|
RISCVVType::VLMUL VLMul = RISCVVType::LMUL_1;
|
|
uint8_t SEW = 0;
|
|
uint8_t TailAgnostic : 1;
|
|
uint8_t MaskAgnostic : 1;
|
|
uint8_t SEWLMULRatioOnly : 1;
|
|
uint8_t AltFmt : 1;
|
|
uint8_t TWiden : 3;
|
|
|
|
public:
|
|
VSETVLIInfo()
|
|
: AVLImm(0), TailAgnostic(false), MaskAgnostic(false),
|
|
SEWLMULRatioOnly(false), AltFmt(false), TWiden(0) {}
|
|
|
|
static VSETVLIInfo getUnknown() {
|
|
VSETVLIInfo Info;
|
|
Info.setUnknown();
|
|
return Info;
|
|
}
|
|
|
|
bool isValid() const { return State != AVLState::Uninitialized; }
|
|
void setUnknown() { State = AVLState::Unknown; }
|
|
bool isUnknown() const { return State == AVLState::Unknown; }
|
|
bool isKnown() const { return isValid() && !isUnknown(); }
|
|
|
|
void setAVLRegDef(const VNInfo *VNInfo, Register AVLReg) {
|
|
assert(AVLReg.isVirtual());
|
|
AVLRegDef.ValNo = VNInfo;
|
|
AVLRegDef.DefReg = AVLReg;
|
|
State = AVLState::AVLIsReg;
|
|
}
|
|
|
|
void setAVLImm(unsigned Imm) {
|
|
AVLImm = Imm;
|
|
State = AVLState::AVLIsImm;
|
|
}
|
|
|
|
void setAVLVLMAX() { State = AVLState::AVLIsVLMAX; }
|
|
|
|
bool hasAVLImm() const { return State == AVLState::AVLIsImm; }
|
|
bool hasAVLReg() const { return State == AVLState::AVLIsReg; }
|
|
bool hasAVLVLMAX() const { return State == AVLState::AVLIsVLMAX; }
|
|
Register getAVLReg() const {
|
|
assert(hasAVLReg() && AVLRegDef.DefReg.isVirtual());
|
|
return AVLRegDef.DefReg;
|
|
}
|
|
unsigned getAVLImm() const {
|
|
assert(hasAVLImm());
|
|
return AVLImm;
|
|
}
|
|
const VNInfo *getAVLVNInfo() const {
|
|
assert(hasAVLReg());
|
|
return AVLRegDef.ValNo;
|
|
}
|
|
// Most AVLIsReg infos will have a single defining MachineInstr, unless it was
|
|
// a PHI node. In that case getAVLVNInfo()->def will point to the block
|
|
// boundary slot and this will return nullptr. If LiveIntervals isn't
|
|
// available, nullptr is also returned.
|
|
const MachineInstr *getAVLDefMI(const LiveIntervals *LIS) const {
|
|
assert(hasAVLReg());
|
|
if (!LIS || getAVLVNInfo()->isPHIDef())
|
|
return nullptr;
|
|
auto *MI = LIS->getInstructionFromIndex(getAVLVNInfo()->def);
|
|
assert(MI);
|
|
return MI;
|
|
}
|
|
|
|
void setAVL(const VSETVLIInfo &Info) {
|
|
assert(Info.isValid());
|
|
if (Info.isUnknown())
|
|
setUnknown();
|
|
else if (Info.hasAVLReg())
|
|
setAVLRegDef(Info.getAVLVNInfo(), Info.getAVLReg());
|
|
else if (Info.hasAVLVLMAX())
|
|
setAVLVLMAX();
|
|
else {
|
|
assert(Info.hasAVLImm());
|
|
setAVLImm(Info.getAVLImm());
|
|
}
|
|
}
|
|
|
|
bool hasSEWLMULRatioOnly() const {
|
|
assert(isKnown() && "Can't use VTYPE for uninitialized or unknown");
|
|
return SEWLMULRatioOnly;
|
|
}
|
|
|
|
unsigned getSEW() const {
|
|
assert(isKnown() && !hasSEWLMULRatioOnly() &&
|
|
"Can't use VTYPE for uninitialized or unknown");
|
|
return SEW;
|
|
}
|
|
RISCVVType::VLMUL getVLMUL() const {
|
|
assert(isKnown() && !hasSEWLMULRatioOnly() &&
|
|
"Can't use VTYPE for uninitialized or unknown");
|
|
return VLMul;
|
|
}
|
|
bool getTailAgnostic() const {
|
|
assert(isKnown() && "Can't use VTYPE for uninitialized or unknown");
|
|
return TailAgnostic;
|
|
}
|
|
bool getMaskAgnostic() const {
|
|
assert(isKnown() && "Can't use VTYPE for uninitialized or unknown");
|
|
return MaskAgnostic;
|
|
}
|
|
bool getAltFmt() const {
|
|
assert(isKnown() && "Can't use VTYPE for uninitialized or unknown");
|
|
return AltFmt;
|
|
}
|
|
unsigned getTWiden() const {
|
|
assert(isKnown() && "Can't use VTYPE for uninitialized or unknown");
|
|
return TWiden;
|
|
}
|
|
|
|
bool hasNonZeroAVL(const LiveIntervals *LIS) const {
|
|
if (hasAVLImm())
|
|
return getAVLImm() > 0;
|
|
if (hasAVLReg()) {
|
|
if (auto *DefMI = getAVLDefMI(LIS))
|
|
return RISCVInstrInfo::isNonZeroLoadImmediate(*DefMI);
|
|
}
|
|
if (hasAVLVLMAX())
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool hasEquallyZeroAVL(const VSETVLIInfo &Other,
|
|
const LiveIntervals *LIS) const {
|
|
if (hasSameAVL(Other))
|
|
return true;
|
|
return (hasNonZeroAVL(LIS) && Other.hasNonZeroAVL(LIS));
|
|
}
|
|
|
|
bool hasSameAVLLatticeValue(const VSETVLIInfo &Other) const {
|
|
if (hasAVLReg() && Other.hasAVLReg()) {
|
|
assert(!getAVLVNInfo() == !Other.getAVLVNInfo() &&
|
|
"we either have intervals or we don't");
|
|
if (!getAVLVNInfo())
|
|
return getAVLReg() == Other.getAVLReg();
|
|
return getAVLVNInfo()->id == Other.getAVLVNInfo()->id &&
|
|
getAVLReg() == Other.getAVLReg();
|
|
}
|
|
|
|
if (hasAVLImm() && Other.hasAVLImm())
|
|
return getAVLImm() == Other.getAVLImm();
|
|
|
|
if (hasAVLVLMAX())
|
|
return Other.hasAVLVLMAX() && hasSameVLMAX(Other);
|
|
|
|
return false;
|
|
}
|
|
|
|
// Return true if the two lattice values are guaranteed to have
|
|
// the same AVL value at runtime.
|
|
bool hasSameAVL(const VSETVLIInfo &Other) const {
|
|
// Without LiveIntervals, we don't know which instruction defines a
|
|
// register. Since a register may be redefined, this means all AVLIsReg
|
|
// states must be treated as possibly distinct.
|
|
if (hasAVLReg() && Other.hasAVLReg()) {
|
|
assert(!getAVLVNInfo() == !Other.getAVLVNInfo() &&
|
|
"we either have intervals or we don't");
|
|
if (!getAVLVNInfo())
|
|
return false;
|
|
}
|
|
return hasSameAVLLatticeValue(Other);
|
|
}
|
|
|
|
void setVTYPE(unsigned VType) {
|
|
assert(isKnown() && "Can't set VTYPE for uninitialized or unknown");
|
|
VLMul = RISCVVType::getVLMUL(VType);
|
|
SEW = RISCVVType::getSEW(VType);
|
|
TailAgnostic = RISCVVType::isTailAgnostic(VType);
|
|
MaskAgnostic = RISCVVType::isMaskAgnostic(VType);
|
|
AltFmt = RISCVVType::isAltFmt(VType);
|
|
TWiden =
|
|
RISCVVType::hasXSfmmWiden(VType) ? RISCVVType::getXSfmmWiden(VType) : 0;
|
|
}
|
|
void setVTYPE(RISCVVType::VLMUL L, unsigned S, bool TA, bool MA, bool Altfmt,
|
|
unsigned W) {
|
|
assert(isKnown() && "Can't set VTYPE for uninitialized or unknown");
|
|
VLMul = L;
|
|
SEW = S;
|
|
TailAgnostic = TA;
|
|
MaskAgnostic = MA;
|
|
AltFmt = Altfmt;
|
|
TWiden = W;
|
|
}
|
|
|
|
void setAltFmt(bool AF) { AltFmt = AF; }
|
|
|
|
void setVLMul(RISCVVType::VLMUL VLMul) { this->VLMul = VLMul; }
|
|
|
|
unsigned encodeVTYPE() const {
|
|
assert(isKnown() && !SEWLMULRatioOnly &&
|
|
"Can't encode VTYPE for uninitialized or unknown");
|
|
if (TWiden != 0)
|
|
return RISCVVType::encodeXSfmmVType(SEW, TWiden, AltFmt);
|
|
return RISCVVType::encodeVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic,
|
|
AltFmt);
|
|
}
|
|
|
|
bool hasSameVTYPE(const VSETVLIInfo &Other) const {
|
|
assert(isValid() && Other.isValid() &&
|
|
"Can't compare invalid VSETVLIInfos");
|
|
assert(!isUnknown() && !Other.isUnknown() &&
|
|
"Can't compare VTYPE in unknown state");
|
|
assert(!SEWLMULRatioOnly && !Other.SEWLMULRatioOnly &&
|
|
"Can't compare when only LMUL/SEW ratio is valid.");
|
|
return std::tie(VLMul, SEW, TailAgnostic, MaskAgnostic, AltFmt, TWiden) ==
|
|
std::tie(Other.VLMul, Other.SEW, Other.TailAgnostic,
|
|
Other.MaskAgnostic, Other.AltFmt, Other.TWiden);
|
|
}
|
|
|
|
unsigned getSEWLMULRatio() const {
|
|
assert(isKnown() && "Can't use VTYPE for uninitialized or unknown");
|
|
return RISCVVType::getSEWLMULRatio(SEW, VLMul);
|
|
}
|
|
|
|
// Check if the VTYPE for these two VSETVLIInfos produce the same VLMAX.
|
|
// Note that having the same VLMAX ensures that both share the same
|
|
// function from AVL to VL; that is, they must produce the same VL value
|
|
// for any given AVL value.
|
|
bool hasSameVLMAX(const VSETVLIInfo &Other) const {
|
|
assert(isValid() && Other.isValid() &&
|
|
"Can't compare invalid VSETVLIInfos");
|
|
assert(!isUnknown() && !Other.isUnknown() &&
|
|
"Can't compare VTYPE in unknown state");
|
|
if (getTWiden() != Other.getTWiden())
|
|
return false;
|
|
if (getTWiden())
|
|
return getSEW() == Other.getSEW();
|
|
return getSEWLMULRatio() == Other.getSEWLMULRatio();
|
|
}
|
|
|
|
bool hasCompatibleVTYPE(const DemandedFields &Used,
|
|
const VSETVLIInfo &Require) const;
|
|
|
|
// Determine whether the vector instructions requirements represented by
|
|
// Require are compatible with the previous vsetvli instruction represented
|
|
// by this. MI is the instruction whose requirements we're considering.
|
|
bool isCompatible(const DemandedFields &Used, const VSETVLIInfo &Require,
|
|
const LiveIntervals *LIS) const {
|
|
assert(isValid() && Require.isValid() &&
|
|
"Can't compare invalid VSETVLIInfos");
|
|
// Nothing is compatible with Unknown.
|
|
if (isUnknown() || Require.isUnknown())
|
|
return false;
|
|
|
|
// If only our VLMAX ratio is valid, then this isn't compatible.
|
|
if (SEWLMULRatioOnly || Require.SEWLMULRatioOnly)
|
|
return false;
|
|
|
|
if (Used.VLAny && !(hasSameAVL(Require) && hasSameVLMAX(Require)))
|
|
return false;
|
|
|
|
if (Used.VLZeroness && !hasEquallyZeroAVL(Require, LIS))
|
|
return false;
|
|
|
|
return hasCompatibleVTYPE(Used, Require);
|
|
}
|
|
|
|
bool operator==(const VSETVLIInfo &Other) const {
|
|
// Uninitialized is only equal to another Uninitialized.
|
|
if (!isValid())
|
|
return !Other.isValid();
|
|
if (!Other.isValid())
|
|
return !isValid();
|
|
|
|
// Unknown is only equal to another Unknown.
|
|
if (isUnknown())
|
|
return Other.isUnknown();
|
|
if (Other.isUnknown())
|
|
return isUnknown();
|
|
|
|
if (!hasSameAVLLatticeValue(Other))
|
|
return false;
|
|
|
|
// If the SEWLMULRatioOnly bits are different, then they aren't equal.
|
|
if (SEWLMULRatioOnly != Other.SEWLMULRatioOnly)
|
|
return false;
|
|
|
|
// If only the VLMAX is valid, check that it is the same.
|
|
if (SEWLMULRatioOnly)
|
|
return hasSameVLMAX(Other);
|
|
|
|
// If the full VTYPE is valid, check that it is the same.
|
|
return hasSameVTYPE(Other);
|
|
}
|
|
|
|
bool operator!=(const VSETVLIInfo &Other) const { return !(*this == Other); }
|
|
|
|
// Calculate the VSETVLIInfo visible to a block assuming this and Other are
|
|
// both predecessors.
|
|
VSETVLIInfo intersect(const VSETVLIInfo &Other) const {
|
|
// If the new value isn't valid, ignore it.
|
|
if (!Other.isValid())
|
|
return *this;
|
|
|
|
// If this value isn't valid, this must be the first predecessor, use it.
|
|
if (!isValid())
|
|
return Other;
|
|
|
|
// If either is unknown, the result is unknown.
|
|
if (isUnknown() || Other.isUnknown())
|
|
return VSETVLIInfo::getUnknown();
|
|
|
|
// If we have an exact, match return this.
|
|
if (*this == Other)
|
|
return *this;
|
|
|
|
// Not an exact match, but maybe the AVL and VLMAX are the same. If so,
|
|
// return an SEW/LMUL ratio only value.
|
|
if (hasSameAVL(Other) && hasSameVLMAX(Other)) {
|
|
VSETVLIInfo MergeInfo = *this;
|
|
MergeInfo.SEWLMULRatioOnly = true;
|
|
return MergeInfo;
|
|
}
|
|
|
|
// Otherwise the result is unknown.
|
|
return VSETVLIInfo::getUnknown();
|
|
}
|
|
|
|
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
|
/// Support for debugging, callable in GDB: V->dump()
|
|
LLVM_DUMP_METHOD void dump() const {
|
|
print(dbgs());
|
|
dbgs() << "\n";
|
|
}
|
|
|
|
/// Implement operator<<.
|
|
/// @{
|
|
void print(raw_ostream &OS) const {
|
|
OS << '{';
|
|
switch (State) {
|
|
case AVLState::Uninitialized:
|
|
OS << "Uninitialized";
|
|
break;
|
|
case AVLState::Unknown:
|
|
OS << "unknown";
|
|
break;
|
|
case AVLState::AVLIsReg:
|
|
OS << "AVLReg=" << llvm::printReg(getAVLReg());
|
|
break;
|
|
case AVLState::AVLIsImm:
|
|
OS << "AVLImm=" << (unsigned)AVLImm;
|
|
break;
|
|
case AVLState::AVLIsVLMAX:
|
|
OS << "AVLVLMAX";
|
|
break;
|
|
}
|
|
if (isKnown()) {
|
|
OS << ", ";
|
|
|
|
unsigned LMul;
|
|
bool Fractional;
|
|
std::tie(LMul, Fractional) = decodeVLMUL(VLMul);
|
|
|
|
OS << "VLMul=m";
|
|
if (Fractional)
|
|
OS << 'f';
|
|
OS << LMul << ", "
|
|
<< "SEW=e" << (unsigned)SEW << ", "
|
|
<< "TailAgnostic=" << (bool)TailAgnostic << ", "
|
|
<< "MaskAgnostic=" << (bool)MaskAgnostic << ", "
|
|
<< "SEWLMULRatioOnly=" << (bool)SEWLMULRatioOnly << ", "
|
|
<< "TWiden=" << (unsigned)TWiden << ", "
|
|
<< "AltFmt=" << (bool)AltFmt;
|
|
}
|
|
|
|
OS << '}';
|
|
}
|
|
#endif
|
|
};
|
|
|
|
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
|
LLVM_ATTRIBUTE_USED
|
|
inline raw_ostream &operator<<(raw_ostream &OS, const VSETVLIInfo &V) {
|
|
V.print(OS);
|
|
return OS;
|
|
}
|
|
#endif
|
|
|
|
class RISCVVSETVLIInfoAnalysis {
|
|
const RISCVSubtarget *ST;
|
|
// Possibly null!
|
|
LiveIntervals *LIS;
|
|
|
|
public:
|
|
RISCVVSETVLIInfoAnalysis() = default;
|
|
RISCVVSETVLIInfoAnalysis(const RISCVSubtarget *ST, LiveIntervals *LIS)
|
|
: ST(ST), LIS(LIS) {}
|
|
|
|
VSETVLIInfo getInfoForVSETVLI(const MachineInstr &MI) const;
|
|
VSETVLIInfo computeInfoForInstr(const MachineInstr &MI) const;
|
|
|
|
private:
|
|
void forwardVSETVLIAVL(VSETVLIInfo &Info) const;
|
|
};
|
|
|
|
} // namespace RISCV
|
|
} // namespace llvm
|