xref: /freebsd/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVMoveMerger.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
1  //===-- RISCVMoveMerger.cpp - RISC-V move merge pass ----------------------===//
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  // This file contains a pass that performs move related peephole optimizations
10  // as Zcmp has specified. This pass should be run after register allocation.
11  //
12  //===----------------------------------------------------------------------===//
13  
14  #include "RISCVInstrInfo.h"
15  #include "RISCVMachineFunctionInfo.h"
16  
17  using namespace llvm;
18  
19  #define RISCV_MOVE_MERGE_NAME "RISC-V Zcmp move merging pass"
20  
21  namespace {
22  struct RISCVMoveMerge : public MachineFunctionPass {
23    static char ID;
24  
25    RISCVMoveMerge() : MachineFunctionPass(ID) {}
26  
27    const RISCVInstrInfo *TII;
28    const TargetRegisterInfo *TRI;
29  
30    // Track which register units have been modified and used.
31    LiveRegUnits ModifiedRegUnits, UsedRegUnits;
32  
33    bool isCandidateToMergeMVA01S(const DestSourcePair &RegPair);
34    bool isCandidateToMergeMVSA01(const DestSourcePair &RegPair);
35    // Merge the two instructions indicated into a single pair instruction.
36    MachineBasicBlock::iterator
37    mergePairedInsns(MachineBasicBlock::iterator I,
38                     MachineBasicBlock::iterator Paired, unsigned Opcode);
39  
40    // Look for C.MV instruction that can be combined with
41    // the given instruction into CM.MVA01S or CM.MVSA01. Return the matching
42    // instruction if one exists.
43    MachineBasicBlock::iterator
44    findMatchingInst(MachineBasicBlock::iterator &MBBI, unsigned InstOpcode,
45                     const DestSourcePair &RegPair);
46    bool mergeMoveSARegPair(MachineBasicBlock &MBB);
47    bool runOnMachineFunction(MachineFunction &Fn) override;
48  
49    StringRef getPassName() const override { return RISCV_MOVE_MERGE_NAME; }
50  };
51  
52  char RISCVMoveMerge::ID = 0;
53  
54  } // end of anonymous namespace
55  
56  INITIALIZE_PASS(RISCVMoveMerge, "riscv-move-merge", RISCV_MOVE_MERGE_NAME,
57                  false, false)
58  
59  // Check if registers meet CM.MVA01S constraints.
60  bool RISCVMoveMerge::isCandidateToMergeMVA01S(const DestSourcePair &RegPair) {
61    Register Destination = RegPair.Destination->getReg();
62    Register Source = RegPair.Source->getReg();
63    // If destination is not a0 or a1.
64    if ((Destination == RISCV::X10 || Destination == RISCV::X11) &&
65        RISCV::SR07RegClass.contains(Source))
66      return true;
67    return false;
68  }
69  
70  // Check if registers meet CM.MVSA01 constraints.
71  bool RISCVMoveMerge::isCandidateToMergeMVSA01(const DestSourcePair &RegPair) {
72    Register Destination = RegPair.Destination->getReg();
73    Register Source = RegPair.Source->getReg();
74    // If Source is s0 - s7.
75    if ((Source == RISCV::X10 || Source == RISCV::X11) &&
76        RISCV::SR07RegClass.contains(Destination))
77      return true;
78    return false;
79  }
80  
81  MachineBasicBlock::iterator
82  RISCVMoveMerge::mergePairedInsns(MachineBasicBlock::iterator I,
83                                   MachineBasicBlock::iterator Paired,
84                                   unsigned Opcode) {
85    const MachineOperand *Sreg1, *Sreg2;
86    MachineBasicBlock::iterator E = I->getParent()->end();
87    MachineBasicBlock::iterator NextI = next_nodbg(I, E);
88    DestSourcePair FirstPair = TII->isCopyInstrImpl(*I).value();
89    DestSourcePair PairedRegs = TII->isCopyInstrImpl(*Paired).value();
90    Register ARegInFirstPair = Opcode == RISCV::CM_MVA01S
91                                   ? FirstPair.Destination->getReg()
92                                   : FirstPair.Source->getReg();
93  
94    if (NextI == Paired)
95      NextI = next_nodbg(NextI, E);
96    DebugLoc DL = I->getDebugLoc();
97  
98    // The order of S-reg depends on which instruction holds A0, instead of
99    // the order of register pair.
100    // e,g.
101    //   mv a1, s1
102    //   mv a0, s2    =>  cm.mva01s s2,s1
103    //
104    //   mv a0, s2
105    //   mv a1, s1    =>  cm.mva01s s2,s1
106    bool StartWithX10 = ARegInFirstPair == RISCV::X10;
107    if (Opcode == RISCV::CM_MVA01S) {
108      Sreg1 = StartWithX10 ? FirstPair.Source : PairedRegs.Source;
109      Sreg2 = StartWithX10 ? PairedRegs.Source : FirstPair.Source;
110    } else {
111      Sreg1 = StartWithX10 ? FirstPair.Destination : PairedRegs.Destination;
112      Sreg2 = StartWithX10 ? PairedRegs.Destination : FirstPair.Destination;
113    }
114  
115    BuildMI(*I->getParent(), I, DL, TII->get(Opcode)).add(*Sreg1).add(*Sreg2);
116  
117    I->eraseFromParent();
118    Paired->eraseFromParent();
119    return NextI;
120  }
121  
122  MachineBasicBlock::iterator
123  RISCVMoveMerge::findMatchingInst(MachineBasicBlock::iterator &MBBI,
124                                   unsigned InstOpcode,
125                                   const DestSourcePair &RegPair) {
126    MachineBasicBlock::iterator E = MBBI->getParent()->end();
127  
128    // Track which register units have been modified and used between the first
129    // insn and the second insn.
130    ModifiedRegUnits.clear();
131    UsedRegUnits.clear();
132  
133    for (MachineBasicBlock::iterator I = next_nodbg(MBBI, E); I != E;
134         I = next_nodbg(I, E)) {
135  
136      MachineInstr &MI = *I;
137  
138      if (auto SecondPair = TII->isCopyInstrImpl(MI)) {
139        Register SourceReg = SecondPair->Source->getReg();
140        Register DestReg = SecondPair->Destination->getReg();
141  
142        if (InstOpcode == RISCV::CM_MVA01S &&
143            isCandidateToMergeMVA01S(*SecondPair)) {
144          // If register pair is valid and destination registers are different.
145          if ((RegPair.Destination->getReg() == DestReg))
146            return E;
147  
148          //  If paired destination register was modified or used, the source reg
149          //  was modified, there is no possibility of finding matching
150          //  instruction so exit early.
151          if (!ModifiedRegUnits.available(DestReg) ||
152              !UsedRegUnits.available(DestReg) ||
153              !ModifiedRegUnits.available(SourceReg))
154            return E;
155  
156          return I;
157        } else if (InstOpcode == RISCV::CM_MVSA01 &&
158                   isCandidateToMergeMVSA01(*SecondPair)) {
159          if ((RegPair.Source->getReg() == SourceReg) ||
160              (RegPair.Destination->getReg() == DestReg))
161            return E;
162  
163          if (!ModifiedRegUnits.available(DestReg) ||
164              !UsedRegUnits.available(DestReg) ||
165              !ModifiedRegUnits.available(SourceReg))
166            return E;
167  
168          return I;
169        }
170      }
171      // Update modified / used register units.
172      LiveRegUnits::accumulateUsedDefed(MI, ModifiedRegUnits, UsedRegUnits, TRI);
173    }
174    return E;
175  }
176  
177  // Finds instructions, which could be represented as C.MV instructions and
178  // merged into CM.MVA01S or CM.MVSA01.
179  bool RISCVMoveMerge::mergeMoveSARegPair(MachineBasicBlock &MBB) {
180    bool Modified = false;
181  
182    for (MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
183         MBBI != E;) {
184      // Check if the instruction can be compressed to C.MV instruction. If it
185      // can, return Dest/Src register pair.
186      auto RegPair = TII->isCopyInstrImpl(*MBBI);
187      if (RegPair.has_value()) {
188        unsigned Opcode = 0;
189  
190        if (isCandidateToMergeMVA01S(*RegPair))
191          Opcode = RISCV::CM_MVA01S;
192        else if (isCandidateToMergeMVSA01(*RegPair))
193          Opcode = RISCV::CM_MVSA01;
194        else {
195          ++MBBI;
196          continue;
197        }
198  
199        MachineBasicBlock::iterator Paired =
200            findMatchingInst(MBBI, Opcode, RegPair.value());
201        // If matching instruction can be found merge them.
202        if (Paired != E) {
203          MBBI = mergePairedInsns(MBBI, Paired, Opcode);
204          Modified = true;
205          continue;
206        }
207      }
208      ++MBBI;
209    }
210    return Modified;
211  }
212  
213  bool RISCVMoveMerge::runOnMachineFunction(MachineFunction &Fn) {
214    if (skipFunction(Fn.getFunction()))
215      return false;
216  
217    const RISCVSubtarget *Subtarget = &Fn.getSubtarget<RISCVSubtarget>();
218    if (!Subtarget->hasStdExtZcmp())
219      return false;
220  
221    TII = Subtarget->getInstrInfo();
222    TRI = Subtarget->getRegisterInfo();
223    // Resize the modified and used register unit trackers.  We do this once
224    // per function and then clear the register units each time we optimize a
225    // move.
226    ModifiedRegUnits.init(*TRI);
227    UsedRegUnits.init(*TRI);
228    bool Modified = false;
229    for (auto &MBB : Fn)
230      Modified |= mergeMoveSARegPair(MBB);
231    return Modified;
232  }
233  
234  /// createRISCVMoveMergePass - returns an instance of the
235  /// move merge pass.
236  FunctionPass *llvm::createRISCVMoveMergePass() { return new RISCVMoveMerge(); }
237