xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVOptWInstrs.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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*5f757f3fSDimitry Andric // Then it removes the -w suffix from opw instructions whenever all users are
16*5f757f3fSDimitry Andric // dependent only on the lower word of the result of the instruction.
17*5f757f3fSDimitry Andric // The cases handled are:
18*5f757f3fSDimitry Andric // * addw because c.add has a larger register encoding than c.addw.
19*5f757f3fSDimitry Andric // * addiw because it helps reduce test differences between RV32 and RV64
20*5f757f3fSDimitry Andric //   w/o being a pessimization.
21*5f757f3fSDimitry Andric // * mulw because c.mulw doesn't exist but c.mul does (w/ zcb)
22*5f757f3fSDimitry 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"
29*5f757f3fSDimitry 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 
56*5f757f3fSDimitry 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 
82*5f757f3fSDimitry Andric static bool vectorPseudoHasAllNBitUsers(const MachineOperand &UserOp,
83*5f757f3fSDimitry Andric                                         unsigned Bits) {
84*5f757f3fSDimitry Andric   const MachineInstr &MI = *UserOp.getParent();
85*5f757f3fSDimitry Andric   unsigned MCOpcode = RISCV::getRVVMCOpcode(MI.getOpcode());
86*5f757f3fSDimitry Andric 
87*5f757f3fSDimitry Andric   if (!MCOpcode)
88*5f757f3fSDimitry Andric     return false;
89*5f757f3fSDimitry Andric 
90*5f757f3fSDimitry Andric   const MCInstrDesc &MCID = MI.getDesc();
91*5f757f3fSDimitry Andric   const uint64_t TSFlags = MCID.TSFlags;
92*5f757f3fSDimitry Andric   if (!RISCVII::hasSEWOp(TSFlags))
93*5f757f3fSDimitry Andric     return false;
94*5f757f3fSDimitry Andric   assert(RISCVII::hasVLOp(TSFlags));
95*5f757f3fSDimitry Andric   const unsigned Log2SEW = MI.getOperand(RISCVII::getSEWOpNum(MCID)).getImm();
96*5f757f3fSDimitry Andric 
97*5f757f3fSDimitry Andric   if (UserOp.getOperandNo() == RISCVII::getVLOpNum(MCID))
98*5f757f3fSDimitry Andric     return false;
99*5f757f3fSDimitry Andric 
100*5f757f3fSDimitry Andric   auto NumDemandedBits =
101*5f757f3fSDimitry Andric       RISCV::getVectorLowDemandedScalarBits(MCOpcode, Log2SEW);
102*5f757f3fSDimitry Andric   return NumDemandedBits && Bits >= *NumDemandedBits;
103*5f757f3fSDimitry Andric }
104*5f757f3fSDimitry 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*5f757f3fSDimitry Andric     for (auto &UserOp : MRI.use_nodbg_operands(MI->getOperand(0).getReg())) {
13006c3fb27SDimitry Andric       const MachineInstr *UserMI = UserOp.getParent();
13106c3fb27SDimitry Andric       unsigned OpIdx = UserOp.getOperandNo();
13206c3fb27SDimitry Andric 
13306c3fb27SDimitry Andric       switch (UserMI->getOpcode()) {
13406c3fb27SDimitry Andric       default:
135*5f757f3fSDimitry Andric         if (vectorPseudoHasAllNBitUsers(UserOp, Bits))
136*5f757f3fSDimitry Andric           break;
13706c3fb27SDimitry Andric         return false;
13806c3fb27SDimitry Andric 
13906c3fb27SDimitry Andric       case RISCV::ADDIW:
14006c3fb27SDimitry Andric       case RISCV::ADDW:
14106c3fb27SDimitry Andric       case RISCV::DIVUW:
14206c3fb27SDimitry Andric       case RISCV::DIVW:
14306c3fb27SDimitry Andric       case RISCV::MULW:
14406c3fb27SDimitry Andric       case RISCV::REMUW:
14506c3fb27SDimitry Andric       case RISCV::REMW:
14606c3fb27SDimitry Andric       case RISCV::SLLIW:
14706c3fb27SDimitry Andric       case RISCV::SLLW:
14806c3fb27SDimitry Andric       case RISCV::SRAIW:
14906c3fb27SDimitry Andric       case RISCV::SRAW:
15006c3fb27SDimitry Andric       case RISCV::SRLIW:
15106c3fb27SDimitry Andric       case RISCV::SRLW:
15206c3fb27SDimitry Andric       case RISCV::SUBW:
15306c3fb27SDimitry Andric       case RISCV::ROLW:
15406c3fb27SDimitry Andric       case RISCV::RORW:
15506c3fb27SDimitry Andric       case RISCV::RORIW:
15606c3fb27SDimitry Andric       case RISCV::CLZW:
15706c3fb27SDimitry Andric       case RISCV::CTZW:
15806c3fb27SDimitry Andric       case RISCV::CPOPW:
15906c3fb27SDimitry Andric       case RISCV::SLLI_UW:
16006c3fb27SDimitry Andric       case RISCV::FMV_W_X:
16106c3fb27SDimitry Andric       case RISCV::FCVT_H_W:
16206c3fb27SDimitry Andric       case RISCV::FCVT_H_WU:
16306c3fb27SDimitry Andric       case RISCV::FCVT_S_W:
16406c3fb27SDimitry Andric       case RISCV::FCVT_S_WU:
16506c3fb27SDimitry Andric       case RISCV::FCVT_D_W:
16606c3fb27SDimitry Andric       case RISCV::FCVT_D_WU:
16706c3fb27SDimitry Andric         if (Bits >= 32)
16806c3fb27SDimitry Andric           break;
16906c3fb27SDimitry Andric         return false;
17006c3fb27SDimitry Andric       case RISCV::SEXT_B:
17106c3fb27SDimitry Andric       case RISCV::PACKH:
17206c3fb27SDimitry Andric         if (Bits >= 8)
17306c3fb27SDimitry Andric           break;
17406c3fb27SDimitry Andric         return false;
17506c3fb27SDimitry Andric       case RISCV::SEXT_H:
17606c3fb27SDimitry Andric       case RISCV::FMV_H_X:
17706c3fb27SDimitry Andric       case RISCV::ZEXT_H_RV32:
17806c3fb27SDimitry Andric       case RISCV::ZEXT_H_RV64:
17906c3fb27SDimitry Andric       case RISCV::PACKW:
18006c3fb27SDimitry Andric         if (Bits >= 16)
18106c3fb27SDimitry Andric           break;
18206c3fb27SDimitry Andric         return false;
18306c3fb27SDimitry Andric 
18406c3fb27SDimitry Andric       case RISCV::PACK:
18506c3fb27SDimitry Andric         if (Bits >= (ST.getXLen() / 2))
18606c3fb27SDimitry Andric           break;
18706c3fb27SDimitry Andric         return false;
18806c3fb27SDimitry Andric 
18906c3fb27SDimitry Andric       case RISCV::SRLI: {
19006c3fb27SDimitry Andric         // If we are shifting right by less than Bits, and users don't demand
19106c3fb27SDimitry Andric         // any bits that were shifted into [Bits-1:0], then we can consider this
19206c3fb27SDimitry Andric         // as an N-Bit user.
19306c3fb27SDimitry Andric         unsigned ShAmt = UserMI->getOperand(2).getImm();
19406c3fb27SDimitry Andric         if (Bits > ShAmt) {
19506c3fb27SDimitry Andric           Worklist.push_back(std::make_pair(UserMI, Bits - ShAmt));
19606c3fb27SDimitry Andric           break;
19706c3fb27SDimitry Andric         }
19806c3fb27SDimitry Andric         return false;
19906c3fb27SDimitry Andric       }
20006c3fb27SDimitry Andric 
20106c3fb27SDimitry Andric       // these overwrite higher input bits, otherwise the lower word of output
20206c3fb27SDimitry Andric       // depends only on the lower word of input. So check their uses read W.
20306c3fb27SDimitry Andric       case RISCV::SLLI:
20406c3fb27SDimitry Andric         if (Bits >= (ST.getXLen() - UserMI->getOperand(2).getImm()))
20506c3fb27SDimitry Andric           break;
20606c3fb27SDimitry Andric         Worklist.push_back(std::make_pair(UserMI, Bits));
20706c3fb27SDimitry Andric         break;
20806c3fb27SDimitry Andric       case RISCV::ANDI: {
20906c3fb27SDimitry Andric         uint64_t Imm = UserMI->getOperand(2).getImm();
21006c3fb27SDimitry Andric         if (Bits >= (unsigned)llvm::bit_width(Imm))
21106c3fb27SDimitry Andric           break;
21206c3fb27SDimitry Andric         Worklist.push_back(std::make_pair(UserMI, Bits));
21306c3fb27SDimitry Andric         break;
21406c3fb27SDimitry Andric       }
21506c3fb27SDimitry Andric       case RISCV::ORI: {
21606c3fb27SDimitry Andric         uint64_t Imm = UserMI->getOperand(2).getImm();
21706c3fb27SDimitry Andric         if (Bits >= (unsigned)llvm::bit_width<uint64_t>(~Imm))
21806c3fb27SDimitry Andric           break;
21906c3fb27SDimitry Andric         Worklist.push_back(std::make_pair(UserMI, Bits));
22006c3fb27SDimitry Andric         break;
22106c3fb27SDimitry Andric       }
22206c3fb27SDimitry Andric 
22306c3fb27SDimitry Andric       case RISCV::SLL:
22406c3fb27SDimitry Andric       case RISCV::BSET:
22506c3fb27SDimitry Andric       case RISCV::BCLR:
22606c3fb27SDimitry Andric       case RISCV::BINV:
22706c3fb27SDimitry Andric         // Operand 2 is the shift amount which uses log2(xlen) bits.
22806c3fb27SDimitry Andric         if (OpIdx == 2) {
22906c3fb27SDimitry Andric           if (Bits >= Log2_32(ST.getXLen()))
23006c3fb27SDimitry Andric             break;
23106c3fb27SDimitry Andric           return false;
23206c3fb27SDimitry Andric         }
23306c3fb27SDimitry Andric         Worklist.push_back(std::make_pair(UserMI, Bits));
23406c3fb27SDimitry Andric         break;
23506c3fb27SDimitry Andric 
23606c3fb27SDimitry Andric       case RISCV::SRA:
23706c3fb27SDimitry Andric       case RISCV::SRL:
23806c3fb27SDimitry Andric       case RISCV::ROL:
23906c3fb27SDimitry Andric       case RISCV::ROR:
24006c3fb27SDimitry Andric         // Operand 2 is the shift amount which uses 6 bits.
24106c3fb27SDimitry Andric         if (OpIdx == 2 && Bits >= Log2_32(ST.getXLen()))
24206c3fb27SDimitry Andric           break;
24306c3fb27SDimitry Andric         return false;
24406c3fb27SDimitry Andric 
24506c3fb27SDimitry Andric       case RISCV::ADD_UW:
24606c3fb27SDimitry Andric       case RISCV::SH1ADD_UW:
24706c3fb27SDimitry Andric       case RISCV::SH2ADD_UW:
24806c3fb27SDimitry Andric       case RISCV::SH3ADD_UW:
24906c3fb27SDimitry Andric         // Operand 1 is implicitly zero extended.
25006c3fb27SDimitry Andric         if (OpIdx == 1 && Bits >= 32)
25106c3fb27SDimitry Andric           break;
25206c3fb27SDimitry Andric         Worklist.push_back(std::make_pair(UserMI, Bits));
25306c3fb27SDimitry Andric         break;
25406c3fb27SDimitry Andric 
25506c3fb27SDimitry Andric       case RISCV::BEXTI:
25606c3fb27SDimitry Andric         if (UserMI->getOperand(2).getImm() >= Bits)
25706c3fb27SDimitry Andric           return false;
25806c3fb27SDimitry Andric         break;
25906c3fb27SDimitry Andric 
26006c3fb27SDimitry Andric       case RISCV::SB:
26106c3fb27SDimitry Andric         // The first argument is the value to store.
26206c3fb27SDimitry Andric         if (OpIdx == 0 && Bits >= 8)
26306c3fb27SDimitry Andric           break;
26406c3fb27SDimitry Andric         return false;
26506c3fb27SDimitry Andric       case RISCV::SH:
26606c3fb27SDimitry Andric         // The first argument is the value to store.
26706c3fb27SDimitry Andric         if (OpIdx == 0 && Bits >= 16)
26806c3fb27SDimitry Andric           break;
26906c3fb27SDimitry Andric         return false;
27006c3fb27SDimitry Andric       case RISCV::SW:
27106c3fb27SDimitry Andric         // The first argument is the value to store.
27206c3fb27SDimitry Andric         if (OpIdx == 0 && Bits >= 32)
27306c3fb27SDimitry Andric           break;
27406c3fb27SDimitry Andric         return false;
27506c3fb27SDimitry Andric 
27606c3fb27SDimitry Andric       // For these, lower word of output in these operations, depends only on
27706c3fb27SDimitry Andric       // the lower word of input. So, we check all uses only read lower word.
27806c3fb27SDimitry Andric       case RISCV::COPY:
27906c3fb27SDimitry Andric       case RISCV::PHI:
28006c3fb27SDimitry Andric 
28106c3fb27SDimitry Andric       case RISCV::ADD:
28206c3fb27SDimitry Andric       case RISCV::ADDI:
28306c3fb27SDimitry Andric       case RISCV::AND:
28406c3fb27SDimitry Andric       case RISCV::MUL:
28506c3fb27SDimitry Andric       case RISCV::OR:
28606c3fb27SDimitry Andric       case RISCV::SUB:
28706c3fb27SDimitry Andric       case RISCV::XOR:
28806c3fb27SDimitry Andric       case RISCV::XORI:
28906c3fb27SDimitry Andric 
29006c3fb27SDimitry Andric       case RISCV::ANDN:
29106c3fb27SDimitry Andric       case RISCV::BREV8:
29206c3fb27SDimitry Andric       case RISCV::CLMUL:
29306c3fb27SDimitry Andric       case RISCV::ORC_B:
29406c3fb27SDimitry Andric       case RISCV::ORN:
29506c3fb27SDimitry Andric       case RISCV::SH1ADD:
29606c3fb27SDimitry Andric       case RISCV::SH2ADD:
29706c3fb27SDimitry Andric       case RISCV::SH3ADD:
29806c3fb27SDimitry Andric       case RISCV::XNOR:
29906c3fb27SDimitry Andric       case RISCV::BSETI:
30006c3fb27SDimitry Andric       case RISCV::BCLRI:
30106c3fb27SDimitry Andric       case RISCV::BINVI:
30206c3fb27SDimitry Andric         Worklist.push_back(std::make_pair(UserMI, Bits));
30306c3fb27SDimitry Andric         break;
30406c3fb27SDimitry Andric 
30506c3fb27SDimitry Andric       case RISCV::PseudoCCMOVGPR:
30606c3fb27SDimitry Andric         // Either operand 4 or operand 5 is returned by this instruction. If
30706c3fb27SDimitry Andric         // only the lower word of the result is used, then only the lower word
30806c3fb27SDimitry Andric         // of operand 4 and 5 is used.
30906c3fb27SDimitry Andric         if (OpIdx != 4 && OpIdx != 5)
31006c3fb27SDimitry Andric           return false;
31106c3fb27SDimitry Andric         Worklist.push_back(std::make_pair(UserMI, Bits));
31206c3fb27SDimitry Andric         break;
31306c3fb27SDimitry Andric 
314*5f757f3fSDimitry Andric       case RISCV::CZERO_EQZ:
315*5f757f3fSDimitry Andric       case RISCV::CZERO_NEZ:
31606c3fb27SDimitry Andric       case RISCV::VT_MASKC:
31706c3fb27SDimitry Andric       case RISCV::VT_MASKCN:
31806c3fb27SDimitry Andric         if (OpIdx != 1)
31906c3fb27SDimitry Andric           return false;
32006c3fb27SDimitry Andric         Worklist.push_back(std::make_pair(UserMI, Bits));
32106c3fb27SDimitry Andric         break;
32206c3fb27SDimitry Andric       }
32306c3fb27SDimitry Andric     }
32406c3fb27SDimitry Andric   }
32506c3fb27SDimitry Andric 
32606c3fb27SDimitry Andric   return true;
32706c3fb27SDimitry Andric }
32806c3fb27SDimitry Andric 
32906c3fb27SDimitry Andric static bool hasAllWUsers(const MachineInstr &OrigMI, const RISCVSubtarget &ST,
33006c3fb27SDimitry Andric                          const MachineRegisterInfo &MRI) {
33106c3fb27SDimitry Andric   return hasAllNBitUsers(OrigMI, ST, MRI, 32);
33206c3fb27SDimitry Andric }
33306c3fb27SDimitry Andric 
33406c3fb27SDimitry Andric // This function returns true if the machine instruction always outputs a value
33506c3fb27SDimitry Andric // where bits 63:32 match bit 31.
33606c3fb27SDimitry Andric static bool isSignExtendingOpW(const MachineInstr &MI,
33706c3fb27SDimitry Andric                                const MachineRegisterInfo &MRI) {
33806c3fb27SDimitry Andric   uint64_t TSFlags = MI.getDesc().TSFlags;
33906c3fb27SDimitry Andric 
34006c3fb27SDimitry Andric   // Instructions that can be determined from opcode are marked in tablegen.
34106c3fb27SDimitry Andric   if (TSFlags & RISCVII::IsSignExtendingOpWMask)
34206c3fb27SDimitry Andric     return true;
34306c3fb27SDimitry Andric 
34406c3fb27SDimitry Andric   // Special cases that require checking operands.
34506c3fb27SDimitry Andric   switch (MI.getOpcode()) {
34606c3fb27SDimitry Andric   // shifting right sufficiently makes the value 32-bit sign-extended
34706c3fb27SDimitry Andric   case RISCV::SRAI:
34806c3fb27SDimitry Andric     return MI.getOperand(2).getImm() >= 32;
34906c3fb27SDimitry Andric   case RISCV::SRLI:
35006c3fb27SDimitry Andric     return MI.getOperand(2).getImm() > 32;
35106c3fb27SDimitry Andric   // The LI pattern ADDI rd, X0, imm is sign extended.
35206c3fb27SDimitry Andric   case RISCV::ADDI:
35306c3fb27SDimitry Andric     return MI.getOperand(1).isReg() && MI.getOperand(1).getReg() == RISCV::X0;
35406c3fb27SDimitry Andric   // An ANDI with an 11 bit immediate will zero bits 63:11.
35506c3fb27SDimitry Andric   case RISCV::ANDI:
35606c3fb27SDimitry Andric     return isUInt<11>(MI.getOperand(2).getImm());
35706c3fb27SDimitry Andric   // An ORI with an >11 bit immediate (negative 12-bit) will set bits 63:11.
35806c3fb27SDimitry Andric   case RISCV::ORI:
35906c3fb27SDimitry Andric     return !isUInt<11>(MI.getOperand(2).getImm());
360*5f757f3fSDimitry Andric   // A bseti with X0 is sign extended if the immediate is less than 31.
361*5f757f3fSDimitry Andric   case RISCV::BSETI:
362*5f757f3fSDimitry Andric     return MI.getOperand(2).getImm() < 31 &&
363*5f757f3fSDimitry Andric            MI.getOperand(1).getReg() == RISCV::X0;
36406c3fb27SDimitry Andric   // Copying from X0 produces zero.
36506c3fb27SDimitry Andric   case RISCV::COPY:
36606c3fb27SDimitry Andric     return MI.getOperand(1).getReg() == RISCV::X0;
367*5f757f3fSDimitry Andric   case RISCV::PseudoAtomicLoadNand32:
368*5f757f3fSDimitry Andric     return true;
369*5f757f3fSDimitry Andric   case RISCV::PseudoVMV_X_S_MF8:
370*5f757f3fSDimitry Andric   case RISCV::PseudoVMV_X_S_MF4:
371*5f757f3fSDimitry Andric   case RISCV::PseudoVMV_X_S_MF2:
372*5f757f3fSDimitry Andric   case RISCV::PseudoVMV_X_S_M1:
373*5f757f3fSDimitry Andric   case RISCV::PseudoVMV_X_S_M2:
374*5f757f3fSDimitry Andric   case RISCV::PseudoVMV_X_S_M4:
375*5f757f3fSDimitry Andric   case RISCV::PseudoVMV_X_S_M8: {
376*5f757f3fSDimitry Andric     // vmv.x.s has at least 33 sign bits if log2(sew) <= 5.
377*5f757f3fSDimitry Andric     int64_t Log2SEW = MI.getOperand(2).getImm();
378*5f757f3fSDimitry Andric     assert(Log2SEW >= 3 && Log2SEW <= 6 && "Unexpected Log2SEW");
379*5f757f3fSDimitry Andric     return Log2SEW <= 5;
380*5f757f3fSDimitry Andric   }
38106c3fb27SDimitry Andric   }
38206c3fb27SDimitry Andric 
38306c3fb27SDimitry Andric   return false;
38406c3fb27SDimitry Andric }
38506c3fb27SDimitry Andric 
38606c3fb27SDimitry Andric static bool isSignExtendedW(Register SrcReg, const RISCVSubtarget &ST,
38706c3fb27SDimitry Andric                             const MachineRegisterInfo &MRI,
38806c3fb27SDimitry Andric                             SmallPtrSetImpl<MachineInstr *> &FixableDef) {
38906c3fb27SDimitry Andric 
39006c3fb27SDimitry Andric   SmallPtrSet<const MachineInstr *, 4> Visited;
39106c3fb27SDimitry Andric   SmallVector<MachineInstr *, 4> Worklist;
39206c3fb27SDimitry Andric 
39306c3fb27SDimitry Andric   auto AddRegDefToWorkList = [&](Register SrcReg) {
39406c3fb27SDimitry Andric     if (!SrcReg.isVirtual())
39506c3fb27SDimitry Andric       return false;
39606c3fb27SDimitry Andric     MachineInstr *SrcMI = MRI.getVRegDef(SrcReg);
39706c3fb27SDimitry Andric     if (!SrcMI)
39806c3fb27SDimitry Andric       return false;
399*5f757f3fSDimitry Andric     // Code assumes the register is operand 0.
400*5f757f3fSDimitry Andric     // TODO: Maybe the worklist should store register?
401*5f757f3fSDimitry Andric     if (!SrcMI->getOperand(0).isReg() ||
402*5f757f3fSDimitry Andric         SrcMI->getOperand(0).getReg() != SrcReg)
403*5f757f3fSDimitry Andric       return false;
40406c3fb27SDimitry Andric     // Add SrcMI to the worklist.
40506c3fb27SDimitry Andric     Worklist.push_back(SrcMI);
40606c3fb27SDimitry Andric     return true;
40706c3fb27SDimitry Andric   };
40806c3fb27SDimitry Andric 
40906c3fb27SDimitry Andric   if (!AddRegDefToWorkList(SrcReg))
41006c3fb27SDimitry Andric     return false;
41106c3fb27SDimitry Andric 
41206c3fb27SDimitry Andric   while (!Worklist.empty()) {
41306c3fb27SDimitry Andric     MachineInstr *MI = Worklist.pop_back_val();
41406c3fb27SDimitry Andric 
41506c3fb27SDimitry Andric     // If we already visited this instruction, we don't need to check it again.
41606c3fb27SDimitry Andric     if (!Visited.insert(MI).second)
41706c3fb27SDimitry Andric       continue;
41806c3fb27SDimitry Andric 
41906c3fb27SDimitry Andric     // If this is a sign extending operation we don't need to look any further.
42006c3fb27SDimitry Andric     if (isSignExtendingOpW(*MI, MRI))
42106c3fb27SDimitry Andric       continue;
42206c3fb27SDimitry Andric 
42306c3fb27SDimitry Andric     // Is this an instruction that propagates sign extend?
42406c3fb27SDimitry Andric     switch (MI->getOpcode()) {
42506c3fb27SDimitry Andric     default:
42606c3fb27SDimitry Andric       // Unknown opcode, give up.
42706c3fb27SDimitry Andric       return false;
42806c3fb27SDimitry Andric     case RISCV::COPY: {
42906c3fb27SDimitry Andric       const MachineFunction *MF = MI->getMF();
43006c3fb27SDimitry Andric       const RISCVMachineFunctionInfo *RVFI =
43106c3fb27SDimitry Andric           MF->getInfo<RISCVMachineFunctionInfo>();
43206c3fb27SDimitry Andric 
43306c3fb27SDimitry Andric       // If this is the entry block and the register is livein, see if we know
43406c3fb27SDimitry Andric       // it is sign extended.
43506c3fb27SDimitry Andric       if (MI->getParent() == &MF->front()) {
43606c3fb27SDimitry Andric         Register VReg = MI->getOperand(0).getReg();
43706c3fb27SDimitry Andric         if (MF->getRegInfo().isLiveIn(VReg) && RVFI->isSExt32Register(VReg))
43806c3fb27SDimitry Andric           continue;
43906c3fb27SDimitry Andric       }
44006c3fb27SDimitry Andric 
44106c3fb27SDimitry Andric       Register CopySrcReg = MI->getOperand(1).getReg();
44206c3fb27SDimitry Andric       if (CopySrcReg == RISCV::X10) {
44306c3fb27SDimitry Andric         // For a method return value, we check the ZExt/SExt flags in attribute.
44406c3fb27SDimitry Andric         // We assume the following code sequence for method call.
44506c3fb27SDimitry Andric         // PseudoCALL @bar, ...
44606c3fb27SDimitry Andric         // ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2
44706c3fb27SDimitry Andric         // %0:gpr = COPY $x10
44806c3fb27SDimitry Andric         //
44906c3fb27SDimitry Andric         // We use the PseudoCall to look up the IR function being called to find
45006c3fb27SDimitry Andric         // its return attributes.
45106c3fb27SDimitry Andric         const MachineBasicBlock *MBB = MI->getParent();
45206c3fb27SDimitry Andric         auto II = MI->getIterator();
45306c3fb27SDimitry Andric         if (II == MBB->instr_begin() ||
45406c3fb27SDimitry Andric             (--II)->getOpcode() != RISCV::ADJCALLSTACKUP)
45506c3fb27SDimitry Andric           return false;
45606c3fb27SDimitry Andric 
45706c3fb27SDimitry Andric         const MachineInstr &CallMI = *(--II);
45806c3fb27SDimitry Andric         if (!CallMI.isCall() || !CallMI.getOperand(0).isGlobal())
45906c3fb27SDimitry Andric           return false;
46006c3fb27SDimitry Andric 
46106c3fb27SDimitry Andric         auto *CalleeFn =
46206c3fb27SDimitry Andric             dyn_cast_if_present<Function>(CallMI.getOperand(0).getGlobal());
46306c3fb27SDimitry Andric         if (!CalleeFn)
46406c3fb27SDimitry Andric           return false;
46506c3fb27SDimitry Andric 
46606c3fb27SDimitry Andric         auto *IntTy = dyn_cast<IntegerType>(CalleeFn->getReturnType());
46706c3fb27SDimitry Andric         if (!IntTy)
46806c3fb27SDimitry Andric           return false;
46906c3fb27SDimitry Andric 
47006c3fb27SDimitry Andric         const AttributeSet &Attrs = CalleeFn->getAttributes().getRetAttrs();
47106c3fb27SDimitry Andric         unsigned BitWidth = IntTy->getBitWidth();
47206c3fb27SDimitry Andric         if ((BitWidth <= 32 && Attrs.hasAttribute(Attribute::SExt)) ||
47306c3fb27SDimitry Andric             (BitWidth < 32 && Attrs.hasAttribute(Attribute::ZExt)))
47406c3fb27SDimitry Andric           continue;
47506c3fb27SDimitry Andric       }
47606c3fb27SDimitry Andric 
47706c3fb27SDimitry Andric       if (!AddRegDefToWorkList(CopySrcReg))
47806c3fb27SDimitry Andric         return false;
47906c3fb27SDimitry Andric 
48006c3fb27SDimitry Andric       break;
48106c3fb27SDimitry Andric     }
48206c3fb27SDimitry Andric 
48306c3fb27SDimitry Andric     // For these, we just need to check if the 1st operand is sign extended.
48406c3fb27SDimitry Andric     case RISCV::BCLRI:
48506c3fb27SDimitry Andric     case RISCV::BINVI:
48606c3fb27SDimitry Andric     case RISCV::BSETI:
48706c3fb27SDimitry Andric       if (MI->getOperand(2).getImm() >= 31)
48806c3fb27SDimitry Andric         return false;
48906c3fb27SDimitry Andric       [[fallthrough]];
49006c3fb27SDimitry Andric     case RISCV::REM:
49106c3fb27SDimitry Andric     case RISCV::ANDI:
49206c3fb27SDimitry Andric     case RISCV::ORI:
49306c3fb27SDimitry Andric     case RISCV::XORI:
49406c3fb27SDimitry Andric       // |Remainder| is always <= |Dividend|. If D is 32-bit, then so is R.
49506c3fb27SDimitry Andric       // DIV doesn't work because of the edge case 0xf..f 8000 0000 / (long)-1
49606c3fb27SDimitry Andric       // Logical operations use a sign extended 12-bit immediate.
49706c3fb27SDimitry Andric       if (!AddRegDefToWorkList(MI->getOperand(1).getReg()))
49806c3fb27SDimitry Andric         return false;
49906c3fb27SDimitry Andric 
50006c3fb27SDimitry Andric       break;
50106c3fb27SDimitry Andric     case RISCV::PseudoCCADDW:
502*5f757f3fSDimitry Andric     case RISCV::PseudoCCADDIW:
50306c3fb27SDimitry Andric     case RISCV::PseudoCCSUBW:
504*5f757f3fSDimitry Andric     case RISCV::PseudoCCSLLW:
505*5f757f3fSDimitry Andric     case RISCV::PseudoCCSRLW:
506*5f757f3fSDimitry Andric     case RISCV::PseudoCCSRAW:
507*5f757f3fSDimitry Andric     case RISCV::PseudoCCSLLIW:
508*5f757f3fSDimitry Andric     case RISCV::PseudoCCSRLIW:
509*5f757f3fSDimitry Andric     case RISCV::PseudoCCSRAIW:
510*5f757f3fSDimitry Andric       // Returns operand 4 or an ADDW/SUBW/etc. of operands 5 and 6. We only
511*5f757f3fSDimitry Andric       // need to check if operand 4 is sign extended.
51206c3fb27SDimitry Andric       if (!AddRegDefToWorkList(MI->getOperand(4).getReg()))
51306c3fb27SDimitry Andric         return false;
51406c3fb27SDimitry Andric       break;
51506c3fb27SDimitry Andric     case RISCV::REMU:
51606c3fb27SDimitry Andric     case RISCV::AND:
51706c3fb27SDimitry Andric     case RISCV::OR:
51806c3fb27SDimitry Andric     case RISCV::XOR:
51906c3fb27SDimitry Andric     case RISCV::ANDN:
52006c3fb27SDimitry Andric     case RISCV::ORN:
52106c3fb27SDimitry Andric     case RISCV::XNOR:
52206c3fb27SDimitry Andric     case RISCV::MAX:
52306c3fb27SDimitry Andric     case RISCV::MAXU:
52406c3fb27SDimitry Andric     case RISCV::MIN:
52506c3fb27SDimitry Andric     case RISCV::MINU:
52606c3fb27SDimitry Andric     case RISCV::PseudoCCMOVGPR:
52706c3fb27SDimitry Andric     case RISCV::PseudoCCAND:
52806c3fb27SDimitry Andric     case RISCV::PseudoCCOR:
52906c3fb27SDimitry Andric     case RISCV::PseudoCCXOR:
53006c3fb27SDimitry Andric     case RISCV::PHI: {
53106c3fb27SDimitry Andric       // If all incoming values are sign-extended, the output of AND, OR, XOR,
53206c3fb27SDimitry Andric       // MIN, MAX, or PHI is also sign-extended.
53306c3fb27SDimitry Andric 
53406c3fb27SDimitry Andric       // The input registers for PHI are operand 1, 3, ...
53506c3fb27SDimitry Andric       // The input registers for PseudoCCMOVGPR are 4 and 5.
53606c3fb27SDimitry Andric       // The input registers for PseudoCCAND/OR/XOR are 4, 5, and 6.
53706c3fb27SDimitry Andric       // The input registers for others are operand 1 and 2.
53806c3fb27SDimitry Andric       unsigned B = 1, E = 3, D = 1;
53906c3fb27SDimitry Andric       switch (MI->getOpcode()) {
54006c3fb27SDimitry Andric       case RISCV::PHI:
54106c3fb27SDimitry Andric         E = MI->getNumOperands();
54206c3fb27SDimitry Andric         D = 2;
54306c3fb27SDimitry Andric         break;
54406c3fb27SDimitry Andric       case RISCV::PseudoCCMOVGPR:
54506c3fb27SDimitry Andric         B = 4;
54606c3fb27SDimitry Andric         E = 6;
54706c3fb27SDimitry Andric         break;
54806c3fb27SDimitry Andric       case RISCV::PseudoCCAND:
54906c3fb27SDimitry Andric       case RISCV::PseudoCCOR:
55006c3fb27SDimitry Andric       case RISCV::PseudoCCXOR:
55106c3fb27SDimitry Andric         B = 4;
55206c3fb27SDimitry Andric         E = 7;
55306c3fb27SDimitry Andric         break;
55406c3fb27SDimitry Andric        }
55506c3fb27SDimitry Andric 
55606c3fb27SDimitry Andric       for (unsigned I = B; I != E; I += D) {
55706c3fb27SDimitry Andric         if (!MI->getOperand(I).isReg())
55806c3fb27SDimitry Andric           return false;
55906c3fb27SDimitry Andric 
56006c3fb27SDimitry Andric         if (!AddRegDefToWorkList(MI->getOperand(I).getReg()))
56106c3fb27SDimitry Andric           return false;
56206c3fb27SDimitry Andric       }
56306c3fb27SDimitry Andric 
56406c3fb27SDimitry Andric       break;
56506c3fb27SDimitry Andric     }
56606c3fb27SDimitry Andric 
567*5f757f3fSDimitry Andric     case RISCV::CZERO_EQZ:
568*5f757f3fSDimitry Andric     case RISCV::CZERO_NEZ:
56906c3fb27SDimitry Andric     case RISCV::VT_MASKC:
57006c3fb27SDimitry Andric     case RISCV::VT_MASKCN:
57106c3fb27SDimitry Andric       // Instructions return zero or operand 1. Result is sign extended if
57206c3fb27SDimitry Andric       // operand 1 is sign extended.
57306c3fb27SDimitry Andric       if (!AddRegDefToWorkList(MI->getOperand(1).getReg()))
57406c3fb27SDimitry Andric         return false;
57506c3fb27SDimitry Andric       break;
57606c3fb27SDimitry Andric 
57706c3fb27SDimitry Andric     // With these opcode, we can "fix" them with the W-version
57806c3fb27SDimitry Andric     // if we know all users of the result only rely on bits 31:0
57906c3fb27SDimitry Andric     case RISCV::SLLI:
58006c3fb27SDimitry Andric       // SLLIW reads the lowest 5 bits, while SLLI reads lowest 6 bits
58106c3fb27SDimitry Andric       if (MI->getOperand(2).getImm() >= 32)
58206c3fb27SDimitry Andric         return false;
58306c3fb27SDimitry Andric       [[fallthrough]];
58406c3fb27SDimitry Andric     case RISCV::ADDI:
58506c3fb27SDimitry Andric     case RISCV::ADD:
58606c3fb27SDimitry Andric     case RISCV::LD:
58706c3fb27SDimitry Andric     case RISCV::LWU:
58806c3fb27SDimitry Andric     case RISCV::MUL:
58906c3fb27SDimitry Andric     case RISCV::SUB:
59006c3fb27SDimitry Andric       if (hasAllWUsers(*MI, ST, MRI)) {
59106c3fb27SDimitry Andric         FixableDef.insert(MI);
59206c3fb27SDimitry Andric         break;
59306c3fb27SDimitry Andric       }
59406c3fb27SDimitry Andric       return false;
59506c3fb27SDimitry Andric     }
59606c3fb27SDimitry Andric   }
59706c3fb27SDimitry Andric 
59806c3fb27SDimitry Andric   // If we get here, then every node we visited produces a sign extended value
59906c3fb27SDimitry Andric   // or propagated sign extended values. So the result must be sign extended.
60006c3fb27SDimitry Andric   return true;
60106c3fb27SDimitry Andric }
60206c3fb27SDimitry Andric 
60306c3fb27SDimitry Andric static unsigned getWOp(unsigned Opcode) {
60406c3fb27SDimitry Andric   switch (Opcode) {
60506c3fb27SDimitry Andric   case RISCV::ADDI:
60606c3fb27SDimitry Andric     return RISCV::ADDIW;
60706c3fb27SDimitry Andric   case RISCV::ADD:
60806c3fb27SDimitry Andric     return RISCV::ADDW;
60906c3fb27SDimitry Andric   case RISCV::LD:
61006c3fb27SDimitry Andric   case RISCV::LWU:
61106c3fb27SDimitry Andric     return RISCV::LW;
61206c3fb27SDimitry Andric   case RISCV::MUL:
61306c3fb27SDimitry Andric     return RISCV::MULW;
61406c3fb27SDimitry Andric   case RISCV::SLLI:
61506c3fb27SDimitry Andric     return RISCV::SLLIW;
61606c3fb27SDimitry Andric   case RISCV::SUB:
61706c3fb27SDimitry Andric     return RISCV::SUBW;
61806c3fb27SDimitry Andric   default:
61906c3fb27SDimitry Andric     llvm_unreachable("Unexpected opcode for replacement with W variant");
62006c3fb27SDimitry Andric   }
62106c3fb27SDimitry Andric }
62206c3fb27SDimitry Andric 
62306c3fb27SDimitry Andric bool RISCVOptWInstrs::removeSExtWInstrs(MachineFunction &MF,
62406c3fb27SDimitry Andric                                         const RISCVInstrInfo &TII,
62506c3fb27SDimitry Andric                                         const RISCVSubtarget &ST,
62606c3fb27SDimitry Andric                                         MachineRegisterInfo &MRI) {
62706c3fb27SDimitry Andric   if (DisableSExtWRemoval)
62806c3fb27SDimitry Andric     return false;
62906c3fb27SDimitry Andric 
63006c3fb27SDimitry Andric   bool MadeChange = false;
63106c3fb27SDimitry Andric   for (MachineBasicBlock &MBB : MF) {
632*5f757f3fSDimitry Andric     for (MachineInstr &MI : llvm::make_early_inc_range(MBB)) {
63306c3fb27SDimitry Andric       // We're looking for the sext.w pattern ADDIW rd, rs1, 0.
634*5f757f3fSDimitry Andric       if (!RISCV::isSEXT_W(MI))
63506c3fb27SDimitry Andric         continue;
63606c3fb27SDimitry Andric 
637*5f757f3fSDimitry Andric       Register SrcReg = MI.getOperand(1).getReg();
63806c3fb27SDimitry Andric 
63906c3fb27SDimitry Andric       SmallPtrSet<MachineInstr *, 4> FixableDefs;
64006c3fb27SDimitry Andric 
64106c3fb27SDimitry Andric       // If all users only use the lower bits, this sext.w is redundant.
64206c3fb27SDimitry Andric       // Or if all definitions reaching MI sign-extend their output,
64306c3fb27SDimitry Andric       // then sext.w is redundant.
644*5f757f3fSDimitry Andric       if (!hasAllWUsers(MI, ST, MRI) &&
64506c3fb27SDimitry Andric           !isSignExtendedW(SrcReg, ST, MRI, FixableDefs))
64606c3fb27SDimitry Andric         continue;
64706c3fb27SDimitry Andric 
648*5f757f3fSDimitry Andric       Register DstReg = MI.getOperand(0).getReg();
64906c3fb27SDimitry Andric       if (!MRI.constrainRegClass(SrcReg, MRI.getRegClass(DstReg)))
65006c3fb27SDimitry Andric         continue;
65106c3fb27SDimitry Andric 
65206c3fb27SDimitry Andric       // Convert Fixable instructions to their W versions.
65306c3fb27SDimitry Andric       for (MachineInstr *Fixable : FixableDefs) {
65406c3fb27SDimitry Andric         LLVM_DEBUG(dbgs() << "Replacing " << *Fixable);
65506c3fb27SDimitry Andric         Fixable->setDesc(TII.get(getWOp(Fixable->getOpcode())));
65606c3fb27SDimitry Andric         Fixable->clearFlag(MachineInstr::MIFlag::NoSWrap);
65706c3fb27SDimitry Andric         Fixable->clearFlag(MachineInstr::MIFlag::NoUWrap);
65806c3fb27SDimitry Andric         Fixable->clearFlag(MachineInstr::MIFlag::IsExact);
65906c3fb27SDimitry Andric         LLVM_DEBUG(dbgs() << "     with " << *Fixable);
66006c3fb27SDimitry Andric         ++NumTransformedToWInstrs;
66106c3fb27SDimitry Andric       }
66206c3fb27SDimitry Andric 
66306c3fb27SDimitry Andric       LLVM_DEBUG(dbgs() << "Removing redundant sign-extension\n");
66406c3fb27SDimitry Andric       MRI.replaceRegWith(DstReg, SrcReg);
66506c3fb27SDimitry Andric       MRI.clearKillFlags(SrcReg);
666*5f757f3fSDimitry Andric       MI.eraseFromParent();
66706c3fb27SDimitry Andric       ++NumRemovedSExtW;
66806c3fb27SDimitry Andric       MadeChange = true;
66906c3fb27SDimitry Andric     }
67006c3fb27SDimitry Andric   }
67106c3fb27SDimitry Andric 
67206c3fb27SDimitry Andric   return MadeChange;
67306c3fb27SDimitry Andric }
67406c3fb27SDimitry Andric 
67506c3fb27SDimitry Andric bool RISCVOptWInstrs::stripWSuffixes(MachineFunction &MF,
67606c3fb27SDimitry Andric                                      const RISCVInstrInfo &TII,
67706c3fb27SDimitry Andric                                      const RISCVSubtarget &ST,
67806c3fb27SDimitry Andric                                      MachineRegisterInfo &MRI) {
67906c3fb27SDimitry Andric   if (DisableStripWSuffix)
68006c3fb27SDimitry Andric     return false;
68106c3fb27SDimitry Andric 
68206c3fb27SDimitry Andric   bool MadeChange = false;
68306c3fb27SDimitry Andric   for (MachineBasicBlock &MBB : MF) {
684*5f757f3fSDimitry Andric     for (MachineInstr &MI : MBB) {
68506c3fb27SDimitry Andric       unsigned Opc;
68606c3fb27SDimitry Andric       switch (MI.getOpcode()) {
68706c3fb27SDimitry Andric       default:
68806c3fb27SDimitry Andric         continue;
68906c3fb27SDimitry Andric       case RISCV::ADDW:  Opc = RISCV::ADD;  break;
690*5f757f3fSDimitry Andric       case RISCV::ADDIW: Opc = RISCV::ADDI; break;
69106c3fb27SDimitry Andric       case RISCV::MULW:  Opc = RISCV::MUL;  break;
69206c3fb27SDimitry Andric       case RISCV::SLLIW: Opc = RISCV::SLLI; break;
69306c3fb27SDimitry Andric       }
69406c3fb27SDimitry Andric 
69506c3fb27SDimitry Andric       if (hasAllWUsers(MI, ST, MRI)) {
69606c3fb27SDimitry Andric         MI.setDesc(TII.get(Opc));
69706c3fb27SDimitry Andric         MadeChange = true;
69806c3fb27SDimitry Andric       }
69906c3fb27SDimitry Andric     }
70006c3fb27SDimitry Andric   }
70106c3fb27SDimitry Andric 
70206c3fb27SDimitry Andric   return MadeChange;
70306c3fb27SDimitry Andric }
70406c3fb27SDimitry Andric 
70506c3fb27SDimitry Andric bool RISCVOptWInstrs::runOnMachineFunction(MachineFunction &MF) {
70606c3fb27SDimitry Andric   if (skipFunction(MF.getFunction()))
70706c3fb27SDimitry Andric     return false;
70806c3fb27SDimitry Andric 
70906c3fb27SDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
71006c3fb27SDimitry Andric   const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>();
71106c3fb27SDimitry Andric   const RISCVInstrInfo &TII = *ST.getInstrInfo();
71206c3fb27SDimitry Andric 
71306c3fb27SDimitry Andric   if (!ST.is64Bit())
71406c3fb27SDimitry Andric     return false;
71506c3fb27SDimitry Andric 
71606c3fb27SDimitry Andric   bool MadeChange = false;
71706c3fb27SDimitry Andric   MadeChange |= removeSExtWInstrs(MF, TII, ST, MRI);
71806c3fb27SDimitry Andric   MadeChange |= stripWSuffixes(MF, TII, ST, MRI);
71906c3fb27SDimitry Andric 
72006c3fb27SDimitry Andric   return MadeChange;
72106c3fb27SDimitry Andric }
722