1fdc4ea34SJonas Paulsson //==---- SystemZPostRewrite.cpp - Select pseudos after RegAlloc ---*- C++ -*-=//
2fdc4ea34SJonas Paulsson //
3fdc4ea34SJonas Paulsson // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fdc4ea34SJonas Paulsson // See https://llvm.org/LICENSE.txt for license information.
5fdc4ea34SJonas Paulsson // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fdc4ea34SJonas Paulsson //
7fdc4ea34SJonas Paulsson //===----------------------------------------------------------------------===//
8fdc4ea34SJonas Paulsson //
9fdc4ea34SJonas Paulsson // This file contains a pass that is run immediately after VirtRegRewriter
10fdc4ea34SJonas Paulsson // but before MachineCopyPropagation. The purpose is to lower pseudos to
11fdc4ea34SJonas Paulsson // target instructions before any later pass might substitute a register for
12fdc4ea34SJonas Paulsson // another.
13fdc4ea34SJonas Paulsson //
14fdc4ea34SJonas Paulsson //===----------------------------------------------------------------------===//
15fdc4ea34SJonas Paulsson 
16fdc4ea34SJonas Paulsson #include "SystemZ.h"
17fdc4ea34SJonas Paulsson #include "SystemZInstrInfo.h"
18fdc4ea34SJonas Paulsson #include "SystemZSubtarget.h"
19fdc4ea34SJonas Paulsson #include "llvm/ADT/Statistic.h"
20989f1c72Sserge-sans-paille #include "llvm/CodeGen/LivePhysRegs.h"
21fdc4ea34SJonas Paulsson #include "llvm/CodeGen/MachineFunctionPass.h"
22fdc4ea34SJonas Paulsson #include "llvm/CodeGen/MachineInstrBuilder.h"
23fdc4ea34SJonas Paulsson using namespace llvm;
24fdc4ea34SJonas Paulsson 
25fdc4ea34SJonas Paulsson #define DEBUG_TYPE "systemz-postrewrite"
26fdc4ea34SJonas Paulsson STATISTIC(MemFoldCopies, "Number of copies inserted before folded mem ops.");
27ca5acf5bSJonas Paulsson STATISTIC(LOCRMuxJumps, "Number of LOCRMux jump-sequences (lower is better)");
28fdc4ea34SJonas Paulsson 
29fdc4ea34SJonas Paulsson namespace {
30fdc4ea34SJonas Paulsson 
31fdc4ea34SJonas Paulsson class SystemZPostRewrite : public MachineFunctionPass {
32fdc4ea34SJonas Paulsson public:
33fdc4ea34SJonas Paulsson   static char ID;
SystemZPostRewrite()34fdc4ea34SJonas Paulsson   SystemZPostRewrite() : MachineFunctionPass(ID) {
35fdc4ea34SJonas Paulsson     initializeSystemZPostRewritePass(*PassRegistry::getPassRegistry());
36fdc4ea34SJonas Paulsson   }
37fdc4ea34SJonas Paulsson 
38fdc4ea34SJonas Paulsson   const SystemZInstrInfo *TII;
39fdc4ea34SJonas Paulsson 
40fdc4ea34SJonas Paulsson   bool runOnMachineFunction(MachineFunction &Fn) override;
41fdc4ea34SJonas Paulsson 
42fdc4ea34SJonas Paulsson private:
43ca5acf5bSJonas Paulsson   void selectLOCRMux(MachineBasicBlock &MBB,
44ca5acf5bSJonas Paulsson                      MachineBasicBlock::iterator MBBI,
45ca5acf5bSJonas Paulsson                      MachineBasicBlock::iterator &NextMBBI,
46ca5acf5bSJonas Paulsson                      unsigned LowOpcode,
47ca5acf5bSJonas Paulsson                      unsigned HighOpcode);
48ca5acf5bSJonas Paulsson   void selectSELRMux(MachineBasicBlock &MBB,
49ca5acf5bSJonas Paulsson                      MachineBasicBlock::iterator MBBI,
50ca5acf5bSJonas Paulsson                      MachineBasicBlock::iterator &NextMBBI,
51ca5acf5bSJonas Paulsson                      unsigned LowOpcode,
52ca5acf5bSJonas Paulsson                      unsigned HighOpcode);
53ca5acf5bSJonas Paulsson   bool expandCondMove(MachineBasicBlock &MBB,
54ca5acf5bSJonas Paulsson                       MachineBasicBlock::iterator MBBI,
55ca5acf5bSJonas Paulsson                       MachineBasicBlock::iterator &NextMBBI);
56fdc4ea34SJonas Paulsson   bool selectMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
57fdc4ea34SJonas Paulsson                 MachineBasicBlock::iterator &NextMBBI);
58fdc4ea34SJonas Paulsson   bool selectMBB(MachineBasicBlock &MBB);
59fdc4ea34SJonas Paulsson };
60fdc4ea34SJonas Paulsson 
61fdc4ea34SJonas Paulsson char SystemZPostRewrite::ID = 0;
62fdc4ea34SJonas Paulsson 
63fdc4ea34SJonas Paulsson } // end anonymous namespace
64fdc4ea34SJonas Paulsson 
65fdc4ea34SJonas Paulsson INITIALIZE_PASS(SystemZPostRewrite, "systemz-post-rewrite",
66d5ae039eSKai Nacke                 "SystemZ Post Rewrite pass", false, false)
67fdc4ea34SJonas Paulsson 
68fdc4ea34SJonas Paulsson /// Returns an instance of the Post Rewrite pass.
createSystemZPostRewritePass(SystemZTargetMachine & TM)69fdc4ea34SJonas Paulsson FunctionPass *llvm::createSystemZPostRewritePass(SystemZTargetMachine &TM) {
70fdc4ea34SJonas Paulsson   return new SystemZPostRewrite();
71fdc4ea34SJonas Paulsson }
72fdc4ea34SJonas Paulsson 
73ca5acf5bSJonas Paulsson // MI is a load-register-on-condition pseudo instruction.  Replace it with
74ca5acf5bSJonas Paulsson // LowOpcode if source and destination are both low GR32s and HighOpcode if
75ca5acf5bSJonas Paulsson // source and destination are both high GR32s. Otherwise, a branch sequence
76ca5acf5bSJonas Paulsson // is created.
selectLOCRMux(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI,unsigned LowOpcode,unsigned HighOpcode)77ca5acf5bSJonas Paulsson void SystemZPostRewrite::selectLOCRMux(MachineBasicBlock &MBB,
78ca5acf5bSJonas Paulsson                                        MachineBasicBlock::iterator MBBI,
79ca5acf5bSJonas Paulsson                                        MachineBasicBlock::iterator &NextMBBI,
80ca5acf5bSJonas Paulsson                                        unsigned LowOpcode,
81ca5acf5bSJonas Paulsson                                        unsigned HighOpcode) {
82ca5acf5bSJonas Paulsson   Register DestReg = MBBI->getOperand(0).getReg();
83ca5acf5bSJonas Paulsson   Register SrcReg = MBBI->getOperand(2).getReg();
84ca5acf5bSJonas Paulsson   bool DestIsHigh = SystemZ::isHighReg(DestReg);
85ca5acf5bSJonas Paulsson   bool SrcIsHigh = SystemZ::isHighReg(SrcReg);
86ca5acf5bSJonas Paulsson 
87ca5acf5bSJonas Paulsson   if (!DestIsHigh && !SrcIsHigh)
88ca5acf5bSJonas Paulsson     MBBI->setDesc(TII->get(LowOpcode));
89ca5acf5bSJonas Paulsson   else if (DestIsHigh && SrcIsHigh)
90ca5acf5bSJonas Paulsson     MBBI->setDesc(TII->get(HighOpcode));
91ca5acf5bSJonas Paulsson   else
92ca5acf5bSJonas Paulsson     expandCondMove(MBB, MBBI, NextMBBI);
93ca5acf5bSJonas Paulsson }
94ca5acf5bSJonas Paulsson 
95ca5acf5bSJonas Paulsson // MI is a select pseudo instruction.  Replace it with LowOpcode if source
96ca5acf5bSJonas Paulsson // and destination are all low GR32s and HighOpcode if source and destination
97ca5acf5bSJonas Paulsson // are all high GR32s. Otherwise, a branch sequence is created.
selectSELRMux(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI,unsigned LowOpcode,unsigned HighOpcode)98ca5acf5bSJonas Paulsson void SystemZPostRewrite::selectSELRMux(MachineBasicBlock &MBB,
99ca5acf5bSJonas Paulsson                                        MachineBasicBlock::iterator MBBI,
100ca5acf5bSJonas Paulsson                                        MachineBasicBlock::iterator &NextMBBI,
101ca5acf5bSJonas Paulsson                                        unsigned LowOpcode,
102ca5acf5bSJonas Paulsson                                        unsigned HighOpcode) {
103ca5acf5bSJonas Paulsson   Register DestReg = MBBI->getOperand(0).getReg();
104ca5acf5bSJonas Paulsson   Register Src1Reg = MBBI->getOperand(1).getReg();
105ca5acf5bSJonas Paulsson   Register Src2Reg = MBBI->getOperand(2).getReg();
106ca5acf5bSJonas Paulsson   bool DestIsHigh = SystemZ::isHighReg(DestReg);
107ca5acf5bSJonas Paulsson   bool Src1IsHigh = SystemZ::isHighReg(Src1Reg);
108ca5acf5bSJonas Paulsson   bool Src2IsHigh = SystemZ::isHighReg(Src2Reg);
109ca5acf5bSJonas Paulsson 
110ca5acf5bSJonas Paulsson   // If sources and destination aren't all high or all low, we may be able to
111ca5acf5bSJonas Paulsson   // simplify the operation by moving one of the sources to the destination
112ca5acf5bSJonas Paulsson   // first.  But only if this doesn't clobber the other source.
113ca5acf5bSJonas Paulsson   if (DestReg != Src1Reg && DestReg != Src2Reg) {
114ca5acf5bSJonas Paulsson     if (DestIsHigh != Src1IsHigh) {
115ca5acf5bSJonas Paulsson       BuildMI(*MBBI->getParent(), MBBI, MBBI->getDebugLoc(),
116ca5acf5bSJonas Paulsson               TII->get(SystemZ::COPY), DestReg)
117ca5acf5bSJonas Paulsson         .addReg(MBBI->getOperand(1).getReg(), getRegState(MBBI->getOperand(1)));
118ca5acf5bSJonas Paulsson       MBBI->getOperand(1).setReg(DestReg);
119ca5acf5bSJonas Paulsson       Src1Reg = DestReg;
120ca5acf5bSJonas Paulsson       Src1IsHigh = DestIsHigh;
121ca5acf5bSJonas Paulsson     } else if (DestIsHigh != Src2IsHigh) {
122ca5acf5bSJonas Paulsson       BuildMI(*MBBI->getParent(), MBBI, MBBI->getDebugLoc(),
123ca5acf5bSJonas Paulsson               TII->get(SystemZ::COPY), DestReg)
124ca5acf5bSJonas Paulsson         .addReg(MBBI->getOperand(2).getReg(), getRegState(MBBI->getOperand(2)));
125ca5acf5bSJonas Paulsson       MBBI->getOperand(2).setReg(DestReg);
126ca5acf5bSJonas Paulsson       Src2Reg = DestReg;
127ca5acf5bSJonas Paulsson       Src2IsHigh = DestIsHigh;
128ca5acf5bSJonas Paulsson     }
129ca5acf5bSJonas Paulsson   }
130ca5acf5bSJonas Paulsson 
131ca5acf5bSJonas Paulsson   // If the destination (now) matches one source, prefer this to be first.
132ca5acf5bSJonas Paulsson   if (DestReg != Src1Reg && DestReg == Src2Reg) {
133ca5acf5bSJonas Paulsson     TII->commuteInstruction(*MBBI, false, 1, 2);
134ca5acf5bSJonas Paulsson     std::swap(Src1Reg, Src2Reg);
135ca5acf5bSJonas Paulsson     std::swap(Src1IsHigh, Src2IsHigh);
136ca5acf5bSJonas Paulsson   }
137ca5acf5bSJonas Paulsson 
138ca5acf5bSJonas Paulsson   if (!DestIsHigh && !Src1IsHigh && !Src2IsHigh)
139ca5acf5bSJonas Paulsson     MBBI->setDesc(TII->get(LowOpcode));
140ca5acf5bSJonas Paulsson   else if (DestIsHigh && Src1IsHigh && Src2IsHigh)
141ca5acf5bSJonas Paulsson     MBBI->setDesc(TII->get(HighOpcode));
142ca5acf5bSJonas Paulsson   else
143ca5acf5bSJonas Paulsson     // Given the simplification above, we must already have a two-operand case.
144ca5acf5bSJonas Paulsson     expandCondMove(MBB, MBBI, NextMBBI);
145ca5acf5bSJonas Paulsson }
146ca5acf5bSJonas Paulsson 
147ca5acf5bSJonas Paulsson // Replace MBBI by a branch sequence that performs a conditional move of
148ca5acf5bSJonas Paulsson // operand 2 to the destination register. Operand 1 is expected to be the
149ca5acf5bSJonas Paulsson // same register as the destination.
expandCondMove(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)150ca5acf5bSJonas Paulsson bool SystemZPostRewrite::expandCondMove(MachineBasicBlock &MBB,
151ca5acf5bSJonas Paulsson                                         MachineBasicBlock::iterator MBBI,
152ca5acf5bSJonas Paulsson                                         MachineBasicBlock::iterator &NextMBBI) {
153ca5acf5bSJonas Paulsson   MachineFunction &MF = *MBB.getParent();
154ca5acf5bSJonas Paulsson   const BasicBlock *BB = MBB.getBasicBlock();
155ca5acf5bSJonas Paulsson   MachineInstr &MI = *MBBI;
156ca5acf5bSJonas Paulsson   DebugLoc DL = MI.getDebugLoc();
157ca5acf5bSJonas Paulsson   Register DestReg = MI.getOperand(0).getReg();
158ca5acf5bSJonas Paulsson   Register SrcReg = MI.getOperand(2).getReg();
159ca5acf5bSJonas Paulsson   unsigned CCValid = MI.getOperand(3).getImm();
160ca5acf5bSJonas Paulsson   unsigned CCMask = MI.getOperand(4).getImm();
161ca5acf5bSJonas Paulsson   assert(DestReg == MI.getOperand(1).getReg() &&
162ca5acf5bSJonas Paulsson          "Expected destination and first source operand to be the same.");
163ca5acf5bSJonas Paulsson 
164ca5acf5bSJonas Paulsson   LivePhysRegs LiveRegs(TII->getRegisterInfo());
165ca5acf5bSJonas Paulsson   LiveRegs.addLiveOuts(MBB);
166ca5acf5bSJonas Paulsson   for (auto I = std::prev(MBB.end()); I != MBBI; --I)
167ca5acf5bSJonas Paulsson     LiveRegs.stepBackward(*I);
168ca5acf5bSJonas Paulsson 
169ca5acf5bSJonas Paulsson   // Splice MBB at MI, moving the rest of the block into RestMBB.
170ca5acf5bSJonas Paulsson   MachineBasicBlock *RestMBB = MF.CreateMachineBasicBlock(BB);
171ca5acf5bSJonas Paulsson   MF.insert(std::next(MachineFunction::iterator(MBB)), RestMBB);
172ca5acf5bSJonas Paulsson   RestMBB->splice(RestMBB->begin(), &MBB, MI, MBB.end());
173ca5acf5bSJonas Paulsson   RestMBB->transferSuccessors(&MBB);
174bf039a86SKazu Hirata   for (MCPhysReg R : LiveRegs)
175bf039a86SKazu Hirata     RestMBB->addLiveIn(R);
176ca5acf5bSJonas Paulsson 
177ca5acf5bSJonas Paulsson   // Create a new block MoveMBB to hold the move instruction.
178ca5acf5bSJonas Paulsson   MachineBasicBlock *MoveMBB = MF.CreateMachineBasicBlock(BB);
179ca5acf5bSJonas Paulsson   MF.insert(std::next(MachineFunction::iterator(MBB)), MoveMBB);
180ca5acf5bSJonas Paulsson   MoveMBB->addLiveIn(SrcReg);
181bf039a86SKazu Hirata   for (MCPhysReg R : LiveRegs)
182bf039a86SKazu Hirata     MoveMBB->addLiveIn(R);
183ca5acf5bSJonas Paulsson 
184ca5acf5bSJonas Paulsson   // At the end of MBB, create a conditional branch to RestMBB if the
185ca5acf5bSJonas Paulsson   // condition is false, otherwise fall through to MoveMBB.
186ca5acf5bSJonas Paulsson   BuildMI(&MBB, DL, TII->get(SystemZ::BRC))
187ca5acf5bSJonas Paulsson     .addImm(CCValid).addImm(CCMask ^ CCValid).addMBB(RestMBB);
188ca5acf5bSJonas Paulsson   MBB.addSuccessor(RestMBB);
189ca5acf5bSJonas Paulsson   MBB.addSuccessor(MoveMBB);
190ca5acf5bSJonas Paulsson 
191ca5acf5bSJonas Paulsson   // In MoveMBB, emit an instruction to move SrcReg into DestReg,
192ca5acf5bSJonas Paulsson   // then fall through to RestMBB.
193ca5acf5bSJonas Paulsson   BuildMI(*MoveMBB, MoveMBB->end(), DL, TII->get(SystemZ::COPY), DestReg)
194ca5acf5bSJonas Paulsson       .addReg(MI.getOperand(2).getReg(), getRegState(MI.getOperand(2)));
195ca5acf5bSJonas Paulsson   MoveMBB->addSuccessor(RestMBB);
196ca5acf5bSJonas Paulsson 
197ca5acf5bSJonas Paulsson   NextMBBI = MBB.end();
198ca5acf5bSJonas Paulsson   MI.eraseFromParent();
199ca5acf5bSJonas Paulsson   LOCRMuxJumps++;
200ca5acf5bSJonas Paulsson   return true;
201ca5acf5bSJonas Paulsson }
202ca5acf5bSJonas Paulsson 
203fdc4ea34SJonas Paulsson /// If MBBI references a pseudo instruction that should be selected here,
204fdc4ea34SJonas Paulsson /// do it and return true.  Otherwise return false.
selectMI(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)205fdc4ea34SJonas Paulsson bool SystemZPostRewrite::selectMI(MachineBasicBlock &MBB,
206fdc4ea34SJonas Paulsson                                   MachineBasicBlock::iterator MBBI,
207fdc4ea34SJonas Paulsson                                   MachineBasicBlock::iterator &NextMBBI) {
208fdc4ea34SJonas Paulsson   MachineInstr &MI = *MBBI;
209fdc4ea34SJonas Paulsson   unsigned Opcode = MI.getOpcode();
210fdc4ea34SJonas Paulsson 
211fdc4ea34SJonas Paulsson   // Note: If this could be done during regalloc in foldMemoryOperandImpl()
212fdc4ea34SJonas Paulsson   // while also updating the LiveIntervals, there would be no need for the
213fdc4ea34SJonas Paulsson   // MemFoldPseudo to begin with.
214fdc4ea34SJonas Paulsson   int TargetMemOpcode = SystemZ::getTargetMemOpcode(Opcode);
215fdc4ea34SJonas Paulsson   if (TargetMemOpcode != -1) {
216fdc4ea34SJonas Paulsson     MI.setDesc(TII->get(TargetMemOpcode));
217fdc4ea34SJonas Paulsson     MI.tieOperands(0, 1);
2180c476111SDaniel Sanders     Register DstReg = MI.getOperand(0).getReg();
219fdc4ea34SJonas Paulsson     MachineOperand &SrcMO = MI.getOperand(1);
220fdc4ea34SJonas Paulsson     if (DstReg != SrcMO.getReg()) {
221fdc4ea34SJonas Paulsson       BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(SystemZ::COPY), DstReg)
222fdc4ea34SJonas Paulsson         .addReg(SrcMO.getReg());
223fdc4ea34SJonas Paulsson       SrcMO.setReg(DstReg);
224fdc4ea34SJonas Paulsson       MemFoldCopies++;
225fdc4ea34SJonas Paulsson     }
226fdc4ea34SJonas Paulsson     return true;
227fdc4ea34SJonas Paulsson   }
228fdc4ea34SJonas Paulsson 
229ca5acf5bSJonas Paulsson   switch (Opcode) {
230ca5acf5bSJonas Paulsson   case SystemZ::LOCRMux:
231ca5acf5bSJonas Paulsson     selectLOCRMux(MBB, MBBI, NextMBBI, SystemZ::LOCR, SystemZ::LOCFHR);
232ca5acf5bSJonas Paulsson     return true;
233ca5acf5bSJonas Paulsson   case SystemZ::SELRMux:
234ca5acf5bSJonas Paulsson     selectSELRMux(MBB, MBBI, NextMBBI, SystemZ::SELR, SystemZ::SELFHR);
235ca5acf5bSJonas Paulsson     return true;
236ca5acf5bSJonas Paulsson   }
237ca5acf5bSJonas Paulsson 
238fdc4ea34SJonas Paulsson   return false;
239fdc4ea34SJonas Paulsson }
240fdc4ea34SJonas Paulsson 
241fdc4ea34SJonas Paulsson /// Iterate over the instructions in basic block MBB and select any
242fdc4ea34SJonas Paulsson /// pseudo instructions.  Return true if anything was modified.
selectMBB(MachineBasicBlock & MBB)243fdc4ea34SJonas Paulsson bool SystemZPostRewrite::selectMBB(MachineBasicBlock &MBB) {
244fdc4ea34SJonas Paulsson   bool Modified = false;
245fdc4ea34SJonas Paulsson 
246fdc4ea34SJonas Paulsson   MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
247fdc4ea34SJonas Paulsson   while (MBBI != E) {
248fdc4ea34SJonas Paulsson     MachineBasicBlock::iterator NMBBI = std::next(MBBI);
249fdc4ea34SJonas Paulsson     Modified |= selectMI(MBB, MBBI, NMBBI);
250fdc4ea34SJonas Paulsson     MBBI = NMBBI;
251fdc4ea34SJonas Paulsson   }
252fdc4ea34SJonas Paulsson 
253fdc4ea34SJonas Paulsson   return Modified;
254fdc4ea34SJonas Paulsson }
255fdc4ea34SJonas Paulsson 
runOnMachineFunction(MachineFunction & MF)256fdc4ea34SJonas Paulsson bool SystemZPostRewrite::runOnMachineFunction(MachineFunction &MF) {
257*3432d40cSJonas Paulsson   TII = MF.getSubtarget<SystemZSubtarget>().getInstrInfo();
258fdc4ea34SJonas Paulsson 
259fdc4ea34SJonas Paulsson   bool Modified = false;
260fdc4ea34SJonas Paulsson   for (auto &MBB : MF)
261fdc4ea34SJonas Paulsson     Modified |= selectMBB(MBB);
262fdc4ea34SJonas Paulsson 
263fdc4ea34SJonas Paulsson   return Modified;
264fdc4ea34SJonas Paulsson }
265fdc4ea34SJonas Paulsson 
266