xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVOptWInstrs.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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