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