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" 29fe6060f1SDimitry Andric #include "llvm/CodeGen/LiveIntervals.h" 30fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 31fe6060f1SDimitry Andric #include <queue> 32fe6060f1SDimitry Andric using namespace llvm; 33fe6060f1SDimitry Andric 34fe6060f1SDimitry Andric #define DEBUG_TYPE "riscv-insert-vsetvli" 35fe6060f1SDimitry Andric #define RISCV_INSERT_VSETVLI_NAME "RISCV Insert VSETVLI pass" 36fe6060f1SDimitry Andric 37fe6060f1SDimitry Andric static cl::opt<bool> DisableInsertVSETVLPHIOpt( 38fe6060f1SDimitry Andric "riscv-disable-insert-vsetvl-phi-opt", cl::init(false), cl::Hidden, 39fe6060f1SDimitry Andric cl::desc("Disable looking through phis when inserting vsetvlis.")); 40fe6060f1SDimitry Andric 4181ad6265SDimitry Andric static cl::opt<bool> UseStrictAsserts( 4281ad6265SDimitry Andric "riscv-insert-vsetvl-strict-asserts", cl::init(true), cl::Hidden, 4381ad6265SDimitry Andric cl::desc("Enable strict assertion checking for the dataflow algorithm")); 4481ad6265SDimitry Andric 45fe6060f1SDimitry Andric namespace { 46fe6060f1SDimitry Andric 4781ad6265SDimitry Andric static unsigned getVLOpNum(const MachineInstr &MI) { 4881ad6265SDimitry Andric return RISCVII::getVLOpNum(MI.getDesc()); 49fe6060f1SDimitry Andric } 50fe6060f1SDimitry Andric 5181ad6265SDimitry Andric static unsigned getSEWOpNum(const MachineInstr &MI) { 5281ad6265SDimitry Andric return RISCVII::getSEWOpNum(MI.getDesc()); 53fe6060f1SDimitry Andric } 54fe6060f1SDimitry Andric 5504eeddc0SDimitry Andric static bool isScalarMoveInstr(const MachineInstr &MI) { 5604eeddc0SDimitry Andric switch (MI.getOpcode()) { 5704eeddc0SDimitry Andric default: 5804eeddc0SDimitry Andric return false; 5904eeddc0SDimitry Andric case RISCV::PseudoVMV_S_X_M1: 6004eeddc0SDimitry Andric case RISCV::PseudoVMV_S_X_M2: 6104eeddc0SDimitry Andric case RISCV::PseudoVMV_S_X_M4: 6204eeddc0SDimitry Andric case RISCV::PseudoVMV_S_X_M8: 6304eeddc0SDimitry Andric case RISCV::PseudoVMV_S_X_MF2: 6404eeddc0SDimitry Andric case RISCV::PseudoVMV_S_X_MF4: 6504eeddc0SDimitry Andric case RISCV::PseudoVMV_S_X_MF8: 6604eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F16_M1: 6704eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F16_M2: 6804eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F16_M4: 6904eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F16_M8: 7004eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F16_MF2: 7104eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F16_MF4: 7204eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F32_M1: 7304eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F32_M2: 7404eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F32_M4: 7504eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F32_M8: 7604eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F32_MF2: 7704eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F64_M1: 7804eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F64_M2: 7904eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F64_M4: 8004eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F64_M8: 8104eeddc0SDimitry Andric return true; 8204eeddc0SDimitry Andric } 8304eeddc0SDimitry Andric } 8404eeddc0SDimitry Andric 8581ad6265SDimitry Andric /// Get the EEW for a load or store instruction. Return None if MI is not 8681ad6265SDimitry Andric /// a load or store which ignores SEW. 8781ad6265SDimitry Andric static Optional<unsigned> getEEWForLoadStore(const MachineInstr &MI) { 88349cc55cSDimitry Andric switch (MI.getOpcode()) { 89349cc55cSDimitry Andric default: 9081ad6265SDimitry Andric return None; 91349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_M1: 92349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_M1_MASK: 93349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_M2: 94349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_M2_MASK: 95349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_M4: 96349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_M4_MASK: 97349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_M8: 98349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_M8_MASK: 99349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_MF2: 100349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_MF2_MASK: 101349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_MF4: 102349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_MF4_MASK: 103349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_MF8: 104349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_MF8_MASK: 105349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_M1: 106349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_M1_MASK: 107349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_M2: 108349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_M2_MASK: 109349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_M4: 110349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_M4_MASK: 111349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_M8: 112349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_M8_MASK: 113349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_MF2: 114349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_MF2_MASK: 115349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_MF4: 116349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_MF4_MASK: 117349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_MF8: 118349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_MF8_MASK: 119349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_M1: 120349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_M1_MASK: 121349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_M2: 122349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_M2_MASK: 123349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_M4: 124349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_M4_MASK: 125349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_M8: 126349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_M8_MASK: 127349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_MF2: 128349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_MF2_MASK: 129349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_MF4: 130349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_MF4_MASK: 131349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_MF8: 132349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_MF8_MASK: 133349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_M1: 134349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_M1_MASK: 135349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_M2: 136349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_M2_MASK: 137349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_M4: 138349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_M4_MASK: 139349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_M8: 140349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_M8_MASK: 141349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_MF2: 142349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_MF2_MASK: 143349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_MF4: 144349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_MF4_MASK: 145349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_MF8: 146349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_MF8_MASK: 14781ad6265SDimitry Andric return 8; 148349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_M1: 149349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_M1_MASK: 150349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_M2: 151349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_M2_MASK: 152349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_M4: 153349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_M4_MASK: 154349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_M8: 155349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_M8_MASK: 156349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_MF2: 157349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_MF2_MASK: 158349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_MF4: 159349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_MF4_MASK: 160349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_M1: 161349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_M1_MASK: 162349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_M2: 163349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_M2_MASK: 164349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_M4: 165349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_M4_MASK: 166349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_M8: 167349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_M8_MASK: 168349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_MF2: 169349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_MF2_MASK: 170349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_MF4: 171349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_MF4_MASK: 172349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_M1: 173349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_M1_MASK: 174349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_M2: 175349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_M2_MASK: 176349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_M4: 177349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_M4_MASK: 178349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_M8: 179349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_M8_MASK: 180349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_MF2: 181349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_MF2_MASK: 182349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_MF4: 183349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_MF4_MASK: 184349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_M1: 185349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_M1_MASK: 186349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_M2: 187349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_M2_MASK: 188349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_M4: 189349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_M4_MASK: 190349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_M8: 191349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_M8_MASK: 192349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_MF2: 193349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_MF2_MASK: 194349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_MF4: 195349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_MF4_MASK: 19681ad6265SDimitry Andric return 16; 197349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_M1: 198349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_M1_MASK: 199349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_M2: 200349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_M2_MASK: 201349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_M4: 202349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_M4_MASK: 203349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_M8: 204349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_M8_MASK: 205349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_MF2: 206349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_MF2_MASK: 207349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_M1: 208349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_M1_MASK: 209349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_M2: 210349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_M2_MASK: 211349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_M4: 212349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_M4_MASK: 213349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_M8: 214349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_M8_MASK: 215349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_MF2: 216349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_MF2_MASK: 217349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_M1: 218349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_M1_MASK: 219349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_M2: 220349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_M2_MASK: 221349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_M4: 222349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_M4_MASK: 223349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_M8: 224349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_M8_MASK: 225349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_MF2: 226349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_MF2_MASK: 227349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_M1: 228349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_M1_MASK: 229349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_M2: 230349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_M2_MASK: 231349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_M4: 232349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_M4_MASK: 233349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_M8: 234349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_M8_MASK: 235349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_MF2: 236349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_MF2_MASK: 23781ad6265SDimitry Andric return 32; 238349cc55cSDimitry Andric case RISCV::PseudoVLE64_V_M1: 239349cc55cSDimitry Andric case RISCV::PseudoVLE64_V_M1_MASK: 240349cc55cSDimitry Andric case RISCV::PseudoVLE64_V_M2: 241349cc55cSDimitry Andric case RISCV::PseudoVLE64_V_M2_MASK: 242349cc55cSDimitry Andric case RISCV::PseudoVLE64_V_M4: 243349cc55cSDimitry Andric case RISCV::PseudoVLE64_V_M4_MASK: 244349cc55cSDimitry Andric case RISCV::PseudoVLE64_V_M8: 245349cc55cSDimitry Andric case RISCV::PseudoVLE64_V_M8_MASK: 246349cc55cSDimitry Andric case RISCV::PseudoVLSE64_V_M1: 247349cc55cSDimitry Andric case RISCV::PseudoVLSE64_V_M1_MASK: 248349cc55cSDimitry Andric case RISCV::PseudoVLSE64_V_M2: 249349cc55cSDimitry Andric case RISCV::PseudoVLSE64_V_M2_MASK: 250349cc55cSDimitry Andric case RISCV::PseudoVLSE64_V_M4: 251349cc55cSDimitry Andric case RISCV::PseudoVLSE64_V_M4_MASK: 252349cc55cSDimitry Andric case RISCV::PseudoVLSE64_V_M8: 253349cc55cSDimitry Andric case RISCV::PseudoVLSE64_V_M8_MASK: 254349cc55cSDimitry Andric case RISCV::PseudoVSE64_V_M1: 255349cc55cSDimitry Andric case RISCV::PseudoVSE64_V_M1_MASK: 256349cc55cSDimitry Andric case RISCV::PseudoVSE64_V_M2: 257349cc55cSDimitry Andric case RISCV::PseudoVSE64_V_M2_MASK: 258349cc55cSDimitry Andric case RISCV::PseudoVSE64_V_M4: 259349cc55cSDimitry Andric case RISCV::PseudoVSE64_V_M4_MASK: 260349cc55cSDimitry Andric case RISCV::PseudoVSE64_V_M8: 261349cc55cSDimitry Andric case RISCV::PseudoVSE64_V_M8_MASK: 262349cc55cSDimitry Andric case RISCV::PseudoVSSE64_V_M1: 263349cc55cSDimitry Andric case RISCV::PseudoVSSE64_V_M1_MASK: 264349cc55cSDimitry Andric case RISCV::PseudoVSSE64_V_M2: 265349cc55cSDimitry Andric case RISCV::PseudoVSSE64_V_M2_MASK: 266349cc55cSDimitry Andric case RISCV::PseudoVSSE64_V_M4: 267349cc55cSDimitry Andric case RISCV::PseudoVSSE64_V_M4_MASK: 268349cc55cSDimitry Andric case RISCV::PseudoVSSE64_V_M8: 269349cc55cSDimitry Andric case RISCV::PseudoVSSE64_V_M8_MASK: 27081ad6265SDimitry Andric return 64; 27181ad6265SDimitry Andric } 272349cc55cSDimitry Andric } 273349cc55cSDimitry Andric 27481ad6265SDimitry Andric /// Return true if this is an operation on mask registers. Note that 27581ad6265SDimitry Andric /// this includes both arithmetic/logical ops and load/store (vlm/vsm). 27681ad6265SDimitry Andric static bool isMaskRegOp(const MachineInstr &MI) { 27781ad6265SDimitry Andric if (RISCVII::hasSEWOp(MI.getDesc().TSFlags)) { 27881ad6265SDimitry Andric const unsigned Log2SEW = MI.getOperand(getSEWOpNum(MI)).getImm(); 27981ad6265SDimitry Andric // A Log2SEW of 0 is an operation on mask registers only. 28081ad6265SDimitry Andric return Log2SEW == 0; 28181ad6265SDimitry Andric } 28281ad6265SDimitry Andric return false; 28381ad6265SDimitry Andric } 28481ad6265SDimitry Andric 28581ad6265SDimitry Andric static unsigned getSEWLMULRatio(unsigned SEW, RISCVII::VLMUL VLMul) { 28681ad6265SDimitry Andric unsigned LMul; 28781ad6265SDimitry Andric bool Fractional; 28881ad6265SDimitry Andric std::tie(LMul, Fractional) = RISCVVType::decodeVLMUL(VLMul); 28981ad6265SDimitry Andric 29081ad6265SDimitry Andric // Convert LMul to a fixed point value with 3 fractional bits. 29181ad6265SDimitry Andric LMul = Fractional ? (8 / LMul) : (LMul * 8); 29281ad6265SDimitry Andric 29381ad6265SDimitry Andric assert(SEW >= 8 && "Unexpected SEW value"); 29481ad6265SDimitry Andric return (SEW * 8) / LMul; 29581ad6265SDimitry Andric } 29681ad6265SDimitry Andric 29781ad6265SDimitry Andric /// Which subfields of VL or VTYPE have values we need to preserve? 29881ad6265SDimitry Andric struct DemandedFields { 29981ad6265SDimitry Andric bool VL = false; 30081ad6265SDimitry Andric bool SEW = false; 30181ad6265SDimitry Andric bool LMUL = false; 30281ad6265SDimitry Andric bool SEWLMULRatio = false; 30381ad6265SDimitry Andric bool TailPolicy = false; 30481ad6265SDimitry Andric bool MaskPolicy = false; 30581ad6265SDimitry Andric 30681ad6265SDimitry Andric // Return true if any part of VTYPE was used 30781ad6265SDimitry Andric bool usedVTYPE() { 30881ad6265SDimitry Andric return SEW || LMUL || SEWLMULRatio || TailPolicy || MaskPolicy; 30981ad6265SDimitry Andric } 31081ad6265SDimitry Andric 31181ad6265SDimitry Andric // Mark all VTYPE subfields and properties as demanded 31281ad6265SDimitry Andric void demandVTYPE() { 31381ad6265SDimitry Andric SEW = true; 31481ad6265SDimitry Andric LMUL = true; 31581ad6265SDimitry Andric SEWLMULRatio = true; 31681ad6265SDimitry Andric TailPolicy = true; 31781ad6265SDimitry Andric MaskPolicy = true; 31881ad6265SDimitry Andric } 31981ad6265SDimitry Andric }; 32081ad6265SDimitry Andric 32181ad6265SDimitry Andric /// Return true if the two values of the VTYPE register provided are 32281ad6265SDimitry Andric /// indistinguishable from the perspective of an instruction (or set of 32381ad6265SDimitry Andric /// instructions) which use only the Used subfields and properties. 32481ad6265SDimitry Andric static bool areCompatibleVTYPEs(uint64_t VType1, 32581ad6265SDimitry Andric uint64_t VType2, 32681ad6265SDimitry Andric const DemandedFields &Used) { 32781ad6265SDimitry Andric if (Used.SEW && 32881ad6265SDimitry Andric RISCVVType::getSEW(VType1) != RISCVVType::getSEW(VType2)) 32981ad6265SDimitry Andric return false; 33081ad6265SDimitry Andric 33181ad6265SDimitry Andric if (Used.LMUL && 33281ad6265SDimitry Andric RISCVVType::getVLMUL(VType1) != RISCVVType::getVLMUL(VType2)) 33381ad6265SDimitry Andric return false; 33481ad6265SDimitry Andric 33581ad6265SDimitry Andric if (Used.SEWLMULRatio) { 33681ad6265SDimitry Andric auto Ratio1 = getSEWLMULRatio(RISCVVType::getSEW(VType1), 33781ad6265SDimitry Andric RISCVVType::getVLMUL(VType1)); 33881ad6265SDimitry Andric auto Ratio2 = getSEWLMULRatio(RISCVVType::getSEW(VType2), 33981ad6265SDimitry Andric RISCVVType::getVLMUL(VType2)); 34081ad6265SDimitry Andric if (Ratio1 != Ratio2) 34181ad6265SDimitry Andric return false; 34281ad6265SDimitry Andric } 34381ad6265SDimitry Andric 34481ad6265SDimitry Andric if (Used.TailPolicy && 34581ad6265SDimitry Andric RISCVVType::isTailAgnostic(VType1) != RISCVVType::isTailAgnostic(VType2)) 34681ad6265SDimitry Andric return false; 34781ad6265SDimitry Andric if (Used.MaskPolicy && 34881ad6265SDimitry Andric RISCVVType::isMaskAgnostic(VType1) != RISCVVType::isMaskAgnostic(VType2)) 34981ad6265SDimitry Andric return false; 35081ad6265SDimitry Andric return true; 35181ad6265SDimitry Andric } 35281ad6265SDimitry Andric 35381ad6265SDimitry Andric /// Return the fields and properties demanded by the provided instruction. 35481ad6265SDimitry Andric static DemandedFields getDemanded(const MachineInstr &MI) { 35581ad6265SDimitry Andric // Warning: This function has to work on both the lowered (i.e. post 35681ad6265SDimitry Andric // emitVSETVLIs) and pre-lowering forms. The main implication of this is 35781ad6265SDimitry Andric // that it can't use the value of a SEW, VL, or Policy operand as they might 35881ad6265SDimitry Andric // be stale after lowering. 35981ad6265SDimitry Andric 36081ad6265SDimitry Andric // Most instructions don't use any of these subfeilds. 36181ad6265SDimitry Andric DemandedFields Res; 36281ad6265SDimitry Andric // Start conservative if registers are used 36381ad6265SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || MI.readsRegister(RISCV::VL)) 36481ad6265SDimitry Andric Res.VL = true; 36581ad6265SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || MI.readsRegister(RISCV::VTYPE)) 36681ad6265SDimitry Andric Res.demandVTYPE(); 36781ad6265SDimitry Andric // Start conservative on the unlowered form too 36881ad6265SDimitry Andric uint64_t TSFlags = MI.getDesc().TSFlags; 36981ad6265SDimitry Andric if (RISCVII::hasSEWOp(TSFlags)) { 37081ad6265SDimitry Andric Res.demandVTYPE(); 37181ad6265SDimitry Andric if (RISCVII::hasVLOp(TSFlags)) 37281ad6265SDimitry Andric Res.VL = true; 37381ad6265SDimitry Andric } 37481ad6265SDimitry Andric 37581ad6265SDimitry Andric // Loads and stores with implicit EEW do not demand SEW or LMUL directly. 37681ad6265SDimitry Andric // They instead demand the ratio of the two which is used in computing 37781ad6265SDimitry Andric // EMUL, but which allows us the flexibility to change SEW and LMUL 37881ad6265SDimitry Andric // provided we don't change the ratio. 37981ad6265SDimitry Andric // Note: We assume that the instructions initial SEW is the EEW encoded 38081ad6265SDimitry Andric // in the opcode. This is asserted when constructing the VSETVLIInfo. 38181ad6265SDimitry Andric if (getEEWForLoadStore(MI)) { 38281ad6265SDimitry Andric Res.SEW = false; 38381ad6265SDimitry Andric Res.LMUL = false; 38481ad6265SDimitry Andric } 38581ad6265SDimitry Andric 38681ad6265SDimitry Andric // Store instructions don't use the policy fields. 38781ad6265SDimitry Andric if (RISCVII::hasSEWOp(TSFlags) && MI.getNumExplicitDefs() == 0) { 38881ad6265SDimitry Andric Res.TailPolicy = false; 38981ad6265SDimitry Andric Res.MaskPolicy = false; 39081ad6265SDimitry Andric } 39181ad6265SDimitry Andric 39281ad6265SDimitry Andric // If this is a mask reg operation, it only cares about VLMAX. 39381ad6265SDimitry Andric // TODO: Possible extensions to this logic 39481ad6265SDimitry Andric // * Probably ok if available VLMax is larger than demanded 39581ad6265SDimitry Andric // * The policy bits can probably be ignored.. 39681ad6265SDimitry Andric if (isMaskRegOp(MI)) { 39781ad6265SDimitry Andric Res.SEW = false; 39881ad6265SDimitry Andric Res.LMUL = false; 39981ad6265SDimitry Andric } 40081ad6265SDimitry Andric 40181ad6265SDimitry Andric return Res; 40281ad6265SDimitry Andric } 40381ad6265SDimitry Andric 40481ad6265SDimitry Andric /// Defines the abstract state with which the forward dataflow models the 40581ad6265SDimitry Andric /// values of the VL and VTYPE registers after insertion. 40681ad6265SDimitry Andric class VSETVLIInfo { 40781ad6265SDimitry Andric union { 40881ad6265SDimitry Andric Register AVLReg; 40981ad6265SDimitry Andric unsigned AVLImm; 41081ad6265SDimitry Andric }; 41181ad6265SDimitry Andric 41281ad6265SDimitry Andric enum : uint8_t { 41381ad6265SDimitry Andric Uninitialized, 41481ad6265SDimitry Andric AVLIsReg, 41581ad6265SDimitry Andric AVLIsImm, 41681ad6265SDimitry Andric Unknown, 41781ad6265SDimitry Andric } State = Uninitialized; 41881ad6265SDimitry Andric 41981ad6265SDimitry Andric // Fields from VTYPE. 42081ad6265SDimitry Andric RISCVII::VLMUL VLMul = RISCVII::LMUL_1; 42181ad6265SDimitry Andric uint8_t SEW = 0; 42281ad6265SDimitry Andric uint8_t TailAgnostic : 1; 42381ad6265SDimitry Andric uint8_t MaskAgnostic : 1; 42481ad6265SDimitry Andric uint8_t SEWLMULRatioOnly : 1; 42581ad6265SDimitry Andric 42681ad6265SDimitry Andric public: 42781ad6265SDimitry Andric VSETVLIInfo() 42881ad6265SDimitry Andric : AVLImm(0), TailAgnostic(false), MaskAgnostic(false), 42981ad6265SDimitry Andric SEWLMULRatioOnly(false) {} 43081ad6265SDimitry Andric 43181ad6265SDimitry Andric static VSETVLIInfo getUnknown() { 43281ad6265SDimitry Andric VSETVLIInfo Info; 43381ad6265SDimitry Andric Info.setUnknown(); 43481ad6265SDimitry Andric return Info; 43581ad6265SDimitry Andric } 43681ad6265SDimitry Andric 43781ad6265SDimitry Andric bool isValid() const { return State != Uninitialized; } 43881ad6265SDimitry Andric void setUnknown() { State = Unknown; } 43981ad6265SDimitry Andric bool isUnknown() const { return State == Unknown; } 44081ad6265SDimitry Andric 44181ad6265SDimitry Andric void setAVLReg(Register Reg) { 44281ad6265SDimitry Andric AVLReg = Reg; 44381ad6265SDimitry Andric State = AVLIsReg; 44481ad6265SDimitry Andric } 44581ad6265SDimitry Andric 44681ad6265SDimitry Andric void setAVLImm(unsigned Imm) { 44781ad6265SDimitry Andric AVLImm = Imm; 44881ad6265SDimitry Andric State = AVLIsImm; 44981ad6265SDimitry Andric } 45081ad6265SDimitry Andric 45181ad6265SDimitry Andric bool hasAVLImm() const { return State == AVLIsImm; } 45281ad6265SDimitry Andric bool hasAVLReg() const { return State == AVLIsReg; } 45381ad6265SDimitry Andric Register getAVLReg() const { 45481ad6265SDimitry Andric assert(hasAVLReg()); 45581ad6265SDimitry Andric return AVLReg; 45681ad6265SDimitry Andric } 45781ad6265SDimitry Andric unsigned getAVLImm() const { 45881ad6265SDimitry Andric assert(hasAVLImm()); 45981ad6265SDimitry Andric return AVLImm; 46081ad6265SDimitry Andric } 46181ad6265SDimitry Andric 46281ad6265SDimitry Andric unsigned getSEW() const { return SEW; } 46381ad6265SDimitry Andric RISCVII::VLMUL getVLMUL() const { return VLMul; } 46481ad6265SDimitry Andric 46581ad6265SDimitry Andric bool hasNonZeroAVL() const { 46681ad6265SDimitry Andric if (hasAVLImm()) 46781ad6265SDimitry Andric return getAVLImm() > 0; 46881ad6265SDimitry Andric if (hasAVLReg()) 46981ad6265SDimitry Andric return getAVLReg() == RISCV::X0; 47081ad6265SDimitry Andric return false; 47181ad6265SDimitry Andric } 47281ad6265SDimitry Andric 47381ad6265SDimitry Andric bool hasSameAVL(const VSETVLIInfo &Other) const { 47481ad6265SDimitry Andric assert(isValid() && Other.isValid() && 47581ad6265SDimitry Andric "Can't compare invalid VSETVLIInfos"); 47681ad6265SDimitry Andric assert(!isUnknown() && !Other.isUnknown() && 47781ad6265SDimitry Andric "Can't compare AVL in unknown state"); 47881ad6265SDimitry Andric if (hasAVLReg() && Other.hasAVLReg()) 47981ad6265SDimitry Andric return getAVLReg() == Other.getAVLReg(); 48081ad6265SDimitry Andric 48181ad6265SDimitry Andric if (hasAVLImm() && Other.hasAVLImm()) 48281ad6265SDimitry Andric return getAVLImm() == Other.getAVLImm(); 48381ad6265SDimitry Andric 48481ad6265SDimitry Andric return false; 48581ad6265SDimitry Andric } 48681ad6265SDimitry Andric 48781ad6265SDimitry Andric void setVTYPE(unsigned VType) { 48881ad6265SDimitry Andric assert(isValid() && !isUnknown() && 48981ad6265SDimitry Andric "Can't set VTYPE for uninitialized or unknown"); 49081ad6265SDimitry Andric VLMul = RISCVVType::getVLMUL(VType); 49181ad6265SDimitry Andric SEW = RISCVVType::getSEW(VType); 49281ad6265SDimitry Andric TailAgnostic = RISCVVType::isTailAgnostic(VType); 49381ad6265SDimitry Andric MaskAgnostic = RISCVVType::isMaskAgnostic(VType); 49481ad6265SDimitry Andric } 49581ad6265SDimitry Andric void setVTYPE(RISCVII::VLMUL L, unsigned S, bool TA, bool MA) { 49681ad6265SDimitry Andric assert(isValid() && !isUnknown() && 49781ad6265SDimitry Andric "Can't set VTYPE for uninitialized or unknown"); 49881ad6265SDimitry Andric VLMul = L; 49981ad6265SDimitry Andric SEW = S; 50081ad6265SDimitry Andric TailAgnostic = TA; 50181ad6265SDimitry Andric MaskAgnostic = MA; 50281ad6265SDimitry Andric } 50381ad6265SDimitry Andric 50481ad6265SDimitry Andric unsigned encodeVTYPE() const { 50581ad6265SDimitry Andric assert(isValid() && !isUnknown() && !SEWLMULRatioOnly && 50681ad6265SDimitry Andric "Can't encode VTYPE for uninitialized or unknown"); 50781ad6265SDimitry Andric return RISCVVType::encodeVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic); 50881ad6265SDimitry Andric } 50981ad6265SDimitry Andric 51081ad6265SDimitry Andric bool hasSEWLMULRatioOnly() const { return SEWLMULRatioOnly; } 51181ad6265SDimitry Andric 51281ad6265SDimitry Andric bool hasSameSEW(const VSETVLIInfo &Other) const { 51381ad6265SDimitry Andric assert(isValid() && Other.isValid() && 51481ad6265SDimitry Andric "Can't compare invalid VSETVLIInfos"); 51581ad6265SDimitry Andric assert(!isUnknown() && !Other.isUnknown() && 51681ad6265SDimitry Andric "Can't compare VTYPE in unknown state"); 51781ad6265SDimitry Andric assert(!SEWLMULRatioOnly && !Other.SEWLMULRatioOnly && 51881ad6265SDimitry Andric "Can't compare when only LMUL/SEW ratio is valid."); 51981ad6265SDimitry Andric return SEW == Other.SEW; 52081ad6265SDimitry Andric } 52181ad6265SDimitry Andric 52281ad6265SDimitry Andric bool hasSameVTYPE(const VSETVLIInfo &Other) const { 52381ad6265SDimitry Andric assert(isValid() && Other.isValid() && 52481ad6265SDimitry Andric "Can't compare invalid VSETVLIInfos"); 52581ad6265SDimitry Andric assert(!isUnknown() && !Other.isUnknown() && 52681ad6265SDimitry Andric "Can't compare VTYPE in unknown state"); 52781ad6265SDimitry Andric assert(!SEWLMULRatioOnly && !Other.SEWLMULRatioOnly && 52881ad6265SDimitry Andric "Can't compare when only LMUL/SEW ratio is valid."); 52981ad6265SDimitry Andric return std::tie(VLMul, SEW, TailAgnostic, MaskAgnostic) == 53081ad6265SDimitry Andric std::tie(Other.VLMul, Other.SEW, Other.TailAgnostic, 53181ad6265SDimitry Andric Other.MaskAgnostic); 53281ad6265SDimitry Andric } 53381ad6265SDimitry Andric 53481ad6265SDimitry Andric unsigned getSEWLMULRatio() const { 53581ad6265SDimitry Andric assert(isValid() && !isUnknown() && 53681ad6265SDimitry Andric "Can't use VTYPE for uninitialized or unknown"); 53781ad6265SDimitry Andric return ::getSEWLMULRatio(SEW, VLMul); 53881ad6265SDimitry Andric } 53981ad6265SDimitry Andric 54081ad6265SDimitry Andric // Check if the VTYPE for these two VSETVLIInfos produce the same VLMAX. 54181ad6265SDimitry Andric // Note that having the same VLMAX ensures that both share the same 54281ad6265SDimitry Andric // function from AVL to VL; that is, they must produce the same VL value 54381ad6265SDimitry Andric // for any given AVL value. 54481ad6265SDimitry Andric bool hasSameVLMAX(const VSETVLIInfo &Other) const { 54581ad6265SDimitry Andric assert(isValid() && Other.isValid() && 54681ad6265SDimitry Andric "Can't compare invalid VSETVLIInfos"); 54781ad6265SDimitry Andric assert(!isUnknown() && !Other.isUnknown() && 54881ad6265SDimitry Andric "Can't compare VTYPE in unknown state"); 54981ad6265SDimitry Andric return getSEWLMULRatio() == Other.getSEWLMULRatio(); 55081ad6265SDimitry Andric } 55181ad6265SDimitry Andric 55281ad6265SDimitry Andric bool hasSamePolicy(const VSETVLIInfo &Other) const { 55381ad6265SDimitry Andric assert(isValid() && Other.isValid() && 55481ad6265SDimitry Andric "Can't compare invalid VSETVLIInfos"); 55581ad6265SDimitry Andric assert(!isUnknown() && !Other.isUnknown() && 55681ad6265SDimitry Andric "Can't compare VTYPE in unknown state"); 55781ad6265SDimitry Andric return TailAgnostic == Other.TailAgnostic && 55881ad6265SDimitry Andric MaskAgnostic == Other.MaskAgnostic; 55981ad6265SDimitry Andric } 56081ad6265SDimitry Andric 56181ad6265SDimitry Andric bool hasCompatibleVTYPE(const MachineInstr &MI, 56281ad6265SDimitry Andric const VSETVLIInfo &Require) const { 56381ad6265SDimitry Andric const DemandedFields Used = getDemanded(MI); 56481ad6265SDimitry Andric return areCompatibleVTYPEs(encodeVTYPE(), Require.encodeVTYPE(), Used); 56581ad6265SDimitry Andric } 56681ad6265SDimitry Andric 56781ad6265SDimitry Andric // Determine whether the vector instructions requirements represented by 56881ad6265SDimitry Andric // Require are compatible with the previous vsetvli instruction represented 56981ad6265SDimitry Andric // by this. MI is the instruction whose requirements we're considering. 57081ad6265SDimitry Andric bool isCompatible(const MachineInstr &MI, const VSETVLIInfo &Require) const { 57181ad6265SDimitry Andric assert(isValid() && Require.isValid() && 57281ad6265SDimitry Andric "Can't compare invalid VSETVLIInfos"); 57381ad6265SDimitry Andric assert(!Require.SEWLMULRatioOnly && 57481ad6265SDimitry Andric "Expected a valid VTYPE for instruction!"); 57581ad6265SDimitry Andric // Nothing is compatible with Unknown. 57681ad6265SDimitry Andric if (isUnknown() || Require.isUnknown()) 57781ad6265SDimitry Andric return false; 57881ad6265SDimitry Andric 57981ad6265SDimitry Andric // If only our VLMAX ratio is valid, then this isn't compatible. 58081ad6265SDimitry Andric if (SEWLMULRatioOnly) 58181ad6265SDimitry Andric return false; 58281ad6265SDimitry Andric 58381ad6265SDimitry Andric // If the instruction doesn't need an AVLReg and the SEW matches, consider 58481ad6265SDimitry Andric // it compatible. 58581ad6265SDimitry Andric if (Require.hasAVLReg() && Require.AVLReg == RISCV::NoRegister) 58681ad6265SDimitry Andric if (SEW == Require.SEW) 58781ad6265SDimitry Andric return true; 58881ad6265SDimitry Andric 58981ad6265SDimitry Andric return hasSameAVL(Require) && hasCompatibleVTYPE(MI, Require); 59081ad6265SDimitry Andric } 59181ad6265SDimitry Andric 59281ad6265SDimitry Andric bool operator==(const VSETVLIInfo &Other) const { 59381ad6265SDimitry Andric // Uninitialized is only equal to another Uninitialized. 59481ad6265SDimitry Andric if (!isValid()) 59581ad6265SDimitry Andric return !Other.isValid(); 59681ad6265SDimitry Andric if (!Other.isValid()) 59781ad6265SDimitry Andric return !isValid(); 59881ad6265SDimitry Andric 59981ad6265SDimitry Andric // Unknown is only equal to another Unknown. 60081ad6265SDimitry Andric if (isUnknown()) 60181ad6265SDimitry Andric return Other.isUnknown(); 60281ad6265SDimitry Andric if (Other.isUnknown()) 60381ad6265SDimitry Andric return isUnknown(); 60481ad6265SDimitry Andric 60581ad6265SDimitry Andric if (!hasSameAVL(Other)) 60681ad6265SDimitry Andric return false; 60781ad6265SDimitry Andric 60881ad6265SDimitry Andric // If the SEWLMULRatioOnly bits are different, then they aren't equal. 60981ad6265SDimitry Andric if (SEWLMULRatioOnly != Other.SEWLMULRatioOnly) 61081ad6265SDimitry Andric return false; 61181ad6265SDimitry Andric 61281ad6265SDimitry Andric // If only the VLMAX is valid, check that it is the same. 61381ad6265SDimitry Andric if (SEWLMULRatioOnly) 61481ad6265SDimitry Andric return hasSameVLMAX(Other); 61581ad6265SDimitry Andric 61681ad6265SDimitry Andric // If the full VTYPE is valid, check that it is the same. 61781ad6265SDimitry Andric return hasSameVTYPE(Other); 61881ad6265SDimitry Andric } 61981ad6265SDimitry Andric 62081ad6265SDimitry Andric bool operator!=(const VSETVLIInfo &Other) const { 62181ad6265SDimitry Andric return !(*this == Other); 62281ad6265SDimitry Andric } 62381ad6265SDimitry Andric 62481ad6265SDimitry Andric // Calculate the VSETVLIInfo visible to a block assuming this and Other are 62581ad6265SDimitry Andric // both predecessors. 62681ad6265SDimitry Andric VSETVLIInfo intersect(const VSETVLIInfo &Other) const { 62781ad6265SDimitry Andric // If the new value isn't valid, ignore it. 62881ad6265SDimitry Andric if (!Other.isValid()) 62981ad6265SDimitry Andric return *this; 63081ad6265SDimitry Andric 63181ad6265SDimitry Andric // If this value isn't valid, this must be the first predecessor, use it. 63281ad6265SDimitry Andric if (!isValid()) 63381ad6265SDimitry Andric return Other; 63481ad6265SDimitry Andric 63581ad6265SDimitry Andric // If either is unknown, the result is unknown. 63681ad6265SDimitry Andric if (isUnknown() || Other.isUnknown()) 63781ad6265SDimitry Andric return VSETVLIInfo::getUnknown(); 63881ad6265SDimitry Andric 63981ad6265SDimitry Andric // If we have an exact, match return this. 64081ad6265SDimitry Andric if (*this == Other) 64181ad6265SDimitry Andric return *this; 64281ad6265SDimitry Andric 64381ad6265SDimitry Andric // Not an exact match, but maybe the AVL and VLMAX are the same. If so, 64481ad6265SDimitry Andric // return an SEW/LMUL ratio only value. 64581ad6265SDimitry Andric if (hasSameAVL(Other) && hasSameVLMAX(Other)) { 64681ad6265SDimitry Andric VSETVLIInfo MergeInfo = *this; 64781ad6265SDimitry Andric MergeInfo.SEWLMULRatioOnly = true; 64881ad6265SDimitry Andric return MergeInfo; 64981ad6265SDimitry Andric } 65081ad6265SDimitry Andric 65181ad6265SDimitry Andric // Otherwise the result is unknown. 65281ad6265SDimitry Andric return VSETVLIInfo::getUnknown(); 65381ad6265SDimitry Andric } 65481ad6265SDimitry Andric 65581ad6265SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 65681ad6265SDimitry Andric /// Support for debugging, callable in GDB: V->dump() 65781ad6265SDimitry Andric LLVM_DUMP_METHOD void dump() const { 65881ad6265SDimitry Andric print(dbgs()); 65981ad6265SDimitry Andric dbgs() << "\n"; 66081ad6265SDimitry Andric } 66181ad6265SDimitry Andric 66281ad6265SDimitry Andric /// Implement operator<<. 66381ad6265SDimitry Andric /// @{ 66481ad6265SDimitry Andric void print(raw_ostream &OS) const { 66581ad6265SDimitry Andric OS << "{"; 66681ad6265SDimitry Andric if (!isValid()) 66781ad6265SDimitry Andric OS << "Uninitialized"; 66881ad6265SDimitry Andric if (isUnknown()) 66981ad6265SDimitry Andric OS << "unknown"; 67081ad6265SDimitry Andric if (hasAVLReg()) 67181ad6265SDimitry Andric OS << "AVLReg=" << (unsigned)AVLReg; 67281ad6265SDimitry Andric if (hasAVLImm()) 67381ad6265SDimitry Andric OS << "AVLImm=" << (unsigned)AVLImm; 67481ad6265SDimitry Andric OS << ", " 67581ad6265SDimitry Andric << "VLMul=" << (unsigned)VLMul << ", " 67681ad6265SDimitry Andric << "SEW=" << (unsigned)SEW << ", " 67781ad6265SDimitry Andric << "TailAgnostic=" << (bool)TailAgnostic << ", " 67881ad6265SDimitry Andric << "MaskAgnostic=" << (bool)MaskAgnostic << ", " 67981ad6265SDimitry Andric << "SEWLMULRatioOnly=" << (bool)SEWLMULRatioOnly << "}"; 68081ad6265SDimitry Andric } 68181ad6265SDimitry Andric #endif 68281ad6265SDimitry Andric }; 68381ad6265SDimitry Andric 68481ad6265SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 68581ad6265SDimitry Andric LLVM_ATTRIBUTE_USED 68681ad6265SDimitry Andric inline raw_ostream &operator<<(raw_ostream &OS, const VSETVLIInfo &V) { 68781ad6265SDimitry Andric V.print(OS); 68881ad6265SDimitry Andric return OS; 68981ad6265SDimitry Andric } 69081ad6265SDimitry Andric #endif 69181ad6265SDimitry Andric 69281ad6265SDimitry Andric struct BlockData { 69381ad6265SDimitry Andric // The VSETVLIInfo that represents the net changes to the VL/VTYPE registers 69481ad6265SDimitry Andric // made by this block. Calculated in Phase 1. 69581ad6265SDimitry Andric VSETVLIInfo Change; 69681ad6265SDimitry Andric 69781ad6265SDimitry Andric // The VSETVLIInfo that represents the VL/VTYPE settings on exit from this 69881ad6265SDimitry Andric // block. Calculated in Phase 2. 69981ad6265SDimitry Andric VSETVLIInfo Exit; 70081ad6265SDimitry Andric 70181ad6265SDimitry Andric // The VSETVLIInfo that represents the VL/VTYPE settings from all predecessor 70281ad6265SDimitry Andric // blocks. Calculated in Phase 2, and used by Phase 3. 70381ad6265SDimitry Andric VSETVLIInfo Pred; 70481ad6265SDimitry Andric 70581ad6265SDimitry Andric // Keeps track of whether the block is already in the queue. 70681ad6265SDimitry Andric bool InQueue = false; 70781ad6265SDimitry Andric 70881ad6265SDimitry Andric BlockData() = default; 70981ad6265SDimitry Andric }; 71081ad6265SDimitry Andric 71181ad6265SDimitry Andric class RISCVInsertVSETVLI : public MachineFunctionPass { 71281ad6265SDimitry Andric const TargetInstrInfo *TII; 71381ad6265SDimitry Andric MachineRegisterInfo *MRI; 71481ad6265SDimitry Andric 71581ad6265SDimitry Andric std::vector<BlockData> BlockInfo; 71681ad6265SDimitry Andric std::queue<const MachineBasicBlock *> WorkList; 71781ad6265SDimitry Andric 71881ad6265SDimitry Andric public: 71981ad6265SDimitry Andric static char ID; 72081ad6265SDimitry Andric 72181ad6265SDimitry Andric RISCVInsertVSETVLI() : MachineFunctionPass(ID) { 72281ad6265SDimitry Andric initializeRISCVInsertVSETVLIPass(*PassRegistry::getPassRegistry()); 72381ad6265SDimitry Andric } 72481ad6265SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 72581ad6265SDimitry Andric 72681ad6265SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 72781ad6265SDimitry Andric AU.setPreservesCFG(); 72881ad6265SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 72981ad6265SDimitry Andric } 73081ad6265SDimitry Andric 73181ad6265SDimitry Andric StringRef getPassName() const override { return RISCV_INSERT_VSETVLI_NAME; } 73281ad6265SDimitry Andric 73381ad6265SDimitry Andric private: 73481ad6265SDimitry Andric bool needVSETVLI(const MachineInstr &MI, const VSETVLIInfo &Require, 73581ad6265SDimitry Andric const VSETVLIInfo &CurInfo) const; 73681ad6265SDimitry Andric bool needVSETVLIPHI(const VSETVLIInfo &Require, 73781ad6265SDimitry Andric const MachineBasicBlock &MBB) const; 73881ad6265SDimitry Andric void insertVSETVLI(MachineBasicBlock &MBB, MachineInstr &MI, 73981ad6265SDimitry Andric const VSETVLIInfo &Info, const VSETVLIInfo &PrevInfo); 74081ad6265SDimitry Andric void insertVSETVLI(MachineBasicBlock &MBB, 74181ad6265SDimitry Andric MachineBasicBlock::iterator InsertPt, DebugLoc DL, 74281ad6265SDimitry Andric const VSETVLIInfo &Info, const VSETVLIInfo &PrevInfo); 74381ad6265SDimitry Andric 74481ad6265SDimitry Andric void transferBefore(VSETVLIInfo &Info, const MachineInstr &MI); 74581ad6265SDimitry Andric void transferAfter(VSETVLIInfo &Info, const MachineInstr &MI); 74681ad6265SDimitry Andric bool computeVLVTYPEChanges(const MachineBasicBlock &MBB); 74781ad6265SDimitry Andric void computeIncomingVLVTYPE(const MachineBasicBlock &MBB); 74881ad6265SDimitry Andric void emitVSETVLIs(MachineBasicBlock &MBB); 74981ad6265SDimitry Andric void doLocalPostpass(MachineBasicBlock &MBB); 75081ad6265SDimitry Andric void doPRE(MachineBasicBlock &MBB); 75181ad6265SDimitry Andric void insertReadVL(MachineBasicBlock &MBB); 75281ad6265SDimitry Andric }; 75381ad6265SDimitry Andric 75481ad6265SDimitry Andric } // end anonymous namespace 75581ad6265SDimitry Andric 75681ad6265SDimitry Andric char RISCVInsertVSETVLI::ID = 0; 75781ad6265SDimitry Andric 75881ad6265SDimitry Andric INITIALIZE_PASS(RISCVInsertVSETVLI, DEBUG_TYPE, RISCV_INSERT_VSETVLI_NAME, 75981ad6265SDimitry Andric false, false) 76081ad6265SDimitry Andric 76181ad6265SDimitry Andric static bool isVectorConfigInstr(const MachineInstr &MI) { 76281ad6265SDimitry Andric return MI.getOpcode() == RISCV::PseudoVSETVLI || 76381ad6265SDimitry Andric MI.getOpcode() == RISCV::PseudoVSETVLIX0 || 76481ad6265SDimitry Andric MI.getOpcode() == RISCV::PseudoVSETIVLI; 76581ad6265SDimitry Andric } 76681ad6265SDimitry Andric 76781ad6265SDimitry Andric /// Return true if this is 'vsetvli x0, x0, vtype' which preserves 76881ad6265SDimitry Andric /// VL and only sets VTYPE. 76981ad6265SDimitry Andric static bool isVLPreservingConfig(const MachineInstr &MI) { 77081ad6265SDimitry Andric if (MI.getOpcode() != RISCV::PseudoVSETVLIX0) 77181ad6265SDimitry Andric return false; 77281ad6265SDimitry Andric assert(RISCV::X0 == MI.getOperand(1).getReg()); 77381ad6265SDimitry Andric return RISCV::X0 == MI.getOperand(0).getReg(); 77481ad6265SDimitry Andric } 77581ad6265SDimitry Andric 77681ad6265SDimitry Andric static VSETVLIInfo computeInfoForInstr(const MachineInstr &MI, uint64_t TSFlags, 77781ad6265SDimitry Andric const MachineRegisterInfo *MRI) { 77881ad6265SDimitry Andric VSETVLIInfo InstrInfo; 77981ad6265SDimitry Andric 78081ad6265SDimitry Andric // If the instruction has policy argument, use the argument. 78181ad6265SDimitry Andric // If there is no policy argument, default to tail agnostic unless the 78281ad6265SDimitry Andric // destination is tied to a source. Unless the source is undef. In that case 78381ad6265SDimitry Andric // the user would have some control over the policy values. 78481ad6265SDimitry Andric bool TailAgnostic = true; 78581ad6265SDimitry Andric bool UsesMaskPolicy = RISCVII::usesMaskPolicy(TSFlags); 78681ad6265SDimitry Andric // FIXME: Could we look at the above or below instructions to choose the 78781ad6265SDimitry Andric // matched mask policy to reduce vsetvli instructions? Default mask policy is 78881ad6265SDimitry Andric // agnostic if instructions use mask policy, otherwise is undisturbed. Because 78981ad6265SDimitry Andric // most mask operations are mask undisturbed, so we could possibly reduce the 79081ad6265SDimitry Andric // vsetvli between mask and nomasked instruction sequence. 79181ad6265SDimitry Andric bool MaskAgnostic = UsesMaskPolicy; 79281ad6265SDimitry Andric unsigned UseOpIdx; 79381ad6265SDimitry Andric if (RISCVII::hasVecPolicyOp(TSFlags)) { 79481ad6265SDimitry Andric const MachineOperand &Op = MI.getOperand(MI.getNumExplicitOperands() - 1); 79581ad6265SDimitry Andric uint64_t Policy = Op.getImm(); 79681ad6265SDimitry Andric assert(Policy <= (RISCVII::TAIL_AGNOSTIC | RISCVII::MASK_AGNOSTIC) && 79781ad6265SDimitry Andric "Invalid Policy Value"); 79881ad6265SDimitry Andric // Although in some cases, mismatched passthru/maskedoff with policy value 79981ad6265SDimitry Andric // does not make sense (ex. tied operand is IMPLICIT_DEF with non-TAMA 80081ad6265SDimitry Andric // policy, or tied operand is not IMPLICIT_DEF with TAMA policy), but users 80181ad6265SDimitry Andric // have set the policy value explicitly, so compiler would not fix it. 80281ad6265SDimitry Andric TailAgnostic = Policy & RISCVII::TAIL_AGNOSTIC; 80381ad6265SDimitry Andric MaskAgnostic = Policy & RISCVII::MASK_AGNOSTIC; 80481ad6265SDimitry Andric } else if (MI.isRegTiedToUseOperand(0, &UseOpIdx)) { 80581ad6265SDimitry Andric TailAgnostic = false; 80681ad6265SDimitry Andric if (UsesMaskPolicy) 80781ad6265SDimitry Andric MaskAgnostic = false; 80881ad6265SDimitry Andric // If the tied operand is an IMPLICIT_DEF we can keep TailAgnostic. 80981ad6265SDimitry Andric const MachineOperand &UseMO = MI.getOperand(UseOpIdx); 81081ad6265SDimitry Andric MachineInstr *UseMI = MRI->getVRegDef(UseMO.getReg()); 81181ad6265SDimitry Andric if (UseMI && UseMI->isImplicitDef()) { 81281ad6265SDimitry Andric TailAgnostic = true; 81381ad6265SDimitry Andric if (UsesMaskPolicy) 81481ad6265SDimitry Andric MaskAgnostic = true; 81581ad6265SDimitry Andric } 81681ad6265SDimitry Andric // Some pseudo instructions force a tail agnostic policy despite having a 81781ad6265SDimitry Andric // tied def. 81881ad6265SDimitry Andric if (RISCVII::doesForceTailAgnostic(TSFlags)) 81981ad6265SDimitry Andric TailAgnostic = true; 82081ad6265SDimitry Andric } 82181ad6265SDimitry Andric 82281ad6265SDimitry Andric RISCVII::VLMUL VLMul = RISCVII::getLMul(TSFlags); 82381ad6265SDimitry Andric 82481ad6265SDimitry Andric unsigned Log2SEW = MI.getOperand(getSEWOpNum(MI)).getImm(); 82581ad6265SDimitry Andric // A Log2SEW of 0 is an operation on mask registers only. 82681ad6265SDimitry Andric unsigned SEW = Log2SEW ? 1 << Log2SEW : 8; 82781ad6265SDimitry Andric assert(RISCVVType::isValidSEW(SEW) && "Unexpected SEW"); 82881ad6265SDimitry Andric 82981ad6265SDimitry Andric if (RISCVII::hasVLOp(TSFlags)) { 83081ad6265SDimitry Andric const MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI)); 83181ad6265SDimitry Andric if (VLOp.isImm()) { 83281ad6265SDimitry Andric int64_t Imm = VLOp.getImm(); 83381ad6265SDimitry Andric // Conver the VLMax sentintel to X0 register. 83481ad6265SDimitry Andric if (Imm == RISCV::VLMaxSentinel) 83581ad6265SDimitry Andric InstrInfo.setAVLReg(RISCV::X0); 83681ad6265SDimitry Andric else 83781ad6265SDimitry Andric InstrInfo.setAVLImm(Imm); 83881ad6265SDimitry Andric } else { 83981ad6265SDimitry Andric InstrInfo.setAVLReg(VLOp.getReg()); 84081ad6265SDimitry Andric } 84181ad6265SDimitry Andric } else { 84281ad6265SDimitry Andric InstrInfo.setAVLReg(RISCV::NoRegister); 84381ad6265SDimitry Andric } 84481ad6265SDimitry Andric #ifndef NDEBUG 84581ad6265SDimitry Andric if (Optional<unsigned> EEW = getEEWForLoadStore(MI)) { 84681ad6265SDimitry Andric assert(SEW == EEW && "Initial SEW doesn't match expected EEW"); 84781ad6265SDimitry Andric } 84881ad6265SDimitry Andric #endif 84981ad6265SDimitry Andric InstrInfo.setVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic); 85081ad6265SDimitry Andric 85181ad6265SDimitry Andric return InstrInfo; 85281ad6265SDimitry Andric } 85381ad6265SDimitry Andric 85481ad6265SDimitry Andric void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB, MachineInstr &MI, 85581ad6265SDimitry Andric const VSETVLIInfo &Info, 85681ad6265SDimitry Andric const VSETVLIInfo &PrevInfo) { 85781ad6265SDimitry Andric DebugLoc DL = MI.getDebugLoc(); 85881ad6265SDimitry Andric insertVSETVLI(MBB, MachineBasicBlock::iterator(&MI), DL, Info, PrevInfo); 85981ad6265SDimitry Andric } 86081ad6265SDimitry Andric 86181ad6265SDimitry Andric void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB, 86281ad6265SDimitry Andric MachineBasicBlock::iterator InsertPt, DebugLoc DL, 86381ad6265SDimitry Andric const VSETVLIInfo &Info, const VSETVLIInfo &PrevInfo) { 86481ad6265SDimitry Andric 86581ad6265SDimitry Andric // Use X0, X0 form if the AVL is the same and the SEW+LMUL gives the same 86681ad6265SDimitry Andric // VLMAX. 86781ad6265SDimitry Andric if (PrevInfo.isValid() && !PrevInfo.isUnknown() && 86881ad6265SDimitry Andric Info.hasSameAVL(PrevInfo) && Info.hasSameVLMAX(PrevInfo)) { 86981ad6265SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0)) 87081ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 87181ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Kill) 87281ad6265SDimitry Andric .addImm(Info.encodeVTYPE()) 87381ad6265SDimitry Andric .addReg(RISCV::VL, RegState::Implicit); 87481ad6265SDimitry Andric return; 87581ad6265SDimitry Andric } 87681ad6265SDimitry Andric 87781ad6265SDimitry Andric if (Info.hasAVLImm()) { 87881ad6265SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETIVLI)) 87981ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 88081ad6265SDimitry Andric .addImm(Info.getAVLImm()) 88181ad6265SDimitry Andric .addImm(Info.encodeVTYPE()); 88281ad6265SDimitry Andric return; 88381ad6265SDimitry Andric } 88481ad6265SDimitry Andric 88581ad6265SDimitry Andric Register AVLReg = Info.getAVLReg(); 88681ad6265SDimitry Andric if (AVLReg == RISCV::NoRegister) { 88781ad6265SDimitry Andric // We can only use x0, x0 if there's no chance of the vtype change causing 88881ad6265SDimitry Andric // the previous vl to become invalid. 88981ad6265SDimitry Andric if (PrevInfo.isValid() && !PrevInfo.isUnknown() && 89081ad6265SDimitry Andric Info.hasSameVLMAX(PrevInfo)) { 89181ad6265SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0)) 89281ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 89381ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Kill) 89481ad6265SDimitry Andric .addImm(Info.encodeVTYPE()) 89581ad6265SDimitry Andric .addReg(RISCV::VL, RegState::Implicit); 89681ad6265SDimitry Andric return; 89781ad6265SDimitry Andric } 89881ad6265SDimitry Andric // Otherwise use an AVL of 0 to avoid depending on previous vl. 89981ad6265SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETIVLI)) 90081ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 90181ad6265SDimitry Andric .addImm(0) 90281ad6265SDimitry Andric .addImm(Info.encodeVTYPE()); 90381ad6265SDimitry Andric return; 90481ad6265SDimitry Andric } 90581ad6265SDimitry Andric 90681ad6265SDimitry Andric if (AVLReg.isVirtual()) 90781ad6265SDimitry Andric MRI->constrainRegClass(AVLReg, &RISCV::GPRNoX0RegClass); 90881ad6265SDimitry Andric 90981ad6265SDimitry Andric // Use X0 as the DestReg unless AVLReg is X0. We also need to change the 91081ad6265SDimitry Andric // opcode if the AVLReg is X0 as they have different register classes for 91181ad6265SDimitry Andric // the AVL operand. 91281ad6265SDimitry Andric Register DestReg = RISCV::X0; 91381ad6265SDimitry Andric unsigned Opcode = RISCV::PseudoVSETVLI; 91481ad6265SDimitry Andric if (AVLReg == RISCV::X0) { 91581ad6265SDimitry Andric DestReg = MRI->createVirtualRegister(&RISCV::GPRRegClass); 91681ad6265SDimitry Andric Opcode = RISCV::PseudoVSETVLIX0; 91781ad6265SDimitry Andric } 91881ad6265SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(Opcode)) 91981ad6265SDimitry Andric .addReg(DestReg, RegState::Define | RegState::Dead) 92081ad6265SDimitry Andric .addReg(AVLReg) 92181ad6265SDimitry Andric .addImm(Info.encodeVTYPE()); 92281ad6265SDimitry Andric } 92381ad6265SDimitry Andric 92481ad6265SDimitry Andric // Return a VSETVLIInfo representing the changes made by this VSETVLI or 92581ad6265SDimitry Andric // VSETIVLI instruction. 92681ad6265SDimitry Andric static VSETVLIInfo getInfoForVSETVLI(const MachineInstr &MI) { 92781ad6265SDimitry Andric VSETVLIInfo NewInfo; 92881ad6265SDimitry Andric if (MI.getOpcode() == RISCV::PseudoVSETIVLI) { 92981ad6265SDimitry Andric NewInfo.setAVLImm(MI.getOperand(1).getImm()); 93081ad6265SDimitry Andric } else { 93181ad6265SDimitry Andric assert(MI.getOpcode() == RISCV::PseudoVSETVLI || 93281ad6265SDimitry Andric MI.getOpcode() == RISCV::PseudoVSETVLIX0); 93381ad6265SDimitry Andric Register AVLReg = MI.getOperand(1).getReg(); 93481ad6265SDimitry Andric assert((AVLReg != RISCV::X0 || MI.getOperand(0).getReg() != RISCV::X0) && 93581ad6265SDimitry Andric "Can't handle X0, X0 vsetvli yet"); 93681ad6265SDimitry Andric NewInfo.setAVLReg(AVLReg); 93781ad6265SDimitry Andric } 93881ad6265SDimitry Andric NewInfo.setVTYPE(MI.getOperand(2).getImm()); 93981ad6265SDimitry Andric 94081ad6265SDimitry Andric return NewInfo; 94181ad6265SDimitry Andric } 94281ad6265SDimitry Andric 94381ad6265SDimitry Andric /// Return true if a VSETVLI is required to transition from CurInfo to Require 94481ad6265SDimitry Andric /// before MI. 94581ad6265SDimitry Andric bool RISCVInsertVSETVLI::needVSETVLI(const MachineInstr &MI, 94681ad6265SDimitry Andric const VSETVLIInfo &Require, 94781ad6265SDimitry Andric const VSETVLIInfo &CurInfo) const { 94881ad6265SDimitry Andric assert(Require == computeInfoForInstr(MI, MI.getDesc().TSFlags, MRI)); 94981ad6265SDimitry Andric 95081ad6265SDimitry Andric if (CurInfo.isCompatible(MI, Require)) 95181ad6265SDimitry Andric return false; 95281ad6265SDimitry Andric 95381ad6265SDimitry Andric if (!CurInfo.isValid() || CurInfo.isUnknown() || CurInfo.hasSEWLMULRatioOnly()) 95481ad6265SDimitry Andric return true; 95581ad6265SDimitry Andric 95681ad6265SDimitry Andric // For vmv.s.x and vfmv.s.f, there is only two behaviors, VL = 0 and VL > 0. 95781ad6265SDimitry Andric // VL=0 is uninteresting (as it should have been deleted already), so it is 95881ad6265SDimitry Andric // compatible if we can prove both are non-zero. Additionally, if writing 95981ad6265SDimitry Andric // to an implicit_def operand, we don't need to preserve any other bits and 96081ad6265SDimitry Andric // are thus compatible with any larger etype, and can disregard policy bits. 96181ad6265SDimitry Andric if (isScalarMoveInstr(MI) && 96281ad6265SDimitry Andric CurInfo.hasNonZeroAVL() && Require.hasNonZeroAVL()) { 96381ad6265SDimitry Andric auto *VRegDef = MRI->getVRegDef(MI.getOperand(1).getReg()); 96481ad6265SDimitry Andric if (VRegDef && VRegDef->isImplicitDef() && 96581ad6265SDimitry Andric CurInfo.getSEW() >= Require.getSEW()) 96681ad6265SDimitry Andric return false; 96781ad6265SDimitry Andric if (CurInfo.hasSameSEW(Require) && CurInfo.hasSamePolicy(Require)) 96881ad6265SDimitry Andric return false; 96981ad6265SDimitry Andric } 97081ad6265SDimitry Andric 97181ad6265SDimitry Andric // We didn't find a compatible value. If our AVL is a virtual register, 97281ad6265SDimitry Andric // it might be defined by a VSET(I)VLI. If it has the same VLMAX we need 97381ad6265SDimitry Andric // and the last VL/VTYPE we observed is the same, we don't need a 97481ad6265SDimitry Andric // VSETVLI here. 97581ad6265SDimitry Andric if (Require.hasAVLReg() && Require.getAVLReg().isVirtual() && 97681ad6265SDimitry Andric CurInfo.hasCompatibleVTYPE(MI, Require)) { 97781ad6265SDimitry Andric if (MachineInstr *DefMI = MRI->getVRegDef(Require.getAVLReg())) { 97881ad6265SDimitry Andric if (isVectorConfigInstr(*DefMI)) { 97981ad6265SDimitry Andric VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI); 98081ad6265SDimitry Andric if (DefInfo.hasSameAVL(CurInfo) && DefInfo.hasSameVLMAX(CurInfo)) 98181ad6265SDimitry Andric return false; 98281ad6265SDimitry Andric } 98381ad6265SDimitry Andric } 98481ad6265SDimitry Andric } 98581ad6265SDimitry Andric 98681ad6265SDimitry Andric return true; 98781ad6265SDimitry Andric } 98881ad6265SDimitry Andric 98981ad6265SDimitry Andric // Given an incoming state reaching MI, modifies that state so that it is minimally 99081ad6265SDimitry Andric // compatible with MI. The resulting state is guaranteed to be semantically legal 99181ad6265SDimitry Andric // for MI, but may not be the state requested by MI. 99281ad6265SDimitry Andric void RISCVInsertVSETVLI::transferBefore(VSETVLIInfo &Info, const MachineInstr &MI) { 99381ad6265SDimitry Andric uint64_t TSFlags = MI.getDesc().TSFlags; 99481ad6265SDimitry Andric if (!RISCVII::hasSEWOp(TSFlags)) 99581ad6265SDimitry Andric return; 99681ad6265SDimitry Andric 99781ad6265SDimitry Andric const VSETVLIInfo NewInfo = computeInfoForInstr(MI, TSFlags, MRI); 99881ad6265SDimitry Andric if (Info.isValid() && !needVSETVLI(MI, NewInfo, Info)) 99981ad6265SDimitry Andric return; 100081ad6265SDimitry Andric 100181ad6265SDimitry Andric const VSETVLIInfo PrevInfo = Info; 100281ad6265SDimitry Andric Info = NewInfo; 100381ad6265SDimitry Andric 100481ad6265SDimitry Andric if (!RISCVII::hasVLOp(TSFlags)) 100581ad6265SDimitry Andric return; 100681ad6265SDimitry Andric 100781ad6265SDimitry Andric // For vmv.s.x and vfmv.s.f, there are only two behaviors, VL = 0 and 100881ad6265SDimitry Andric // VL > 0. We can discard the user requested AVL and just use the last 100981ad6265SDimitry Andric // one if we can prove it equally zero. This removes a vsetvli entirely 101081ad6265SDimitry Andric // if the types match or allows use of cheaper avl preserving variant 101181ad6265SDimitry Andric // if VLMAX doesn't change. If VLMAX might change, we couldn't use 101281ad6265SDimitry Andric // the 'vsetvli x0, x0, vtype" variant, so we avoid the transform to 101381ad6265SDimitry Andric // prevent extending live range of an avl register operand. 101481ad6265SDimitry Andric // TODO: We can probably relax this for immediates. 101581ad6265SDimitry Andric if (isScalarMoveInstr(MI) && PrevInfo.isValid() && 101681ad6265SDimitry Andric PrevInfo.hasNonZeroAVL() && Info.hasNonZeroAVL() && 101781ad6265SDimitry Andric Info.hasSameVLMAX(PrevInfo)) { 101881ad6265SDimitry Andric if (PrevInfo.hasAVLImm()) 101981ad6265SDimitry Andric Info.setAVLImm(PrevInfo.getAVLImm()); 102081ad6265SDimitry Andric else 102181ad6265SDimitry Andric Info.setAVLReg(PrevInfo.getAVLReg()); 102281ad6265SDimitry Andric return; 102381ad6265SDimitry Andric } 102481ad6265SDimitry Andric 1025*61cfbce3SDimitry Andric // If AVL is defined by a vsetvli with the same VLMAX, we can 102681ad6265SDimitry Andric // replace the AVL operand with the AVL of the defining vsetvli. 102781ad6265SDimitry Andric // We avoid general register AVLs to avoid extending live ranges 102881ad6265SDimitry Andric // without being sure we can kill the original source reg entirely. 102981ad6265SDimitry Andric if (!Info.hasAVLReg() || !Info.getAVLReg().isVirtual()) 103081ad6265SDimitry Andric return; 103181ad6265SDimitry Andric MachineInstr *DefMI = MRI->getVRegDef(Info.getAVLReg()); 103281ad6265SDimitry Andric if (!DefMI || !isVectorConfigInstr(*DefMI)) 103381ad6265SDimitry Andric return; 103481ad6265SDimitry Andric 103581ad6265SDimitry Andric VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI); 103681ad6265SDimitry Andric if (DefInfo.hasSameVLMAX(Info) && 103781ad6265SDimitry Andric (DefInfo.hasAVLImm() || DefInfo.getAVLReg() == RISCV::X0)) { 103881ad6265SDimitry Andric if (DefInfo.hasAVLImm()) 103981ad6265SDimitry Andric Info.setAVLImm(DefInfo.getAVLImm()); 104081ad6265SDimitry Andric else 104181ad6265SDimitry Andric Info.setAVLReg(DefInfo.getAVLReg()); 104281ad6265SDimitry Andric return; 104381ad6265SDimitry Andric } 104481ad6265SDimitry Andric } 104581ad6265SDimitry Andric 104681ad6265SDimitry Andric // Given a state with which we evaluated MI (see transferBefore above for why 104781ad6265SDimitry Andric // this might be different that the state MI requested), modify the state to 104881ad6265SDimitry Andric // reflect the changes MI might make. 104981ad6265SDimitry Andric void RISCVInsertVSETVLI::transferAfter(VSETVLIInfo &Info, const MachineInstr &MI) { 105081ad6265SDimitry Andric if (isVectorConfigInstr(MI)) { 105181ad6265SDimitry Andric Info = getInfoForVSETVLI(MI); 105281ad6265SDimitry Andric return; 105381ad6265SDimitry Andric } 105481ad6265SDimitry Andric 105581ad6265SDimitry Andric if (RISCV::isFaultFirstLoad(MI)) { 105681ad6265SDimitry Andric // Update AVL to vl-output of the fault first load. 105781ad6265SDimitry Andric Info.setAVLReg(MI.getOperand(1).getReg()); 105881ad6265SDimitry Andric return; 105981ad6265SDimitry Andric } 106081ad6265SDimitry Andric 106181ad6265SDimitry Andric // If this is something that updates VL/VTYPE that we don't know about, set 106281ad6265SDimitry Andric // the state to unknown. 106381ad6265SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || MI.modifiesRegister(RISCV::VL) || 106481ad6265SDimitry Andric MI.modifiesRegister(RISCV::VTYPE)) 106581ad6265SDimitry Andric Info = VSETVLIInfo::getUnknown(); 1066349cc55cSDimitry Andric } 1067349cc55cSDimitry Andric 1068fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::computeVLVTYPEChanges(const MachineBasicBlock &MBB) { 1069fe6060f1SDimitry Andric bool HadVectorOp = false; 1070fe6060f1SDimitry Andric 1071fe6060f1SDimitry Andric BlockData &BBInfo = BlockInfo[MBB.getNumber()]; 107281ad6265SDimitry Andric BBInfo.Change = BBInfo.Pred; 1073fe6060f1SDimitry Andric for (const MachineInstr &MI : MBB) { 107481ad6265SDimitry Andric transferBefore(BBInfo.Change, MI); 1075fe6060f1SDimitry Andric 107681ad6265SDimitry Andric if (isVectorConfigInstr(MI) || RISCVII::hasSEWOp(MI.getDesc().TSFlags)) 1077fe6060f1SDimitry Andric HadVectorOp = true; 1078fe6060f1SDimitry Andric 107981ad6265SDimitry Andric transferAfter(BBInfo.Change, MI); 1080fe6060f1SDimitry Andric } 1081fe6060f1SDimitry Andric 1082fe6060f1SDimitry Andric return HadVectorOp; 1083fe6060f1SDimitry Andric } 1084fe6060f1SDimitry Andric 1085fe6060f1SDimitry Andric void RISCVInsertVSETVLI::computeIncomingVLVTYPE(const MachineBasicBlock &MBB) { 108681ad6265SDimitry Andric 1087fe6060f1SDimitry Andric BlockData &BBInfo = BlockInfo[MBB.getNumber()]; 1088fe6060f1SDimitry Andric 1089fe6060f1SDimitry Andric BBInfo.InQueue = false; 1090fe6060f1SDimitry Andric 1091fe6060f1SDimitry Andric VSETVLIInfo InInfo; 1092fe6060f1SDimitry Andric if (MBB.pred_empty()) { 1093fe6060f1SDimitry Andric // There are no predecessors, so use the default starting status. 1094fe6060f1SDimitry Andric InInfo.setUnknown(); 1095fe6060f1SDimitry Andric } else { 1096fe6060f1SDimitry Andric for (MachineBasicBlock *P : MBB.predecessors()) 1097fe6060f1SDimitry Andric InInfo = InInfo.intersect(BlockInfo[P->getNumber()].Exit); 1098fe6060f1SDimitry Andric } 1099fe6060f1SDimitry Andric 1100fe6060f1SDimitry Andric // If we don't have any valid predecessor value, wait until we do. 1101fe6060f1SDimitry Andric if (!InInfo.isValid()) 1102fe6060f1SDimitry Andric return; 1103fe6060f1SDimitry Andric 110481ad6265SDimitry Andric // If no change, no need to rerun block 110581ad6265SDimitry Andric if (InInfo == BBInfo.Pred) 110681ad6265SDimitry Andric return; 1107fe6060f1SDimitry Andric 110881ad6265SDimitry Andric BBInfo.Pred = InInfo; 110981ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Entry state of " << printMBBReference(MBB) 111081ad6265SDimitry Andric << " changed to " << BBInfo.Pred << "\n"); 111181ad6265SDimitry Andric 111281ad6265SDimitry Andric // Note: It's tempting to cache the state changes here, but due to the 111381ad6265SDimitry Andric // compatibility checks performed a blocks output state can change based on 111481ad6265SDimitry Andric // the input state. To cache, we'd have to add logic for finding 111581ad6265SDimitry Andric // never-compatible state changes. 111681ad6265SDimitry Andric computeVLVTYPEChanges(MBB); 111781ad6265SDimitry Andric VSETVLIInfo TmpStatus = BBInfo.Change; 1118fe6060f1SDimitry Andric 1119fe6060f1SDimitry Andric // If the new exit value matches the old exit value, we don't need to revisit 1120fe6060f1SDimitry Andric // any blocks. 1121fe6060f1SDimitry Andric if (BBInfo.Exit == TmpStatus) 1122fe6060f1SDimitry Andric return; 1123fe6060f1SDimitry Andric 1124fe6060f1SDimitry Andric BBInfo.Exit = TmpStatus; 112581ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Exit state of " << printMBBReference(MBB) 112681ad6265SDimitry Andric << " changed to " << BBInfo.Exit << "\n"); 1127fe6060f1SDimitry Andric 1128fe6060f1SDimitry Andric // Add the successors to the work list so we can propagate the changed exit 1129fe6060f1SDimitry Andric // status. 1130fe6060f1SDimitry Andric for (MachineBasicBlock *S : MBB.successors()) 1131fe6060f1SDimitry Andric if (!BlockInfo[S->getNumber()].InQueue) 1132fe6060f1SDimitry Andric WorkList.push(S); 1133fe6060f1SDimitry Andric } 1134fe6060f1SDimitry Andric 1135fe6060f1SDimitry Andric // If we weren't able to prove a vsetvli was directly unneeded, it might still 113681ad6265SDimitry Andric // be unneeded if the AVL is a phi node where all incoming values are VL 1137fe6060f1SDimitry Andric // outputs from the last VSETVLI in their respective basic blocks. 1138fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::needVSETVLIPHI(const VSETVLIInfo &Require, 113981ad6265SDimitry Andric const MachineBasicBlock &MBB) const { 1140fe6060f1SDimitry Andric if (DisableInsertVSETVLPHIOpt) 1141fe6060f1SDimitry Andric return true; 1142fe6060f1SDimitry Andric 1143fe6060f1SDimitry Andric if (!Require.hasAVLReg()) 1144fe6060f1SDimitry Andric return true; 1145fe6060f1SDimitry Andric 1146fe6060f1SDimitry Andric Register AVLReg = Require.getAVLReg(); 1147fe6060f1SDimitry Andric if (!AVLReg.isVirtual()) 1148fe6060f1SDimitry Andric return true; 1149fe6060f1SDimitry Andric 1150fe6060f1SDimitry Andric // We need the AVL to be produce by a PHI node in this basic block. 1151fe6060f1SDimitry Andric MachineInstr *PHI = MRI->getVRegDef(AVLReg); 1152fe6060f1SDimitry Andric if (!PHI || PHI->getOpcode() != RISCV::PHI || PHI->getParent() != &MBB) 1153fe6060f1SDimitry Andric return true; 1154fe6060f1SDimitry Andric 1155fe6060f1SDimitry Andric for (unsigned PHIOp = 1, NumOps = PHI->getNumOperands(); PHIOp != NumOps; 1156fe6060f1SDimitry Andric PHIOp += 2) { 1157fe6060f1SDimitry Andric Register InReg = PHI->getOperand(PHIOp).getReg(); 1158fe6060f1SDimitry Andric MachineBasicBlock *PBB = PHI->getOperand(PHIOp + 1).getMBB(); 1159fe6060f1SDimitry Andric const BlockData &PBBInfo = BlockInfo[PBB->getNumber()]; 1160fe6060f1SDimitry Andric // If the exit from the predecessor has the VTYPE we are looking for 1161fe6060f1SDimitry Andric // we might be able to avoid a VSETVLI. 116281ad6265SDimitry Andric if (PBBInfo.Exit.isUnknown() || !PBBInfo.Exit.hasSameVTYPE(Require)) 1163fe6060f1SDimitry Andric return true; 1164fe6060f1SDimitry Andric 1165fe6060f1SDimitry Andric // We need the PHI input to the be the output of a VSET(I)VLI. 1166fe6060f1SDimitry Andric MachineInstr *DefMI = MRI->getVRegDef(InReg); 116781ad6265SDimitry Andric if (!DefMI || !isVectorConfigInstr(*DefMI)) 1168fe6060f1SDimitry Andric return true; 1169fe6060f1SDimitry Andric 1170fe6060f1SDimitry Andric // We found a VSET(I)VLI make sure it matches the output of the 1171fe6060f1SDimitry Andric // predecessor block. 1172fe6060f1SDimitry Andric VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI); 1173fe6060f1SDimitry Andric if (!DefInfo.hasSameAVL(PBBInfo.Exit) || 1174fe6060f1SDimitry Andric !DefInfo.hasSameVTYPE(PBBInfo.Exit)) 1175fe6060f1SDimitry Andric return true; 1176fe6060f1SDimitry Andric } 1177fe6060f1SDimitry Andric 1178fe6060f1SDimitry Andric // If all the incoming values to the PHI checked out, we don't need 1179fe6060f1SDimitry Andric // to insert a VSETVLI. 1180fe6060f1SDimitry Andric return false; 1181fe6060f1SDimitry Andric } 1182fe6060f1SDimitry Andric 1183fe6060f1SDimitry Andric void RISCVInsertVSETVLI::emitVSETVLIs(MachineBasicBlock &MBB) { 118481ad6265SDimitry Andric VSETVLIInfo CurInfo = BlockInfo[MBB.getNumber()].Pred; 118581ad6265SDimitry Andric // Track whether the prefix of the block we've scanned is transparent 118681ad6265SDimitry Andric // (meaning has not yet changed the abstract state). 118781ad6265SDimitry Andric bool PrefixTransparent = true; 1188fe6060f1SDimitry Andric for (MachineInstr &MI : MBB) { 118981ad6265SDimitry Andric const VSETVLIInfo PrevInfo = CurInfo; 119081ad6265SDimitry Andric transferBefore(CurInfo, MI); 119181ad6265SDimitry Andric 1192fe6060f1SDimitry Andric // If this is an explicit VSETVLI or VSETIVLI, update our state. 119381ad6265SDimitry Andric if (isVectorConfigInstr(MI)) { 1194fe6060f1SDimitry Andric // Conservatively, mark the VL and VTYPE as live. 1195fe6060f1SDimitry Andric assert(MI.getOperand(3).getReg() == RISCV::VL && 1196fe6060f1SDimitry Andric MI.getOperand(4).getReg() == RISCV::VTYPE && 1197fe6060f1SDimitry Andric "Unexpected operands where VL and VTYPE should be"); 1198fe6060f1SDimitry Andric MI.getOperand(3).setIsDead(false); 1199fe6060f1SDimitry Andric MI.getOperand(4).setIsDead(false); 120081ad6265SDimitry Andric PrefixTransparent = false; 1201fe6060f1SDimitry Andric } 1202fe6060f1SDimitry Andric 1203fe6060f1SDimitry Andric uint64_t TSFlags = MI.getDesc().TSFlags; 1204fe6060f1SDimitry Andric if (RISCVII::hasSEWOp(TSFlags)) { 120581ad6265SDimitry Andric if (PrevInfo != CurInfo) { 120681ad6265SDimitry Andric // If this is the first implicit state change, and the state change 120781ad6265SDimitry Andric // requested can be proven to produce the same register contents, we 120881ad6265SDimitry Andric // can skip emitting the actual state change and continue as if we 120981ad6265SDimitry Andric // had since we know the GPR result of the implicit state change 121081ad6265SDimitry Andric // wouldn't be used and VL/VTYPE registers are correct. Note that 121181ad6265SDimitry Andric // we *do* need to model the state as if it changed as while the 121281ad6265SDimitry Andric // register contents are unchanged, the abstract model can change. 121381ad6265SDimitry Andric if (!PrefixTransparent || needVSETVLIPHI(CurInfo, MBB)) 121481ad6265SDimitry Andric insertVSETVLI(MBB, MI, CurInfo, PrevInfo); 121581ad6265SDimitry Andric PrefixTransparent = false; 121681ad6265SDimitry Andric } 121781ad6265SDimitry Andric 1218fe6060f1SDimitry Andric if (RISCVII::hasVLOp(TSFlags)) { 121981ad6265SDimitry Andric MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI)); 1220fe6060f1SDimitry Andric if (VLOp.isReg()) { 1221fe6060f1SDimitry Andric // Erase the AVL operand from the instruction. 1222fe6060f1SDimitry Andric VLOp.setReg(RISCV::NoRegister); 1223fe6060f1SDimitry Andric VLOp.setIsKill(false); 1224fe6060f1SDimitry Andric } 1225fe6060f1SDimitry Andric MI.addOperand(MachineOperand::CreateReg(RISCV::VL, /*isDef*/ false, 1226fe6060f1SDimitry Andric /*isImp*/ true)); 1227fe6060f1SDimitry Andric } 1228fe6060f1SDimitry Andric MI.addOperand(MachineOperand::CreateReg(RISCV::VTYPE, /*isDef*/ false, 1229fe6060f1SDimitry Andric /*isImp*/ true)); 1230fe6060f1SDimitry Andric } 1231fe6060f1SDimitry Andric 1232fe6060f1SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || MI.modifiesRegister(RISCV::VL) || 123381ad6265SDimitry Andric MI.modifiesRegister(RISCV::VTYPE)) 123481ad6265SDimitry Andric PrefixTransparent = false; 123581ad6265SDimitry Andric 123681ad6265SDimitry Andric transferAfter(CurInfo, MI); 1237fe6060f1SDimitry Andric } 1238d56accc7SDimitry Andric 1239d56accc7SDimitry Andric // If we reach the end of the block and our current info doesn't match the 1240d56accc7SDimitry Andric // expected info, insert a vsetvli to correct. 124181ad6265SDimitry Andric if (!UseStrictAsserts) { 1242d56accc7SDimitry Andric const VSETVLIInfo &ExitInfo = BlockInfo[MBB.getNumber()].Exit; 1243d56accc7SDimitry Andric if (CurInfo.isValid() && ExitInfo.isValid() && !ExitInfo.isUnknown() && 1244d56accc7SDimitry Andric CurInfo != ExitInfo) { 124581ad6265SDimitry Andric // Note there's an implicit assumption here that terminators never use 124681ad6265SDimitry Andric // or modify VL or VTYPE. Also, fallthrough will return end(). 124781ad6265SDimitry Andric auto InsertPt = MBB.getFirstInstrTerminator(); 124881ad6265SDimitry Andric insertVSETVLI(MBB, InsertPt, MBB.findDebugLoc(InsertPt), ExitInfo, 124981ad6265SDimitry Andric CurInfo); 1250d56accc7SDimitry Andric CurInfo = ExitInfo; 1251d56accc7SDimitry Andric } 1252d56accc7SDimitry Andric } 125381ad6265SDimitry Andric 125481ad6265SDimitry Andric if (UseStrictAsserts && CurInfo.isValid()) { 125581ad6265SDimitry Andric const auto &Info = BlockInfo[MBB.getNumber()]; 125681ad6265SDimitry Andric if (CurInfo != Info.Exit) { 125781ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "in block " << printMBBReference(MBB) << "\n"); 125881ad6265SDimitry Andric LLVM_DEBUG(dbgs() << " begin state: " << Info.Pred << "\n"); 125981ad6265SDimitry Andric LLVM_DEBUG(dbgs() << " expected end state: " << Info.Exit << "\n"); 126081ad6265SDimitry Andric LLVM_DEBUG(dbgs() << " actual end state: " << CurInfo << "\n"); 126181ad6265SDimitry Andric } 126281ad6265SDimitry Andric assert(CurInfo == Info.Exit && 126381ad6265SDimitry Andric "InsertVSETVLI dataflow invariant violated"); 126481ad6265SDimitry Andric } 126581ad6265SDimitry Andric } 126681ad6265SDimitry Andric 126781ad6265SDimitry Andric /// Return true if the VL value configured must be equal to the requested one. 126881ad6265SDimitry Andric static bool hasFixedResult(const VSETVLIInfo &Info, const RISCVSubtarget &ST) { 126981ad6265SDimitry Andric if (!Info.hasAVLImm()) 127081ad6265SDimitry Andric // VLMAX is always the same value. 127181ad6265SDimitry Andric // TODO: Could extend to other registers by looking at the associated vreg 127281ad6265SDimitry Andric // def placement. 127381ad6265SDimitry Andric return RISCV::X0 == Info.getAVLReg(); 127481ad6265SDimitry Andric 127581ad6265SDimitry Andric unsigned AVL = Info.getAVLImm(); 127681ad6265SDimitry Andric unsigned SEW = Info.getSEW(); 127781ad6265SDimitry Andric unsigned AVLInBits = AVL * SEW; 127881ad6265SDimitry Andric 127981ad6265SDimitry Andric unsigned LMul; 128081ad6265SDimitry Andric bool Fractional; 128181ad6265SDimitry Andric std::tie(LMul, Fractional) = RISCVVType::decodeVLMUL(Info.getVLMUL()); 128281ad6265SDimitry Andric 128381ad6265SDimitry Andric if (Fractional) 128481ad6265SDimitry Andric return ST.getRealMinVLen() / LMul >= AVLInBits; 128581ad6265SDimitry Andric return ST.getRealMinVLen() * LMul >= AVLInBits; 128681ad6265SDimitry Andric } 128781ad6265SDimitry Andric 128881ad6265SDimitry Andric /// Perform simple partial redundancy elimination of the VSETVLI instructions 128981ad6265SDimitry Andric /// we're about to insert by looking for cases where we can PRE from the 129081ad6265SDimitry Andric /// beginning of one block to the end of one of its predecessors. Specifically, 129181ad6265SDimitry Andric /// this is geared to catch the common case of a fixed length vsetvl in a single 129281ad6265SDimitry Andric /// block loop when it could execute once in the preheader instead. 129381ad6265SDimitry Andric void RISCVInsertVSETVLI::doPRE(MachineBasicBlock &MBB) { 129481ad6265SDimitry Andric const MachineFunction &MF = *MBB.getParent(); 129581ad6265SDimitry Andric const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>(); 129681ad6265SDimitry Andric 129781ad6265SDimitry Andric if (!BlockInfo[MBB.getNumber()].Pred.isUnknown()) 129881ad6265SDimitry Andric return; 129981ad6265SDimitry Andric 130081ad6265SDimitry Andric MachineBasicBlock *UnavailablePred = nullptr; 130181ad6265SDimitry Andric VSETVLIInfo AvailableInfo; 130281ad6265SDimitry Andric for (MachineBasicBlock *P : MBB.predecessors()) { 130381ad6265SDimitry Andric const VSETVLIInfo &PredInfo = BlockInfo[P->getNumber()].Exit; 130481ad6265SDimitry Andric if (PredInfo.isUnknown()) { 130581ad6265SDimitry Andric if (UnavailablePred) 130681ad6265SDimitry Andric return; 130781ad6265SDimitry Andric UnavailablePred = P; 130881ad6265SDimitry Andric } else if (!AvailableInfo.isValid()) { 130981ad6265SDimitry Andric AvailableInfo = PredInfo; 131081ad6265SDimitry Andric } else if (AvailableInfo != PredInfo) { 131181ad6265SDimitry Andric return; 131281ad6265SDimitry Andric } 131381ad6265SDimitry Andric } 131481ad6265SDimitry Andric 131581ad6265SDimitry Andric // Unreachable, single pred, or full redundancy. Note that FRE is handled by 131681ad6265SDimitry Andric // phase 3. 131781ad6265SDimitry Andric if (!UnavailablePred || !AvailableInfo.isValid()) 131881ad6265SDimitry Andric return; 131981ad6265SDimitry Andric 132081ad6265SDimitry Andric // Critical edge - TODO: consider splitting? 132181ad6265SDimitry Andric if (UnavailablePred->succ_size() != 1) 132281ad6265SDimitry Andric return; 132381ad6265SDimitry Andric 132481ad6265SDimitry Andric // If VL can be less than AVL, then we can't reduce the frequency of exec. 132581ad6265SDimitry Andric if (!hasFixedResult(AvailableInfo, ST)) 132681ad6265SDimitry Andric return; 132781ad6265SDimitry Andric 132881ad6265SDimitry Andric // Does it actually let us remove an implicit transition in MBB? 132981ad6265SDimitry Andric bool Found = false; 133081ad6265SDimitry Andric for (auto &MI : MBB) { 133181ad6265SDimitry Andric if (isVectorConfigInstr(MI)) 133281ad6265SDimitry Andric return; 133381ad6265SDimitry Andric 133481ad6265SDimitry Andric const uint64_t TSFlags = MI.getDesc().TSFlags; 133581ad6265SDimitry Andric if (RISCVII::hasSEWOp(TSFlags)) { 133681ad6265SDimitry Andric if (AvailableInfo != computeInfoForInstr(MI, TSFlags, MRI)) 133781ad6265SDimitry Andric return; 133881ad6265SDimitry Andric Found = true; 133981ad6265SDimitry Andric break; 134081ad6265SDimitry Andric } 134181ad6265SDimitry Andric } 134281ad6265SDimitry Andric if (!Found) 134381ad6265SDimitry Andric return; 134481ad6265SDimitry Andric 134581ad6265SDimitry Andric // Finally, update both data flow state and insert the actual vsetvli. 134681ad6265SDimitry Andric // Doing both keeps the code in sync with the dataflow results, which 134781ad6265SDimitry Andric // is critical for correctness of phase 3. 134881ad6265SDimitry Andric auto OldInfo = BlockInfo[UnavailablePred->getNumber()].Exit; 134981ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "PRE VSETVLI from " << MBB.getName() << " to " 135081ad6265SDimitry Andric << UnavailablePred->getName() << " with state " 135181ad6265SDimitry Andric << AvailableInfo << "\n"); 135281ad6265SDimitry Andric BlockInfo[UnavailablePred->getNumber()].Exit = AvailableInfo; 135381ad6265SDimitry Andric BlockInfo[MBB.getNumber()].Pred = AvailableInfo; 135481ad6265SDimitry Andric 135581ad6265SDimitry Andric // Note there's an implicit assumption here that terminators never use 135681ad6265SDimitry Andric // or modify VL or VTYPE. Also, fallthrough will return end(). 135781ad6265SDimitry Andric auto InsertPt = UnavailablePred->getFirstInstrTerminator(); 135881ad6265SDimitry Andric insertVSETVLI(*UnavailablePred, InsertPt, 135981ad6265SDimitry Andric UnavailablePred->findDebugLoc(InsertPt), 136081ad6265SDimitry Andric AvailableInfo, OldInfo); 136181ad6265SDimitry Andric } 136281ad6265SDimitry Andric 136381ad6265SDimitry Andric static void doUnion(DemandedFields &A, DemandedFields B) { 136481ad6265SDimitry Andric A.VL |= B.VL; 136581ad6265SDimitry Andric A.SEW |= B.SEW; 136681ad6265SDimitry Andric A.LMUL |= B.LMUL; 136781ad6265SDimitry Andric A.SEWLMULRatio |= B.SEWLMULRatio; 136881ad6265SDimitry Andric A.TailPolicy |= B.TailPolicy; 136981ad6265SDimitry Andric A.MaskPolicy |= B.MaskPolicy; 137081ad6265SDimitry Andric } 137181ad6265SDimitry Andric 137281ad6265SDimitry Andric // Return true if we can mutate PrevMI's VTYPE to match MI's 137381ad6265SDimitry Andric // without changing any the fields which have been used. 137481ad6265SDimitry Andric // TODO: Restructure code to allow code reuse between this and isCompatible 137581ad6265SDimitry Andric // above. 137681ad6265SDimitry Andric static bool canMutatePriorConfig(const MachineInstr &PrevMI, 137781ad6265SDimitry Andric const MachineInstr &MI, 137881ad6265SDimitry Andric const DemandedFields &Used) { 137981ad6265SDimitry Andric // TODO: Extend this to handle cases where VL does change, but VL 138081ad6265SDimitry Andric // has not been used. (e.g. over a vmv.x.s) 138181ad6265SDimitry Andric if (!isVLPreservingConfig(MI)) 138281ad6265SDimitry Andric // Note: `vsetvli x0, x0, vtype' is the canonical instruction 138381ad6265SDimitry Andric // for this case. If you find yourself wanting to add other forms 138481ad6265SDimitry Andric // to this "unused VTYPE" case, we're probably missing a 138581ad6265SDimitry Andric // canonicalization earlier. 138681ad6265SDimitry Andric return false; 138781ad6265SDimitry Andric 138881ad6265SDimitry Andric if (!PrevMI.getOperand(2).isImm() || !MI.getOperand(2).isImm()) 138981ad6265SDimitry Andric return false; 139081ad6265SDimitry Andric 139181ad6265SDimitry Andric auto PriorVType = PrevMI.getOperand(2).getImm(); 139281ad6265SDimitry Andric auto VType = MI.getOperand(2).getImm(); 139381ad6265SDimitry Andric return areCompatibleVTYPEs(PriorVType, VType, Used); 139481ad6265SDimitry Andric } 139581ad6265SDimitry Andric 139681ad6265SDimitry Andric void RISCVInsertVSETVLI::doLocalPostpass(MachineBasicBlock &MBB) { 139781ad6265SDimitry Andric MachineInstr *PrevMI = nullptr; 139881ad6265SDimitry Andric DemandedFields Used; 139981ad6265SDimitry Andric SmallVector<MachineInstr*> ToDelete; 140081ad6265SDimitry Andric for (MachineInstr &MI : MBB) { 140181ad6265SDimitry Andric // Note: Must be *before* vsetvli handling to account for config cases 140281ad6265SDimitry Andric // which only change some subfields. 140381ad6265SDimitry Andric doUnion(Used, getDemanded(MI)); 140481ad6265SDimitry Andric 140581ad6265SDimitry Andric if (!isVectorConfigInstr(MI)) 140681ad6265SDimitry Andric continue; 140781ad6265SDimitry Andric 140881ad6265SDimitry Andric if (PrevMI) { 140981ad6265SDimitry Andric if (!Used.VL && !Used.usedVTYPE()) { 141081ad6265SDimitry Andric ToDelete.push_back(PrevMI); 141181ad6265SDimitry Andric // fallthrough 141281ad6265SDimitry Andric } else if (canMutatePriorConfig(*PrevMI, MI, Used)) { 141381ad6265SDimitry Andric PrevMI->getOperand(2).setImm(MI.getOperand(2).getImm()); 141481ad6265SDimitry Andric ToDelete.push_back(&MI); 141581ad6265SDimitry Andric // Leave PrevMI unchanged 141681ad6265SDimitry Andric continue; 141781ad6265SDimitry Andric } 141881ad6265SDimitry Andric } 141981ad6265SDimitry Andric PrevMI = &MI; 142081ad6265SDimitry Andric Used = getDemanded(MI); 142181ad6265SDimitry Andric Register VRegDef = MI.getOperand(0).getReg(); 142281ad6265SDimitry Andric if (VRegDef != RISCV::X0 && 142381ad6265SDimitry Andric !(VRegDef.isVirtual() && MRI->use_nodbg_empty(VRegDef))) 142481ad6265SDimitry Andric Used.VL = true; 142581ad6265SDimitry Andric } 142681ad6265SDimitry Andric 142781ad6265SDimitry Andric for (auto *MI : ToDelete) 142881ad6265SDimitry Andric MI->eraseFromParent(); 142981ad6265SDimitry Andric } 143081ad6265SDimitry Andric 143181ad6265SDimitry Andric void RISCVInsertVSETVLI::insertReadVL(MachineBasicBlock &MBB) { 143281ad6265SDimitry Andric for (auto I = MBB.begin(), E = MBB.end(); I != E;) { 143381ad6265SDimitry Andric MachineInstr &MI = *I++; 143481ad6265SDimitry Andric if (RISCV::isFaultFirstLoad(MI)) { 143581ad6265SDimitry Andric Register VLOutput = MI.getOperand(1).getReg(); 143681ad6265SDimitry Andric if (!MRI->use_nodbg_empty(VLOutput)) 143781ad6265SDimitry Andric BuildMI(MBB, I, MI.getDebugLoc(), TII->get(RISCV::PseudoReadVL), 143881ad6265SDimitry Andric VLOutput); 143981ad6265SDimitry Andric // We don't use the vl output of the VLEFF/VLSEGFF anymore. 144081ad6265SDimitry Andric MI.getOperand(1).setReg(RISCV::X0); 144181ad6265SDimitry Andric } 1442fe6060f1SDimitry Andric } 1443fe6060f1SDimitry Andric } 1444fe6060f1SDimitry Andric 1445fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::runOnMachineFunction(MachineFunction &MF) { 1446fe6060f1SDimitry Andric // Skip if the vector extension is not enabled. 1447fe6060f1SDimitry Andric const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>(); 1448349cc55cSDimitry Andric if (!ST.hasVInstructions()) 1449fe6060f1SDimitry Andric return false; 1450fe6060f1SDimitry Andric 145181ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Entering InsertVSETVLI for " << MF.getName() << "\n"); 145281ad6265SDimitry Andric 1453fe6060f1SDimitry Andric TII = ST.getInstrInfo(); 1454fe6060f1SDimitry Andric MRI = &MF.getRegInfo(); 1455fe6060f1SDimitry Andric 1456fe6060f1SDimitry Andric assert(BlockInfo.empty() && "Expect empty block infos"); 1457fe6060f1SDimitry Andric BlockInfo.resize(MF.getNumBlockIDs()); 1458fe6060f1SDimitry Andric 1459fe6060f1SDimitry Andric bool HaveVectorOp = false; 1460fe6060f1SDimitry Andric 1461fe6060f1SDimitry Andric // Phase 1 - determine how VL/VTYPE are affected by the each block. 146281ad6265SDimitry Andric for (const MachineBasicBlock &MBB : MF) { 1463fe6060f1SDimitry Andric HaveVectorOp |= computeVLVTYPEChanges(MBB); 146481ad6265SDimitry Andric // Initial exit state is whatever change we found in the block. 146581ad6265SDimitry Andric BlockData &BBInfo = BlockInfo[MBB.getNumber()]; 146681ad6265SDimitry Andric BBInfo.Exit = BBInfo.Change; 146781ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Initial exit state of " << printMBBReference(MBB) 146881ad6265SDimitry Andric << " is " << BBInfo.Exit << "\n"); 146981ad6265SDimitry Andric 147081ad6265SDimitry Andric } 1471fe6060f1SDimitry Andric 1472fe6060f1SDimitry Andric // If we didn't find any instructions that need VSETVLI, we're done. 147381ad6265SDimitry Andric if (!HaveVectorOp) { 147481ad6265SDimitry Andric BlockInfo.clear(); 147581ad6265SDimitry Andric return false; 147681ad6265SDimitry Andric } 147781ad6265SDimitry Andric 1478fe6060f1SDimitry Andric // Phase 2 - determine the exit VL/VTYPE from each block. We add all 1479fe6060f1SDimitry Andric // blocks to the list here, but will also add any that need to be revisited 1480fe6060f1SDimitry Andric // during Phase 2 processing. 1481fe6060f1SDimitry Andric for (const MachineBasicBlock &MBB : MF) { 1482fe6060f1SDimitry Andric WorkList.push(&MBB); 1483fe6060f1SDimitry Andric BlockInfo[MBB.getNumber()].InQueue = true; 1484fe6060f1SDimitry Andric } 1485fe6060f1SDimitry Andric while (!WorkList.empty()) { 1486fe6060f1SDimitry Andric const MachineBasicBlock &MBB = *WorkList.front(); 1487fe6060f1SDimitry Andric WorkList.pop(); 1488fe6060f1SDimitry Andric computeIncomingVLVTYPE(MBB); 1489fe6060f1SDimitry Andric } 1490fe6060f1SDimitry Andric 149181ad6265SDimitry Andric // Perform partial redundancy elimination of vsetvli transitions. 149281ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) 149381ad6265SDimitry Andric doPRE(MBB); 149481ad6265SDimitry Andric 1495fe6060f1SDimitry Andric // Phase 3 - add any vsetvli instructions needed in the block. Use the 1496fe6060f1SDimitry Andric // Phase 2 information to avoid adding vsetvlis before the first vector 1497fe6060f1SDimitry Andric // instruction in the block if the VL/VTYPE is satisfied by its 1498fe6060f1SDimitry Andric // predecessors. 1499fe6060f1SDimitry Andric for (MachineBasicBlock &MBB : MF) 1500fe6060f1SDimitry Andric emitVSETVLIs(MBB); 150181ad6265SDimitry Andric 150281ad6265SDimitry Andric // Now that all vsetvlis are explicit, go through and do block local 150381ad6265SDimitry Andric // DSE and peephole based demanded fields based transforms. Note that 150481ad6265SDimitry Andric // this *must* be done outside the main dataflow so long as we allow 150581ad6265SDimitry Andric // any cross block analysis within the dataflow. We can't have both 150681ad6265SDimitry Andric // demanded fields based mutation and non-local analysis in the 150781ad6265SDimitry Andric // dataflow at the same time without introducing inconsistencies. 150881ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) 150981ad6265SDimitry Andric doLocalPostpass(MBB); 151081ad6265SDimitry Andric 151181ad6265SDimitry Andric // Once we're fully done rewriting all the instructions, do a final pass 151281ad6265SDimitry Andric // through to check for VSETVLIs which write to an unused destination. 151381ad6265SDimitry Andric // For the non X0, X0 variant, we can replace the destination register 151481ad6265SDimitry Andric // with X0 to reduce register pressure. This is really a generic 151581ad6265SDimitry Andric // optimization which can be applied to any dead def (TODO: generalize). 151681ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) { 151781ad6265SDimitry Andric for (MachineInstr &MI : MBB) { 151881ad6265SDimitry Andric if (MI.getOpcode() == RISCV::PseudoVSETVLI || 151981ad6265SDimitry Andric MI.getOpcode() == RISCV::PseudoVSETIVLI) { 152081ad6265SDimitry Andric Register VRegDef = MI.getOperand(0).getReg(); 152181ad6265SDimitry Andric if (VRegDef != RISCV::X0 && MRI->use_nodbg_empty(VRegDef)) 152281ad6265SDimitry Andric MI.getOperand(0).setReg(RISCV::X0); 152381ad6265SDimitry Andric } 152481ad6265SDimitry Andric } 1525fe6060f1SDimitry Andric } 1526fe6060f1SDimitry Andric 152781ad6265SDimitry Andric // Insert PseudoReadVL after VLEFF/VLSEGFF and replace it with the vl output 152881ad6265SDimitry Andric // of VLEFF/VLSEGFF. 152981ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) 153081ad6265SDimitry Andric insertReadVL(MBB); 1531fe6060f1SDimitry Andric 153281ad6265SDimitry Andric BlockInfo.clear(); 1533fe6060f1SDimitry Andric return HaveVectorOp; 1534fe6060f1SDimitry Andric } 1535fe6060f1SDimitry Andric 1536fe6060f1SDimitry Andric /// Returns an instance of the Insert VSETVLI pass. 1537fe6060f1SDimitry Andric FunctionPass *llvm::createRISCVInsertVSETVLIPass() { 1538fe6060f1SDimitry Andric return new RISCVInsertVSETVLI(); 1539fe6060f1SDimitry Andric } 1540