1 //===-------------- RISCVSExtWRemoval.cpp - MI sext.w Removal -------------===// 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 removes unneeded sext.w instructions at the MI level. 10 // 11 //===---------------------------------------------------------------------===// 12 13 #include "RISCV.h" 14 #include "RISCVSubtarget.h" 15 #include "llvm/ADT/Statistic.h" 16 #include "llvm/CodeGen/MachineFunctionPass.h" 17 #include "llvm/CodeGen/TargetInstrInfo.h" 18 19 using namespace llvm; 20 21 #define DEBUG_TYPE "riscv-sextw-removal" 22 23 STATISTIC(NumRemovedSExtW, "Number of removed sign-extensions"); 24 25 static cl::opt<bool> DisableSExtWRemoval("riscv-disable-sextw-removal", 26 cl::desc("Disable removal of sext.w"), 27 cl::init(false), cl::Hidden); 28 namespace { 29 30 class RISCVSExtWRemoval : public MachineFunctionPass { 31 public: 32 static char ID; 33 34 RISCVSExtWRemoval() : MachineFunctionPass(ID) { 35 initializeRISCVSExtWRemovalPass(*PassRegistry::getPassRegistry()); 36 } 37 38 bool runOnMachineFunction(MachineFunction &MF) override; 39 40 void getAnalysisUsage(AnalysisUsage &AU) const override { 41 AU.setPreservesCFG(); 42 MachineFunctionPass::getAnalysisUsage(AU); 43 } 44 45 StringRef getPassName() const override { return "RISCV sext.w Removal"; } 46 }; 47 48 } // end anonymous namespace 49 50 char RISCVSExtWRemoval::ID = 0; 51 INITIALIZE_PASS(RISCVSExtWRemoval, DEBUG_TYPE, "RISCV sext.w Removal", false, 52 false) 53 54 FunctionPass *llvm::createRISCVSExtWRemovalPass() { 55 return new RISCVSExtWRemoval(); 56 } 57 58 // This function returns true if the machine instruction always outputs a value 59 // where bits 63:32 match bit 31. 60 // TODO: Allocate a bit in TSFlags for the W instructions? 61 // TODO: Add other W instructions. 62 static bool isSignExtendingOpW(const MachineInstr &MI) { 63 switch (MI.getOpcode()) { 64 case RISCV::LUI: 65 case RISCV::LW: 66 case RISCV::ADDW: 67 case RISCV::ADDIW: 68 case RISCV::SUBW: 69 case RISCV::MULW: 70 case RISCV::SLLW: 71 case RISCV::SLLIW: 72 case RISCV::SRAW: 73 case RISCV::SRAIW: 74 case RISCV::SRLW: 75 case RISCV::SRLIW: 76 case RISCV::DIVW: 77 case RISCV::DIVUW: 78 case RISCV::REMW: 79 case RISCV::REMUW: 80 case RISCV::ROLW: 81 case RISCV::RORW: 82 case RISCV::RORIW: 83 case RISCV::CLZW: 84 case RISCV::CTZW: 85 case RISCV::CPOPW: 86 case RISCV::FCVT_W_H: 87 case RISCV::FCVT_WU_H: 88 case RISCV::FCVT_W_S: 89 case RISCV::FCVT_WU_S: 90 case RISCV::FCVT_W_D: 91 case RISCV::FCVT_WU_D: 92 // The following aren't W instructions, but are either sign extended from a 93 // smaller size or put zeros in bits 63:31. 94 case RISCV::LBU: 95 case RISCV::LHU: 96 case RISCV::LB: 97 case RISCV::LH: 98 case RISCV::SLT: 99 case RISCV::SLTI: 100 case RISCV::SLTU: 101 case RISCV::SLTIU: 102 case RISCV::SEXTB: 103 case RISCV::SEXTH: 104 case RISCV::ZEXTH_RV64: 105 return true; 106 // shifting right sufficiently makes the value 32-bit sign-extended 107 case RISCV::SRAI: 108 return MI.getOperand(2).getImm() >= 32; 109 case RISCV::SRLI: 110 return MI.getOperand(2).getImm() > 32; 111 // The LI pattern ADDI rd, X0, imm is sign extended. 112 case RISCV::ADDI: 113 return MI.getOperand(1).isReg() && MI.getOperand(1).getReg() == RISCV::X0; 114 // An ANDI with an 11 bit immediate will zero bits 63:11. 115 case RISCV::ANDI: 116 return isUInt<11>(MI.getOperand(2).getImm()); 117 // An ORI with an >11 bit immediate (negative 12-bit) will set bits 63:11. 118 case RISCV::ORI: 119 return !isUInt<11>(MI.getOperand(2).getImm()); 120 // Copying from X0 produces zero. 121 case RISCV::COPY: 122 return MI.getOperand(1).getReg() == RISCV::X0; 123 } 124 125 return false; 126 } 127 128 static bool isSignExtendedW(const MachineInstr &OrigMI, 129 MachineRegisterInfo &MRI) { 130 131 SmallPtrSet<const MachineInstr *, 4> Visited; 132 SmallVector<const MachineInstr *, 4> Worklist; 133 134 Worklist.push_back(&OrigMI); 135 136 while (!Worklist.empty()) { 137 const MachineInstr *MI = Worklist.pop_back_val(); 138 139 // If we already visited this instruction, we don't need to check it again. 140 if (!Visited.insert(MI).second) 141 continue; 142 143 // If this is a sign extending operation we don't need to look any further. 144 if (isSignExtendingOpW(*MI)) 145 continue; 146 147 // Is this an instruction that propagates sign extend. 148 switch (MI->getOpcode()) { 149 default: 150 // Unknown opcode, give up. 151 return false; 152 case RISCV::COPY: { 153 Register SrcReg = MI->getOperand(1).getReg(); 154 155 // TODO: Handle arguments and returns from calls? 156 157 // If this is a copy from another register, check its source instruction. 158 if (!SrcReg.isVirtual()) 159 return false; 160 const MachineInstr *SrcMI = MRI.getVRegDef(SrcReg); 161 if (!SrcMI) 162 return false; 163 164 // Add SrcMI to the worklist. 165 Worklist.push_back(SrcMI); 166 break; 167 } 168 case RISCV::REM: 169 case RISCV::ANDI: 170 case RISCV::ORI: 171 case RISCV::XORI: { 172 // |Remainder| is always <= |Dividend|. If D is 32-bit, then so is R. 173 // DIV doesn't work because of the edge case 0xf..f 8000 0000 / (long)-1 174 // Logical operations use a sign extended 12-bit immediate. We just need 175 // to check if the other operand is sign extended. 176 Register SrcReg = MI->getOperand(1).getReg(); 177 if (!SrcReg.isVirtual()) 178 return false; 179 const MachineInstr *SrcMI = MRI.getVRegDef(SrcReg); 180 if (!SrcMI) 181 return false; 182 183 // Add SrcMI to the worklist. 184 Worklist.push_back(SrcMI); 185 break; 186 } 187 case RISCV::REMU: 188 case RISCV::AND: 189 case RISCV::OR: 190 case RISCV::XOR: 191 case RISCV::ANDN: 192 case RISCV::ORN: 193 case RISCV::XNOR: 194 case RISCV::MAX: 195 case RISCV::MAXU: 196 case RISCV::MIN: 197 case RISCV::MINU: 198 case RISCV::PHI: { 199 // If all incoming values are sign-extended, the output of AND, OR, XOR, 200 // MIN, MAX, or PHI is also sign-extended. 201 202 // The input registers for PHI are operand 1, 3, ... 203 // The input registers for others are operand 1 and 2. 204 unsigned E = 3, D = 1; 205 if (MI->getOpcode() == RISCV::PHI) { 206 E = MI->getNumOperands(); 207 D = 2; 208 } 209 210 for (unsigned I = 1; I != E; I += D) { 211 if (!MI->getOperand(I).isReg()) 212 return false; 213 214 Register SrcReg = MI->getOperand(I).getReg(); 215 if (!SrcReg.isVirtual()) 216 return false; 217 const MachineInstr *SrcMI = MRI.getVRegDef(SrcReg); 218 if (!SrcMI) 219 return false; 220 221 // Add SrcMI to the worklist. 222 Worklist.push_back(SrcMI); 223 } 224 225 break; 226 } 227 } 228 } 229 230 // If we get here, then every node we visited produces a sign extended value 231 // or propagated sign extended values. So the result must be sign extended. 232 return true; 233 } 234 235 bool RISCVSExtWRemoval::runOnMachineFunction(MachineFunction &MF) { 236 if (skipFunction(MF.getFunction()) || DisableSExtWRemoval) 237 return false; 238 239 MachineRegisterInfo &MRI = MF.getRegInfo(); 240 const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>(); 241 242 if (!ST.is64Bit()) 243 return false; 244 245 bool MadeChange = false; 246 for (MachineBasicBlock &MBB : MF) { 247 for (auto I = MBB.begin(), IE = MBB.end(); I != IE;) { 248 MachineInstr *MI = &*I++; 249 250 // We're looking for the sext.w pattern ADDIW rd, rs1, 0. 251 if (MI->getOpcode() != RISCV::ADDIW || !MI->getOperand(2).isImm() || 252 MI->getOperand(2).getImm() != 0 || !MI->getOperand(1).isReg()) 253 continue; 254 255 // Input should be a virtual register. 256 Register SrcReg = MI->getOperand(1).getReg(); 257 if (!SrcReg.isVirtual()) 258 continue; 259 260 const MachineInstr &SrcMI = *MRI.getVRegDef(SrcReg); 261 if (!isSignExtendedW(SrcMI, MRI)) 262 continue; 263 264 Register DstReg = MI->getOperand(0).getReg(); 265 if (!MRI.constrainRegClass(SrcReg, MRI.getRegClass(DstReg))) 266 continue; 267 268 LLVM_DEBUG(dbgs() << "Removing redundant sign-extension\n"); 269 MRI.replaceRegWith(DstReg, SrcReg); 270 MRI.clearKillFlags(SrcReg); 271 MI->eraseFromParent(); 272 ++NumRemovedSExtW; 273 MadeChange = true; 274 } 275 } 276 277 return MadeChange; 278 } 279