[ADT] Switch a bunch of places in LLVM that were doing single-character
[oota-llvm.git] / lib / Target / SystemZ / SystemZShortenInst.cpp
1 //===-- SystemZShortenInst.cpp - Instruction-shortening pass --------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This pass tries to replace instructions with shorter forms.  For example,
11 // IILF can be replaced with LLILL or LLILH if the constant fits and if the
12 // other 32 bits of the GR64 destination are not live.
13 //
14 //===----------------------------------------------------------------------===//
15
16 #include "SystemZTargetMachine.h"
17 #include "llvm/CodeGen/MachineFunctionPass.h"
18 #include "llvm/CodeGen/MachineInstrBuilder.h"
19
20 using namespace llvm;
21
22 #define DEBUG_TYPE "systemz-shorten-inst"
23
24 namespace {
25 class SystemZShortenInst : public MachineFunctionPass {
26 public:
27   static char ID;
28   SystemZShortenInst(const SystemZTargetMachine &tm);
29
30   const char *getPassName() const override {
31     return "SystemZ Instruction Shortening";
32   }
33
34   bool processBlock(MachineBasicBlock &MBB);
35   bool runOnMachineFunction(MachineFunction &F) override;
36
37 private:
38   bool shortenIIF(MachineInstr &MI, unsigned *GPRMap, unsigned LiveOther,
39                   unsigned LLIxL, unsigned LLIxH);
40   bool shortenOn0(MachineInstr &MI, unsigned Opcode);
41   bool shortenOn01(MachineInstr &MI, unsigned Opcode);
42   bool shortenOn001(MachineInstr &MI, unsigned Opcode);
43   bool shortenFPConv(MachineInstr &MI, unsigned Opcode);
44
45   const SystemZInstrInfo *TII;
46
47   // LowGPRs[I] has bit N set if LLVM register I includes the low
48   // word of GPR N.  HighGPRs is the same for the high word.
49   unsigned LowGPRs[SystemZ::NUM_TARGET_REGS];
50   unsigned HighGPRs[SystemZ::NUM_TARGET_REGS];
51 };
52
53 char SystemZShortenInst::ID = 0;
54 } // end anonymous namespace
55
56 FunctionPass *llvm::createSystemZShortenInstPass(SystemZTargetMachine &TM) {
57   return new SystemZShortenInst(TM);
58 }
59
60 SystemZShortenInst::SystemZShortenInst(const SystemZTargetMachine &tm)
61   : MachineFunctionPass(ID), TII(nullptr), LowGPRs(), HighGPRs() {
62   // Set up LowGPRs and HighGPRs.
63   for (unsigned I = 0; I < 16; ++I) {
64     LowGPRs[SystemZMC::GR32Regs[I]] |= 1 << I;
65     LowGPRs[SystemZMC::GR64Regs[I]] |= 1 << I;
66     HighGPRs[SystemZMC::GRH32Regs[I]] |= 1 << I;
67     HighGPRs[SystemZMC::GR64Regs[I]] |= 1 << I;
68     if (unsigned GR128 = SystemZMC::GR128Regs[I]) {
69       LowGPRs[GR128] |= 3 << I;
70       HighGPRs[GR128] |= 3 << I;
71     }
72   }
73 }
74
75 // MI loads one word of a GPR using an IIxF instruction and LLIxL and LLIxH
76 // are the halfword immediate loads for the same word.  Try to use one of them
77 // instead of IIxF.  If MI loads the high word, GPRMap[X] is the set of high
78 // words referenced by LLVM register X while LiveOther is the mask of low
79 // words that are currently live, and vice versa.
80 bool SystemZShortenInst::shortenIIF(MachineInstr &MI, unsigned *GPRMap,
81                                     unsigned LiveOther, unsigned LLIxL,
82                                     unsigned LLIxH) {
83   unsigned Reg = MI.getOperand(0).getReg();
84   assert(Reg < SystemZ::NUM_TARGET_REGS && "Invalid register number");
85   unsigned GPRs = GPRMap[Reg];
86   assert(GPRs != 0 && "Register must be a GPR");
87   if (GPRs & LiveOther)
88     return false;
89
90   uint64_t Imm = MI.getOperand(1).getImm();
91   if (SystemZ::isImmLL(Imm)) {
92     MI.setDesc(TII->get(LLIxL));
93     MI.getOperand(0).setReg(SystemZMC::getRegAsGR64(Reg));
94     return true;
95   }
96   if (SystemZ::isImmLH(Imm)) {
97     MI.setDesc(TII->get(LLIxH));
98     MI.getOperand(0).setReg(SystemZMC::getRegAsGR64(Reg));
99     MI.getOperand(1).setImm(Imm >> 16);
100     return true;
101   }
102   return false;
103 }
104
105 // Change MI's opcode to Opcode if register operand 0 has a 4-bit encoding.
106 bool SystemZShortenInst::shortenOn0(MachineInstr &MI, unsigned Opcode) {
107   if (SystemZMC::getFirstReg(MI.getOperand(0).getReg()) < 16) {
108     MI.setDesc(TII->get(Opcode));
109     return true;
110   }
111   return false;
112 }
113
114 // Change MI's opcode to Opcode if register operands 0 and 1 have a
115 // 4-bit encoding.
116 bool SystemZShortenInst::shortenOn01(MachineInstr &MI, unsigned Opcode) {
117   if (SystemZMC::getFirstReg(MI.getOperand(0).getReg()) < 16 &&
118       SystemZMC::getFirstReg(MI.getOperand(1).getReg()) < 16) {
119     MI.setDesc(TII->get(Opcode));
120     return true;
121   }
122   return false;
123 }
124
125 // Change MI's opcode to Opcode if register operands 0, 1 and 2 have a
126 // 4-bit encoding and if operands 0 and 1 are tied.
127 bool SystemZShortenInst::shortenOn001(MachineInstr &MI, unsigned Opcode) {
128   if (SystemZMC::getFirstReg(MI.getOperand(0).getReg()) < 16 &&
129       MI.getOperand(1).getReg() == MI.getOperand(0).getReg() &&
130       SystemZMC::getFirstReg(MI.getOperand(2).getReg()) < 16) {
131     MI.setDesc(TII->get(Opcode));
132     return true;
133   }
134   return false;
135 }
136
137 // MI is a vector-style conversion instruction with the operand order:
138 // destination, source, exact-suppress, rounding-mode.  If both registers
139 // have a 4-bit encoding then change it to Opcode, which has operand order:
140 // destination, rouding-mode, source, exact-suppress.
141 bool SystemZShortenInst::shortenFPConv(MachineInstr &MI, unsigned Opcode) {
142   if (SystemZMC::getFirstReg(MI.getOperand(0).getReg()) < 16 &&
143       SystemZMC::getFirstReg(MI.getOperand(1).getReg()) < 16) {
144     MachineOperand Dest(MI.getOperand(0));
145     MachineOperand Src(MI.getOperand(1));
146     MachineOperand Suppress(MI.getOperand(2));
147     MachineOperand Mode(MI.getOperand(3));
148     MI.RemoveOperand(3);
149     MI.RemoveOperand(2);
150     MI.RemoveOperand(1);
151     MI.RemoveOperand(0);
152     MI.setDesc(TII->get(Opcode));
153     MachineInstrBuilder(*MI.getParent()->getParent(), &MI)
154       .addOperand(Dest)
155       .addOperand(Mode)
156       .addOperand(Src)
157       .addOperand(Suppress);
158     return true;
159   }
160   return false;
161 }
162
163 // Process all instructions in MBB.  Return true if something changed.
164 bool SystemZShortenInst::processBlock(MachineBasicBlock &MBB) {
165   bool Changed = false;
166
167   // Work out which words are live on exit from the block.
168   unsigned LiveLow = 0;
169   unsigned LiveHigh = 0;
170   for (auto SI = MBB.succ_begin(), SE = MBB.succ_end(); SI != SE; ++SI) {
171     for (const auto &LI : (*SI)->liveins()) {
172       unsigned Reg = LI.PhysReg;
173       assert(Reg < SystemZ::NUM_TARGET_REGS && "Invalid register number");
174       LiveLow |= LowGPRs[Reg];
175       LiveHigh |= HighGPRs[Reg];
176     }
177   }
178
179   // Iterate backwards through the block looking for instructions to change.
180   for (auto MBBI = MBB.rbegin(), MBBE = MBB.rend(); MBBI != MBBE; ++MBBI) {
181     MachineInstr &MI = *MBBI;
182     switch (MI.getOpcode()) {
183     case SystemZ::IILF:
184       Changed |= shortenIIF(MI, LowGPRs, LiveHigh, SystemZ::LLILL,
185                             SystemZ::LLILH);
186       break;
187
188     case SystemZ::IIHF:
189       Changed |= shortenIIF(MI, HighGPRs, LiveLow, SystemZ::LLIHL,
190                             SystemZ::LLIHH);
191       break;
192
193     case SystemZ::WFADB:
194       Changed |= shortenOn001(MI, SystemZ::ADBR);
195       break;
196
197     case SystemZ::WFDDB:
198       Changed |= shortenOn001(MI, SystemZ::DDBR);
199       break;
200
201     case SystemZ::WFIDB:
202       Changed |= shortenFPConv(MI, SystemZ::FIDBRA);
203       break;
204
205     case SystemZ::WLDEB:
206       Changed |= shortenOn01(MI, SystemZ::LDEBR);
207       break;
208
209     case SystemZ::WLEDB:
210       Changed |= shortenFPConv(MI, SystemZ::LEDBRA);
211       break;
212
213     case SystemZ::WFMDB:
214       Changed |= shortenOn001(MI, SystemZ::MDBR);
215       break;
216
217     case SystemZ::WFLCDB:
218       Changed |= shortenOn01(MI, SystemZ::LCDBR);
219       break;
220
221     case SystemZ::WFLNDB:
222       Changed |= shortenOn01(MI, SystemZ::LNDBR);
223       break;
224
225     case SystemZ::WFLPDB:
226       Changed |= shortenOn01(MI, SystemZ::LPDBR);
227       break;
228
229     case SystemZ::WFSQDB:
230       Changed |= shortenOn01(MI, SystemZ::SQDBR);
231       break;
232
233     case SystemZ::WFSDB:
234       Changed |= shortenOn001(MI, SystemZ::SDBR);
235       break;
236
237     case SystemZ::WFCDB:
238       Changed |= shortenOn01(MI, SystemZ::CDBR);
239       break;
240
241     case SystemZ::VL32:
242       // For z13 we prefer LDE over LE to avoid partial register dependencies.
243       Changed |= shortenOn0(MI, SystemZ::LDE32);
244       break;
245
246     case SystemZ::VST32:
247       Changed |= shortenOn0(MI, SystemZ::STE);
248       break;
249
250     case SystemZ::VL64:
251       Changed |= shortenOn0(MI, SystemZ::LD);
252       break;
253
254     case SystemZ::VST64:
255       Changed |= shortenOn0(MI, SystemZ::STD);
256       break;
257     }
258
259     unsigned UsedLow = 0;
260     unsigned UsedHigh = 0;
261     for (auto MOI = MI.operands_begin(), MOE = MI.operands_end();
262          MOI != MOE; ++MOI) {
263       MachineOperand &MO = *MOI;
264       if (MO.isReg()) {
265         if (unsigned Reg = MO.getReg()) {
266           assert(Reg < SystemZ::NUM_TARGET_REGS && "Invalid register number");
267           if (MO.isDef()) {
268             LiveLow &= ~LowGPRs[Reg];
269             LiveHigh &= ~HighGPRs[Reg];
270           } else if (!MO.isUndef()) {
271             UsedLow |= LowGPRs[Reg];
272             UsedHigh |= HighGPRs[Reg];
273           }
274         }
275       }
276     }
277     LiveLow |= UsedLow;
278     LiveHigh |= UsedHigh;
279   }
280
281   return Changed;
282 }
283
284 bool SystemZShortenInst::runOnMachineFunction(MachineFunction &F) {
285   TII = static_cast<const SystemZInstrInfo *>(F.getSubtarget().getInstrInfo());
286
287   bool Changed = false;
288   for (auto &MBB : F)
289     Changed |= processBlock(MBB);
290
291   return Changed;
292 }