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