xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVInsertWriteVXRM.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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