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