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
RISCVOptWInstrs()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
getAnalysisUsage(AnalysisUsage & AU) const7506c3fb27SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override {
7606c3fb27SDimitry Andric AU.setPreservesCFG();
7706c3fb27SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU);
7806c3fb27SDimitry Andric }
7906c3fb27SDimitry Andric
getPassName() const8006c3fb27SDimitry 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;
INITIALIZE_PASS(RISCVOptWInstrs,DEBUG_TYPE,RISCV_OPT_W_INSTRS_NAME,false,false)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
vectorPseudoHasAllNBitUsers(const MachineOperand & UserOp,unsigned Bits)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
hasAllNBitUsers(const MachineInstr & OrigMI,const RISCVSubtarget & ST,const MachineRegisterInfo & MRI,unsigned OrigBits)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
hasAllWUsers(const MachineInstr & OrigMI,const RISCVSubtarget & ST,const MachineRegisterInfo & MRI)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.
isSignExtendingOpW(const MachineInstr & MI,const MachineRegisterInfo & MRI,unsigned OpNo)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
isSignExtendedW(Register SrcReg,const RISCVSubtarget & ST,const MachineRegisterInfo & MRI,SmallPtrSetImpl<MachineInstr * > & FixableDef)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
getWOp(unsigned Opcode)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
removeSExtWInstrs(MachineFunction & MF,const RISCVInstrInfo & TII,const RISCVSubtarget & ST,MachineRegisterInfo & MRI)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
stripWSuffixes(MachineFunction & MF,const RISCVInstrInfo & TII,const RISCVSubtarget & ST,MachineRegisterInfo & MRI)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
appendWSuffixes(MachineFunction & MF,const RISCVInstrInfo & TII,const RISCVSubtarget & ST,MachineRegisterInfo & MRI)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
runOnMachineFunction(MachineFunction & MF)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