| 1 | //==---- SystemZPostRewrite.cpp - Select pseudos after RegAlloc ---*- C++ -*-=// |
| 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 file contains a pass that is run immediately after VirtRegRewriter |
| 10 | // but before MachineCopyPropagation. The purpose is to lower pseudos to |
| 11 | // target instructions before any later pass might substitute a register for |
| 12 | // another. |
| 13 | // |
| 14 | //===----------------------------------------------------------------------===// |
| 15 | |
| 16 | #include "SystemZ.h" |
| 17 | #include "SystemZInstrInfo.h" |
| 18 | #include "SystemZSubtarget.h" |
| 19 | #include "llvm/ADT/Statistic.h" |
| 20 | #include "llvm/CodeGen/LivePhysRegs.h" |
| 21 | #include "llvm/CodeGen/MachineFunctionPass.h" |
| 22 | #include "llvm/CodeGen/MachineInstr.h" |
| 23 | #include "llvm/CodeGen/MachineInstrBuilder.h" |
| 24 | using namespace llvm; |
| 25 | |
| 26 | #define DEBUG_TYPE "systemz-postrewrite" |
| 27 | STATISTIC(MemFoldCopies, "Number of copies inserted before folded mem ops." ); |
| 28 | STATISTIC(LOCRMuxJumps, "Number of LOCRMux jump-sequences (lower is better)" ); |
| 29 | |
| 30 | namespace { |
| 31 | |
| 32 | class SystemZPostRewrite : public MachineFunctionPass { |
| 33 | public: |
| 34 | static char ID; |
| 35 | SystemZPostRewrite() : MachineFunctionPass(ID) {} |
| 36 | |
| 37 | const SystemZInstrInfo *TII; |
| 38 | |
| 39 | bool runOnMachineFunction(MachineFunction &Fn) override; |
| 40 | |
| 41 | private: |
| 42 | void selectLOCRMux(MachineBasicBlock &MBB, |
| 43 | MachineBasicBlock::iterator MBBI, |
| 44 | MachineBasicBlock::iterator &NextMBBI, |
| 45 | unsigned LowOpcode, |
| 46 | unsigned HighOpcode); |
| 47 | void selectSELRMux(MachineBasicBlock &MBB, |
| 48 | MachineBasicBlock::iterator MBBI, |
| 49 | MachineBasicBlock::iterator &NextMBBI, |
| 50 | unsigned LowOpcode, |
| 51 | unsigned HighOpcode); |
| 52 | bool expandCondMove(MachineBasicBlock &MBB, |
| 53 | MachineBasicBlock::iterator MBBI, |
| 54 | MachineBasicBlock::iterator &NextMBBI); |
| 55 | bool selectMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
| 56 | MachineBasicBlock::iterator &NextMBBI); |
| 57 | bool selectMBB(MachineBasicBlock &MBB); |
| 58 | }; |
| 59 | |
| 60 | char SystemZPostRewrite::ID = 0; |
| 61 | |
| 62 | } // end anonymous namespace |
| 63 | |
| 64 | INITIALIZE_PASS(SystemZPostRewrite, "systemz-post-rewrite" , |
| 65 | "SystemZ Post Rewrite pass" , false, false) |
| 66 | |
| 67 | /// Returns an instance of the Post Rewrite pass. |
| 68 | FunctionPass *llvm::createSystemZPostRewritePass(SystemZTargetMachine &TM) { |
| 69 | return new SystemZPostRewrite(); |
| 70 | } |
| 71 | |
| 72 | // MI is a load-register-on-condition pseudo instruction. Replace it with |
| 73 | // LowOpcode if source and destination are both low GR32s and HighOpcode if |
| 74 | // source and destination are both high GR32s. Otherwise, a branch sequence |
| 75 | // is created. |
| 76 | void SystemZPostRewrite::selectLOCRMux(MachineBasicBlock &MBB, |
| 77 | MachineBasicBlock::iterator MBBI, |
| 78 | MachineBasicBlock::iterator &NextMBBI, |
| 79 | unsigned LowOpcode, |
| 80 | unsigned HighOpcode) { |
| 81 | Register DestReg = MBBI->getOperand(i: 0).getReg(); |
| 82 | Register SrcReg = MBBI->getOperand(i: 2).getReg(); |
| 83 | bool DestIsHigh = SystemZ::isHighReg(Reg: DestReg); |
| 84 | bool SrcIsHigh = SystemZ::isHighReg(Reg: SrcReg); |
| 85 | |
| 86 | if (!DestIsHigh && !SrcIsHigh) |
| 87 | MBBI->setDesc(TII->get(Opcode: LowOpcode)); |
| 88 | else if (DestIsHigh && SrcIsHigh) |
| 89 | MBBI->setDesc(TII->get(Opcode: HighOpcode)); |
| 90 | else |
| 91 | expandCondMove(MBB, MBBI, NextMBBI); |
| 92 | } |
| 93 | |
| 94 | // MI is a select pseudo instruction. Replace it with LowOpcode if source |
| 95 | // and destination are all low GR32s and HighOpcode if source and destination |
| 96 | // are all high GR32s. Otherwise, a branch sequence is created. |
| 97 | void SystemZPostRewrite::selectSELRMux(MachineBasicBlock &MBB, |
| 98 | MachineBasicBlock::iterator MBBI, |
| 99 | MachineBasicBlock::iterator &NextMBBI, |
| 100 | unsigned LowOpcode, |
| 101 | unsigned HighOpcode) { |
| 102 | Register DestReg = MBBI->getOperand(i: 0).getReg(); |
| 103 | MachineOperand &Src1MO = MBBI->getOperand(i: 1); |
| 104 | MachineOperand &Src2MO = MBBI->getOperand(i: 2); |
| 105 | Register Src1Reg = Src1MO.getReg(); |
| 106 | Register Src2Reg = Src2MO.getReg(); |
| 107 | bool DestIsHigh = SystemZ::isHighReg(Reg: DestReg); |
| 108 | bool Src1IsHigh = SystemZ::isHighReg(Reg: Src1Reg); |
| 109 | bool Src2IsHigh = SystemZ::isHighReg(Reg: Src2Reg); |
| 110 | // A copy instruction that we might create, held here for the purpose of |
| 111 | // debug instr value tracking. |
| 112 | MachineInstr *CopyInst = nullptr; |
| 113 | |
| 114 | // In rare cases both sources are the same register (after |
| 115 | // machine-cse). This must be handled as it may lead to wrong-code (after |
| 116 | // machine-cp) if the kill flag on Src1 isn't cleared (with |
| 117 | // expandCondMove()). |
| 118 | if (Src1Reg == Src2Reg) { |
| 119 | CopyInst = BuildMI(BB&: *MBBI->getParent(), I: MBBI, MIMD: MBBI->getDebugLoc(), |
| 120 | MCID: TII->get(Opcode: SystemZ::COPY), DestReg) |
| 121 | .addReg(RegNo: Src1Reg, flags: getRegState(RegOp: Src1MO) & getRegState(RegOp: Src2MO)); |
| 122 | MBB.getParent()->substituteDebugValuesForInst(Old: *MBBI, New&: *CopyInst, MaxOperand: 1); |
| 123 | MBBI->eraseFromParent(); |
| 124 | return; |
| 125 | } |
| 126 | |
| 127 | // If sources and destination aren't all high or all low, we may be able to |
| 128 | // simplify the operation by moving one of the sources to the destination |
| 129 | // first. But only if this doesn't clobber the other source. |
| 130 | if (DestReg != Src1Reg && DestReg != Src2Reg) { |
| 131 | if (DestIsHigh != Src1IsHigh) { |
| 132 | CopyInst = BuildMI(BB&: *MBBI->getParent(), I: MBBI, MIMD: MBBI->getDebugLoc(), |
| 133 | MCID: TII->get(Opcode: SystemZ::COPY), DestReg) |
| 134 | .addReg(RegNo: Src1Reg, flags: getRegState(RegOp: Src1MO)); |
| 135 | Src1MO.setReg(DestReg); |
| 136 | Src1Reg = DestReg; |
| 137 | Src1IsHigh = DestIsHigh; |
| 138 | } else if (DestIsHigh != Src2IsHigh) { |
| 139 | CopyInst = BuildMI(BB&: *MBBI->getParent(), I: MBBI, MIMD: MBBI->getDebugLoc(), |
| 140 | MCID: TII->get(Opcode: SystemZ::COPY), DestReg) |
| 141 | .addReg(RegNo: Src2Reg, flags: getRegState(RegOp: Src2MO)); |
| 142 | Src2MO.setReg(DestReg); |
| 143 | Src2Reg = DestReg; |
| 144 | Src2IsHigh = DestIsHigh; |
| 145 | } |
| 146 | } |
| 147 | // if a copy instruction was inserted, record the debug value substitution |
| 148 | if (CopyInst) |
| 149 | MBB.getParent()->substituteDebugValuesForInst(Old: *MBBI, New&: *CopyInst, MaxOperand: 1); |
| 150 | |
| 151 | // If the destination (now) matches one source, prefer this to be first. |
| 152 | if (DestReg != Src1Reg && DestReg == Src2Reg) { |
| 153 | TII->commuteInstruction(MI&: *MBBI, NewMI: false, OpIdx1: 1, OpIdx2: 2); |
| 154 | std::swap(a&: Src1Reg, b&: Src2Reg); |
| 155 | std::swap(a&: Src1IsHigh, b&: Src2IsHigh); |
| 156 | } |
| 157 | |
| 158 | if (!DestIsHigh && !Src1IsHigh && !Src2IsHigh) |
| 159 | MBBI->setDesc(TII->get(Opcode: LowOpcode)); |
| 160 | else if (DestIsHigh && Src1IsHigh && Src2IsHigh) |
| 161 | MBBI->setDesc(TII->get(Opcode: HighOpcode)); |
| 162 | else |
| 163 | // Given the simplification above, we must already have a two-operand case. |
| 164 | expandCondMove(MBB, MBBI, NextMBBI); |
| 165 | } |
| 166 | |
| 167 | // Replace MBBI by a branch sequence that performs a conditional move of |
| 168 | // operand 2 to the destination register. Operand 1 is expected to be the |
| 169 | // same register as the destination. |
| 170 | bool SystemZPostRewrite::expandCondMove(MachineBasicBlock &MBB, |
| 171 | MachineBasicBlock::iterator MBBI, |
| 172 | MachineBasicBlock::iterator &NextMBBI) { |
| 173 | MachineFunction &MF = *MBB.getParent(); |
| 174 | const BasicBlock *BB = MBB.getBasicBlock(); |
| 175 | MachineInstr &MI = *MBBI; |
| 176 | DebugLoc DL = MI.getDebugLoc(); |
| 177 | Register DestReg = MI.getOperand(i: 0).getReg(); |
| 178 | Register SrcReg = MI.getOperand(i: 2).getReg(); |
| 179 | unsigned CCValid = MI.getOperand(i: 3).getImm(); |
| 180 | unsigned CCMask = MI.getOperand(i: 4).getImm(); |
| 181 | assert(DestReg == MI.getOperand(1).getReg() && |
| 182 | "Expected destination and first source operand to be the same." ); |
| 183 | |
| 184 | LivePhysRegs LiveRegs(TII->getRegisterInfo()); |
| 185 | LiveRegs.addLiveOuts(MBB); |
| 186 | for (auto I = std::prev(x: MBB.end()); I != MBBI; --I) |
| 187 | LiveRegs.stepBackward(MI: *I); |
| 188 | |
| 189 | // Splice MBB at MI, moving the rest of the block into RestMBB. |
| 190 | MachineBasicBlock *RestMBB = MF.CreateMachineBasicBlock(BB); |
| 191 | MF.insert(MBBI: std::next(x: MachineFunction::iterator(MBB)), MBB: RestMBB); |
| 192 | RestMBB->splice(Where: RestMBB->begin(), Other: &MBB, From: MI, To: MBB.end()); |
| 193 | RestMBB->transferSuccessors(FromMBB: &MBB); |
| 194 | for (MCPhysReg R : LiveRegs) |
| 195 | RestMBB->addLiveIn(PhysReg: R); |
| 196 | |
| 197 | // Create a new block MoveMBB to hold the move instruction. |
| 198 | MachineBasicBlock *MoveMBB = MF.CreateMachineBasicBlock(BB); |
| 199 | MF.insert(MBBI: std::next(x: MachineFunction::iterator(MBB)), MBB: MoveMBB); |
| 200 | MoveMBB->addLiveIn(PhysReg: SrcReg); |
| 201 | for (MCPhysReg R : LiveRegs) |
| 202 | MoveMBB->addLiveIn(PhysReg: R); |
| 203 | |
| 204 | // At the end of MBB, create a conditional branch to RestMBB if the |
| 205 | // condition is false, otherwise fall through to MoveMBB. |
| 206 | BuildMI(BB: &MBB, MIMD: DL, MCID: TII->get(Opcode: SystemZ::BRC)) |
| 207 | .addImm(Val: CCValid).addImm(Val: CCMask ^ CCValid).addMBB(MBB: RestMBB); |
| 208 | MBB.addSuccessor(Succ: RestMBB); |
| 209 | MBB.addSuccessor(Succ: MoveMBB); |
| 210 | |
| 211 | // In MoveMBB, emit an instruction to move SrcReg into DestReg, |
| 212 | // then fall through to RestMBB. |
| 213 | MachineInstr *CopyInst = |
| 214 | BuildMI(BB&: *MoveMBB, I: MoveMBB->end(), MIMD: DL, MCID: TII->get(Opcode: SystemZ::COPY), DestReg) |
| 215 | .addReg(RegNo: MI.getOperand(i: 2).getReg(), flags: getRegState(RegOp: MI.getOperand(i: 2))); |
| 216 | // record the debug value substitution for CopyInst |
| 217 | MBB.getParent()->substituteDebugValuesForInst(Old: *MBBI, New&: *CopyInst, MaxOperand: 1); |
| 218 | MoveMBB->addSuccessor(Succ: RestMBB); |
| 219 | |
| 220 | NextMBBI = MBB.end(); |
| 221 | MI.eraseFromParent(); |
| 222 | LOCRMuxJumps++; |
| 223 | return true; |
| 224 | } |
| 225 | |
| 226 | /// If MBBI references a pseudo instruction that should be selected here, |
| 227 | /// do it and return true. Otherwise return false. |
| 228 | bool SystemZPostRewrite::selectMI(MachineBasicBlock &MBB, |
| 229 | MachineBasicBlock::iterator MBBI, |
| 230 | MachineBasicBlock::iterator &NextMBBI) { |
| 231 | MachineInstr &MI = *MBBI; |
| 232 | unsigned Opcode = MI.getOpcode(); |
| 233 | |
| 234 | // Note: If this could be done during regalloc in foldMemoryOperandImpl() |
| 235 | // while also updating the LiveIntervals, there would be no need for the |
| 236 | // MemFoldPseudo to begin with. |
| 237 | int TargetMemOpcode = SystemZ::getTargetMemOpcode(Opcode); |
| 238 | if (TargetMemOpcode != -1) { |
| 239 | MI.setDesc(TII->get(Opcode: TargetMemOpcode)); |
| 240 | MI.tieOperands(DefIdx: 0, UseIdx: 1); |
| 241 | Register DstReg = MI.getOperand(i: 0).getReg(); |
| 242 | MachineOperand &SrcMO = MI.getOperand(i: 1); |
| 243 | if (DstReg != SrcMO.getReg()) { |
| 244 | BuildMI(BB&: MBB, I: &MI, MIMD: MI.getDebugLoc(), MCID: TII->get(Opcode: SystemZ::COPY), DestReg: DstReg) |
| 245 | .addReg(RegNo: SrcMO.getReg()); |
| 246 | SrcMO.setReg(DstReg); |
| 247 | MemFoldCopies++; |
| 248 | } |
| 249 | return true; |
| 250 | } |
| 251 | |
| 252 | switch (Opcode) { |
| 253 | case SystemZ::LOCRMux: |
| 254 | selectLOCRMux(MBB, MBBI, NextMBBI, LowOpcode: SystemZ::LOCR, HighOpcode: SystemZ::LOCFHR); |
| 255 | return true; |
| 256 | case SystemZ::SELRMux: |
| 257 | selectSELRMux(MBB, MBBI, NextMBBI, LowOpcode: SystemZ::SELR, HighOpcode: SystemZ::SELFHR); |
| 258 | return true; |
| 259 | } |
| 260 | |
| 261 | return false; |
| 262 | } |
| 263 | |
| 264 | /// Iterate over the instructions in basic block MBB and select any |
| 265 | /// pseudo instructions. Return true if anything was modified. |
| 266 | bool SystemZPostRewrite::selectMBB(MachineBasicBlock &MBB) { |
| 267 | bool Modified = false; |
| 268 | |
| 269 | MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end(); |
| 270 | while (MBBI != E) { |
| 271 | MachineBasicBlock::iterator NMBBI = std::next(x: MBBI); |
| 272 | Modified |= selectMI(MBB, MBBI, NextMBBI&: NMBBI); |
| 273 | MBBI = NMBBI; |
| 274 | } |
| 275 | |
| 276 | return Modified; |
| 277 | } |
| 278 | |
| 279 | bool SystemZPostRewrite::runOnMachineFunction(MachineFunction &MF) { |
| 280 | TII = MF.getSubtarget<SystemZSubtarget>().getInstrInfo(); |
| 281 | |
| 282 | bool Modified = false; |
| 283 | for (auto &MBB : MF) |
| 284 | Modified |= selectMBB(MBB); |
| 285 | |
| 286 | return Modified; |
| 287 | } |
| 288 | |
| 289 | |