xref: /freebsd/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVMoveMerger.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
1*5f757f3fSDimitry Andric //===-- RISCVMoveMerger.cpp - RISC-V move merge pass ----------------------===//
206c3fb27SDimitry Andric //
306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606c3fb27SDimitry Andric //
706c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
806c3fb27SDimitry Andric //
906c3fb27SDimitry Andric // This file contains a pass that performs move related peephole optimizations
1006c3fb27SDimitry Andric // as Zcmp has specified. This pass should be run after register allocation.
1106c3fb27SDimitry Andric //
1206c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
1306c3fb27SDimitry Andric 
1406c3fb27SDimitry Andric #include "RISCVInstrInfo.h"
1506c3fb27SDimitry Andric #include "RISCVMachineFunctionInfo.h"
1606c3fb27SDimitry Andric 
1706c3fb27SDimitry Andric using namespace llvm;
1806c3fb27SDimitry Andric 
1906c3fb27SDimitry Andric #define RISCV_MOVE_MERGE_NAME "RISC-V Zcmp move merging pass"
2006c3fb27SDimitry Andric 
2106c3fb27SDimitry Andric namespace {
2206c3fb27SDimitry Andric struct RISCVMoveMerge : public MachineFunctionPass {
2306c3fb27SDimitry Andric   static char ID;
2406c3fb27SDimitry Andric 
25*5f757f3fSDimitry Andric   RISCVMoveMerge() : MachineFunctionPass(ID) {}
2606c3fb27SDimitry Andric 
2706c3fb27SDimitry Andric   const RISCVInstrInfo *TII;
2806c3fb27SDimitry Andric   const TargetRegisterInfo *TRI;
2906c3fb27SDimitry Andric 
3006c3fb27SDimitry Andric   // Track which register units have been modified and used.
3106c3fb27SDimitry Andric   LiveRegUnits ModifiedRegUnits, UsedRegUnits;
3206c3fb27SDimitry Andric 
3306c3fb27SDimitry Andric   bool isCandidateToMergeMVA01S(const DestSourcePair &RegPair);
3406c3fb27SDimitry Andric   bool isCandidateToMergeMVSA01(const DestSourcePair &RegPair);
3506c3fb27SDimitry Andric   // Merge the two instructions indicated into a single pair instruction.
3606c3fb27SDimitry Andric   MachineBasicBlock::iterator
3706c3fb27SDimitry Andric   mergePairedInsns(MachineBasicBlock::iterator I,
3806c3fb27SDimitry Andric                    MachineBasicBlock::iterator Paired, unsigned Opcode);
3906c3fb27SDimitry Andric 
4006c3fb27SDimitry Andric   // Look for C.MV instruction that can be combined with
4106c3fb27SDimitry Andric   // the given instruction into CM.MVA01S or CM.MVSA01. Return the matching
4206c3fb27SDimitry Andric   // instruction if one exists.
4306c3fb27SDimitry Andric   MachineBasicBlock::iterator
4406c3fb27SDimitry Andric   findMatchingInst(MachineBasicBlock::iterator &MBBI, unsigned InstOpcode,
4506c3fb27SDimitry Andric                    const DestSourcePair &RegPair);
4606c3fb27SDimitry Andric   bool mergeMoveSARegPair(MachineBasicBlock &MBB);
4706c3fb27SDimitry Andric   bool runOnMachineFunction(MachineFunction &Fn) override;
4806c3fb27SDimitry Andric 
4906c3fb27SDimitry Andric   StringRef getPassName() const override { return RISCV_MOVE_MERGE_NAME; }
5006c3fb27SDimitry Andric };
5106c3fb27SDimitry Andric 
5206c3fb27SDimitry Andric char RISCVMoveMerge::ID = 0;
5306c3fb27SDimitry Andric 
5406c3fb27SDimitry Andric } // end of anonymous namespace
5506c3fb27SDimitry Andric 
5606c3fb27SDimitry Andric INITIALIZE_PASS(RISCVMoveMerge, "riscv-move-merge", RISCV_MOVE_MERGE_NAME,
5706c3fb27SDimitry Andric                 false, false)
5806c3fb27SDimitry Andric 
5906c3fb27SDimitry Andric // Check if registers meet CM.MVA01S constraints.
6006c3fb27SDimitry Andric bool RISCVMoveMerge::isCandidateToMergeMVA01S(const DestSourcePair &RegPair) {
6106c3fb27SDimitry Andric   Register Destination = RegPair.Destination->getReg();
6206c3fb27SDimitry Andric   Register Source = RegPair.Source->getReg();
6306c3fb27SDimitry Andric   // If destination is not a0 or a1.
6406c3fb27SDimitry Andric   if ((Destination == RISCV::X10 || Destination == RISCV::X11) &&
6506c3fb27SDimitry Andric       RISCV::SR07RegClass.contains(Source))
6606c3fb27SDimitry Andric     return true;
6706c3fb27SDimitry Andric   return false;
6806c3fb27SDimitry Andric }
6906c3fb27SDimitry Andric 
7006c3fb27SDimitry Andric // Check if registers meet CM.MVSA01 constraints.
7106c3fb27SDimitry Andric bool RISCVMoveMerge::isCandidateToMergeMVSA01(const DestSourcePair &RegPair) {
7206c3fb27SDimitry Andric   Register Destination = RegPair.Destination->getReg();
7306c3fb27SDimitry Andric   Register Source = RegPair.Source->getReg();
7406c3fb27SDimitry Andric   // If Source is s0 - s7.
7506c3fb27SDimitry Andric   if ((Source == RISCV::X10 || Source == RISCV::X11) &&
7606c3fb27SDimitry Andric       RISCV::SR07RegClass.contains(Destination))
7706c3fb27SDimitry Andric     return true;
7806c3fb27SDimitry Andric   return false;
7906c3fb27SDimitry Andric }
8006c3fb27SDimitry Andric 
8106c3fb27SDimitry Andric MachineBasicBlock::iterator
8206c3fb27SDimitry Andric RISCVMoveMerge::mergePairedInsns(MachineBasicBlock::iterator I,
8306c3fb27SDimitry Andric                                  MachineBasicBlock::iterator Paired,
8406c3fb27SDimitry Andric                                  unsigned Opcode) {
8506c3fb27SDimitry Andric   const MachineOperand *Sreg1, *Sreg2;
8606c3fb27SDimitry Andric   MachineBasicBlock::iterator E = I->getParent()->end();
8706c3fb27SDimitry Andric   MachineBasicBlock::iterator NextI = next_nodbg(I, E);
8806c3fb27SDimitry Andric   DestSourcePair FirstPair = TII->isCopyInstrImpl(*I).value();
8906c3fb27SDimitry Andric   DestSourcePair PairedRegs = TII->isCopyInstrImpl(*Paired).value();
9006c3fb27SDimitry Andric   Register ARegInFirstPair = Opcode == RISCV::CM_MVA01S
9106c3fb27SDimitry Andric                                  ? FirstPair.Destination->getReg()
9206c3fb27SDimitry Andric                                  : FirstPair.Source->getReg();
9306c3fb27SDimitry Andric 
9406c3fb27SDimitry Andric   if (NextI == Paired)
9506c3fb27SDimitry Andric     NextI = next_nodbg(NextI, E);
9606c3fb27SDimitry Andric   DebugLoc DL = I->getDebugLoc();
9706c3fb27SDimitry Andric 
9806c3fb27SDimitry Andric   // The order of S-reg depends on which instruction holds A0, instead of
9906c3fb27SDimitry Andric   // the order of register pair.
10006c3fb27SDimitry Andric   // e,g.
10106c3fb27SDimitry Andric   //   mv a1, s1
10206c3fb27SDimitry Andric   //   mv a0, s2    =>  cm.mva01s s2,s1
10306c3fb27SDimitry Andric   //
10406c3fb27SDimitry Andric   //   mv a0, s2
10506c3fb27SDimitry Andric   //   mv a1, s1    =>  cm.mva01s s2,s1
10606c3fb27SDimitry Andric   bool StartWithX10 = ARegInFirstPair == RISCV::X10;
10706c3fb27SDimitry Andric   if (Opcode == RISCV::CM_MVA01S) {
10806c3fb27SDimitry Andric     Sreg1 = StartWithX10 ? FirstPair.Source : PairedRegs.Source;
10906c3fb27SDimitry Andric     Sreg2 = StartWithX10 ? PairedRegs.Source : FirstPair.Source;
11006c3fb27SDimitry Andric   } else {
11106c3fb27SDimitry Andric     Sreg1 = StartWithX10 ? FirstPair.Destination : PairedRegs.Destination;
11206c3fb27SDimitry Andric     Sreg2 = StartWithX10 ? PairedRegs.Destination : FirstPair.Destination;
11306c3fb27SDimitry Andric   }
11406c3fb27SDimitry Andric 
11506c3fb27SDimitry Andric   BuildMI(*I->getParent(), I, DL, TII->get(Opcode)).add(*Sreg1).add(*Sreg2);
11606c3fb27SDimitry Andric 
11706c3fb27SDimitry Andric   I->eraseFromParent();
11806c3fb27SDimitry Andric   Paired->eraseFromParent();
11906c3fb27SDimitry Andric   return NextI;
12006c3fb27SDimitry Andric }
12106c3fb27SDimitry Andric 
12206c3fb27SDimitry Andric MachineBasicBlock::iterator
12306c3fb27SDimitry Andric RISCVMoveMerge::findMatchingInst(MachineBasicBlock::iterator &MBBI,
12406c3fb27SDimitry Andric                                  unsigned InstOpcode,
12506c3fb27SDimitry Andric                                  const DestSourcePair &RegPair) {
12606c3fb27SDimitry Andric   MachineBasicBlock::iterator E = MBBI->getParent()->end();
12706c3fb27SDimitry Andric 
12806c3fb27SDimitry Andric   // Track which register units have been modified and used between the first
12906c3fb27SDimitry Andric   // insn and the second insn.
13006c3fb27SDimitry Andric   ModifiedRegUnits.clear();
13106c3fb27SDimitry Andric   UsedRegUnits.clear();
13206c3fb27SDimitry Andric 
13306c3fb27SDimitry Andric   for (MachineBasicBlock::iterator I = next_nodbg(MBBI, E); I != E;
13406c3fb27SDimitry Andric        I = next_nodbg(I, E)) {
13506c3fb27SDimitry Andric 
13606c3fb27SDimitry Andric     MachineInstr &MI = *I;
13706c3fb27SDimitry Andric 
13806c3fb27SDimitry Andric     if (auto SecondPair = TII->isCopyInstrImpl(MI)) {
13906c3fb27SDimitry Andric       Register SourceReg = SecondPair->Source->getReg();
14006c3fb27SDimitry Andric       Register DestReg = SecondPair->Destination->getReg();
14106c3fb27SDimitry Andric 
14206c3fb27SDimitry Andric       if (InstOpcode == RISCV::CM_MVA01S &&
14306c3fb27SDimitry Andric           isCandidateToMergeMVA01S(*SecondPair)) {
14406c3fb27SDimitry Andric         // If register pair is valid and destination registers are different.
14506c3fb27SDimitry Andric         if ((RegPair.Destination->getReg() == DestReg))
14606c3fb27SDimitry Andric           return E;
14706c3fb27SDimitry Andric 
14806c3fb27SDimitry Andric         //  If paired destination register was modified or used, the source reg
14906c3fb27SDimitry Andric         //  was modified, there is no possibility of finding matching
15006c3fb27SDimitry Andric         //  instruction so exit early.
15106c3fb27SDimitry Andric         if (!ModifiedRegUnits.available(DestReg) ||
15206c3fb27SDimitry Andric             !UsedRegUnits.available(DestReg) ||
15306c3fb27SDimitry Andric             !ModifiedRegUnits.available(SourceReg))
15406c3fb27SDimitry Andric           return E;
15506c3fb27SDimitry Andric 
15606c3fb27SDimitry Andric         return I;
15706c3fb27SDimitry Andric       } else if (InstOpcode == RISCV::CM_MVSA01 &&
15806c3fb27SDimitry Andric                  isCandidateToMergeMVSA01(*SecondPair)) {
15906c3fb27SDimitry Andric         if ((RegPair.Source->getReg() == SourceReg) ||
16006c3fb27SDimitry Andric             (RegPair.Destination->getReg() == DestReg))
16106c3fb27SDimitry Andric           return E;
16206c3fb27SDimitry Andric 
16306c3fb27SDimitry Andric         if (!ModifiedRegUnits.available(DestReg) ||
16406c3fb27SDimitry Andric             !UsedRegUnits.available(DestReg) ||
16506c3fb27SDimitry Andric             !ModifiedRegUnits.available(SourceReg))
16606c3fb27SDimitry Andric           return E;
16706c3fb27SDimitry Andric 
16806c3fb27SDimitry Andric         return I;
16906c3fb27SDimitry Andric       }
17006c3fb27SDimitry Andric     }
17106c3fb27SDimitry Andric     // Update modified / used register units.
17206c3fb27SDimitry Andric     LiveRegUnits::accumulateUsedDefed(MI, ModifiedRegUnits, UsedRegUnits, TRI);
17306c3fb27SDimitry Andric   }
17406c3fb27SDimitry Andric   return E;
17506c3fb27SDimitry Andric }
17606c3fb27SDimitry Andric 
17706c3fb27SDimitry Andric // Finds instructions, which could be represented as C.MV instructions and
17806c3fb27SDimitry Andric // merged into CM.MVA01S or CM.MVSA01.
17906c3fb27SDimitry Andric bool RISCVMoveMerge::mergeMoveSARegPair(MachineBasicBlock &MBB) {
18006c3fb27SDimitry Andric   bool Modified = false;
18106c3fb27SDimitry Andric 
18206c3fb27SDimitry Andric   for (MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
18306c3fb27SDimitry Andric        MBBI != E;) {
18406c3fb27SDimitry Andric     // Check if the instruction can be compressed to C.MV instruction. If it
18506c3fb27SDimitry Andric     // can, return Dest/Src register pair.
18606c3fb27SDimitry Andric     auto RegPair = TII->isCopyInstrImpl(*MBBI);
18706c3fb27SDimitry Andric     if (RegPair.has_value()) {
18806c3fb27SDimitry Andric       unsigned Opcode = 0;
18906c3fb27SDimitry Andric 
19006c3fb27SDimitry Andric       if (isCandidateToMergeMVA01S(*RegPair))
19106c3fb27SDimitry Andric         Opcode = RISCV::CM_MVA01S;
19206c3fb27SDimitry Andric       else if (isCandidateToMergeMVSA01(*RegPair))
19306c3fb27SDimitry Andric         Opcode = RISCV::CM_MVSA01;
19406c3fb27SDimitry Andric       else {
19506c3fb27SDimitry Andric         ++MBBI;
19606c3fb27SDimitry Andric         continue;
19706c3fb27SDimitry Andric       }
19806c3fb27SDimitry Andric 
19906c3fb27SDimitry Andric       MachineBasicBlock::iterator Paired =
20006c3fb27SDimitry Andric           findMatchingInst(MBBI, Opcode, RegPair.value());
20106c3fb27SDimitry Andric       // If matching instruction can be found merge them.
20206c3fb27SDimitry Andric       if (Paired != E) {
20306c3fb27SDimitry Andric         MBBI = mergePairedInsns(MBBI, Paired, Opcode);
20406c3fb27SDimitry Andric         Modified = true;
20506c3fb27SDimitry Andric         continue;
20606c3fb27SDimitry Andric       }
20706c3fb27SDimitry Andric     }
20806c3fb27SDimitry Andric     ++MBBI;
20906c3fb27SDimitry Andric   }
21006c3fb27SDimitry Andric   return Modified;
21106c3fb27SDimitry Andric }
21206c3fb27SDimitry Andric 
21306c3fb27SDimitry Andric bool RISCVMoveMerge::runOnMachineFunction(MachineFunction &Fn) {
21406c3fb27SDimitry Andric   if (skipFunction(Fn.getFunction()))
21506c3fb27SDimitry Andric     return false;
21606c3fb27SDimitry Andric 
21706c3fb27SDimitry Andric   const RISCVSubtarget *Subtarget = &Fn.getSubtarget<RISCVSubtarget>();
21806c3fb27SDimitry Andric   if (!Subtarget->hasStdExtZcmp())
21906c3fb27SDimitry Andric     return false;
22006c3fb27SDimitry Andric 
22106c3fb27SDimitry Andric   TII = Subtarget->getInstrInfo();
22206c3fb27SDimitry Andric   TRI = Subtarget->getRegisterInfo();
22306c3fb27SDimitry Andric   // Resize the modified and used register unit trackers.  We do this once
22406c3fb27SDimitry Andric   // per function and then clear the register units each time we optimize a
22506c3fb27SDimitry Andric   // move.
22606c3fb27SDimitry Andric   ModifiedRegUnits.init(*TRI);
22706c3fb27SDimitry Andric   UsedRegUnits.init(*TRI);
22806c3fb27SDimitry Andric   bool Modified = false;
22906c3fb27SDimitry Andric   for (auto &MBB : Fn)
23006c3fb27SDimitry Andric     Modified |= mergeMoveSARegPair(MBB);
23106c3fb27SDimitry Andric   return Modified;
23206c3fb27SDimitry Andric }
23306c3fb27SDimitry Andric 
23406c3fb27SDimitry Andric /// createRISCVMoveMergePass - returns an instance of the
23506c3fb27SDimitry Andric /// move merge pass.
23606c3fb27SDimitry Andric FunctionPass *llvm::createRISCVMoveMergePass() { return new RISCVMoveMerge(); }
237