1f785676fSDimitry Andric //===-- SystemZShortenInst.cpp - Instruction-shortening pass --------------===//
2f785676fSDimitry Andric //
3f785676fSDimitry Andric //                     The LLVM Compiler Infrastructure
4f785676fSDimitry Andric //
5f785676fSDimitry Andric // This file is distributed under the University of Illinois Open Source
6f785676fSDimitry Andric // License. See LICENSE.TXT for details.
7f785676fSDimitry Andric //
8f785676fSDimitry Andric //===----------------------------------------------------------------------===//
9f785676fSDimitry Andric //
10f785676fSDimitry Andric // This pass tries to replace instructions with shorter forms.  For example,
11f785676fSDimitry Andric // IILF can be replaced with LLILL or LLILH if the constant fits and if the
12f785676fSDimitry Andric // other 32 bits of the GR64 destination are not live.
13f785676fSDimitry Andric //
14f785676fSDimitry Andric //===----------------------------------------------------------------------===//
15f785676fSDimitry Andric 
16f785676fSDimitry Andric #include "SystemZTargetMachine.h"
17db17bf38SDimitry Andric #include "llvm/CodeGen/LivePhysRegs.h"
18f785676fSDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
19ff0cc061SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
20*2cab237bSDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
21f785676fSDimitry Andric 
22f785676fSDimitry Andric using namespace llvm;
23f785676fSDimitry Andric 
2491bc56edSDimitry Andric #define DEBUG_TYPE "systemz-shorten-inst"
2591bc56edSDimitry Andric 
26f785676fSDimitry Andric namespace {
27f785676fSDimitry Andric class SystemZShortenInst : public MachineFunctionPass {
28f785676fSDimitry Andric public:
29f785676fSDimitry Andric   static char ID;
30f785676fSDimitry Andric   SystemZShortenInst(const SystemZTargetMachine &tm);
31f785676fSDimitry Andric 
getPassName() const32d88c1a5aSDimitry Andric   StringRef getPassName() const override {
33f785676fSDimitry Andric     return "SystemZ Instruction Shortening";
34f785676fSDimitry Andric   }
35f785676fSDimitry Andric 
3691bc56edSDimitry Andric   bool processBlock(MachineBasicBlock &MBB);
3791bc56edSDimitry Andric   bool runOnMachineFunction(MachineFunction &F) override;
getRequiredProperties() const383ca95b02SDimitry Andric   MachineFunctionProperties getRequiredProperties() const override {
393ca95b02SDimitry Andric     return MachineFunctionProperties().set(
40d88c1a5aSDimitry Andric         MachineFunctionProperties::Property::NoVRegs);
413ca95b02SDimitry Andric   }
42f785676fSDimitry Andric 
43f785676fSDimitry Andric private:
447d523365SDimitry Andric   bool shortenIIF(MachineInstr &MI, unsigned LLIxL, unsigned LLIxH);
45ff0cc061SDimitry Andric   bool shortenOn0(MachineInstr &MI, unsigned Opcode);
46ff0cc061SDimitry Andric   bool shortenOn01(MachineInstr &MI, unsigned Opcode);
47ff0cc061SDimitry Andric   bool shortenOn001(MachineInstr &MI, unsigned Opcode);
487d523365SDimitry Andric   bool shortenOn001AddCC(MachineInstr &MI, unsigned Opcode);
49ff0cc061SDimitry Andric   bool shortenFPConv(MachineInstr &MI, unsigned Opcode);
50f785676fSDimitry Andric 
51f785676fSDimitry Andric   const SystemZInstrInfo *TII;
527d523365SDimitry Andric   const TargetRegisterInfo *TRI;
537d523365SDimitry Andric   LivePhysRegs LiveRegs;
54f785676fSDimitry Andric };
55f785676fSDimitry Andric 
56f785676fSDimitry Andric char SystemZShortenInst::ID = 0;
5791bc56edSDimitry Andric } // end anonymous namespace
58f785676fSDimitry Andric 
createSystemZShortenInstPass(SystemZTargetMachine & TM)59f785676fSDimitry Andric FunctionPass *llvm::createSystemZShortenInstPass(SystemZTargetMachine &TM) {
60f785676fSDimitry Andric   return new SystemZShortenInst(TM);
61f785676fSDimitry Andric }
62f785676fSDimitry Andric 
SystemZShortenInst(const SystemZTargetMachine & tm)63f785676fSDimitry Andric SystemZShortenInst::SystemZShortenInst(const SystemZTargetMachine &tm)
647d523365SDimitry Andric   : MachineFunctionPass(ID), TII(nullptr) {}
657d523365SDimitry Andric 
667d523365SDimitry Andric // Tie operands if MI has become a two-address instruction.
tieOpsIfNeeded(MachineInstr & MI)677d523365SDimitry Andric static void tieOpsIfNeeded(MachineInstr &MI) {
687d523365SDimitry Andric   if (MI.getDesc().getOperandConstraint(0, MCOI::TIED_TO) &&
697d523365SDimitry Andric       !MI.getOperand(0).isTied())
707d523365SDimitry Andric     MI.tieOperands(0, 1);
71f785676fSDimitry Andric }
72f785676fSDimitry Andric 
73f785676fSDimitry Andric // MI loads one word of a GPR using an IIxF instruction and LLIxL and LLIxH
74f785676fSDimitry Andric // are the halfword immediate loads for the same word.  Try to use one of them
757d523365SDimitry Andric // instead of IIxF.
shortenIIF(MachineInstr & MI,unsigned LLIxL,unsigned LLIxH)763ca95b02SDimitry Andric bool SystemZShortenInst::shortenIIF(MachineInstr &MI, unsigned LLIxL,
773ca95b02SDimitry Andric                                     unsigned LLIxH) {
78f785676fSDimitry Andric   unsigned Reg = MI.getOperand(0).getReg();
797d523365SDimitry Andric   // The new opcode will clear the other half of the GR64 reg, so
807d523365SDimitry Andric   // cancel if that is live.
813ca95b02SDimitry Andric   unsigned thisSubRegIdx =
823ca95b02SDimitry Andric       (SystemZ::GRH32BitRegClass.contains(Reg) ? SystemZ::subreg_h32
833ca95b02SDimitry Andric                                                : SystemZ::subreg_l32);
843ca95b02SDimitry Andric   unsigned otherSubRegIdx =
853ca95b02SDimitry Andric       (thisSubRegIdx == SystemZ::subreg_l32 ? SystemZ::subreg_h32
863ca95b02SDimitry Andric                                             : SystemZ::subreg_l32);
873ca95b02SDimitry Andric   unsigned GR64BitReg =
883ca95b02SDimitry Andric       TRI->getMatchingSuperReg(Reg, thisSubRegIdx, &SystemZ::GR64BitRegClass);
897d523365SDimitry Andric   unsigned OtherReg = TRI->getSubReg(GR64BitReg, otherSubRegIdx);
907d523365SDimitry Andric   if (LiveRegs.contains(OtherReg))
91f785676fSDimitry Andric     return false;
92f785676fSDimitry Andric 
93f785676fSDimitry Andric   uint64_t Imm = MI.getOperand(1).getImm();
94f785676fSDimitry Andric   if (SystemZ::isImmLL(Imm)) {
95f785676fSDimitry Andric     MI.setDesc(TII->get(LLIxL));
96f785676fSDimitry Andric     MI.getOperand(0).setReg(SystemZMC::getRegAsGR64(Reg));
97f785676fSDimitry Andric     return true;
98f785676fSDimitry Andric   }
99f785676fSDimitry Andric   if (SystemZ::isImmLH(Imm)) {
100f785676fSDimitry Andric     MI.setDesc(TII->get(LLIxH));
101f785676fSDimitry Andric     MI.getOperand(0).setReg(SystemZMC::getRegAsGR64(Reg));
102f785676fSDimitry Andric     MI.getOperand(1).setImm(Imm >> 16);
103f785676fSDimitry Andric     return true;
104f785676fSDimitry Andric   }
105f785676fSDimitry Andric   return false;
106f785676fSDimitry Andric }
107f785676fSDimitry Andric 
108ff0cc061SDimitry Andric // Change MI's opcode to Opcode if register operand 0 has a 4-bit encoding.
shortenOn0(MachineInstr & MI,unsigned Opcode)109ff0cc061SDimitry Andric bool SystemZShortenInst::shortenOn0(MachineInstr &MI, unsigned Opcode) {
110ff0cc061SDimitry Andric   if (SystemZMC::getFirstReg(MI.getOperand(0).getReg()) < 16) {
111ff0cc061SDimitry Andric     MI.setDesc(TII->get(Opcode));
112ff0cc061SDimitry Andric     return true;
113ff0cc061SDimitry Andric   }
114ff0cc061SDimitry Andric   return false;
115ff0cc061SDimitry Andric }
116ff0cc061SDimitry Andric 
117ff0cc061SDimitry Andric // Change MI's opcode to Opcode if register operands 0 and 1 have a
118ff0cc061SDimitry Andric // 4-bit encoding.
shortenOn01(MachineInstr & MI,unsigned Opcode)119ff0cc061SDimitry Andric bool SystemZShortenInst::shortenOn01(MachineInstr &MI, unsigned Opcode) {
120ff0cc061SDimitry Andric   if (SystemZMC::getFirstReg(MI.getOperand(0).getReg()) < 16 &&
121ff0cc061SDimitry Andric       SystemZMC::getFirstReg(MI.getOperand(1).getReg()) < 16) {
122ff0cc061SDimitry Andric     MI.setDesc(TII->get(Opcode));
123ff0cc061SDimitry Andric     return true;
124ff0cc061SDimitry Andric   }
125ff0cc061SDimitry Andric   return false;
126ff0cc061SDimitry Andric }
127ff0cc061SDimitry Andric 
128ff0cc061SDimitry Andric // Change MI's opcode to Opcode if register operands 0, 1 and 2 have a
1297d523365SDimitry Andric // 4-bit encoding and if operands 0 and 1 are tied. Also ties op 0
1307d523365SDimitry Andric // with op 1, if MI becomes 2-address.
shortenOn001(MachineInstr & MI,unsigned Opcode)131ff0cc061SDimitry Andric bool SystemZShortenInst::shortenOn001(MachineInstr &MI, unsigned Opcode) {
132ff0cc061SDimitry Andric   if (SystemZMC::getFirstReg(MI.getOperand(0).getReg()) < 16 &&
133ff0cc061SDimitry Andric       MI.getOperand(1).getReg() == MI.getOperand(0).getReg() &&
134ff0cc061SDimitry Andric       SystemZMC::getFirstReg(MI.getOperand(2).getReg()) < 16) {
135ff0cc061SDimitry Andric     MI.setDesc(TII->get(Opcode));
1367d523365SDimitry Andric     tieOpsIfNeeded(MI);
1377d523365SDimitry Andric     return true;
1387d523365SDimitry Andric   }
1397d523365SDimitry Andric   return false;
1407d523365SDimitry Andric }
1417d523365SDimitry Andric 
1427d523365SDimitry Andric // Calls shortenOn001 if CCLive is false. CC def operand is added in
1437d523365SDimitry Andric // case of success.
shortenOn001AddCC(MachineInstr & MI,unsigned Opcode)1443ca95b02SDimitry Andric bool SystemZShortenInst::shortenOn001AddCC(MachineInstr &MI, unsigned Opcode) {
1457d523365SDimitry Andric   if (!LiveRegs.contains(SystemZ::CC) && shortenOn001(MI, Opcode)) {
1467d523365SDimitry Andric     MachineInstrBuilder(*MI.getParent()->getParent(), &MI)
1473ca95b02SDimitry Andric       .addReg(SystemZ::CC, RegState::ImplicitDefine | RegState::Dead);
148ff0cc061SDimitry Andric     return true;
149ff0cc061SDimitry Andric   }
150ff0cc061SDimitry Andric   return false;
151ff0cc061SDimitry Andric }
152ff0cc061SDimitry Andric 
153ff0cc061SDimitry Andric // MI is a vector-style conversion instruction with the operand order:
154ff0cc061SDimitry Andric // destination, source, exact-suppress, rounding-mode.  If both registers
155ff0cc061SDimitry Andric // have a 4-bit encoding then change it to Opcode, which has operand order:
156ff0cc061SDimitry Andric // destination, rouding-mode, source, exact-suppress.
shortenFPConv(MachineInstr & MI,unsigned Opcode)157ff0cc061SDimitry Andric bool SystemZShortenInst::shortenFPConv(MachineInstr &MI, unsigned Opcode) {
158ff0cc061SDimitry Andric   if (SystemZMC::getFirstReg(MI.getOperand(0).getReg()) < 16 &&
159ff0cc061SDimitry Andric       SystemZMC::getFirstReg(MI.getOperand(1).getReg()) < 16) {
160ff0cc061SDimitry Andric     MachineOperand Dest(MI.getOperand(0));
161ff0cc061SDimitry Andric     MachineOperand Src(MI.getOperand(1));
162ff0cc061SDimitry Andric     MachineOperand Suppress(MI.getOperand(2));
163ff0cc061SDimitry Andric     MachineOperand Mode(MI.getOperand(3));
164ff0cc061SDimitry Andric     MI.RemoveOperand(3);
165ff0cc061SDimitry Andric     MI.RemoveOperand(2);
166ff0cc061SDimitry Andric     MI.RemoveOperand(1);
167ff0cc061SDimitry Andric     MI.RemoveOperand(0);
168ff0cc061SDimitry Andric     MI.setDesc(TII->get(Opcode));
169ff0cc061SDimitry Andric     MachineInstrBuilder(*MI.getParent()->getParent(), &MI)
1707a7e6055SDimitry Andric         .add(Dest)
1717a7e6055SDimitry Andric         .add(Mode)
1727a7e6055SDimitry Andric         .add(Src)
1737a7e6055SDimitry Andric         .add(Suppress);
174ff0cc061SDimitry Andric     return true;
175ff0cc061SDimitry Andric   }
176ff0cc061SDimitry Andric   return false;
177ff0cc061SDimitry Andric }
178ff0cc061SDimitry Andric 
179f785676fSDimitry Andric // Process all instructions in MBB.  Return true if something changed.
processBlock(MachineBasicBlock & MBB)18091bc56edSDimitry Andric bool SystemZShortenInst::processBlock(MachineBasicBlock &MBB) {
181f785676fSDimitry Andric   bool Changed = false;
182f785676fSDimitry Andric 
1837d523365SDimitry Andric   // Set up the set of live registers at the end of MBB (live out)
1847d523365SDimitry Andric   LiveRegs.clear();
1853ca95b02SDimitry Andric   LiveRegs.addLiveOuts(MBB);
186f785676fSDimitry Andric 
187f785676fSDimitry Andric   // Iterate backwards through the block looking for instructions to change.
18891bc56edSDimitry Andric   for (auto MBBI = MBB.rbegin(), MBBE = MBB.rend(); MBBI != MBBE; ++MBBI) {
189f785676fSDimitry Andric     MachineInstr &MI = *MBBI;
190ff0cc061SDimitry Andric     switch (MI.getOpcode()) {
191ff0cc061SDimitry Andric     case SystemZ::IILF:
1927d523365SDimitry Andric       Changed |= shortenIIF(MI, SystemZ::LLILL, SystemZ::LLILH);
193ff0cc061SDimitry Andric       break;
194ff0cc061SDimitry Andric 
195ff0cc061SDimitry Andric     case SystemZ::IIHF:
1967d523365SDimitry Andric       Changed |= shortenIIF(MI, SystemZ::LLIHL, SystemZ::LLIHH);
197ff0cc061SDimitry Andric       break;
198ff0cc061SDimitry Andric 
199ff0cc061SDimitry Andric     case SystemZ::WFADB:
2007d523365SDimitry Andric       Changed |= shortenOn001AddCC(MI, SystemZ::ADBR);
201ff0cc061SDimitry Andric       break;
202ff0cc061SDimitry Andric 
203b40b48b8SDimitry Andric     case SystemZ::WFASB:
204b40b48b8SDimitry Andric       Changed |= shortenOn001AddCC(MI, SystemZ::AEBR);
205b40b48b8SDimitry Andric       break;
206b40b48b8SDimitry Andric 
207ff0cc061SDimitry Andric     case SystemZ::WFDDB:
208ff0cc061SDimitry Andric       Changed |= shortenOn001(MI, SystemZ::DDBR);
209ff0cc061SDimitry Andric       break;
210ff0cc061SDimitry Andric 
211b40b48b8SDimitry Andric     case SystemZ::WFDSB:
212b40b48b8SDimitry Andric       Changed |= shortenOn001(MI, SystemZ::DEBR);
213b40b48b8SDimitry Andric       break;
214b40b48b8SDimitry Andric 
215ff0cc061SDimitry Andric     case SystemZ::WFIDB:
216ff0cc061SDimitry Andric       Changed |= shortenFPConv(MI, SystemZ::FIDBRA);
217ff0cc061SDimitry Andric       break;
218ff0cc061SDimitry Andric 
219b40b48b8SDimitry Andric     case SystemZ::WFISB:
220b40b48b8SDimitry Andric       Changed |= shortenFPConv(MI, SystemZ::FIEBRA);
221b40b48b8SDimitry Andric       break;
222b40b48b8SDimitry Andric 
223ff0cc061SDimitry Andric     case SystemZ::WLDEB:
224ff0cc061SDimitry Andric       Changed |= shortenOn01(MI, SystemZ::LDEBR);
225ff0cc061SDimitry Andric       break;
226ff0cc061SDimitry Andric 
227ff0cc061SDimitry Andric     case SystemZ::WLEDB:
228ff0cc061SDimitry Andric       Changed |= shortenFPConv(MI, SystemZ::LEDBRA);
229ff0cc061SDimitry Andric       break;
230ff0cc061SDimitry Andric 
231ff0cc061SDimitry Andric     case SystemZ::WFMDB:
232ff0cc061SDimitry Andric       Changed |= shortenOn001(MI, SystemZ::MDBR);
233ff0cc061SDimitry Andric       break;
234ff0cc061SDimitry Andric 
235b40b48b8SDimitry Andric     case SystemZ::WFMSB:
236b40b48b8SDimitry Andric       Changed |= shortenOn001(MI, SystemZ::MEEBR);
237b40b48b8SDimitry Andric       break;
238b40b48b8SDimitry Andric 
239ff0cc061SDimitry Andric     case SystemZ::WFLCDB:
2407d523365SDimitry Andric       Changed |= shortenOn01(MI, SystemZ::LCDFR);
241ff0cc061SDimitry Andric       break;
242ff0cc061SDimitry Andric 
243b40b48b8SDimitry Andric     case SystemZ::WFLCSB:
244b40b48b8SDimitry Andric       Changed |= shortenOn01(MI, SystemZ::LCDFR_32);
245b40b48b8SDimitry Andric       break;
246b40b48b8SDimitry Andric 
247ff0cc061SDimitry Andric     case SystemZ::WFLNDB:
2487d523365SDimitry Andric       Changed |= shortenOn01(MI, SystemZ::LNDFR);
249ff0cc061SDimitry Andric       break;
250ff0cc061SDimitry Andric 
251b40b48b8SDimitry Andric     case SystemZ::WFLNSB:
252b40b48b8SDimitry Andric       Changed |= shortenOn01(MI, SystemZ::LNDFR_32);
253b40b48b8SDimitry Andric       break;
254b40b48b8SDimitry Andric 
255ff0cc061SDimitry Andric     case SystemZ::WFLPDB:
2567d523365SDimitry Andric       Changed |= shortenOn01(MI, SystemZ::LPDFR);
257ff0cc061SDimitry Andric       break;
258ff0cc061SDimitry Andric 
259b40b48b8SDimitry Andric     case SystemZ::WFLPSB:
260b40b48b8SDimitry Andric       Changed |= shortenOn01(MI, SystemZ::LPDFR_32);
261b40b48b8SDimitry Andric       break;
262b40b48b8SDimitry Andric 
263ff0cc061SDimitry Andric     case SystemZ::WFSQDB:
264ff0cc061SDimitry Andric       Changed |= shortenOn01(MI, SystemZ::SQDBR);
265ff0cc061SDimitry Andric       break;
266ff0cc061SDimitry Andric 
267b40b48b8SDimitry Andric     case SystemZ::WFSQSB:
268b40b48b8SDimitry Andric       Changed |= shortenOn01(MI, SystemZ::SQEBR);
269b40b48b8SDimitry Andric       break;
270b40b48b8SDimitry Andric 
271ff0cc061SDimitry Andric     case SystemZ::WFSDB:
2727d523365SDimitry Andric       Changed |= shortenOn001AddCC(MI, SystemZ::SDBR);
273ff0cc061SDimitry Andric       break;
274ff0cc061SDimitry Andric 
275b40b48b8SDimitry Andric     case SystemZ::WFSSB:
276b40b48b8SDimitry Andric       Changed |= shortenOn001AddCC(MI, SystemZ::SEBR);
277b40b48b8SDimitry Andric       break;
278b40b48b8SDimitry Andric 
279ff0cc061SDimitry Andric     case SystemZ::WFCDB:
280ff0cc061SDimitry Andric       Changed |= shortenOn01(MI, SystemZ::CDBR);
281ff0cc061SDimitry Andric       break;
282ff0cc061SDimitry Andric 
283b40b48b8SDimitry Andric     case SystemZ::WFCSB:
284b40b48b8SDimitry Andric       Changed |= shortenOn01(MI, SystemZ::CEBR);
285b40b48b8SDimitry Andric       break;
286b40b48b8SDimitry Andric 
287ff0cc061SDimitry Andric     case SystemZ::VL32:
288ff0cc061SDimitry Andric       // For z13 we prefer LDE over LE to avoid partial register dependencies.
289ff0cc061SDimitry Andric       Changed |= shortenOn0(MI, SystemZ::LDE32);
290ff0cc061SDimitry Andric       break;
291ff0cc061SDimitry Andric 
292ff0cc061SDimitry Andric     case SystemZ::VST32:
293ff0cc061SDimitry Andric       Changed |= shortenOn0(MI, SystemZ::STE);
294ff0cc061SDimitry Andric       break;
295ff0cc061SDimitry Andric 
296ff0cc061SDimitry Andric     case SystemZ::VL64:
297ff0cc061SDimitry Andric       Changed |= shortenOn0(MI, SystemZ::LD);
298ff0cc061SDimitry Andric       break;
299ff0cc061SDimitry Andric 
300ff0cc061SDimitry Andric     case SystemZ::VST64:
301ff0cc061SDimitry Andric       Changed |= shortenOn0(MI, SystemZ::STD);
302ff0cc061SDimitry Andric       break;
303ff0cc061SDimitry Andric     }
304ff0cc061SDimitry Andric 
3057d523365SDimitry Andric     LiveRegs.stepBackward(MI);
306f785676fSDimitry Andric   }
307f785676fSDimitry Andric 
308f785676fSDimitry Andric   return Changed;
309f785676fSDimitry Andric }
310f785676fSDimitry Andric 
runOnMachineFunction(MachineFunction & F)311f785676fSDimitry Andric bool SystemZShortenInst::runOnMachineFunction(MachineFunction &F) {
312*2cab237bSDimitry Andric   if (skipFunction(F.getFunction()))
3133ca95b02SDimitry Andric     return false;
3143ca95b02SDimitry Andric 
3157d523365SDimitry Andric   const SystemZSubtarget &ST = F.getSubtarget<SystemZSubtarget>();
3167d523365SDimitry Andric   TII = ST.getInstrInfo();
3177d523365SDimitry Andric   TRI = ST.getRegisterInfo();
318d88c1a5aSDimitry Andric   LiveRegs.init(*TRI);
319f785676fSDimitry Andric 
320f785676fSDimitry Andric   bool Changed = false;
32191bc56edSDimitry Andric   for (auto &MBB : F)
32291bc56edSDimitry Andric     Changed |= processBlock(MBB);
323f785676fSDimitry Andric 
324f785676fSDimitry Andric   return Changed;
325f785676fSDimitry Andric }
326