LLVM 22.0.0git
RISCVVectorMaskDAGMutation.cpp
Go to the documentation of this file.
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// If there are multiple masks producers followed by multiple masked
14// instructions, then at each masked instructions add dependency edges between
15// every producer and masked instruction.
16//
17// The reason why we need to do this:
18// 1. When tracking register pressure, we don't track physical registers.
19// 2. We have a RegisterClass for mask register (which is `VMV0`), but we don't
20// use it by the time we reach scheduling. Instead, we use physical
21// register V0 directly and insert a `$v0 = COPY ...` before the use.
22// 3. For mask producers, we are using VR RegisterClass (we can allocate V0-V31
23// to it). So if V0 is not available, there are still 31 available registers
24// out there.
25//
26// This means that the RegPressureTracker can't track the pressure of mask
27// registers correctly.
28//
29// This schedule mutation is a workaround to fix this issue.
30//
31//===----------------------------------------------------------------------===//
32
35#include "RISCVTargetMachine.h"
41
42#define DEBUG_TYPE "machine-scheduler"
43
44namespace llvm {
45
46static bool isCopyToV0(const MachineInstr &MI) {
47 return MI.isFullCopy() && MI.getOperand(0).getReg() == RISCV::V0 &&
48 MI.getOperand(1).getReg().isVirtual();
49}
50
51static bool isSoleUseCopyToV0(SUnit &SU) {
52 if (SU.Succs.size() != 1)
53 return false;
54 SDep &Dep = SU.Succs[0];
55 // Ignore dependencies other than data or strong ordering.
56 if (Dep.isWeak())
57 return false;
58
59 SUnit &DepSU = *Dep.getSUnit();
60 if (DepSU.isBoundaryNode())
61 return false;
62 return isCopyToV0(*DepSU.getInstr());
63}
64
66private:
67 const TargetRegisterInfo *TRI;
68
69public:
71
72 void apply(ScheduleDAGInstrs *DAG) override {
73 SUnit *NearestUseV0SU = nullptr;
75 for (SUnit &SU : DAG->SUnits) {
76 const MachineInstr *MI = SU.getInstr();
77 bool UseV0 = MI->findRegisterUseOperand(RISCV::V0, TRI);
78 if (isSoleUseCopyToV0(SU) && !UseV0)
79 DefMask.push_back(&SU);
80
81 if (UseV0) {
82 NearestUseV0SU = &SU;
83
84 // Copy may not be a real use, so skip it here.
85 if (DefMask.size() > 1 && !MI->isCopy()) {
86 for (SUnit *Def : DefMask)
87 if (DAG->canAddEdge(Def, &SU))
88 DAG->addEdge(Def, SDep(&SU, SDep::Artificial));
89 }
90
91 if (!DefMask.empty())
92 DefMask.erase(DefMask.begin());
93 }
94
95 if (NearestUseV0SU && NearestUseV0SU != &SU && isSoleUseCopyToV0(SU) &&
96 // For LMUL=8 cases, there will be more possibilities to spill.
97 // FIXME: We should use RegPressureTracker to do fine-grained
98 // controls.
99 RISCVII::getLMul(MI->getDesc().TSFlags) != RISCVVType::LMUL_8)
100 DAG->addEdge(&SU, SDep(NearestUseV0SU, SDep::Artificial));
101 }
102 }
103};
104
105std::unique_ptr<ScheduleDAGMutation>
107 return std::make_unique<RISCVVectorMaskDAGMutation>(TRI);
108}
109
110} // namespace llvm
IRTranslator LLVM IR MI
Register const TargetRegisterInfo * TRI
Representation of each machine instruction.
Definition: MachineInstr.h:72
RISCVVectorMaskDAGMutation(const TargetRegisterInfo *TRI)
void apply(ScheduleDAGInstrs *DAG) override
Scheduling dependency.
Definition: ScheduleDAG.h:51
SUnit * getSUnit() const
Definition: ScheduleDAG.h:507
bool isWeak() const
Tests if this a weak dependence.
Definition: ScheduleDAG.h:194
@ Artificial
Arbitrary strong DAG edge (no real dependence).
Definition: ScheduleDAG.h:74
Scheduling unit. This is a node in the scheduling DAG.
Definition: ScheduleDAG.h:249
bool isBoundaryNode() const
Boundary nodes are placeholders for the boundary of the scheduling region.
Definition: ScheduleDAG.h:367
SmallVector< SDep, 4 > Succs
All sunit successors.
Definition: ScheduleDAG.h:270
MachineInstr * getInstr() const
Returns the representative MachineInstr for this SUnit.
Definition: ScheduleDAG.h:399
A ScheduleDAG for scheduling lists of MachineInstr.
bool addEdge(SUnit *SuccSU, const SDep &PredDep)
Add a DAG edge to the given SU with the given predecessor dependence data.
bool canAddEdge(SUnit *SuccSU, SUnit *PredSU)
True if an edge can be added from PredSU to SuccSU without creating a cycle.
Mutate the DAG as a postpass after normal DAG building.
std::vector< SUnit > SUnits
The scheduling units.
Definition: ScheduleDAG.h:588
bool empty() const
Definition: SmallVector.h:82
size_t size() const
Definition: SmallVector.h:79
iterator erase(const_iterator CI)
Definition: SmallVector.h:738
void push_back(const T &Elt)
Definition: SmallVector.h:414
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
static RISCVVType::VLMUL getLMul(uint64_t TSFlags)
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
std::unique_ptr< ScheduleDAGMutation > createRISCVVectorMaskDAGMutation(const TargetRegisterInfo *TRI)
static bool isCopyToV0(const MachineInstr &MI)
static bool isSoleUseCopyToV0(SUnit &SU)