1 //===- RISCVVectorMaskDAGMutation.cpp - RISC-V Vector Mask DAGMutation ----===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // A schedule mutation that adds an artificial dependency between masks producer 10 // instructions and masked instructions, so that we can reduce the live range 11 // overlaps of mask registers. 12 // 13 // The reason why we need to do this: 14 // 1. When tracking register pressure, we don't track physical registers. 15 // 2. We have a RegisterClass for mask register (which is `VMV0`), but we don't 16 // use it by the time we reach scheduling. Instead, we use physical 17 // register V0 directly and insert a `$v0 = COPY ...` before the use. 18 // 3. For mask producers, we are using VR RegisterClass (we can allocate V0-V31 19 // to it). So if V0 is not available, there are still 31 available registers 20 // out there. 21 // 22 // This means that the RegPressureTracker can't track the pressure of mask 23 // registers correctly. 24 // 25 // This schedule mutation is a workaround to fix this issue. 26 // 27 //===----------------------------------------------------------------------===// 28 29 #include "MCTargetDesc/RISCVBaseInfo.h" 30 #include "MCTargetDesc/RISCVMCTargetDesc.h" 31 #include "RISCVTargetMachine.h" 32 #include "llvm/CodeGen/LiveIntervals.h" 33 #include "llvm/CodeGen/MachineInstr.h" 34 #include "llvm/CodeGen/ScheduleDAGInstrs.h" 35 #include "llvm/CodeGen/ScheduleDAGMutation.h" 36 #include "llvm/TargetParser/RISCVTargetParser.h" 37 38 #define DEBUG_TYPE "machine-scheduler" 39 40 namespace llvm { 41 42 static bool isCopyToV0(const MachineInstr &MI) { 43 return MI.isFullCopy() && MI.getOperand(0).getReg() == RISCV::V0 && 44 MI.getOperand(1).getReg().isVirtual(); 45 } 46 47 static bool isSoleUseCopyToV0(SUnit &SU) { 48 if (SU.Succs.size() != 1) 49 return false; 50 SDep &Dep = SU.Succs[0]; 51 // Ignore dependencies other than data or strong ordering. 52 if (Dep.isWeak()) 53 return false; 54 55 SUnit &DepSU = *Dep.getSUnit(); 56 if (DepSU.isBoundaryNode()) 57 return false; 58 return isCopyToV0(*DepSU.getInstr()); 59 } 60 61 class RISCVVectorMaskDAGMutation : public ScheduleDAGMutation { 62 private: 63 const TargetRegisterInfo *TRI; 64 65 public: 66 RISCVVectorMaskDAGMutation(const TargetRegisterInfo *TRI) : TRI(TRI) {} 67 68 void apply(ScheduleDAGInstrs *DAG) override { 69 SUnit *NearestUseV0SU = nullptr; 70 for (SUnit &SU : DAG->SUnits) { 71 const MachineInstr *MI = SU.getInstr(); 72 if (MI->findRegisterUseOperand(RISCV::V0, TRI)) 73 NearestUseV0SU = &SU; 74 75 if (NearestUseV0SU && NearestUseV0SU != &SU && isSoleUseCopyToV0(SU) && 76 // For LMUL=8 cases, there will be more possibilities to spill. 77 // FIXME: We should use RegPressureTracker to do fine-grained 78 // controls. 79 RISCVII::getLMul(MI->getDesc().TSFlags) != RISCVVType::LMUL_8) 80 DAG->addEdge(&SU, SDep(NearestUseV0SU, SDep::Artificial)); 81 } 82 } 83 }; 84 85 std::unique_ptr<ScheduleDAGMutation> 86 createRISCVVectorMaskDAGMutation(const TargetRegisterInfo *TRI) { 87 return std::make_unique<RISCVVectorMaskDAGMutation>(TRI); 88 } 89 90 } // namespace llvm 91