| Richard Sandiford | 35ec4e356 | 2013-09-25 10:11:07 +0000 | [diff] [blame] | 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 |  | 
| Richard Sandiford | 35ec4e356 | 2013-09-25 10:11:07 +0000 | [diff] [blame] | 16 | #include "SystemZTargetMachine.h" | 
|  | 17 | #include "llvm/CodeGen/MachineFunctionPass.h" | 
| Ulrich Weigand | 49506d7 | 2015-05-05 19:28:34 +0000 | [diff] [blame] | 18 | #include "llvm/CodeGen/MachineInstrBuilder.h" | 
| Richard Sandiford | 35ec4e356 | 2013-09-25 10:11:07 +0000 | [diff] [blame] | 19 |  | 
|  | 20 | using namespace llvm; | 
|  | 21 |  | 
| Chandler Carruth | 84e68b2 | 2014-04-22 02:41:26 +0000 | [diff] [blame] | 22 | #define DEBUG_TYPE "systemz-shorten-inst" | 
|  | 23 |  | 
| Richard Sandiford | 35ec4e356 | 2013-09-25 10:11:07 +0000 | [diff] [blame] | 24 | namespace { | 
| Richard Sandiford | c231269 | 2014-03-06 10:38:30 +0000 | [diff] [blame] | 25 | class SystemZShortenInst : public MachineFunctionPass { | 
|  | 26 | public: | 
|  | 27 | static char ID; | 
|  | 28 | SystemZShortenInst(const SystemZTargetMachine &tm); | 
| Richard Sandiford | 35ec4e356 | 2013-09-25 10:11:07 +0000 | [diff] [blame] | 29 |  | 
| Richard Sandiford | b4d67b5 | 2014-03-06 12:03:36 +0000 | [diff] [blame] | 30 | const char *getPassName() const override { | 
| Richard Sandiford | c231269 | 2014-03-06 10:38:30 +0000 | [diff] [blame] | 31 | return "SystemZ Instruction Shortening"; | 
|  | 32 | } | 
| Richard Sandiford | 35ec4e356 | 2013-09-25 10:11:07 +0000 | [diff] [blame] | 33 |  | 
| Richard Sandiford | 28c111e | 2014-03-06 11:00:15 +0000 | [diff] [blame] | 34 | bool processBlock(MachineBasicBlock &MBB); | 
| Craig Topper | 9d74a5a | 2014-04-29 07:58:41 +0000 | [diff] [blame] | 35 | bool runOnMachineFunction(MachineFunction &F) override; | 
| Richard Sandiford | 35ec4e356 | 2013-09-25 10:11:07 +0000 | [diff] [blame] | 36 |  | 
| Richard Sandiford | c231269 | 2014-03-06 10:38:30 +0000 | [diff] [blame] | 37 | private: | 
|  | 38 | bool shortenIIF(MachineInstr &MI, unsigned *GPRMap, unsigned LiveOther, | 
|  | 39 | unsigned LLIxL, unsigned LLIxH); | 
| Ulrich Weigand | 49506d7 | 2015-05-05 19:28:34 +0000 | [diff] [blame] | 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); | 
| Richard Sandiford | 35ec4e356 | 2013-09-25 10:11:07 +0000 | [diff] [blame] | 44 |  | 
| Richard Sandiford | c231269 | 2014-03-06 10:38:30 +0000 | [diff] [blame] | 45 | const SystemZInstrInfo *TII; | 
| Richard Sandiford | 35ec4e356 | 2013-09-25 10:11:07 +0000 | [diff] [blame] | 46 |  | 
| Richard Sandiford | c231269 | 2014-03-06 10:38:30 +0000 | [diff] [blame] | 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 | }; | 
| Richard Sandiford | 35ec4e356 | 2013-09-25 10:11:07 +0000 | [diff] [blame] | 52 |  | 
| Richard Sandiford | c231269 | 2014-03-06 10:38:30 +0000 | [diff] [blame] | 53 | char SystemZShortenInst::ID = 0; | 
|  | 54 | } // end anonymous namespace | 
| Richard Sandiford | 35ec4e356 | 2013-09-25 10:11:07 +0000 | [diff] [blame] | 55 |  | 
|  | 56 | FunctionPass *llvm::createSystemZShortenInstPass(SystemZTargetMachine &TM) { | 
|  | 57 | return new SystemZShortenInst(TM); | 
|  | 58 | } | 
|  | 59 |  | 
|  | 60 | SystemZShortenInst::SystemZShortenInst(const SystemZTargetMachine &tm) | 
| Craig Topper | 062a2ba | 2014-04-25 05:30:21 +0000 | [diff] [blame] | 61 | : MachineFunctionPass(ID), TII(nullptr), LowGPRs(), HighGPRs() { | 
| Richard Sandiford | 35ec4e356 | 2013-09-25 10:11:07 +0000 | [diff] [blame] | 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; | 
| Richard Sandiford | 0124023 | 2013-10-01 13:02:28 +0000 | [diff] [blame] | 66 | HighGPRs[SystemZMC::GRH32Regs[I]] |= 1 << I; | 
| Richard Sandiford | 35ec4e356 | 2013-09-25 10:11:07 +0000 | [diff] [blame] | 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 |  | 
| Ulrich Weigand | 49506d7 | 2015-05-05 19:28:34 +0000 | [diff] [blame] | 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 |  | 
| Richard Sandiford | 35ec4e356 | 2013-09-25 10:11:07 +0000 | [diff] [blame] | 163 | // Process all instructions in MBB.  Return true if something changed. | 
| Richard Sandiford | 28c111e | 2014-03-06 11:00:15 +0000 | [diff] [blame] | 164 | bool SystemZShortenInst::processBlock(MachineBasicBlock &MBB) { | 
| Richard Sandiford | 35ec4e356 | 2013-09-25 10:11:07 +0000 | [diff] [blame] | 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; | 
| Richard Sandiford | 28c111e | 2014-03-06 11:00:15 +0000 | [diff] [blame] | 170 | for (auto SI = MBB.succ_begin(), SE = MBB.succ_end(); SI != SE; ++SI) { | 
|  | 171 | for (auto LI = (*SI)->livein_begin(), LE = (*SI)->livein_end(); | 
|  | 172 | LI != LE; ++LI) { | 
| Richard Sandiford | 35ec4e356 | 2013-09-25 10:11:07 +0000 | [diff] [blame] | 173 | unsigned Reg = *LI; | 
|  | 174 | assert(Reg < SystemZ::NUM_TARGET_REGS && "Invalid register number"); | 
|  | 175 | LiveLow |= LowGPRs[Reg]; | 
|  | 176 | LiveHigh |= HighGPRs[Reg]; | 
|  | 177 | } | 
|  | 178 | } | 
|  | 179 |  | 
|  | 180 | // Iterate backwards through the block looking for instructions to change. | 
| Richard Sandiford | 28c111e | 2014-03-06 11:00:15 +0000 | [diff] [blame] | 181 | for (auto MBBI = MBB.rbegin(), MBBE = MBB.rend(); MBBI != MBBE; ++MBBI) { | 
| Richard Sandiford | 35ec4e356 | 2013-09-25 10:11:07 +0000 | [diff] [blame] | 182 | MachineInstr &MI = *MBBI; | 
| Ulrich Weigand | 49506d7 | 2015-05-05 19:28:34 +0000 | [diff] [blame] | 183 | switch (MI.getOpcode()) { | 
|  | 184 | case SystemZ::IILF: | 
| Richard Sandiford | 35ec4e356 | 2013-09-25 10:11:07 +0000 | [diff] [blame] | 185 | Changed |= shortenIIF(MI, LowGPRs, LiveHigh, SystemZ::LLILL, | 
|  | 186 | SystemZ::LLILH); | 
| Ulrich Weigand | 49506d7 | 2015-05-05 19:28:34 +0000 | [diff] [blame] | 187 | break; | 
|  | 188 |  | 
|  | 189 | case SystemZ::IIHF: | 
| Richard Sandiford | 0124023 | 2013-10-01 13:02:28 +0000 | [diff] [blame] | 190 | Changed |= shortenIIF(MI, HighGPRs, LiveLow, SystemZ::LLIHL, | 
|  | 191 | SystemZ::LLIHH); | 
| Ulrich Weigand | 49506d7 | 2015-05-05 19:28:34 +0000 | [diff] [blame] | 192 | break; | 
|  | 193 |  | 
|  | 194 | case SystemZ::WFADB: | 
|  | 195 | Changed |= shortenOn001(MI, SystemZ::ADBR); | 
|  | 196 | break; | 
|  | 197 |  | 
|  | 198 | case SystemZ::WFDDB: | 
|  | 199 | Changed |= shortenOn001(MI, SystemZ::DDBR); | 
|  | 200 | break; | 
|  | 201 |  | 
|  | 202 | case SystemZ::WFIDB: | 
|  | 203 | Changed |= shortenFPConv(MI, SystemZ::FIDBRA); | 
|  | 204 | break; | 
|  | 205 |  | 
|  | 206 | case SystemZ::WLDEB: | 
|  | 207 | Changed |= shortenOn01(MI, SystemZ::LDEBR); | 
|  | 208 | break; | 
|  | 209 |  | 
|  | 210 | case SystemZ::WLEDB: | 
|  | 211 | Changed |= shortenFPConv(MI, SystemZ::LEDBRA); | 
|  | 212 | break; | 
|  | 213 |  | 
|  | 214 | case SystemZ::WFMDB: | 
|  | 215 | Changed |= shortenOn001(MI, SystemZ::MDBR); | 
|  | 216 | break; | 
|  | 217 |  | 
|  | 218 | case SystemZ::WFLCDB: | 
|  | 219 | Changed |= shortenOn01(MI, SystemZ::LCDBR); | 
|  | 220 | break; | 
|  | 221 |  | 
|  | 222 | case SystemZ::WFLNDB: | 
|  | 223 | Changed |= shortenOn01(MI, SystemZ::LNDBR); | 
|  | 224 | break; | 
|  | 225 |  | 
|  | 226 | case SystemZ::WFLPDB: | 
|  | 227 | Changed |= shortenOn01(MI, SystemZ::LPDBR); | 
|  | 228 | break; | 
|  | 229 |  | 
|  | 230 | case SystemZ::WFSQDB: | 
|  | 231 | Changed |= shortenOn01(MI, SystemZ::SQDBR); | 
|  | 232 | break; | 
|  | 233 |  | 
|  | 234 | case SystemZ::WFSDB: | 
|  | 235 | Changed |= shortenOn001(MI, SystemZ::SDBR); | 
|  | 236 | break; | 
|  | 237 |  | 
|  | 238 | case SystemZ::WFCDB: | 
|  | 239 | Changed |= shortenOn01(MI, SystemZ::CDBR); | 
|  | 240 | break; | 
|  | 241 |  | 
|  | 242 | case SystemZ::VL32: | 
|  | 243 | // For z13 we prefer LDE over LE to avoid partial register dependencies. | 
|  | 244 | Changed |= shortenOn0(MI, SystemZ::LDE32); | 
|  | 245 | break; | 
|  | 246 |  | 
|  | 247 | case SystemZ::VST32: | 
|  | 248 | Changed |= shortenOn0(MI, SystemZ::STE); | 
|  | 249 | break; | 
|  | 250 |  | 
|  | 251 | case SystemZ::VL64: | 
|  | 252 | Changed |= shortenOn0(MI, SystemZ::LD); | 
|  | 253 | break; | 
|  | 254 |  | 
|  | 255 | case SystemZ::VST64: | 
|  | 256 | Changed |= shortenOn0(MI, SystemZ::STD); | 
|  | 257 | break; | 
|  | 258 | } | 
|  | 259 |  | 
| Richard Sandiford | 35ec4e356 | 2013-09-25 10:11:07 +0000 | [diff] [blame] | 260 | unsigned UsedLow = 0; | 
|  | 261 | unsigned UsedHigh = 0; | 
| Richard Sandiford | 28c111e | 2014-03-06 11:00:15 +0000 | [diff] [blame] | 262 | for (auto MOI = MI.operands_begin(), MOE = MI.operands_end(); | 
|  | 263 | MOI != MOE; ++MOI) { | 
| Richard Sandiford | 35ec4e356 | 2013-09-25 10:11:07 +0000 | [diff] [blame] | 264 | MachineOperand &MO = *MOI; | 
|  | 265 | if (MO.isReg()) { | 
|  | 266 | if (unsigned Reg = MO.getReg()) { | 
|  | 267 | assert(Reg < SystemZ::NUM_TARGET_REGS && "Invalid register number"); | 
|  | 268 | if (MO.isDef()) { | 
|  | 269 | LiveLow &= ~LowGPRs[Reg]; | 
|  | 270 | LiveHigh &= ~HighGPRs[Reg]; | 
|  | 271 | } else if (!MO.isUndef()) { | 
|  | 272 | UsedLow |= LowGPRs[Reg]; | 
|  | 273 | UsedHigh |= HighGPRs[Reg]; | 
|  | 274 | } | 
|  | 275 | } | 
|  | 276 | } | 
|  | 277 | } | 
|  | 278 | LiveLow |= UsedLow; | 
|  | 279 | LiveHigh |= UsedHigh; | 
|  | 280 | } | 
|  | 281 |  | 
|  | 282 | return Changed; | 
|  | 283 | } | 
|  | 284 |  | 
|  | 285 | bool SystemZShortenInst::runOnMachineFunction(MachineFunction &F) { | 
| Eric Christopher | fc6de42 | 2014-08-05 02:39:49 +0000 | [diff] [blame] | 286 | TII = static_cast<const SystemZInstrInfo *>(F.getSubtarget().getInstrInfo()); | 
| Richard Sandiford | 35ec4e356 | 2013-09-25 10:11:07 +0000 | [diff] [blame] | 287 |  | 
|  | 288 | bool Changed = false; | 
| Richard Sandiford | 28c111e | 2014-03-06 11:00:15 +0000 | [diff] [blame] | 289 | for (auto &MBB : F) | 
|  | 290 | Changed |= processBlock(MBB); | 
| Richard Sandiford | 35ec4e356 | 2013-09-25 10:11:07 +0000 | [diff] [blame] | 291 |  | 
|  | 292 | return Changed; | 
|  | 293 | } |