xref: /freebsd/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVVectorMaskDAGMutation.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 
isCopyToV0(const MachineInstr & MI)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 
isSoleUseCopyToV0(SUnit & SU)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:
RISCVVectorMaskDAGMutation(const TargetRegisterInfo * TRI)66   RISCVVectorMaskDAGMutation(const TargetRegisterInfo *TRI) : TRI(TRI) {}
67 
apply(ScheduleDAGInstrs * DAG)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>
createRISCVVectorMaskDAGMutation(const TargetRegisterInfo * TRI)86 createRISCVVectorMaskDAGMutation(const TargetRegisterInfo *TRI) {
87   return std::make_unique<RISCVVectorMaskDAGMutation>(TRI);
88 }
89 
90 } // namespace llvm
91