| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 1 | //===-- SystemZElimCompare.cpp - Eliminate comparison instructions --------===// | 
|  | 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: | 
|  | 11 | // (1) tries to remove compares if CC already contains the required information | 
|  | 12 | // (2) fuses compares and branches into COMPARE AND BRANCH instructions | 
|  | 13 | // | 
|  | 14 | //===----------------------------------------------------------------------===// | 
|  | 15 |  | 
| Eugene Zelenko | 3943d2b | 2017-01-24 22:10:43 +0000 | [diff] [blame] | 16 | #include "SystemZ.h" | 
|  | 17 | #include "SystemZInstrInfo.h" | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 18 | #include "SystemZTargetMachine.h" | 
| Eugene Zelenko | 3943d2b | 2017-01-24 22:10:43 +0000 | [diff] [blame] | 19 | #include "llvm/ADT/SmallVector.h" | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 20 | #include "llvm/ADT/Statistic.h" | 
| Eugene Zelenko | 3943d2b | 2017-01-24 22:10:43 +0000 | [diff] [blame] | 21 | #include "llvm/ADT/StringRef.h" | 
|  | 22 | #include "llvm/CodeGen/MachineBasicBlock.h" | 
|  | 23 | #include "llvm/CodeGen/MachineFunction.h" | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 24 | #include "llvm/CodeGen/MachineFunctionPass.h" | 
| Eugene Zelenko | 3943d2b | 2017-01-24 22:10:43 +0000 | [diff] [blame] | 25 | #include "llvm/CodeGen/MachineInstr.h" | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 26 | #include "llvm/CodeGen/MachineInstrBuilder.h" | 
| Eugene Zelenko | 3943d2b | 2017-01-24 22:10:43 +0000 | [diff] [blame] | 27 | #include "llvm/CodeGen/MachineOperand.h" | 
| David Blaikie | b3bde2e | 2017-11-17 01:07:10 +0000 | [diff] [blame] | 28 | #include "llvm/CodeGen/TargetRegisterInfo.h" | 
|  | 29 | #include "llvm/CodeGen/TargetSubtargetInfo.h" | 
| Eugene Zelenko | 3943d2b | 2017-01-24 22:10:43 +0000 | [diff] [blame] | 30 | #include "llvm/MC/MCInstrDesc.h" | 
| Eugene Zelenko | 3943d2b | 2017-01-24 22:10:43 +0000 | [diff] [blame] | 31 | #include <cassert> | 
|  | 32 | #include <cstdint> | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 33 |  | 
|  | 34 | using namespace llvm; | 
|  | 35 |  | 
| Chandler Carruth | 84e68b2 | 2014-04-22 02:41:26 +0000 | [diff] [blame] | 36 | #define DEBUG_TYPE "systemz-elim-compare" | 
|  | 37 |  | 
| Richard Sandiford | c212125 | 2013-08-05 11:23:46 +0000 | [diff] [blame] | 38 | STATISTIC(BranchOnCounts, "Number of branch-on-count instructions"); | 
| Ulrich Weigand | 2d9e3d9 | 2016-11-28 13:59:22 +0000 | [diff] [blame] | 39 | STATISTIC(LoadAndTraps, "Number of load-and-trap instructions"); | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 40 | STATISTIC(EliminatedComparisons, "Number of eliminated comparisons"); | 
|  | 41 | STATISTIC(FusedComparisons, "Number of fused compare-and-branch instructions"); | 
|  | 42 |  | 
|  | 43 | namespace { | 
| Eugene Zelenko | 3943d2b | 2017-01-24 22:10:43 +0000 | [diff] [blame] | 44 |  | 
| Richard Sandiford | c231269 | 2014-03-06 10:38:30 +0000 | [diff] [blame] | 45 | // Represents the references to a particular register in one or more | 
|  | 46 | // instructions. | 
|  | 47 | struct Reference { | 
| Eugene Zelenko | 3943d2b | 2017-01-24 22:10:43 +0000 | [diff] [blame] | 48 | Reference() = default; | 
| Richard Sandiford | c212125 | 2013-08-05 11:23:46 +0000 | [diff] [blame] | 49 |  | 
| Richard Sandiford | c231269 | 2014-03-06 10:38:30 +0000 | [diff] [blame] | 50 | Reference &operator|=(const Reference &Other) { | 
|  | 51 | Def |= Other.Def; | 
| Richard Sandiford | c231269 | 2014-03-06 10:38:30 +0000 | [diff] [blame] | 52 | Use |= Other.Use; | 
| Richard Sandiford | c231269 | 2014-03-06 10:38:30 +0000 | [diff] [blame] | 53 | return *this; | 
|  | 54 | } | 
| Richard Sandiford | c212125 | 2013-08-05 11:23:46 +0000 | [diff] [blame] | 55 |  | 
| Aaron Ballman | b46962f | 2015-02-15 22:00:20 +0000 | [diff] [blame] | 56 | explicit operator bool() const { return Def || Use; } | 
| Richard Sandiford | c212125 | 2013-08-05 11:23:46 +0000 | [diff] [blame] | 57 |  | 
| Richard Sandiford | c231269 | 2014-03-06 10:38:30 +0000 | [diff] [blame] | 58 | // True if the register is defined or used in some form, either directly or | 
|  | 59 | // via a sub- or super-register. | 
| Eugene Zelenko | 3943d2b | 2017-01-24 22:10:43 +0000 | [diff] [blame] | 60 | bool Def = false; | 
|  | 61 | bool Use = false; | 
| Richard Sandiford | c231269 | 2014-03-06 10:38:30 +0000 | [diff] [blame] | 62 | }; | 
| Richard Sandiford | c212125 | 2013-08-05 11:23:46 +0000 | [diff] [blame] | 63 |  | 
| Richard Sandiford | c231269 | 2014-03-06 10:38:30 +0000 | [diff] [blame] | 64 | class SystemZElimCompare : public MachineFunctionPass { | 
|  | 65 | public: | 
|  | 66 | static char ID; | 
| Eugene Zelenko | 3943d2b | 2017-01-24 22:10:43 +0000 | [diff] [blame] | 67 |  | 
| Richard Sandiford | c231269 | 2014-03-06 10:38:30 +0000 | [diff] [blame] | 68 | SystemZElimCompare(const SystemZTargetMachine &tm) | 
| Eugene Zelenko | 3943d2b | 2017-01-24 22:10:43 +0000 | [diff] [blame] | 69 | : MachineFunctionPass(ID) {} | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 70 |  | 
| Mehdi Amini | 117296c | 2016-10-01 02:56:57 +0000 | [diff] [blame] | 71 | StringRef getPassName() const override { | 
| Richard Sandiford | c231269 | 2014-03-06 10:38:30 +0000 | [diff] [blame] | 72 | return "SystemZ Comparison Elimination"; | 
|  | 73 | } | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 74 |  | 
| Richard Sandiford | 28c111e | 2014-03-06 11:00:15 +0000 | [diff] [blame] | 75 | bool processBlock(MachineBasicBlock &MBB); | 
| Craig Topper | 9d74a5a | 2014-04-29 07:58:41 +0000 | [diff] [blame] | 76 | bool runOnMachineFunction(MachineFunction &F) override; | 
| Eugene Zelenko | 3943d2b | 2017-01-24 22:10:43 +0000 | [diff] [blame] | 77 |  | 
| Derek Schuff | 1dbf7a5 | 2016-04-04 17:09:25 +0000 | [diff] [blame] | 78 | MachineFunctionProperties getRequiredProperties() const override { | 
|  | 79 | return MachineFunctionProperties().set( | 
| Matthias Braun | 1eb4736 | 2016-08-25 01:27:13 +0000 | [diff] [blame] | 80 | MachineFunctionProperties::Property::NoVRegs); | 
| Derek Schuff | 1dbf7a5 | 2016-04-04 17:09:25 +0000 | [diff] [blame] | 81 | } | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 82 |  | 
| Richard Sandiford | c231269 | 2014-03-06 10:38:30 +0000 | [diff] [blame] | 83 | private: | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 84 | Reference getRegReferences(MachineInstr &MI, unsigned Reg); | 
|  | 85 | bool convertToBRCT(MachineInstr &MI, MachineInstr &Compare, | 
| Richard Sandiford | c231269 | 2014-03-06 10:38:30 +0000 | [diff] [blame] | 86 | SmallVectorImpl<MachineInstr *> &CCUsers); | 
| Ulrich Weigand | 2d9e3d9 | 2016-11-28 13:59:22 +0000 | [diff] [blame] | 87 | bool convertToLoadAndTrap(MachineInstr &MI, MachineInstr &Compare, | 
|  | 88 | SmallVectorImpl<MachineInstr *> &CCUsers); | 
| Jonas Paulsson | 776a81a | 2018-01-15 15:41:26 +0000 | [diff] [blame] | 89 | bool convertToLoadAndTest(MachineInstr &MI, MachineInstr &Compare, | 
|  | 90 | SmallVectorImpl<MachineInstr *> &CCUsers); | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 91 | bool adjustCCMasksForInstr(MachineInstr &MI, MachineInstr &Compare, | 
| Jonas Paulsson | 776a81a | 2018-01-15 15:41:26 +0000 | [diff] [blame] | 92 | SmallVectorImpl<MachineInstr *> &CCUsers, | 
|  | 93 | unsigned ConvOpc = 0); | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 94 | bool optimizeCompareZero(MachineInstr &Compare, | 
| Richard Sandiford | c231269 | 2014-03-06 10:38:30 +0000 | [diff] [blame] | 95 | SmallVectorImpl<MachineInstr *> &CCUsers); | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 96 | bool fuseCompareOperations(MachineInstr &Compare, | 
| Zhan Jun Liau | ab42cbc | 2016-06-10 19:58:10 +0000 | [diff] [blame] | 97 | SmallVectorImpl<MachineInstr *> &CCUsers); | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 98 |  | 
| Eugene Zelenko | 3943d2b | 2017-01-24 22:10:43 +0000 | [diff] [blame] | 99 | const SystemZInstrInfo *TII = nullptr; | 
|  | 100 | const TargetRegisterInfo *TRI = nullptr; | 
| Richard Sandiford | c231269 | 2014-03-06 10:38:30 +0000 | [diff] [blame] | 101 | }; | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 102 |  | 
| Richard Sandiford | c231269 | 2014-03-06 10:38:30 +0000 | [diff] [blame] | 103 | char SystemZElimCompare::ID = 0; | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 104 |  | 
| Eugene Zelenko | 3943d2b | 2017-01-24 22:10:43 +0000 | [diff] [blame] | 105 | } // end anonymous namespace | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 106 |  | 
|  | 107 | // Return true if CC is live out of MBB. | 
| Richard Sandiford | 28c111e | 2014-03-06 11:00:15 +0000 | [diff] [blame] | 108 | static bool isCCLiveOut(MachineBasicBlock &MBB) { | 
|  | 109 | for (auto SI = MBB.succ_begin(), SE = MBB.succ_end(); SI != SE; ++SI) | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 110 | if ((*SI)->isLiveIn(SystemZ::CC)) | 
|  | 111 | return true; | 
|  | 112 | return false; | 
|  | 113 | } | 
|  | 114 |  | 
| Jonas Paulsson | b0e8a2e | 2017-09-21 13:52:24 +0000 | [diff] [blame] | 115 | // Returns true if MI is an instruction whose output equals the value in Reg. | 
|  | 116 | static bool preservesValueOf(MachineInstr &MI, unsigned Reg) { | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 117 | switch (MI.getOpcode()) { | 
| Richard Sandiford | b49a3ab | 2013-08-05 11:03:20 +0000 | [diff] [blame] | 118 | case SystemZ::LR: | 
|  | 119 | case SystemZ::LGR: | 
|  | 120 | case SystemZ::LGFR: | 
|  | 121 | case SystemZ::LTR: | 
|  | 122 | case SystemZ::LTGR: | 
|  | 123 | case SystemZ::LTGFR: | 
| Richard Sandiford | 0897fce | 2013-08-07 11:10:06 +0000 | [diff] [blame] | 124 | case SystemZ::LER: | 
|  | 125 | case SystemZ::LDR: | 
|  | 126 | case SystemZ::LXR: | 
|  | 127 | case SystemZ::LTEBR: | 
|  | 128 | case SystemZ::LTDBR: | 
|  | 129 | case SystemZ::LTXBR: | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 130 | if (MI.getOperand(1).getReg() == Reg) | 
| Richard Sandiford | b49a3ab | 2013-08-05 11:03:20 +0000 | [diff] [blame] | 131 | return true; | 
|  | 132 | } | 
|  | 133 |  | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 134 | return false; | 
|  | 135 | } | 
|  | 136 |  | 
| Jonas Paulsson | b0e8a2e | 2017-09-21 13:52:24 +0000 | [diff] [blame] | 137 | // Return true if any CC result of MI would (perhaps after conversion) | 
|  | 138 | // reflect the value of Reg. | 
|  | 139 | static bool resultTests(MachineInstr &MI, unsigned Reg) { | 
|  | 140 | if (MI.getNumOperands() > 0 && MI.getOperand(0).isReg() && | 
|  | 141 | MI.getOperand(0).isDef() && MI.getOperand(0).getReg() == Reg) | 
|  | 142 | return true; | 
|  | 143 |  | 
|  | 144 | return (preservesValueOf(MI, Reg)); | 
|  | 145 | } | 
|  | 146 |  | 
| Jonas Paulsson | ee3685f | 2015-10-09 11:27:44 +0000 | [diff] [blame] | 147 | // Describe the references to Reg or any of its aliases in MI. | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 148 | Reference SystemZElimCompare::getRegReferences(MachineInstr &MI, unsigned Reg) { | 
| Richard Sandiford | c212125 | 2013-08-05 11:23:46 +0000 | [diff] [blame] | 149 | Reference Ref; | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 150 | for (unsigned I = 0, E = MI.getNumOperands(); I != E; ++I) { | 
|  | 151 | const MachineOperand &MO = MI.getOperand(I); | 
| Richard Sandiford | c212125 | 2013-08-05 11:23:46 +0000 | [diff] [blame] | 152 | if (MO.isReg()) { | 
|  | 153 | if (unsigned MOReg = MO.getReg()) { | 
| Jonas Paulsson | ee3685f | 2015-10-09 11:27:44 +0000 | [diff] [blame] | 154 | if (TRI->regsOverlap(MOReg, Reg)) { | 
|  | 155 | if (MO.isUse()) | 
| Richard Sandiford | c212125 | 2013-08-05 11:23:46 +0000 | [diff] [blame] | 156 | Ref.Use = true; | 
| Jonas Paulsson | ee3685f | 2015-10-09 11:27:44 +0000 | [diff] [blame] | 157 | else if (MO.isDef()) | 
| Richard Sandiford | c212125 | 2013-08-05 11:23:46 +0000 | [diff] [blame] | 158 | Ref.Def = true; | 
| Richard Sandiford | c212125 | 2013-08-05 11:23:46 +0000 | [diff] [blame] | 159 | } | 
|  | 160 | } | 
|  | 161 | } | 
|  | 162 | } | 
|  | 163 | return Ref; | 
|  | 164 | } | 
|  | 165 |  | 
| Jonas Paulsson | 5d3fbd3 | 2015-10-08 07:40:23 +0000 | [diff] [blame] | 166 | // Return true if this is a load and test which can be optimized the | 
|  | 167 | // same way as compare instruction. | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 168 | static bool isLoadAndTestAsCmp(MachineInstr &MI) { | 
| Jonas Paulsson | 5d3fbd3 | 2015-10-08 07:40:23 +0000 | [diff] [blame] | 169 | // If we during isel used a load-and-test as a compare with 0, the | 
|  | 170 | // def operand is dead. | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 171 | return (MI.getOpcode() == SystemZ::LTEBR || | 
|  | 172 | MI.getOpcode() == SystemZ::LTDBR || | 
|  | 173 | MI.getOpcode() == SystemZ::LTXBR) && | 
|  | 174 | MI.getOperand(0).isDead(); | 
| Jonas Paulsson | 5d3fbd3 | 2015-10-08 07:40:23 +0000 | [diff] [blame] | 175 | } | 
|  | 176 |  | 
|  | 177 | // Return the source register of Compare, which is the unknown value | 
|  | 178 | // being tested. | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 179 | static unsigned getCompareSourceReg(MachineInstr &Compare) { | 
| Jonas Paulsson | 5d3fbd3 | 2015-10-08 07:40:23 +0000 | [diff] [blame] | 180 | unsigned reg = 0; | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 181 | if (Compare.isCompare()) | 
|  | 182 | reg = Compare.getOperand(0).getReg(); | 
| Jonas Paulsson | 5d3fbd3 | 2015-10-08 07:40:23 +0000 | [diff] [blame] | 183 | else if (isLoadAndTestAsCmp(Compare)) | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 184 | reg = Compare.getOperand(1).getReg(); | 
| Eugene Zelenko | 3943d2b | 2017-01-24 22:10:43 +0000 | [diff] [blame] | 185 | assert(reg); | 
| Jonas Paulsson | 5d3fbd3 | 2015-10-08 07:40:23 +0000 | [diff] [blame] | 186 |  | 
|  | 187 | return reg; | 
|  | 188 | } | 
|  | 189 |  | 
| Richard Sandiford | c212125 | 2013-08-05 11:23:46 +0000 | [diff] [blame] | 190 | // Compare compares the result of MI against zero.  If MI is an addition | 
|  | 191 | // of -1 and if CCUsers is a single branch on nonzero, eliminate the addition | 
| Ulrich Weigand | 7583991 | 2016-11-28 13:40:08 +0000 | [diff] [blame] | 192 | // and convert the branch to a BRCT(G) or BRCTH.  Return true on success. | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 193 | bool SystemZElimCompare::convertToBRCT( | 
|  | 194 | MachineInstr &MI, MachineInstr &Compare, | 
|  | 195 | SmallVectorImpl<MachineInstr *> &CCUsers) { | 
| Richard Sandiford | c212125 | 2013-08-05 11:23:46 +0000 | [diff] [blame] | 196 | // Check whether we have an addition of -1. | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 197 | unsigned Opcode = MI.getOpcode(); | 
| Richard Sandiford | c212125 | 2013-08-05 11:23:46 +0000 | [diff] [blame] | 198 | unsigned BRCT; | 
|  | 199 | if (Opcode == SystemZ::AHI) | 
|  | 200 | BRCT = SystemZ::BRCT; | 
|  | 201 | else if (Opcode == SystemZ::AGHI) | 
|  | 202 | BRCT = SystemZ::BRCTG; | 
| Ulrich Weigand | 7583991 | 2016-11-28 13:40:08 +0000 | [diff] [blame] | 203 | else if (Opcode == SystemZ::AIH) | 
|  | 204 | BRCT = SystemZ::BRCTH; | 
| Richard Sandiford | c212125 | 2013-08-05 11:23:46 +0000 | [diff] [blame] | 205 | else | 
|  | 206 | return false; | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 207 | if (MI.getOperand(2).getImm() != -1) | 
| Richard Sandiford | c212125 | 2013-08-05 11:23:46 +0000 | [diff] [blame] | 208 | return false; | 
|  | 209 |  | 
|  | 210 | // Check whether we have a single JLH. | 
|  | 211 | if (CCUsers.size() != 1) | 
|  | 212 | return false; | 
|  | 213 | MachineInstr *Branch = CCUsers[0]; | 
|  | 214 | if (Branch->getOpcode() != SystemZ::BRC || | 
|  | 215 | Branch->getOperand(0).getImm() != SystemZ::CCMASK_ICMP || | 
|  | 216 | Branch->getOperand(1).getImm() != SystemZ::CCMASK_CMP_NE) | 
|  | 217 | return false; | 
|  | 218 |  | 
|  | 219 | // We already know that there are no references to the register between | 
|  | 220 | // MI and Compare.  Make sure that there are also no references between | 
|  | 221 | // Compare and Branch. | 
| Jonas Paulsson | 5d3fbd3 | 2015-10-08 07:40:23 +0000 | [diff] [blame] | 222 | unsigned SrcReg = getCompareSourceReg(Compare); | 
| Richard Sandiford | c212125 | 2013-08-05 11:23:46 +0000 | [diff] [blame] | 223 | MachineBasicBlock::iterator MBBI = Compare, MBBE = Branch; | 
|  | 224 | for (++MBBI; MBBI != MBBE; ++MBBI) | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 225 | if (getRegReferences(*MBBI, SrcReg)) | 
| Richard Sandiford | c212125 | 2013-08-05 11:23:46 +0000 | [diff] [blame] | 226 | return false; | 
|  | 227 |  | 
| Ulrich Weigand | 7583991 | 2016-11-28 13:40:08 +0000 | [diff] [blame] | 228 | // The transformation is OK.  Rebuild Branch as a BRCT(G) or BRCTH. | 
| Richard Sandiford | c212125 | 2013-08-05 11:23:46 +0000 | [diff] [blame] | 229 | MachineOperand Target(Branch->getOperand(2)); | 
| Jonas Paulsson | 63a2b68 | 2015-10-10 07:14:24 +0000 | [diff] [blame] | 230 | while (Branch->getNumOperands()) | 
|  | 231 | Branch->RemoveOperand(0); | 
| Richard Sandiford | c212125 | 2013-08-05 11:23:46 +0000 | [diff] [blame] | 232 | Branch->setDesc(TII->get(BRCT)); | 
| Ulrich Weigand | 7583991 | 2016-11-28 13:40:08 +0000 | [diff] [blame] | 233 | MachineInstrBuilder MIB(*Branch->getParent()->getParent(), Branch); | 
| Diana Picus | 116bbab | 2017-01-13 09:58:52 +0000 | [diff] [blame] | 234 | MIB.add(MI.getOperand(0)).add(MI.getOperand(1)).add(Target); | 
| Ulrich Weigand | 7583991 | 2016-11-28 13:40:08 +0000 | [diff] [blame] | 235 | // Add a CC def to BRCT(G), since we may have to split them again if the | 
|  | 236 | // branch displacement overflows.  BRCTH has a 32-bit displacement, so | 
|  | 237 | // this is not necessary there. | 
|  | 238 | if (BRCT != SystemZ::BRCTH) | 
|  | 239 | MIB.addReg(SystemZ::CC, RegState::ImplicitDefine | RegState::Dead); | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 240 | MI.eraseFromParent(); | 
| Richard Sandiford | c212125 | 2013-08-05 11:23:46 +0000 | [diff] [blame] | 241 | return true; | 
|  | 242 | } | 
|  | 243 |  | 
| Ulrich Weigand | 2d9e3d9 | 2016-11-28 13:59:22 +0000 | [diff] [blame] | 244 | // Compare compares the result of MI against zero.  If MI is a suitable load | 
|  | 245 | // instruction and if CCUsers is a single conditional trap on zero, eliminate | 
|  | 246 | // the load and convert the branch to a load-and-trap.  Return true on success. | 
|  | 247 | bool SystemZElimCompare::convertToLoadAndTrap( | 
|  | 248 | MachineInstr &MI, MachineInstr &Compare, | 
|  | 249 | SmallVectorImpl<MachineInstr *> &CCUsers) { | 
|  | 250 | unsigned LATOpcode = TII->getLoadAndTrap(MI.getOpcode()); | 
|  | 251 | if (!LATOpcode) | 
|  | 252 | return false; | 
|  | 253 |  | 
|  | 254 | // Check whether we have a single CondTrap that traps on zero. | 
|  | 255 | if (CCUsers.size() != 1) | 
|  | 256 | return false; | 
|  | 257 | MachineInstr *Branch = CCUsers[0]; | 
|  | 258 | if (Branch->getOpcode() != SystemZ::CondTrap || | 
|  | 259 | Branch->getOperand(0).getImm() != SystemZ::CCMASK_ICMP || | 
|  | 260 | Branch->getOperand(1).getImm() != SystemZ::CCMASK_CMP_EQ) | 
|  | 261 | return false; | 
|  | 262 |  | 
|  | 263 | // We already know that there are no references to the register between | 
|  | 264 | // MI and Compare.  Make sure that there are also no references between | 
|  | 265 | // Compare and Branch. | 
|  | 266 | unsigned SrcReg = getCompareSourceReg(Compare); | 
|  | 267 | MachineBasicBlock::iterator MBBI = Compare, MBBE = Branch; | 
|  | 268 | for (++MBBI; MBBI != MBBE; ++MBBI) | 
|  | 269 | if (getRegReferences(*MBBI, SrcReg)) | 
|  | 270 | return false; | 
|  | 271 |  | 
|  | 272 | // The transformation is OK.  Rebuild Branch as a load-and-trap. | 
| Ulrich Weigand | 2d9e3d9 | 2016-11-28 13:59:22 +0000 | [diff] [blame] | 273 | while (Branch->getNumOperands()) | 
|  | 274 | Branch->RemoveOperand(0); | 
|  | 275 | Branch->setDesc(TII->get(LATOpcode)); | 
|  | 276 | MachineInstrBuilder(*Branch->getParent()->getParent(), Branch) | 
| Diana Picus | 116bbab | 2017-01-13 09:58:52 +0000 | [diff] [blame] | 277 | .add(MI.getOperand(0)) | 
|  | 278 | .add(MI.getOperand(1)) | 
|  | 279 | .add(MI.getOperand(2)) | 
|  | 280 | .add(MI.getOperand(3)); | 
| Ulrich Weigand | 2d9e3d9 | 2016-11-28 13:59:22 +0000 | [diff] [blame] | 281 | MI.eraseFromParent(); | 
|  | 282 | return true; | 
|  | 283 | } | 
|  | 284 |  | 
| Richard Sandiford | b49a3ab | 2013-08-05 11:03:20 +0000 | [diff] [blame] | 285 | // If MI is a load instruction, try to convert it into a LOAD AND TEST. | 
|  | 286 | // Return true on success. | 
| Jonas Paulsson | 776a81a | 2018-01-15 15:41:26 +0000 | [diff] [blame] | 287 | bool SystemZElimCompare::convertToLoadAndTest( | 
|  | 288 | MachineInstr &MI, MachineInstr &Compare, | 
|  | 289 | SmallVectorImpl<MachineInstr *> &CCUsers) { | 
|  | 290 |  | 
|  | 291 | // Try to adjust CC masks for the LOAD AND TEST opcode that could replace MI. | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 292 | unsigned Opcode = TII->getLoadAndTest(MI.getOpcode()); | 
| Jonas Paulsson | 776a81a | 2018-01-15 15:41:26 +0000 | [diff] [blame] | 293 | if (!Opcode || !adjustCCMasksForInstr(MI, Compare, CCUsers, Opcode)) | 
| Richard Sandiford | b49a3ab | 2013-08-05 11:03:20 +0000 | [diff] [blame] | 294 | return false; | 
|  | 295 |  | 
| Jonas Paulsson | e80d405 | 2018-06-07 05:59:07 +0000 | [diff] [blame] | 296 | // Rebuild to get the CC operand in the right place. | 
| Chandler Carruth | c73c030 | 2018-08-16 21:30:05 +0000 | [diff] [blame] | 297 | auto MIB = BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII->get(Opcode)); | 
| Jonas Paulsson | e80d405 | 2018-06-07 05:59:07 +0000 | [diff] [blame] | 298 | for (const auto &MO : MI.operands()) | 
| Chandler Carruth | c73c030 | 2018-08-16 21:30:05 +0000 | [diff] [blame] | 299 | MIB.add(MO); | 
|  | 300 | MIB.setMemRefs(MI.memoperands()); | 
| Jonas Paulsson | e80d405 | 2018-06-07 05:59:07 +0000 | [diff] [blame] | 301 | MI.eraseFromParent(); | 
|  | 302 |  | 
| Richard Sandiford | b49a3ab | 2013-08-05 11:03:20 +0000 | [diff] [blame] | 303 | return true; | 
|  | 304 | } | 
|  | 305 |  | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 306 | // The CC users in CCUsers are testing the result of a comparison of some | 
| Jonas Paulsson | 776a81a | 2018-01-15 15:41:26 +0000 | [diff] [blame] | 307 | // value X against zero and we know that any CC value produced by MI would | 
|  | 308 | // also reflect the value of X.  ConvOpc may be used to pass the transfomed | 
|  | 309 | // opcode MI will have if this succeeds.  Try to adjust CCUsers so that they | 
|  | 310 | // test the result of MI directly, returning true on success.  Leave | 
|  | 311 | // everything unchanged on failure. | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 312 | bool SystemZElimCompare::adjustCCMasksForInstr( | 
|  | 313 | MachineInstr &MI, MachineInstr &Compare, | 
| Jonas Paulsson | 776a81a | 2018-01-15 15:41:26 +0000 | [diff] [blame] | 314 | SmallVectorImpl<MachineInstr *> &CCUsers, | 
|  | 315 | unsigned ConvOpc) { | 
|  | 316 | int Opcode = (ConvOpc ? ConvOpc : MI.getOpcode()); | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 317 | const MCInstrDesc &Desc = TII->get(Opcode); | 
|  | 318 | unsigned MIFlags = Desc.TSFlags; | 
|  | 319 |  | 
|  | 320 | // See which compare-style condition codes are available. | 
| Richard Sandiford | 0897fce | 2013-08-07 11:10:06 +0000 | [diff] [blame] | 321 | unsigned ReusableCCMask = SystemZII::getCompareZeroCCMask(MIFlags); | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 322 |  | 
|  | 323 | // For unsigned comparisons with zero, only equality makes sense. | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 324 | unsigned CompareFlags = Compare.getDesc().TSFlags; | 
| Richard Sandiford | 0897fce | 2013-08-07 11:10:06 +0000 | [diff] [blame] | 325 | if (CompareFlags & SystemZII::IsLogical) | 
|  | 326 | ReusableCCMask &= SystemZ::CCMASK_CMP_EQ; | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 327 |  | 
|  | 328 | if (ReusableCCMask == 0) | 
|  | 329 | return false; | 
|  | 330 |  | 
|  | 331 | unsigned CCValues = SystemZII::getCCValues(MIFlags); | 
|  | 332 | assert((ReusableCCMask & ~CCValues) == 0 && "Invalid CCValues"); | 
|  | 333 |  | 
| Jonas Paulsson | 776a81a | 2018-01-15 15:41:26 +0000 | [diff] [blame] | 334 | bool MIEquivalentToCmp = | 
|  | 335 | (ReusableCCMask == CCValues && | 
|  | 336 | CCValues == SystemZII::getCCValues(CompareFlags)); | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 337 |  | 
| Jonas Paulsson | 776a81a | 2018-01-15 15:41:26 +0000 | [diff] [blame] | 338 | if (!MIEquivalentToCmp) { | 
|  | 339 | // Now check whether these flags are enough for all users. | 
|  | 340 | SmallVector<MachineOperand *, 4> AlterMasks; | 
|  | 341 | for (unsigned int I = 0, E = CCUsers.size(); I != E; ++I) { | 
|  | 342 | MachineInstr *MI = CCUsers[I]; | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 343 |  | 
| Jonas Paulsson | 776a81a | 2018-01-15 15:41:26 +0000 | [diff] [blame] | 344 | // Fail if this isn't a use of CC that we understand. | 
|  | 345 | unsigned Flags = MI->getDesc().TSFlags; | 
|  | 346 | unsigned FirstOpNum; | 
|  | 347 | if (Flags & SystemZII::CCMaskFirst) | 
|  | 348 | FirstOpNum = 0; | 
|  | 349 | else if (Flags & SystemZII::CCMaskLast) | 
|  | 350 | FirstOpNum = MI->getNumExplicitOperands() - 2; | 
|  | 351 | else | 
|  | 352 | return false; | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 353 |  | 
| Jonas Paulsson | 776a81a | 2018-01-15 15:41:26 +0000 | [diff] [blame] | 354 | // Check whether the instruction predicate treats all CC values | 
|  | 355 | // outside of ReusableCCMask in the same way.  In that case it | 
|  | 356 | // doesn't matter what those CC values mean. | 
|  | 357 | unsigned CCValid = MI->getOperand(FirstOpNum).getImm(); | 
|  | 358 | unsigned CCMask = MI->getOperand(FirstOpNum + 1).getImm(); | 
|  | 359 | unsigned OutValid = ~ReusableCCMask & CCValid; | 
|  | 360 | unsigned OutMask = ~ReusableCCMask & CCMask; | 
|  | 361 | if (OutMask != 0 && OutMask != OutValid) | 
|  | 362 | return false; | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 363 |  | 
| Jonas Paulsson | 776a81a | 2018-01-15 15:41:26 +0000 | [diff] [blame] | 364 | AlterMasks.push_back(&MI->getOperand(FirstOpNum)); | 
|  | 365 | AlterMasks.push_back(&MI->getOperand(FirstOpNum + 1)); | 
|  | 366 | } | 
|  | 367 |  | 
|  | 368 | // All users are OK.  Adjust the masks for MI. | 
|  | 369 | for (unsigned I = 0, E = AlterMasks.size(); I != E; I += 2) { | 
|  | 370 | AlterMasks[I]->setImm(CCValues); | 
|  | 371 | unsigned CCMask = AlterMasks[I + 1]->getImm(); | 
|  | 372 | if (CCMask & ~ReusableCCMask) | 
|  | 373 | AlterMasks[I + 1]->setImm((CCMask & ReusableCCMask) | | 
|  | 374 | (CCValues & ~ReusableCCMask)); | 
|  | 375 | } | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 376 | } | 
|  | 377 |  | 
|  | 378 | // CC is now live after MI. | 
| Jonas Paulsson | 776a81a | 2018-01-15 15:41:26 +0000 | [diff] [blame] | 379 | if (!ConvOpc) { | 
|  | 380 | int CCDef = MI.findRegisterDefOperandIdx(SystemZ::CC, false, true, TRI); | 
|  | 381 | assert(CCDef >= 0 && "Couldn't find CC set"); | 
|  | 382 | MI.getOperand(CCDef).setIsDead(false); | 
|  | 383 | } | 
|  | 384 |  | 
|  | 385 | // Check if MI lies before Compare. | 
|  | 386 | bool BeforeCmp = false; | 
|  | 387 | MachineBasicBlock::iterator MBBI = MI, MBBE = MI.getParent()->end(); | 
|  | 388 | for (++MBBI; MBBI != MBBE; ++MBBI) | 
|  | 389 | if (MBBI == Compare) { | 
|  | 390 | BeforeCmp = true; | 
|  | 391 | break; | 
|  | 392 | } | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 393 |  | 
|  | 394 | // Clear any intervening kills of CC. | 
| Jonas Paulsson | 776a81a | 2018-01-15 15:41:26 +0000 | [diff] [blame] | 395 | if (BeforeCmp) { | 
|  | 396 | MachineBasicBlock::iterator MBBI = MI, MBBE = Compare; | 
|  | 397 | for (++MBBI; MBBI != MBBE; ++MBBI) | 
|  | 398 | MBBI->clearRegisterKills(SystemZ::CC, TRI); | 
|  | 399 | } | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 400 |  | 
|  | 401 | return true; | 
|  | 402 | } | 
|  | 403 |  | 
| Richard Sandiford | 0897fce | 2013-08-07 11:10:06 +0000 | [diff] [blame] | 404 | // Return true if Compare is a comparison against zero. | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 405 | static bool isCompareZero(MachineInstr &Compare) { | 
|  | 406 | switch (Compare.getOpcode()) { | 
| Richard Sandiford | 0897fce | 2013-08-07 11:10:06 +0000 | [diff] [blame] | 407 | case SystemZ::LTEBRCompare: | 
|  | 408 | case SystemZ::LTDBRCompare: | 
|  | 409 | case SystemZ::LTXBRCompare: | 
|  | 410 | return true; | 
|  | 411 |  | 
|  | 412 | default: | 
| Jonas Paulsson | 5d3fbd3 | 2015-10-08 07:40:23 +0000 | [diff] [blame] | 413 | if (isLoadAndTestAsCmp(Compare)) | 
|  | 414 | return true; | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 415 | return Compare.getNumExplicitOperands() == 2 && | 
|  | 416 | Compare.getOperand(1).isImm() && Compare.getOperand(1).getImm() == 0; | 
| Richard Sandiford | 0897fce | 2013-08-07 11:10:06 +0000 | [diff] [blame] | 417 | } | 
|  | 418 | } | 
|  | 419 |  | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 420 | // Try to optimize cases where comparison instruction Compare is testing | 
|  | 421 | // a value against zero.  Return true on success and if Compare should be | 
|  | 422 | // deleted as dead.  CCUsers is the list of instructions that use the CC | 
|  | 423 | // value produced by Compare. | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 424 | bool SystemZElimCompare::optimizeCompareZero( | 
|  | 425 | MachineInstr &Compare, SmallVectorImpl<MachineInstr *> &CCUsers) { | 
| Richard Sandiford | 0897fce | 2013-08-07 11:10:06 +0000 | [diff] [blame] | 426 | if (!isCompareZero(Compare)) | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 427 | return false; | 
|  | 428 |  | 
|  | 429 | // Search back for CC results that are based on the first operand. | 
| Jonas Paulsson | 5d3fbd3 | 2015-10-08 07:40:23 +0000 | [diff] [blame] | 430 | unsigned SrcReg = getCompareSourceReg(Compare); | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 431 | MachineBasicBlock &MBB = *Compare.getParent(); | 
| Richard Sandiford | c212125 | 2013-08-05 11:23:46 +0000 | [diff] [blame] | 432 | Reference CCRefs; | 
|  | 433 | Reference SrcRefs; | 
| Jonas Paulsson | e80d405 | 2018-06-07 05:59:07 +0000 | [diff] [blame] | 434 | for (MachineBasicBlock::reverse_iterator MBBI = | 
|  | 435 | std::next(MachineBasicBlock::reverse_iterator(&Compare)), | 
|  | 436 | MBBE = MBB.rend(); MBBI != MBBE;) { | 
|  | 437 | MachineInstr &MI = *MBBI++; | 
| Jonas Paulsson | 2c96dd6 | 2015-10-08 07:40:11 +0000 | [diff] [blame] | 438 | if (resultTests(MI, SrcReg)) { | 
| Richard Sandiford | c212125 | 2013-08-05 11:23:46 +0000 | [diff] [blame] | 439 | // Try to remove both MI and Compare by converting a branch to BRCT(G). | 
| Ulrich Weigand | 2d9e3d9 | 2016-11-28 13:59:22 +0000 | [diff] [blame] | 440 | // or a load-and-trap instruction.  We don't care in this case whether | 
|  | 441 | // CC is modified between MI and Compare. | 
|  | 442 | if (!CCRefs.Use && !SrcRefs) { | 
|  | 443 | if (convertToBRCT(MI, Compare, CCUsers)) { | 
|  | 444 | BranchOnCounts += 1; | 
|  | 445 | return true; | 
|  | 446 | } | 
|  | 447 | if (convertToLoadAndTrap(MI, Compare, CCUsers)) { | 
|  | 448 | LoadAndTraps += 1; | 
|  | 449 | return true; | 
|  | 450 | } | 
| Richard Sandiford | c212125 | 2013-08-05 11:23:46 +0000 | [diff] [blame] | 451 | } | 
|  | 452 | // Try to eliminate Compare by reusing a CC result from MI. | 
| Jonas Paulsson | 776a81a | 2018-01-15 15:41:26 +0000 | [diff] [blame] | 453 | if ((!CCRefs && convertToLoadAndTest(MI, Compare, CCUsers)) || | 
| Richard Sandiford | c212125 | 2013-08-05 11:23:46 +0000 | [diff] [blame] | 454 | (!CCRefs.Def && adjustCCMasksForInstr(MI, Compare, CCUsers))) { | 
|  | 455 | EliminatedComparisons += 1; | 
|  | 456 | return true; | 
|  | 457 | } | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 458 | } | 
| Richard Sandiford | c212125 | 2013-08-05 11:23:46 +0000 | [diff] [blame] | 459 | SrcRefs |= getRegReferences(MI, SrcReg); | 
|  | 460 | if (SrcRefs.Def) | 
| Jonas Paulsson | b0e8a2e | 2017-09-21 13:52:24 +0000 | [diff] [blame] | 461 | break; | 
| Richard Sandiford | c212125 | 2013-08-05 11:23:46 +0000 | [diff] [blame] | 462 | CCRefs |= getRegReferences(MI, SystemZ::CC); | 
|  | 463 | if (CCRefs.Use && CCRefs.Def) | 
| Jonas Paulsson | b0e8a2e | 2017-09-21 13:52:24 +0000 | [diff] [blame] | 464 | break; | 
|  | 465 | } | 
|  | 466 |  | 
|  | 467 | // Also do a forward search to handle cases where an instruction after the | 
| Jonas Paulsson | 22f208f | 2018-01-08 12:52:40 +0000 | [diff] [blame] | 468 | // compare can be converted, like | 
|  | 469 | // LTEBRCompare %f0s, %f0s; %f2s = LER %f0s  =>  LTEBRCompare %f2s, %f0s | 
| Jonas Paulsson | e80d405 | 2018-06-07 05:59:07 +0000 | [diff] [blame] | 470 | for (MachineBasicBlock::iterator MBBI = | 
|  | 471 | std::next(MachineBasicBlock::iterator(&Compare)), MBBE = MBB.end(); | 
|  | 472 | MBBI != MBBE;) { | 
|  | 473 | MachineInstr &MI = *MBBI++; | 
| Jonas Paulsson | b0e8a2e | 2017-09-21 13:52:24 +0000 | [diff] [blame] | 474 | if (preservesValueOf(MI, SrcReg)) { | 
|  | 475 | // Try to eliminate Compare by reusing a CC result from MI. | 
| Jonas Paulsson | 776a81a | 2018-01-15 15:41:26 +0000 | [diff] [blame] | 476 | if (convertToLoadAndTest(MI, Compare, CCUsers)) { | 
| Jonas Paulsson | b0e8a2e | 2017-09-21 13:52:24 +0000 | [diff] [blame] | 477 | EliminatedComparisons += 1; | 
|  | 478 | return true; | 
|  | 479 | } | 
|  | 480 | } | 
|  | 481 | if (getRegReferences(MI, SrcReg).Def) | 
|  | 482 | return false; | 
|  | 483 | if (getRegReferences(MI, SystemZ::CC)) | 
| Richard Sandiford | c212125 | 2013-08-05 11:23:46 +0000 | [diff] [blame] | 484 | return false; | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 485 | } | 
| Jonas Paulsson | b0e8a2e | 2017-09-21 13:52:24 +0000 | [diff] [blame] | 486 |  | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 487 | return false; | 
|  | 488 | } | 
|  | 489 |  | 
|  | 490 | // Try to fuse comparison instruction Compare into a later branch. | 
|  | 491 | // Return true on success and if Compare is therefore redundant. | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 492 | bool SystemZElimCompare::fuseCompareOperations( | 
|  | 493 | MachineInstr &Compare, SmallVectorImpl<MachineInstr *> &CCUsers) { | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 494 | // See whether we have a single branch with which to fuse. | 
|  | 495 | if (CCUsers.size() != 1) | 
|  | 496 | return false; | 
|  | 497 | MachineInstr *Branch = CCUsers[0]; | 
| Zhan Jun Liau | ab42cbc | 2016-06-10 19:58:10 +0000 | [diff] [blame] | 498 | SystemZII::FusedCompareType Type; | 
| Ulrich Weigand | 2eb027d | 2016-04-07 16:11:44 +0000 | [diff] [blame] | 499 | switch (Branch->getOpcode()) { | 
|  | 500 | case SystemZ::BRC: | 
|  | 501 | Type = SystemZII::CompareAndBranch; | 
|  | 502 | break; | 
|  | 503 | case SystemZ::CondReturn: | 
|  | 504 | Type = SystemZII::CompareAndReturn; | 
|  | 505 | break; | 
| Ulrich Weigand | 848a513 | 2016-04-11 12:12:32 +0000 | [diff] [blame] | 506 | case SystemZ::CallBCR: | 
|  | 507 | Type = SystemZII::CompareAndSibcall; | 
|  | 508 | break; | 
| Zhan Jun Liau | ab42cbc | 2016-06-10 19:58:10 +0000 | [diff] [blame] | 509 | case SystemZ::CondTrap: | 
|  | 510 | Type = SystemZII::CompareAndTrap; | 
|  | 511 | break; | 
| Ulrich Weigand | 2eb027d | 2016-04-07 16:11:44 +0000 | [diff] [blame] | 512 | default: | 
|  | 513 | return false; | 
|  | 514 | } | 
|  | 515 |  | 
|  | 516 | // See whether we have a comparison that can be fused. | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 517 | unsigned FusedOpcode = | 
|  | 518 | TII->getFusedCompare(Compare.getOpcode(), Type, &Compare); | 
| Ulrich Weigand | 2eb027d | 2016-04-07 16:11:44 +0000 | [diff] [blame] | 519 | if (!FusedOpcode) | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 520 | return false; | 
|  | 521 |  | 
|  | 522 | // Make sure that the operands are available at the branch. | 
| Ulrich Weigand | a0e7325 | 2016-11-11 12:48:26 +0000 | [diff] [blame] | 523 | // SrcReg2 is the register if the source operand is a register, | 
|  | 524 | // 0 if the source operand is immediate, and the base register | 
|  | 525 | // if the source operand is memory (index is not supported). | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 526 | unsigned SrcReg = Compare.getOperand(0).getReg(); | 
|  | 527 | unsigned SrcReg2 = | 
|  | 528 | Compare.getOperand(1).isReg() ? Compare.getOperand(1).getReg() : 0; | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 529 | MachineBasicBlock::iterator MBBI = Compare, MBBE = Branch; | 
|  | 530 | for (++MBBI; MBBI != MBBE; ++MBBI) | 
|  | 531 | if (MBBI->modifiesRegister(SrcReg, TRI) || | 
|  | 532 | (SrcReg2 && MBBI->modifiesRegister(SrcReg2, TRI))) | 
|  | 533 | return false; | 
|  | 534 |  | 
| Ulrich Weigand | 848a513 | 2016-04-11 12:12:32 +0000 | [diff] [blame] | 535 | // Read the branch mask, target (if applicable), regmask (if applicable). | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 536 | MachineOperand CCMask(MBBI->getOperand(1)); | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 537 | assert((CCMask.getImm() & ~SystemZ::CCMASK_ICMP) == 0 && | 
|  | 538 | "Invalid condition-code mask for integer comparison"); | 
| Ulrich Weigand | 2eb027d | 2016-04-07 16:11:44 +0000 | [diff] [blame] | 539 | // This is only valid for CompareAndBranch. | 
|  | 540 | MachineOperand Target(MBBI->getOperand( | 
|  | 541 | Type == SystemZII::CompareAndBranch ? 2 : 0)); | 
| Ulrich Weigand | 848a513 | 2016-04-11 12:12:32 +0000 | [diff] [blame] | 542 | const uint32_t *RegMask; | 
|  | 543 | if (Type == SystemZII::CompareAndSibcall) | 
|  | 544 | RegMask = MBBI->getOperand(2).getRegMask(); | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 545 |  | 
|  | 546 | // Clear out all current operands. | 
|  | 547 | int CCUse = MBBI->findRegisterUseOperandIdx(SystemZ::CC, false, TRI); | 
| Ulrich Weigand | 2eb027d | 2016-04-07 16:11:44 +0000 | [diff] [blame] | 548 | assert(CCUse >= 0 && "BRC/BCR must use CC"); | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 549 | Branch->RemoveOperand(CCUse); | 
| Ulrich Weigand | 848a513 | 2016-04-11 12:12:32 +0000 | [diff] [blame] | 550 | // Remove target (branch) or regmask (sibcall). | 
|  | 551 | if (Type == SystemZII::CompareAndBranch || | 
|  | 552 | Type == SystemZII::CompareAndSibcall) | 
| Ulrich Weigand | 2eb027d | 2016-04-07 16:11:44 +0000 | [diff] [blame] | 553 | Branch->RemoveOperand(2); | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 554 | Branch->RemoveOperand(1); | 
|  | 555 | Branch->RemoveOperand(0); | 
|  | 556 |  | 
|  | 557 | // Rebuild Branch as a fused compare and branch. | 
| Ulrich Weigand | a0e7325 | 2016-11-11 12:48:26 +0000 | [diff] [blame] | 558 | // SrcNOps is the number of MI operands of the compare instruction | 
|  | 559 | // that we need to copy over. | 
|  | 560 | unsigned SrcNOps = 2; | 
|  | 561 | if (FusedOpcode == SystemZ::CLT || FusedOpcode == SystemZ::CLGT) | 
|  | 562 | SrcNOps = 3; | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 563 | Branch->setDesc(TII->get(FusedOpcode)); | 
| Ulrich Weigand | 2eb027d | 2016-04-07 16:11:44 +0000 | [diff] [blame] | 564 | MachineInstrBuilder MIB(*Branch->getParent()->getParent(), Branch); | 
| Ulrich Weigand | a0e7325 | 2016-11-11 12:48:26 +0000 | [diff] [blame] | 565 | for (unsigned I = 0; I < SrcNOps; I++) | 
| Diana Picus | 116bbab | 2017-01-13 09:58:52 +0000 | [diff] [blame] | 566 | MIB.add(Compare.getOperand(I)); | 
|  | 567 | MIB.add(CCMask); | 
| Ulrich Weigand | 2eb027d | 2016-04-07 16:11:44 +0000 | [diff] [blame] | 568 |  | 
|  | 569 | if (Type == SystemZII::CompareAndBranch) { | 
|  | 570 | // Only conditional branches define CC, as they may be converted back | 
|  | 571 | // to a non-fused branch because of a long displacement.  Conditional | 
|  | 572 | // returns don't have that problem. | 
| Diana Picus | 116bbab | 2017-01-13 09:58:52 +0000 | [diff] [blame] | 573 | MIB.add(Target).addReg(SystemZ::CC, | 
|  | 574 | RegState::ImplicitDefine | RegState::Dead); | 
| Ulrich Weigand | 2eb027d | 2016-04-07 16:11:44 +0000 | [diff] [blame] | 575 | } | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 576 |  | 
| Ulrich Weigand | 848a513 | 2016-04-11 12:12:32 +0000 | [diff] [blame] | 577 | if (Type == SystemZII::CompareAndSibcall) | 
|  | 578 | MIB.addRegMask(RegMask); | 
|  | 579 |  | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 580 | // Clear any intervening kills of SrcReg and SrcReg2. | 
|  | 581 | MBBI = Compare; | 
|  | 582 | for (++MBBI; MBBI != MBBE; ++MBBI) { | 
|  | 583 | MBBI->clearRegisterKills(SrcReg, TRI); | 
|  | 584 | if (SrcReg2) | 
|  | 585 | MBBI->clearRegisterKills(SrcReg2, TRI); | 
|  | 586 | } | 
|  | 587 | FusedComparisons += 1; | 
|  | 588 | return true; | 
|  | 589 | } | 
|  | 590 |  | 
|  | 591 | // Process all comparison instructions in MBB.  Return true if something | 
|  | 592 | // changed. | 
| Richard Sandiford | 28c111e | 2014-03-06 11:00:15 +0000 | [diff] [blame] | 593 | bool SystemZElimCompare::processBlock(MachineBasicBlock &MBB) { | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 594 | bool Changed = false; | 
|  | 595 |  | 
|  | 596 | // Walk backwards through the block looking for comparisons, recording | 
|  | 597 | // all CC users as we go.  The subroutines can delete Compare and | 
|  | 598 | // instructions before it. | 
|  | 599 | bool CompleteCCUsers = !isCCLiveOut(MBB); | 
|  | 600 | SmallVector<MachineInstr *, 4> CCUsers; | 
| Richard Sandiford | 28c111e | 2014-03-06 11:00:15 +0000 | [diff] [blame] | 601 | MachineBasicBlock::iterator MBBI = MBB.end(); | 
|  | 602 | while (MBBI != MBB.begin()) { | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 603 | MachineInstr &MI = *--MBBI; | 
|  | 604 | if (CompleteCCUsers && (MI.isCompare() || isLoadAndTestAsCmp(MI)) && | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 605 | (optimizeCompareZero(MI, CCUsers) || | 
| Zhan Jun Liau | ab42cbc | 2016-06-10 19:58:10 +0000 | [diff] [blame] | 606 | fuseCompareOperations(MI, CCUsers))) { | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 607 | ++MBBI; | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 608 | MI.eraseFromParent(); | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 609 | Changed = true; | 
|  | 610 | CCUsers.clear(); | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 611 | continue; | 
|  | 612 | } | 
|  | 613 |  | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 614 | if (MI.definesRegister(SystemZ::CC)) { | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 615 | CCUsers.clear(); | 
| Jonas Paulsson | 9e1f3bd | 2015-10-08 07:39:55 +0000 | [diff] [blame] | 616 | CompleteCCUsers = true; | 
| Richard Sandiford | c212125 | 2013-08-05 11:23:46 +0000 | [diff] [blame] | 617 | } | 
| Duncan P. N. Exon Smith | 4565ec0 | 2016-07-12 01:39:01 +0000 | [diff] [blame] | 618 | if (MI.readsRegister(SystemZ::CC) && CompleteCCUsers) | 
|  | 619 | CCUsers.push_back(&MI); | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 620 | } | 
|  | 621 | return Changed; | 
|  | 622 | } | 
|  | 623 |  | 
|  | 624 | bool SystemZElimCompare::runOnMachineFunction(MachineFunction &F) { | 
| Matthias Braun | f1caa28 | 2017-12-15 22:22:58 +0000 | [diff] [blame] | 625 | if (skipFunction(F.getFunction())) | 
| Andrew Kaylor | d9974cc | 2016-04-26 23:49:41 +0000 | [diff] [blame] | 626 | return false; | 
|  | 627 |  | 
| Eric Christopher | fc6de42 | 2014-08-05 02:39:49 +0000 | [diff] [blame] | 628 | TII = static_cast<const SystemZInstrInfo *>(F.getSubtarget().getInstrInfo()); | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 629 | TRI = &TII->getRegisterInfo(); | 
|  | 630 |  | 
|  | 631 | bool Changed = false; | 
| Richard Sandiford | 28c111e | 2014-03-06 11:00:15 +0000 | [diff] [blame] | 632 | for (auto &MBB : F) | 
|  | 633 | Changed |= processBlock(MBB); | 
| Richard Sandiford | bdbb8af | 2013-08-05 10:58:53 +0000 | [diff] [blame] | 634 |  | 
|  | 635 | return Changed; | 
|  | 636 | } | 
| Eugene Zelenko | 3943d2b | 2017-01-24 22:10:43 +0000 | [diff] [blame] | 637 |  | 
|  | 638 | FunctionPass *llvm::createSystemZElimComparePass(SystemZTargetMachine &TM) { | 
|  | 639 | return new SystemZElimCompare(TM); | 
|  | 640 | } |