15f757f3fSDimitry Andric //===-- RISCVInsertWriteVXRM.cpp - Insert Write of RISC-V VXRM CSR --------===// 25f757f3fSDimitry Andric // 35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65f757f3fSDimitry Andric // 75f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 85f757f3fSDimitry Andric // 95f757f3fSDimitry Andric // This pass inserts writes to the VXRM CSR as needed by vector instructions. 105f757f3fSDimitry Andric // Each instruction that uses VXRM carries an operand that contains its required 115f757f3fSDimitry Andric // VXRM value. This pass tries to optimize placement to avoid redundant writes 125f757f3fSDimitry Andric // to VXRM. 135f757f3fSDimitry Andric // 145f757f3fSDimitry Andric // This is done using 2 dataflow algorithms. The first is a forward data flow 155f757f3fSDimitry Andric // to calculate where a VXRM value is available. The second is a backwards 165f757f3fSDimitry Andric // dataflow to determine where a VXRM value is anticipated. 175f757f3fSDimitry Andric // 185f757f3fSDimitry Andric // Finally, we use the results of these two dataflows to insert VXRM writes 195f757f3fSDimitry Andric // where a value is anticipated, but not available. 205f757f3fSDimitry Andric // 215f757f3fSDimitry Andric // FIXME: This pass does not split critical edges, so there can still be some 225f757f3fSDimitry Andric // redundancy. 235f757f3fSDimitry Andric // 245f757f3fSDimitry Andric // FIXME: If we are willing to have writes that aren't always needed, we could 255f757f3fSDimitry Andric // reduce the number of VXRM writes in some cases. 265f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 275f757f3fSDimitry Andric 285f757f3fSDimitry Andric #include "MCTargetDesc/RISCVBaseInfo.h" 295f757f3fSDimitry Andric #include "RISCV.h" 305f757f3fSDimitry Andric #include "RISCVSubtarget.h" 315f757f3fSDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 325f757f3fSDimitry Andric #include <queue> 335f757f3fSDimitry Andric 345f757f3fSDimitry Andric using namespace llvm; 355f757f3fSDimitry Andric 365f757f3fSDimitry Andric #define DEBUG_TYPE "riscv-insert-write-vxrm" 375f757f3fSDimitry Andric #define RISCV_INSERT_WRITE_VXRM_NAME "RISC-V Insert Write VXRM Pass" 385f757f3fSDimitry Andric 395f757f3fSDimitry Andric namespace { 405f757f3fSDimitry Andric 415f757f3fSDimitry Andric class VXRMInfo { 425f757f3fSDimitry Andric uint8_t VXRMImm = 0; 435f757f3fSDimitry Andric 445f757f3fSDimitry Andric enum : uint8_t { 455f757f3fSDimitry Andric Uninitialized, 465f757f3fSDimitry Andric Static, 475f757f3fSDimitry Andric Unknown, 485f757f3fSDimitry Andric } State = Uninitialized; 495f757f3fSDimitry Andric 505f757f3fSDimitry Andric public: 515f757f3fSDimitry Andric VXRMInfo() {} 525f757f3fSDimitry Andric 535f757f3fSDimitry Andric static VXRMInfo getUnknown() { 545f757f3fSDimitry Andric VXRMInfo Info; 555f757f3fSDimitry Andric Info.setUnknown(); 565f757f3fSDimitry Andric return Info; 575f757f3fSDimitry Andric } 585f757f3fSDimitry Andric 595f757f3fSDimitry Andric bool isValid() const { return State != Uninitialized; } 605f757f3fSDimitry Andric void setUnknown() { State = Unknown; } 615f757f3fSDimitry Andric bool isUnknown() const { return State == Unknown; } 625f757f3fSDimitry Andric 635f757f3fSDimitry Andric bool isStatic() const { return State == Static; } 645f757f3fSDimitry Andric 655f757f3fSDimitry Andric void setVXRMImm(unsigned Imm) { 665f757f3fSDimitry Andric assert(Imm <= 3 && "Unexpected VXRM value"); 675f757f3fSDimitry Andric VXRMImm = Imm; 685f757f3fSDimitry Andric State = Static; 695f757f3fSDimitry Andric } 705f757f3fSDimitry Andric unsigned getVXRMImm() const { 715f757f3fSDimitry Andric assert(isStatic() && VXRMImm <= 3 && "Unexpected state"); 725f757f3fSDimitry Andric return VXRMImm; 735f757f3fSDimitry Andric } 745f757f3fSDimitry Andric 755f757f3fSDimitry Andric bool operator==(const VXRMInfo &Other) const { 765f757f3fSDimitry Andric // Uninitialized is only equal to another Uninitialized. 775f757f3fSDimitry Andric if (State != Other.State) 785f757f3fSDimitry Andric return false; 795f757f3fSDimitry Andric 805f757f3fSDimitry Andric if (isStatic()) 815f757f3fSDimitry Andric return VXRMImm == Other.VXRMImm; 825f757f3fSDimitry Andric 835f757f3fSDimitry Andric assert((isValid() || isUnknown()) && "Unexpected state"); 845f757f3fSDimitry Andric return true; 855f757f3fSDimitry Andric } 865f757f3fSDimitry Andric 875f757f3fSDimitry Andric bool operator!=(const VXRMInfo &Other) const { return !(*this == Other); } 885f757f3fSDimitry Andric 895f757f3fSDimitry Andric // Calculate the VXRMInfo visible to a block assuming this and Other are 905f757f3fSDimitry Andric // both predecessors. 915f757f3fSDimitry Andric VXRMInfo intersect(const VXRMInfo &Other) const { 925f757f3fSDimitry Andric // If the new value isn't valid, ignore it. 935f757f3fSDimitry Andric if (!Other.isValid()) 945f757f3fSDimitry Andric return *this; 955f757f3fSDimitry Andric 965f757f3fSDimitry Andric // If this value isn't valid, this must be the first predecessor, use it. 975f757f3fSDimitry Andric if (!isValid()) 985f757f3fSDimitry Andric return Other; 995f757f3fSDimitry Andric 1005f757f3fSDimitry Andric // If either is unknown, the result is unknown. 1015f757f3fSDimitry Andric if (isUnknown() || Other.isUnknown()) 1025f757f3fSDimitry Andric return VXRMInfo::getUnknown(); 1035f757f3fSDimitry Andric 1045f757f3fSDimitry Andric // If we have an exact match, return this. 1055f757f3fSDimitry Andric if (*this == Other) 1065f757f3fSDimitry Andric return *this; 1075f757f3fSDimitry Andric 1085f757f3fSDimitry Andric // Otherwise the result is unknown. 1095f757f3fSDimitry Andric return VXRMInfo::getUnknown(); 1105f757f3fSDimitry Andric } 1115f757f3fSDimitry Andric 1125f757f3fSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 1135f757f3fSDimitry Andric /// Support for debugging, callable in GDB: V->dump() 1145f757f3fSDimitry Andric LLVM_DUMP_METHOD void dump() const { 1155f757f3fSDimitry Andric print(dbgs()); 1165f757f3fSDimitry Andric dbgs() << "\n"; 1175f757f3fSDimitry Andric } 1185f757f3fSDimitry Andric 1195f757f3fSDimitry Andric void print(raw_ostream &OS) const { 1205f757f3fSDimitry Andric OS << '{'; 1215f757f3fSDimitry Andric if (!isValid()) 1225f757f3fSDimitry Andric OS << "Uninitialized"; 1235f757f3fSDimitry Andric else if (isUnknown()) 1245f757f3fSDimitry Andric OS << "Unknown"; 1255f757f3fSDimitry Andric else 1265f757f3fSDimitry Andric OS << getVXRMImm(); 1275f757f3fSDimitry Andric OS << '}'; 1285f757f3fSDimitry Andric } 1295f757f3fSDimitry Andric #endif 1305f757f3fSDimitry Andric }; 1315f757f3fSDimitry Andric 1325f757f3fSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 1335f757f3fSDimitry Andric LLVM_ATTRIBUTE_USED 1345f757f3fSDimitry Andric inline raw_ostream &operator<<(raw_ostream &OS, const VXRMInfo &V) { 1355f757f3fSDimitry Andric V.print(OS); 1365f757f3fSDimitry Andric return OS; 1375f757f3fSDimitry Andric } 1385f757f3fSDimitry Andric #endif 1395f757f3fSDimitry Andric 1405f757f3fSDimitry Andric struct BlockData { 1415f757f3fSDimitry Andric // Indicates if the block uses VXRM. Uninitialized means no use. 1425f757f3fSDimitry Andric VXRMInfo VXRMUse; 1435f757f3fSDimitry Andric 1445f757f3fSDimitry Andric // Indicates the VXRM output from the block. Unitialized means transparent. 1455f757f3fSDimitry Andric VXRMInfo VXRMOut; 1465f757f3fSDimitry Andric 1475f757f3fSDimitry Andric // Keeps track of the available VXRM value at the start of the basic bloc. 1485f757f3fSDimitry Andric VXRMInfo AvailableIn; 1495f757f3fSDimitry Andric 1505f757f3fSDimitry Andric // Keeps track of the available VXRM value at the end of the basic block. 1515f757f3fSDimitry Andric VXRMInfo AvailableOut; 1525f757f3fSDimitry Andric 1535f757f3fSDimitry Andric // Keeps track of what VXRM is anticipated at the start of the basic block. 1545f757f3fSDimitry Andric VXRMInfo AnticipatedIn; 1555f757f3fSDimitry Andric 1565f757f3fSDimitry Andric // Keeps track of what VXRM is anticipated at the end of the basic block. 1575f757f3fSDimitry Andric VXRMInfo AnticipatedOut; 1585f757f3fSDimitry Andric 1595f757f3fSDimitry Andric // Keeps track of whether the block is already in the queue. 1605f757f3fSDimitry Andric bool InQueue; 1615f757f3fSDimitry Andric 1625f757f3fSDimitry Andric BlockData() = default; 1635f757f3fSDimitry Andric }; 1645f757f3fSDimitry Andric 1655f757f3fSDimitry Andric class RISCVInsertWriteVXRM : public MachineFunctionPass { 1665f757f3fSDimitry Andric const TargetInstrInfo *TII; 1675f757f3fSDimitry Andric 1685f757f3fSDimitry Andric std::vector<BlockData> BlockInfo; 1695f757f3fSDimitry Andric std::queue<const MachineBasicBlock *> WorkList; 1705f757f3fSDimitry Andric 1715f757f3fSDimitry Andric public: 1725f757f3fSDimitry Andric static char ID; 1735f757f3fSDimitry Andric 1745f757f3fSDimitry Andric RISCVInsertWriteVXRM() : MachineFunctionPass(ID) {} 1755f757f3fSDimitry Andric 1765f757f3fSDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 1775f757f3fSDimitry Andric 1785f757f3fSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 1795f757f3fSDimitry Andric AU.setPreservesCFG(); 1805f757f3fSDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 1815f757f3fSDimitry Andric } 1825f757f3fSDimitry Andric 1835f757f3fSDimitry Andric StringRef getPassName() const override { 1845f757f3fSDimitry Andric return RISCV_INSERT_WRITE_VXRM_NAME; 1855f757f3fSDimitry Andric } 1865f757f3fSDimitry Andric 1875f757f3fSDimitry Andric private: 1885f757f3fSDimitry Andric bool computeVXRMChanges(const MachineBasicBlock &MBB); 1895f757f3fSDimitry Andric void computeAvailable(const MachineBasicBlock &MBB); 1905f757f3fSDimitry Andric void computeAnticipated(const MachineBasicBlock &MBB); 1915f757f3fSDimitry Andric void emitWriteVXRM(MachineBasicBlock &MBB); 1925f757f3fSDimitry Andric }; 1935f757f3fSDimitry Andric 1945f757f3fSDimitry Andric } // end anonymous namespace 1955f757f3fSDimitry Andric 1965f757f3fSDimitry Andric char RISCVInsertWriteVXRM::ID = 0; 1975f757f3fSDimitry Andric 1985f757f3fSDimitry Andric INITIALIZE_PASS(RISCVInsertWriteVXRM, DEBUG_TYPE, RISCV_INSERT_WRITE_VXRM_NAME, 1995f757f3fSDimitry Andric false, false) 2005f757f3fSDimitry Andric 201647cbc5dSDimitry Andric static bool ignoresVXRM(const MachineInstr &MI) { 202647cbc5dSDimitry Andric switch (RISCV::getRVVMCOpcode(MI.getOpcode())) { 203647cbc5dSDimitry Andric default: 204647cbc5dSDimitry Andric return false; 205647cbc5dSDimitry Andric case RISCV::VNCLIP_WI: 206647cbc5dSDimitry Andric case RISCV::VNCLIPU_WI: 207647cbc5dSDimitry Andric return MI.getOperand(3).getImm() == 0; 208647cbc5dSDimitry Andric } 209647cbc5dSDimitry Andric } 210647cbc5dSDimitry Andric 2115f757f3fSDimitry Andric bool RISCVInsertWriteVXRM::computeVXRMChanges(const MachineBasicBlock &MBB) { 2125f757f3fSDimitry Andric BlockData &BBInfo = BlockInfo[MBB.getNumber()]; 2135f757f3fSDimitry Andric 2145f757f3fSDimitry Andric bool NeedVXRMWrite = false; 2155f757f3fSDimitry Andric for (const MachineInstr &MI : MBB) { 2165f757f3fSDimitry Andric int VXRMIdx = RISCVII::getVXRMOpNum(MI.getDesc()); 217647cbc5dSDimitry Andric if (VXRMIdx >= 0 && !ignoresVXRM(MI)) { 2185f757f3fSDimitry Andric unsigned NewVXRMImm = MI.getOperand(VXRMIdx).getImm(); 2195f757f3fSDimitry Andric 2205f757f3fSDimitry Andric if (!BBInfo.VXRMUse.isValid()) 2215f757f3fSDimitry Andric BBInfo.VXRMUse.setVXRMImm(NewVXRMImm); 2225f757f3fSDimitry Andric 2235f757f3fSDimitry Andric BBInfo.VXRMOut.setVXRMImm(NewVXRMImm); 2245f757f3fSDimitry Andric NeedVXRMWrite = true; 2255f757f3fSDimitry Andric continue; 2265f757f3fSDimitry Andric } 2275f757f3fSDimitry Andric 228*0fca6ea1SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || 229*0fca6ea1SDimitry Andric MI.modifiesRegister(RISCV::VXRM, /*TRI=*/nullptr)) { 2305f757f3fSDimitry Andric if (!BBInfo.VXRMUse.isValid()) 2315f757f3fSDimitry Andric BBInfo.VXRMUse.setUnknown(); 2325f757f3fSDimitry Andric 2335f757f3fSDimitry Andric BBInfo.VXRMOut.setUnknown(); 2345f757f3fSDimitry Andric } 2355f757f3fSDimitry Andric } 2365f757f3fSDimitry Andric 2375f757f3fSDimitry Andric return NeedVXRMWrite; 2385f757f3fSDimitry Andric } 2395f757f3fSDimitry Andric 2405f757f3fSDimitry Andric void RISCVInsertWriteVXRM::computeAvailable(const MachineBasicBlock &MBB) { 2415f757f3fSDimitry Andric BlockData &BBInfo = BlockInfo[MBB.getNumber()]; 2425f757f3fSDimitry Andric 2435f757f3fSDimitry Andric BBInfo.InQueue = false; 2445f757f3fSDimitry Andric 2455f757f3fSDimitry Andric VXRMInfo Available; 2465f757f3fSDimitry Andric if (MBB.pred_empty()) { 2475f757f3fSDimitry Andric Available.setUnknown(); 2485f757f3fSDimitry Andric } else { 2495f757f3fSDimitry Andric for (const MachineBasicBlock *P : MBB.predecessors()) 2505f757f3fSDimitry Andric Available = Available.intersect(BlockInfo[P->getNumber()].AvailableOut); 2515f757f3fSDimitry Andric } 2525f757f3fSDimitry Andric 2535f757f3fSDimitry Andric // If we don't have any valid available info, wait until we do. 2545f757f3fSDimitry Andric if (!Available.isValid()) 2555f757f3fSDimitry Andric return; 2565f757f3fSDimitry Andric 2575f757f3fSDimitry Andric if (Available != BBInfo.AvailableIn) { 2585f757f3fSDimitry Andric BBInfo.AvailableIn = Available; 2595f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "AvailableIn state of " << printMBBReference(MBB) 2605f757f3fSDimitry Andric << " changed to " << BBInfo.AvailableIn << "\n"); 2615f757f3fSDimitry Andric } 2625f757f3fSDimitry Andric 2635f757f3fSDimitry Andric if (BBInfo.VXRMOut.isValid()) 2645f757f3fSDimitry Andric Available = BBInfo.VXRMOut; 2655f757f3fSDimitry Andric 2665f757f3fSDimitry Andric if (Available == BBInfo.AvailableOut) 2675f757f3fSDimitry Andric return; 2685f757f3fSDimitry Andric 2695f757f3fSDimitry Andric BBInfo.AvailableOut = Available; 2705f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "AvailableOut state of " << printMBBReference(MBB) 2715f757f3fSDimitry Andric << " changed to " << BBInfo.AvailableOut << "\n"); 2725f757f3fSDimitry Andric 2735f757f3fSDimitry Andric // Add the successors to the work list so that we can propagate. 2745f757f3fSDimitry Andric for (MachineBasicBlock *S : MBB.successors()) { 2755f757f3fSDimitry Andric if (!BlockInfo[S->getNumber()].InQueue) { 2765f757f3fSDimitry Andric BlockInfo[S->getNumber()].InQueue = true; 2775f757f3fSDimitry Andric WorkList.push(S); 2785f757f3fSDimitry Andric } 2795f757f3fSDimitry Andric } 2805f757f3fSDimitry Andric } 2815f757f3fSDimitry Andric 2825f757f3fSDimitry Andric void RISCVInsertWriteVXRM::computeAnticipated(const MachineBasicBlock &MBB) { 2835f757f3fSDimitry Andric BlockData &BBInfo = BlockInfo[MBB.getNumber()]; 2845f757f3fSDimitry Andric 2855f757f3fSDimitry Andric BBInfo.InQueue = false; 2865f757f3fSDimitry Andric 2875f757f3fSDimitry Andric VXRMInfo Anticipated; 2885f757f3fSDimitry Andric if (MBB.succ_empty()) { 2895f757f3fSDimitry Andric Anticipated.setUnknown(); 2905f757f3fSDimitry Andric } else { 2915f757f3fSDimitry Andric for (const MachineBasicBlock *S : MBB.successors()) 2925f757f3fSDimitry Andric Anticipated = 2935f757f3fSDimitry Andric Anticipated.intersect(BlockInfo[S->getNumber()].AnticipatedIn); 2945f757f3fSDimitry Andric } 2955f757f3fSDimitry Andric 2965f757f3fSDimitry Andric // If we don't have any valid anticipated info, wait until we do. 2975f757f3fSDimitry Andric if (!Anticipated.isValid()) 2985f757f3fSDimitry Andric return; 2995f757f3fSDimitry Andric 3005f757f3fSDimitry Andric if (Anticipated != BBInfo.AnticipatedOut) { 3015f757f3fSDimitry Andric BBInfo.AnticipatedOut = Anticipated; 3025f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "AnticipatedOut state of " << printMBBReference(MBB) 3035f757f3fSDimitry Andric << " changed to " << BBInfo.AnticipatedOut << "\n"); 3045f757f3fSDimitry Andric } 3055f757f3fSDimitry Andric 3065f757f3fSDimitry Andric // If this block reads VXRM, copy it. 3075f757f3fSDimitry Andric if (BBInfo.VXRMUse.isValid()) 3085f757f3fSDimitry Andric Anticipated = BBInfo.VXRMUse; 3095f757f3fSDimitry Andric 3105f757f3fSDimitry Andric if (Anticipated == BBInfo.AnticipatedIn) 3115f757f3fSDimitry Andric return; 3125f757f3fSDimitry Andric 3135f757f3fSDimitry Andric BBInfo.AnticipatedIn = Anticipated; 3145f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "AnticipatedIn state of " << printMBBReference(MBB) 3155f757f3fSDimitry Andric << " changed to " << BBInfo.AnticipatedIn << "\n"); 3165f757f3fSDimitry Andric 3175f757f3fSDimitry Andric // Add the predecessors to the work list so that we can propagate. 3185f757f3fSDimitry Andric for (MachineBasicBlock *P : MBB.predecessors()) { 3195f757f3fSDimitry Andric if (!BlockInfo[P->getNumber()].InQueue) { 3205f757f3fSDimitry Andric BlockInfo[P->getNumber()].InQueue = true; 3215f757f3fSDimitry Andric WorkList.push(P); 3225f757f3fSDimitry Andric } 3235f757f3fSDimitry Andric } 3245f757f3fSDimitry Andric } 3255f757f3fSDimitry Andric 3265f757f3fSDimitry Andric void RISCVInsertWriteVXRM::emitWriteVXRM(MachineBasicBlock &MBB) { 3275f757f3fSDimitry Andric const BlockData &BBInfo = BlockInfo[MBB.getNumber()]; 3285f757f3fSDimitry Andric 3295f757f3fSDimitry Andric VXRMInfo Info = BBInfo.AvailableIn; 3305f757f3fSDimitry Andric 3315f757f3fSDimitry Andric // Flag to indicates we need to insert a VXRM write. We want to delay it as 3325f757f3fSDimitry Andric // late as possible in this block. 3335f757f3fSDimitry Andric bool PendingInsert = false; 3345f757f3fSDimitry Andric 3355f757f3fSDimitry Andric // Insert VXRM write if anticipated and not available. 3365f757f3fSDimitry Andric if (BBInfo.AnticipatedIn.isStatic()) { 3375f757f3fSDimitry Andric // If this is the entry block and the value is anticipated, insert. 3385f757f3fSDimitry Andric if (MBB.isEntryBlock()) { 3395f757f3fSDimitry Andric PendingInsert = true; 3405f757f3fSDimitry Andric } else { 3415f757f3fSDimitry Andric // Search for any predecessors that wouldn't satisfy our requirement and 3425f757f3fSDimitry Andric // insert a write VXRM if needed. 3435f757f3fSDimitry Andric // NOTE: If one predecessor is able to provide the requirement, but 3445f757f3fSDimitry Andric // another isn't, it means we have a critical edge. The better placement 3455f757f3fSDimitry Andric // would be to split the critical edge. 3465f757f3fSDimitry Andric for (MachineBasicBlock *P : MBB.predecessors()) { 3475f757f3fSDimitry Andric const BlockData &PInfo = BlockInfo[P->getNumber()]; 3485f757f3fSDimitry Andric // If it's available out of the predecessor, then we're ok. 3495f757f3fSDimitry Andric if (PInfo.AvailableOut.isStatic() && 3505f757f3fSDimitry Andric PInfo.AvailableOut.getVXRMImm() == 3515f757f3fSDimitry Andric BBInfo.AnticipatedIn.getVXRMImm()) 3525f757f3fSDimitry Andric continue; 3535f757f3fSDimitry Andric // If the predecessor anticipates this value for all its succesors, 3545f757f3fSDimitry Andric // then a write to VXRM would have already occured before this block is 3555f757f3fSDimitry Andric // executed. 3565f757f3fSDimitry Andric if (PInfo.AnticipatedOut.isStatic() && 3575f757f3fSDimitry Andric PInfo.AnticipatedOut.getVXRMImm() == 3585f757f3fSDimitry Andric BBInfo.AnticipatedIn.getVXRMImm()) 3595f757f3fSDimitry Andric continue; 3605f757f3fSDimitry Andric PendingInsert = true; 3615f757f3fSDimitry Andric break; 3625f757f3fSDimitry Andric } 3635f757f3fSDimitry Andric } 3645f757f3fSDimitry Andric 3655f757f3fSDimitry Andric Info = BBInfo.AnticipatedIn; 3665f757f3fSDimitry Andric } 3675f757f3fSDimitry Andric 3685f757f3fSDimitry Andric for (MachineInstr &MI : MBB) { 3695f757f3fSDimitry Andric int VXRMIdx = RISCVII::getVXRMOpNum(MI.getDesc()); 370647cbc5dSDimitry Andric if (VXRMIdx >= 0 && !ignoresVXRM(MI)) { 3715f757f3fSDimitry Andric unsigned NewVXRMImm = MI.getOperand(VXRMIdx).getImm(); 3725f757f3fSDimitry Andric 3735f757f3fSDimitry Andric if (PendingInsert || !Info.isStatic() || 3745f757f3fSDimitry Andric Info.getVXRMImm() != NewVXRMImm) { 3755f757f3fSDimitry Andric assert((!PendingInsert || 3765f757f3fSDimitry Andric (Info.isStatic() && Info.getVXRMImm() == NewVXRMImm)) && 3775f757f3fSDimitry Andric "Pending VXRM insertion mismatch"); 3785f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Inserting before "; MI.print(dbgs())); 3795f757f3fSDimitry Andric BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(RISCV::WriteVXRMImm)) 3805f757f3fSDimitry Andric .addImm(NewVXRMImm); 3815f757f3fSDimitry Andric PendingInsert = false; 3825f757f3fSDimitry Andric } 3835f757f3fSDimitry Andric 3845f757f3fSDimitry Andric MI.addOperand(MachineOperand::CreateReg(RISCV::VXRM, /*IsDef*/ false, 3855f757f3fSDimitry Andric /*IsImp*/ true)); 3865f757f3fSDimitry Andric Info.setVXRMImm(NewVXRMImm); 3875f757f3fSDimitry Andric continue; 3885f757f3fSDimitry Andric } 3895f757f3fSDimitry Andric 390*0fca6ea1SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || 391*0fca6ea1SDimitry Andric MI.modifiesRegister(RISCV::VXRM, /*TRI=*/nullptr)) 3925f757f3fSDimitry Andric Info.setUnknown(); 3935f757f3fSDimitry Andric } 3945f757f3fSDimitry Andric 3955f757f3fSDimitry Andric // If all our successors anticipate a value, do the insert. 3965f757f3fSDimitry Andric // NOTE: It's possible that not all predecessors of our successor provide the 3975f757f3fSDimitry Andric // correct value. This can occur on critical edges. If we don't split the 3985f757f3fSDimitry Andric // critical edge we'll also have a write vxrm in the succesor that is 3995f757f3fSDimitry Andric // redundant with this one. 4005f757f3fSDimitry Andric if (PendingInsert || 4015f757f3fSDimitry Andric (BBInfo.AnticipatedOut.isStatic() && 4025f757f3fSDimitry Andric (!Info.isStatic() || 4035f757f3fSDimitry Andric Info.getVXRMImm() != BBInfo.AnticipatedOut.getVXRMImm()))) { 4045f757f3fSDimitry Andric assert((!PendingInsert || 4055f757f3fSDimitry Andric (Info.isStatic() && BBInfo.AnticipatedOut.isStatic() && 4065f757f3fSDimitry Andric Info.getVXRMImm() == BBInfo.AnticipatedOut.getVXRMImm())) && 4075f757f3fSDimitry Andric "Pending VXRM insertion mismatch"); 4085f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Inserting at end of " << printMBBReference(MBB) 4095f757f3fSDimitry Andric << " changing to " << BBInfo.AnticipatedOut << "\n"); 4105f757f3fSDimitry Andric BuildMI(MBB, MBB.getFirstTerminator(), DebugLoc(), 4115f757f3fSDimitry Andric TII->get(RISCV::WriteVXRMImm)) 4125f757f3fSDimitry Andric .addImm(BBInfo.AnticipatedOut.getVXRMImm()); 4135f757f3fSDimitry Andric } 4145f757f3fSDimitry Andric } 4155f757f3fSDimitry Andric 4165f757f3fSDimitry Andric bool RISCVInsertWriteVXRM::runOnMachineFunction(MachineFunction &MF) { 4175f757f3fSDimitry Andric // Skip if the vector extension is not enabled. 4185f757f3fSDimitry Andric const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>(); 4195f757f3fSDimitry Andric if (!ST.hasVInstructions()) 4205f757f3fSDimitry Andric return false; 4215f757f3fSDimitry Andric 4225f757f3fSDimitry Andric TII = ST.getInstrInfo(); 4235f757f3fSDimitry Andric 4245f757f3fSDimitry Andric assert(BlockInfo.empty() && "Expect empty block infos"); 4255f757f3fSDimitry Andric BlockInfo.resize(MF.getNumBlockIDs()); 4265f757f3fSDimitry Andric 4275f757f3fSDimitry Andric // Phase 1 - collect block information. 4285f757f3fSDimitry Andric bool NeedVXRMChange = false; 4295f757f3fSDimitry Andric for (const MachineBasicBlock &MBB : MF) 4305f757f3fSDimitry Andric NeedVXRMChange |= computeVXRMChanges(MBB); 4315f757f3fSDimitry Andric 4325f757f3fSDimitry Andric if (!NeedVXRMChange) { 4335f757f3fSDimitry Andric BlockInfo.clear(); 4345f757f3fSDimitry Andric return false; 4355f757f3fSDimitry Andric } 4365f757f3fSDimitry Andric 4375f757f3fSDimitry Andric // Phase 2 - Compute available VXRM using a forward walk. 4385f757f3fSDimitry Andric for (const MachineBasicBlock &MBB : MF) { 4395f757f3fSDimitry Andric WorkList.push(&MBB); 4405f757f3fSDimitry Andric BlockInfo[MBB.getNumber()].InQueue = true; 4415f757f3fSDimitry Andric } 4425f757f3fSDimitry Andric while (!WorkList.empty()) { 4435f757f3fSDimitry Andric const MachineBasicBlock &MBB = *WorkList.front(); 4445f757f3fSDimitry Andric WorkList.pop(); 4455f757f3fSDimitry Andric computeAvailable(MBB); 4465f757f3fSDimitry Andric } 4475f757f3fSDimitry Andric 4485f757f3fSDimitry Andric // Phase 3 - Compute anticipated VXRM using a backwards walk. 4495f757f3fSDimitry Andric for (const MachineBasicBlock &MBB : llvm::reverse(MF)) { 4505f757f3fSDimitry Andric WorkList.push(&MBB); 4515f757f3fSDimitry Andric BlockInfo[MBB.getNumber()].InQueue = true; 4525f757f3fSDimitry Andric } 4535f757f3fSDimitry Andric while (!WorkList.empty()) { 4545f757f3fSDimitry Andric const MachineBasicBlock &MBB = *WorkList.front(); 4555f757f3fSDimitry Andric WorkList.pop(); 4565f757f3fSDimitry Andric computeAnticipated(MBB); 4575f757f3fSDimitry Andric } 4585f757f3fSDimitry Andric 4595f757f3fSDimitry Andric // Phase 4 - Emit VXRM writes at the earliest place possible. 4605f757f3fSDimitry Andric for (MachineBasicBlock &MBB : MF) 4615f757f3fSDimitry Andric emitWriteVXRM(MBB); 4625f757f3fSDimitry Andric 4635f757f3fSDimitry Andric BlockInfo.clear(); 4645f757f3fSDimitry Andric 4655f757f3fSDimitry Andric return true; 4665f757f3fSDimitry Andric } 4675f757f3fSDimitry Andric 4685f757f3fSDimitry Andric FunctionPass *llvm::createRISCVInsertWriteVXRMPass() { 4695f757f3fSDimitry Andric return new RISCVInsertWriteVXRM(); 4705f757f3fSDimitry Andric } 471