|
| 1 | +//=== lib/Target/Z80/Z80MachineEarlyOptimization.cpp ----------------------===// |
| 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 does combining of machine instructions at the generic MI level, |
| 10 | +// before register allocation. |
| 11 | +// |
| 12 | +//===----------------------------------------------------------------------===// |
| 13 | + |
| 14 | +#include "MCTargetDesc/Z80MCTargetDesc.h" |
| 15 | +#include "Z80.h" |
| 16 | +#include "Z80InstrInfo.h" |
| 17 | +#include "llvm/CodeGen/LiveRegUnits.h" |
| 18 | +#include "llvm/CodeGen/MachineDominators.h" |
| 19 | +#include "llvm/CodeGen/TargetInstrInfo.h" |
| 20 | +#include "llvm/CodeGen/TargetRegisterInfo.h" |
| 21 | +#include "llvm/CodeGen/TargetSubtargetInfo.h" |
| 22 | +#include "llvm/IR/Constants.h" |
| 23 | +#include "llvm/Support/Debug.h" |
| 24 | + |
| 25 | +#define DEBUG_TYPE "z80-machine-early-opt" |
| 26 | + |
| 27 | +using namespace llvm; |
| 28 | + |
| 29 | +namespace { |
| 30 | +cl::opt<unsigned> CondCallThreshold("z80-cond-call-threshold", cl::Hidden, |
| 31 | + cl::init(10)); |
| 32 | + |
| 33 | +class Z80MachineEarlyOptimization : public MachineFunctionPass { |
| 34 | +public: |
| 35 | + static char ID; |
| 36 | + |
| 37 | + Z80MachineEarlyOptimization() : MachineFunctionPass(ID) {} |
| 38 | + |
| 39 | + StringRef getPassName() const override { |
| 40 | + return "Z80 Machine Early Optimization"; |
| 41 | + } |
| 42 | + |
| 43 | + bool runOnMachineFunction(MachineFunction &MF) override; |
| 44 | +}; |
| 45 | +} // end anonymous namespace |
| 46 | + |
| 47 | +bool Z80MachineEarlyOptimization::runOnMachineFunction(MachineFunction &MF) { |
| 48 | + bool Changed = false; |
| 49 | + const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo(); |
| 50 | + const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); |
| 51 | + MachineRegisterInfo &MRI = MF.getRegInfo(); |
| 52 | + |
| 53 | + for (MachineBasicBlock &MBB : MF) { |
| 54 | + MachineBasicBlock *TrueMBB = nullptr, *FalseMBB = nullptr; |
| 55 | + SmallVector<MachineOperand, 1> Cond; |
| 56 | + if (TII.analyzeBranch(MBB, TrueMBB, FalseMBB, Cond, false) || Cond.empty()) |
| 57 | + continue; |
| 58 | + if (!FalseMBB) |
| 59 | + FalseMBB = &*std::next(MBB.getIterator()); |
| 60 | + assert(TrueMBB && FalseMBB && "Expected to be nonnull"); |
| 61 | + for (int I = 0; I != 2; ++I) { |
| 62 | + if (TrueMBB->succ_empty() && TrueMBB->isReturnBlock()) { |
| 63 | + auto II = TrueMBB->begin(); |
| 64 | + while (II->isCopy() || II->isMetaInstruction()) |
| 65 | + ++II; |
| 66 | + if (++II == TrueMBB->end()) { |
| 67 | + // Unimplemented until FPE works. |
| 68 | + //Changed = true; |
| 69 | + } |
| 70 | + } |
| 71 | + if (TII.reverseBranchCondition(Cond)) |
| 72 | + break; |
| 73 | + std::swap(TrueMBB, FalseMBB); |
| 74 | + } |
| 75 | + // Separate loop because we want to prefer the above optimization. |
| 76 | + for (int I = 0; I != 2; ++I) { |
| 77 | + if (TrueMBB->pred_size() == 1 && TrueMBB->succ_size() == 1 && |
| 78 | + TrueMBB->isSuccessor(FalseMBB)) { |
| 79 | + MachineBasicBlock::iterator I = TrueMBB->begin(); |
| 80 | + MachineBasicBlock::iterator E = TrueMBB->getFirstTerminator(); |
| 81 | + if (I != E && TII.isFrameSetup(*I) && TII.isFrameInstr(*--E) && |
| 82 | + I != E) { |
| 83 | + unsigned Cost = 0; |
| 84 | + MachineInstr *CallMI = nullptr; |
| 85 | + struct Result { |
| 86 | + Register PhysReg, TrueReg, FalseReg, ResReg; |
| 87 | + }; |
| 88 | + SmallVector<Result, 4> Results; |
| 89 | + while (++I != E) { |
| 90 | + ++Cost; |
| 91 | + unsigned Opc = I->getOpcode(); |
| 92 | + if (Opc == Z80::CALL16 || Opc == Z80::CALL24) { |
| 93 | + if (CallMI) { |
| 94 | + CallMI = nullptr; |
| 95 | + break; |
| 96 | + } |
| 97 | + CallMI = &*I; |
| 98 | + } |
| 99 | + if (TII.isFrameInstr(*I) || |
| 100 | + (!CallMI && I->modifiesRegister(Z80::F, &TRI))) { |
| 101 | + CallMI = nullptr; |
| 102 | + break; |
| 103 | + } |
| 104 | + if (CallMI && Opc == TargetOpcode::COPY) { |
| 105 | + if (Results.size() == 4) { |
| 106 | + CallMI = nullptr; |
| 107 | + break; |
| 108 | + } |
| 109 | + Result &Res = Results.emplace_back(); |
| 110 | + Res.TrueReg = I->getOperand(0).getReg(); |
| 111 | + Res.PhysReg = I->getOperand(1).getReg(); |
| 112 | + assert(Res.TrueReg.isVirtual() && Res.PhysReg.isPhysical() && |
| 113 | + "Expected phys to virt reg copy inside call sequence"); |
| 114 | + } |
| 115 | + } |
| 116 | + for (I = FalseMBB->begin(), E = FalseMBB->end(); CallMI && I != E && I->isPHI(); |
| 117 | + ++I) { |
| 118 | + if (I->getNumOperands() != 5) { |
| 119 | + CallMI = nullptr; |
| 120 | + break; |
| 121 | + } |
| 122 | + Register FalseReg, TrueReg; |
| 123 | + for (unsigned OpNo = 1; CallMI && OpNo != 5; OpNo += 2) { |
| 124 | + Register Reg = I->getOperand(OpNo).getReg(); |
| 125 | + MachineBasicBlock &PredMBB = *I->getOperand(OpNo + 1).getMBB(); |
| 126 | + if (&PredMBB == &MBB) |
| 127 | + FalseReg = Reg; |
| 128 | + else if (&PredMBB == TrueMBB) |
| 129 | + TrueReg = Reg; |
| 130 | + else |
| 131 | + CallMI = nullptr; |
| 132 | + } |
| 133 | + bool Found = false; |
| 134 | + for (Result &Res : Results) { |
| 135 | + if (Res.TrueReg != TrueReg) |
| 136 | + continue; |
| 137 | + if (Res.FalseReg.isValid()) |
| 138 | + break; |
| 139 | + Res.FalseReg = FalseReg; |
| 140 | + Res.ResReg = I->getOperand(0).getReg(); |
| 141 | + Found = true; |
| 142 | + break; |
| 143 | + } |
| 144 | + if (!Found) |
| 145 | + CallMI = nullptr; |
| 146 | + } |
| 147 | + if (CallMI) { |
| 148 | + for (Result &Res : Results) { |
| 149 | + if (!Res.FalseReg.isValid() || |
| 150 | + CallMI->readsRegister(Res.PhysReg)) { |
| 151 | + CallMI = nullptr; |
| 152 | + break; |
| 153 | + } |
| 154 | + } |
| 155 | + } |
| 156 | + if (CallMI && Cost < CondCallThreshold) { |
| 157 | + Register TempReg = MRI.createVirtualRegister(&Z80::F8RegClass); |
| 158 | + DebugLoc DL = MBB.findBranchDebugLoc(); |
| 159 | + MBB.removeSuccessor(FalseMBB); |
| 160 | + TII.removeBranch(MBB); |
| 161 | + BuildMI(&MBB, DL, TII.get(TargetOpcode::COPY), TempReg) |
| 162 | + .addReg(Z80::F); |
| 163 | + if (!MBB.isLayoutSuccessor(TrueMBB)) |
| 164 | + TII.insertUnconditionalBranch(MBB, TrueMBB, DL); |
| 165 | + BuildMI(*TrueMBB, TrueMBB->begin(), DL, TII.get(TargetOpcode::COPY), |
| 166 | + Z80::F).addReg(TempReg); |
| 167 | + CallMI->setDesc(TII.get(CallMI->getOpcode() == Z80::CALL24 |
| 168 | + ? Z80::CALL24CC : Z80::CALL16CC)); |
| 169 | + auto RegMask = CallMI->getOperand(1).getRegMask(); |
| 170 | + CallMI->RemoveOperand(1); |
| 171 | + MachineInstrBuilder(MF, CallMI) |
| 172 | + .add(Cond[0]).addRegMask(RegMask) |
| 173 | + .addReg(Z80::F, RegState::Implicit); |
| 174 | + for (Result &Res : Results) { |
| 175 | + BuildMI(*TrueMBB, CallMI, CallMI->getDebugLoc(), |
| 176 | + TII.get(TargetOpcode::COPY), Res.PhysReg) |
| 177 | + .addReg(Res.FalseReg); |
| 178 | + CallMI->addRegisterKilled(Res.PhysReg, &TRI, true); |
| 179 | + } |
| 180 | + Changed = true; |
| 181 | + } |
| 182 | + } |
| 183 | + } |
| 184 | + if (TII.reverseBranchCondition(Cond)) |
| 185 | + break; |
| 186 | + std::swap(TrueMBB, FalseMBB); |
| 187 | + } |
| 188 | + } |
| 189 | + |
| 190 | + return Changed; |
| 191 | +} |
| 192 | + |
| 193 | +char Z80MachineEarlyOptimization::ID = 0; |
| 194 | +INITIALIZE_PASS(Z80MachineEarlyOptimization, DEBUG_TYPE, |
| 195 | + "Optimize Z80 machine instrs before regselect", false, false) |
| 196 | + |
| 197 | +namespace llvm { |
| 198 | +FunctionPass *createZ80MachineEarlyOptimizationPass() { |
| 199 | + return new Z80MachineEarlyOptimization(); |
| 200 | +} |
| 201 | +} // end namespace llvm |
0 commit comments