xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVOptWInstrs.cpp (revision 1db9f3b21e39176dd5b67cf8ac378633b172463e)
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 //
155f757f3fSDimitry Andric // Then it removes the -w suffix from opw instructions whenever all users are
165f757f3fSDimitry Andric // dependent only on the lower word of the result of the instruction.
175f757f3fSDimitry Andric // The cases handled are:
185f757f3fSDimitry Andric // * addw because c.add has a larger register encoding than c.addw.
195f757f3fSDimitry Andric // * addiw because it helps reduce test differences between RV32 and RV64
205f757f3fSDimitry Andric //   w/o being a pessimization.
215f757f3fSDimitry Andric // * mulw because c.mulw doesn't exist but c.mul does (w/ zcb)
225f757f3fSDimitry Andric // * slliw because c.slliw doesn't exist and c.slli does
2306c3fb27SDimitry Andric //
2406c3fb27SDimitry Andric //===---------------------------------------------------------------------===//
2506c3fb27SDimitry Andric 
2606c3fb27SDimitry Andric #include "RISCV.h"
2706c3fb27SDimitry Andric #include "RISCVMachineFunctionInfo.h"
2806c3fb27SDimitry Andric #include "RISCVSubtarget.h"
295f757f3fSDimitry Andric #include "llvm/ADT/SmallSet.h"
3006c3fb27SDimitry Andric #include "llvm/ADT/Statistic.h"
3106c3fb27SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
3206c3fb27SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
3306c3fb27SDimitry Andric 
3406c3fb27SDimitry Andric using namespace llvm;
3506c3fb27SDimitry Andric 
3606c3fb27SDimitry Andric #define DEBUG_TYPE "riscv-opt-w-instrs"
3706c3fb27SDimitry Andric #define RISCV_OPT_W_INSTRS_NAME "RISC-V Optimize W Instructions"
3806c3fb27SDimitry Andric 
3906c3fb27SDimitry Andric STATISTIC(NumRemovedSExtW, "Number of removed sign-extensions");
4006c3fb27SDimitry Andric STATISTIC(NumTransformedToWInstrs,
4106c3fb27SDimitry Andric           "Number of instructions transformed to W-ops");
4206c3fb27SDimitry Andric 
4306c3fb27SDimitry Andric static cl::opt<bool> DisableSExtWRemoval("riscv-disable-sextw-removal",
4406c3fb27SDimitry Andric                                          cl::desc("Disable removal of sext.w"),
4506c3fb27SDimitry Andric                                          cl::init(false), cl::Hidden);
4606c3fb27SDimitry Andric static cl::opt<bool> DisableStripWSuffix("riscv-disable-strip-w-suffix",
4706c3fb27SDimitry Andric                                          cl::desc("Disable strip W suffix"),
4806c3fb27SDimitry Andric                                          cl::init(false), cl::Hidden);
4906c3fb27SDimitry Andric 
5006c3fb27SDimitry Andric namespace {
5106c3fb27SDimitry Andric 
5206c3fb27SDimitry Andric class RISCVOptWInstrs : public MachineFunctionPass {
5306c3fb27SDimitry Andric public:
5406c3fb27SDimitry Andric   static char ID;
5506c3fb27SDimitry Andric 
565f757f3fSDimitry Andric   RISCVOptWInstrs() : MachineFunctionPass(ID) {}
5706c3fb27SDimitry Andric 
5806c3fb27SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
5906c3fb27SDimitry Andric   bool removeSExtWInstrs(MachineFunction &MF, const RISCVInstrInfo &TII,
6006c3fb27SDimitry Andric                          const RISCVSubtarget &ST, MachineRegisterInfo &MRI);
6106c3fb27SDimitry Andric   bool stripWSuffixes(MachineFunction &MF, const RISCVInstrInfo &TII,
6206c3fb27SDimitry Andric                       const RISCVSubtarget &ST, MachineRegisterInfo &MRI);
6306c3fb27SDimitry Andric 
6406c3fb27SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
6506c3fb27SDimitry Andric     AU.setPreservesCFG();
6606c3fb27SDimitry Andric     MachineFunctionPass::getAnalysisUsage(AU);
6706c3fb27SDimitry Andric   }
6806c3fb27SDimitry Andric 
6906c3fb27SDimitry Andric   StringRef getPassName() const override { return RISCV_OPT_W_INSTRS_NAME; }
7006c3fb27SDimitry Andric };
7106c3fb27SDimitry Andric 
7206c3fb27SDimitry Andric } // end anonymous namespace
7306c3fb27SDimitry Andric 
7406c3fb27SDimitry Andric char RISCVOptWInstrs::ID = 0;
7506c3fb27SDimitry Andric INITIALIZE_PASS(RISCVOptWInstrs, DEBUG_TYPE, RISCV_OPT_W_INSTRS_NAME, false,
7606c3fb27SDimitry Andric                 false)
7706c3fb27SDimitry Andric 
7806c3fb27SDimitry Andric FunctionPass *llvm::createRISCVOptWInstrsPass() {
7906c3fb27SDimitry Andric   return new RISCVOptWInstrs();
8006c3fb27SDimitry Andric }
8106c3fb27SDimitry Andric 
825f757f3fSDimitry Andric static bool vectorPseudoHasAllNBitUsers(const MachineOperand &UserOp,
835f757f3fSDimitry Andric                                         unsigned Bits) {
845f757f3fSDimitry Andric   const MachineInstr &MI = *UserOp.getParent();
855f757f3fSDimitry Andric   unsigned MCOpcode = RISCV::getRVVMCOpcode(MI.getOpcode());
865f757f3fSDimitry Andric 
875f757f3fSDimitry Andric   if (!MCOpcode)
885f757f3fSDimitry Andric     return false;
895f757f3fSDimitry Andric 
905f757f3fSDimitry Andric   const MCInstrDesc &MCID = MI.getDesc();
915f757f3fSDimitry Andric   const uint64_t TSFlags = MCID.TSFlags;
925f757f3fSDimitry Andric   if (!RISCVII::hasSEWOp(TSFlags))
935f757f3fSDimitry Andric     return false;
945f757f3fSDimitry Andric   assert(RISCVII::hasVLOp(TSFlags));
955f757f3fSDimitry Andric   const unsigned Log2SEW = MI.getOperand(RISCVII::getSEWOpNum(MCID)).getImm();
965f757f3fSDimitry Andric 
975f757f3fSDimitry Andric   if (UserOp.getOperandNo() == RISCVII::getVLOpNum(MCID))
985f757f3fSDimitry Andric     return false;
995f757f3fSDimitry Andric 
1005f757f3fSDimitry Andric   auto NumDemandedBits =
1015f757f3fSDimitry Andric       RISCV::getVectorLowDemandedScalarBits(MCOpcode, Log2SEW);
1025f757f3fSDimitry Andric   return NumDemandedBits && Bits >= *NumDemandedBits;
1035f757f3fSDimitry Andric }
1045f757f3fSDimitry Andric 
10506c3fb27SDimitry Andric // Checks if all users only demand the lower \p OrigBits of the original
10606c3fb27SDimitry Andric // instruction's result.
10706c3fb27SDimitry Andric // TODO: handle multiple interdependent transformations
10806c3fb27SDimitry Andric static bool hasAllNBitUsers(const MachineInstr &OrigMI,
10906c3fb27SDimitry Andric                             const RISCVSubtarget &ST,
11006c3fb27SDimitry Andric                             const MachineRegisterInfo &MRI, unsigned OrigBits) {
11106c3fb27SDimitry Andric 
11206c3fb27SDimitry Andric   SmallSet<std::pair<const MachineInstr *, unsigned>, 4> Visited;
11306c3fb27SDimitry Andric   SmallVector<std::pair<const MachineInstr *, unsigned>, 4> Worklist;
11406c3fb27SDimitry Andric 
11506c3fb27SDimitry Andric   Worklist.push_back(std::make_pair(&OrigMI, OrigBits));
11606c3fb27SDimitry Andric 
11706c3fb27SDimitry Andric   while (!Worklist.empty()) {
11806c3fb27SDimitry Andric     auto P = Worklist.pop_back_val();
11906c3fb27SDimitry Andric     const MachineInstr *MI = P.first;
12006c3fb27SDimitry Andric     unsigned Bits = P.second;
12106c3fb27SDimitry Andric 
12206c3fb27SDimitry Andric     if (!Visited.insert(P).second)
12306c3fb27SDimitry Andric       continue;
12406c3fb27SDimitry Andric 
12506c3fb27SDimitry Andric     // Only handle instructions with one def.
12606c3fb27SDimitry Andric     if (MI->getNumExplicitDefs() != 1)
12706c3fb27SDimitry Andric       return false;
12806c3fb27SDimitry Andric 
129*1db9f3b2SDimitry Andric     Register DestReg = MI->getOperand(0).getReg();
130*1db9f3b2SDimitry Andric     if (!DestReg.isVirtual())
131*1db9f3b2SDimitry Andric       return false;
132*1db9f3b2SDimitry Andric 
133*1db9f3b2SDimitry Andric     for (auto &UserOp : MRI.use_nodbg_operands(DestReg)) {
13406c3fb27SDimitry Andric       const MachineInstr *UserMI = UserOp.getParent();
13506c3fb27SDimitry Andric       unsigned OpIdx = UserOp.getOperandNo();
13606c3fb27SDimitry Andric 
13706c3fb27SDimitry Andric       switch (UserMI->getOpcode()) {
13806c3fb27SDimitry Andric       default:
1395f757f3fSDimitry Andric         if (vectorPseudoHasAllNBitUsers(UserOp, Bits))
1405f757f3fSDimitry Andric           break;
14106c3fb27SDimitry Andric         return false;
14206c3fb27SDimitry Andric 
14306c3fb27SDimitry Andric       case RISCV::ADDIW:
14406c3fb27SDimitry Andric       case RISCV::ADDW:
14506c3fb27SDimitry Andric       case RISCV::DIVUW:
14606c3fb27SDimitry Andric       case RISCV::DIVW:
14706c3fb27SDimitry Andric       case RISCV::MULW:
14806c3fb27SDimitry Andric       case RISCV::REMUW:
14906c3fb27SDimitry Andric       case RISCV::REMW:
15006c3fb27SDimitry Andric       case RISCV::SLLIW:
15106c3fb27SDimitry Andric       case RISCV::SLLW:
15206c3fb27SDimitry Andric       case RISCV::SRAIW:
15306c3fb27SDimitry Andric       case RISCV::SRAW:
15406c3fb27SDimitry Andric       case RISCV::SRLIW:
15506c3fb27SDimitry Andric       case RISCV::SRLW:
15606c3fb27SDimitry Andric       case RISCV::SUBW:
15706c3fb27SDimitry Andric       case RISCV::ROLW:
15806c3fb27SDimitry Andric       case RISCV::RORW:
15906c3fb27SDimitry Andric       case RISCV::RORIW:
16006c3fb27SDimitry Andric       case RISCV::CLZW:
16106c3fb27SDimitry Andric       case RISCV::CTZW:
16206c3fb27SDimitry Andric       case RISCV::CPOPW:
16306c3fb27SDimitry Andric       case RISCV::SLLI_UW:
16406c3fb27SDimitry Andric       case RISCV::FMV_W_X:
16506c3fb27SDimitry Andric       case RISCV::FCVT_H_W:
16606c3fb27SDimitry Andric       case RISCV::FCVT_H_WU:
16706c3fb27SDimitry Andric       case RISCV::FCVT_S_W:
16806c3fb27SDimitry Andric       case RISCV::FCVT_S_WU:
16906c3fb27SDimitry Andric       case RISCV::FCVT_D_W:
17006c3fb27SDimitry Andric       case RISCV::FCVT_D_WU:
17106c3fb27SDimitry Andric         if (Bits >= 32)
17206c3fb27SDimitry Andric           break;
17306c3fb27SDimitry Andric         return false;
17406c3fb27SDimitry Andric       case RISCV::SEXT_B:
17506c3fb27SDimitry Andric       case RISCV::PACKH:
17606c3fb27SDimitry Andric         if (Bits >= 8)
17706c3fb27SDimitry Andric           break;
17806c3fb27SDimitry Andric         return false;
17906c3fb27SDimitry Andric       case RISCV::SEXT_H:
18006c3fb27SDimitry Andric       case RISCV::FMV_H_X:
18106c3fb27SDimitry Andric       case RISCV::ZEXT_H_RV32:
18206c3fb27SDimitry Andric       case RISCV::ZEXT_H_RV64:
18306c3fb27SDimitry Andric       case RISCV::PACKW:
18406c3fb27SDimitry Andric         if (Bits >= 16)
18506c3fb27SDimitry Andric           break;
18606c3fb27SDimitry Andric         return false;
18706c3fb27SDimitry Andric 
18806c3fb27SDimitry Andric       case RISCV::PACK:
18906c3fb27SDimitry Andric         if (Bits >= (ST.getXLen() / 2))
19006c3fb27SDimitry Andric           break;
19106c3fb27SDimitry Andric         return false;
19206c3fb27SDimitry Andric 
19306c3fb27SDimitry Andric       case RISCV::SRLI: {
19406c3fb27SDimitry Andric         // If we are shifting right by less than Bits, and users don't demand
19506c3fb27SDimitry Andric         // any bits that were shifted into [Bits-1:0], then we can consider this
19606c3fb27SDimitry Andric         // as an N-Bit user.
19706c3fb27SDimitry Andric         unsigned ShAmt = UserMI->getOperand(2).getImm();
19806c3fb27SDimitry Andric         if (Bits > ShAmt) {
19906c3fb27SDimitry Andric           Worklist.push_back(std::make_pair(UserMI, Bits - ShAmt));
20006c3fb27SDimitry Andric           break;
20106c3fb27SDimitry Andric         }
20206c3fb27SDimitry Andric         return false;
20306c3fb27SDimitry Andric       }
20406c3fb27SDimitry Andric 
20506c3fb27SDimitry Andric       // these overwrite higher input bits, otherwise the lower word of output
20606c3fb27SDimitry Andric       // depends only on the lower word of input. So check their uses read W.
20706c3fb27SDimitry Andric       case RISCV::SLLI:
20806c3fb27SDimitry Andric         if (Bits >= (ST.getXLen() - UserMI->getOperand(2).getImm()))
20906c3fb27SDimitry Andric           break;
21006c3fb27SDimitry Andric         Worklist.push_back(std::make_pair(UserMI, Bits));
21106c3fb27SDimitry Andric         break;
21206c3fb27SDimitry Andric       case RISCV::ANDI: {
21306c3fb27SDimitry Andric         uint64_t Imm = UserMI->getOperand(2).getImm();
21406c3fb27SDimitry Andric         if (Bits >= (unsigned)llvm::bit_width(Imm))
21506c3fb27SDimitry Andric           break;
21606c3fb27SDimitry Andric         Worklist.push_back(std::make_pair(UserMI, Bits));
21706c3fb27SDimitry Andric         break;
21806c3fb27SDimitry Andric       }
21906c3fb27SDimitry Andric       case RISCV::ORI: {
22006c3fb27SDimitry Andric         uint64_t Imm = UserMI->getOperand(2).getImm();
22106c3fb27SDimitry Andric         if (Bits >= (unsigned)llvm::bit_width<uint64_t>(~Imm))
22206c3fb27SDimitry Andric           break;
22306c3fb27SDimitry Andric         Worklist.push_back(std::make_pair(UserMI, Bits));
22406c3fb27SDimitry Andric         break;
22506c3fb27SDimitry Andric       }
22606c3fb27SDimitry Andric 
22706c3fb27SDimitry Andric       case RISCV::SLL:
22806c3fb27SDimitry Andric       case RISCV::BSET:
22906c3fb27SDimitry Andric       case RISCV::BCLR:
23006c3fb27SDimitry Andric       case RISCV::BINV:
23106c3fb27SDimitry Andric         // Operand 2 is the shift amount which uses log2(xlen) bits.
23206c3fb27SDimitry Andric         if (OpIdx == 2) {
23306c3fb27SDimitry Andric           if (Bits >= Log2_32(ST.getXLen()))
23406c3fb27SDimitry Andric             break;
23506c3fb27SDimitry Andric           return false;
23606c3fb27SDimitry Andric         }
23706c3fb27SDimitry Andric         Worklist.push_back(std::make_pair(UserMI, Bits));
23806c3fb27SDimitry Andric         break;
23906c3fb27SDimitry Andric 
24006c3fb27SDimitry Andric       case RISCV::SRA:
24106c3fb27SDimitry Andric       case RISCV::SRL:
24206c3fb27SDimitry Andric       case RISCV::ROL:
24306c3fb27SDimitry Andric       case RISCV::ROR:
24406c3fb27SDimitry Andric         // Operand 2 is the shift amount which uses 6 bits.
24506c3fb27SDimitry Andric         if (OpIdx == 2 && Bits >= Log2_32(ST.getXLen()))
24606c3fb27SDimitry Andric           break;
24706c3fb27SDimitry Andric         return false;
24806c3fb27SDimitry Andric 
24906c3fb27SDimitry Andric       case RISCV::ADD_UW:
25006c3fb27SDimitry Andric       case RISCV::SH1ADD_UW:
25106c3fb27SDimitry Andric       case RISCV::SH2ADD_UW:
25206c3fb27SDimitry Andric       case RISCV::SH3ADD_UW:
25306c3fb27SDimitry Andric         // Operand 1 is implicitly zero extended.
25406c3fb27SDimitry Andric         if (OpIdx == 1 && Bits >= 32)
25506c3fb27SDimitry Andric           break;
25606c3fb27SDimitry Andric         Worklist.push_back(std::make_pair(UserMI, Bits));
25706c3fb27SDimitry Andric         break;
25806c3fb27SDimitry Andric 
25906c3fb27SDimitry Andric       case RISCV::BEXTI:
26006c3fb27SDimitry Andric         if (UserMI->getOperand(2).getImm() >= Bits)
26106c3fb27SDimitry Andric           return false;
26206c3fb27SDimitry Andric         break;
26306c3fb27SDimitry Andric 
26406c3fb27SDimitry Andric       case RISCV::SB:
26506c3fb27SDimitry Andric         // The first argument is the value to store.
26606c3fb27SDimitry Andric         if (OpIdx == 0 && Bits >= 8)
26706c3fb27SDimitry Andric           break;
26806c3fb27SDimitry Andric         return false;
26906c3fb27SDimitry Andric       case RISCV::SH:
27006c3fb27SDimitry Andric         // The first argument is the value to store.
27106c3fb27SDimitry Andric         if (OpIdx == 0 && Bits >= 16)
27206c3fb27SDimitry Andric           break;
27306c3fb27SDimitry Andric         return false;
27406c3fb27SDimitry Andric       case RISCV::SW:
27506c3fb27SDimitry Andric         // The first argument is the value to store.
27606c3fb27SDimitry Andric         if (OpIdx == 0 && Bits >= 32)
27706c3fb27SDimitry Andric           break;
27806c3fb27SDimitry Andric         return false;
27906c3fb27SDimitry Andric 
28006c3fb27SDimitry Andric       // For these, lower word of output in these operations, depends only on
28106c3fb27SDimitry Andric       // the lower word of input. So, we check all uses only read lower word.
28206c3fb27SDimitry Andric       case RISCV::COPY:
28306c3fb27SDimitry Andric       case RISCV::PHI:
28406c3fb27SDimitry Andric 
28506c3fb27SDimitry Andric       case RISCV::ADD:
28606c3fb27SDimitry Andric       case RISCV::ADDI:
28706c3fb27SDimitry Andric       case RISCV::AND:
28806c3fb27SDimitry Andric       case RISCV::MUL:
28906c3fb27SDimitry Andric       case RISCV::OR:
29006c3fb27SDimitry Andric       case RISCV::SUB:
29106c3fb27SDimitry Andric       case RISCV::XOR:
29206c3fb27SDimitry Andric       case RISCV::XORI:
29306c3fb27SDimitry Andric 
29406c3fb27SDimitry Andric       case RISCV::ANDN:
29506c3fb27SDimitry Andric       case RISCV::BREV8:
29606c3fb27SDimitry Andric       case RISCV::CLMUL:
29706c3fb27SDimitry Andric       case RISCV::ORC_B:
29806c3fb27SDimitry Andric       case RISCV::ORN:
29906c3fb27SDimitry Andric       case RISCV::SH1ADD:
30006c3fb27SDimitry Andric       case RISCV::SH2ADD:
30106c3fb27SDimitry Andric       case RISCV::SH3ADD:
30206c3fb27SDimitry Andric       case RISCV::XNOR:
30306c3fb27SDimitry Andric       case RISCV::BSETI:
30406c3fb27SDimitry Andric       case RISCV::BCLRI:
30506c3fb27SDimitry Andric       case RISCV::BINVI:
30606c3fb27SDimitry Andric         Worklist.push_back(std::make_pair(UserMI, Bits));
30706c3fb27SDimitry Andric         break;
30806c3fb27SDimitry Andric 
30906c3fb27SDimitry Andric       case RISCV::PseudoCCMOVGPR:
31006c3fb27SDimitry Andric         // Either operand 4 or operand 5 is returned by this instruction. If
31106c3fb27SDimitry Andric         // only the lower word of the result is used, then only the lower word
31206c3fb27SDimitry Andric         // of operand 4 and 5 is used.
31306c3fb27SDimitry Andric         if (OpIdx != 4 && OpIdx != 5)
31406c3fb27SDimitry Andric           return false;
31506c3fb27SDimitry Andric         Worklist.push_back(std::make_pair(UserMI, Bits));
31606c3fb27SDimitry Andric         break;
31706c3fb27SDimitry Andric 
3185f757f3fSDimitry Andric       case RISCV::CZERO_EQZ:
3195f757f3fSDimitry Andric       case RISCV::CZERO_NEZ:
32006c3fb27SDimitry Andric       case RISCV::VT_MASKC:
32106c3fb27SDimitry Andric       case RISCV::VT_MASKCN:
32206c3fb27SDimitry Andric         if (OpIdx != 1)
32306c3fb27SDimitry Andric           return false;
32406c3fb27SDimitry Andric         Worklist.push_back(std::make_pair(UserMI, Bits));
32506c3fb27SDimitry Andric         break;
32606c3fb27SDimitry Andric       }
32706c3fb27SDimitry Andric     }
32806c3fb27SDimitry Andric   }
32906c3fb27SDimitry Andric 
33006c3fb27SDimitry Andric   return true;
33106c3fb27SDimitry Andric }
33206c3fb27SDimitry Andric 
33306c3fb27SDimitry Andric static bool hasAllWUsers(const MachineInstr &OrigMI, const RISCVSubtarget &ST,
33406c3fb27SDimitry Andric                          const MachineRegisterInfo &MRI) {
33506c3fb27SDimitry Andric   return hasAllNBitUsers(OrigMI, ST, MRI, 32);
33606c3fb27SDimitry Andric }
33706c3fb27SDimitry Andric 
33806c3fb27SDimitry Andric // This function returns true if the machine instruction always outputs a value
33906c3fb27SDimitry Andric // where bits 63:32 match bit 31.
34006c3fb27SDimitry Andric static bool isSignExtendingOpW(const MachineInstr &MI,
34106c3fb27SDimitry Andric                                const MachineRegisterInfo &MRI) {
34206c3fb27SDimitry Andric   uint64_t TSFlags = MI.getDesc().TSFlags;
34306c3fb27SDimitry Andric 
34406c3fb27SDimitry Andric   // Instructions that can be determined from opcode are marked in tablegen.
34506c3fb27SDimitry Andric   if (TSFlags & RISCVII::IsSignExtendingOpWMask)
34606c3fb27SDimitry Andric     return true;
34706c3fb27SDimitry Andric 
34806c3fb27SDimitry Andric   // Special cases that require checking operands.
34906c3fb27SDimitry Andric   switch (MI.getOpcode()) {
35006c3fb27SDimitry Andric   // shifting right sufficiently makes the value 32-bit sign-extended
35106c3fb27SDimitry Andric   case RISCV::SRAI:
35206c3fb27SDimitry Andric     return MI.getOperand(2).getImm() >= 32;
35306c3fb27SDimitry Andric   case RISCV::SRLI:
35406c3fb27SDimitry Andric     return MI.getOperand(2).getImm() > 32;
35506c3fb27SDimitry Andric   // The LI pattern ADDI rd, X0, imm is sign extended.
35606c3fb27SDimitry Andric   case RISCV::ADDI:
35706c3fb27SDimitry Andric     return MI.getOperand(1).isReg() && MI.getOperand(1).getReg() == RISCV::X0;
35806c3fb27SDimitry Andric   // An ANDI with an 11 bit immediate will zero bits 63:11.
35906c3fb27SDimitry Andric   case RISCV::ANDI:
36006c3fb27SDimitry Andric     return isUInt<11>(MI.getOperand(2).getImm());
36106c3fb27SDimitry Andric   // An ORI with an >11 bit immediate (negative 12-bit) will set bits 63:11.
36206c3fb27SDimitry Andric   case RISCV::ORI:
36306c3fb27SDimitry Andric     return !isUInt<11>(MI.getOperand(2).getImm());
3645f757f3fSDimitry Andric   // A bseti with X0 is sign extended if the immediate is less than 31.
3655f757f3fSDimitry Andric   case RISCV::BSETI:
3665f757f3fSDimitry Andric     return MI.getOperand(2).getImm() < 31 &&
3675f757f3fSDimitry Andric            MI.getOperand(1).getReg() == RISCV::X0;
36806c3fb27SDimitry Andric   // Copying from X0 produces zero.
36906c3fb27SDimitry Andric   case RISCV::COPY:
37006c3fb27SDimitry Andric     return MI.getOperand(1).getReg() == RISCV::X0;
3715f757f3fSDimitry Andric   case RISCV::PseudoAtomicLoadNand32:
3725f757f3fSDimitry Andric     return true;
3735f757f3fSDimitry Andric   case RISCV::PseudoVMV_X_S_MF8:
3745f757f3fSDimitry Andric   case RISCV::PseudoVMV_X_S_MF4:
3755f757f3fSDimitry Andric   case RISCV::PseudoVMV_X_S_MF2:
3765f757f3fSDimitry Andric   case RISCV::PseudoVMV_X_S_M1:
3775f757f3fSDimitry Andric   case RISCV::PseudoVMV_X_S_M2:
3785f757f3fSDimitry Andric   case RISCV::PseudoVMV_X_S_M4:
3795f757f3fSDimitry Andric   case RISCV::PseudoVMV_X_S_M8: {
3805f757f3fSDimitry Andric     // vmv.x.s has at least 33 sign bits if log2(sew) <= 5.
3815f757f3fSDimitry Andric     int64_t Log2SEW = MI.getOperand(2).getImm();
3825f757f3fSDimitry Andric     assert(Log2SEW >= 3 && Log2SEW <= 6 && "Unexpected Log2SEW");
3835f757f3fSDimitry Andric     return Log2SEW <= 5;
3845f757f3fSDimitry Andric   }
38506c3fb27SDimitry Andric   }
38606c3fb27SDimitry Andric 
38706c3fb27SDimitry Andric   return false;
38806c3fb27SDimitry Andric }
38906c3fb27SDimitry Andric 
39006c3fb27SDimitry Andric static bool isSignExtendedW(Register SrcReg, const RISCVSubtarget &ST,
39106c3fb27SDimitry Andric                             const MachineRegisterInfo &MRI,
39206c3fb27SDimitry Andric                             SmallPtrSetImpl<MachineInstr *> &FixableDef) {
39306c3fb27SDimitry Andric 
39406c3fb27SDimitry Andric   SmallPtrSet<const MachineInstr *, 4> Visited;
39506c3fb27SDimitry Andric   SmallVector<MachineInstr *, 4> Worklist;
39606c3fb27SDimitry Andric 
39706c3fb27SDimitry Andric   auto AddRegDefToWorkList = [&](Register SrcReg) {
39806c3fb27SDimitry Andric     if (!SrcReg.isVirtual())
39906c3fb27SDimitry Andric       return false;
40006c3fb27SDimitry Andric     MachineInstr *SrcMI = MRI.getVRegDef(SrcReg);
40106c3fb27SDimitry Andric     if (!SrcMI)
40206c3fb27SDimitry Andric       return false;
4035f757f3fSDimitry Andric     // Code assumes the register is operand 0.
4045f757f3fSDimitry Andric     // TODO: Maybe the worklist should store register?
4055f757f3fSDimitry Andric     if (!SrcMI->getOperand(0).isReg() ||
4065f757f3fSDimitry Andric         SrcMI->getOperand(0).getReg() != SrcReg)
4075f757f3fSDimitry Andric       return false;
40806c3fb27SDimitry Andric     // Add SrcMI to the worklist.
40906c3fb27SDimitry Andric     Worklist.push_back(SrcMI);
41006c3fb27SDimitry Andric     return true;
41106c3fb27SDimitry Andric   };
41206c3fb27SDimitry Andric 
41306c3fb27SDimitry Andric   if (!AddRegDefToWorkList(SrcReg))
41406c3fb27SDimitry Andric     return false;
41506c3fb27SDimitry Andric 
41606c3fb27SDimitry Andric   while (!Worklist.empty()) {
41706c3fb27SDimitry Andric     MachineInstr *MI = Worklist.pop_back_val();
41806c3fb27SDimitry Andric 
41906c3fb27SDimitry Andric     // If we already visited this instruction, we don't need to check it again.
42006c3fb27SDimitry Andric     if (!Visited.insert(MI).second)
42106c3fb27SDimitry Andric       continue;
42206c3fb27SDimitry Andric 
42306c3fb27SDimitry Andric     // If this is a sign extending operation we don't need to look any further.
42406c3fb27SDimitry Andric     if (isSignExtendingOpW(*MI, MRI))
42506c3fb27SDimitry Andric       continue;
42606c3fb27SDimitry Andric 
42706c3fb27SDimitry Andric     // Is this an instruction that propagates sign extend?
42806c3fb27SDimitry Andric     switch (MI->getOpcode()) {
42906c3fb27SDimitry Andric     default:
43006c3fb27SDimitry Andric       // Unknown opcode, give up.
43106c3fb27SDimitry Andric       return false;
43206c3fb27SDimitry Andric     case RISCV::COPY: {
43306c3fb27SDimitry Andric       const MachineFunction *MF = MI->getMF();
43406c3fb27SDimitry Andric       const RISCVMachineFunctionInfo *RVFI =
43506c3fb27SDimitry Andric           MF->getInfo<RISCVMachineFunctionInfo>();
43606c3fb27SDimitry Andric 
43706c3fb27SDimitry Andric       // If this is the entry block and the register is livein, see if we know
43806c3fb27SDimitry Andric       // it is sign extended.
43906c3fb27SDimitry Andric       if (MI->getParent() == &MF->front()) {
44006c3fb27SDimitry Andric         Register VReg = MI->getOperand(0).getReg();
44106c3fb27SDimitry Andric         if (MF->getRegInfo().isLiveIn(VReg) && RVFI->isSExt32Register(VReg))
44206c3fb27SDimitry Andric           continue;
44306c3fb27SDimitry Andric       }
44406c3fb27SDimitry Andric 
44506c3fb27SDimitry Andric       Register CopySrcReg = MI->getOperand(1).getReg();
44606c3fb27SDimitry Andric       if (CopySrcReg == RISCV::X10) {
44706c3fb27SDimitry Andric         // For a method return value, we check the ZExt/SExt flags in attribute.
44806c3fb27SDimitry Andric         // We assume the following code sequence for method call.
44906c3fb27SDimitry Andric         // PseudoCALL @bar, ...
45006c3fb27SDimitry Andric         // ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
45106c3fb27SDimitry Andric         // %0:gpr = COPY $x10
45206c3fb27SDimitry Andric         //
45306c3fb27SDimitry Andric         // We use the PseudoCall to look up the IR function being called to find
45406c3fb27SDimitry Andric         // its return attributes.
45506c3fb27SDimitry Andric         const MachineBasicBlock *MBB = MI->getParent();
45606c3fb27SDimitry Andric         auto II = MI->getIterator();
45706c3fb27SDimitry Andric         if (II == MBB->instr_begin() ||
45806c3fb27SDimitry Andric             (--II)->getOpcode() != RISCV::ADJCALLSTACKUP)
45906c3fb27SDimitry Andric           return false;
46006c3fb27SDimitry Andric 
46106c3fb27SDimitry Andric         const MachineInstr &CallMI = *(--II);
46206c3fb27SDimitry Andric         if (!CallMI.isCall() || !CallMI.getOperand(0).isGlobal())
46306c3fb27SDimitry Andric           return false;
46406c3fb27SDimitry Andric 
46506c3fb27SDimitry Andric         auto *CalleeFn =
46606c3fb27SDimitry Andric             dyn_cast_if_present<Function>(CallMI.getOperand(0).getGlobal());
46706c3fb27SDimitry Andric         if (!CalleeFn)
46806c3fb27SDimitry Andric           return false;
46906c3fb27SDimitry Andric 
47006c3fb27SDimitry Andric         auto *IntTy = dyn_cast<IntegerType>(CalleeFn->getReturnType());
47106c3fb27SDimitry Andric         if (!IntTy)
47206c3fb27SDimitry Andric           return false;
47306c3fb27SDimitry Andric 
47406c3fb27SDimitry Andric         const AttributeSet &Attrs = CalleeFn->getAttributes().getRetAttrs();
47506c3fb27SDimitry Andric         unsigned BitWidth = IntTy->getBitWidth();
47606c3fb27SDimitry Andric         if ((BitWidth <= 32 && Attrs.hasAttribute(Attribute::SExt)) ||
47706c3fb27SDimitry Andric             (BitWidth < 32 && Attrs.hasAttribute(Attribute::ZExt)))
47806c3fb27SDimitry Andric           continue;
47906c3fb27SDimitry Andric       }
48006c3fb27SDimitry Andric 
48106c3fb27SDimitry Andric       if (!AddRegDefToWorkList(CopySrcReg))
48206c3fb27SDimitry Andric         return false;
48306c3fb27SDimitry Andric 
48406c3fb27SDimitry Andric       break;
48506c3fb27SDimitry Andric     }
48606c3fb27SDimitry Andric 
48706c3fb27SDimitry Andric     // For these, we just need to check if the 1st operand is sign extended.
48806c3fb27SDimitry Andric     case RISCV::BCLRI:
48906c3fb27SDimitry Andric     case RISCV::BINVI:
49006c3fb27SDimitry Andric     case RISCV::BSETI:
49106c3fb27SDimitry Andric       if (MI->getOperand(2).getImm() >= 31)
49206c3fb27SDimitry Andric         return false;
49306c3fb27SDimitry Andric       [[fallthrough]];
49406c3fb27SDimitry Andric     case RISCV::REM:
49506c3fb27SDimitry Andric     case RISCV::ANDI:
49606c3fb27SDimitry Andric     case RISCV::ORI:
49706c3fb27SDimitry Andric     case RISCV::XORI:
49806c3fb27SDimitry Andric       // |Remainder| is always <= |Dividend|. If D is 32-bit, then so is R.
49906c3fb27SDimitry Andric       // DIV doesn't work because of the edge case 0xf..f 8000 0000 / (long)-1
50006c3fb27SDimitry Andric       // Logical operations use a sign extended 12-bit immediate.
50106c3fb27SDimitry Andric       if (!AddRegDefToWorkList(MI->getOperand(1).getReg()))
50206c3fb27SDimitry Andric         return false;
50306c3fb27SDimitry Andric 
50406c3fb27SDimitry Andric       break;
50506c3fb27SDimitry Andric     case RISCV::PseudoCCADDW:
5065f757f3fSDimitry Andric     case RISCV::PseudoCCADDIW:
50706c3fb27SDimitry Andric     case RISCV::PseudoCCSUBW:
5085f757f3fSDimitry Andric     case RISCV::PseudoCCSLLW:
5095f757f3fSDimitry Andric     case RISCV::PseudoCCSRLW:
5105f757f3fSDimitry Andric     case RISCV::PseudoCCSRAW:
5115f757f3fSDimitry Andric     case RISCV::PseudoCCSLLIW:
5125f757f3fSDimitry Andric     case RISCV::PseudoCCSRLIW:
5135f757f3fSDimitry Andric     case RISCV::PseudoCCSRAIW:
5145f757f3fSDimitry Andric       // Returns operand 4 or an ADDW/SUBW/etc. of operands 5 and 6. We only
5155f757f3fSDimitry Andric       // need to check if operand 4 is sign extended.
51606c3fb27SDimitry Andric       if (!AddRegDefToWorkList(MI->getOperand(4).getReg()))
51706c3fb27SDimitry Andric         return false;
51806c3fb27SDimitry Andric       break;
51906c3fb27SDimitry Andric     case RISCV::REMU:
52006c3fb27SDimitry Andric     case RISCV::AND:
52106c3fb27SDimitry Andric     case RISCV::OR:
52206c3fb27SDimitry Andric     case RISCV::XOR:
52306c3fb27SDimitry Andric     case RISCV::ANDN:
52406c3fb27SDimitry Andric     case RISCV::ORN:
52506c3fb27SDimitry Andric     case RISCV::XNOR:
52606c3fb27SDimitry Andric     case RISCV::MAX:
52706c3fb27SDimitry Andric     case RISCV::MAXU:
52806c3fb27SDimitry Andric     case RISCV::MIN:
52906c3fb27SDimitry Andric     case RISCV::MINU:
53006c3fb27SDimitry Andric     case RISCV::PseudoCCMOVGPR:
53106c3fb27SDimitry Andric     case RISCV::PseudoCCAND:
53206c3fb27SDimitry Andric     case RISCV::PseudoCCOR:
53306c3fb27SDimitry Andric     case RISCV::PseudoCCXOR:
53406c3fb27SDimitry Andric     case RISCV::PHI: {
53506c3fb27SDimitry Andric       // If all incoming values are sign-extended, the output of AND, OR, XOR,
53606c3fb27SDimitry Andric       // MIN, MAX, or PHI is also sign-extended.
53706c3fb27SDimitry Andric 
53806c3fb27SDimitry Andric       // The input registers for PHI are operand 1, 3, ...
53906c3fb27SDimitry Andric       // The input registers for PseudoCCMOVGPR are 4 and 5.
54006c3fb27SDimitry Andric       // The input registers for PseudoCCAND/OR/XOR are 4, 5, and 6.
54106c3fb27SDimitry Andric       // The input registers for others are operand 1 and 2.
54206c3fb27SDimitry Andric       unsigned B = 1, E = 3, D = 1;
54306c3fb27SDimitry Andric       switch (MI->getOpcode()) {
54406c3fb27SDimitry Andric       case RISCV::PHI:
54506c3fb27SDimitry Andric         E = MI->getNumOperands();
54606c3fb27SDimitry Andric         D = 2;
54706c3fb27SDimitry Andric         break;
54806c3fb27SDimitry Andric       case RISCV::PseudoCCMOVGPR:
54906c3fb27SDimitry Andric         B = 4;
55006c3fb27SDimitry Andric         E = 6;
55106c3fb27SDimitry Andric         break;
55206c3fb27SDimitry Andric       case RISCV::PseudoCCAND:
55306c3fb27SDimitry Andric       case RISCV::PseudoCCOR:
55406c3fb27SDimitry Andric       case RISCV::PseudoCCXOR:
55506c3fb27SDimitry Andric         B = 4;
55606c3fb27SDimitry Andric         E = 7;
55706c3fb27SDimitry Andric         break;
55806c3fb27SDimitry Andric        }
55906c3fb27SDimitry Andric 
56006c3fb27SDimitry Andric       for (unsigned I = B; I != E; I += D) {
56106c3fb27SDimitry Andric         if (!MI->getOperand(I).isReg())
56206c3fb27SDimitry Andric           return false;
56306c3fb27SDimitry Andric 
56406c3fb27SDimitry Andric         if (!AddRegDefToWorkList(MI->getOperand(I).getReg()))
56506c3fb27SDimitry Andric           return false;
56606c3fb27SDimitry Andric       }
56706c3fb27SDimitry Andric 
56806c3fb27SDimitry Andric       break;
56906c3fb27SDimitry Andric     }
57006c3fb27SDimitry Andric 
5715f757f3fSDimitry Andric     case RISCV::CZERO_EQZ:
5725f757f3fSDimitry Andric     case RISCV::CZERO_NEZ:
57306c3fb27SDimitry Andric     case RISCV::VT_MASKC:
57406c3fb27SDimitry Andric     case RISCV::VT_MASKCN:
57506c3fb27SDimitry Andric       // Instructions return zero or operand 1. Result is sign extended if
57606c3fb27SDimitry Andric       // operand 1 is sign extended.
57706c3fb27SDimitry Andric       if (!AddRegDefToWorkList(MI->getOperand(1).getReg()))
57806c3fb27SDimitry Andric         return false;
57906c3fb27SDimitry Andric       break;
58006c3fb27SDimitry Andric 
58106c3fb27SDimitry Andric     // With these opcode, we can "fix" them with the W-version
58206c3fb27SDimitry Andric     // if we know all users of the result only rely on bits 31:0
58306c3fb27SDimitry Andric     case RISCV::SLLI:
58406c3fb27SDimitry Andric       // SLLIW reads the lowest 5 bits, while SLLI reads lowest 6 bits
58506c3fb27SDimitry Andric       if (MI->getOperand(2).getImm() >= 32)
58606c3fb27SDimitry Andric         return false;
58706c3fb27SDimitry Andric       [[fallthrough]];
58806c3fb27SDimitry Andric     case RISCV::ADDI:
58906c3fb27SDimitry Andric     case RISCV::ADD:
59006c3fb27SDimitry Andric     case RISCV::LD:
59106c3fb27SDimitry Andric     case RISCV::LWU:
59206c3fb27SDimitry Andric     case RISCV::MUL:
59306c3fb27SDimitry Andric     case RISCV::SUB:
59406c3fb27SDimitry Andric       if (hasAllWUsers(*MI, ST, MRI)) {
59506c3fb27SDimitry Andric         FixableDef.insert(MI);
59606c3fb27SDimitry Andric         break;
59706c3fb27SDimitry Andric       }
59806c3fb27SDimitry Andric       return false;
59906c3fb27SDimitry Andric     }
60006c3fb27SDimitry Andric   }
60106c3fb27SDimitry Andric 
60206c3fb27SDimitry Andric   // If we get here, then every node we visited produces a sign extended value
60306c3fb27SDimitry Andric   // or propagated sign extended values. So the result must be sign extended.
60406c3fb27SDimitry Andric   return true;
60506c3fb27SDimitry Andric }
60606c3fb27SDimitry Andric 
60706c3fb27SDimitry Andric static unsigned getWOp(unsigned Opcode) {
60806c3fb27SDimitry Andric   switch (Opcode) {
60906c3fb27SDimitry Andric   case RISCV::ADDI:
61006c3fb27SDimitry Andric     return RISCV::ADDIW;
61106c3fb27SDimitry Andric   case RISCV::ADD:
61206c3fb27SDimitry Andric     return RISCV::ADDW;
61306c3fb27SDimitry Andric   case RISCV::LD:
61406c3fb27SDimitry Andric   case RISCV::LWU:
61506c3fb27SDimitry Andric     return RISCV::LW;
61606c3fb27SDimitry Andric   case RISCV::MUL:
61706c3fb27SDimitry Andric     return RISCV::MULW;
61806c3fb27SDimitry Andric   case RISCV::SLLI:
61906c3fb27SDimitry Andric     return RISCV::SLLIW;
62006c3fb27SDimitry Andric   case RISCV::SUB:
62106c3fb27SDimitry Andric     return RISCV::SUBW;
62206c3fb27SDimitry Andric   default:
62306c3fb27SDimitry Andric     llvm_unreachable("Unexpected opcode for replacement with W variant");
62406c3fb27SDimitry Andric   }
62506c3fb27SDimitry Andric }
62606c3fb27SDimitry Andric 
62706c3fb27SDimitry Andric bool RISCVOptWInstrs::removeSExtWInstrs(MachineFunction &MF,
62806c3fb27SDimitry Andric                                         const RISCVInstrInfo &TII,
62906c3fb27SDimitry Andric                                         const RISCVSubtarget &ST,
63006c3fb27SDimitry Andric                                         MachineRegisterInfo &MRI) {
63106c3fb27SDimitry Andric   if (DisableSExtWRemoval)
63206c3fb27SDimitry Andric     return false;
63306c3fb27SDimitry Andric 
63406c3fb27SDimitry Andric   bool MadeChange = false;
63506c3fb27SDimitry Andric   for (MachineBasicBlock &MBB : MF) {
6365f757f3fSDimitry Andric     for (MachineInstr &MI : llvm::make_early_inc_range(MBB)) {
63706c3fb27SDimitry Andric       // We're looking for the sext.w pattern ADDIW rd, rs1, 0.
6385f757f3fSDimitry Andric       if (!RISCV::isSEXT_W(MI))
63906c3fb27SDimitry Andric         continue;
64006c3fb27SDimitry Andric 
6415f757f3fSDimitry Andric       Register SrcReg = MI.getOperand(1).getReg();
64206c3fb27SDimitry Andric 
64306c3fb27SDimitry Andric       SmallPtrSet<MachineInstr *, 4> FixableDefs;
64406c3fb27SDimitry Andric 
64506c3fb27SDimitry Andric       // If all users only use the lower bits, this sext.w is redundant.
64606c3fb27SDimitry Andric       // Or if all definitions reaching MI sign-extend their output,
64706c3fb27SDimitry Andric       // then sext.w is redundant.
6485f757f3fSDimitry Andric       if (!hasAllWUsers(MI, ST, MRI) &&
64906c3fb27SDimitry Andric           !isSignExtendedW(SrcReg, ST, MRI, FixableDefs))
65006c3fb27SDimitry Andric         continue;
65106c3fb27SDimitry Andric 
6525f757f3fSDimitry Andric       Register DstReg = MI.getOperand(0).getReg();
65306c3fb27SDimitry Andric       if (!MRI.constrainRegClass(SrcReg, MRI.getRegClass(DstReg)))
65406c3fb27SDimitry Andric         continue;
65506c3fb27SDimitry Andric 
65606c3fb27SDimitry Andric       // Convert Fixable instructions to their W versions.
65706c3fb27SDimitry Andric       for (MachineInstr *Fixable : FixableDefs) {
65806c3fb27SDimitry Andric         LLVM_DEBUG(dbgs() << "Replacing " << *Fixable);
65906c3fb27SDimitry Andric         Fixable->setDesc(TII.get(getWOp(Fixable->getOpcode())));
66006c3fb27SDimitry Andric         Fixable->clearFlag(MachineInstr::MIFlag::NoSWrap);
66106c3fb27SDimitry Andric         Fixable->clearFlag(MachineInstr::MIFlag::NoUWrap);
66206c3fb27SDimitry Andric         Fixable->clearFlag(MachineInstr::MIFlag::IsExact);
66306c3fb27SDimitry Andric         LLVM_DEBUG(dbgs() << "     with " << *Fixable);
66406c3fb27SDimitry Andric         ++NumTransformedToWInstrs;
66506c3fb27SDimitry Andric       }
66606c3fb27SDimitry Andric 
66706c3fb27SDimitry Andric       LLVM_DEBUG(dbgs() << "Removing redundant sign-extension\n");
66806c3fb27SDimitry Andric       MRI.replaceRegWith(DstReg, SrcReg);
66906c3fb27SDimitry Andric       MRI.clearKillFlags(SrcReg);
6705f757f3fSDimitry Andric       MI.eraseFromParent();
67106c3fb27SDimitry Andric       ++NumRemovedSExtW;
67206c3fb27SDimitry Andric       MadeChange = true;
67306c3fb27SDimitry Andric     }
67406c3fb27SDimitry Andric   }
67506c3fb27SDimitry Andric 
67606c3fb27SDimitry Andric   return MadeChange;
67706c3fb27SDimitry Andric }
67806c3fb27SDimitry Andric 
67906c3fb27SDimitry Andric bool RISCVOptWInstrs::stripWSuffixes(MachineFunction &MF,
68006c3fb27SDimitry Andric                                      const RISCVInstrInfo &TII,
68106c3fb27SDimitry Andric                                      const RISCVSubtarget &ST,
68206c3fb27SDimitry Andric                                      MachineRegisterInfo &MRI) {
68306c3fb27SDimitry Andric   if (DisableStripWSuffix)
68406c3fb27SDimitry Andric     return false;
68506c3fb27SDimitry Andric 
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 
70906c3fb27SDimitry Andric bool RISCVOptWInstrs::runOnMachineFunction(MachineFunction &MF) {
71006c3fb27SDimitry Andric   if (skipFunction(MF.getFunction()))
71106c3fb27SDimitry Andric     return false;
71206c3fb27SDimitry Andric 
71306c3fb27SDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
71406c3fb27SDimitry Andric   const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>();
71506c3fb27SDimitry Andric   const RISCVInstrInfo &TII = *ST.getInstrInfo();
71606c3fb27SDimitry Andric 
71706c3fb27SDimitry Andric   if (!ST.is64Bit())
71806c3fb27SDimitry Andric     return false;
71906c3fb27SDimitry Andric 
72006c3fb27SDimitry Andric   bool MadeChange = false;
72106c3fb27SDimitry Andric   MadeChange |= removeSExtWInstrs(MF, TII, ST, MRI);
72206c3fb27SDimitry Andric   MadeChange |= stripWSuffixes(MF, TII, ST, MRI);
72306c3fb27SDimitry Andric 
72406c3fb27SDimitry Andric   return MadeChange;
72506c3fb27SDimitry Andric }
726