1 //===-- SystemZShortenInst.cpp - Instruction-shortening 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 pass tries to replace instructions with shorter forms.  For example,
10 // IILF can be replaced with LLILL or LLILH if the constant fits and if the
11 // other 32 bits of the GR64 destination are not live.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "SystemZTargetMachine.h"
16 #include "llvm/CodeGen/LivePhysRegs.h"
17 #include "llvm/CodeGen/MachineFunctionPass.h"
18 #include "llvm/CodeGen/MachineInstrBuilder.h"
19 #include "llvm/CodeGen/TargetRegisterInfo.h"
20 
21 using namespace llvm;
22 
23 #define DEBUG_TYPE "systemz-shorten-inst"
24 
25 namespace {
26 class SystemZShortenInst : public MachineFunctionPass {
27 public:
28   static char ID;
29   SystemZShortenInst(const SystemZTargetMachine &tm);
30 
31   StringRef getPassName() const override {
32     return "SystemZ Instruction Shortening";
33   }
34 
35   bool processBlock(MachineBasicBlock &MBB);
36   bool runOnMachineFunction(MachineFunction &F) override;
37   MachineFunctionProperties getRequiredProperties() const override {
38     return MachineFunctionProperties().set(
39         MachineFunctionProperties::Property::NoVRegs);
40   }
41 
42 private:
43   bool shortenIIF(MachineInstr &MI, unsigned LLIxL, unsigned LLIxH);
44   bool shortenOn0(MachineInstr &MI, unsigned Opcode);
45   bool shortenOn01(MachineInstr &MI, unsigned Opcode);
46   bool shortenOn001(MachineInstr &MI, unsigned Opcode);
47   bool shortenOn001AddCC(MachineInstr &MI, unsigned Opcode);
48   bool shortenFPConv(MachineInstr &MI, unsigned Opcode);
49 
50   const SystemZInstrInfo *TII;
51   const TargetRegisterInfo *TRI;
52   LivePhysRegs LiveRegs;
53 };
54 
55 char SystemZShortenInst::ID = 0;
56 } // end anonymous namespace
57 
58 FunctionPass *llvm::createSystemZShortenInstPass(SystemZTargetMachine &TM) {
59   return new SystemZShortenInst(TM);
60 }
61 
62 SystemZShortenInst::SystemZShortenInst(const SystemZTargetMachine &tm)
63   : MachineFunctionPass(ID), TII(nullptr) {}
64 
65 // Tie operands if MI has become a two-address instruction.
66 static void tieOpsIfNeeded(MachineInstr &MI) {
67   if (MI.getDesc().getOperandConstraint(0, MCOI::TIED_TO) &&
68       !MI.getOperand(0).isTied())
69     MI.tieOperands(0, 1);
70 }
71 
72 // MI loads one word of a GPR using an IIxF instruction and LLIxL and LLIxH
73 // are the halfword immediate loads for the same word.  Try to use one of them
74 // instead of IIxF.
75 bool SystemZShortenInst::shortenIIF(MachineInstr &MI, unsigned LLIxL,
76                                     unsigned LLIxH) {
77   Register Reg = MI.getOperand(0).getReg();
78   // The new opcode will clear the other half of the GR64 reg, so
79   // cancel if that is live.
80   unsigned thisSubRegIdx =
81       (SystemZ::GRH32BitRegClass.contains(Reg) ? SystemZ::subreg_h32
82                                                : SystemZ::subreg_l32);
83   unsigned otherSubRegIdx =
84       (thisSubRegIdx == SystemZ::subreg_l32 ? SystemZ::subreg_h32
85                                             : SystemZ::subreg_l32);
86   unsigned GR64BitReg =
87       TRI->getMatchingSuperReg(Reg, thisSubRegIdx, &SystemZ::GR64BitRegClass);
88   Register OtherReg = TRI->getSubReg(GR64BitReg, otherSubRegIdx);
89   if (LiveRegs.contains(OtherReg))
90     return false;
91 
92   uint64_t Imm = MI.getOperand(1).getImm();
93   if (SystemZ::isImmLL(Imm)) {
94     MI.setDesc(TII->get(LLIxL));
95     MI.getOperand(0).setReg(SystemZMC::getRegAsGR64(Reg));
96     return true;
97   }
98   if (SystemZ::isImmLH(Imm)) {
99     MI.setDesc(TII->get(LLIxH));
100     MI.getOperand(0).setReg(SystemZMC::getRegAsGR64(Reg));
101     MI.getOperand(1).setImm(Imm >> 16);
102     return true;
103   }
104   return false;
105 }
106 
107 // Change MI's opcode to Opcode if register operand 0 has a 4-bit encoding.
108 bool SystemZShortenInst::shortenOn0(MachineInstr &MI, unsigned Opcode) {
109   if (SystemZMC::getFirstReg(MI.getOperand(0).getReg()) < 16) {
110     MI.setDesc(TII->get(Opcode));
111     return true;
112   }
113   return false;
114 }
115 
116 // Change MI's opcode to Opcode if register operands 0 and 1 have a
117 // 4-bit encoding.
118 bool SystemZShortenInst::shortenOn01(MachineInstr &MI, unsigned Opcode) {
119   if (SystemZMC::getFirstReg(MI.getOperand(0).getReg()) < 16 &&
120       SystemZMC::getFirstReg(MI.getOperand(1).getReg()) < 16) {
121     MI.setDesc(TII->get(Opcode));
122     return true;
123   }
124   return false;
125 }
126 
127 // Change MI's opcode to Opcode if register operands 0, 1 and 2 have a
128 // 4-bit encoding and if operands 0 and 1 are tied. Also ties op 0
129 // with op 1, if MI becomes 2-address.
130 bool SystemZShortenInst::shortenOn001(MachineInstr &MI, unsigned Opcode) {
131   if (SystemZMC::getFirstReg(MI.getOperand(0).getReg()) < 16 &&
132       MI.getOperand(1).getReg() == MI.getOperand(0).getReg() &&
133       SystemZMC::getFirstReg(MI.getOperand(2).getReg()) < 16) {
134     MI.setDesc(TII->get(Opcode));
135     tieOpsIfNeeded(MI);
136     return true;
137   }
138   return false;
139 }
140 
141 // Calls shortenOn001 if CCLive is false. CC def operand is added in
142 // case of success.
143 bool SystemZShortenInst::shortenOn001AddCC(MachineInstr &MI, unsigned Opcode) {
144   if (!LiveRegs.contains(SystemZ::CC) && shortenOn001(MI, Opcode)) {
145     MachineInstrBuilder(*MI.getParent()->getParent(), &MI)
146       .addReg(SystemZ::CC, RegState::ImplicitDefine | RegState::Dead);
147     return true;
148   }
149   return false;
150 }
151 
152 // MI is a vector-style conversion instruction with the operand order:
153 // destination, source, exact-suppress, rounding-mode.  If both registers
154 // have a 4-bit encoding then change it to Opcode, which has operand order:
155 // destination, rouding-mode, source, exact-suppress.
156 bool SystemZShortenInst::shortenFPConv(MachineInstr &MI, unsigned Opcode) {
157   if (SystemZMC::getFirstReg(MI.getOperand(0).getReg()) < 16 &&
158       SystemZMC::getFirstReg(MI.getOperand(1).getReg()) < 16) {
159     MachineOperand Dest(MI.getOperand(0));
160     MachineOperand Src(MI.getOperand(1));
161     MachineOperand Suppress(MI.getOperand(2));
162     MachineOperand Mode(MI.getOperand(3));
163     MI.RemoveOperand(3);
164     MI.RemoveOperand(2);
165     MI.RemoveOperand(1);
166     MI.RemoveOperand(0);
167     MI.setDesc(TII->get(Opcode));
168     MachineInstrBuilder(*MI.getParent()->getParent(), &MI)
169         .add(Dest)
170         .add(Mode)
171         .add(Src)
172         .add(Suppress);
173     return true;
174   }
175   return false;
176 }
177 
178 // Process all instructions in MBB.  Return true if something changed.
179 bool SystemZShortenInst::processBlock(MachineBasicBlock &MBB) {
180   bool Changed = false;
181 
182   // Set up the set of live registers at the end of MBB (live out)
183   LiveRegs.clear();
184   LiveRegs.addLiveOuts(MBB);
185 
186   // Iterate backwards through the block looking for instructions to change.
187   for (auto MBBI = MBB.rbegin(), MBBE = MBB.rend(); MBBI != MBBE; ++MBBI) {
188     MachineInstr &MI = *MBBI;
189     switch (MI.getOpcode()) {
190     case SystemZ::IILF:
191       Changed |= shortenIIF(MI, SystemZ::LLILL, SystemZ::LLILH);
192       break;
193 
194     case SystemZ::IIHF:
195       Changed |= shortenIIF(MI, SystemZ::LLIHL, SystemZ::LLIHH);
196       break;
197 
198     case SystemZ::WFADB:
199       Changed |= shortenOn001AddCC(MI, SystemZ::ADBR);
200       break;
201 
202     case SystemZ::WFASB:
203       Changed |= shortenOn001AddCC(MI, SystemZ::AEBR);
204       break;
205 
206     case SystemZ::WFDDB:
207       Changed |= shortenOn001(MI, SystemZ::DDBR);
208       break;
209 
210     case SystemZ::WFDSB:
211       Changed |= shortenOn001(MI, SystemZ::DEBR);
212       break;
213 
214     case SystemZ::WFIDB:
215       Changed |= shortenFPConv(MI, SystemZ::FIDBRA);
216       break;
217 
218     case SystemZ::WFISB:
219       Changed |= shortenFPConv(MI, SystemZ::FIEBRA);
220       break;
221 
222     case SystemZ::WLDEB:
223       Changed |= shortenOn01(MI, SystemZ::LDEBR);
224       break;
225 
226     case SystemZ::WLEDB:
227       Changed |= shortenFPConv(MI, SystemZ::LEDBRA);
228       break;
229 
230     case SystemZ::WFMDB:
231       Changed |= shortenOn001(MI, SystemZ::MDBR);
232       break;
233 
234     case SystemZ::WFMSB:
235       Changed |= shortenOn001(MI, SystemZ::MEEBR);
236       break;
237 
238     case SystemZ::WFLCDB:
239       Changed |= shortenOn01(MI, SystemZ::LCDFR);
240       break;
241 
242     case SystemZ::WFLCSB:
243       Changed |= shortenOn01(MI, SystemZ::LCDFR_32);
244       break;
245 
246     case SystemZ::WFLNDB:
247       Changed |= shortenOn01(MI, SystemZ::LNDFR);
248       break;
249 
250     case SystemZ::WFLNSB:
251       Changed |= shortenOn01(MI, SystemZ::LNDFR_32);
252       break;
253 
254     case SystemZ::WFLPDB:
255       Changed |= shortenOn01(MI, SystemZ::LPDFR);
256       break;
257 
258     case SystemZ::WFLPSB:
259       Changed |= shortenOn01(MI, SystemZ::LPDFR_32);
260       break;
261 
262     case SystemZ::WFSQDB:
263       Changed |= shortenOn01(MI, SystemZ::SQDBR);
264       break;
265 
266     case SystemZ::WFSQSB:
267       Changed |= shortenOn01(MI, SystemZ::SQEBR);
268       break;
269 
270     case SystemZ::WFSDB:
271       Changed |= shortenOn001AddCC(MI, SystemZ::SDBR);
272       break;
273 
274     case SystemZ::WFSSB:
275       Changed |= shortenOn001AddCC(MI, SystemZ::SEBR);
276       break;
277 
278     case SystemZ::WFCDB:
279       Changed |= shortenOn01(MI, SystemZ::CDBR);
280       break;
281 
282     case SystemZ::WFCSB:
283       Changed |= shortenOn01(MI, SystemZ::CEBR);
284       break;
285 
286     case SystemZ::WFKDB:
287       Changed |= shortenOn01(MI, SystemZ::KDBR);
288       break;
289 
290     case SystemZ::WFKSB:
291       Changed |= shortenOn01(MI, SystemZ::KEBR);
292       break;
293 
294     case SystemZ::VL32:
295       // For z13 we prefer LDE over LE to avoid partial register dependencies.
296       Changed |= shortenOn0(MI, SystemZ::LDE32);
297       break;
298 
299     case SystemZ::VST32:
300       Changed |= shortenOn0(MI, SystemZ::STE);
301       break;
302 
303     case SystemZ::VL64:
304       Changed |= shortenOn0(MI, SystemZ::LD);
305       break;
306 
307     case SystemZ::VST64:
308       Changed |= shortenOn0(MI, SystemZ::STD);
309       break;
310 
311     default: {
312       int TwoOperandOpcode = SystemZ::getTwoOperandOpcode(MI.getOpcode());
313       if (TwoOperandOpcode == -1)
314         break;
315 
316       if ((MI.getOperand(0).getReg() != MI.getOperand(1).getReg()) &&
317           (!MI.isCommutable() ||
318            MI.getOperand(0).getReg() != MI.getOperand(2).getReg() ||
319            !TII->commuteInstruction(MI, false, 1, 2)))
320           break;
321 
322       MI.setDesc(TII->get(TwoOperandOpcode));
323       MI.tieOperands(0, 1);
324       if (TwoOperandOpcode == SystemZ::SLL ||
325           TwoOperandOpcode == SystemZ::SLA ||
326           TwoOperandOpcode == SystemZ::SRL ||
327           TwoOperandOpcode == SystemZ::SRA) {
328         // These shifts only use the low 6 bits of the shift count.
329         MachineOperand &ImmMO = MI.getOperand(3);
330         ImmMO.setImm(ImmMO.getImm() & 0xfff);
331       }
332       Changed = true;
333       break;
334     }
335     }
336 
337     LiveRegs.stepBackward(MI);
338   }
339 
340   return Changed;
341 }
342 
343 bool SystemZShortenInst::runOnMachineFunction(MachineFunction &F) {
344   if (skipFunction(F.getFunction()))
345     return false;
346 
347   const SystemZSubtarget &ST = F.getSubtarget<SystemZSubtarget>();
348   TII = ST.getInstrInfo();
349   TRI = ST.getRegisterInfo();
350   LiveRegs.init(*TRI);
351 
352   bool Changed = false;
353   for (auto &MBB : F)
354     Changed |= processBlock(MBB);
355 
356   return Changed;
357 }
358