1*5f757f3fSDimitry Andric //===-- RISCVInsertWriteVXRM.cpp - Insert Write of RISC-V VXRM CSR --------===// 2*5f757f3fSDimitry Andric // 3*5f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*5f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*5f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*5f757f3fSDimitry Andric // 7*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 8*5f757f3fSDimitry Andric // 9*5f757f3fSDimitry Andric // This pass inserts writes to the VXRM CSR as needed by vector instructions. 10*5f757f3fSDimitry Andric // Each instruction that uses VXRM carries an operand that contains its required 11*5f757f3fSDimitry Andric // VXRM value. This pass tries to optimize placement to avoid redundant writes 12*5f757f3fSDimitry Andric // to VXRM. 13*5f757f3fSDimitry Andric // 14*5f757f3fSDimitry Andric // This is done using 2 dataflow algorithms. The first is a forward data flow 15*5f757f3fSDimitry Andric // to calculate where a VXRM value is available. The second is a backwards 16*5f757f3fSDimitry Andric // dataflow to determine where a VXRM value is anticipated. 17*5f757f3fSDimitry Andric // 18*5f757f3fSDimitry Andric // Finally, we use the results of these two dataflows to insert VXRM writes 19*5f757f3fSDimitry Andric // where a value is anticipated, but not available. 20*5f757f3fSDimitry Andric // 21*5f757f3fSDimitry Andric // FIXME: This pass does not split critical edges, so there can still be some 22*5f757f3fSDimitry Andric // redundancy. 23*5f757f3fSDimitry Andric // 24*5f757f3fSDimitry Andric // FIXME: If we are willing to have writes that aren't always needed, we could 25*5f757f3fSDimitry Andric // reduce the number of VXRM writes in some cases. 26*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 27*5f757f3fSDimitry Andric 28*5f757f3fSDimitry Andric #include "MCTargetDesc/RISCVBaseInfo.h" 29*5f757f3fSDimitry Andric #include "RISCV.h" 30*5f757f3fSDimitry Andric #include "RISCVSubtarget.h" 31*5f757f3fSDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 32*5f757f3fSDimitry Andric #include <queue> 33*5f757f3fSDimitry Andric 34*5f757f3fSDimitry Andric using namespace llvm; 35*5f757f3fSDimitry Andric 36*5f757f3fSDimitry Andric #define DEBUG_TYPE "riscv-insert-write-vxrm" 37*5f757f3fSDimitry Andric #define RISCV_INSERT_WRITE_VXRM_NAME "RISC-V Insert Write VXRM Pass" 38*5f757f3fSDimitry Andric 39*5f757f3fSDimitry Andric namespace { 40*5f757f3fSDimitry Andric 41*5f757f3fSDimitry Andric class VXRMInfo { 42*5f757f3fSDimitry Andric uint8_t VXRMImm = 0; 43*5f757f3fSDimitry Andric 44*5f757f3fSDimitry Andric enum : uint8_t { 45*5f757f3fSDimitry Andric Uninitialized, 46*5f757f3fSDimitry Andric Static, 47*5f757f3fSDimitry Andric Unknown, 48*5f757f3fSDimitry Andric } State = Uninitialized; 49*5f757f3fSDimitry Andric 50*5f757f3fSDimitry Andric public: 51*5f757f3fSDimitry Andric VXRMInfo() {} 52*5f757f3fSDimitry Andric 53*5f757f3fSDimitry Andric static VXRMInfo getUnknown() { 54*5f757f3fSDimitry Andric VXRMInfo Info; 55*5f757f3fSDimitry Andric Info.setUnknown(); 56*5f757f3fSDimitry Andric return Info; 57*5f757f3fSDimitry Andric } 58*5f757f3fSDimitry Andric 59*5f757f3fSDimitry Andric bool isValid() const { return State != Uninitialized; } 60*5f757f3fSDimitry Andric void setUnknown() { State = Unknown; } 61*5f757f3fSDimitry Andric bool isUnknown() const { return State == Unknown; } 62*5f757f3fSDimitry Andric 63*5f757f3fSDimitry Andric bool isStatic() const { return State == Static; } 64*5f757f3fSDimitry Andric 65*5f757f3fSDimitry Andric void setVXRMImm(unsigned Imm) { 66*5f757f3fSDimitry Andric assert(Imm <= 3 && "Unexpected VXRM value"); 67*5f757f3fSDimitry Andric VXRMImm = Imm; 68*5f757f3fSDimitry Andric State = Static; 69*5f757f3fSDimitry Andric } 70*5f757f3fSDimitry Andric unsigned getVXRMImm() const { 71*5f757f3fSDimitry Andric assert(isStatic() && VXRMImm <= 3 && "Unexpected state"); 72*5f757f3fSDimitry Andric return VXRMImm; 73*5f757f3fSDimitry Andric } 74*5f757f3fSDimitry Andric 75*5f757f3fSDimitry Andric bool operator==(const VXRMInfo &Other) const { 76*5f757f3fSDimitry Andric // Uninitialized is only equal to another Uninitialized. 77*5f757f3fSDimitry Andric if (State != Other.State) 78*5f757f3fSDimitry Andric return false; 79*5f757f3fSDimitry Andric 80*5f757f3fSDimitry Andric if (isStatic()) 81*5f757f3fSDimitry Andric return VXRMImm == Other.VXRMImm; 82*5f757f3fSDimitry Andric 83*5f757f3fSDimitry Andric assert((isValid() || isUnknown()) && "Unexpected state"); 84*5f757f3fSDimitry Andric return true; 85*5f757f3fSDimitry Andric } 86*5f757f3fSDimitry Andric 87*5f757f3fSDimitry Andric bool operator!=(const VXRMInfo &Other) const { return !(*this == Other); } 88*5f757f3fSDimitry Andric 89*5f757f3fSDimitry Andric // Calculate the VXRMInfo visible to a block assuming this and Other are 90*5f757f3fSDimitry Andric // both predecessors. 91*5f757f3fSDimitry Andric VXRMInfo intersect(const VXRMInfo &Other) const { 92*5f757f3fSDimitry Andric // If the new value isn't valid, ignore it. 93*5f757f3fSDimitry Andric if (!Other.isValid()) 94*5f757f3fSDimitry Andric return *this; 95*5f757f3fSDimitry Andric 96*5f757f3fSDimitry Andric // If this value isn't valid, this must be the first predecessor, use it. 97*5f757f3fSDimitry Andric if (!isValid()) 98*5f757f3fSDimitry Andric return Other; 99*5f757f3fSDimitry Andric 100*5f757f3fSDimitry Andric // If either is unknown, the result is unknown. 101*5f757f3fSDimitry Andric if (isUnknown() || Other.isUnknown()) 102*5f757f3fSDimitry Andric return VXRMInfo::getUnknown(); 103*5f757f3fSDimitry Andric 104*5f757f3fSDimitry Andric // If we have an exact match, return this. 105*5f757f3fSDimitry Andric if (*this == Other) 106*5f757f3fSDimitry Andric return *this; 107*5f757f3fSDimitry Andric 108*5f757f3fSDimitry Andric // Otherwise the result is unknown. 109*5f757f3fSDimitry Andric return VXRMInfo::getUnknown(); 110*5f757f3fSDimitry Andric } 111*5f757f3fSDimitry Andric 112*5f757f3fSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 113*5f757f3fSDimitry Andric /// Support for debugging, callable in GDB: V->dump() 114*5f757f3fSDimitry Andric LLVM_DUMP_METHOD void dump() const { 115*5f757f3fSDimitry Andric print(dbgs()); 116*5f757f3fSDimitry Andric dbgs() << "\n"; 117*5f757f3fSDimitry Andric } 118*5f757f3fSDimitry Andric 119*5f757f3fSDimitry Andric void print(raw_ostream &OS) const { 120*5f757f3fSDimitry Andric OS << '{'; 121*5f757f3fSDimitry Andric if (!isValid()) 122*5f757f3fSDimitry Andric OS << "Uninitialized"; 123*5f757f3fSDimitry Andric else if (isUnknown()) 124*5f757f3fSDimitry Andric OS << "Unknown"; 125*5f757f3fSDimitry Andric else 126*5f757f3fSDimitry Andric OS << getVXRMImm(); 127*5f757f3fSDimitry Andric OS << '}'; 128*5f757f3fSDimitry Andric } 129*5f757f3fSDimitry Andric #endif 130*5f757f3fSDimitry Andric }; 131*5f757f3fSDimitry Andric 132*5f757f3fSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 133*5f757f3fSDimitry Andric LLVM_ATTRIBUTE_USED 134*5f757f3fSDimitry Andric inline raw_ostream &operator<<(raw_ostream &OS, const VXRMInfo &V) { 135*5f757f3fSDimitry Andric V.print(OS); 136*5f757f3fSDimitry Andric return OS; 137*5f757f3fSDimitry Andric } 138*5f757f3fSDimitry Andric #endif 139*5f757f3fSDimitry Andric 140*5f757f3fSDimitry Andric struct BlockData { 141*5f757f3fSDimitry Andric // Indicates if the block uses VXRM. Uninitialized means no use. 142*5f757f3fSDimitry Andric VXRMInfo VXRMUse; 143*5f757f3fSDimitry Andric 144*5f757f3fSDimitry Andric // Indicates the VXRM output from the block. Unitialized means transparent. 145*5f757f3fSDimitry Andric VXRMInfo VXRMOut; 146*5f757f3fSDimitry Andric 147*5f757f3fSDimitry Andric // Keeps track of the available VXRM value at the start of the basic bloc. 148*5f757f3fSDimitry Andric VXRMInfo AvailableIn; 149*5f757f3fSDimitry Andric 150*5f757f3fSDimitry Andric // Keeps track of the available VXRM value at the end of the basic block. 151*5f757f3fSDimitry Andric VXRMInfo AvailableOut; 152*5f757f3fSDimitry Andric 153*5f757f3fSDimitry Andric // Keeps track of what VXRM is anticipated at the start of the basic block. 154*5f757f3fSDimitry Andric VXRMInfo AnticipatedIn; 155*5f757f3fSDimitry Andric 156*5f757f3fSDimitry Andric // Keeps track of what VXRM is anticipated at the end of the basic block. 157*5f757f3fSDimitry Andric VXRMInfo AnticipatedOut; 158*5f757f3fSDimitry Andric 159*5f757f3fSDimitry Andric // Keeps track of whether the block is already in the queue. 160*5f757f3fSDimitry Andric bool InQueue; 161*5f757f3fSDimitry Andric 162*5f757f3fSDimitry Andric BlockData() = default; 163*5f757f3fSDimitry Andric }; 164*5f757f3fSDimitry Andric 165*5f757f3fSDimitry Andric class RISCVInsertWriteVXRM : public MachineFunctionPass { 166*5f757f3fSDimitry Andric const TargetInstrInfo *TII; 167*5f757f3fSDimitry Andric 168*5f757f3fSDimitry Andric std::vector<BlockData> BlockInfo; 169*5f757f3fSDimitry Andric std::queue<const MachineBasicBlock *> WorkList; 170*5f757f3fSDimitry Andric 171*5f757f3fSDimitry Andric public: 172*5f757f3fSDimitry Andric static char ID; 173*5f757f3fSDimitry Andric 174*5f757f3fSDimitry Andric RISCVInsertWriteVXRM() : MachineFunctionPass(ID) {} 175*5f757f3fSDimitry Andric 176*5f757f3fSDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 177*5f757f3fSDimitry Andric 178*5f757f3fSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 179*5f757f3fSDimitry Andric AU.setPreservesCFG(); 180*5f757f3fSDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 181*5f757f3fSDimitry Andric } 182*5f757f3fSDimitry Andric 183*5f757f3fSDimitry Andric StringRef getPassName() const override { 184*5f757f3fSDimitry Andric return RISCV_INSERT_WRITE_VXRM_NAME; 185*5f757f3fSDimitry Andric } 186*5f757f3fSDimitry Andric 187*5f757f3fSDimitry Andric private: 188*5f757f3fSDimitry Andric bool computeVXRMChanges(const MachineBasicBlock &MBB); 189*5f757f3fSDimitry Andric void computeAvailable(const MachineBasicBlock &MBB); 190*5f757f3fSDimitry Andric void computeAnticipated(const MachineBasicBlock &MBB); 191*5f757f3fSDimitry Andric void emitWriteVXRM(MachineBasicBlock &MBB); 192*5f757f3fSDimitry Andric }; 193*5f757f3fSDimitry Andric 194*5f757f3fSDimitry Andric } // end anonymous namespace 195*5f757f3fSDimitry Andric 196*5f757f3fSDimitry Andric char RISCVInsertWriteVXRM::ID = 0; 197*5f757f3fSDimitry Andric 198*5f757f3fSDimitry Andric INITIALIZE_PASS(RISCVInsertWriteVXRM, DEBUG_TYPE, RISCV_INSERT_WRITE_VXRM_NAME, 199*5f757f3fSDimitry Andric false, false) 200*5f757f3fSDimitry Andric 201*5f757f3fSDimitry Andric bool RISCVInsertWriteVXRM::computeVXRMChanges(const MachineBasicBlock &MBB) { 202*5f757f3fSDimitry Andric BlockData &BBInfo = BlockInfo[MBB.getNumber()]; 203*5f757f3fSDimitry Andric 204*5f757f3fSDimitry Andric bool NeedVXRMWrite = false; 205*5f757f3fSDimitry Andric for (const MachineInstr &MI : MBB) { 206*5f757f3fSDimitry Andric int VXRMIdx = RISCVII::getVXRMOpNum(MI.getDesc()); 207*5f757f3fSDimitry Andric if (VXRMIdx >= 0) { 208*5f757f3fSDimitry Andric unsigned NewVXRMImm = MI.getOperand(VXRMIdx).getImm(); 209*5f757f3fSDimitry Andric 210*5f757f3fSDimitry Andric if (!BBInfo.VXRMUse.isValid()) 211*5f757f3fSDimitry Andric BBInfo.VXRMUse.setVXRMImm(NewVXRMImm); 212*5f757f3fSDimitry Andric 213*5f757f3fSDimitry Andric BBInfo.VXRMOut.setVXRMImm(NewVXRMImm); 214*5f757f3fSDimitry Andric NeedVXRMWrite = true; 215*5f757f3fSDimitry Andric continue; 216*5f757f3fSDimitry Andric } 217*5f757f3fSDimitry Andric 218*5f757f3fSDimitry Andric if (MI.isCall() || MI.isInlineAsm() || MI.modifiesRegister(RISCV::VXRM)) { 219*5f757f3fSDimitry Andric if (!BBInfo.VXRMUse.isValid()) 220*5f757f3fSDimitry Andric BBInfo.VXRMUse.setUnknown(); 221*5f757f3fSDimitry Andric 222*5f757f3fSDimitry Andric BBInfo.VXRMOut.setUnknown(); 223*5f757f3fSDimitry Andric } 224*5f757f3fSDimitry Andric } 225*5f757f3fSDimitry Andric 226*5f757f3fSDimitry Andric return NeedVXRMWrite; 227*5f757f3fSDimitry Andric } 228*5f757f3fSDimitry Andric 229*5f757f3fSDimitry Andric void RISCVInsertWriteVXRM::computeAvailable(const MachineBasicBlock &MBB) { 230*5f757f3fSDimitry Andric BlockData &BBInfo = BlockInfo[MBB.getNumber()]; 231*5f757f3fSDimitry Andric 232*5f757f3fSDimitry Andric BBInfo.InQueue = false; 233*5f757f3fSDimitry Andric 234*5f757f3fSDimitry Andric VXRMInfo Available; 235*5f757f3fSDimitry Andric if (MBB.pred_empty()) { 236*5f757f3fSDimitry Andric Available.setUnknown(); 237*5f757f3fSDimitry Andric } else { 238*5f757f3fSDimitry Andric for (const MachineBasicBlock *P : MBB.predecessors()) 239*5f757f3fSDimitry Andric Available = Available.intersect(BlockInfo[P->getNumber()].AvailableOut); 240*5f757f3fSDimitry Andric } 241*5f757f3fSDimitry Andric 242*5f757f3fSDimitry Andric // If we don't have any valid available info, wait until we do. 243*5f757f3fSDimitry Andric if (!Available.isValid()) 244*5f757f3fSDimitry Andric return; 245*5f757f3fSDimitry Andric 246*5f757f3fSDimitry Andric if (Available != BBInfo.AvailableIn) { 247*5f757f3fSDimitry Andric BBInfo.AvailableIn = Available; 248*5f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "AvailableIn state of " << printMBBReference(MBB) 249*5f757f3fSDimitry Andric << " changed to " << BBInfo.AvailableIn << "\n"); 250*5f757f3fSDimitry Andric } 251*5f757f3fSDimitry Andric 252*5f757f3fSDimitry Andric if (BBInfo.VXRMOut.isValid()) 253*5f757f3fSDimitry Andric Available = BBInfo.VXRMOut; 254*5f757f3fSDimitry Andric 255*5f757f3fSDimitry Andric if (Available == BBInfo.AvailableOut) 256*5f757f3fSDimitry Andric return; 257*5f757f3fSDimitry Andric 258*5f757f3fSDimitry Andric BBInfo.AvailableOut = Available; 259*5f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "AvailableOut state of " << printMBBReference(MBB) 260*5f757f3fSDimitry Andric << " changed to " << BBInfo.AvailableOut << "\n"); 261*5f757f3fSDimitry Andric 262*5f757f3fSDimitry Andric // Add the successors to the work list so that we can propagate. 263*5f757f3fSDimitry Andric for (MachineBasicBlock *S : MBB.successors()) { 264*5f757f3fSDimitry Andric if (!BlockInfo[S->getNumber()].InQueue) { 265*5f757f3fSDimitry Andric BlockInfo[S->getNumber()].InQueue = true; 266*5f757f3fSDimitry Andric WorkList.push(S); 267*5f757f3fSDimitry Andric } 268*5f757f3fSDimitry Andric } 269*5f757f3fSDimitry Andric } 270*5f757f3fSDimitry Andric 271*5f757f3fSDimitry Andric void RISCVInsertWriteVXRM::computeAnticipated(const MachineBasicBlock &MBB) { 272*5f757f3fSDimitry Andric BlockData &BBInfo = BlockInfo[MBB.getNumber()]; 273*5f757f3fSDimitry Andric 274*5f757f3fSDimitry Andric BBInfo.InQueue = false; 275*5f757f3fSDimitry Andric 276*5f757f3fSDimitry Andric VXRMInfo Anticipated; 277*5f757f3fSDimitry Andric if (MBB.succ_empty()) { 278*5f757f3fSDimitry Andric Anticipated.setUnknown(); 279*5f757f3fSDimitry Andric } else { 280*5f757f3fSDimitry Andric for (const MachineBasicBlock *S : MBB.successors()) 281*5f757f3fSDimitry Andric Anticipated = 282*5f757f3fSDimitry Andric Anticipated.intersect(BlockInfo[S->getNumber()].AnticipatedIn); 283*5f757f3fSDimitry Andric } 284*5f757f3fSDimitry Andric 285*5f757f3fSDimitry Andric // If we don't have any valid anticipated info, wait until we do. 286*5f757f3fSDimitry Andric if (!Anticipated.isValid()) 287*5f757f3fSDimitry Andric return; 288*5f757f3fSDimitry Andric 289*5f757f3fSDimitry Andric if (Anticipated != BBInfo.AnticipatedOut) { 290*5f757f3fSDimitry Andric BBInfo.AnticipatedOut = Anticipated; 291*5f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "AnticipatedOut state of " << printMBBReference(MBB) 292*5f757f3fSDimitry Andric << " changed to " << BBInfo.AnticipatedOut << "\n"); 293*5f757f3fSDimitry Andric } 294*5f757f3fSDimitry Andric 295*5f757f3fSDimitry Andric // If this block reads VXRM, copy it. 296*5f757f3fSDimitry Andric if (BBInfo.VXRMUse.isValid()) 297*5f757f3fSDimitry Andric Anticipated = BBInfo.VXRMUse; 298*5f757f3fSDimitry Andric 299*5f757f3fSDimitry Andric if (Anticipated == BBInfo.AnticipatedIn) 300*5f757f3fSDimitry Andric return; 301*5f757f3fSDimitry Andric 302*5f757f3fSDimitry Andric BBInfo.AnticipatedIn = Anticipated; 303*5f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "AnticipatedIn state of " << printMBBReference(MBB) 304*5f757f3fSDimitry Andric << " changed to " << BBInfo.AnticipatedIn << "\n"); 305*5f757f3fSDimitry Andric 306*5f757f3fSDimitry Andric // Add the predecessors to the work list so that we can propagate. 307*5f757f3fSDimitry Andric for (MachineBasicBlock *P : MBB.predecessors()) { 308*5f757f3fSDimitry Andric if (!BlockInfo[P->getNumber()].InQueue) { 309*5f757f3fSDimitry Andric BlockInfo[P->getNumber()].InQueue = true; 310*5f757f3fSDimitry Andric WorkList.push(P); 311*5f757f3fSDimitry Andric } 312*5f757f3fSDimitry Andric } 313*5f757f3fSDimitry Andric } 314*5f757f3fSDimitry Andric 315*5f757f3fSDimitry Andric void RISCVInsertWriteVXRM::emitWriteVXRM(MachineBasicBlock &MBB) { 316*5f757f3fSDimitry Andric const BlockData &BBInfo = BlockInfo[MBB.getNumber()]; 317*5f757f3fSDimitry Andric 318*5f757f3fSDimitry Andric VXRMInfo Info = BBInfo.AvailableIn; 319*5f757f3fSDimitry Andric 320*5f757f3fSDimitry Andric // Flag to indicates we need to insert a VXRM write. We want to delay it as 321*5f757f3fSDimitry Andric // late as possible in this block. 322*5f757f3fSDimitry Andric bool PendingInsert = false; 323*5f757f3fSDimitry Andric 324*5f757f3fSDimitry Andric // Insert VXRM write if anticipated and not available. 325*5f757f3fSDimitry Andric if (BBInfo.AnticipatedIn.isStatic()) { 326*5f757f3fSDimitry Andric // If this is the entry block and the value is anticipated, insert. 327*5f757f3fSDimitry Andric if (MBB.isEntryBlock()) { 328*5f757f3fSDimitry Andric PendingInsert = true; 329*5f757f3fSDimitry Andric } else { 330*5f757f3fSDimitry Andric // Search for any predecessors that wouldn't satisfy our requirement and 331*5f757f3fSDimitry Andric // insert a write VXRM if needed. 332*5f757f3fSDimitry Andric // NOTE: If one predecessor is able to provide the requirement, but 333*5f757f3fSDimitry Andric // another isn't, it means we have a critical edge. The better placement 334*5f757f3fSDimitry Andric // would be to split the critical edge. 335*5f757f3fSDimitry Andric for (MachineBasicBlock *P : MBB.predecessors()) { 336*5f757f3fSDimitry Andric const BlockData &PInfo = BlockInfo[P->getNumber()]; 337*5f757f3fSDimitry Andric // If it's available out of the predecessor, then we're ok. 338*5f757f3fSDimitry Andric if (PInfo.AvailableOut.isStatic() && 339*5f757f3fSDimitry Andric PInfo.AvailableOut.getVXRMImm() == 340*5f757f3fSDimitry Andric BBInfo.AnticipatedIn.getVXRMImm()) 341*5f757f3fSDimitry Andric continue; 342*5f757f3fSDimitry Andric // If the predecessor anticipates this value for all its succesors, 343*5f757f3fSDimitry Andric // then a write to VXRM would have already occured before this block is 344*5f757f3fSDimitry Andric // executed. 345*5f757f3fSDimitry Andric if (PInfo.AnticipatedOut.isStatic() && 346*5f757f3fSDimitry Andric PInfo.AnticipatedOut.getVXRMImm() == 347*5f757f3fSDimitry Andric BBInfo.AnticipatedIn.getVXRMImm()) 348*5f757f3fSDimitry Andric continue; 349*5f757f3fSDimitry Andric PendingInsert = true; 350*5f757f3fSDimitry Andric break; 351*5f757f3fSDimitry Andric } 352*5f757f3fSDimitry Andric } 353*5f757f3fSDimitry Andric 354*5f757f3fSDimitry Andric Info = BBInfo.AnticipatedIn; 355*5f757f3fSDimitry Andric } 356*5f757f3fSDimitry Andric 357*5f757f3fSDimitry Andric for (MachineInstr &MI : MBB) { 358*5f757f3fSDimitry Andric int VXRMIdx = RISCVII::getVXRMOpNum(MI.getDesc()); 359*5f757f3fSDimitry Andric if (VXRMIdx >= 0) { 360*5f757f3fSDimitry Andric unsigned NewVXRMImm = MI.getOperand(VXRMIdx).getImm(); 361*5f757f3fSDimitry Andric 362*5f757f3fSDimitry Andric if (PendingInsert || !Info.isStatic() || 363*5f757f3fSDimitry Andric Info.getVXRMImm() != NewVXRMImm) { 364*5f757f3fSDimitry Andric assert((!PendingInsert || 365*5f757f3fSDimitry Andric (Info.isStatic() && Info.getVXRMImm() == NewVXRMImm)) && 366*5f757f3fSDimitry Andric "Pending VXRM insertion mismatch"); 367*5f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Inserting before "; MI.print(dbgs())); 368*5f757f3fSDimitry Andric BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(RISCV::WriteVXRMImm)) 369*5f757f3fSDimitry Andric .addImm(NewVXRMImm); 370*5f757f3fSDimitry Andric PendingInsert = false; 371*5f757f3fSDimitry Andric } 372*5f757f3fSDimitry Andric 373*5f757f3fSDimitry Andric MI.addOperand(MachineOperand::CreateReg(RISCV::VXRM, /*IsDef*/ false, 374*5f757f3fSDimitry Andric /*IsImp*/ true)); 375*5f757f3fSDimitry Andric Info.setVXRMImm(NewVXRMImm); 376*5f757f3fSDimitry Andric continue; 377*5f757f3fSDimitry Andric } 378*5f757f3fSDimitry Andric 379*5f757f3fSDimitry Andric if (MI.isCall() || MI.isInlineAsm() || MI.modifiesRegister(RISCV::VXRM)) 380*5f757f3fSDimitry Andric Info.setUnknown(); 381*5f757f3fSDimitry Andric } 382*5f757f3fSDimitry Andric 383*5f757f3fSDimitry Andric // If all our successors anticipate a value, do the insert. 384*5f757f3fSDimitry Andric // NOTE: It's possible that not all predecessors of our successor provide the 385*5f757f3fSDimitry Andric // correct value. This can occur on critical edges. If we don't split the 386*5f757f3fSDimitry Andric // critical edge we'll also have a write vxrm in the succesor that is 387*5f757f3fSDimitry Andric // redundant with this one. 388*5f757f3fSDimitry Andric if (PendingInsert || 389*5f757f3fSDimitry Andric (BBInfo.AnticipatedOut.isStatic() && 390*5f757f3fSDimitry Andric (!Info.isStatic() || 391*5f757f3fSDimitry Andric Info.getVXRMImm() != BBInfo.AnticipatedOut.getVXRMImm()))) { 392*5f757f3fSDimitry Andric assert((!PendingInsert || 393*5f757f3fSDimitry Andric (Info.isStatic() && BBInfo.AnticipatedOut.isStatic() && 394*5f757f3fSDimitry Andric Info.getVXRMImm() == BBInfo.AnticipatedOut.getVXRMImm())) && 395*5f757f3fSDimitry Andric "Pending VXRM insertion mismatch"); 396*5f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Inserting at end of " << printMBBReference(MBB) 397*5f757f3fSDimitry Andric << " changing to " << BBInfo.AnticipatedOut << "\n"); 398*5f757f3fSDimitry Andric BuildMI(MBB, MBB.getFirstTerminator(), DebugLoc(), 399*5f757f3fSDimitry Andric TII->get(RISCV::WriteVXRMImm)) 400*5f757f3fSDimitry Andric .addImm(BBInfo.AnticipatedOut.getVXRMImm()); 401*5f757f3fSDimitry Andric } 402*5f757f3fSDimitry Andric } 403*5f757f3fSDimitry Andric 404*5f757f3fSDimitry Andric bool RISCVInsertWriteVXRM::runOnMachineFunction(MachineFunction &MF) { 405*5f757f3fSDimitry Andric // Skip if the vector extension is not enabled. 406*5f757f3fSDimitry Andric const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>(); 407*5f757f3fSDimitry Andric if (!ST.hasVInstructions()) 408*5f757f3fSDimitry Andric return false; 409*5f757f3fSDimitry Andric 410*5f757f3fSDimitry Andric TII = ST.getInstrInfo(); 411*5f757f3fSDimitry Andric 412*5f757f3fSDimitry Andric assert(BlockInfo.empty() && "Expect empty block infos"); 413*5f757f3fSDimitry Andric BlockInfo.resize(MF.getNumBlockIDs()); 414*5f757f3fSDimitry Andric 415*5f757f3fSDimitry Andric // Phase 1 - collect block information. 416*5f757f3fSDimitry Andric bool NeedVXRMChange = false; 417*5f757f3fSDimitry Andric for (const MachineBasicBlock &MBB : MF) 418*5f757f3fSDimitry Andric NeedVXRMChange |= computeVXRMChanges(MBB); 419*5f757f3fSDimitry Andric 420*5f757f3fSDimitry Andric if (!NeedVXRMChange) { 421*5f757f3fSDimitry Andric BlockInfo.clear(); 422*5f757f3fSDimitry Andric return false; 423*5f757f3fSDimitry Andric } 424*5f757f3fSDimitry Andric 425*5f757f3fSDimitry Andric // Phase 2 - Compute available VXRM using a forward walk. 426*5f757f3fSDimitry Andric for (const MachineBasicBlock &MBB : MF) { 427*5f757f3fSDimitry Andric WorkList.push(&MBB); 428*5f757f3fSDimitry Andric BlockInfo[MBB.getNumber()].InQueue = true; 429*5f757f3fSDimitry Andric } 430*5f757f3fSDimitry Andric while (!WorkList.empty()) { 431*5f757f3fSDimitry Andric const MachineBasicBlock &MBB = *WorkList.front(); 432*5f757f3fSDimitry Andric WorkList.pop(); 433*5f757f3fSDimitry Andric computeAvailable(MBB); 434*5f757f3fSDimitry Andric } 435*5f757f3fSDimitry Andric 436*5f757f3fSDimitry Andric // Phase 3 - Compute anticipated VXRM using a backwards walk. 437*5f757f3fSDimitry Andric for (const MachineBasicBlock &MBB : llvm::reverse(MF)) { 438*5f757f3fSDimitry Andric WorkList.push(&MBB); 439*5f757f3fSDimitry Andric BlockInfo[MBB.getNumber()].InQueue = true; 440*5f757f3fSDimitry Andric } 441*5f757f3fSDimitry Andric while (!WorkList.empty()) { 442*5f757f3fSDimitry Andric const MachineBasicBlock &MBB = *WorkList.front(); 443*5f757f3fSDimitry Andric WorkList.pop(); 444*5f757f3fSDimitry Andric computeAnticipated(MBB); 445*5f757f3fSDimitry Andric } 446*5f757f3fSDimitry Andric 447*5f757f3fSDimitry Andric // Phase 4 - Emit VXRM writes at the earliest place possible. 448*5f757f3fSDimitry Andric for (MachineBasicBlock &MBB : MF) 449*5f757f3fSDimitry Andric emitWriteVXRM(MBB); 450*5f757f3fSDimitry Andric 451*5f757f3fSDimitry Andric BlockInfo.clear(); 452*5f757f3fSDimitry Andric 453*5f757f3fSDimitry Andric return true; 454*5f757f3fSDimitry Andric } 455*5f757f3fSDimitry Andric 456*5f757f3fSDimitry Andric FunctionPass *llvm::createRISCVInsertWriteVXRMPass() { 457*5f757f3fSDimitry Andric return new RISCVInsertWriteVXRM(); 458*5f757f3fSDimitry Andric } 459