106c3fb27SDimitry Andric //===- RISCVOptWInstrs.cpp - MI W instruction optimizations ---------------===// 206c3fb27SDimitry Andric // 306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 606c3fb27SDimitry Andric // 706c3fb27SDimitry Andric //===---------------------------------------------------------------------===// 806c3fb27SDimitry Andric // 906c3fb27SDimitry Andric // This pass does some optimizations for *W instructions at the MI level. 1006c3fb27SDimitry Andric // 1106c3fb27SDimitry Andric // First it removes unneeded sext.w instructions. Either because the sign 1206c3fb27SDimitry Andric // extended bits aren't consumed or because the input was already sign extended 1306c3fb27SDimitry Andric // by an earlier instruction. 1406c3fb27SDimitry Andric // 15*0fca6ea1SDimitry Andric // Then: 16*0fca6ea1SDimitry Andric // 1. Unless explicit disabled or the target prefers instructions with W suffix, 17*0fca6ea1SDimitry Andric // it removes the -w suffix from opw instructions whenever all users are 185f757f3fSDimitry Andric // dependent only on the lower word of the result of the instruction. 195f757f3fSDimitry Andric // The cases handled are: 205f757f3fSDimitry Andric // * addw because c.add has a larger register encoding than c.addw. 215f757f3fSDimitry Andric // * addiw because it helps reduce test differences between RV32 and RV64 225f757f3fSDimitry Andric // w/o being a pessimization. 235f757f3fSDimitry Andric // * mulw because c.mulw doesn't exist but c.mul does (w/ zcb) 245f757f3fSDimitry Andric // * slliw because c.slliw doesn't exist and c.slli does 2506c3fb27SDimitry Andric // 26*0fca6ea1SDimitry Andric // 2. Or if explicit enabled or the target prefers instructions with W suffix, 27*0fca6ea1SDimitry Andric // it adds the W suffix to the instruction whenever all users are dependent 28*0fca6ea1SDimitry Andric // only on the lower word of the result of the instruction. 29*0fca6ea1SDimitry Andric // The cases handled are: 30*0fca6ea1SDimitry Andric // * add/addi/sub/mul. 31*0fca6ea1SDimitry Andric // * slli with imm < 32. 32*0fca6ea1SDimitry Andric // * ld/lwu. 3306c3fb27SDimitry Andric //===---------------------------------------------------------------------===// 3406c3fb27SDimitry Andric 3506c3fb27SDimitry Andric #include "RISCV.h" 3606c3fb27SDimitry Andric #include "RISCVMachineFunctionInfo.h" 3706c3fb27SDimitry Andric #include "RISCVSubtarget.h" 385f757f3fSDimitry Andric #include "llvm/ADT/SmallSet.h" 3906c3fb27SDimitry Andric #include "llvm/ADT/Statistic.h" 4006c3fb27SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 4106c3fb27SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h" 4206c3fb27SDimitry Andric 4306c3fb27SDimitry Andric using namespace llvm; 4406c3fb27SDimitry Andric 4506c3fb27SDimitry Andric #define DEBUG_TYPE "riscv-opt-w-instrs" 4606c3fb27SDimitry Andric #define RISCV_OPT_W_INSTRS_NAME "RISC-V Optimize W Instructions" 4706c3fb27SDimitry Andric 4806c3fb27SDimitry Andric STATISTIC(NumRemovedSExtW, "Number of removed sign-extensions"); 4906c3fb27SDimitry Andric STATISTIC(NumTransformedToWInstrs, 5006c3fb27SDimitry Andric "Number of instructions transformed to W-ops"); 5106c3fb27SDimitry Andric 5206c3fb27SDimitry Andric static cl::opt<bool> DisableSExtWRemoval("riscv-disable-sextw-removal", 5306c3fb27SDimitry Andric cl::desc("Disable removal of sext.w"), 5406c3fb27SDimitry Andric cl::init(false), cl::Hidden); 5506c3fb27SDimitry Andric static cl::opt<bool> DisableStripWSuffix("riscv-disable-strip-w-suffix", 5606c3fb27SDimitry Andric cl::desc("Disable strip W suffix"), 5706c3fb27SDimitry Andric cl::init(false), cl::Hidden); 5806c3fb27SDimitry Andric 5906c3fb27SDimitry Andric namespace { 6006c3fb27SDimitry Andric 6106c3fb27SDimitry Andric class RISCVOptWInstrs : public MachineFunctionPass { 6206c3fb27SDimitry Andric public: 6306c3fb27SDimitry Andric static char ID; 6406c3fb27SDimitry Andric 655f757f3fSDimitry Andric RISCVOptWInstrs() : MachineFunctionPass(ID) {} 6606c3fb27SDimitry Andric 6706c3fb27SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 6806c3fb27SDimitry Andric bool removeSExtWInstrs(MachineFunction &MF, const RISCVInstrInfo &TII, 6906c3fb27SDimitry Andric const RISCVSubtarget &ST, MachineRegisterInfo &MRI); 7006c3fb27SDimitry Andric bool stripWSuffixes(MachineFunction &MF, const RISCVInstrInfo &TII, 7106c3fb27SDimitry Andric const RISCVSubtarget &ST, MachineRegisterInfo &MRI); 72*0fca6ea1SDimitry Andric bool appendWSuffixes(MachineFunction &MF, const RISCVInstrInfo &TII, 73*0fca6ea1SDimitry Andric const RISCVSubtarget &ST, MachineRegisterInfo &MRI); 7406c3fb27SDimitry Andric 7506c3fb27SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 7606c3fb27SDimitry Andric AU.setPreservesCFG(); 7706c3fb27SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 7806c3fb27SDimitry Andric } 7906c3fb27SDimitry Andric 8006c3fb27SDimitry Andric StringRef getPassName() const override { return RISCV_OPT_W_INSTRS_NAME; } 8106c3fb27SDimitry Andric }; 8206c3fb27SDimitry Andric 8306c3fb27SDimitry Andric } // end anonymous namespace 8406c3fb27SDimitry Andric 8506c3fb27SDimitry Andric char RISCVOptWInstrs::ID = 0; 8606c3fb27SDimitry Andric INITIALIZE_PASS(RISCVOptWInstrs, DEBUG_TYPE, RISCV_OPT_W_INSTRS_NAME, false, 8706c3fb27SDimitry Andric false) 8806c3fb27SDimitry Andric 8906c3fb27SDimitry Andric FunctionPass *llvm::createRISCVOptWInstrsPass() { 9006c3fb27SDimitry Andric return new RISCVOptWInstrs(); 9106c3fb27SDimitry Andric } 9206c3fb27SDimitry Andric 935f757f3fSDimitry Andric static bool vectorPseudoHasAllNBitUsers(const MachineOperand &UserOp, 945f757f3fSDimitry Andric unsigned Bits) { 955f757f3fSDimitry Andric const MachineInstr &MI = *UserOp.getParent(); 965f757f3fSDimitry Andric unsigned MCOpcode = RISCV::getRVVMCOpcode(MI.getOpcode()); 975f757f3fSDimitry Andric 985f757f3fSDimitry Andric if (!MCOpcode) 995f757f3fSDimitry Andric return false; 1005f757f3fSDimitry Andric 1015f757f3fSDimitry Andric const MCInstrDesc &MCID = MI.getDesc(); 1025f757f3fSDimitry Andric const uint64_t TSFlags = MCID.TSFlags; 1035f757f3fSDimitry Andric if (!RISCVII::hasSEWOp(TSFlags)) 1045f757f3fSDimitry Andric return false; 1055f757f3fSDimitry Andric assert(RISCVII::hasVLOp(TSFlags)); 1065f757f3fSDimitry Andric const unsigned Log2SEW = MI.getOperand(RISCVII::getSEWOpNum(MCID)).getImm(); 1075f757f3fSDimitry Andric 1085f757f3fSDimitry Andric if (UserOp.getOperandNo() == RISCVII::getVLOpNum(MCID)) 1095f757f3fSDimitry Andric return false; 1105f757f3fSDimitry Andric 1115f757f3fSDimitry Andric auto NumDemandedBits = 1125f757f3fSDimitry Andric RISCV::getVectorLowDemandedScalarBits(MCOpcode, Log2SEW); 1135f757f3fSDimitry Andric return NumDemandedBits && Bits >= *NumDemandedBits; 1145f757f3fSDimitry Andric } 1155f757f3fSDimitry Andric 11606c3fb27SDimitry Andric // Checks if all users only demand the lower \p OrigBits of the original 11706c3fb27SDimitry Andric // instruction's result. 11806c3fb27SDimitry Andric // TODO: handle multiple interdependent transformations 11906c3fb27SDimitry Andric static bool hasAllNBitUsers(const MachineInstr &OrigMI, 12006c3fb27SDimitry Andric const RISCVSubtarget &ST, 12106c3fb27SDimitry Andric const MachineRegisterInfo &MRI, unsigned OrigBits) { 12206c3fb27SDimitry Andric 12306c3fb27SDimitry Andric SmallSet<std::pair<const MachineInstr *, unsigned>, 4> Visited; 12406c3fb27SDimitry Andric SmallVector<std::pair<const MachineInstr *, unsigned>, 4> Worklist; 12506c3fb27SDimitry Andric 12606c3fb27SDimitry Andric Worklist.push_back(std::make_pair(&OrigMI, OrigBits)); 12706c3fb27SDimitry Andric 12806c3fb27SDimitry Andric while (!Worklist.empty()) { 12906c3fb27SDimitry Andric auto P = Worklist.pop_back_val(); 13006c3fb27SDimitry Andric const MachineInstr *MI = P.first; 13106c3fb27SDimitry Andric unsigned Bits = P.second; 13206c3fb27SDimitry Andric 13306c3fb27SDimitry Andric if (!Visited.insert(P).second) 13406c3fb27SDimitry Andric continue; 13506c3fb27SDimitry Andric 13606c3fb27SDimitry Andric // Only handle instructions with one def. 13706c3fb27SDimitry Andric if (MI->getNumExplicitDefs() != 1) 13806c3fb27SDimitry Andric return false; 13906c3fb27SDimitry Andric 1401db9f3b2SDimitry Andric Register DestReg = MI->getOperand(0).getReg(); 1411db9f3b2SDimitry Andric if (!DestReg.isVirtual()) 1421db9f3b2SDimitry Andric return false; 1431db9f3b2SDimitry Andric 1441db9f3b2SDimitry Andric for (auto &UserOp : MRI.use_nodbg_operands(DestReg)) { 14506c3fb27SDimitry Andric const MachineInstr *UserMI = UserOp.getParent(); 14606c3fb27SDimitry Andric unsigned OpIdx = UserOp.getOperandNo(); 14706c3fb27SDimitry Andric 14806c3fb27SDimitry Andric switch (UserMI->getOpcode()) { 14906c3fb27SDimitry Andric default: 1505f757f3fSDimitry Andric if (vectorPseudoHasAllNBitUsers(UserOp, Bits)) 1515f757f3fSDimitry Andric break; 15206c3fb27SDimitry Andric return false; 15306c3fb27SDimitry Andric 15406c3fb27SDimitry Andric case RISCV::ADDIW: 15506c3fb27SDimitry Andric case RISCV::ADDW: 15606c3fb27SDimitry Andric case RISCV::DIVUW: 15706c3fb27SDimitry Andric case RISCV::DIVW: 15806c3fb27SDimitry Andric case RISCV::MULW: 15906c3fb27SDimitry Andric case RISCV::REMUW: 16006c3fb27SDimitry Andric case RISCV::REMW: 16106c3fb27SDimitry Andric case RISCV::SLLIW: 16206c3fb27SDimitry Andric case RISCV::SLLW: 16306c3fb27SDimitry Andric case RISCV::SRAIW: 16406c3fb27SDimitry Andric case RISCV::SRAW: 16506c3fb27SDimitry Andric case RISCV::SRLIW: 16606c3fb27SDimitry Andric case RISCV::SRLW: 16706c3fb27SDimitry Andric case RISCV::SUBW: 16806c3fb27SDimitry Andric case RISCV::ROLW: 16906c3fb27SDimitry Andric case RISCV::RORW: 17006c3fb27SDimitry Andric case RISCV::RORIW: 17106c3fb27SDimitry Andric case RISCV::CLZW: 17206c3fb27SDimitry Andric case RISCV::CTZW: 17306c3fb27SDimitry Andric case RISCV::CPOPW: 17406c3fb27SDimitry Andric case RISCV::SLLI_UW: 17506c3fb27SDimitry Andric case RISCV::FMV_W_X: 17606c3fb27SDimitry Andric case RISCV::FCVT_H_W: 17706c3fb27SDimitry Andric case RISCV::FCVT_H_WU: 17806c3fb27SDimitry Andric case RISCV::FCVT_S_W: 17906c3fb27SDimitry Andric case RISCV::FCVT_S_WU: 18006c3fb27SDimitry Andric case RISCV::FCVT_D_W: 18106c3fb27SDimitry Andric case RISCV::FCVT_D_WU: 18206c3fb27SDimitry Andric if (Bits >= 32) 18306c3fb27SDimitry Andric break; 18406c3fb27SDimitry Andric return false; 18506c3fb27SDimitry Andric case RISCV::SEXT_B: 18606c3fb27SDimitry Andric case RISCV::PACKH: 18706c3fb27SDimitry Andric if (Bits >= 8) 18806c3fb27SDimitry Andric break; 18906c3fb27SDimitry Andric return false; 19006c3fb27SDimitry Andric case RISCV::SEXT_H: 19106c3fb27SDimitry Andric case RISCV::FMV_H_X: 19206c3fb27SDimitry Andric case RISCV::ZEXT_H_RV32: 19306c3fb27SDimitry Andric case RISCV::ZEXT_H_RV64: 19406c3fb27SDimitry Andric case RISCV::PACKW: 19506c3fb27SDimitry Andric if (Bits >= 16) 19606c3fb27SDimitry Andric break; 19706c3fb27SDimitry Andric return false; 19806c3fb27SDimitry Andric 19906c3fb27SDimitry Andric case RISCV::PACK: 20006c3fb27SDimitry Andric if (Bits >= (ST.getXLen() / 2)) 20106c3fb27SDimitry Andric break; 20206c3fb27SDimitry Andric return false; 20306c3fb27SDimitry Andric 20406c3fb27SDimitry Andric case RISCV::SRLI: { 20506c3fb27SDimitry Andric // If we are shifting right by less than Bits, and users don't demand 20606c3fb27SDimitry Andric // any bits that were shifted into [Bits-1:0], then we can consider this 20706c3fb27SDimitry Andric // as an N-Bit user. 20806c3fb27SDimitry Andric unsigned ShAmt = UserMI->getOperand(2).getImm(); 20906c3fb27SDimitry Andric if (Bits > ShAmt) { 21006c3fb27SDimitry Andric Worklist.push_back(std::make_pair(UserMI, Bits - ShAmt)); 21106c3fb27SDimitry Andric break; 21206c3fb27SDimitry Andric } 21306c3fb27SDimitry Andric return false; 21406c3fb27SDimitry Andric } 21506c3fb27SDimitry Andric 21606c3fb27SDimitry Andric // these overwrite higher input bits, otherwise the lower word of output 21706c3fb27SDimitry Andric // depends only on the lower word of input. So check their uses read W. 21806c3fb27SDimitry Andric case RISCV::SLLI: 21906c3fb27SDimitry Andric if (Bits >= (ST.getXLen() - UserMI->getOperand(2).getImm())) 22006c3fb27SDimitry Andric break; 22106c3fb27SDimitry Andric Worklist.push_back(std::make_pair(UserMI, Bits)); 22206c3fb27SDimitry Andric break; 22306c3fb27SDimitry Andric case RISCV::ANDI: { 22406c3fb27SDimitry Andric uint64_t Imm = UserMI->getOperand(2).getImm(); 22506c3fb27SDimitry Andric if (Bits >= (unsigned)llvm::bit_width(Imm)) 22606c3fb27SDimitry Andric break; 22706c3fb27SDimitry Andric Worklist.push_back(std::make_pair(UserMI, Bits)); 22806c3fb27SDimitry Andric break; 22906c3fb27SDimitry Andric } 23006c3fb27SDimitry Andric case RISCV::ORI: { 23106c3fb27SDimitry Andric uint64_t Imm = UserMI->getOperand(2).getImm(); 23206c3fb27SDimitry Andric if (Bits >= (unsigned)llvm::bit_width<uint64_t>(~Imm)) 23306c3fb27SDimitry Andric break; 23406c3fb27SDimitry Andric Worklist.push_back(std::make_pair(UserMI, Bits)); 23506c3fb27SDimitry Andric break; 23606c3fb27SDimitry Andric } 23706c3fb27SDimitry Andric 23806c3fb27SDimitry Andric case RISCV::SLL: 23906c3fb27SDimitry Andric case RISCV::BSET: 24006c3fb27SDimitry Andric case RISCV::BCLR: 24106c3fb27SDimitry Andric case RISCV::BINV: 24206c3fb27SDimitry Andric // Operand 2 is the shift amount which uses log2(xlen) bits. 24306c3fb27SDimitry Andric if (OpIdx == 2) { 24406c3fb27SDimitry Andric if (Bits >= Log2_32(ST.getXLen())) 24506c3fb27SDimitry Andric break; 24606c3fb27SDimitry Andric return false; 24706c3fb27SDimitry Andric } 24806c3fb27SDimitry Andric Worklist.push_back(std::make_pair(UserMI, Bits)); 24906c3fb27SDimitry Andric break; 25006c3fb27SDimitry Andric 25106c3fb27SDimitry Andric case RISCV::SRA: 25206c3fb27SDimitry Andric case RISCV::SRL: 25306c3fb27SDimitry Andric case RISCV::ROL: 25406c3fb27SDimitry Andric case RISCV::ROR: 25506c3fb27SDimitry Andric // Operand 2 is the shift amount which uses 6 bits. 25606c3fb27SDimitry Andric if (OpIdx == 2 && Bits >= Log2_32(ST.getXLen())) 25706c3fb27SDimitry Andric break; 25806c3fb27SDimitry Andric return false; 25906c3fb27SDimitry Andric 26006c3fb27SDimitry Andric case RISCV::ADD_UW: 26106c3fb27SDimitry Andric case RISCV::SH1ADD_UW: 26206c3fb27SDimitry Andric case RISCV::SH2ADD_UW: 26306c3fb27SDimitry Andric case RISCV::SH3ADD_UW: 26406c3fb27SDimitry Andric // Operand 1 is implicitly zero extended. 26506c3fb27SDimitry Andric if (OpIdx == 1 && Bits >= 32) 26606c3fb27SDimitry Andric break; 26706c3fb27SDimitry Andric Worklist.push_back(std::make_pair(UserMI, Bits)); 26806c3fb27SDimitry Andric break; 26906c3fb27SDimitry Andric 27006c3fb27SDimitry Andric case RISCV::BEXTI: 27106c3fb27SDimitry Andric if (UserMI->getOperand(2).getImm() >= Bits) 27206c3fb27SDimitry Andric return false; 27306c3fb27SDimitry Andric break; 27406c3fb27SDimitry Andric 27506c3fb27SDimitry Andric case RISCV::SB: 27606c3fb27SDimitry Andric // The first argument is the value to store. 27706c3fb27SDimitry Andric if (OpIdx == 0 && Bits >= 8) 27806c3fb27SDimitry Andric break; 27906c3fb27SDimitry Andric return false; 28006c3fb27SDimitry Andric case RISCV::SH: 28106c3fb27SDimitry Andric // The first argument is the value to store. 28206c3fb27SDimitry Andric if (OpIdx == 0 && Bits >= 16) 28306c3fb27SDimitry Andric break; 28406c3fb27SDimitry Andric return false; 28506c3fb27SDimitry Andric case RISCV::SW: 28606c3fb27SDimitry Andric // The first argument is the value to store. 28706c3fb27SDimitry Andric if (OpIdx == 0 && Bits >= 32) 28806c3fb27SDimitry Andric break; 28906c3fb27SDimitry Andric return false; 29006c3fb27SDimitry Andric 29106c3fb27SDimitry Andric // For these, lower word of output in these operations, depends only on 29206c3fb27SDimitry Andric // the lower word of input. So, we check all uses only read lower word. 29306c3fb27SDimitry Andric case RISCV::COPY: 29406c3fb27SDimitry Andric case RISCV::PHI: 29506c3fb27SDimitry Andric 29606c3fb27SDimitry Andric case RISCV::ADD: 29706c3fb27SDimitry Andric case RISCV::ADDI: 29806c3fb27SDimitry Andric case RISCV::AND: 29906c3fb27SDimitry Andric case RISCV::MUL: 30006c3fb27SDimitry Andric case RISCV::OR: 30106c3fb27SDimitry Andric case RISCV::SUB: 30206c3fb27SDimitry Andric case RISCV::XOR: 30306c3fb27SDimitry Andric case RISCV::XORI: 30406c3fb27SDimitry Andric 30506c3fb27SDimitry Andric case RISCV::ANDN: 30606c3fb27SDimitry Andric case RISCV::BREV8: 30706c3fb27SDimitry Andric case RISCV::CLMUL: 30806c3fb27SDimitry Andric case RISCV::ORC_B: 30906c3fb27SDimitry Andric case RISCV::ORN: 31006c3fb27SDimitry Andric case RISCV::SH1ADD: 31106c3fb27SDimitry Andric case RISCV::SH2ADD: 31206c3fb27SDimitry Andric case RISCV::SH3ADD: 31306c3fb27SDimitry Andric case RISCV::XNOR: 31406c3fb27SDimitry Andric case RISCV::BSETI: 31506c3fb27SDimitry Andric case RISCV::BCLRI: 31606c3fb27SDimitry Andric case RISCV::BINVI: 31706c3fb27SDimitry Andric Worklist.push_back(std::make_pair(UserMI, Bits)); 31806c3fb27SDimitry Andric break; 31906c3fb27SDimitry Andric 32006c3fb27SDimitry Andric case RISCV::PseudoCCMOVGPR: 32106c3fb27SDimitry Andric // Either operand 4 or operand 5 is returned by this instruction. If 32206c3fb27SDimitry Andric // only the lower word of the result is used, then only the lower word 32306c3fb27SDimitry Andric // of operand 4 and 5 is used. 32406c3fb27SDimitry Andric if (OpIdx != 4 && OpIdx != 5) 32506c3fb27SDimitry Andric return false; 32606c3fb27SDimitry Andric Worklist.push_back(std::make_pair(UserMI, Bits)); 32706c3fb27SDimitry Andric break; 32806c3fb27SDimitry Andric 3295f757f3fSDimitry Andric case RISCV::CZERO_EQZ: 3305f757f3fSDimitry Andric case RISCV::CZERO_NEZ: 33106c3fb27SDimitry Andric case RISCV::VT_MASKC: 33206c3fb27SDimitry Andric case RISCV::VT_MASKCN: 33306c3fb27SDimitry Andric if (OpIdx != 1) 33406c3fb27SDimitry Andric return false; 33506c3fb27SDimitry Andric Worklist.push_back(std::make_pair(UserMI, Bits)); 33606c3fb27SDimitry Andric break; 33706c3fb27SDimitry Andric } 33806c3fb27SDimitry Andric } 33906c3fb27SDimitry Andric } 34006c3fb27SDimitry Andric 34106c3fb27SDimitry Andric return true; 34206c3fb27SDimitry Andric } 34306c3fb27SDimitry Andric 34406c3fb27SDimitry Andric static bool hasAllWUsers(const MachineInstr &OrigMI, const RISCVSubtarget &ST, 34506c3fb27SDimitry Andric const MachineRegisterInfo &MRI) { 34606c3fb27SDimitry Andric return hasAllNBitUsers(OrigMI, ST, MRI, 32); 34706c3fb27SDimitry Andric } 34806c3fb27SDimitry Andric 34906c3fb27SDimitry Andric // This function returns true if the machine instruction always outputs a value 35006c3fb27SDimitry Andric // where bits 63:32 match bit 31. 35106c3fb27SDimitry Andric static bool isSignExtendingOpW(const MachineInstr &MI, 352*0fca6ea1SDimitry Andric const MachineRegisterInfo &MRI, unsigned OpNo) { 35306c3fb27SDimitry Andric uint64_t TSFlags = MI.getDesc().TSFlags; 35406c3fb27SDimitry Andric 35506c3fb27SDimitry Andric // Instructions that can be determined from opcode are marked in tablegen. 35606c3fb27SDimitry Andric if (TSFlags & RISCVII::IsSignExtendingOpWMask) 35706c3fb27SDimitry Andric return true; 35806c3fb27SDimitry Andric 35906c3fb27SDimitry Andric // Special cases that require checking operands. 36006c3fb27SDimitry Andric switch (MI.getOpcode()) { 36106c3fb27SDimitry Andric // shifting right sufficiently makes the value 32-bit sign-extended 36206c3fb27SDimitry Andric case RISCV::SRAI: 36306c3fb27SDimitry Andric return MI.getOperand(2).getImm() >= 32; 36406c3fb27SDimitry Andric case RISCV::SRLI: 36506c3fb27SDimitry Andric return MI.getOperand(2).getImm() > 32; 36606c3fb27SDimitry Andric // The LI pattern ADDI rd, X0, imm is sign extended. 36706c3fb27SDimitry Andric case RISCV::ADDI: 36806c3fb27SDimitry Andric return MI.getOperand(1).isReg() && MI.getOperand(1).getReg() == RISCV::X0; 36906c3fb27SDimitry Andric // An ANDI with an 11 bit immediate will zero bits 63:11. 37006c3fb27SDimitry Andric case RISCV::ANDI: 37106c3fb27SDimitry Andric return isUInt<11>(MI.getOperand(2).getImm()); 37206c3fb27SDimitry Andric // An ORI with an >11 bit immediate (negative 12-bit) will set bits 63:11. 37306c3fb27SDimitry Andric case RISCV::ORI: 37406c3fb27SDimitry Andric return !isUInt<11>(MI.getOperand(2).getImm()); 3755f757f3fSDimitry Andric // A bseti with X0 is sign extended if the immediate is less than 31. 3765f757f3fSDimitry Andric case RISCV::BSETI: 3775f757f3fSDimitry Andric return MI.getOperand(2).getImm() < 31 && 3785f757f3fSDimitry Andric MI.getOperand(1).getReg() == RISCV::X0; 37906c3fb27SDimitry Andric // Copying from X0 produces zero. 38006c3fb27SDimitry Andric case RISCV::COPY: 38106c3fb27SDimitry Andric return MI.getOperand(1).getReg() == RISCV::X0; 382*0fca6ea1SDimitry Andric // Ignore the scratch register destination. 3835f757f3fSDimitry Andric case RISCV::PseudoAtomicLoadNand32: 384*0fca6ea1SDimitry Andric return OpNo == 0; 3857a6dacacSDimitry Andric case RISCV::PseudoVMV_X_S: { 3865f757f3fSDimitry Andric // vmv.x.s has at least 33 sign bits if log2(sew) <= 5. 3875f757f3fSDimitry Andric int64_t Log2SEW = MI.getOperand(2).getImm(); 3885f757f3fSDimitry Andric assert(Log2SEW >= 3 && Log2SEW <= 6 && "Unexpected Log2SEW"); 3895f757f3fSDimitry Andric return Log2SEW <= 5; 3905f757f3fSDimitry Andric } 39106c3fb27SDimitry Andric } 39206c3fb27SDimitry Andric 39306c3fb27SDimitry Andric return false; 39406c3fb27SDimitry Andric } 39506c3fb27SDimitry Andric 39606c3fb27SDimitry Andric static bool isSignExtendedW(Register SrcReg, const RISCVSubtarget &ST, 39706c3fb27SDimitry Andric const MachineRegisterInfo &MRI, 39806c3fb27SDimitry Andric SmallPtrSetImpl<MachineInstr *> &FixableDef) { 399*0fca6ea1SDimitry Andric SmallSet<Register, 4> Visited; 400*0fca6ea1SDimitry Andric SmallVector<Register, 4> Worklist; 40106c3fb27SDimitry Andric 402*0fca6ea1SDimitry Andric auto AddRegToWorkList = [&](Register SrcReg) { 40306c3fb27SDimitry Andric if (!SrcReg.isVirtual()) 40406c3fb27SDimitry Andric return false; 405*0fca6ea1SDimitry Andric Worklist.push_back(SrcReg); 40606c3fb27SDimitry Andric return true; 40706c3fb27SDimitry Andric }; 40806c3fb27SDimitry Andric 409*0fca6ea1SDimitry Andric if (!AddRegToWorkList(SrcReg)) 41006c3fb27SDimitry Andric return false; 41106c3fb27SDimitry Andric 41206c3fb27SDimitry Andric while (!Worklist.empty()) { 413*0fca6ea1SDimitry Andric Register Reg = Worklist.pop_back_val(); 41406c3fb27SDimitry Andric 415*0fca6ea1SDimitry Andric // If we already visited this register, we don't need to check it again. 416*0fca6ea1SDimitry Andric if (!Visited.insert(Reg).second) 41706c3fb27SDimitry Andric continue; 41806c3fb27SDimitry Andric 419*0fca6ea1SDimitry Andric MachineInstr *MI = MRI.getVRegDef(Reg); 420*0fca6ea1SDimitry Andric if (!MI) 421*0fca6ea1SDimitry Andric continue; 422*0fca6ea1SDimitry Andric 423*0fca6ea1SDimitry Andric int OpNo = MI->findRegisterDefOperandIdx(Reg, /*TRI=*/nullptr); 424*0fca6ea1SDimitry Andric assert(OpNo != -1 && "Couldn't find register"); 425*0fca6ea1SDimitry Andric 42606c3fb27SDimitry Andric // If this is a sign extending operation we don't need to look any further. 427*0fca6ea1SDimitry Andric if (isSignExtendingOpW(*MI, MRI, OpNo)) 42806c3fb27SDimitry Andric continue; 42906c3fb27SDimitry Andric 43006c3fb27SDimitry Andric // Is this an instruction that propagates sign extend? 43106c3fb27SDimitry Andric switch (MI->getOpcode()) { 43206c3fb27SDimitry Andric default: 43306c3fb27SDimitry Andric // Unknown opcode, give up. 43406c3fb27SDimitry Andric return false; 43506c3fb27SDimitry Andric case RISCV::COPY: { 43606c3fb27SDimitry Andric const MachineFunction *MF = MI->getMF(); 43706c3fb27SDimitry Andric const RISCVMachineFunctionInfo *RVFI = 43806c3fb27SDimitry Andric MF->getInfo<RISCVMachineFunctionInfo>(); 43906c3fb27SDimitry Andric 44006c3fb27SDimitry Andric // If this is the entry block and the register is livein, see if we know 44106c3fb27SDimitry Andric // it is sign extended. 44206c3fb27SDimitry Andric if (MI->getParent() == &MF->front()) { 44306c3fb27SDimitry Andric Register VReg = MI->getOperand(0).getReg(); 44406c3fb27SDimitry Andric if (MF->getRegInfo().isLiveIn(VReg) && RVFI->isSExt32Register(VReg)) 44506c3fb27SDimitry Andric continue; 44606c3fb27SDimitry Andric } 44706c3fb27SDimitry Andric 44806c3fb27SDimitry Andric Register CopySrcReg = MI->getOperand(1).getReg(); 44906c3fb27SDimitry Andric if (CopySrcReg == RISCV::X10) { 45006c3fb27SDimitry Andric // For a method return value, we check the ZExt/SExt flags in attribute. 45106c3fb27SDimitry Andric // We assume the following code sequence for method call. 45206c3fb27SDimitry Andric // PseudoCALL @bar, ... 45306c3fb27SDimitry Andric // ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2 45406c3fb27SDimitry Andric // %0:gpr = COPY $x10 45506c3fb27SDimitry Andric // 45606c3fb27SDimitry Andric // We use the PseudoCall to look up the IR function being called to find 45706c3fb27SDimitry Andric // its return attributes. 45806c3fb27SDimitry Andric const MachineBasicBlock *MBB = MI->getParent(); 45906c3fb27SDimitry Andric auto II = MI->getIterator(); 46006c3fb27SDimitry Andric if (II == MBB->instr_begin() || 46106c3fb27SDimitry Andric (--II)->getOpcode() != RISCV::ADJCALLSTACKUP) 46206c3fb27SDimitry Andric return false; 46306c3fb27SDimitry Andric 46406c3fb27SDimitry Andric const MachineInstr &CallMI = *(--II); 46506c3fb27SDimitry Andric if (!CallMI.isCall() || !CallMI.getOperand(0).isGlobal()) 46606c3fb27SDimitry Andric return false; 46706c3fb27SDimitry Andric 46806c3fb27SDimitry Andric auto *CalleeFn = 46906c3fb27SDimitry Andric dyn_cast_if_present<Function>(CallMI.getOperand(0).getGlobal()); 47006c3fb27SDimitry Andric if (!CalleeFn) 47106c3fb27SDimitry Andric return false; 47206c3fb27SDimitry Andric 47306c3fb27SDimitry Andric auto *IntTy = dyn_cast<IntegerType>(CalleeFn->getReturnType()); 47406c3fb27SDimitry Andric if (!IntTy) 47506c3fb27SDimitry Andric return false; 47606c3fb27SDimitry Andric 47706c3fb27SDimitry Andric const AttributeSet &Attrs = CalleeFn->getAttributes().getRetAttrs(); 47806c3fb27SDimitry Andric unsigned BitWidth = IntTy->getBitWidth(); 47906c3fb27SDimitry Andric if ((BitWidth <= 32 && Attrs.hasAttribute(Attribute::SExt)) || 48006c3fb27SDimitry Andric (BitWidth < 32 && Attrs.hasAttribute(Attribute::ZExt))) 48106c3fb27SDimitry Andric continue; 48206c3fb27SDimitry Andric } 48306c3fb27SDimitry Andric 484*0fca6ea1SDimitry Andric if (!AddRegToWorkList(CopySrcReg)) 48506c3fb27SDimitry Andric return false; 48606c3fb27SDimitry Andric 48706c3fb27SDimitry Andric break; 48806c3fb27SDimitry Andric } 48906c3fb27SDimitry Andric 49006c3fb27SDimitry Andric // For these, we just need to check if the 1st operand is sign extended. 49106c3fb27SDimitry Andric case RISCV::BCLRI: 49206c3fb27SDimitry Andric case RISCV::BINVI: 49306c3fb27SDimitry Andric case RISCV::BSETI: 49406c3fb27SDimitry Andric if (MI->getOperand(2).getImm() >= 31) 49506c3fb27SDimitry Andric return false; 49606c3fb27SDimitry Andric [[fallthrough]]; 49706c3fb27SDimitry Andric case RISCV::REM: 49806c3fb27SDimitry Andric case RISCV::ANDI: 49906c3fb27SDimitry Andric case RISCV::ORI: 50006c3fb27SDimitry Andric case RISCV::XORI: 50106c3fb27SDimitry Andric // |Remainder| is always <= |Dividend|. If D is 32-bit, then so is R. 50206c3fb27SDimitry Andric // DIV doesn't work because of the edge case 0xf..f 8000 0000 / (long)-1 50306c3fb27SDimitry Andric // Logical operations use a sign extended 12-bit immediate. 504*0fca6ea1SDimitry Andric if (!AddRegToWorkList(MI->getOperand(1).getReg())) 50506c3fb27SDimitry Andric return false; 50606c3fb27SDimitry Andric 50706c3fb27SDimitry Andric break; 50806c3fb27SDimitry Andric case RISCV::PseudoCCADDW: 5095f757f3fSDimitry Andric case RISCV::PseudoCCADDIW: 51006c3fb27SDimitry Andric case RISCV::PseudoCCSUBW: 5115f757f3fSDimitry Andric case RISCV::PseudoCCSLLW: 5125f757f3fSDimitry Andric case RISCV::PseudoCCSRLW: 5135f757f3fSDimitry Andric case RISCV::PseudoCCSRAW: 5145f757f3fSDimitry Andric case RISCV::PseudoCCSLLIW: 5155f757f3fSDimitry Andric case RISCV::PseudoCCSRLIW: 5165f757f3fSDimitry Andric case RISCV::PseudoCCSRAIW: 5175f757f3fSDimitry Andric // Returns operand 4 or an ADDW/SUBW/etc. of operands 5 and 6. We only 5185f757f3fSDimitry Andric // need to check if operand 4 is sign extended. 519*0fca6ea1SDimitry Andric if (!AddRegToWorkList(MI->getOperand(4).getReg())) 52006c3fb27SDimitry Andric return false; 52106c3fb27SDimitry Andric break; 52206c3fb27SDimitry Andric case RISCV::REMU: 52306c3fb27SDimitry Andric case RISCV::AND: 52406c3fb27SDimitry Andric case RISCV::OR: 52506c3fb27SDimitry Andric case RISCV::XOR: 52606c3fb27SDimitry Andric case RISCV::ANDN: 52706c3fb27SDimitry Andric case RISCV::ORN: 52806c3fb27SDimitry Andric case RISCV::XNOR: 52906c3fb27SDimitry Andric case RISCV::MAX: 53006c3fb27SDimitry Andric case RISCV::MAXU: 53106c3fb27SDimitry Andric case RISCV::MIN: 53206c3fb27SDimitry Andric case RISCV::MINU: 53306c3fb27SDimitry Andric case RISCV::PseudoCCMOVGPR: 53406c3fb27SDimitry Andric case RISCV::PseudoCCAND: 53506c3fb27SDimitry Andric case RISCV::PseudoCCOR: 53606c3fb27SDimitry Andric case RISCV::PseudoCCXOR: 53706c3fb27SDimitry Andric case RISCV::PHI: { 53806c3fb27SDimitry Andric // If all incoming values are sign-extended, the output of AND, OR, XOR, 53906c3fb27SDimitry Andric // MIN, MAX, or PHI is also sign-extended. 54006c3fb27SDimitry Andric 54106c3fb27SDimitry Andric // The input registers for PHI are operand 1, 3, ... 54206c3fb27SDimitry Andric // The input registers for PseudoCCMOVGPR are 4 and 5. 54306c3fb27SDimitry Andric // The input registers for PseudoCCAND/OR/XOR are 4, 5, and 6. 54406c3fb27SDimitry Andric // The input registers for others are operand 1 and 2. 54506c3fb27SDimitry Andric unsigned B = 1, E = 3, D = 1; 54606c3fb27SDimitry Andric switch (MI->getOpcode()) { 54706c3fb27SDimitry Andric case RISCV::PHI: 54806c3fb27SDimitry Andric E = MI->getNumOperands(); 54906c3fb27SDimitry Andric D = 2; 55006c3fb27SDimitry Andric break; 55106c3fb27SDimitry Andric case RISCV::PseudoCCMOVGPR: 55206c3fb27SDimitry Andric B = 4; 55306c3fb27SDimitry Andric E = 6; 55406c3fb27SDimitry Andric break; 55506c3fb27SDimitry Andric case RISCV::PseudoCCAND: 55606c3fb27SDimitry Andric case RISCV::PseudoCCOR: 55706c3fb27SDimitry Andric case RISCV::PseudoCCXOR: 55806c3fb27SDimitry Andric B = 4; 55906c3fb27SDimitry Andric E = 7; 56006c3fb27SDimitry Andric break; 56106c3fb27SDimitry Andric } 56206c3fb27SDimitry Andric 56306c3fb27SDimitry Andric for (unsigned I = B; I != E; I += D) { 56406c3fb27SDimitry Andric if (!MI->getOperand(I).isReg()) 56506c3fb27SDimitry Andric return false; 56606c3fb27SDimitry Andric 567*0fca6ea1SDimitry Andric if (!AddRegToWorkList(MI->getOperand(I).getReg())) 56806c3fb27SDimitry Andric return false; 56906c3fb27SDimitry Andric } 57006c3fb27SDimitry Andric 57106c3fb27SDimitry Andric break; 57206c3fb27SDimitry Andric } 57306c3fb27SDimitry Andric 5745f757f3fSDimitry Andric case RISCV::CZERO_EQZ: 5755f757f3fSDimitry Andric case RISCV::CZERO_NEZ: 57606c3fb27SDimitry Andric case RISCV::VT_MASKC: 57706c3fb27SDimitry Andric case RISCV::VT_MASKCN: 57806c3fb27SDimitry Andric // Instructions return zero or operand 1. Result is sign extended if 57906c3fb27SDimitry Andric // operand 1 is sign extended. 580*0fca6ea1SDimitry Andric if (!AddRegToWorkList(MI->getOperand(1).getReg())) 58106c3fb27SDimitry Andric return false; 58206c3fb27SDimitry Andric break; 58306c3fb27SDimitry Andric 58406c3fb27SDimitry Andric // With these opcode, we can "fix" them with the W-version 58506c3fb27SDimitry Andric // if we know all users of the result only rely on bits 31:0 58606c3fb27SDimitry Andric case RISCV::SLLI: 58706c3fb27SDimitry Andric // SLLIW reads the lowest 5 bits, while SLLI reads lowest 6 bits 58806c3fb27SDimitry Andric if (MI->getOperand(2).getImm() >= 32) 58906c3fb27SDimitry Andric return false; 59006c3fb27SDimitry Andric [[fallthrough]]; 59106c3fb27SDimitry Andric case RISCV::ADDI: 59206c3fb27SDimitry Andric case RISCV::ADD: 59306c3fb27SDimitry Andric case RISCV::LD: 59406c3fb27SDimitry Andric case RISCV::LWU: 59506c3fb27SDimitry Andric case RISCV::MUL: 59606c3fb27SDimitry Andric case RISCV::SUB: 59706c3fb27SDimitry Andric if (hasAllWUsers(*MI, ST, MRI)) { 59806c3fb27SDimitry Andric FixableDef.insert(MI); 59906c3fb27SDimitry Andric break; 60006c3fb27SDimitry Andric } 60106c3fb27SDimitry Andric return false; 60206c3fb27SDimitry Andric } 60306c3fb27SDimitry Andric } 60406c3fb27SDimitry Andric 60506c3fb27SDimitry Andric // If we get here, then every node we visited produces a sign extended value 60606c3fb27SDimitry Andric // or propagated sign extended values. So the result must be sign extended. 60706c3fb27SDimitry Andric return true; 60806c3fb27SDimitry Andric } 60906c3fb27SDimitry Andric 61006c3fb27SDimitry Andric static unsigned getWOp(unsigned Opcode) { 61106c3fb27SDimitry Andric switch (Opcode) { 61206c3fb27SDimitry Andric case RISCV::ADDI: 61306c3fb27SDimitry Andric return RISCV::ADDIW; 61406c3fb27SDimitry Andric case RISCV::ADD: 61506c3fb27SDimitry Andric return RISCV::ADDW; 61606c3fb27SDimitry Andric case RISCV::LD: 61706c3fb27SDimitry Andric case RISCV::LWU: 61806c3fb27SDimitry Andric return RISCV::LW; 61906c3fb27SDimitry Andric case RISCV::MUL: 62006c3fb27SDimitry Andric return RISCV::MULW; 62106c3fb27SDimitry Andric case RISCV::SLLI: 62206c3fb27SDimitry Andric return RISCV::SLLIW; 62306c3fb27SDimitry Andric case RISCV::SUB: 62406c3fb27SDimitry Andric return RISCV::SUBW; 62506c3fb27SDimitry Andric default: 62606c3fb27SDimitry Andric llvm_unreachable("Unexpected opcode for replacement with W variant"); 62706c3fb27SDimitry Andric } 62806c3fb27SDimitry Andric } 62906c3fb27SDimitry Andric 63006c3fb27SDimitry Andric bool RISCVOptWInstrs::removeSExtWInstrs(MachineFunction &MF, 63106c3fb27SDimitry Andric const RISCVInstrInfo &TII, 63206c3fb27SDimitry Andric const RISCVSubtarget &ST, 63306c3fb27SDimitry Andric MachineRegisterInfo &MRI) { 63406c3fb27SDimitry Andric if (DisableSExtWRemoval) 63506c3fb27SDimitry Andric return false; 63606c3fb27SDimitry Andric 63706c3fb27SDimitry Andric bool MadeChange = false; 63806c3fb27SDimitry Andric for (MachineBasicBlock &MBB : MF) { 6395f757f3fSDimitry Andric for (MachineInstr &MI : llvm::make_early_inc_range(MBB)) { 64006c3fb27SDimitry Andric // We're looking for the sext.w pattern ADDIW rd, rs1, 0. 6415f757f3fSDimitry Andric if (!RISCV::isSEXT_W(MI)) 64206c3fb27SDimitry Andric continue; 64306c3fb27SDimitry Andric 6445f757f3fSDimitry Andric Register SrcReg = MI.getOperand(1).getReg(); 64506c3fb27SDimitry Andric 64606c3fb27SDimitry Andric SmallPtrSet<MachineInstr *, 4> FixableDefs; 64706c3fb27SDimitry Andric 64806c3fb27SDimitry Andric // If all users only use the lower bits, this sext.w is redundant. 64906c3fb27SDimitry Andric // Or if all definitions reaching MI sign-extend their output, 65006c3fb27SDimitry Andric // then sext.w is redundant. 6515f757f3fSDimitry Andric if (!hasAllWUsers(MI, ST, MRI) && 65206c3fb27SDimitry Andric !isSignExtendedW(SrcReg, ST, MRI, FixableDefs)) 65306c3fb27SDimitry Andric continue; 65406c3fb27SDimitry Andric 6555f757f3fSDimitry Andric Register DstReg = MI.getOperand(0).getReg(); 65606c3fb27SDimitry Andric if (!MRI.constrainRegClass(SrcReg, MRI.getRegClass(DstReg))) 65706c3fb27SDimitry Andric continue; 65806c3fb27SDimitry Andric 65906c3fb27SDimitry Andric // Convert Fixable instructions to their W versions. 66006c3fb27SDimitry Andric for (MachineInstr *Fixable : FixableDefs) { 66106c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "Replacing " << *Fixable); 66206c3fb27SDimitry Andric Fixable->setDesc(TII.get(getWOp(Fixable->getOpcode()))); 66306c3fb27SDimitry Andric Fixable->clearFlag(MachineInstr::MIFlag::NoSWrap); 66406c3fb27SDimitry Andric Fixable->clearFlag(MachineInstr::MIFlag::NoUWrap); 66506c3fb27SDimitry Andric Fixable->clearFlag(MachineInstr::MIFlag::IsExact); 66606c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << " with " << *Fixable); 66706c3fb27SDimitry Andric ++NumTransformedToWInstrs; 66806c3fb27SDimitry Andric } 66906c3fb27SDimitry Andric 67006c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "Removing redundant sign-extension\n"); 67106c3fb27SDimitry Andric MRI.replaceRegWith(DstReg, SrcReg); 67206c3fb27SDimitry Andric MRI.clearKillFlags(SrcReg); 6735f757f3fSDimitry Andric MI.eraseFromParent(); 67406c3fb27SDimitry Andric ++NumRemovedSExtW; 67506c3fb27SDimitry Andric MadeChange = true; 67606c3fb27SDimitry Andric } 67706c3fb27SDimitry Andric } 67806c3fb27SDimitry Andric 67906c3fb27SDimitry Andric return MadeChange; 68006c3fb27SDimitry Andric } 68106c3fb27SDimitry Andric 68206c3fb27SDimitry Andric bool RISCVOptWInstrs::stripWSuffixes(MachineFunction &MF, 68306c3fb27SDimitry Andric const RISCVInstrInfo &TII, 68406c3fb27SDimitry Andric const RISCVSubtarget &ST, 68506c3fb27SDimitry Andric MachineRegisterInfo &MRI) { 68606c3fb27SDimitry Andric bool MadeChange = false; 68706c3fb27SDimitry Andric for (MachineBasicBlock &MBB : MF) { 6885f757f3fSDimitry Andric for (MachineInstr &MI : MBB) { 68906c3fb27SDimitry Andric unsigned Opc; 69006c3fb27SDimitry Andric switch (MI.getOpcode()) { 69106c3fb27SDimitry Andric default: 69206c3fb27SDimitry Andric continue; 69306c3fb27SDimitry Andric case RISCV::ADDW: Opc = RISCV::ADD; break; 6945f757f3fSDimitry Andric case RISCV::ADDIW: Opc = RISCV::ADDI; break; 69506c3fb27SDimitry Andric case RISCV::MULW: Opc = RISCV::MUL; break; 69606c3fb27SDimitry Andric case RISCV::SLLIW: Opc = RISCV::SLLI; break; 69706c3fb27SDimitry Andric } 69806c3fb27SDimitry Andric 69906c3fb27SDimitry Andric if (hasAllWUsers(MI, ST, MRI)) { 70006c3fb27SDimitry Andric MI.setDesc(TII.get(Opc)); 70106c3fb27SDimitry Andric MadeChange = true; 70206c3fb27SDimitry Andric } 70306c3fb27SDimitry Andric } 70406c3fb27SDimitry Andric } 70506c3fb27SDimitry Andric 70606c3fb27SDimitry Andric return MadeChange; 70706c3fb27SDimitry Andric } 70806c3fb27SDimitry Andric 709*0fca6ea1SDimitry Andric bool RISCVOptWInstrs::appendWSuffixes(MachineFunction &MF, 710*0fca6ea1SDimitry Andric const RISCVInstrInfo &TII, 711*0fca6ea1SDimitry Andric const RISCVSubtarget &ST, 712*0fca6ea1SDimitry Andric MachineRegisterInfo &MRI) { 713*0fca6ea1SDimitry Andric bool MadeChange = false; 714*0fca6ea1SDimitry Andric for (MachineBasicBlock &MBB : MF) { 715*0fca6ea1SDimitry Andric for (MachineInstr &MI : MBB) { 716*0fca6ea1SDimitry Andric unsigned WOpc; 717*0fca6ea1SDimitry Andric // TODO: Add more? 718*0fca6ea1SDimitry Andric switch (MI.getOpcode()) { 719*0fca6ea1SDimitry Andric default: 720*0fca6ea1SDimitry Andric continue; 721*0fca6ea1SDimitry Andric case RISCV::ADD: 722*0fca6ea1SDimitry Andric WOpc = RISCV::ADDW; 723*0fca6ea1SDimitry Andric break; 724*0fca6ea1SDimitry Andric case RISCV::ADDI: 725*0fca6ea1SDimitry Andric WOpc = RISCV::ADDIW; 726*0fca6ea1SDimitry Andric break; 727*0fca6ea1SDimitry Andric case RISCV::SUB: 728*0fca6ea1SDimitry Andric WOpc = RISCV::SUBW; 729*0fca6ea1SDimitry Andric break; 730*0fca6ea1SDimitry Andric case RISCV::MUL: 731*0fca6ea1SDimitry Andric WOpc = RISCV::MULW; 732*0fca6ea1SDimitry Andric break; 733*0fca6ea1SDimitry Andric case RISCV::SLLI: 734*0fca6ea1SDimitry Andric // SLLIW reads the lowest 5 bits, while SLLI reads lowest 6 bits 735*0fca6ea1SDimitry Andric if (MI.getOperand(2).getImm() >= 32) 736*0fca6ea1SDimitry Andric continue; 737*0fca6ea1SDimitry Andric WOpc = RISCV::SLLIW; 738*0fca6ea1SDimitry Andric break; 739*0fca6ea1SDimitry Andric case RISCV::LD: 740*0fca6ea1SDimitry Andric case RISCV::LWU: 741*0fca6ea1SDimitry Andric WOpc = RISCV::LW; 742*0fca6ea1SDimitry Andric break; 743*0fca6ea1SDimitry Andric } 744*0fca6ea1SDimitry Andric 745*0fca6ea1SDimitry Andric if (hasAllWUsers(MI, ST, MRI)) { 746*0fca6ea1SDimitry Andric LLVM_DEBUG(dbgs() << "Replacing " << MI); 747*0fca6ea1SDimitry Andric MI.setDesc(TII.get(WOpc)); 748*0fca6ea1SDimitry Andric MI.clearFlag(MachineInstr::MIFlag::NoSWrap); 749*0fca6ea1SDimitry Andric MI.clearFlag(MachineInstr::MIFlag::NoUWrap); 750*0fca6ea1SDimitry Andric MI.clearFlag(MachineInstr::MIFlag::IsExact); 751*0fca6ea1SDimitry Andric LLVM_DEBUG(dbgs() << " with " << MI); 752*0fca6ea1SDimitry Andric ++NumTransformedToWInstrs; 753*0fca6ea1SDimitry Andric MadeChange = true; 754*0fca6ea1SDimitry Andric } 755*0fca6ea1SDimitry Andric } 756*0fca6ea1SDimitry Andric } 757*0fca6ea1SDimitry Andric 758*0fca6ea1SDimitry Andric return MadeChange; 759*0fca6ea1SDimitry Andric } 760*0fca6ea1SDimitry Andric 76106c3fb27SDimitry Andric bool RISCVOptWInstrs::runOnMachineFunction(MachineFunction &MF) { 76206c3fb27SDimitry Andric if (skipFunction(MF.getFunction())) 76306c3fb27SDimitry Andric return false; 76406c3fb27SDimitry Andric 76506c3fb27SDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 76606c3fb27SDimitry Andric const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>(); 76706c3fb27SDimitry Andric const RISCVInstrInfo &TII = *ST.getInstrInfo(); 76806c3fb27SDimitry Andric 76906c3fb27SDimitry Andric if (!ST.is64Bit()) 77006c3fb27SDimitry Andric return false; 77106c3fb27SDimitry Andric 77206c3fb27SDimitry Andric bool MadeChange = false; 77306c3fb27SDimitry Andric MadeChange |= removeSExtWInstrs(MF, TII, ST, MRI); 774*0fca6ea1SDimitry Andric 775*0fca6ea1SDimitry Andric if (!(DisableStripWSuffix || ST.preferWInst())) 77606c3fb27SDimitry Andric MadeChange |= stripWSuffixes(MF, TII, ST, MRI); 77706c3fb27SDimitry Andric 778*0fca6ea1SDimitry Andric if (ST.preferWInst()) 779*0fca6ea1SDimitry Andric MadeChange |= appendWSuffixes(MF, TII, ST, MRI); 780*0fca6ea1SDimitry Andric 78106c3fb27SDimitry Andric return MadeChange; 78206c3fb27SDimitry Andric } 783