1fe6060f1SDimitry Andric //===- RISCVInsertVSETVLI.cpp - Insert VSETVLI instructions ---------------===// 2fe6060f1SDimitry Andric // 3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fe6060f1SDimitry Andric // 7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8fe6060f1SDimitry Andric // 9fe6060f1SDimitry Andric // This file implements a function pass that inserts VSETVLI instructions where 1081ad6265SDimitry Andric // needed and expands the vl outputs of VLEFF/VLSEGFF to PseudoReadVL 1181ad6265SDimitry Andric // instructions. 12fe6060f1SDimitry Andric // 13fe6060f1SDimitry Andric // This pass consists of 3 phases: 14fe6060f1SDimitry Andric // 15fe6060f1SDimitry Andric // Phase 1 collects how each basic block affects VL/VTYPE. 16fe6060f1SDimitry Andric // 17fe6060f1SDimitry Andric // Phase 2 uses the information from phase 1 to do a data flow analysis to 18fe6060f1SDimitry Andric // propagate the VL/VTYPE changes through the function. This gives us the 19fe6060f1SDimitry Andric // VL/VTYPE at the start of each basic block. 20fe6060f1SDimitry Andric // 21fe6060f1SDimitry Andric // Phase 3 inserts VSETVLI instructions in each basic block. Information from 22fe6060f1SDimitry Andric // phase 2 is used to prevent inserting a VSETVLI before the first vector 23fe6060f1SDimitry Andric // instruction in the block if possible. 24fe6060f1SDimitry Andric // 25fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 26fe6060f1SDimitry Andric 27fe6060f1SDimitry Andric #include "RISCV.h" 28fe6060f1SDimitry Andric #include "RISCVSubtarget.h" 297a6dacacSDimitry Andric #include "llvm/ADT/Statistic.h" 30*0fca6ea1SDimitry Andric #include "llvm/CodeGen/LiveDebugVariables.h" 31fe6060f1SDimitry Andric #include "llvm/CodeGen/LiveIntervals.h" 32*0fca6ea1SDimitry Andric #include "llvm/CodeGen/LiveStacks.h" 33fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 34fe6060f1SDimitry Andric #include <queue> 35fe6060f1SDimitry Andric using namespace llvm; 36fe6060f1SDimitry Andric 37fe6060f1SDimitry Andric #define DEBUG_TYPE "riscv-insert-vsetvli" 3806c3fb27SDimitry Andric #define RISCV_INSERT_VSETVLI_NAME "RISC-V Insert VSETVLI pass" 39*0fca6ea1SDimitry Andric #define RISCV_COALESCE_VSETVLI_NAME "RISC-V Coalesce VSETVLI pass" 40fe6060f1SDimitry Andric 417a6dacacSDimitry Andric STATISTIC(NumInsertedVSETVL, "Number of VSETVL inst inserted"); 42*0fca6ea1SDimitry Andric STATISTIC(NumCoalescedVSETVL, "Number of VSETVL inst coalesced"); 4381ad6265SDimitry Andric 44fe6060f1SDimitry Andric namespace { 45fe6060f1SDimitry Andric 46*0fca6ea1SDimitry Andric /// Given a virtual register \p Reg, return the corresponding VNInfo for it. 47*0fca6ea1SDimitry Andric /// This will return nullptr if the virtual register is an implicit_def or 48*0fca6ea1SDimitry Andric /// if LiveIntervals is not available. 49*0fca6ea1SDimitry Andric static VNInfo *getVNInfoFromReg(Register Reg, const MachineInstr &MI, 50*0fca6ea1SDimitry Andric const LiveIntervals *LIS) { 51*0fca6ea1SDimitry Andric assert(Reg.isVirtual()); 52*0fca6ea1SDimitry Andric if (!LIS) 53*0fca6ea1SDimitry Andric return nullptr; 54*0fca6ea1SDimitry Andric auto &LI = LIS->getInterval(Reg); 55*0fca6ea1SDimitry Andric SlotIndex SI = LIS->getSlotIndexes()->getInstructionIndex(MI); 56*0fca6ea1SDimitry Andric return LI.getVNInfoBefore(SI); 57*0fca6ea1SDimitry Andric } 58*0fca6ea1SDimitry Andric 5981ad6265SDimitry Andric static unsigned getVLOpNum(const MachineInstr &MI) { 6081ad6265SDimitry Andric return RISCVII::getVLOpNum(MI.getDesc()); 61fe6060f1SDimitry Andric } 62fe6060f1SDimitry Andric 6381ad6265SDimitry Andric static unsigned getSEWOpNum(const MachineInstr &MI) { 6481ad6265SDimitry Andric return RISCVII::getSEWOpNum(MI.getDesc()); 65fe6060f1SDimitry Andric } 66fe6060f1SDimitry Andric 67bdd1243dSDimitry Andric static bool isVectorConfigInstr(const MachineInstr &MI) { 68bdd1243dSDimitry Andric return MI.getOpcode() == RISCV::PseudoVSETVLI || 69bdd1243dSDimitry Andric MI.getOpcode() == RISCV::PseudoVSETVLIX0 || 70bdd1243dSDimitry Andric MI.getOpcode() == RISCV::PseudoVSETIVLI; 71bdd1243dSDimitry Andric } 72bdd1243dSDimitry Andric 73bdd1243dSDimitry Andric /// Return true if this is 'vsetvli x0, x0, vtype' which preserves 74bdd1243dSDimitry Andric /// VL and only sets VTYPE. 75bdd1243dSDimitry Andric static bool isVLPreservingConfig(const MachineInstr &MI) { 76bdd1243dSDimitry Andric if (MI.getOpcode() != RISCV::PseudoVSETVLIX0) 77bdd1243dSDimitry Andric return false; 78bdd1243dSDimitry Andric assert(RISCV::X0 == MI.getOperand(1).getReg()); 79bdd1243dSDimitry Andric return RISCV::X0 == MI.getOperand(0).getReg(); 80bdd1243dSDimitry Andric } 81bdd1243dSDimitry Andric 825f757f3fSDimitry Andric static bool isFloatScalarMoveOrScalarSplatInstr(const MachineInstr &MI) { 835f757f3fSDimitry Andric switch (RISCV::getRVVMCOpcode(MI.getOpcode())) { 845f757f3fSDimitry Andric default: 855f757f3fSDimitry Andric return false; 865f757f3fSDimitry Andric case RISCV::VFMV_S_F: 875f757f3fSDimitry Andric case RISCV::VFMV_V_F: 885f757f3fSDimitry Andric return true; 895f757f3fSDimitry Andric } 90bdd1243dSDimitry Andric } 91bdd1243dSDimitry Andric 925f757f3fSDimitry Andric static bool isScalarExtractInstr(const MachineInstr &MI) { 935f757f3fSDimitry Andric switch (RISCV::getRVVMCOpcode(MI.getOpcode())) { 945f757f3fSDimitry Andric default: 955f757f3fSDimitry Andric return false; 965f757f3fSDimitry Andric case RISCV::VMV_X_S: 975f757f3fSDimitry Andric case RISCV::VFMV_F_S: 985f757f3fSDimitry Andric return true; 995f757f3fSDimitry Andric } 1005f757f3fSDimitry Andric } 1015f757f3fSDimitry Andric 1025f757f3fSDimitry Andric static bool isScalarInsertInstr(const MachineInstr &MI) { 1035f757f3fSDimitry Andric switch (RISCV::getRVVMCOpcode(MI.getOpcode())) { 10404eeddc0SDimitry Andric default: 10504eeddc0SDimitry Andric return false; 106bdd1243dSDimitry Andric case RISCV::VMV_S_X: 107bdd1243dSDimitry Andric case RISCV::VFMV_S_F: 10804eeddc0SDimitry Andric return true; 10904eeddc0SDimitry Andric } 11004eeddc0SDimitry Andric } 11104eeddc0SDimitry Andric 11206c3fb27SDimitry Andric static bool isScalarSplatInstr(const MachineInstr &MI) { 1135f757f3fSDimitry Andric switch (RISCV::getRVVMCOpcode(MI.getOpcode())) { 11406c3fb27SDimitry Andric default: 11506c3fb27SDimitry Andric return false; 11606c3fb27SDimitry Andric case RISCV::VMV_V_I: 11706c3fb27SDimitry Andric case RISCV::VMV_V_X: 11806c3fb27SDimitry Andric case RISCV::VFMV_V_F: 11906c3fb27SDimitry Andric return true; 12006c3fb27SDimitry Andric } 12106c3fb27SDimitry Andric } 12206c3fb27SDimitry Andric 12306c3fb27SDimitry Andric static bool isVSlideInstr(const MachineInstr &MI) { 1245f757f3fSDimitry Andric switch (RISCV::getRVVMCOpcode(MI.getOpcode())) { 12506c3fb27SDimitry Andric default: 12606c3fb27SDimitry Andric return false; 12706c3fb27SDimitry Andric case RISCV::VSLIDEDOWN_VX: 12806c3fb27SDimitry Andric case RISCV::VSLIDEDOWN_VI: 12906c3fb27SDimitry Andric case RISCV::VSLIDEUP_VX: 13006c3fb27SDimitry Andric case RISCV::VSLIDEUP_VI: 13106c3fb27SDimitry Andric return true; 13206c3fb27SDimitry Andric } 13306c3fb27SDimitry Andric } 13406c3fb27SDimitry Andric 135bdd1243dSDimitry Andric /// Get the EEW for a load or store instruction. Return std::nullopt if MI is 136bdd1243dSDimitry Andric /// not a load or store which ignores SEW. 137bdd1243dSDimitry Andric static std::optional<unsigned> getEEWForLoadStore(const MachineInstr &MI) { 1385f757f3fSDimitry Andric switch (RISCV::getRVVMCOpcode(MI.getOpcode())) { 139349cc55cSDimitry Andric default: 140bdd1243dSDimitry Andric return std::nullopt; 141bdd1243dSDimitry Andric case RISCV::VLE8_V: 142bdd1243dSDimitry Andric case RISCV::VLSE8_V: 143bdd1243dSDimitry Andric case RISCV::VSE8_V: 144bdd1243dSDimitry Andric case RISCV::VSSE8_V: 14581ad6265SDimitry Andric return 8; 146bdd1243dSDimitry Andric case RISCV::VLE16_V: 147bdd1243dSDimitry Andric case RISCV::VLSE16_V: 148bdd1243dSDimitry Andric case RISCV::VSE16_V: 149bdd1243dSDimitry Andric case RISCV::VSSE16_V: 15081ad6265SDimitry Andric return 16; 151bdd1243dSDimitry Andric case RISCV::VLE32_V: 152bdd1243dSDimitry Andric case RISCV::VLSE32_V: 153bdd1243dSDimitry Andric case RISCV::VSE32_V: 154bdd1243dSDimitry Andric case RISCV::VSSE32_V: 15581ad6265SDimitry Andric return 32; 156bdd1243dSDimitry Andric case RISCV::VLE64_V: 157bdd1243dSDimitry Andric case RISCV::VLSE64_V: 158bdd1243dSDimitry Andric case RISCV::VSE64_V: 159bdd1243dSDimitry Andric case RISCV::VSSE64_V: 16081ad6265SDimitry Andric return 64; 16181ad6265SDimitry Andric } 162349cc55cSDimitry Andric } 163349cc55cSDimitry Andric 164*0fca6ea1SDimitry Andric static bool isNonZeroLoadImmediate(const MachineInstr &MI) { 1655f757f3fSDimitry Andric return MI.getOpcode() == RISCV::ADDI && 1665f757f3fSDimitry Andric MI.getOperand(1).isReg() && MI.getOperand(2).isImm() && 1675f757f3fSDimitry Andric MI.getOperand(1).getReg() == RISCV::X0 && 1685f757f3fSDimitry Andric MI.getOperand(2).getImm() != 0; 1695f757f3fSDimitry Andric } 1705f757f3fSDimitry Andric 17181ad6265SDimitry Andric /// Return true if this is an operation on mask registers. Note that 17281ad6265SDimitry Andric /// this includes both arithmetic/logical ops and load/store (vlm/vsm). 17381ad6265SDimitry Andric static bool isMaskRegOp(const MachineInstr &MI) { 174bdd1243dSDimitry Andric if (!RISCVII::hasSEWOp(MI.getDesc().TSFlags)) 175bdd1243dSDimitry Andric return false; 17681ad6265SDimitry Andric const unsigned Log2SEW = MI.getOperand(getSEWOpNum(MI)).getImm(); 17781ad6265SDimitry Andric // A Log2SEW of 0 is an operation on mask registers only. 17881ad6265SDimitry Andric return Log2SEW == 0; 17981ad6265SDimitry Andric } 18081ad6265SDimitry Andric 18106c3fb27SDimitry Andric /// Return true if the inactive elements in the result are entirely undefined. 18206c3fb27SDimitry Andric /// Note that this is different from "agnostic" as defined by the vector 18306c3fb27SDimitry Andric /// specification. Agnostic requires each lane to either be undisturbed, or 18406c3fb27SDimitry Andric /// take the value -1; no other value is allowed. 185*0fca6ea1SDimitry Andric static bool hasUndefinedMergeOp(const MachineInstr &MI) { 18606c3fb27SDimitry Andric 18706c3fb27SDimitry Andric unsigned UseOpIdx; 18806c3fb27SDimitry Andric if (!MI.isRegTiedToUseOperand(0, &UseOpIdx)) 18906c3fb27SDimitry Andric // If there is no passthrough operand, then the pass through 19006c3fb27SDimitry Andric // lanes are undefined. 19106c3fb27SDimitry Andric return true; 19206c3fb27SDimitry Andric 193*0fca6ea1SDimitry Andric // All undefined passthrus should be $noreg: see 194*0fca6ea1SDimitry Andric // RISCVDAGToDAGISel::doPeepholeNoRegPassThru 19506c3fb27SDimitry Andric const MachineOperand &UseMO = MI.getOperand(UseOpIdx); 196*0fca6ea1SDimitry Andric return UseMO.getReg() == RISCV::NoRegister || UseMO.isUndef(); 19706c3fb27SDimitry Andric } 19806c3fb27SDimitry Andric 19981ad6265SDimitry Andric /// Which subfields of VL or VTYPE have values we need to preserve? 20081ad6265SDimitry Andric struct DemandedFields { 201bdd1243dSDimitry Andric // Some unknown property of VL is used. If demanded, must preserve entire 202bdd1243dSDimitry Andric // value. 203bdd1243dSDimitry Andric bool VLAny = false; 204bdd1243dSDimitry Andric // Only zero vs non-zero is used. If demanded, can change non-zero values. 205bdd1243dSDimitry Andric bool VLZeroness = false; 20606c3fb27SDimitry Andric // What properties of SEW we need to preserve. 20706c3fb27SDimitry Andric enum : uint8_t { 2085f757f3fSDimitry Andric SEWEqual = 3, // The exact value of SEW needs to be preserved. 2095f757f3fSDimitry Andric SEWGreaterThanOrEqual = 2, // SEW can be changed as long as it's greater 21006c3fb27SDimitry Andric // than or equal to the original value. 2115f757f3fSDimitry Andric SEWGreaterThanOrEqualAndLessThan64 = 2125f757f3fSDimitry Andric 1, // SEW can be changed as long as it's greater 2135f757f3fSDimitry Andric // than or equal to the original value, but must be less 2145f757f3fSDimitry Andric // than 64. 21506c3fb27SDimitry Andric SEWNone = 0 // We don't need to preserve SEW at all. 21606c3fb27SDimitry Andric } SEW = SEWNone; 217*0fca6ea1SDimitry Andric enum : uint8_t { 218*0fca6ea1SDimitry Andric LMULEqual = 2, // The exact value of LMUL needs to be preserved. 219*0fca6ea1SDimitry Andric LMULLessThanOrEqualToM1 = 1, // We can use any LMUL <= M1. 220*0fca6ea1SDimitry Andric LMULNone = 0 // We don't need to preserve LMUL at all. 221*0fca6ea1SDimitry Andric } LMUL = LMULNone; 22281ad6265SDimitry Andric bool SEWLMULRatio = false; 22381ad6265SDimitry Andric bool TailPolicy = false; 22481ad6265SDimitry Andric bool MaskPolicy = false; 22581ad6265SDimitry Andric 22681ad6265SDimitry Andric // Return true if any part of VTYPE was used 227bdd1243dSDimitry Andric bool usedVTYPE() const { 22881ad6265SDimitry Andric return SEW || LMUL || SEWLMULRatio || TailPolicy || MaskPolicy; 22981ad6265SDimitry Andric } 23081ad6265SDimitry Andric 231bdd1243dSDimitry Andric // Return true if any property of VL was used 232bdd1243dSDimitry Andric bool usedVL() { 233bdd1243dSDimitry Andric return VLAny || VLZeroness; 234bdd1243dSDimitry Andric } 235bdd1243dSDimitry Andric 23681ad6265SDimitry Andric // Mark all VTYPE subfields and properties as demanded 23781ad6265SDimitry Andric void demandVTYPE() { 23806c3fb27SDimitry Andric SEW = SEWEqual; 239*0fca6ea1SDimitry Andric LMUL = LMULEqual; 24081ad6265SDimitry Andric SEWLMULRatio = true; 24181ad6265SDimitry Andric TailPolicy = true; 24281ad6265SDimitry Andric MaskPolicy = true; 24381ad6265SDimitry Andric } 244bdd1243dSDimitry Andric 245bdd1243dSDimitry Andric // Mark all VL properties as demanded 246bdd1243dSDimitry Andric void demandVL() { 247bdd1243dSDimitry Andric VLAny = true; 248bdd1243dSDimitry Andric VLZeroness = true; 249bdd1243dSDimitry Andric } 250bdd1243dSDimitry Andric 251*0fca6ea1SDimitry Andric static DemandedFields all() { 252*0fca6ea1SDimitry Andric DemandedFields DF; 253*0fca6ea1SDimitry Andric DF.demandVTYPE(); 254*0fca6ea1SDimitry Andric DF.demandVL(); 255*0fca6ea1SDimitry Andric return DF; 256*0fca6ea1SDimitry Andric } 257*0fca6ea1SDimitry Andric 258*0fca6ea1SDimitry Andric // Make this the result of demanding both the fields in this and B. 259*0fca6ea1SDimitry Andric void doUnion(const DemandedFields &B) { 260*0fca6ea1SDimitry Andric VLAny |= B.VLAny; 261*0fca6ea1SDimitry Andric VLZeroness |= B.VLZeroness; 262*0fca6ea1SDimitry Andric SEW = std::max(SEW, B.SEW); 263*0fca6ea1SDimitry Andric LMUL = std::max(LMUL, B.LMUL); 264*0fca6ea1SDimitry Andric SEWLMULRatio |= B.SEWLMULRatio; 265*0fca6ea1SDimitry Andric TailPolicy |= B.TailPolicy; 266*0fca6ea1SDimitry Andric MaskPolicy |= B.MaskPolicy; 267*0fca6ea1SDimitry Andric } 268*0fca6ea1SDimitry Andric 269bdd1243dSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 270bdd1243dSDimitry Andric /// Support for debugging, callable in GDB: V->dump() 271bdd1243dSDimitry Andric LLVM_DUMP_METHOD void dump() const { 272bdd1243dSDimitry Andric print(dbgs()); 273bdd1243dSDimitry Andric dbgs() << "\n"; 274bdd1243dSDimitry Andric } 275bdd1243dSDimitry Andric 276bdd1243dSDimitry Andric /// Implement operator<<. 277bdd1243dSDimitry Andric void print(raw_ostream &OS) const { 278bdd1243dSDimitry Andric OS << "{"; 279bdd1243dSDimitry Andric OS << "VLAny=" << VLAny << ", "; 280bdd1243dSDimitry Andric OS << "VLZeroness=" << VLZeroness << ", "; 28106c3fb27SDimitry Andric OS << "SEW="; 28206c3fb27SDimitry Andric switch (SEW) { 28306c3fb27SDimitry Andric case SEWEqual: 28406c3fb27SDimitry Andric OS << "SEWEqual"; 28506c3fb27SDimitry Andric break; 28606c3fb27SDimitry Andric case SEWGreaterThanOrEqual: 28706c3fb27SDimitry Andric OS << "SEWGreaterThanOrEqual"; 28806c3fb27SDimitry Andric break; 2895f757f3fSDimitry Andric case SEWGreaterThanOrEqualAndLessThan64: 2905f757f3fSDimitry Andric OS << "SEWGreaterThanOrEqualAndLessThan64"; 2915f757f3fSDimitry Andric break; 29206c3fb27SDimitry Andric case SEWNone: 29306c3fb27SDimitry Andric OS << "SEWNone"; 29406c3fb27SDimitry Andric break; 29506c3fb27SDimitry Andric }; 29606c3fb27SDimitry Andric OS << ", "; 297*0fca6ea1SDimitry Andric OS << "LMUL="; 298*0fca6ea1SDimitry Andric switch (LMUL) { 299*0fca6ea1SDimitry Andric case LMULEqual: 300*0fca6ea1SDimitry Andric OS << "LMULEqual"; 301*0fca6ea1SDimitry Andric break; 302*0fca6ea1SDimitry Andric case LMULLessThanOrEqualToM1: 303*0fca6ea1SDimitry Andric OS << "LMULLessThanOrEqualToM1"; 304*0fca6ea1SDimitry Andric break; 305*0fca6ea1SDimitry Andric case LMULNone: 306*0fca6ea1SDimitry Andric OS << "LMULNone"; 307*0fca6ea1SDimitry Andric break; 308*0fca6ea1SDimitry Andric }; 309*0fca6ea1SDimitry Andric OS << ", "; 310bdd1243dSDimitry Andric OS << "SEWLMULRatio=" << SEWLMULRatio << ", "; 311bdd1243dSDimitry Andric OS << "TailPolicy=" << TailPolicy << ", "; 312bdd1243dSDimitry Andric OS << "MaskPolicy=" << MaskPolicy; 313bdd1243dSDimitry Andric OS << "}"; 314bdd1243dSDimitry Andric } 315bdd1243dSDimitry Andric #endif 31681ad6265SDimitry Andric }; 31781ad6265SDimitry Andric 318bdd1243dSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 319bdd1243dSDimitry Andric LLVM_ATTRIBUTE_USED 320bdd1243dSDimitry Andric inline raw_ostream &operator<<(raw_ostream &OS, const DemandedFields &DF) { 321bdd1243dSDimitry Andric DF.print(OS); 322bdd1243dSDimitry Andric return OS; 323bdd1243dSDimitry Andric } 324bdd1243dSDimitry Andric #endif 325bdd1243dSDimitry Andric 326*0fca6ea1SDimitry Andric static bool isLMUL1OrSmaller(RISCVII::VLMUL LMUL) { 327*0fca6ea1SDimitry Andric auto [LMul, Fractional] = RISCVVType::decodeVLMUL(LMUL); 328*0fca6ea1SDimitry Andric return Fractional || LMul == 1; 329*0fca6ea1SDimitry Andric } 330*0fca6ea1SDimitry Andric 33106c3fb27SDimitry Andric /// Return true if moving from CurVType to NewVType is 33206c3fb27SDimitry Andric /// indistinguishable from the perspective of an instruction (or set 33306c3fb27SDimitry Andric /// of instructions) which use only the Used subfields and properties. 33406c3fb27SDimitry Andric static bool areCompatibleVTYPEs(uint64_t CurVType, uint64_t NewVType, 33581ad6265SDimitry Andric const DemandedFields &Used) { 3365f757f3fSDimitry Andric switch (Used.SEW) { 3375f757f3fSDimitry Andric case DemandedFields::SEWNone: 3385f757f3fSDimitry Andric break; 3395f757f3fSDimitry Andric case DemandedFields::SEWEqual: 3405f757f3fSDimitry Andric if (RISCVVType::getSEW(CurVType) != RISCVVType::getSEW(NewVType)) 34106c3fb27SDimitry Andric return false; 3425f757f3fSDimitry Andric break; 3435f757f3fSDimitry Andric case DemandedFields::SEWGreaterThanOrEqual: 3445f757f3fSDimitry Andric if (RISCVVType::getSEW(NewVType) < RISCVVType::getSEW(CurVType)) 34581ad6265SDimitry Andric return false; 3465f757f3fSDimitry Andric break; 3475f757f3fSDimitry Andric case DemandedFields::SEWGreaterThanOrEqualAndLessThan64: 3485f757f3fSDimitry Andric if (RISCVVType::getSEW(NewVType) < RISCVVType::getSEW(CurVType) || 3495f757f3fSDimitry Andric RISCVVType::getSEW(NewVType) >= 64) 3505f757f3fSDimitry Andric return false; 3515f757f3fSDimitry Andric break; 3525f757f3fSDimitry Andric } 35381ad6265SDimitry Andric 354*0fca6ea1SDimitry Andric switch (Used.LMUL) { 355*0fca6ea1SDimitry Andric case DemandedFields::LMULNone: 356*0fca6ea1SDimitry Andric break; 357*0fca6ea1SDimitry Andric case DemandedFields::LMULEqual: 358*0fca6ea1SDimitry Andric if (RISCVVType::getVLMUL(CurVType) != RISCVVType::getVLMUL(NewVType)) 35981ad6265SDimitry Andric return false; 360*0fca6ea1SDimitry Andric break; 361*0fca6ea1SDimitry Andric case DemandedFields::LMULLessThanOrEqualToM1: 362*0fca6ea1SDimitry Andric if (!isLMUL1OrSmaller(RISCVVType::getVLMUL(NewVType))) 363*0fca6ea1SDimitry Andric return false; 364*0fca6ea1SDimitry Andric break; 365*0fca6ea1SDimitry Andric } 36681ad6265SDimitry Andric 36781ad6265SDimitry Andric if (Used.SEWLMULRatio) { 36806c3fb27SDimitry Andric auto Ratio1 = RISCVVType::getSEWLMULRatio(RISCVVType::getSEW(CurVType), 36906c3fb27SDimitry Andric RISCVVType::getVLMUL(CurVType)); 37006c3fb27SDimitry Andric auto Ratio2 = RISCVVType::getSEWLMULRatio(RISCVVType::getSEW(NewVType), 37106c3fb27SDimitry Andric RISCVVType::getVLMUL(NewVType)); 37281ad6265SDimitry Andric if (Ratio1 != Ratio2) 37381ad6265SDimitry Andric return false; 37481ad6265SDimitry Andric } 37581ad6265SDimitry Andric 37606c3fb27SDimitry Andric if (Used.TailPolicy && RISCVVType::isTailAgnostic(CurVType) != 37706c3fb27SDimitry Andric RISCVVType::isTailAgnostic(NewVType)) 37881ad6265SDimitry Andric return false; 37906c3fb27SDimitry Andric if (Used.MaskPolicy && RISCVVType::isMaskAgnostic(CurVType) != 38006c3fb27SDimitry Andric RISCVVType::isMaskAgnostic(NewVType)) 38181ad6265SDimitry Andric return false; 38281ad6265SDimitry Andric return true; 38381ad6265SDimitry Andric } 38481ad6265SDimitry Andric 38581ad6265SDimitry Andric /// Return the fields and properties demanded by the provided instruction. 386*0fca6ea1SDimitry Andric DemandedFields getDemanded(const MachineInstr &MI, const RISCVSubtarget *ST) { 387*0fca6ea1SDimitry Andric // This function works in coalesceVSETVLI too. We can still use the value of a 388*0fca6ea1SDimitry Andric // SEW, VL, or Policy operand even though it might not be the exact value in 389*0fca6ea1SDimitry Andric // the VL or VTYPE, since we only care about what the instruction originally 390*0fca6ea1SDimitry Andric // demanded. 39181ad6265SDimitry Andric 39281ad6265SDimitry Andric // Most instructions don't use any of these subfeilds. 39381ad6265SDimitry Andric DemandedFields Res; 39481ad6265SDimitry Andric // Start conservative if registers are used 395*0fca6ea1SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || 396*0fca6ea1SDimitry Andric MI.readsRegister(RISCV::VL, /*TRI=*/nullptr)) 39706c3fb27SDimitry Andric Res.demandVL(); 398*0fca6ea1SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || 399*0fca6ea1SDimitry Andric MI.readsRegister(RISCV::VTYPE, /*TRI=*/nullptr)) 40081ad6265SDimitry Andric Res.demandVTYPE(); 40181ad6265SDimitry Andric // Start conservative on the unlowered form too 40281ad6265SDimitry Andric uint64_t TSFlags = MI.getDesc().TSFlags; 40381ad6265SDimitry Andric if (RISCVII::hasSEWOp(TSFlags)) { 40481ad6265SDimitry Andric Res.demandVTYPE(); 40581ad6265SDimitry Andric if (RISCVII::hasVLOp(TSFlags)) 406*0fca6ea1SDimitry Andric if (const MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI)); 407*0fca6ea1SDimitry Andric !VLOp.isReg() || !VLOp.isUndef()) 408bdd1243dSDimitry Andric Res.demandVL(); 409bdd1243dSDimitry Andric 410bdd1243dSDimitry Andric // Behavior is independent of mask policy. 411bdd1243dSDimitry Andric if (!RISCVII::usesMaskPolicy(TSFlags)) 412bdd1243dSDimitry Andric Res.MaskPolicy = false; 41381ad6265SDimitry Andric } 41481ad6265SDimitry Andric 41581ad6265SDimitry Andric // Loads and stores with implicit EEW do not demand SEW or LMUL directly. 41681ad6265SDimitry Andric // They instead demand the ratio of the two which is used in computing 41781ad6265SDimitry Andric // EMUL, but which allows us the flexibility to change SEW and LMUL 41881ad6265SDimitry Andric // provided we don't change the ratio. 41981ad6265SDimitry Andric // Note: We assume that the instructions initial SEW is the EEW encoded 42081ad6265SDimitry Andric // in the opcode. This is asserted when constructing the VSETVLIInfo. 42181ad6265SDimitry Andric if (getEEWForLoadStore(MI)) { 42206c3fb27SDimitry Andric Res.SEW = DemandedFields::SEWNone; 423*0fca6ea1SDimitry Andric Res.LMUL = DemandedFields::LMULNone; 42481ad6265SDimitry Andric } 42581ad6265SDimitry Andric 42681ad6265SDimitry Andric // Store instructions don't use the policy fields. 42781ad6265SDimitry Andric if (RISCVII::hasSEWOp(TSFlags) && MI.getNumExplicitDefs() == 0) { 42881ad6265SDimitry Andric Res.TailPolicy = false; 42981ad6265SDimitry Andric Res.MaskPolicy = false; 43081ad6265SDimitry Andric } 43181ad6265SDimitry Andric 43281ad6265SDimitry Andric // If this is a mask reg operation, it only cares about VLMAX. 43381ad6265SDimitry Andric // TODO: Possible extensions to this logic 43481ad6265SDimitry Andric // * Probably ok if available VLMax is larger than demanded 43581ad6265SDimitry Andric // * The policy bits can probably be ignored.. 43681ad6265SDimitry Andric if (isMaskRegOp(MI)) { 43706c3fb27SDimitry Andric Res.SEW = DemandedFields::SEWNone; 438*0fca6ea1SDimitry Andric Res.LMUL = DemandedFields::LMULNone; 43981ad6265SDimitry Andric } 44081ad6265SDimitry Andric 441bdd1243dSDimitry Andric // For vmv.s.x and vfmv.s.f, there are only two behaviors, VL = 0 and VL > 0. 4425f757f3fSDimitry Andric if (isScalarInsertInstr(MI)) { 443*0fca6ea1SDimitry Andric Res.LMUL = DemandedFields::LMULNone; 444bdd1243dSDimitry Andric Res.SEWLMULRatio = false; 445bdd1243dSDimitry Andric Res.VLAny = false; 44606c3fb27SDimitry Andric // For vmv.s.x and vfmv.s.f, if the merge operand is *undefined*, we don't 44706c3fb27SDimitry Andric // need to preserve any other bits and are thus compatible with any larger, 44806c3fb27SDimitry Andric // etype and can disregard policy bits. Warning: It's tempting to try doing 44906c3fb27SDimitry Andric // this for any tail agnostic operation, but we can't as TA requires 45006c3fb27SDimitry Andric // tail lanes to either be the original value or -1. We are writing 45106c3fb27SDimitry Andric // unknown bits to the lanes here. 452*0fca6ea1SDimitry Andric if (hasUndefinedMergeOp(MI)) { 4535f757f3fSDimitry Andric if (isFloatScalarMoveOrScalarSplatInstr(MI) && !ST->hasVInstructionsF64()) 4545f757f3fSDimitry Andric Res.SEW = DemandedFields::SEWGreaterThanOrEqualAndLessThan64; 4555f757f3fSDimitry Andric else 45606c3fb27SDimitry Andric Res.SEW = DemandedFields::SEWGreaterThanOrEqual; 45706c3fb27SDimitry Andric Res.TailPolicy = false; 45806c3fb27SDimitry Andric } 459bdd1243dSDimitry Andric } 460bdd1243dSDimitry Andric 4615f757f3fSDimitry Andric // vmv.x.s, and vmv.f.s are unconditional and ignore everything except SEW. 4625f757f3fSDimitry Andric if (isScalarExtractInstr(MI)) { 4635f757f3fSDimitry Andric assert(!RISCVII::hasVLOp(TSFlags)); 464*0fca6ea1SDimitry Andric Res.LMUL = DemandedFields::LMULNone; 4655f757f3fSDimitry Andric Res.SEWLMULRatio = false; 4665f757f3fSDimitry Andric Res.TailPolicy = false; 4675f757f3fSDimitry Andric Res.MaskPolicy = false; 4685f757f3fSDimitry Andric } 4695f757f3fSDimitry Andric 470*0fca6ea1SDimitry Andric if (RISCVII::hasVLOp(MI.getDesc().TSFlags)) { 471*0fca6ea1SDimitry Andric const MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI)); 472*0fca6ea1SDimitry Andric // A slidedown/slideup with an *undefined* merge op can freely clobber 473*0fca6ea1SDimitry Andric // elements not copied from the source vector (e.g. masked off, tail, or 474*0fca6ea1SDimitry Andric // slideup's prefix). Notes: 475*0fca6ea1SDimitry Andric // * We can't modify SEW here since the slide amount is in units of SEW. 476*0fca6ea1SDimitry Andric // * VL=1 is special only because we have existing support for zero vs 477*0fca6ea1SDimitry Andric // non-zero VL. We could generalize this if we had a VL > C predicate. 478*0fca6ea1SDimitry Andric // * The LMUL1 restriction is for machines whose latency may depend on VL. 479*0fca6ea1SDimitry Andric // * As above, this is only legal for tail "undefined" not "agnostic". 480*0fca6ea1SDimitry Andric if (isVSlideInstr(MI) && VLOp.isImm() && VLOp.getImm() == 1 && 481*0fca6ea1SDimitry Andric hasUndefinedMergeOp(MI)) { 482*0fca6ea1SDimitry Andric Res.VLAny = false; 483*0fca6ea1SDimitry Andric Res.VLZeroness = true; 484*0fca6ea1SDimitry Andric Res.LMUL = DemandedFields::LMULLessThanOrEqualToM1; 485*0fca6ea1SDimitry Andric Res.TailPolicy = false; 486*0fca6ea1SDimitry Andric } 487*0fca6ea1SDimitry Andric 488*0fca6ea1SDimitry Andric // A tail undefined vmv.v.i/x or vfmv.v.f with VL=1 can be treated in the 489*0fca6ea1SDimitry Andric // same semantically as vmv.s.x. This is particularly useful since we don't 490*0fca6ea1SDimitry Andric // have an immediate form of vmv.s.x, and thus frequently use vmv.v.i in 491*0fca6ea1SDimitry Andric // it's place. Since a splat is non-constant time in LMUL, we do need to be 492*0fca6ea1SDimitry Andric // careful to not increase the number of active vector registers (unlike for 493*0fca6ea1SDimitry Andric // vmv.s.x.) 494*0fca6ea1SDimitry Andric if (isScalarSplatInstr(MI) && VLOp.isImm() && VLOp.getImm() == 1 && 495*0fca6ea1SDimitry Andric hasUndefinedMergeOp(MI)) { 496*0fca6ea1SDimitry Andric Res.LMUL = DemandedFields::LMULLessThanOrEqualToM1; 497*0fca6ea1SDimitry Andric Res.SEWLMULRatio = false; 498*0fca6ea1SDimitry Andric Res.VLAny = false; 499*0fca6ea1SDimitry Andric if (isFloatScalarMoveOrScalarSplatInstr(MI) && !ST->hasVInstructionsF64()) 500*0fca6ea1SDimitry Andric Res.SEW = DemandedFields::SEWGreaterThanOrEqualAndLessThan64; 501*0fca6ea1SDimitry Andric else 502*0fca6ea1SDimitry Andric Res.SEW = DemandedFields::SEWGreaterThanOrEqual; 503*0fca6ea1SDimitry Andric Res.TailPolicy = false; 504*0fca6ea1SDimitry Andric } 505*0fca6ea1SDimitry Andric } 506*0fca6ea1SDimitry Andric 50781ad6265SDimitry Andric return Res; 50881ad6265SDimitry Andric } 50981ad6265SDimitry Andric 51081ad6265SDimitry Andric /// Defines the abstract state with which the forward dataflow models the 51181ad6265SDimitry Andric /// values of the VL and VTYPE registers after insertion. 51281ad6265SDimitry Andric class VSETVLIInfo { 513*0fca6ea1SDimitry Andric struct AVLDef { 514*0fca6ea1SDimitry Andric // Every AVLDef should have a VNInfo, unless we're running without 515*0fca6ea1SDimitry Andric // LiveIntervals in which case this will be nullptr. 516*0fca6ea1SDimitry Andric const VNInfo *ValNo; 517*0fca6ea1SDimitry Andric Register DefReg; 518*0fca6ea1SDimitry Andric }; 51981ad6265SDimitry Andric union { 520*0fca6ea1SDimitry Andric AVLDef AVLRegDef; 52181ad6265SDimitry Andric unsigned AVLImm; 52281ad6265SDimitry Andric }; 52381ad6265SDimitry Andric 52481ad6265SDimitry Andric enum : uint8_t { 52581ad6265SDimitry Andric Uninitialized, 52681ad6265SDimitry Andric AVLIsReg, 52781ad6265SDimitry Andric AVLIsImm, 528*0fca6ea1SDimitry Andric AVLIsVLMAX, 529*0fca6ea1SDimitry Andric Unknown, // AVL and VTYPE are fully unknown 53081ad6265SDimitry Andric } State = Uninitialized; 53181ad6265SDimitry Andric 53281ad6265SDimitry Andric // Fields from VTYPE. 53381ad6265SDimitry Andric RISCVII::VLMUL VLMul = RISCVII::LMUL_1; 53481ad6265SDimitry Andric uint8_t SEW = 0; 53581ad6265SDimitry Andric uint8_t TailAgnostic : 1; 53681ad6265SDimitry Andric uint8_t MaskAgnostic : 1; 53781ad6265SDimitry Andric uint8_t SEWLMULRatioOnly : 1; 53881ad6265SDimitry Andric 53981ad6265SDimitry Andric public: 54081ad6265SDimitry Andric VSETVLIInfo() 54181ad6265SDimitry Andric : AVLImm(0), TailAgnostic(false), MaskAgnostic(false), 54281ad6265SDimitry Andric SEWLMULRatioOnly(false) {} 54381ad6265SDimitry Andric 54481ad6265SDimitry Andric static VSETVLIInfo getUnknown() { 54581ad6265SDimitry Andric VSETVLIInfo Info; 54681ad6265SDimitry Andric Info.setUnknown(); 54781ad6265SDimitry Andric return Info; 54881ad6265SDimitry Andric } 54981ad6265SDimitry Andric 55081ad6265SDimitry Andric bool isValid() const { return State != Uninitialized; } 55181ad6265SDimitry Andric void setUnknown() { State = Unknown; } 55281ad6265SDimitry Andric bool isUnknown() const { return State == Unknown; } 55381ad6265SDimitry Andric 554*0fca6ea1SDimitry Andric void setAVLRegDef(const VNInfo *VNInfo, Register AVLReg) { 555*0fca6ea1SDimitry Andric assert(AVLReg.isVirtual()); 556*0fca6ea1SDimitry Andric AVLRegDef.ValNo = VNInfo; 557*0fca6ea1SDimitry Andric AVLRegDef.DefReg = AVLReg; 55881ad6265SDimitry Andric State = AVLIsReg; 55981ad6265SDimitry Andric } 56081ad6265SDimitry Andric 56181ad6265SDimitry Andric void setAVLImm(unsigned Imm) { 56281ad6265SDimitry Andric AVLImm = Imm; 56381ad6265SDimitry Andric State = AVLIsImm; 56481ad6265SDimitry Andric } 56581ad6265SDimitry Andric 566*0fca6ea1SDimitry Andric void setAVLVLMAX() { State = AVLIsVLMAX; } 567*0fca6ea1SDimitry Andric 56881ad6265SDimitry Andric bool hasAVLImm() const { return State == AVLIsImm; } 56981ad6265SDimitry Andric bool hasAVLReg() const { return State == AVLIsReg; } 570*0fca6ea1SDimitry Andric bool hasAVLVLMAX() const { return State == AVLIsVLMAX; } 57181ad6265SDimitry Andric Register getAVLReg() const { 572*0fca6ea1SDimitry Andric assert(hasAVLReg() && AVLRegDef.DefReg.isVirtual()); 573*0fca6ea1SDimitry Andric return AVLRegDef.DefReg; 57481ad6265SDimitry Andric } 57581ad6265SDimitry Andric unsigned getAVLImm() const { 57681ad6265SDimitry Andric assert(hasAVLImm()); 57781ad6265SDimitry Andric return AVLImm; 57881ad6265SDimitry Andric } 579*0fca6ea1SDimitry Andric const VNInfo *getAVLVNInfo() const { 580*0fca6ea1SDimitry Andric assert(hasAVLReg()); 581*0fca6ea1SDimitry Andric return AVLRegDef.ValNo; 582*0fca6ea1SDimitry Andric } 583*0fca6ea1SDimitry Andric // Most AVLIsReg infos will have a single defining MachineInstr, unless it was 584*0fca6ea1SDimitry Andric // a PHI node. In that case getAVLVNInfo()->def will point to the block 585*0fca6ea1SDimitry Andric // boundary slot and this will return nullptr. If LiveIntervals isn't 586*0fca6ea1SDimitry Andric // available, nullptr is also returned. 587*0fca6ea1SDimitry Andric const MachineInstr *getAVLDefMI(const LiveIntervals *LIS) const { 588*0fca6ea1SDimitry Andric assert(hasAVLReg()); 589*0fca6ea1SDimitry Andric if (!LIS || getAVLVNInfo()->isPHIDef()) 590*0fca6ea1SDimitry Andric return nullptr; 591*0fca6ea1SDimitry Andric auto *MI = LIS->getInstructionFromIndex(getAVLVNInfo()->def); 592*0fca6ea1SDimitry Andric assert(MI); 593*0fca6ea1SDimitry Andric return MI; 594*0fca6ea1SDimitry Andric } 59581ad6265SDimitry Andric 5965f757f3fSDimitry Andric void setAVL(VSETVLIInfo Info) { 5975f757f3fSDimitry Andric assert(Info.isValid()); 5985f757f3fSDimitry Andric if (Info.isUnknown()) 5995f757f3fSDimitry Andric setUnknown(); 6005f757f3fSDimitry Andric else if (Info.hasAVLReg()) 601*0fca6ea1SDimitry Andric setAVLRegDef(Info.getAVLVNInfo(), Info.getAVLReg()); 602*0fca6ea1SDimitry Andric else if (Info.hasAVLVLMAX()) 603*0fca6ea1SDimitry Andric setAVLVLMAX(); 6045f757f3fSDimitry Andric else { 6055f757f3fSDimitry Andric assert(Info.hasAVLImm()); 6065f757f3fSDimitry Andric setAVLImm(Info.getAVLImm()); 6075f757f3fSDimitry Andric } 6085f757f3fSDimitry Andric } 6095f757f3fSDimitry Andric 61081ad6265SDimitry Andric unsigned getSEW() const { return SEW; } 61181ad6265SDimitry Andric RISCVII::VLMUL getVLMUL() const { return VLMul; } 6125f757f3fSDimitry Andric bool getTailAgnostic() const { return TailAgnostic; } 6135f757f3fSDimitry Andric bool getMaskAgnostic() const { return MaskAgnostic; } 61481ad6265SDimitry Andric 615*0fca6ea1SDimitry Andric bool hasNonZeroAVL(const LiveIntervals *LIS) const { 61681ad6265SDimitry Andric if (hasAVLImm()) 61781ad6265SDimitry Andric return getAVLImm() > 0; 61806c3fb27SDimitry Andric if (hasAVLReg()) { 619*0fca6ea1SDimitry Andric if (auto *DefMI = getAVLDefMI(LIS)) 620*0fca6ea1SDimitry Andric return isNonZeroLoadImmediate(*DefMI); 62106c3fb27SDimitry Andric } 622*0fca6ea1SDimitry Andric if (hasAVLVLMAX()) 623*0fca6ea1SDimitry Andric return true; 62481ad6265SDimitry Andric return false; 62581ad6265SDimitry Andric } 62681ad6265SDimitry Andric 62706c3fb27SDimitry Andric bool hasEquallyZeroAVL(const VSETVLIInfo &Other, 628*0fca6ea1SDimitry Andric const LiveIntervals *LIS) const { 629bdd1243dSDimitry Andric if (hasSameAVL(Other)) 630bdd1243dSDimitry Andric return true; 631*0fca6ea1SDimitry Andric return (hasNonZeroAVL(LIS) && Other.hasNonZeroAVL(LIS)); 632bdd1243dSDimitry Andric } 633bdd1243dSDimitry Andric 634*0fca6ea1SDimitry Andric bool hasSameAVLLatticeValue(const VSETVLIInfo &Other) const { 635*0fca6ea1SDimitry Andric if (hasAVLReg() && Other.hasAVLReg()) { 636*0fca6ea1SDimitry Andric assert(!getAVLVNInfo() == !Other.getAVLVNInfo() && 637*0fca6ea1SDimitry Andric "we either have intervals or we don't"); 638*0fca6ea1SDimitry Andric if (!getAVLVNInfo()) 63981ad6265SDimitry Andric return getAVLReg() == Other.getAVLReg(); 640*0fca6ea1SDimitry Andric return getAVLVNInfo()->id == Other.getAVLVNInfo()->id && 641*0fca6ea1SDimitry Andric getAVLReg() == Other.getAVLReg(); 642*0fca6ea1SDimitry Andric } 64381ad6265SDimitry Andric 64481ad6265SDimitry Andric if (hasAVLImm() && Other.hasAVLImm()) 64581ad6265SDimitry Andric return getAVLImm() == Other.getAVLImm(); 64681ad6265SDimitry Andric 647*0fca6ea1SDimitry Andric if (hasAVLVLMAX()) 648*0fca6ea1SDimitry Andric return Other.hasAVLVLMAX() && hasSameVLMAX(Other); 649*0fca6ea1SDimitry Andric 65081ad6265SDimitry Andric return false; 65181ad6265SDimitry Andric } 65281ad6265SDimitry Andric 653*0fca6ea1SDimitry Andric // Return true if the two lattice values are guaranteed to have 654*0fca6ea1SDimitry Andric // the same AVL value at runtime. 655*0fca6ea1SDimitry Andric bool hasSameAVL(const VSETVLIInfo &Other) const { 656*0fca6ea1SDimitry Andric // Without LiveIntervals, we don't know which instruction defines a 657*0fca6ea1SDimitry Andric // register. Since a register may be redefined, this means all AVLIsReg 658*0fca6ea1SDimitry Andric // states must be treated as possibly distinct. 659*0fca6ea1SDimitry Andric if (hasAVLReg() && Other.hasAVLReg()) { 660*0fca6ea1SDimitry Andric assert(!getAVLVNInfo() == !Other.getAVLVNInfo() && 661*0fca6ea1SDimitry Andric "we either have intervals or we don't"); 662*0fca6ea1SDimitry Andric if (!getAVLVNInfo()) 663*0fca6ea1SDimitry Andric return false; 664*0fca6ea1SDimitry Andric } 665*0fca6ea1SDimitry Andric return hasSameAVLLatticeValue(Other); 666*0fca6ea1SDimitry Andric } 667*0fca6ea1SDimitry Andric 66881ad6265SDimitry Andric void setVTYPE(unsigned VType) { 66981ad6265SDimitry Andric assert(isValid() && !isUnknown() && 67081ad6265SDimitry Andric "Can't set VTYPE for uninitialized or unknown"); 67181ad6265SDimitry Andric VLMul = RISCVVType::getVLMUL(VType); 67281ad6265SDimitry Andric SEW = RISCVVType::getSEW(VType); 67381ad6265SDimitry Andric TailAgnostic = RISCVVType::isTailAgnostic(VType); 67481ad6265SDimitry Andric MaskAgnostic = RISCVVType::isMaskAgnostic(VType); 67581ad6265SDimitry Andric } 67681ad6265SDimitry Andric void setVTYPE(RISCVII::VLMUL L, unsigned S, bool TA, bool MA) { 67781ad6265SDimitry Andric assert(isValid() && !isUnknown() && 67881ad6265SDimitry Andric "Can't set VTYPE for uninitialized or unknown"); 67981ad6265SDimitry Andric VLMul = L; 68081ad6265SDimitry Andric SEW = S; 68181ad6265SDimitry Andric TailAgnostic = TA; 68281ad6265SDimitry Andric MaskAgnostic = MA; 68381ad6265SDimitry Andric } 68481ad6265SDimitry Andric 6855f757f3fSDimitry Andric void setVLMul(RISCVII::VLMUL VLMul) { this->VLMul = VLMul; } 6865f757f3fSDimitry Andric 68781ad6265SDimitry Andric unsigned encodeVTYPE() const { 68881ad6265SDimitry Andric assert(isValid() && !isUnknown() && !SEWLMULRatioOnly && 68981ad6265SDimitry Andric "Can't encode VTYPE for uninitialized or unknown"); 69081ad6265SDimitry Andric return RISCVVType::encodeVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic); 69181ad6265SDimitry Andric } 69281ad6265SDimitry Andric 69381ad6265SDimitry Andric bool hasSEWLMULRatioOnly() const { return SEWLMULRatioOnly; } 69481ad6265SDimitry Andric 69581ad6265SDimitry Andric bool hasSameVTYPE(const VSETVLIInfo &Other) const { 69681ad6265SDimitry Andric assert(isValid() && Other.isValid() && 69781ad6265SDimitry Andric "Can't compare invalid VSETVLIInfos"); 69881ad6265SDimitry Andric assert(!isUnknown() && !Other.isUnknown() && 69981ad6265SDimitry Andric "Can't compare VTYPE in unknown state"); 70081ad6265SDimitry Andric assert(!SEWLMULRatioOnly && !Other.SEWLMULRatioOnly && 70181ad6265SDimitry Andric "Can't compare when only LMUL/SEW ratio is valid."); 70281ad6265SDimitry Andric return std::tie(VLMul, SEW, TailAgnostic, MaskAgnostic) == 70381ad6265SDimitry Andric std::tie(Other.VLMul, Other.SEW, Other.TailAgnostic, 70481ad6265SDimitry Andric Other.MaskAgnostic); 70581ad6265SDimitry Andric } 70681ad6265SDimitry Andric 70781ad6265SDimitry Andric unsigned getSEWLMULRatio() const { 70881ad6265SDimitry Andric assert(isValid() && !isUnknown() && 70981ad6265SDimitry Andric "Can't use VTYPE for uninitialized or unknown"); 710bdd1243dSDimitry Andric return RISCVVType::getSEWLMULRatio(SEW, VLMul); 71181ad6265SDimitry Andric } 71281ad6265SDimitry Andric 71381ad6265SDimitry Andric // Check if the VTYPE for these two VSETVLIInfos produce the same VLMAX. 71481ad6265SDimitry Andric // Note that having the same VLMAX ensures that both share the same 71581ad6265SDimitry Andric // function from AVL to VL; that is, they must produce the same VL value 71681ad6265SDimitry Andric // for any given AVL value. 71781ad6265SDimitry Andric bool hasSameVLMAX(const VSETVLIInfo &Other) const { 71881ad6265SDimitry Andric assert(isValid() && Other.isValid() && 71981ad6265SDimitry Andric "Can't compare invalid VSETVLIInfos"); 72081ad6265SDimitry Andric assert(!isUnknown() && !Other.isUnknown() && 72181ad6265SDimitry Andric "Can't compare VTYPE in unknown state"); 72281ad6265SDimitry Andric return getSEWLMULRatio() == Other.getSEWLMULRatio(); 72381ad6265SDimitry Andric } 72481ad6265SDimitry Andric 725bdd1243dSDimitry Andric bool hasCompatibleVTYPE(const DemandedFields &Used, 72681ad6265SDimitry Andric const VSETVLIInfo &Require) const { 72706c3fb27SDimitry Andric return areCompatibleVTYPEs(Require.encodeVTYPE(), encodeVTYPE(), Used); 72881ad6265SDimitry Andric } 72981ad6265SDimitry Andric 73081ad6265SDimitry Andric // Determine whether the vector instructions requirements represented by 73181ad6265SDimitry Andric // Require are compatible with the previous vsetvli instruction represented 73281ad6265SDimitry Andric // by this. MI is the instruction whose requirements we're considering. 73306c3fb27SDimitry Andric bool isCompatible(const DemandedFields &Used, const VSETVLIInfo &Require, 734*0fca6ea1SDimitry Andric const LiveIntervals *LIS) const { 73581ad6265SDimitry Andric assert(isValid() && Require.isValid() && 73681ad6265SDimitry Andric "Can't compare invalid VSETVLIInfos"); 73781ad6265SDimitry Andric // Nothing is compatible with Unknown. 73881ad6265SDimitry Andric if (isUnknown() || Require.isUnknown()) 73981ad6265SDimitry Andric return false; 74081ad6265SDimitry Andric 74181ad6265SDimitry Andric // If only our VLMAX ratio is valid, then this isn't compatible. 742*0fca6ea1SDimitry Andric if (SEWLMULRatioOnly || Require.SEWLMULRatioOnly) 74381ad6265SDimitry Andric return false; 74481ad6265SDimitry Andric 745*0fca6ea1SDimitry Andric if (Used.VLAny && !(hasSameAVL(Require) && hasSameVLMAX(Require))) 746bdd1243dSDimitry Andric return false; 747bdd1243dSDimitry Andric 748*0fca6ea1SDimitry Andric if (Used.VLZeroness && !hasEquallyZeroAVL(Require, LIS)) 749bdd1243dSDimitry Andric return false; 750bdd1243dSDimitry Andric 75106c3fb27SDimitry Andric return hasCompatibleVTYPE(Used, Require); 75281ad6265SDimitry Andric } 75381ad6265SDimitry Andric 75481ad6265SDimitry Andric bool operator==(const VSETVLIInfo &Other) const { 75581ad6265SDimitry Andric // Uninitialized is only equal to another Uninitialized. 75681ad6265SDimitry Andric if (!isValid()) 75781ad6265SDimitry Andric return !Other.isValid(); 75881ad6265SDimitry Andric if (!Other.isValid()) 75981ad6265SDimitry Andric return !isValid(); 76081ad6265SDimitry Andric 76181ad6265SDimitry Andric // Unknown is only equal to another Unknown. 76281ad6265SDimitry Andric if (isUnknown()) 76381ad6265SDimitry Andric return Other.isUnknown(); 76481ad6265SDimitry Andric if (Other.isUnknown()) 76581ad6265SDimitry Andric return isUnknown(); 76681ad6265SDimitry Andric 767*0fca6ea1SDimitry Andric if (!hasSameAVLLatticeValue(Other)) 76881ad6265SDimitry Andric return false; 76981ad6265SDimitry Andric 77081ad6265SDimitry Andric // If the SEWLMULRatioOnly bits are different, then they aren't equal. 77181ad6265SDimitry Andric if (SEWLMULRatioOnly != Other.SEWLMULRatioOnly) 77281ad6265SDimitry Andric return false; 77381ad6265SDimitry Andric 77481ad6265SDimitry Andric // If only the VLMAX is valid, check that it is the same. 77581ad6265SDimitry Andric if (SEWLMULRatioOnly) 77681ad6265SDimitry Andric return hasSameVLMAX(Other); 77781ad6265SDimitry Andric 77881ad6265SDimitry Andric // If the full VTYPE is valid, check that it is the same. 77981ad6265SDimitry Andric return hasSameVTYPE(Other); 78081ad6265SDimitry Andric } 78181ad6265SDimitry Andric 78281ad6265SDimitry Andric bool operator!=(const VSETVLIInfo &Other) const { 78381ad6265SDimitry Andric return !(*this == Other); 78481ad6265SDimitry Andric } 78581ad6265SDimitry Andric 78681ad6265SDimitry Andric // Calculate the VSETVLIInfo visible to a block assuming this and Other are 78781ad6265SDimitry Andric // both predecessors. 78881ad6265SDimitry Andric VSETVLIInfo intersect(const VSETVLIInfo &Other) const { 78981ad6265SDimitry Andric // If the new value isn't valid, ignore it. 79081ad6265SDimitry Andric if (!Other.isValid()) 79181ad6265SDimitry Andric return *this; 79281ad6265SDimitry Andric 79381ad6265SDimitry Andric // If this value isn't valid, this must be the first predecessor, use it. 79481ad6265SDimitry Andric if (!isValid()) 79581ad6265SDimitry Andric return Other; 79681ad6265SDimitry Andric 79781ad6265SDimitry Andric // If either is unknown, the result is unknown. 79881ad6265SDimitry Andric if (isUnknown() || Other.isUnknown()) 79981ad6265SDimitry Andric return VSETVLIInfo::getUnknown(); 80081ad6265SDimitry Andric 80181ad6265SDimitry Andric // If we have an exact, match return this. 80281ad6265SDimitry Andric if (*this == Other) 80381ad6265SDimitry Andric return *this; 80481ad6265SDimitry Andric 80581ad6265SDimitry Andric // Not an exact match, but maybe the AVL and VLMAX are the same. If so, 80681ad6265SDimitry Andric // return an SEW/LMUL ratio only value. 80781ad6265SDimitry Andric if (hasSameAVL(Other) && hasSameVLMAX(Other)) { 80881ad6265SDimitry Andric VSETVLIInfo MergeInfo = *this; 80981ad6265SDimitry Andric MergeInfo.SEWLMULRatioOnly = true; 81081ad6265SDimitry Andric return MergeInfo; 81181ad6265SDimitry Andric } 81281ad6265SDimitry Andric 81381ad6265SDimitry Andric // Otherwise the result is unknown. 81481ad6265SDimitry Andric return VSETVLIInfo::getUnknown(); 81581ad6265SDimitry Andric } 81681ad6265SDimitry Andric 81781ad6265SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 81881ad6265SDimitry Andric /// Support for debugging, callable in GDB: V->dump() 81981ad6265SDimitry Andric LLVM_DUMP_METHOD void dump() const { 82081ad6265SDimitry Andric print(dbgs()); 82181ad6265SDimitry Andric dbgs() << "\n"; 82281ad6265SDimitry Andric } 82381ad6265SDimitry Andric 82481ad6265SDimitry Andric /// Implement operator<<. 82581ad6265SDimitry Andric /// @{ 82681ad6265SDimitry Andric void print(raw_ostream &OS) const { 82781ad6265SDimitry Andric OS << "{"; 82881ad6265SDimitry Andric if (!isValid()) 82981ad6265SDimitry Andric OS << "Uninitialized"; 83081ad6265SDimitry Andric if (isUnknown()) 83181ad6265SDimitry Andric OS << "unknown"; 83281ad6265SDimitry Andric if (hasAVLReg()) 833*0fca6ea1SDimitry Andric OS << "AVLReg=" << llvm::printReg(getAVLReg()); 83481ad6265SDimitry Andric if (hasAVLImm()) 83581ad6265SDimitry Andric OS << "AVLImm=" << (unsigned)AVLImm; 836*0fca6ea1SDimitry Andric if (hasAVLVLMAX()) 837*0fca6ea1SDimitry Andric OS << "AVLVLMAX"; 83881ad6265SDimitry Andric OS << ", " 83981ad6265SDimitry Andric << "VLMul=" << (unsigned)VLMul << ", " 84081ad6265SDimitry Andric << "SEW=" << (unsigned)SEW << ", " 84181ad6265SDimitry Andric << "TailAgnostic=" << (bool)TailAgnostic << ", " 84281ad6265SDimitry Andric << "MaskAgnostic=" << (bool)MaskAgnostic << ", " 84381ad6265SDimitry Andric << "SEWLMULRatioOnly=" << (bool)SEWLMULRatioOnly << "}"; 84481ad6265SDimitry Andric } 84581ad6265SDimitry Andric #endif 84681ad6265SDimitry Andric }; 84781ad6265SDimitry Andric 84881ad6265SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 84981ad6265SDimitry Andric LLVM_ATTRIBUTE_USED 85081ad6265SDimitry Andric inline raw_ostream &operator<<(raw_ostream &OS, const VSETVLIInfo &V) { 85181ad6265SDimitry Andric V.print(OS); 85281ad6265SDimitry Andric return OS; 85381ad6265SDimitry Andric } 85481ad6265SDimitry Andric #endif 85581ad6265SDimitry Andric 85681ad6265SDimitry Andric struct BlockData { 85781ad6265SDimitry Andric // The VSETVLIInfo that represents the VL/VTYPE settings on exit from this 85881ad6265SDimitry Andric // block. Calculated in Phase 2. 85981ad6265SDimitry Andric VSETVLIInfo Exit; 86081ad6265SDimitry Andric 86181ad6265SDimitry Andric // The VSETVLIInfo that represents the VL/VTYPE settings from all predecessor 86281ad6265SDimitry Andric // blocks. Calculated in Phase 2, and used by Phase 3. 86381ad6265SDimitry Andric VSETVLIInfo Pred; 86481ad6265SDimitry Andric 86581ad6265SDimitry Andric // Keeps track of whether the block is already in the queue. 86681ad6265SDimitry Andric bool InQueue = false; 86781ad6265SDimitry Andric 86881ad6265SDimitry Andric BlockData() = default; 86981ad6265SDimitry Andric }; 87081ad6265SDimitry Andric 87181ad6265SDimitry Andric class RISCVInsertVSETVLI : public MachineFunctionPass { 8725f757f3fSDimitry Andric const RISCVSubtarget *ST; 87381ad6265SDimitry Andric const TargetInstrInfo *TII; 87481ad6265SDimitry Andric MachineRegisterInfo *MRI; 875*0fca6ea1SDimitry Andric // Possibly null! 876*0fca6ea1SDimitry Andric LiveIntervals *LIS; 87781ad6265SDimitry Andric 87881ad6265SDimitry Andric std::vector<BlockData> BlockInfo; 87981ad6265SDimitry Andric std::queue<const MachineBasicBlock *> WorkList; 88081ad6265SDimitry Andric 88181ad6265SDimitry Andric public: 88281ad6265SDimitry Andric static char ID; 88381ad6265SDimitry Andric 8845f757f3fSDimitry Andric RISCVInsertVSETVLI() : MachineFunctionPass(ID) {} 88581ad6265SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 88681ad6265SDimitry Andric 88781ad6265SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 88881ad6265SDimitry Andric AU.setPreservesCFG(); 889*0fca6ea1SDimitry Andric 890*0fca6ea1SDimitry Andric AU.addUsedIfAvailable<LiveIntervalsWrapperPass>(); 891*0fca6ea1SDimitry Andric AU.addPreserved<LiveIntervalsWrapperPass>(); 892*0fca6ea1SDimitry Andric AU.addPreserved<SlotIndexesWrapperPass>(); 893*0fca6ea1SDimitry Andric AU.addPreserved<LiveDebugVariables>(); 894*0fca6ea1SDimitry Andric AU.addPreserved<LiveStacks>(); 895*0fca6ea1SDimitry Andric 89681ad6265SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 89781ad6265SDimitry Andric } 89881ad6265SDimitry Andric 89981ad6265SDimitry Andric StringRef getPassName() const override { return RISCV_INSERT_VSETVLI_NAME; } 90081ad6265SDimitry Andric 90181ad6265SDimitry Andric private: 902*0fca6ea1SDimitry Andric bool needVSETVLI(const DemandedFields &Used, const VSETVLIInfo &Require, 90381ad6265SDimitry Andric const VSETVLIInfo &CurInfo) const; 90481ad6265SDimitry Andric bool needVSETVLIPHI(const VSETVLIInfo &Require, 90581ad6265SDimitry Andric const MachineBasicBlock &MBB) const; 90681ad6265SDimitry Andric void insertVSETVLI(MachineBasicBlock &MBB, 90781ad6265SDimitry Andric MachineBasicBlock::iterator InsertPt, DebugLoc DL, 90881ad6265SDimitry Andric const VSETVLIInfo &Info, const VSETVLIInfo &PrevInfo); 90981ad6265SDimitry Andric 9105f757f3fSDimitry Andric void transferBefore(VSETVLIInfo &Info, const MachineInstr &MI) const; 9115f757f3fSDimitry Andric void transferAfter(VSETVLIInfo &Info, const MachineInstr &MI) const; 9125f757f3fSDimitry Andric bool computeVLVTYPEChanges(const MachineBasicBlock &MBB, 9135f757f3fSDimitry Andric VSETVLIInfo &Info) const; 91481ad6265SDimitry Andric void computeIncomingVLVTYPE(const MachineBasicBlock &MBB); 91581ad6265SDimitry Andric void emitVSETVLIs(MachineBasicBlock &MBB); 91681ad6265SDimitry Andric void doPRE(MachineBasicBlock &MBB); 91781ad6265SDimitry Andric void insertReadVL(MachineBasicBlock &MBB); 918*0fca6ea1SDimitry Andric 919*0fca6ea1SDimitry Andric bool canMutatePriorConfig(const MachineInstr &PrevMI, const MachineInstr &MI, 920*0fca6ea1SDimitry Andric const DemandedFields &Used) const; 921*0fca6ea1SDimitry Andric void coalesceVSETVLIs(MachineBasicBlock &MBB) const; 922*0fca6ea1SDimitry Andric 923*0fca6ea1SDimitry Andric VSETVLIInfo getInfoForVSETVLI(const MachineInstr &MI) const; 924*0fca6ea1SDimitry Andric VSETVLIInfo computeInfoForInstr(const MachineInstr &MI) const; 925*0fca6ea1SDimitry Andric void forwardVSETVLIAVL(VSETVLIInfo &Info) const; 92681ad6265SDimitry Andric }; 92781ad6265SDimitry Andric 92881ad6265SDimitry Andric } // end anonymous namespace 92981ad6265SDimitry Andric 93081ad6265SDimitry Andric char RISCVInsertVSETVLI::ID = 0; 931*0fca6ea1SDimitry Andric char &llvm::RISCVInsertVSETVLIID = RISCVInsertVSETVLI::ID; 93281ad6265SDimitry Andric 93381ad6265SDimitry Andric INITIALIZE_PASS(RISCVInsertVSETVLI, DEBUG_TYPE, RISCV_INSERT_VSETVLI_NAME, 93481ad6265SDimitry Andric false, false) 93581ad6265SDimitry Andric 936*0fca6ea1SDimitry Andric // If the AVL is defined by a vsetvli's output vl with the same VLMAX, we can 937*0fca6ea1SDimitry Andric // replace the AVL operand with the AVL of the defining vsetvli. E.g. 938*0fca6ea1SDimitry Andric // 939*0fca6ea1SDimitry Andric // %vl = PseudoVSETVLI %avl:gpr, SEW=32, LMUL=M1 940*0fca6ea1SDimitry Andric // $x0 = PseudoVSETVLI %vl:gpr, SEW=32, LMUL=M1 941*0fca6ea1SDimitry Andric // -> 942*0fca6ea1SDimitry Andric // %vl = PseudoVSETVLI %avl:gpr, SEW=32, LMUL=M1 943*0fca6ea1SDimitry Andric // $x0 = PseudoVSETVLI %avl:gpr, SEW=32, LMUL=M1 944*0fca6ea1SDimitry Andric void RISCVInsertVSETVLI::forwardVSETVLIAVL(VSETVLIInfo &Info) const { 945*0fca6ea1SDimitry Andric if (!Info.hasAVLReg()) 946*0fca6ea1SDimitry Andric return; 947*0fca6ea1SDimitry Andric const MachineInstr *DefMI = Info.getAVLDefMI(LIS); 948*0fca6ea1SDimitry Andric if (!DefMI || !isVectorConfigInstr(*DefMI)) 949*0fca6ea1SDimitry Andric return; 950*0fca6ea1SDimitry Andric VSETVLIInfo DefInstrInfo = getInfoForVSETVLI(*DefMI); 951*0fca6ea1SDimitry Andric if (!DefInstrInfo.hasSameVLMAX(Info)) 952*0fca6ea1SDimitry Andric return; 953*0fca6ea1SDimitry Andric Info.setAVL(DefInstrInfo); 954*0fca6ea1SDimitry Andric } 955*0fca6ea1SDimitry Andric 9565f757f3fSDimitry Andric // Return a VSETVLIInfo representing the changes made by this VSETVLI or 9575f757f3fSDimitry Andric // VSETIVLI instruction. 958*0fca6ea1SDimitry Andric VSETVLIInfo 959*0fca6ea1SDimitry Andric RISCVInsertVSETVLI::getInfoForVSETVLI(const MachineInstr &MI) const { 9605f757f3fSDimitry Andric VSETVLIInfo NewInfo; 9615f757f3fSDimitry Andric if (MI.getOpcode() == RISCV::PseudoVSETIVLI) { 9625f757f3fSDimitry Andric NewInfo.setAVLImm(MI.getOperand(1).getImm()); 9635f757f3fSDimitry Andric } else { 9645f757f3fSDimitry Andric assert(MI.getOpcode() == RISCV::PseudoVSETVLI || 9655f757f3fSDimitry Andric MI.getOpcode() == RISCV::PseudoVSETVLIX0); 9665f757f3fSDimitry Andric Register AVLReg = MI.getOperand(1).getReg(); 9675f757f3fSDimitry Andric assert((AVLReg != RISCV::X0 || MI.getOperand(0).getReg() != RISCV::X0) && 9685f757f3fSDimitry Andric "Can't handle X0, X0 vsetvli yet"); 969*0fca6ea1SDimitry Andric if (AVLReg == RISCV::X0) 970*0fca6ea1SDimitry Andric NewInfo.setAVLVLMAX(); 971*0fca6ea1SDimitry Andric else if (MI.getOperand(1).isUndef()) 972*0fca6ea1SDimitry Andric // Otherwise use an AVL of 1 to avoid depending on previous vl. 973*0fca6ea1SDimitry Andric NewInfo.setAVLImm(1); 974*0fca6ea1SDimitry Andric else { 975*0fca6ea1SDimitry Andric VNInfo *VNI = getVNInfoFromReg(AVLReg, MI, LIS); 976*0fca6ea1SDimitry Andric NewInfo.setAVLRegDef(VNI, AVLReg); 977*0fca6ea1SDimitry Andric } 9785f757f3fSDimitry Andric } 9795f757f3fSDimitry Andric NewInfo.setVTYPE(MI.getOperand(2).getImm()); 9805f757f3fSDimitry Andric 981*0fca6ea1SDimitry Andric forwardVSETVLIAVL(NewInfo); 982*0fca6ea1SDimitry Andric 9835f757f3fSDimitry Andric return NewInfo; 9845f757f3fSDimitry Andric } 9855f757f3fSDimitry Andric 9867a6dacacSDimitry Andric static unsigned computeVLMAX(unsigned VLEN, unsigned SEW, 9877a6dacacSDimitry Andric RISCVII::VLMUL VLMul) { 9887a6dacacSDimitry Andric auto [LMul, Fractional] = RISCVVType::decodeVLMUL(VLMul); 9897a6dacacSDimitry Andric if (Fractional) 9907a6dacacSDimitry Andric VLEN = VLEN / LMul; 9917a6dacacSDimitry Andric else 9927a6dacacSDimitry Andric VLEN = VLEN * LMul; 9937a6dacacSDimitry Andric return VLEN/SEW; 9947a6dacacSDimitry Andric } 9957a6dacacSDimitry Andric 996*0fca6ea1SDimitry Andric VSETVLIInfo 997*0fca6ea1SDimitry Andric RISCVInsertVSETVLI::computeInfoForInstr(const MachineInstr &MI) const { 99881ad6265SDimitry Andric VSETVLIInfo InstrInfo; 999*0fca6ea1SDimitry Andric const uint64_t TSFlags = MI.getDesc().TSFlags; 100081ad6265SDimitry Andric 100106c3fb27SDimitry Andric bool TailAgnostic = true; 100206c3fb27SDimitry Andric bool MaskAgnostic = true; 1003*0fca6ea1SDimitry Andric if (!hasUndefinedMergeOp(MI)) { 1004bdd1243dSDimitry Andric // Start with undisturbed. 1005bdd1243dSDimitry Andric TailAgnostic = false; 1006bdd1243dSDimitry Andric MaskAgnostic = false; 1007bdd1243dSDimitry Andric 1008bdd1243dSDimitry Andric // If there is a policy operand, use it. 100981ad6265SDimitry Andric if (RISCVII::hasVecPolicyOp(TSFlags)) { 101081ad6265SDimitry Andric const MachineOperand &Op = MI.getOperand(MI.getNumExplicitOperands() - 1); 101181ad6265SDimitry Andric uint64_t Policy = Op.getImm(); 101281ad6265SDimitry Andric assert(Policy <= (RISCVII::TAIL_AGNOSTIC | RISCVII::MASK_AGNOSTIC) && 101381ad6265SDimitry Andric "Invalid Policy Value"); 101481ad6265SDimitry Andric TailAgnostic = Policy & RISCVII::TAIL_AGNOSTIC; 101581ad6265SDimitry Andric MaskAgnostic = Policy & RISCVII::MASK_AGNOSTIC; 1016bdd1243dSDimitry Andric } 1017bdd1243dSDimitry Andric 101881ad6265SDimitry Andric // Some pseudo instructions force a tail agnostic policy despite having a 101981ad6265SDimitry Andric // tied def. 102081ad6265SDimitry Andric if (RISCVII::doesForceTailAgnostic(TSFlags)) 102181ad6265SDimitry Andric TailAgnostic = true; 1022bdd1243dSDimitry Andric 1023bdd1243dSDimitry Andric if (!RISCVII::usesMaskPolicy(TSFlags)) 1024bdd1243dSDimitry Andric MaskAgnostic = true; 102581ad6265SDimitry Andric } 102681ad6265SDimitry Andric 102781ad6265SDimitry Andric RISCVII::VLMUL VLMul = RISCVII::getLMul(TSFlags); 102881ad6265SDimitry Andric 102981ad6265SDimitry Andric unsigned Log2SEW = MI.getOperand(getSEWOpNum(MI)).getImm(); 103081ad6265SDimitry Andric // A Log2SEW of 0 is an operation on mask registers only. 103181ad6265SDimitry Andric unsigned SEW = Log2SEW ? 1 << Log2SEW : 8; 103281ad6265SDimitry Andric assert(RISCVVType::isValidSEW(SEW) && "Unexpected SEW"); 103381ad6265SDimitry Andric 103481ad6265SDimitry Andric if (RISCVII::hasVLOp(TSFlags)) { 103581ad6265SDimitry Andric const MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI)); 103681ad6265SDimitry Andric if (VLOp.isImm()) { 103781ad6265SDimitry Andric int64_t Imm = VLOp.getImm(); 103881ad6265SDimitry Andric // Conver the VLMax sentintel to X0 register. 10397a6dacacSDimitry Andric if (Imm == RISCV::VLMaxSentinel) { 10407a6dacacSDimitry Andric // If we know the exact VLEN, see if we can use the constant encoding 10417a6dacacSDimitry Andric // for the VLMAX instead. This reduces register pressure slightly. 1042*0fca6ea1SDimitry Andric const unsigned VLMAX = computeVLMAX(ST->getRealMaxVLen(), SEW, VLMul); 1043*0fca6ea1SDimitry Andric if (ST->getRealMinVLen() == ST->getRealMaxVLen() && VLMAX <= 31) 10447a6dacacSDimitry Andric InstrInfo.setAVLImm(VLMAX); 10457a6dacacSDimitry Andric else 1046*0fca6ea1SDimitry Andric InstrInfo.setAVLVLMAX(); 10477a6dacacSDimitry Andric } 104881ad6265SDimitry Andric else 104981ad6265SDimitry Andric InstrInfo.setAVLImm(Imm); 1050*0fca6ea1SDimitry Andric } else if (VLOp.isUndef()) { 1051*0fca6ea1SDimitry Andric // Otherwise use an AVL of 1 to avoid depending on previous vl. 1052*0fca6ea1SDimitry Andric InstrInfo.setAVLImm(1); 105381ad6265SDimitry Andric } else { 1054*0fca6ea1SDimitry Andric VNInfo *VNI = getVNInfoFromReg(VLOp.getReg(), MI, LIS); 1055*0fca6ea1SDimitry Andric InstrInfo.setAVLRegDef(VNI, VLOp.getReg()); 105681ad6265SDimitry Andric } 105781ad6265SDimitry Andric } else { 10585f757f3fSDimitry Andric assert(isScalarExtractInstr(MI)); 1059*0fca6ea1SDimitry Andric // Pick a random value for state tracking purposes, will be ignored via 1060*0fca6ea1SDimitry Andric // the demanded fields mechanism 1061*0fca6ea1SDimitry Andric InstrInfo.setAVLImm(1); 106281ad6265SDimitry Andric } 106381ad6265SDimitry Andric #ifndef NDEBUG 1064bdd1243dSDimitry Andric if (std::optional<unsigned> EEW = getEEWForLoadStore(MI)) { 106581ad6265SDimitry Andric assert(SEW == EEW && "Initial SEW doesn't match expected EEW"); 106681ad6265SDimitry Andric } 106781ad6265SDimitry Andric #endif 106881ad6265SDimitry Andric InstrInfo.setVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic); 106981ad6265SDimitry Andric 1070*0fca6ea1SDimitry Andric forwardVSETVLIAVL(InstrInfo); 10715f757f3fSDimitry Andric 107281ad6265SDimitry Andric return InstrInfo; 107381ad6265SDimitry Andric } 107481ad6265SDimitry Andric 107581ad6265SDimitry Andric void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB, 107681ad6265SDimitry Andric MachineBasicBlock::iterator InsertPt, DebugLoc DL, 107781ad6265SDimitry Andric const VSETVLIInfo &Info, const VSETVLIInfo &PrevInfo) { 107881ad6265SDimitry Andric 10797a6dacacSDimitry Andric ++NumInsertedVSETVL; 108006c3fb27SDimitry Andric if (PrevInfo.isValid() && !PrevInfo.isUnknown()) { 108181ad6265SDimitry Andric // Use X0, X0 form if the AVL is the same and the SEW+LMUL gives the same 108281ad6265SDimitry Andric // VLMAX. 108306c3fb27SDimitry Andric if (Info.hasSameAVL(PrevInfo) && Info.hasSameVLMAX(PrevInfo)) { 1084*0fca6ea1SDimitry Andric auto MI = BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0)) 108581ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 108681ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Kill) 108781ad6265SDimitry Andric .addImm(Info.encodeVTYPE()) 108881ad6265SDimitry Andric .addReg(RISCV::VL, RegState::Implicit); 1089*0fca6ea1SDimitry Andric if (LIS) 1090*0fca6ea1SDimitry Andric LIS->InsertMachineInstrInMaps(*MI); 109181ad6265SDimitry Andric return; 109281ad6265SDimitry Andric } 109381ad6265SDimitry Andric 109406c3fb27SDimitry Andric // If our AVL is a virtual register, it might be defined by a VSET(I)VLI. If 109506c3fb27SDimitry Andric // it has the same VLMAX we want and the last VL/VTYPE we observed is the 109606c3fb27SDimitry Andric // same, we can use the X0, X0 form. 1097*0fca6ea1SDimitry Andric if (Info.hasSameVLMAX(PrevInfo) && Info.hasAVLReg()) { 1098*0fca6ea1SDimitry Andric if (const MachineInstr *DefMI = Info.getAVLDefMI(LIS); 1099*0fca6ea1SDimitry Andric DefMI && isVectorConfigInstr(*DefMI)) { 110006c3fb27SDimitry Andric VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI); 110106c3fb27SDimitry Andric if (DefInfo.hasSameAVL(PrevInfo) && DefInfo.hasSameVLMAX(PrevInfo)) { 1102*0fca6ea1SDimitry Andric auto MI = BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0)) 110306c3fb27SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 110406c3fb27SDimitry Andric .addReg(RISCV::X0, RegState::Kill) 110506c3fb27SDimitry Andric .addImm(Info.encodeVTYPE()) 110606c3fb27SDimitry Andric .addReg(RISCV::VL, RegState::Implicit); 1107*0fca6ea1SDimitry Andric if (LIS) 1108*0fca6ea1SDimitry Andric LIS->InsertMachineInstrInMaps(*MI); 110906c3fb27SDimitry Andric return; 111006c3fb27SDimitry Andric } 111106c3fb27SDimitry Andric } 111206c3fb27SDimitry Andric } 111306c3fb27SDimitry Andric } 111406c3fb27SDimitry Andric 111581ad6265SDimitry Andric if (Info.hasAVLImm()) { 1116*0fca6ea1SDimitry Andric auto MI = BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETIVLI)) 111781ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 111881ad6265SDimitry Andric .addImm(Info.getAVLImm()) 111981ad6265SDimitry Andric .addImm(Info.encodeVTYPE()); 1120*0fca6ea1SDimitry Andric if (LIS) 1121*0fca6ea1SDimitry Andric LIS->InsertMachineInstrInMaps(*MI); 1122*0fca6ea1SDimitry Andric return; 1123*0fca6ea1SDimitry Andric } 1124*0fca6ea1SDimitry Andric 1125*0fca6ea1SDimitry Andric if (Info.hasAVLVLMAX()) { 1126*0fca6ea1SDimitry Andric Register DestReg = MRI->createVirtualRegister(&RISCV::GPRRegClass); 1127*0fca6ea1SDimitry Andric auto MI = BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0)) 1128*0fca6ea1SDimitry Andric .addReg(DestReg, RegState::Define | RegState::Dead) 1129*0fca6ea1SDimitry Andric .addReg(RISCV::X0, RegState::Kill) 1130*0fca6ea1SDimitry Andric .addImm(Info.encodeVTYPE()); 1131*0fca6ea1SDimitry Andric if (LIS) { 1132*0fca6ea1SDimitry Andric LIS->InsertMachineInstrInMaps(*MI); 1133*0fca6ea1SDimitry Andric LIS->createAndComputeVirtRegInterval(DestReg); 1134*0fca6ea1SDimitry Andric } 113581ad6265SDimitry Andric return; 113681ad6265SDimitry Andric } 113781ad6265SDimitry Andric 113881ad6265SDimitry Andric Register AVLReg = Info.getAVLReg(); 113981ad6265SDimitry Andric MRI->constrainRegClass(AVLReg, &RISCV::GPRNoX0RegClass); 1140*0fca6ea1SDimitry Andric auto MI = BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLI)) 1141*0fca6ea1SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 114281ad6265SDimitry Andric .addReg(AVLReg) 114381ad6265SDimitry Andric .addImm(Info.encodeVTYPE()); 1144*0fca6ea1SDimitry Andric if (LIS) { 1145*0fca6ea1SDimitry Andric LIS->InsertMachineInstrInMaps(*MI); 1146*0fca6ea1SDimitry Andric LiveInterval &LI = LIS->getInterval(AVLReg); 1147*0fca6ea1SDimitry Andric SlotIndex SI = LIS->getInstructionIndex(*MI).getRegSlot(); 1148*0fca6ea1SDimitry Andric // If the AVL value isn't live at MI, do a quick check to see if it's easily 1149*0fca6ea1SDimitry Andric // extendable. Otherwise, we need to copy it. 1150*0fca6ea1SDimitry Andric if (LI.getVNInfoBefore(SI) != Info.getAVLVNInfo()) { 1151*0fca6ea1SDimitry Andric if (!LI.liveAt(SI) && LI.containsOneValue()) 1152*0fca6ea1SDimitry Andric LIS->extendToIndices(LI, SI); 1153*0fca6ea1SDimitry Andric else { 1154*0fca6ea1SDimitry Andric Register AVLCopyReg = 1155*0fca6ea1SDimitry Andric MRI->createVirtualRegister(&RISCV::GPRNoX0RegClass); 1156*0fca6ea1SDimitry Andric MachineBasicBlock::iterator II; 1157*0fca6ea1SDimitry Andric if (Info.getAVLVNInfo()->isPHIDef()) 1158*0fca6ea1SDimitry Andric II = LIS->getMBBFromIndex(Info.getAVLVNInfo()->def)->getFirstNonPHI(); 1159*0fca6ea1SDimitry Andric else { 1160*0fca6ea1SDimitry Andric II = LIS->getInstructionFromIndex(Info.getAVLVNInfo()->def); 1161*0fca6ea1SDimitry Andric II = std::next(II); 116281ad6265SDimitry Andric } 1163*0fca6ea1SDimitry Andric assert(II.isValid()); 1164*0fca6ea1SDimitry Andric auto AVLCopy = 1165*0fca6ea1SDimitry Andric BuildMI(*II->getParent(), II, DL, TII->get(RISCV::COPY), AVLCopyReg) 1166*0fca6ea1SDimitry Andric .addReg(AVLReg); 1167*0fca6ea1SDimitry Andric LIS->InsertMachineInstrInMaps(*AVLCopy); 1168*0fca6ea1SDimitry Andric MI->getOperand(1).setReg(AVLCopyReg); 1169*0fca6ea1SDimitry Andric LIS->createAndComputeVirtRegInterval(AVLCopyReg); 1170*0fca6ea1SDimitry Andric } 1171*0fca6ea1SDimitry Andric } 1172*0fca6ea1SDimitry Andric } 117381ad6265SDimitry Andric } 117481ad6265SDimitry Andric 117581ad6265SDimitry Andric /// Return true if a VSETVLI is required to transition from CurInfo to Require 1176*0fca6ea1SDimitry Andric /// given a set of DemandedFields \p Used. 1177*0fca6ea1SDimitry Andric bool RISCVInsertVSETVLI::needVSETVLI(const DemandedFields &Used, 117881ad6265SDimitry Andric const VSETVLIInfo &Require, 117981ad6265SDimitry Andric const VSETVLIInfo &CurInfo) const { 118081ad6265SDimitry Andric if (!CurInfo.isValid() || CurInfo.isUnknown() || CurInfo.hasSEWLMULRatioOnly()) 118181ad6265SDimitry Andric return true; 118281ad6265SDimitry Andric 1183*0fca6ea1SDimitry Andric if (CurInfo.isCompatible(Used, Require, LIS)) 1184bdd1243dSDimitry Andric return false; 118581ad6265SDimitry Andric 118681ad6265SDimitry Andric return true; 118781ad6265SDimitry Andric } 118881ad6265SDimitry Andric 11895f757f3fSDimitry Andric // If we don't use LMUL or the SEW/LMUL ratio, then adjust LMUL so that we 11905f757f3fSDimitry Andric // maintain the SEW/LMUL ratio. This allows us to eliminate VL toggles in more 11915f757f3fSDimitry Andric // places. 11925f757f3fSDimitry Andric static VSETVLIInfo adjustIncoming(VSETVLIInfo PrevInfo, VSETVLIInfo NewInfo, 11935f757f3fSDimitry Andric DemandedFields &Demanded) { 11945f757f3fSDimitry Andric VSETVLIInfo Info = NewInfo; 11955f757f3fSDimitry Andric 11965f757f3fSDimitry Andric if (!Demanded.LMUL && !Demanded.SEWLMULRatio && PrevInfo.isValid() && 11975f757f3fSDimitry Andric !PrevInfo.isUnknown()) { 11985f757f3fSDimitry Andric if (auto NewVLMul = RISCVVType::getSameRatioLMUL( 11995f757f3fSDimitry Andric PrevInfo.getSEW(), PrevInfo.getVLMUL(), Info.getSEW())) 12005f757f3fSDimitry Andric Info.setVLMul(*NewVLMul); 1201*0fca6ea1SDimitry Andric Demanded.LMUL = DemandedFields::LMULEqual; 12025f757f3fSDimitry Andric } 12035f757f3fSDimitry Andric 12045f757f3fSDimitry Andric return Info; 12055f757f3fSDimitry Andric } 12065f757f3fSDimitry Andric 12075f757f3fSDimitry Andric // Given an incoming state reaching MI, minimally modifies that state so that it 12085f757f3fSDimitry Andric // is compatible with MI. The resulting state is guaranteed to be semantically 12095f757f3fSDimitry Andric // legal for MI, but may not be the state requested by MI. 12105f757f3fSDimitry Andric void RISCVInsertVSETVLI::transferBefore(VSETVLIInfo &Info, 12115f757f3fSDimitry Andric const MachineInstr &MI) const { 1212*0fca6ea1SDimitry Andric if (!RISCVII::hasSEWOp(MI.getDesc().TSFlags)) 121381ad6265SDimitry Andric return; 121481ad6265SDimitry Andric 1215*0fca6ea1SDimitry Andric DemandedFields Demanded = getDemanded(MI, ST); 1216*0fca6ea1SDimitry Andric 1217*0fca6ea1SDimitry Andric const VSETVLIInfo NewInfo = computeInfoForInstr(MI); 12185f757f3fSDimitry Andric assert(NewInfo.isValid() && !NewInfo.isUnknown()); 1219*0fca6ea1SDimitry Andric if (Info.isValid() && !needVSETVLI(Demanded, NewInfo, Info)) 122081ad6265SDimitry Andric return; 122181ad6265SDimitry Andric 122281ad6265SDimitry Andric const VSETVLIInfo PrevInfo = Info; 12235f757f3fSDimitry Andric if (!Info.isValid() || Info.isUnknown()) 122481ad6265SDimitry Andric Info = NewInfo; 122581ad6265SDimitry Andric 12265f757f3fSDimitry Andric const VSETVLIInfo IncomingInfo = adjustIncoming(PrevInfo, NewInfo, Demanded); 122781ad6265SDimitry Andric 12285f757f3fSDimitry Andric // If MI only demands that VL has the same zeroness, we only need to set the 12295f757f3fSDimitry Andric // AVL if the zeroness differs. This removes a vsetvli entirely if the types 12305f757f3fSDimitry Andric // match or allows use of cheaper avl preserving variant if VLMAX doesn't 12315f757f3fSDimitry Andric // change. If VLMAX might change, we couldn't use the 'vsetvli x0, x0, vtype" 12325f757f3fSDimitry Andric // variant, so we avoid the transform to prevent extending live range of an 12335f757f3fSDimitry Andric // avl register operand. 123481ad6265SDimitry Andric // TODO: We can probably relax this for immediates. 1235*0fca6ea1SDimitry Andric bool EquallyZero = IncomingInfo.hasEquallyZeroAVL(PrevInfo, LIS) && 12365f757f3fSDimitry Andric IncomingInfo.hasSameVLMAX(PrevInfo); 12375f757f3fSDimitry Andric if (Demanded.VLAny || (Demanded.VLZeroness && !EquallyZero)) 12385f757f3fSDimitry Andric Info.setAVL(IncomingInfo); 123981ad6265SDimitry Andric 12405f757f3fSDimitry Andric Info.setVTYPE( 12415f757f3fSDimitry Andric ((Demanded.LMUL || Demanded.SEWLMULRatio) ? IncomingInfo : Info) 12425f757f3fSDimitry Andric .getVLMUL(), 12435f757f3fSDimitry Andric ((Demanded.SEW || Demanded.SEWLMULRatio) ? IncomingInfo : Info).getSEW(), 12445f757f3fSDimitry Andric // Prefer tail/mask agnostic since it can be relaxed to undisturbed later 12455f757f3fSDimitry Andric // if needed. 12465f757f3fSDimitry Andric (Demanded.TailPolicy ? IncomingInfo : Info).getTailAgnostic() || 12475f757f3fSDimitry Andric IncomingInfo.getTailAgnostic(), 12485f757f3fSDimitry Andric (Demanded.MaskPolicy ? IncomingInfo : Info).getMaskAgnostic() || 12495f757f3fSDimitry Andric IncomingInfo.getMaskAgnostic()); 125081ad6265SDimitry Andric 12515f757f3fSDimitry Andric // If we only knew the sew/lmul ratio previously, replace the VTYPE but keep 12525f757f3fSDimitry Andric // the AVL. 12535f757f3fSDimitry Andric if (Info.hasSEWLMULRatioOnly()) { 12545f757f3fSDimitry Andric VSETVLIInfo RatiolessInfo = IncomingInfo; 12555f757f3fSDimitry Andric RatiolessInfo.setAVL(Info); 12565f757f3fSDimitry Andric Info = RatiolessInfo; 125781ad6265SDimitry Andric } 125881ad6265SDimitry Andric } 125981ad6265SDimitry Andric 126081ad6265SDimitry Andric // Given a state with which we evaluated MI (see transferBefore above for why 126181ad6265SDimitry Andric // this might be different that the state MI requested), modify the state to 126281ad6265SDimitry Andric // reflect the changes MI might make. 12635f757f3fSDimitry Andric void RISCVInsertVSETVLI::transferAfter(VSETVLIInfo &Info, 12645f757f3fSDimitry Andric const MachineInstr &MI) const { 126581ad6265SDimitry Andric if (isVectorConfigInstr(MI)) { 126681ad6265SDimitry Andric Info = getInfoForVSETVLI(MI); 126781ad6265SDimitry Andric return; 126881ad6265SDimitry Andric } 126981ad6265SDimitry Andric 127081ad6265SDimitry Andric if (RISCV::isFaultFirstLoad(MI)) { 127181ad6265SDimitry Andric // Update AVL to vl-output of the fault first load. 1272*0fca6ea1SDimitry Andric assert(MI.getOperand(1).getReg().isVirtual()); 1273*0fca6ea1SDimitry Andric if (LIS) { 1274*0fca6ea1SDimitry Andric auto &LI = LIS->getInterval(MI.getOperand(1).getReg()); 1275*0fca6ea1SDimitry Andric SlotIndex SI = 1276*0fca6ea1SDimitry Andric LIS->getSlotIndexes()->getInstructionIndex(MI).getRegSlot(); 1277*0fca6ea1SDimitry Andric VNInfo *VNI = LI.getVNInfoAt(SI); 1278*0fca6ea1SDimitry Andric Info.setAVLRegDef(VNI, MI.getOperand(1).getReg()); 1279*0fca6ea1SDimitry Andric } else 1280*0fca6ea1SDimitry Andric Info.setAVLRegDef(nullptr, MI.getOperand(1).getReg()); 128181ad6265SDimitry Andric return; 128281ad6265SDimitry Andric } 128381ad6265SDimitry Andric 128481ad6265SDimitry Andric // If this is something that updates VL/VTYPE that we don't know about, set 128581ad6265SDimitry Andric // the state to unknown. 1286*0fca6ea1SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || 1287*0fca6ea1SDimitry Andric MI.modifiesRegister(RISCV::VL, /*TRI=*/nullptr) || 1288*0fca6ea1SDimitry Andric MI.modifiesRegister(RISCV::VTYPE, /*TRI=*/nullptr)) 128981ad6265SDimitry Andric Info = VSETVLIInfo::getUnknown(); 1290349cc55cSDimitry Andric } 1291349cc55cSDimitry Andric 12925f757f3fSDimitry Andric bool RISCVInsertVSETVLI::computeVLVTYPEChanges(const MachineBasicBlock &MBB, 12935f757f3fSDimitry Andric VSETVLIInfo &Info) const { 1294fe6060f1SDimitry Andric bool HadVectorOp = false; 1295fe6060f1SDimitry Andric 12965f757f3fSDimitry Andric Info = BlockInfo[MBB.getNumber()].Pred; 1297fe6060f1SDimitry Andric for (const MachineInstr &MI : MBB) { 12985f757f3fSDimitry Andric transferBefore(Info, MI); 1299fe6060f1SDimitry Andric 130081ad6265SDimitry Andric if (isVectorConfigInstr(MI) || RISCVII::hasSEWOp(MI.getDesc().TSFlags)) 1301fe6060f1SDimitry Andric HadVectorOp = true; 1302fe6060f1SDimitry Andric 13035f757f3fSDimitry Andric transferAfter(Info, MI); 1304fe6060f1SDimitry Andric } 1305fe6060f1SDimitry Andric 1306fe6060f1SDimitry Andric return HadVectorOp; 1307fe6060f1SDimitry Andric } 1308fe6060f1SDimitry Andric 1309fe6060f1SDimitry Andric void RISCVInsertVSETVLI::computeIncomingVLVTYPE(const MachineBasicBlock &MBB) { 131081ad6265SDimitry Andric 1311fe6060f1SDimitry Andric BlockData &BBInfo = BlockInfo[MBB.getNumber()]; 1312fe6060f1SDimitry Andric 1313fe6060f1SDimitry Andric BBInfo.InQueue = false; 1314fe6060f1SDimitry Andric 1315bdd1243dSDimitry Andric // Start with the previous entry so that we keep the most conservative state 1316bdd1243dSDimitry Andric // we have ever found. 1317bdd1243dSDimitry Andric VSETVLIInfo InInfo = BBInfo.Pred; 1318fe6060f1SDimitry Andric if (MBB.pred_empty()) { 1319fe6060f1SDimitry Andric // There are no predecessors, so use the default starting status. 1320fe6060f1SDimitry Andric InInfo.setUnknown(); 1321fe6060f1SDimitry Andric } else { 1322fe6060f1SDimitry Andric for (MachineBasicBlock *P : MBB.predecessors()) 1323fe6060f1SDimitry Andric InInfo = InInfo.intersect(BlockInfo[P->getNumber()].Exit); 1324fe6060f1SDimitry Andric } 1325fe6060f1SDimitry Andric 1326fe6060f1SDimitry Andric // If we don't have any valid predecessor value, wait until we do. 1327fe6060f1SDimitry Andric if (!InInfo.isValid()) 1328fe6060f1SDimitry Andric return; 1329fe6060f1SDimitry Andric 133081ad6265SDimitry Andric // If no change, no need to rerun block 133181ad6265SDimitry Andric if (InInfo == BBInfo.Pred) 133281ad6265SDimitry Andric return; 1333fe6060f1SDimitry Andric 133481ad6265SDimitry Andric BBInfo.Pred = InInfo; 133581ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Entry state of " << printMBBReference(MBB) 133681ad6265SDimitry Andric << " changed to " << BBInfo.Pred << "\n"); 133781ad6265SDimitry Andric 133881ad6265SDimitry Andric // Note: It's tempting to cache the state changes here, but due to the 133981ad6265SDimitry Andric // compatibility checks performed a blocks output state can change based on 134081ad6265SDimitry Andric // the input state. To cache, we'd have to add logic for finding 134181ad6265SDimitry Andric // never-compatible state changes. 13425f757f3fSDimitry Andric VSETVLIInfo TmpStatus; 13435f757f3fSDimitry Andric computeVLVTYPEChanges(MBB, TmpStatus); 1344fe6060f1SDimitry Andric 1345fe6060f1SDimitry Andric // If the new exit value matches the old exit value, we don't need to revisit 1346fe6060f1SDimitry Andric // any blocks. 1347fe6060f1SDimitry Andric if (BBInfo.Exit == TmpStatus) 1348fe6060f1SDimitry Andric return; 1349fe6060f1SDimitry Andric 1350fe6060f1SDimitry Andric BBInfo.Exit = TmpStatus; 135181ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Exit state of " << printMBBReference(MBB) 135281ad6265SDimitry Andric << " changed to " << BBInfo.Exit << "\n"); 1353fe6060f1SDimitry Andric 1354fe6060f1SDimitry Andric // Add the successors to the work list so we can propagate the changed exit 1355fe6060f1SDimitry Andric // status. 1356fe6060f1SDimitry Andric for (MachineBasicBlock *S : MBB.successors()) 1357bdd1243dSDimitry Andric if (!BlockInfo[S->getNumber()].InQueue) { 1358bdd1243dSDimitry Andric BlockInfo[S->getNumber()].InQueue = true; 1359fe6060f1SDimitry Andric WorkList.push(S); 1360fe6060f1SDimitry Andric } 1361bdd1243dSDimitry Andric } 1362fe6060f1SDimitry Andric 1363fe6060f1SDimitry Andric // If we weren't able to prove a vsetvli was directly unneeded, it might still 1364*0fca6ea1SDimitry Andric // be unneeded if the AVL was a phi node where all incoming values are VL 1365fe6060f1SDimitry Andric // outputs from the last VSETVLI in their respective basic blocks. 1366fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::needVSETVLIPHI(const VSETVLIInfo &Require, 136781ad6265SDimitry Andric const MachineBasicBlock &MBB) const { 1368fe6060f1SDimitry Andric if (!Require.hasAVLReg()) 1369fe6060f1SDimitry Andric return true; 1370fe6060f1SDimitry Andric 1371*0fca6ea1SDimitry Andric if (!LIS) 1372fe6060f1SDimitry Andric return true; 1373fe6060f1SDimitry Andric 1374*0fca6ea1SDimitry Andric // We need the AVL to have been produced by a PHI node in this basic block. 1375*0fca6ea1SDimitry Andric const VNInfo *Valno = Require.getAVLVNInfo(); 1376*0fca6ea1SDimitry Andric if (!Valno->isPHIDef() || LIS->getMBBFromIndex(Valno->def) != &MBB) 1377fe6060f1SDimitry Andric return true; 1378fe6060f1SDimitry Andric 1379*0fca6ea1SDimitry Andric const LiveRange &LR = LIS->getInterval(Require.getAVLReg()); 1380*0fca6ea1SDimitry Andric 1381*0fca6ea1SDimitry Andric for (auto *PBB : MBB.predecessors()) { 1382*0fca6ea1SDimitry Andric const VSETVLIInfo &PBBExit = BlockInfo[PBB->getNumber()].Exit; 1383fe6060f1SDimitry Andric 1384fe6060f1SDimitry Andric // We need the PHI input to the be the output of a VSET(I)VLI. 1385*0fca6ea1SDimitry Andric const VNInfo *Value = LR.getVNInfoBefore(LIS->getMBBEndIdx(PBB)); 1386*0fca6ea1SDimitry Andric if (!Value) 1387*0fca6ea1SDimitry Andric return true; 1388*0fca6ea1SDimitry Andric MachineInstr *DefMI = LIS->getInstructionFromIndex(Value->def); 138981ad6265SDimitry Andric if (!DefMI || !isVectorConfigInstr(*DefMI)) 1390fe6060f1SDimitry Andric return true; 1391fe6060f1SDimitry Andric 1392fe6060f1SDimitry Andric // We found a VSET(I)VLI make sure it matches the output of the 1393fe6060f1SDimitry Andric // predecessor block. 1394fe6060f1SDimitry Andric VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI); 1395*0fca6ea1SDimitry Andric if (DefInfo != PBBExit) 1396*0fca6ea1SDimitry Andric return true; 1397*0fca6ea1SDimitry Andric 1398*0fca6ea1SDimitry Andric // Require has the same VL as PBBExit, so if the exit from the 1399*0fca6ea1SDimitry Andric // predecessor has the VTYPE we are looking for we might be able 1400*0fca6ea1SDimitry Andric // to avoid a VSETVLI. 1401*0fca6ea1SDimitry Andric if (PBBExit.isUnknown() || !PBBExit.hasSameVTYPE(Require)) 1402fe6060f1SDimitry Andric return true; 1403fe6060f1SDimitry Andric } 1404fe6060f1SDimitry Andric 1405fe6060f1SDimitry Andric // If all the incoming values to the PHI checked out, we don't need 1406fe6060f1SDimitry Andric // to insert a VSETVLI. 1407fe6060f1SDimitry Andric return false; 1408fe6060f1SDimitry Andric } 1409fe6060f1SDimitry Andric 1410fe6060f1SDimitry Andric void RISCVInsertVSETVLI::emitVSETVLIs(MachineBasicBlock &MBB) { 141181ad6265SDimitry Andric VSETVLIInfo CurInfo = BlockInfo[MBB.getNumber()].Pred; 141281ad6265SDimitry Andric // Track whether the prefix of the block we've scanned is transparent 141381ad6265SDimitry Andric // (meaning has not yet changed the abstract state). 141481ad6265SDimitry Andric bool PrefixTransparent = true; 1415fe6060f1SDimitry Andric for (MachineInstr &MI : MBB) { 141681ad6265SDimitry Andric const VSETVLIInfo PrevInfo = CurInfo; 141781ad6265SDimitry Andric transferBefore(CurInfo, MI); 141881ad6265SDimitry Andric 1419fe6060f1SDimitry Andric // If this is an explicit VSETVLI or VSETIVLI, update our state. 142081ad6265SDimitry Andric if (isVectorConfigInstr(MI)) { 1421fe6060f1SDimitry Andric // Conservatively, mark the VL and VTYPE as live. 1422fe6060f1SDimitry Andric assert(MI.getOperand(3).getReg() == RISCV::VL && 1423fe6060f1SDimitry Andric MI.getOperand(4).getReg() == RISCV::VTYPE && 1424fe6060f1SDimitry Andric "Unexpected operands where VL and VTYPE should be"); 1425fe6060f1SDimitry Andric MI.getOperand(3).setIsDead(false); 1426fe6060f1SDimitry Andric MI.getOperand(4).setIsDead(false); 142781ad6265SDimitry Andric PrefixTransparent = false; 1428fe6060f1SDimitry Andric } 1429fe6060f1SDimitry Andric 1430fe6060f1SDimitry Andric uint64_t TSFlags = MI.getDesc().TSFlags; 1431fe6060f1SDimitry Andric if (RISCVII::hasSEWOp(TSFlags)) { 1432*0fca6ea1SDimitry Andric if (!PrevInfo.isCompatible(DemandedFields::all(), CurInfo, LIS)) { 143381ad6265SDimitry Andric // If this is the first implicit state change, and the state change 143481ad6265SDimitry Andric // requested can be proven to produce the same register contents, we 143581ad6265SDimitry Andric // can skip emitting the actual state change and continue as if we 143681ad6265SDimitry Andric // had since we know the GPR result of the implicit state change 143781ad6265SDimitry Andric // wouldn't be used and VL/VTYPE registers are correct. Note that 143881ad6265SDimitry Andric // we *do* need to model the state as if it changed as while the 143981ad6265SDimitry Andric // register contents are unchanged, the abstract model can change. 144081ad6265SDimitry Andric if (!PrefixTransparent || needVSETVLIPHI(CurInfo, MBB)) 1441*0fca6ea1SDimitry Andric insertVSETVLI(MBB, MI, MI.getDebugLoc(), CurInfo, PrevInfo); 144281ad6265SDimitry Andric PrefixTransparent = false; 144381ad6265SDimitry Andric } 144481ad6265SDimitry Andric 1445fe6060f1SDimitry Andric if (RISCVII::hasVLOp(TSFlags)) { 144681ad6265SDimitry Andric MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI)); 1447fe6060f1SDimitry Andric if (VLOp.isReg()) { 14485f757f3fSDimitry Andric Register Reg = VLOp.getReg(); 14495f757f3fSDimitry Andric 1450fe6060f1SDimitry Andric // Erase the AVL operand from the instruction. 1451fe6060f1SDimitry Andric VLOp.setReg(RISCV::NoRegister); 1452fe6060f1SDimitry Andric VLOp.setIsKill(false); 1453*0fca6ea1SDimitry Andric if (LIS) { 1454*0fca6ea1SDimitry Andric LiveInterval &LI = LIS->getInterval(Reg); 1455*0fca6ea1SDimitry Andric SmallVector<MachineInstr *> DeadMIs; 1456*0fca6ea1SDimitry Andric LIS->shrinkToUses(&LI, &DeadMIs); 1457*0fca6ea1SDimitry Andric // We might have separate components that need split due to 1458*0fca6ea1SDimitry Andric // needVSETVLIPHI causing us to skip inserting a new VL def. 1459*0fca6ea1SDimitry Andric SmallVector<LiveInterval *> SplitLIs; 1460*0fca6ea1SDimitry Andric LIS->splitSeparateComponents(LI, SplitLIs); 14615f757f3fSDimitry Andric 14625f757f3fSDimitry Andric // If the AVL was an immediate > 31, then it would have been emitted 14635f757f3fSDimitry Andric // as an ADDI. However, the ADDI might not have been used in the 14645f757f3fSDimitry Andric // vsetvli, or a vsetvli might not have been emitted, so it may be 14655f757f3fSDimitry Andric // dead now. 1466*0fca6ea1SDimitry Andric for (MachineInstr *DeadMI : DeadMIs) { 1467*0fca6ea1SDimitry Andric if (!TII->isAddImmediate(*DeadMI, Reg)) 1468*0fca6ea1SDimitry Andric continue; 1469*0fca6ea1SDimitry Andric LIS->RemoveMachineInstrFromMaps(*DeadMI); 1470*0fca6ea1SDimitry Andric DeadMI->eraseFromParent(); 1471*0fca6ea1SDimitry Andric } 1472*0fca6ea1SDimitry Andric } 1473fe6060f1SDimitry Andric } 1474fe6060f1SDimitry Andric MI.addOperand(MachineOperand::CreateReg(RISCV::VL, /*isDef*/ false, 1475fe6060f1SDimitry Andric /*isImp*/ true)); 1476fe6060f1SDimitry Andric } 1477fe6060f1SDimitry Andric MI.addOperand(MachineOperand::CreateReg(RISCV::VTYPE, /*isDef*/ false, 1478fe6060f1SDimitry Andric /*isImp*/ true)); 1479fe6060f1SDimitry Andric } 1480fe6060f1SDimitry Andric 1481*0fca6ea1SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || 1482*0fca6ea1SDimitry Andric MI.modifiesRegister(RISCV::VL, /*TRI=*/nullptr) || 1483*0fca6ea1SDimitry Andric MI.modifiesRegister(RISCV::VTYPE, /*TRI=*/nullptr)) 148481ad6265SDimitry Andric PrefixTransparent = false; 148581ad6265SDimitry Andric 148681ad6265SDimitry Andric transferAfter(CurInfo, MI); 1487fe6060f1SDimitry Andric } 1488d56accc7SDimitry Andric 148981ad6265SDimitry Andric const auto &Info = BlockInfo[MBB.getNumber()]; 149081ad6265SDimitry Andric if (CurInfo != Info.Exit) { 149181ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "in block " << printMBBReference(MBB) << "\n"); 149281ad6265SDimitry Andric LLVM_DEBUG(dbgs() << " begin state: " << Info.Pred << "\n"); 149381ad6265SDimitry Andric LLVM_DEBUG(dbgs() << " expected end state: " << Info.Exit << "\n"); 149481ad6265SDimitry Andric LLVM_DEBUG(dbgs() << " actual end state: " << CurInfo << "\n"); 149581ad6265SDimitry Andric } 1496*0fca6ea1SDimitry Andric assert(CurInfo == Info.Exit && "InsertVSETVLI dataflow invariant violated"); 149781ad6265SDimitry Andric } 149881ad6265SDimitry Andric 149981ad6265SDimitry Andric /// Perform simple partial redundancy elimination of the VSETVLI instructions 150081ad6265SDimitry Andric /// we're about to insert by looking for cases where we can PRE from the 150181ad6265SDimitry Andric /// beginning of one block to the end of one of its predecessors. Specifically, 150281ad6265SDimitry Andric /// this is geared to catch the common case of a fixed length vsetvl in a single 150381ad6265SDimitry Andric /// block loop when it could execute once in the preheader instead. 150481ad6265SDimitry Andric void RISCVInsertVSETVLI::doPRE(MachineBasicBlock &MBB) { 150581ad6265SDimitry Andric if (!BlockInfo[MBB.getNumber()].Pred.isUnknown()) 150681ad6265SDimitry Andric return; 150781ad6265SDimitry Andric 150881ad6265SDimitry Andric MachineBasicBlock *UnavailablePred = nullptr; 150981ad6265SDimitry Andric VSETVLIInfo AvailableInfo; 151081ad6265SDimitry Andric for (MachineBasicBlock *P : MBB.predecessors()) { 151181ad6265SDimitry Andric const VSETVLIInfo &PredInfo = BlockInfo[P->getNumber()].Exit; 151281ad6265SDimitry Andric if (PredInfo.isUnknown()) { 151381ad6265SDimitry Andric if (UnavailablePred) 151481ad6265SDimitry Andric return; 151581ad6265SDimitry Andric UnavailablePred = P; 151681ad6265SDimitry Andric } else if (!AvailableInfo.isValid()) { 151781ad6265SDimitry Andric AvailableInfo = PredInfo; 151881ad6265SDimitry Andric } else if (AvailableInfo != PredInfo) { 151981ad6265SDimitry Andric return; 152081ad6265SDimitry Andric } 152181ad6265SDimitry Andric } 152281ad6265SDimitry Andric 152381ad6265SDimitry Andric // Unreachable, single pred, or full redundancy. Note that FRE is handled by 152481ad6265SDimitry Andric // phase 3. 152581ad6265SDimitry Andric if (!UnavailablePred || !AvailableInfo.isValid()) 152681ad6265SDimitry Andric return; 152781ad6265SDimitry Andric 1528*0fca6ea1SDimitry Andric if (!LIS) 1529*0fca6ea1SDimitry Andric return; 1530*0fca6ea1SDimitry Andric 15311db9f3b2SDimitry Andric // If we don't know the exact VTYPE, we can't copy the vsetvli to the exit of 15321db9f3b2SDimitry Andric // the unavailable pred. 15331db9f3b2SDimitry Andric if (AvailableInfo.hasSEWLMULRatioOnly()) 15341db9f3b2SDimitry Andric return; 15351db9f3b2SDimitry Andric 153681ad6265SDimitry Andric // Critical edge - TODO: consider splitting? 153781ad6265SDimitry Andric if (UnavailablePred->succ_size() != 1) 153881ad6265SDimitry Andric return; 153981ad6265SDimitry Andric 15405f757f3fSDimitry Andric // If the AVL value is a register (other than our VLMAX sentinel), 15415f757f3fSDimitry Andric // we need to prove the value is available at the point we're going 15425f757f3fSDimitry Andric // to insert the vsetvli at. 1543*0fca6ea1SDimitry Andric if (AvailableInfo.hasAVLReg()) { 1544*0fca6ea1SDimitry Andric SlotIndex SI = AvailableInfo.getAVLVNInfo()->def; 15455f757f3fSDimitry Andric // This is an inline dominance check which covers the case of 15465f757f3fSDimitry Andric // UnavailablePred being the preheader of a loop. 1547*0fca6ea1SDimitry Andric if (LIS->getMBBFromIndex(SI) != UnavailablePred) 15485f757f3fSDimitry Andric return; 1549*0fca6ea1SDimitry Andric if (!UnavailablePred->terminators().empty() && 1550*0fca6ea1SDimitry Andric SI >= LIS->getInstructionIndex(*UnavailablePred->getFirstTerminator())) 15515f757f3fSDimitry Andric return; 15525f757f3fSDimitry Andric } 155381ad6265SDimitry Andric 155406c3fb27SDimitry Andric // Model the effect of changing the input state of the block MBB to 155506c3fb27SDimitry Andric // AvailableInfo. We're looking for two issues here; one legality, 155606c3fb27SDimitry Andric // one profitability. 155706c3fb27SDimitry Andric // 1) If the block doesn't use some of the fields from VL or VTYPE, we 155806c3fb27SDimitry Andric // may hit the end of the block with a different end state. We can 155906c3fb27SDimitry Andric // not make this change without reflowing later blocks as well. 156006c3fb27SDimitry Andric // 2) If we don't actually remove a transition, inserting a vsetvli 156106c3fb27SDimitry Andric // into the predecessor block would be correct, but unprofitable. 156206c3fb27SDimitry Andric VSETVLIInfo OldInfo = BlockInfo[MBB.getNumber()].Pred; 156306c3fb27SDimitry Andric VSETVLIInfo CurInfo = AvailableInfo; 156406c3fb27SDimitry Andric int TransitionsRemoved = 0; 156506c3fb27SDimitry Andric for (const MachineInstr &MI : MBB) { 156606c3fb27SDimitry Andric const VSETVLIInfo LastInfo = CurInfo; 156706c3fb27SDimitry Andric const VSETVLIInfo LastOldInfo = OldInfo; 156806c3fb27SDimitry Andric transferBefore(CurInfo, MI); 156906c3fb27SDimitry Andric transferBefore(OldInfo, MI); 157006c3fb27SDimitry Andric if (CurInfo == LastInfo) 157106c3fb27SDimitry Andric TransitionsRemoved++; 157206c3fb27SDimitry Andric if (LastOldInfo == OldInfo) 157306c3fb27SDimitry Andric TransitionsRemoved--; 157406c3fb27SDimitry Andric transferAfter(CurInfo, MI); 157506c3fb27SDimitry Andric transferAfter(OldInfo, MI); 157606c3fb27SDimitry Andric if (CurInfo == OldInfo) 157706c3fb27SDimitry Andric // Convergence. All transitions after this must match by construction. 157881ad6265SDimitry Andric break; 157981ad6265SDimitry Andric } 158006c3fb27SDimitry Andric if (CurInfo != OldInfo || TransitionsRemoved <= 0) 158106c3fb27SDimitry Andric // Issues 1 and 2 above 158281ad6265SDimitry Andric return; 158381ad6265SDimitry Andric 158481ad6265SDimitry Andric // Finally, update both data flow state and insert the actual vsetvli. 158581ad6265SDimitry Andric // Doing both keeps the code in sync with the dataflow results, which 158681ad6265SDimitry Andric // is critical for correctness of phase 3. 158706c3fb27SDimitry Andric auto OldExit = BlockInfo[UnavailablePred->getNumber()].Exit; 158881ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "PRE VSETVLI from " << MBB.getName() << " to " 158981ad6265SDimitry Andric << UnavailablePred->getName() << " with state " 159081ad6265SDimitry Andric << AvailableInfo << "\n"); 159181ad6265SDimitry Andric BlockInfo[UnavailablePred->getNumber()].Exit = AvailableInfo; 159281ad6265SDimitry Andric BlockInfo[MBB.getNumber()].Pred = AvailableInfo; 159381ad6265SDimitry Andric 159481ad6265SDimitry Andric // Note there's an implicit assumption here that terminators never use 159581ad6265SDimitry Andric // or modify VL or VTYPE. Also, fallthrough will return end(). 159681ad6265SDimitry Andric auto InsertPt = UnavailablePred->getFirstInstrTerminator(); 159781ad6265SDimitry Andric insertVSETVLI(*UnavailablePred, InsertPt, 159881ad6265SDimitry Andric UnavailablePred->findDebugLoc(InsertPt), 159906c3fb27SDimitry Andric AvailableInfo, OldExit); 160081ad6265SDimitry Andric } 160181ad6265SDimitry Andric 1602bdd1243dSDimitry Andric // Return true if we can mutate PrevMI to match MI without changing any the 1603bdd1243dSDimitry Andric // fields which would be observed. 1604*0fca6ea1SDimitry Andric bool RISCVInsertVSETVLI::canMutatePriorConfig( 1605*0fca6ea1SDimitry Andric const MachineInstr &PrevMI, const MachineInstr &MI, 1606*0fca6ea1SDimitry Andric const DemandedFields &Used) const { 1607bdd1243dSDimitry Andric // If the VL values aren't equal, return false if either a) the former is 1608bdd1243dSDimitry Andric // demanded, or b) we can't rewrite the former to be the later for 1609bdd1243dSDimitry Andric // implementation reasons. 1610bdd1243dSDimitry Andric if (!isVLPreservingConfig(MI)) { 1611bdd1243dSDimitry Andric if (Used.VLAny) 161281ad6265SDimitry Andric return false; 161381ad6265SDimitry Andric 16145f757f3fSDimitry Andric if (Used.VLZeroness) { 16155f757f3fSDimitry Andric if (isVLPreservingConfig(PrevMI)) 1616bdd1243dSDimitry Andric return false; 1617297eecfbSDimitry Andric if (!getInfoForVSETVLI(PrevMI).hasEquallyZeroAVL(getInfoForVSETVLI(MI), 1618*0fca6ea1SDimitry Andric LIS)) 16195f757f3fSDimitry Andric return false; 16205f757f3fSDimitry Andric } 1621bdd1243dSDimitry Andric 1622297eecfbSDimitry Andric auto &AVL = MI.getOperand(1); 1623297eecfbSDimitry Andric auto &PrevAVL = PrevMI.getOperand(1); 1624297eecfbSDimitry Andric 1625297eecfbSDimitry Andric // If the AVL is a register, we need to make sure MI's AVL dominates PrevMI. 1626297eecfbSDimitry Andric // For now just check that PrevMI uses the same virtual register. 1627*0fca6ea1SDimitry Andric if (AVL.isReg() && AVL.getReg() != RISCV::X0 && 1628*0fca6ea1SDimitry Andric (!MRI->hasOneDef(AVL.getReg()) || !PrevAVL.isReg() || 1629*0fca6ea1SDimitry Andric PrevAVL.getReg() != AVL.getReg())) 1630297eecfbSDimitry Andric return false; 1631297eecfbSDimitry Andric } 1632bdd1243dSDimitry Andric 1633*0fca6ea1SDimitry Andric assert(PrevMI.getOperand(2).isImm() && MI.getOperand(2).isImm()); 163481ad6265SDimitry Andric auto PriorVType = PrevMI.getOperand(2).getImm(); 163581ad6265SDimitry Andric auto VType = MI.getOperand(2).getImm(); 163681ad6265SDimitry Andric return areCompatibleVTYPEs(PriorVType, VType, Used); 163781ad6265SDimitry Andric } 163881ad6265SDimitry Andric 1639*0fca6ea1SDimitry Andric void RISCVInsertVSETVLI::coalesceVSETVLIs(MachineBasicBlock &MBB) const { 1640bdd1243dSDimitry Andric MachineInstr *NextMI = nullptr; 1641bdd1243dSDimitry Andric // We can have arbitrary code in successors, so VL and VTYPE 1642bdd1243dSDimitry Andric // must be considered demanded. 164381ad6265SDimitry Andric DemandedFields Used; 1644bdd1243dSDimitry Andric Used.demandVL(); 1645bdd1243dSDimitry Andric Used.demandVTYPE(); 164681ad6265SDimitry Andric SmallVector<MachineInstr*> ToDelete; 1647*0fca6ea1SDimitry Andric 1648*0fca6ea1SDimitry Andric // Update LIS and cleanup dead AVLs given a value which has 1649*0fca6ea1SDimitry Andric // has had one use (as an AVL) removed. 1650*0fca6ea1SDimitry Andric auto afterDroppedAVLUse = [&](Register OldVLReg) { 1651*0fca6ea1SDimitry Andric if (LIS) 1652*0fca6ea1SDimitry Andric LIS->shrinkToUses(&LIS->getInterval(OldVLReg)); 1653*0fca6ea1SDimitry Andric 1654*0fca6ea1SDimitry Andric MachineInstr *VLOpDef = MRI->getUniqueVRegDef(OldVLReg); 1655*0fca6ea1SDimitry Andric if (VLOpDef && TII->isAddImmediate(*VLOpDef, OldVLReg) && 1656*0fca6ea1SDimitry Andric MRI->use_nodbg_empty(OldVLReg)) { 1657*0fca6ea1SDimitry Andric if (LIS) { 1658*0fca6ea1SDimitry Andric LIS->removeInterval(OldVLReg); 1659*0fca6ea1SDimitry Andric LIS->RemoveMachineInstrFromMaps(*VLOpDef); 1660*0fca6ea1SDimitry Andric } 1661*0fca6ea1SDimitry Andric VLOpDef->eraseFromParent(); 1662*0fca6ea1SDimitry Andric } 1663*0fca6ea1SDimitry Andric }; 1664*0fca6ea1SDimitry Andric 1665bdd1243dSDimitry Andric for (MachineInstr &MI : make_range(MBB.rbegin(), MBB.rend())) { 1666bdd1243dSDimitry Andric 1667bdd1243dSDimitry Andric if (!isVectorConfigInstr(MI)) { 1668*0fca6ea1SDimitry Andric Used.doUnion(getDemanded(MI, ST)); 1669*0fca6ea1SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || 1670*0fca6ea1SDimitry Andric MI.modifiesRegister(RISCV::VL, /*TRI=*/nullptr) || 1671*0fca6ea1SDimitry Andric MI.modifiesRegister(RISCV::VTYPE, /*TRI=*/nullptr)) 1672*0fca6ea1SDimitry Andric NextMI = nullptr; 167381ad6265SDimitry Andric continue; 167481ad6265SDimitry Andric } 1675bdd1243dSDimitry Andric 1676*0fca6ea1SDimitry Andric if (!MI.getOperand(0).isDead()) 1677bdd1243dSDimitry Andric Used.demandVL(); 1678bdd1243dSDimitry Andric 1679bdd1243dSDimitry Andric if (NextMI) { 1680bdd1243dSDimitry Andric if (!Used.usedVL() && !Used.usedVTYPE()) { 1681bdd1243dSDimitry Andric ToDelete.push_back(&MI); 1682bdd1243dSDimitry Andric // Leave NextMI unchanged 1683bdd1243dSDimitry Andric continue; 1684*0fca6ea1SDimitry Andric } 1685*0fca6ea1SDimitry Andric 1686*0fca6ea1SDimitry Andric if (canMutatePriorConfig(MI, *NextMI, Used)) { 1687bdd1243dSDimitry Andric if (!isVLPreservingConfig(*NextMI)) { 1688*0fca6ea1SDimitry Andric Register DefReg = NextMI->getOperand(0).getReg(); 1689*0fca6ea1SDimitry Andric 1690*0fca6ea1SDimitry Andric MI.getOperand(0).setReg(DefReg); 16915f757f3fSDimitry Andric MI.getOperand(0).setIsDead(false); 1692*0fca6ea1SDimitry Andric 1693*0fca6ea1SDimitry Andric // The def of DefReg moved to MI, so extend the LiveInterval up to 1694*0fca6ea1SDimitry Andric // it. 1695*0fca6ea1SDimitry Andric if (DefReg.isVirtual() && LIS) { 1696*0fca6ea1SDimitry Andric LiveInterval &DefLI = LIS->getInterval(DefReg); 1697*0fca6ea1SDimitry Andric SlotIndex MISlot = LIS->getInstructionIndex(MI).getRegSlot(); 1698*0fca6ea1SDimitry Andric VNInfo *DefVNI = DefLI.getVNInfoAt(DefLI.beginIndex()); 1699*0fca6ea1SDimitry Andric LiveInterval::Segment S(MISlot, DefLI.beginIndex(), DefVNI); 1700*0fca6ea1SDimitry Andric DefLI.addSegment(S); 1701*0fca6ea1SDimitry Andric DefVNI->def = MISlot; 1702*0fca6ea1SDimitry Andric // Mark DefLI as spillable if it was previously unspillable 1703*0fca6ea1SDimitry Andric DefLI.setWeight(0); 1704*0fca6ea1SDimitry Andric 1705*0fca6ea1SDimitry Andric // DefReg may have had no uses, in which case we need to shrink 1706*0fca6ea1SDimitry Andric // the LiveInterval up to MI. 1707*0fca6ea1SDimitry Andric LIS->shrinkToUses(&DefLI); 1708*0fca6ea1SDimitry Andric } 1709*0fca6ea1SDimitry Andric 17105f757f3fSDimitry Andric Register OldVLReg; 17115f757f3fSDimitry Andric if (MI.getOperand(1).isReg()) 17125f757f3fSDimitry Andric OldVLReg = MI.getOperand(1).getReg(); 1713bdd1243dSDimitry Andric if (NextMI->getOperand(1).isImm()) 1714bdd1243dSDimitry Andric MI.getOperand(1).ChangeToImmediate(NextMI->getOperand(1).getImm()); 1715bdd1243dSDimitry Andric else 1716bdd1243dSDimitry Andric MI.getOperand(1).ChangeToRegister(NextMI->getOperand(1).getReg(), false); 1717*0fca6ea1SDimitry Andric if (OldVLReg && OldVLReg.isVirtual()) 1718*0fca6ea1SDimitry Andric afterDroppedAVLUse(OldVLReg); 1719*0fca6ea1SDimitry Andric 1720bdd1243dSDimitry Andric MI.setDesc(NextMI->getDesc()); 1721bdd1243dSDimitry Andric } 1722bdd1243dSDimitry Andric MI.getOperand(2).setImm(NextMI->getOperand(2).getImm()); 1723bdd1243dSDimitry Andric ToDelete.push_back(NextMI); 1724bdd1243dSDimitry Andric // fallthrough 1725bdd1243dSDimitry Andric } 1726bdd1243dSDimitry Andric } 1727bdd1243dSDimitry Andric NextMI = &MI; 1728*0fca6ea1SDimitry Andric Used = getDemanded(MI, ST); 172981ad6265SDimitry Andric } 173081ad6265SDimitry Andric 1731*0fca6ea1SDimitry Andric NumCoalescedVSETVL += ToDelete.size(); 1732*0fca6ea1SDimitry Andric for (auto *MI : ToDelete) { 1733*0fca6ea1SDimitry Andric if (LIS) 1734*0fca6ea1SDimitry Andric LIS->RemoveMachineInstrFromMaps(*MI); 1735*0fca6ea1SDimitry Andric Register OldAVLReg; 1736*0fca6ea1SDimitry Andric if (MI->getOperand(1).isReg()) 1737*0fca6ea1SDimitry Andric OldAVLReg = MI->getOperand(1).getReg(); 173881ad6265SDimitry Andric MI->eraseFromParent(); 1739*0fca6ea1SDimitry Andric if (OldAVLReg && OldAVLReg.isVirtual()) 1740*0fca6ea1SDimitry Andric afterDroppedAVLUse(OldAVLReg); 1741*0fca6ea1SDimitry Andric } 174281ad6265SDimitry Andric } 174381ad6265SDimitry Andric 174481ad6265SDimitry Andric void RISCVInsertVSETVLI::insertReadVL(MachineBasicBlock &MBB) { 174581ad6265SDimitry Andric for (auto I = MBB.begin(), E = MBB.end(); I != E;) { 174681ad6265SDimitry Andric MachineInstr &MI = *I++; 174781ad6265SDimitry Andric if (RISCV::isFaultFirstLoad(MI)) { 174881ad6265SDimitry Andric Register VLOutput = MI.getOperand(1).getReg(); 1749*0fca6ea1SDimitry Andric assert(VLOutput.isVirtual()); 1750*0fca6ea1SDimitry Andric if (!MI.getOperand(1).isDead()) { 1751*0fca6ea1SDimitry Andric auto ReadVLMI = BuildMI(MBB, I, MI.getDebugLoc(), 1752*0fca6ea1SDimitry Andric TII->get(RISCV::PseudoReadVL), VLOutput); 1753*0fca6ea1SDimitry Andric // Move the LiveInterval's definition down to PseudoReadVL. 1754*0fca6ea1SDimitry Andric if (LIS) { 1755*0fca6ea1SDimitry Andric SlotIndex NewDefSI = 1756*0fca6ea1SDimitry Andric LIS->InsertMachineInstrInMaps(*ReadVLMI).getRegSlot(); 1757*0fca6ea1SDimitry Andric LiveInterval &DefLI = LIS->getInterval(VLOutput); 1758*0fca6ea1SDimitry Andric VNInfo *DefVNI = DefLI.getVNInfoAt(DefLI.beginIndex()); 1759*0fca6ea1SDimitry Andric DefLI.removeSegment(DefLI.beginIndex(), NewDefSI); 1760*0fca6ea1SDimitry Andric DefVNI->def = NewDefSI; 1761*0fca6ea1SDimitry Andric } 1762*0fca6ea1SDimitry Andric } 176381ad6265SDimitry Andric // We don't use the vl output of the VLEFF/VLSEGFF anymore. 176481ad6265SDimitry Andric MI.getOperand(1).setReg(RISCV::X0); 176581ad6265SDimitry Andric } 1766fe6060f1SDimitry Andric } 1767fe6060f1SDimitry Andric } 1768fe6060f1SDimitry Andric 1769fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::runOnMachineFunction(MachineFunction &MF) { 1770fe6060f1SDimitry Andric // Skip if the vector extension is not enabled. 17715f757f3fSDimitry Andric ST = &MF.getSubtarget<RISCVSubtarget>(); 17725f757f3fSDimitry Andric if (!ST->hasVInstructions()) 1773fe6060f1SDimitry Andric return false; 1774fe6060f1SDimitry Andric 177581ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Entering InsertVSETVLI for " << MF.getName() << "\n"); 177681ad6265SDimitry Andric 17775f757f3fSDimitry Andric TII = ST->getInstrInfo(); 1778fe6060f1SDimitry Andric MRI = &MF.getRegInfo(); 1779*0fca6ea1SDimitry Andric auto *LISWrapper = getAnalysisIfAvailable<LiveIntervalsWrapperPass>(); 1780*0fca6ea1SDimitry Andric LIS = LISWrapper ? &LISWrapper->getLIS() : nullptr; 1781fe6060f1SDimitry Andric 1782fe6060f1SDimitry Andric assert(BlockInfo.empty() && "Expect empty block infos"); 1783fe6060f1SDimitry Andric BlockInfo.resize(MF.getNumBlockIDs()); 1784fe6060f1SDimitry Andric 1785fe6060f1SDimitry Andric bool HaveVectorOp = false; 1786fe6060f1SDimitry Andric 1787fe6060f1SDimitry Andric // Phase 1 - determine how VL/VTYPE are affected by the each block. 178881ad6265SDimitry Andric for (const MachineBasicBlock &MBB : MF) { 17895f757f3fSDimitry Andric VSETVLIInfo TmpStatus; 17905f757f3fSDimitry Andric HaveVectorOp |= computeVLVTYPEChanges(MBB, TmpStatus); 179181ad6265SDimitry Andric // Initial exit state is whatever change we found in the block. 179281ad6265SDimitry Andric BlockData &BBInfo = BlockInfo[MBB.getNumber()]; 17935f757f3fSDimitry Andric BBInfo.Exit = TmpStatus; 179481ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Initial exit state of " << printMBBReference(MBB) 179581ad6265SDimitry Andric << " is " << BBInfo.Exit << "\n"); 179681ad6265SDimitry Andric 179781ad6265SDimitry Andric } 1798fe6060f1SDimitry Andric 1799fe6060f1SDimitry Andric // If we didn't find any instructions that need VSETVLI, we're done. 180081ad6265SDimitry Andric if (!HaveVectorOp) { 180181ad6265SDimitry Andric BlockInfo.clear(); 180281ad6265SDimitry Andric return false; 180381ad6265SDimitry Andric } 180481ad6265SDimitry Andric 1805fe6060f1SDimitry Andric // Phase 2 - determine the exit VL/VTYPE from each block. We add all 1806fe6060f1SDimitry Andric // blocks to the list here, but will also add any that need to be revisited 1807fe6060f1SDimitry Andric // during Phase 2 processing. 1808fe6060f1SDimitry Andric for (const MachineBasicBlock &MBB : MF) { 1809fe6060f1SDimitry Andric WorkList.push(&MBB); 1810fe6060f1SDimitry Andric BlockInfo[MBB.getNumber()].InQueue = true; 1811fe6060f1SDimitry Andric } 1812fe6060f1SDimitry Andric while (!WorkList.empty()) { 1813fe6060f1SDimitry Andric const MachineBasicBlock &MBB = *WorkList.front(); 1814fe6060f1SDimitry Andric WorkList.pop(); 1815fe6060f1SDimitry Andric computeIncomingVLVTYPE(MBB); 1816fe6060f1SDimitry Andric } 1817fe6060f1SDimitry Andric 181881ad6265SDimitry Andric // Perform partial redundancy elimination of vsetvli transitions. 181981ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) 182081ad6265SDimitry Andric doPRE(MBB); 182181ad6265SDimitry Andric 1822fe6060f1SDimitry Andric // Phase 3 - add any vsetvli instructions needed in the block. Use the 1823fe6060f1SDimitry Andric // Phase 2 information to avoid adding vsetvlis before the first vector 1824fe6060f1SDimitry Andric // instruction in the block if the VL/VTYPE is satisfied by its 1825fe6060f1SDimitry Andric // predecessors. 1826fe6060f1SDimitry Andric for (MachineBasicBlock &MBB : MF) 1827fe6060f1SDimitry Andric emitVSETVLIs(MBB); 182881ad6265SDimitry Andric 182981ad6265SDimitry Andric // Now that all vsetvlis are explicit, go through and do block local 183081ad6265SDimitry Andric // DSE and peephole based demanded fields based transforms. Note that 183181ad6265SDimitry Andric // this *must* be done outside the main dataflow so long as we allow 183281ad6265SDimitry Andric // any cross block analysis within the dataflow. We can't have both 183381ad6265SDimitry Andric // demanded fields based mutation and non-local analysis in the 183481ad6265SDimitry Andric // dataflow at the same time without introducing inconsistencies. 183581ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) 1836*0fca6ea1SDimitry Andric coalesceVSETVLIs(MBB); 183781ad6265SDimitry Andric 183881ad6265SDimitry Andric // Insert PseudoReadVL after VLEFF/VLSEGFF and replace it with the vl output 183981ad6265SDimitry Andric // of VLEFF/VLSEGFF. 184081ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) 184181ad6265SDimitry Andric insertReadVL(MBB); 1842fe6060f1SDimitry Andric 184381ad6265SDimitry Andric BlockInfo.clear(); 1844fe6060f1SDimitry Andric return HaveVectorOp; 1845fe6060f1SDimitry Andric } 1846fe6060f1SDimitry Andric 1847fe6060f1SDimitry Andric /// Returns an instance of the Insert VSETVLI pass. 1848fe6060f1SDimitry Andric FunctionPass *llvm::createRISCVInsertVSETVLIPass() { 1849fe6060f1SDimitry Andric return new RISCVInsertVSETVLI(); 1850fe6060f1SDimitry Andric } 1851