#include "RISCV.h"
#include "RISCVSubtarget.h"
#include "llvm/CodeGen/LiveIntervals.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include <queue>
using namespace llvm;
#define DEBUG_TYPE "riscv-insert-vsetvli"
#define RISCV_INSERT_VSETVLI_NAME "RISCV Insert VSETVLI pass"
static cl::opt<bool> DisableInsertVSETVLPHIOpt(
"riscv-disable-insert-vsetvl-phi-opt", cl::init(false), cl::Hidden,
cl::desc("Disable looking through phis when inserting vsetvlis."));
static cl::opt<bool> UseStrictAsserts(
"riscv-insert-vsetvl-strict-asserts", cl::init(true), cl::Hidden,
cl::desc("Enable strict assertion checking for the dataflow algorithm"));
namespace {
static unsigned getVLOpNum(const MachineInstr &MI) {
return RISCVII::getVLOpNum(MI.getDesc());
}
static unsigned getSEWOpNum(const MachineInstr &MI) {
return RISCVII::getSEWOpNum(MI.getDesc());
}
static bool isScalarMoveInstr(const MachineInstr &MI) {
switch (MI.getOpcode()) {
default:
return false;
case RISCV::PseudoVMV_S_X_M1:
case RISCV::PseudoVMV_S_X_M2:
case RISCV::PseudoVMV_S_X_M4:
case RISCV::PseudoVMV_S_X_M8:
case RISCV::PseudoVMV_S_X_MF2:
case RISCV::PseudoVMV_S_X_MF4:
case RISCV::PseudoVMV_S_X_MF8:
case RISCV::PseudoVFMV_S_F16_M1:
case RISCV::PseudoVFMV_S_F16_M2:
case RISCV::PseudoVFMV_S_F16_M4:
case RISCV::PseudoVFMV_S_F16_M8:
case RISCV::PseudoVFMV_S_F16_MF2:
case RISCV::PseudoVFMV_S_F16_MF4:
case RISCV::PseudoVFMV_S_F32_M1:
case RISCV::PseudoVFMV_S_F32_M2:
case RISCV::PseudoVFMV_S_F32_M4:
case RISCV::PseudoVFMV_S_F32_M8:
case RISCV::PseudoVFMV_S_F32_MF2:
case RISCV::PseudoVFMV_S_F64_M1:
case RISCV::PseudoVFMV_S_F64_M2:
case RISCV::PseudoVFMV_S_F64_M4:
case RISCV::PseudoVFMV_S_F64_M8:
return true;
}
}
static Optional<unsigned> getEEWForLoadStore(const MachineInstr &MI) {
switch (MI.getOpcode()) {
default:
return None;
case RISCV::PseudoVLE8_V_M1:
case RISCV::PseudoVLE8_V_M1_MASK:
case RISCV::PseudoVLE8_V_M2:
case RISCV::PseudoVLE8_V_M2_MASK:
case RISCV::PseudoVLE8_V_M4:
case RISCV::PseudoVLE8_V_M4_MASK:
case RISCV::PseudoVLE8_V_M8:
case RISCV::PseudoVLE8_V_M8_MASK:
case RISCV::PseudoVLE8_V_MF2:
case RISCV::PseudoVLE8_V_MF2_MASK:
case RISCV::PseudoVLE8_V_MF4:
case RISCV::PseudoVLE8_V_MF4_MASK:
case RISCV::PseudoVLE8_V_MF8:
case RISCV::PseudoVLE8_V_MF8_MASK:
case RISCV::PseudoVLSE8_V_M1:
case RISCV::PseudoVLSE8_V_M1_MASK:
case RISCV::PseudoVLSE8_V_M2:
case RISCV::PseudoVLSE8_V_M2_MASK:
case RISCV::PseudoVLSE8_V_M4:
case RISCV::PseudoVLSE8_V_M4_MASK:
case RISCV::PseudoVLSE8_V_M8:
case RISCV::PseudoVLSE8_V_M8_MASK:
case RISCV::PseudoVLSE8_V_MF2:
case RISCV::PseudoVLSE8_V_MF2_MASK:
case RISCV::PseudoVLSE8_V_MF4:
case RISCV::PseudoVLSE8_V_MF4_MASK:
case RISCV::PseudoVLSE8_V_MF8:
case RISCV::PseudoVLSE8_V_MF8_MASK:
case RISCV::PseudoVSE8_V_M1:
case RISCV::PseudoVSE8_V_M1_MASK:
case RISCV::PseudoVSE8_V_M2:
case RISCV::PseudoVSE8_V_M2_MASK:
case RISCV::PseudoVSE8_V_M4:
case RISCV::PseudoVSE8_V_M4_MASK:
case RISCV::PseudoVSE8_V_M8:
case RISCV::PseudoVSE8_V_M8_MASK:
case RISCV::PseudoVSE8_V_MF2:
case RISCV::PseudoVSE8_V_MF2_MASK:
case RISCV::PseudoVSE8_V_MF4:
case RISCV::PseudoVSE8_V_MF4_MASK:
case RISCV::PseudoVSE8_V_MF8:
case RISCV::PseudoVSE8_V_MF8_MASK:
case RISCV::PseudoVSSE8_V_M1:
case RISCV::PseudoVSSE8_V_M1_MASK:
case RISCV::PseudoVSSE8_V_M2:
case RISCV::PseudoVSSE8_V_M2_MASK:
case RISCV::PseudoVSSE8_V_M4:
case RISCV::PseudoVSSE8_V_M4_MASK:
case RISCV::PseudoVSSE8_V_M8:
case RISCV::PseudoVSSE8_V_M8_MASK:
case RISCV::PseudoVSSE8_V_MF2:
case RISCV::PseudoVSSE8_V_MF2_MASK:
case RISCV::PseudoVSSE8_V_MF4:
case RISCV::PseudoVSSE8_V_MF4_MASK:
case RISCV::PseudoVSSE8_V_MF8:
case RISCV::PseudoVSSE8_V_MF8_MASK:
return 8;
case RISCV::PseudoVLE16_V_M1:
case RISCV::PseudoVLE16_V_M1_MASK:
case RISCV::PseudoVLE16_V_M2:
case RISCV::PseudoVLE16_V_M2_MASK:
case RISCV::PseudoVLE16_V_M4:
case RISCV::PseudoVLE16_V_M4_MASK:
case RISCV::PseudoVLE16_V_M8:
case RISCV::PseudoVLE16_V_M8_MASK:
case RISCV::PseudoVLE16_V_MF2:
case RISCV::PseudoVLE16_V_MF2_MASK:
case RISCV::PseudoVLE16_V_MF4:
case RISCV::PseudoVLE16_V_MF4_MASK:
case RISCV::PseudoVLSE16_V_M1:
case RISCV::PseudoVLSE16_V_M1_MASK:
case RISCV::PseudoVLSE16_V_M2:
case RISCV::PseudoVLSE16_V_M2_MASK:
case RISCV::PseudoVLSE16_V_M4:
case RISCV::PseudoVLSE16_V_M4_MASK:
case RISCV::PseudoVLSE16_V_M8:
case RISCV::PseudoVLSE16_V_M8_MASK:
case RISCV::PseudoVLSE16_V_MF2:
case RISCV::PseudoVLSE16_V_MF2_MASK:
case RISCV::PseudoVLSE16_V_MF4:
case RISCV::PseudoVLSE16_V_MF4_MASK:
case RISCV::PseudoVSE16_V_M1:
case RISCV::PseudoVSE16_V_M1_MASK:
case RISCV::PseudoVSE16_V_M2:
case RISCV::PseudoVSE16_V_M2_MASK:
case RISCV::PseudoVSE16_V_M4:
case RISCV::PseudoVSE16_V_M4_MASK:
case RISCV::PseudoVSE16_V_M8:
case RISCV::PseudoVSE16_V_M8_MASK:
case RISCV::PseudoVSE16_V_MF2:
case RISCV::PseudoVSE16_V_MF2_MASK:
case RISCV::PseudoVSE16_V_MF4:
case RISCV::PseudoVSE16_V_MF4_MASK:
case RISCV::PseudoVSSE16_V_M1:
case RISCV::PseudoVSSE16_V_M1_MASK:
case RISCV::PseudoVSSE16_V_M2:
case RISCV::PseudoVSSE16_V_M2_MASK:
case RISCV::PseudoVSSE16_V_M4:
case RISCV::PseudoVSSE16_V_M4_MASK:
case RISCV::PseudoVSSE16_V_M8:
case RISCV::PseudoVSSE16_V_M8_MASK:
case RISCV::PseudoVSSE16_V_MF2:
case RISCV::PseudoVSSE16_V_MF2_MASK:
case RISCV::PseudoVSSE16_V_MF4:
case RISCV::PseudoVSSE16_V_MF4_MASK:
return 16;
case RISCV::PseudoVLE32_V_M1:
case RISCV::PseudoVLE32_V_M1_MASK:
case RISCV::PseudoVLE32_V_M2:
case RISCV::PseudoVLE32_V_M2_MASK:
case RISCV::PseudoVLE32_V_M4:
case RISCV::PseudoVLE32_V_M4_MASK:
case RISCV::PseudoVLE32_V_M8:
case RISCV::PseudoVLE32_V_M8_MASK:
case RISCV::PseudoVLE32_V_MF2:
case RISCV::PseudoVLE32_V_MF2_MASK:
case RISCV::PseudoVLSE32_V_M1:
case RISCV::PseudoVLSE32_V_M1_MASK:
case RISCV::PseudoVLSE32_V_M2:
case RISCV::PseudoVLSE32_V_M2_MASK:
case RISCV::PseudoVLSE32_V_M4:
case RISCV::PseudoVLSE32_V_M4_MASK:
case RISCV::PseudoVLSE32_V_M8:
case RISCV::PseudoVLSE32_V_M8_MASK:
case RISCV::PseudoVLSE32_V_MF2:
case RISCV::PseudoVLSE32_V_MF2_MASK:
case RISCV::PseudoVSE32_V_M1:
case RISCV::PseudoVSE32_V_M1_MASK:
case RISCV::PseudoVSE32_V_M2:
case RISCV::PseudoVSE32_V_M2_MASK:
case RISCV::PseudoVSE32_V_M4:
case RISCV::PseudoVSE32_V_M4_MASK:
case RISCV::PseudoVSE32_V_M8:
case RISCV::PseudoVSE32_V_M8_MASK:
case RISCV::PseudoVSE32_V_MF2:
case RISCV::PseudoVSE32_V_MF2_MASK:
case RISCV::PseudoVSSE32_V_M1:
case RISCV::PseudoVSSE32_V_M1_MASK:
case RISCV::PseudoVSSE32_V_M2:
case RISCV::PseudoVSSE32_V_M2_MASK:
case RISCV::PseudoVSSE32_V_M4:
case RISCV::PseudoVSSE32_V_M4_MASK:
case RISCV::PseudoVSSE32_V_M8:
case RISCV::PseudoVSSE32_V_M8_MASK:
case RISCV::PseudoVSSE32_V_MF2:
case RISCV::PseudoVSSE32_V_MF2_MASK:
return 32;
case RISCV::PseudoVLE64_V_M1:
case RISCV::PseudoVLE64_V_M1_MASK:
case RISCV::PseudoVLE64_V_M2:
case RISCV::PseudoVLE64_V_M2_MASK:
case RISCV::PseudoVLE64_V_M4:
case RISCV::PseudoVLE64_V_M4_MASK:
case RISCV::PseudoVLE64_V_M8:
case RISCV::PseudoVLE64_V_M8_MASK:
case RISCV::PseudoVLSE64_V_M1:
case RISCV::PseudoVLSE64_V_M1_MASK:
case RISCV::PseudoVLSE64_V_M2:
case RISCV::PseudoVLSE64_V_M2_MASK:
case RISCV::PseudoVLSE64_V_M4:
case RISCV::PseudoVLSE64_V_M4_MASK:
case RISCV::PseudoVLSE64_V_M8:
case RISCV::PseudoVLSE64_V_M8_MASK:
case RISCV::PseudoVSE64_V_M1:
case RISCV::PseudoVSE64_V_M1_MASK:
case RISCV::PseudoVSE64_V_M2:
case RISCV::PseudoVSE64_V_M2_MASK:
case RISCV::PseudoVSE64_V_M4:
case RISCV::PseudoVSE64_V_M4_MASK:
case RISCV::PseudoVSE64_V_M8:
case RISCV::PseudoVSE64_V_M8_MASK:
case RISCV::PseudoVSSE64_V_M1:
case RISCV::PseudoVSSE64_V_M1_MASK:
case RISCV::PseudoVSSE64_V_M2:
case RISCV::PseudoVSSE64_V_M2_MASK:
case RISCV::PseudoVSSE64_V_M4:
case RISCV::PseudoVSSE64_V_M4_MASK:
case RISCV::PseudoVSSE64_V_M8:
case RISCV::PseudoVSSE64_V_M8_MASK:
return 64;
}
}
static bool isMaskRegOp(const MachineInstr &MI) {
if (RISCVII::hasSEWOp(MI.getDesc().TSFlags)) {
const unsigned Log2SEW = MI.getOperand(getSEWOpNum(MI)).getImm();
return Log2SEW == 0;
}
return false;
}
static unsigned getSEWLMULRatio(unsigned SEW, RISCVII::VLMUL VLMul) {
unsigned LMul;
bool Fractional;
std::tie(LMul, Fractional) = RISCVVType::decodeVLMUL(VLMul);
LMul = Fractional ? (8 / LMul) : (LMul * 8);
assert(SEW >= 8 && "Unexpected SEW value");
return (SEW * 8) / LMul;
}
struct DemandedFields {
bool VL = false;
bool SEW = false;
bool LMUL = false;
bool SEWLMULRatio = false;
bool TailPolicy = false;
bool MaskPolicy = false;
bool usedVTYPE() {
return SEW || LMUL || SEWLMULRatio || TailPolicy || MaskPolicy;
}
void demandVTYPE() {
SEW = true;
LMUL = true;
SEWLMULRatio = true;
TailPolicy = true;
MaskPolicy = true;
}
};
static bool areCompatibleVTYPEs(uint64_t VType1,
uint64_t VType2,
const DemandedFields &Used) {
if (Used.SEW &&
RISCVVType::getSEW(VType1) != RISCVVType::getSEW(VType2))
return false;
if (Used.LMUL &&
RISCVVType::getVLMUL(VType1) != RISCVVType::getVLMUL(VType2))
return false;
if (Used.SEWLMULRatio) {
auto Ratio1 = getSEWLMULRatio(RISCVVType::getSEW(VType1),
RISCVVType::getVLMUL(VType1));
auto Ratio2 = getSEWLMULRatio(RISCVVType::getSEW(VType2),
RISCVVType::getVLMUL(VType2));
if (Ratio1 != Ratio2)
return false;
}
if (Used.TailPolicy &&
RISCVVType::isTailAgnostic(VType1) != RISCVVType::isTailAgnostic(VType2))
return false;
if (Used.MaskPolicy &&
RISCVVType::isMaskAgnostic(VType1) != RISCVVType::isMaskAgnostic(VType2))
return false;
return true;
}
static DemandedFields getDemanded(const MachineInstr &MI) {
DemandedFields Res;
if (MI.isCall() || MI.isInlineAsm() || MI.readsRegister(RISCV::VL))
Res.VL = true;
if (MI.isCall() || MI.isInlineAsm() || MI.readsRegister(RISCV::VTYPE))
Res.demandVTYPE();
uint64_t TSFlags = MI.getDesc().TSFlags;
if (RISCVII::hasSEWOp(TSFlags)) {
Res.demandVTYPE();
if (RISCVII::hasVLOp(TSFlags))
Res.VL = true;
}
if (getEEWForLoadStore(MI)) {
Res.SEW = false;
Res.LMUL = false;
}
if (RISCVII::hasSEWOp(TSFlags) && MI.getNumExplicitDefs() == 0) {
Res.TailPolicy = false;
Res.MaskPolicy = false;
}
if (isMaskRegOp(MI)) {
Res.SEW = false;
Res.LMUL = false;
}
return Res;
}
class VSETVLIInfo {
union {
Register AVLReg;
unsigned AVLImm;
};
enum : uint8_t {
Uninitialized,
AVLIsReg,
AVLIsImm,
Unknown,
} State = Uninitialized;
RISCVII::VLMUL VLMul = RISCVII::LMUL_1;
uint8_t SEW = 0;
uint8_t TailAgnostic : 1;
uint8_t MaskAgnostic : 1;
uint8_t SEWLMULRatioOnly : 1;
public:
VSETVLIInfo()
: AVLImm(0), TailAgnostic(false), MaskAgnostic(false),
SEWLMULRatioOnly(false) {}
static VSETVLIInfo getUnknown() {
VSETVLIInfo Info;
Info.setUnknown();
return Info;
}
bool isValid() const { return State != Uninitialized; }
void setUnknown() { State = Unknown; }
bool isUnknown() const { return State == Unknown; }
void setAVLReg(Register Reg) {
AVLReg = Reg;
State = AVLIsReg;
}
void setAVLImm(unsigned Imm) {
AVLImm = Imm;
State = AVLIsImm;
}
bool hasAVLImm() const { return State == AVLIsImm; }
bool hasAVLReg() const { return State == AVLIsReg; }
Register getAVLReg() const {
assert(hasAVLReg());
return AVLReg;
}
unsigned getAVLImm() const {
assert(hasAVLImm());
return AVLImm;
}
unsigned getSEW() const { return SEW; }
RISCVII::VLMUL getVLMUL() const { return VLMul; }
bool hasNonZeroAVL() const {
if (hasAVLImm())
return getAVLImm() > 0;
if (hasAVLReg())
return getAVLReg() == RISCV::X0;
return false;
}
bool hasSameAVL(const VSETVLIInfo &Other) const {
assert(isValid() && Other.isValid() &&
"Can't compare invalid VSETVLIInfos");
assert(!isUnknown() && !Other.isUnknown() &&
"Can't compare AVL in unknown state");
if (hasAVLReg() && Other.hasAVLReg())
return getAVLReg() == Other.getAVLReg();
if (hasAVLImm() && Other.hasAVLImm())
return getAVLImm() == Other.getAVLImm();
return false;
}
void setVTYPE(unsigned VType) {
assert(isValid() && !isUnknown() &&
"Can't set VTYPE for uninitialized or unknown");
VLMul = RISCVVType::getVLMUL(VType);
SEW = RISCVVType::getSEW(VType);
TailAgnostic = RISCVVType::isTailAgnostic(VType);
MaskAgnostic = RISCVVType::isMaskAgnostic(VType);
}
void setVTYPE(RISCVII::VLMUL L, unsigned S, bool TA, bool MA) {
assert(isValid() && !isUnknown() &&
"Can't set VTYPE for uninitialized or unknown");
VLMul = L;
SEW = S;
TailAgnostic = TA;
MaskAgnostic = MA;
}
unsigned encodeVTYPE() const {
assert(isValid() && !isUnknown() && !SEWLMULRatioOnly &&
"Can't encode VTYPE for uninitialized or unknown");
return RISCVVType::encodeVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic);
}
bool hasSEWLMULRatioOnly() const { return SEWLMULRatioOnly; }
bool hasSameSEW(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 SEW == Other.SEW;
}
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) ==
std::tie(Other.VLMul, Other.SEW, Other.TailAgnostic,
Other.MaskAgnostic);
}
unsigned getSEWLMULRatio() const {
assert(isValid() && !isUnknown() &&
"Can't use VTYPE for uninitialized or unknown");
return ::getSEWLMULRatio(SEW, VLMul);
}
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");
return getSEWLMULRatio() == Other.getSEWLMULRatio();
}
bool hasSamePolicy(const VSETVLIInfo &Other) const {
assert(isValid() && Other.isValid() &&
"Can't compare invalid VSETVLIInfos");
assert(!isUnknown() && !Other.isUnknown() &&
"Can't compare VTYPE in unknown state");
return TailAgnostic == Other.TailAgnostic &&
MaskAgnostic == Other.MaskAgnostic;
}
bool hasCompatibleVTYPE(const MachineInstr &MI,
const VSETVLIInfo &Require) const {
const DemandedFields Used = getDemanded(MI);
return areCompatibleVTYPEs(encodeVTYPE(), Require.encodeVTYPE(), Used);
}
bool isCompatible(const MachineInstr &MI, const VSETVLIInfo &Require) const {
assert(isValid() && Require.isValid() &&
"Can't compare invalid VSETVLIInfos");
assert(!Require.SEWLMULRatioOnly &&
"Expected a valid VTYPE for instruction!");
if (isUnknown() || Require.isUnknown())
return false;
if (SEWLMULRatioOnly)
return false;
if (Require.hasAVLReg() && Require.AVLReg == RISCV::NoRegister)
if (SEW == Require.SEW)
return true;
return hasSameAVL(Require) && hasCompatibleVTYPE(MI, Require);
}
bool operator==(const VSETVLIInfo &Other) const {
if (!isValid())
return !Other.isValid();
if (!Other.isValid())
return !isValid();
if (isUnknown())
return Other.isUnknown();
if (Other.isUnknown())
return isUnknown();
if (!hasSameAVL(Other))
return false;
if (SEWLMULRatioOnly != Other.SEWLMULRatioOnly)
return false;
if (SEWLMULRatioOnly)
return hasSameVLMAX(Other);
return hasSameVTYPE(Other);
}
bool operator!=(const VSETVLIInfo &Other) const {
return !(*this == Other);
}
VSETVLIInfo intersect(const VSETVLIInfo &Other) const {
if (!Other.isValid())
return *this;
if (!isValid())
return Other;
if (isUnknown() || Other.isUnknown())
return VSETVLIInfo::getUnknown();
if (*this == Other)
return *this;
if (hasSameAVL(Other) && hasSameVLMAX(Other)) {
VSETVLIInfo MergeInfo = *this;
MergeInfo.SEWLMULRatioOnly = true;
return MergeInfo;
}
return VSETVLIInfo::getUnknown();
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void dump() const {
print(dbgs());
dbgs() << "\n";
}
void print(raw_ostream &OS) const {
OS << "{";
if (!isValid())
OS << "Uninitialized";
if (isUnknown())
OS << "unknown";
if (hasAVLReg())
OS << "AVLReg=" << (unsigned)AVLReg;
if (hasAVLImm())
OS << "AVLImm=" << (unsigned)AVLImm;
OS << ", "
<< "VLMul=" << (unsigned)VLMul << ", "
<< "SEW=" << (unsigned)SEW << ", "
<< "TailAgnostic=" << (bool)TailAgnostic << ", "
<< "MaskAgnostic=" << (bool)MaskAgnostic << ", "
<< "SEWLMULRatioOnly=" << (bool)SEWLMULRatioOnly << "}";
}
#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
struct BlockData {
VSETVLIInfo Change;
VSETVLIInfo Exit;
VSETVLIInfo Pred;
bool InQueue = false;
BlockData() = default;
};
class RISCVInsertVSETVLI : public MachineFunctionPass {
const TargetInstrInfo *TII;
MachineRegisterInfo *MRI;
std::vector<BlockData> BlockInfo;
std::queue<const MachineBasicBlock *> WorkList;
public:
static char ID;
RISCVInsertVSETVLI() : MachineFunctionPass(ID) {
initializeRISCVInsertVSETVLIPass(*PassRegistry::getPassRegistry());
}
bool runOnMachineFunction(MachineFunction &MF) override;
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesCFG();
MachineFunctionPass::getAnalysisUsage(AU);
}
StringRef getPassName() const override { return RISCV_INSERT_VSETVLI_NAME; }
private:
bool needVSETVLI(const MachineInstr &MI, const VSETVLIInfo &Require,
const VSETVLIInfo &CurInfo) const;
bool needVSETVLIPHI(const VSETVLIInfo &Require,
const MachineBasicBlock &MBB) const;
void insertVSETVLI(MachineBasicBlock &MBB, MachineInstr &MI,
const VSETVLIInfo &Info, const VSETVLIInfo &PrevInfo);
void insertVSETVLI(MachineBasicBlock &MBB,
MachineBasicBlock::iterator InsertPt, DebugLoc DL,
const VSETVLIInfo &Info, const VSETVLIInfo &PrevInfo);
void transferBefore(VSETVLIInfo &Info, const MachineInstr &MI);
void transferAfter(VSETVLIInfo &Info, const MachineInstr &MI);
bool computeVLVTYPEChanges(const MachineBasicBlock &MBB);
void computeIncomingVLVTYPE(const MachineBasicBlock &MBB);
void emitVSETVLIs(MachineBasicBlock &MBB);
void doLocalPostpass(MachineBasicBlock &MBB);
void doPRE(MachineBasicBlock &MBB);
void insertReadVL(MachineBasicBlock &MBB);
};
}
char RISCVInsertVSETVLI::ID = 0;
INITIALIZE_PASS(RISCVInsertVSETVLI, DEBUG_TYPE, RISCV_INSERT_VSETVLI_NAME,
false, false)
static bool isVectorConfigInstr(const MachineInstr &MI) {
return MI.getOpcode() == RISCV::PseudoVSETVLI ||
MI.getOpcode() == RISCV::PseudoVSETVLIX0 ||
MI.getOpcode() == RISCV::PseudoVSETIVLI;
}
static bool isVLPreservingConfig(const MachineInstr &MI) {
if (MI.getOpcode() != RISCV::PseudoVSETVLIX0)
return false;
assert(RISCV::X0 == MI.getOperand(1).getReg());
return RISCV::X0 == MI.getOperand(0).getReg();
}
static VSETVLIInfo computeInfoForInstr(const MachineInstr &MI, uint64_t TSFlags,
const MachineRegisterInfo *MRI) {
VSETVLIInfo InstrInfo;
bool TailAgnostic = true;
bool UsesMaskPolicy = RISCVII::usesMaskPolicy(TSFlags);
bool MaskAgnostic = UsesMaskPolicy;
unsigned UseOpIdx;
if (RISCVII::hasVecPolicyOp(TSFlags)) {
const MachineOperand &Op = MI.getOperand(MI.getNumExplicitOperands() - 1);
uint64_t Policy = Op.getImm();
assert(Policy <= (RISCVII::TAIL_AGNOSTIC | RISCVII::MASK_AGNOSTIC) &&
"Invalid Policy Value");
TailAgnostic = Policy & RISCVII::TAIL_AGNOSTIC;
MaskAgnostic = Policy & RISCVII::MASK_AGNOSTIC;
} else if (MI.isRegTiedToUseOperand(0, &UseOpIdx)) {
TailAgnostic = false;
if (UsesMaskPolicy)
MaskAgnostic = false;
const MachineOperand &UseMO = MI.getOperand(UseOpIdx);
MachineInstr *UseMI = MRI->getVRegDef(UseMO.getReg());
if (UseMI && UseMI->isImplicitDef()) {
TailAgnostic = true;
if (UsesMaskPolicy)
MaskAgnostic = true;
}
if (RISCVII::doesForceTailAgnostic(TSFlags))
TailAgnostic = true;
}
RISCVII::VLMUL VLMul = RISCVII::getLMul(TSFlags);
unsigned Log2SEW = MI.getOperand(getSEWOpNum(MI)).getImm();
unsigned SEW = Log2SEW ? 1 << Log2SEW : 8;
assert(RISCVVType::isValidSEW(SEW) && "Unexpected SEW");
if (RISCVII::hasVLOp(TSFlags)) {
const MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI));
if (VLOp.isImm()) {
int64_t Imm = VLOp.getImm();
if (Imm == RISCV::VLMaxSentinel)
InstrInfo.setAVLReg(RISCV::X0);
else
InstrInfo.setAVLImm(Imm);
} else {
InstrInfo.setAVLReg(VLOp.getReg());
}
} else {
InstrInfo.setAVLReg(RISCV::NoRegister);
}
#ifndef NDEBUG
if (Optional<unsigned> EEW = getEEWForLoadStore(MI)) {
assert(SEW == EEW && "Initial SEW doesn't match expected EEW");
}
#endif
InstrInfo.setVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic);
return InstrInfo;
}
void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB, MachineInstr &MI,
const VSETVLIInfo &Info,
const VSETVLIInfo &PrevInfo) {
DebugLoc DL = MI.getDebugLoc();
insertVSETVLI(MBB, MachineBasicBlock::iterator(&MI), DL, Info, PrevInfo);
}
void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB,
MachineBasicBlock::iterator InsertPt, DebugLoc DL,
const VSETVLIInfo &Info, const VSETVLIInfo &PrevInfo) {
if (PrevInfo.isValid() && !PrevInfo.isUnknown() &&
Info.hasSameAVL(PrevInfo) && Info.hasSameVLMAX(PrevInfo)) {
BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0))
.addReg(RISCV::X0, RegState::Define | RegState::Dead)
.addReg(RISCV::X0, RegState::Kill)
.addImm(Info.encodeVTYPE())
.addReg(RISCV::VL, RegState::Implicit);
return;
}
if (Info.hasAVLImm()) {
BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETIVLI))
.addReg(RISCV::X0, RegState::Define | RegState::Dead)
.addImm(Info.getAVLImm())
.addImm(Info.encodeVTYPE());
return;
}
Register AVLReg = Info.getAVLReg();
if (AVLReg == RISCV::NoRegister) {
if (PrevInfo.isValid() && !PrevInfo.isUnknown() &&
Info.hasSameVLMAX(PrevInfo)) {
BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0))
.addReg(RISCV::X0, RegState::Define | RegState::Dead)
.addReg(RISCV::X0, RegState::Kill)
.addImm(Info.encodeVTYPE())
.addReg(RISCV::VL, RegState::Implicit);
return;
}
BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETIVLI))
.addReg(RISCV::X0, RegState::Define | RegState::Dead)
.addImm(0)
.addImm(Info.encodeVTYPE());
return;
}
if (AVLReg.isVirtual())
MRI->constrainRegClass(AVLReg, &RISCV::GPRNoX0RegClass);
Register DestReg = RISCV::X0;
unsigned Opcode = RISCV::PseudoVSETVLI;
if (AVLReg == RISCV::X0) {
DestReg = MRI->createVirtualRegister(&RISCV::GPRRegClass);
Opcode = RISCV::PseudoVSETVLIX0;
}
BuildMI(MBB, InsertPt, DL, TII->get(Opcode))
.addReg(DestReg, RegState::Define | RegState::Dead)
.addReg(AVLReg)
.addImm(Info.encodeVTYPE());
}
static VSETVLIInfo getInfoForVSETVLI(const MachineInstr &MI) {
VSETVLIInfo NewInfo;
if (MI.getOpcode() == RISCV::PseudoVSETIVLI) {
NewInfo.setAVLImm(MI.getOperand(1).getImm());
} else {
assert(MI.getOpcode() == RISCV::PseudoVSETVLI ||
MI.getOpcode() == RISCV::PseudoVSETVLIX0);
Register AVLReg = MI.getOperand(1).getReg();
assert((AVLReg != RISCV::X0 || MI.getOperand(0).getReg() != RISCV::X0) &&
"Can't handle X0, X0 vsetvli yet");
NewInfo.setAVLReg(AVLReg);
}
NewInfo.setVTYPE(MI.getOperand(2).getImm());
return NewInfo;
}
bool RISCVInsertVSETVLI::needVSETVLI(const MachineInstr &MI,
const VSETVLIInfo &Require,
const VSETVLIInfo &CurInfo) const {
assert(Require == computeInfoForInstr(MI, MI.getDesc().TSFlags, MRI));
if (CurInfo.isCompatible(MI, Require))
return false;
if (!CurInfo.isValid() || CurInfo.isUnknown() || CurInfo.hasSEWLMULRatioOnly())
return true;
if (isScalarMoveInstr(MI) &&
CurInfo.hasNonZeroAVL() && Require.hasNonZeroAVL()) {
auto *VRegDef = MRI->getVRegDef(MI.getOperand(1).getReg());
if (VRegDef && VRegDef->isImplicitDef() &&
CurInfo.getSEW() >= Require.getSEW())
return false;
if (CurInfo.hasSameSEW(Require) && CurInfo.hasSamePolicy(Require))
return false;
}
if (Require.hasAVLReg() && Require.getAVLReg().isVirtual() &&
CurInfo.hasCompatibleVTYPE(MI, Require)) {
if (MachineInstr *DefMI = MRI->getVRegDef(Require.getAVLReg())) {
if (isVectorConfigInstr(*DefMI)) {
VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI);
if (DefInfo.hasSameAVL(CurInfo) && DefInfo.hasSameVLMAX(CurInfo))
return false;
}
}
}
return true;
}
void RISCVInsertVSETVLI::transferBefore(VSETVLIInfo &Info, const MachineInstr &MI) {
uint64_t TSFlags = MI.getDesc().TSFlags;
if (!RISCVII::hasSEWOp(TSFlags))
return;
const VSETVLIInfo NewInfo = computeInfoForInstr(MI, TSFlags, MRI);
if (Info.isValid() && !needVSETVLI(MI, NewInfo, Info))
return;
const VSETVLIInfo PrevInfo = Info;
Info = NewInfo;
if (!RISCVII::hasVLOp(TSFlags))
return;
if (isScalarMoveInstr(MI) && PrevInfo.isValid() &&
PrevInfo.hasNonZeroAVL() && Info.hasNonZeroAVL() &&
Info.hasSameVLMAX(PrevInfo)) {
if (PrevInfo.hasAVLImm())
Info.setAVLImm(PrevInfo.getAVLImm());
else
Info.setAVLReg(PrevInfo.getAVLReg());
return;
}
if (!Info.hasAVLReg() || !Info.getAVLReg().isVirtual())
return;
MachineInstr *DefMI = MRI->getVRegDef(Info.getAVLReg());
if (!DefMI || !isVectorConfigInstr(*DefMI))
return;
VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI);
if (DefInfo.hasSameVLMAX(Info) &&
(DefInfo.hasAVLImm() || DefInfo.getAVLReg() == RISCV::X0)) {
if (DefInfo.hasAVLImm())
Info.setAVLImm(DefInfo.getAVLImm());
else
Info.setAVLReg(DefInfo.getAVLReg());
return;
}
}
void RISCVInsertVSETVLI::transferAfter(VSETVLIInfo &Info, const MachineInstr &MI) {
if (isVectorConfigInstr(MI)) {
Info = getInfoForVSETVLI(MI);
return;
}
if (RISCV::isFaultFirstLoad(MI)) {
Info.setAVLReg(MI.getOperand(1).getReg());
return;
}
if (MI.isCall() || MI.isInlineAsm() || MI.modifiesRegister(RISCV::VL) ||
MI.modifiesRegister(RISCV::VTYPE))
Info = VSETVLIInfo::getUnknown();
}
bool RISCVInsertVSETVLI::computeVLVTYPEChanges(const MachineBasicBlock &MBB) {
bool HadVectorOp = false;
BlockData &BBInfo = BlockInfo[MBB.getNumber()];
BBInfo.Change = BBInfo.Pred;
for (const MachineInstr &MI : MBB) {
transferBefore(BBInfo.Change, MI);
if (isVectorConfigInstr(MI) || RISCVII::hasSEWOp(MI.getDesc().TSFlags))
HadVectorOp = true;
transferAfter(BBInfo.Change, MI);
}
return HadVectorOp;
}
void RISCVInsertVSETVLI::computeIncomingVLVTYPE(const MachineBasicBlock &MBB) {
BlockData &BBInfo = BlockInfo[MBB.getNumber()];
BBInfo.InQueue = false;
VSETVLIInfo InInfo;
if (MBB.pred_empty()) {
InInfo.setUnknown();
} else {
for (MachineBasicBlock *P : MBB.predecessors())
InInfo = InInfo.intersect(BlockInfo[P->getNumber()].Exit);
}
if (!InInfo.isValid())
return;
if (InInfo == BBInfo.Pred)
return;
BBInfo.Pred = InInfo;
LLVM_DEBUG(dbgs() << "Entry state of " << printMBBReference(MBB)
<< " changed to " << BBInfo.Pred << "\n");
computeVLVTYPEChanges(MBB);
VSETVLIInfo TmpStatus = BBInfo.Change;
if (BBInfo.Exit == TmpStatus)
return;
BBInfo.Exit = TmpStatus;
LLVM_DEBUG(dbgs() << "Exit state of " << printMBBReference(MBB)
<< " changed to " << BBInfo.Exit << "\n");
for (MachineBasicBlock *S : MBB.successors())
if (!BlockInfo[S->getNumber()].InQueue)
WorkList.push(S);
}
bool RISCVInsertVSETVLI::needVSETVLIPHI(const VSETVLIInfo &Require,
const MachineBasicBlock &MBB) const {
if (DisableInsertVSETVLPHIOpt)
return true;
if (!Require.hasAVLReg())
return true;
Register AVLReg = Require.getAVLReg();
if (!AVLReg.isVirtual())
return true;
MachineInstr *PHI = MRI->getVRegDef(AVLReg);
if (!PHI || PHI->getOpcode() != RISCV::PHI || PHI->getParent() != &MBB)
return true;
for (unsigned PHIOp = 1, NumOps = PHI->getNumOperands(); PHIOp != NumOps;
PHIOp += 2) {
Register InReg = PHI->getOperand(PHIOp).getReg();
MachineBasicBlock *PBB = PHI->getOperand(PHIOp + 1).getMBB();
const BlockData &PBBInfo = BlockInfo[PBB->getNumber()];
if (PBBInfo.Exit.isUnknown() || !PBBInfo.Exit.hasSameVTYPE(Require))
return true;
MachineInstr *DefMI = MRI->getVRegDef(InReg);
if (!DefMI || !isVectorConfigInstr(*DefMI))
return true;
VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI);
if (!DefInfo.hasSameAVL(PBBInfo.Exit) ||
!DefInfo.hasSameVTYPE(PBBInfo.Exit))
return true;
}
return false;
}
void RISCVInsertVSETVLI::emitVSETVLIs(MachineBasicBlock &MBB) {
VSETVLIInfo CurInfo = BlockInfo[MBB.getNumber()].Pred;
bool PrefixTransparent = true;
for (MachineInstr &MI : MBB) {
const VSETVLIInfo PrevInfo = CurInfo;
transferBefore(CurInfo, MI);
if (isVectorConfigInstr(MI)) {
assert(MI.getOperand(3).getReg() == RISCV::VL &&
MI.getOperand(4).getReg() == RISCV::VTYPE &&
"Unexpected operands where VL and VTYPE should be");
MI.getOperand(3).setIsDead(false);
MI.getOperand(4).setIsDead(false);
PrefixTransparent = false;
}
uint64_t TSFlags = MI.getDesc().TSFlags;
if (RISCVII::hasSEWOp(TSFlags)) {
if (PrevInfo != CurInfo) {
if (!PrefixTransparent || needVSETVLIPHI(CurInfo, MBB))
insertVSETVLI(MBB, MI, CurInfo, PrevInfo);
PrefixTransparent = false;
}
if (RISCVII::hasVLOp(TSFlags)) {
MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI));
if (VLOp.isReg()) {
VLOp.setReg(RISCV::NoRegister);
VLOp.setIsKill(false);
}
MI.addOperand(MachineOperand::CreateReg(RISCV::VL, false,
true));
}
MI.addOperand(MachineOperand::CreateReg(RISCV::VTYPE, false,
true));
}
if (MI.isCall() || MI.isInlineAsm() || MI.modifiesRegister(RISCV::VL) ||
MI.modifiesRegister(RISCV::VTYPE))
PrefixTransparent = false;
transferAfter(CurInfo, MI);
}
if (!UseStrictAsserts) {
const VSETVLIInfo &ExitInfo = BlockInfo[MBB.getNumber()].Exit;
if (CurInfo.isValid() && ExitInfo.isValid() && !ExitInfo.isUnknown() &&
CurInfo != ExitInfo) {
auto InsertPt = MBB.getFirstInstrTerminator();
insertVSETVLI(MBB, InsertPt, MBB.findDebugLoc(InsertPt), ExitInfo,
CurInfo);
CurInfo = ExitInfo;
}
}
if (UseStrictAsserts && CurInfo.isValid()) {
const auto &Info = BlockInfo[MBB.getNumber()];
if (CurInfo != Info.Exit) {
LLVM_DEBUG(dbgs() << "in block " << printMBBReference(MBB) << "\n");
LLVM_DEBUG(dbgs() << " begin state: " << Info.Pred << "\n");
LLVM_DEBUG(dbgs() << " expected end state: " << Info.Exit << "\n");
LLVM_DEBUG(dbgs() << " actual end state: " << CurInfo << "\n");
}
assert(CurInfo == Info.Exit &&
"InsertVSETVLI dataflow invariant violated");
}
}
static bool hasFixedResult(const VSETVLIInfo &Info, const RISCVSubtarget &ST) {
if (!Info.hasAVLImm())
return RISCV::X0 == Info.getAVLReg();
unsigned AVL = Info.getAVLImm();
unsigned SEW = Info.getSEW();
unsigned AVLInBits = AVL * SEW;
unsigned LMul;
bool Fractional;
std::tie(LMul, Fractional) = RISCVVType::decodeVLMUL(Info.getVLMUL());
if (Fractional)
return ST.getRealMinVLen() / LMul >= AVLInBits;
return ST.getRealMinVLen() * LMul >= AVLInBits;
}
void RISCVInsertVSETVLI::doPRE(MachineBasicBlock &MBB) {
const MachineFunction &MF = *MBB.getParent();
const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>();
if (!BlockInfo[MBB.getNumber()].Pred.isUnknown())
return;
MachineBasicBlock *UnavailablePred = nullptr;
VSETVLIInfo AvailableInfo;
for (MachineBasicBlock *P : MBB.predecessors()) {
const VSETVLIInfo &PredInfo = BlockInfo[P->getNumber()].Exit;
if (PredInfo.isUnknown()) {
if (UnavailablePred)
return;
UnavailablePred = P;
} else if (!AvailableInfo.isValid()) {
AvailableInfo = PredInfo;
} else if (AvailableInfo != PredInfo) {
return;
}
}
if (!UnavailablePred || !AvailableInfo.isValid())
return;
if (UnavailablePred->succ_size() != 1)
return;
if (!hasFixedResult(AvailableInfo, ST))
return;
bool Found = false;
for (auto &MI : MBB) {
if (isVectorConfigInstr(MI))
return;
const uint64_t TSFlags = MI.getDesc().TSFlags;
if (RISCVII::hasSEWOp(TSFlags)) {
if (AvailableInfo != computeInfoForInstr(MI, TSFlags, MRI))
return;
Found = true;
break;
}
}
if (!Found)
return;
auto OldInfo = BlockInfo[UnavailablePred->getNumber()].Exit;
LLVM_DEBUG(dbgs() << "PRE VSETVLI from " << MBB.getName() << " to "
<< UnavailablePred->getName() << " with state "
<< AvailableInfo << "\n");
BlockInfo[UnavailablePred->getNumber()].Exit = AvailableInfo;
BlockInfo[MBB.getNumber()].Pred = AvailableInfo;
auto InsertPt = UnavailablePred->getFirstInstrTerminator();
insertVSETVLI(*UnavailablePred, InsertPt,
UnavailablePred->findDebugLoc(InsertPt),
AvailableInfo, OldInfo);
}
static void doUnion(DemandedFields &A, DemandedFields B) {
A.VL |= B.VL;
A.SEW |= B.SEW;
A.LMUL |= B.LMUL;
A.SEWLMULRatio |= B.SEWLMULRatio;
A.TailPolicy |= B.TailPolicy;
A.MaskPolicy |= B.MaskPolicy;
}
static bool canMutatePriorConfig(const MachineInstr &PrevMI,
const MachineInstr &MI,
const DemandedFields &Used) {
if (!isVLPreservingConfig(MI))
return false;
if (!PrevMI.getOperand(2).isImm() || !MI.getOperand(2).isImm())
return false;
auto PriorVType = PrevMI.getOperand(2).getImm();
auto VType = MI.getOperand(2).getImm();
return areCompatibleVTYPEs(PriorVType, VType, Used);
}
void RISCVInsertVSETVLI::doLocalPostpass(MachineBasicBlock &MBB) {
MachineInstr *PrevMI = nullptr;
DemandedFields Used;
SmallVector<MachineInstr*> ToDelete;
for (MachineInstr &MI : MBB) {
doUnion(Used, getDemanded(MI));
if (!isVectorConfigInstr(MI))
continue;
if (PrevMI) {
if (!Used.VL && !Used.usedVTYPE()) {
ToDelete.push_back(PrevMI);
} else if (canMutatePriorConfig(*PrevMI, MI, Used)) {
PrevMI->getOperand(2).setImm(MI.getOperand(2).getImm());
ToDelete.push_back(&MI);
continue;
}
}
PrevMI = &MI;
Used = getDemanded(MI);
Register VRegDef = MI.getOperand(0).getReg();
if (VRegDef != RISCV::X0 &&
!(VRegDef.isVirtual() && MRI->use_nodbg_empty(VRegDef)))
Used.VL = true;
}
for (auto *MI : ToDelete)
MI->eraseFromParent();
}
void RISCVInsertVSETVLI::insertReadVL(MachineBasicBlock &MBB) {
for (auto I = MBB.begin(), E = MBB.end(); I != E;) {
MachineInstr &MI = *I++;
if (RISCV::isFaultFirstLoad(MI)) {
Register VLOutput = MI.getOperand(1).getReg();
if (!MRI->use_nodbg_empty(VLOutput))
BuildMI(MBB, I, MI.getDebugLoc(), TII->get(RISCV::PseudoReadVL),
VLOutput);
MI.getOperand(1).setReg(RISCV::X0);
}
}
}
bool RISCVInsertVSETVLI::runOnMachineFunction(MachineFunction &MF) {
const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>();
if (!ST.hasVInstructions())
return false;
LLVM_DEBUG(dbgs() << "Entering InsertVSETVLI for " << MF.getName() << "\n");
TII = ST.getInstrInfo();
MRI = &MF.getRegInfo();
assert(BlockInfo.empty() && "Expect empty block infos");
BlockInfo.resize(MF.getNumBlockIDs());
bool HaveVectorOp = false;
for (const MachineBasicBlock &MBB : MF) {
HaveVectorOp |= computeVLVTYPEChanges(MBB);
BlockData &BBInfo = BlockInfo[MBB.getNumber()];
BBInfo.Exit = BBInfo.Change;
LLVM_DEBUG(dbgs() << "Initial exit state of " << printMBBReference(MBB)
<< " is " << BBInfo.Exit << "\n");
}
if (!HaveVectorOp) {
BlockInfo.clear();
return false;
}
for (const MachineBasicBlock &MBB : MF) {
WorkList.push(&MBB);
BlockInfo[MBB.getNumber()].InQueue = true;
}
while (!WorkList.empty()) {
const MachineBasicBlock &MBB = *WorkList.front();
WorkList.pop();
computeIncomingVLVTYPE(MBB);
}
for (MachineBasicBlock &MBB : MF)
doPRE(MBB);
for (MachineBasicBlock &MBB : MF)
emitVSETVLIs(MBB);
for (MachineBasicBlock &MBB : MF)
doLocalPostpass(MBB);
for (MachineBasicBlock &MBB : MF) {
for (MachineInstr &MI : MBB) {
if (MI.getOpcode() == RISCV::PseudoVSETVLI ||
MI.getOpcode() == RISCV::PseudoVSETIVLI) {
Register VRegDef = MI.getOperand(0).getReg();
if (VRegDef != RISCV::X0 && MRI->use_nodbg_empty(VRegDef))
MI.getOperand(0).setReg(RISCV::X0);
}
}
}
for (MachineBasicBlock &MBB : MF)
insertReadVL(MBB);
BlockInfo.clear();
return HaveVectorOp;
}
FunctionPass *llvm::createRISCVInsertVSETVLIPass() {
return new RISCVInsertVSETVLI();
}