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