Skip to content

[RISCV] Generate more W instructons #87237

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions llvm/lib/Target/RISCV/RISCVFeatures.td
Original file line number Diff line number Diff line change
Expand Up @@ -1226,9 +1226,9 @@ def TuneNoSinkSplatOperands
"false", "Disable sink splat operands to enable .vx, .vf,"
".wx, and .wf instructions">;

def TuneNoStripWSuffix
: SubtargetFeature<"no-strip-w-suffix", "EnableStripWSuffix", "false",
"Disable strip W suffix">;
def TunePreferWInst
: SubtargetFeature<"prefer-w-inst", "PreferWInst", "true",
"Prefer instructions with W suffix">;

def TuneConditionalCompressedMoveFusion
: SubtargetFeature<"conditional-cmv-fusion", "HasConditionalCompressedMoveFusion",
Expand Down
89 changes: 77 additions & 12 deletions llvm/lib/Target/RISCV/RISCVOptWInstrs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,24 @@
// extended bits aren't consumed or because the input was already sign extended
// by an earlier instruction.
//
// Then it removes the -w suffix from opw instructions whenever all users are
// dependent only on the lower word of the result of the instruction.
// The cases handled are:
// * addw because c.add has a larger register encoding than c.addw.
// * addiw because it helps reduce test differences between RV32 and RV64
// w/o being a pessimization.
// * mulw because c.mulw doesn't exist but c.mul does (w/ zcb)
// * slliw because c.slliw doesn't exist and c.slli does
// Then:
// 1. Unless explicit disabled or the target prefers instructions with W suffix,
// it removes the -w suffix from opw instructions whenever all users are
// dependent only on the lower word of the result of the instruction.
// The cases handled are:
// * addw because c.add has a larger register encoding than c.addw.
// * addiw because it helps reduce test differences between RV32 and RV64
// w/o being a pessimization.
// * mulw because c.mulw doesn't exist but c.mul does (w/ zcb)
// * slliw because c.slliw doesn't exist and c.slli does
//
// 2. Or if explicit enabled or the target prefers instructions with W suffix,
// it adds the W suffix to the instruction whenever all users are dependent
// only on the lower word of the result of the instruction.
// The cases handled are:
// * add/addi/sub/mul.
// * slli with imm < 32.
// * ld/lwu.
//===---------------------------------------------------------------------===//

#include "RISCV.h"
Expand Down Expand Up @@ -60,6 +69,8 @@ class RISCVOptWInstrs : public MachineFunctionPass {
const RISCVSubtarget &ST, MachineRegisterInfo &MRI);
bool stripWSuffixes(MachineFunction &MF, const RISCVInstrInfo &TII,
const RISCVSubtarget &ST, MachineRegisterInfo &MRI);
bool appendWSuffixes(MachineFunction &MF, const RISCVInstrInfo &TII,
const RISCVSubtarget &ST, MachineRegisterInfo &MRI);

void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesCFG();
Expand Down Expand Up @@ -672,9 +683,6 @@ bool RISCVOptWInstrs::stripWSuffixes(MachineFunction &MF,
const RISCVInstrInfo &TII,
const RISCVSubtarget &ST,
MachineRegisterInfo &MRI) {
if (DisableStripWSuffix || !ST.enableStripWSuffix())
return false;

bool MadeChange = false;
for (MachineBasicBlock &MBB : MF) {
for (MachineInstr &MI : MBB) {
Expand All @@ -698,6 +706,58 @@ bool RISCVOptWInstrs::stripWSuffixes(MachineFunction &MF,
return MadeChange;
}

bool RISCVOptWInstrs::appendWSuffixes(MachineFunction &MF,
const RISCVInstrInfo &TII,
const RISCVSubtarget &ST,
MachineRegisterInfo &MRI) {
bool MadeChange = false;
for (MachineBasicBlock &MBB : MF) {
for (MachineInstr &MI : MBB) {
unsigned WOpc;
// TODO: Add more?
switch (MI.getOpcode()) {
default:
continue;
case RISCV::ADD:
WOpc = RISCV::ADDW;
break;
case RISCV::ADDI:
WOpc = RISCV::ADDIW;
break;
case RISCV::SUB:
WOpc = RISCV::SUBW;
break;
case RISCV::MUL:
WOpc = RISCV::MULW;
break;
case RISCV::SLLI:
// SLLIW reads the lowest 5 bits, while SLLI reads lowest 6 bits
if (MI.getOperand(2).getImm() >= 32)
continue;
WOpc = RISCV::SLLIW;
break;
case RISCV::LD:
case RISCV::LWU:
WOpc = RISCV::LW;
break;
}

if (hasAllWUsers(MI, ST, MRI)) {
LLVM_DEBUG(dbgs() << "Replacing " << MI);
MI.setDesc(TII.get(WOpc));
MI.clearFlag(MachineInstr::MIFlag::NoSWrap);
MI.clearFlag(MachineInstr::MIFlag::NoUWrap);
MI.clearFlag(MachineInstr::MIFlag::IsExact);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add some tests for flags dropping?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the same as RISCVOptWInstrs::removeSExtWInstrs:

// Convert Fixable instructions to their W versions.
for (MachineInstr *Fixable : FixableDefs) {
LLVM_DEBUG(dbgs() << "Replacing " << *Fixable);
Fixable->setDesc(TII.get(getWOp(Fixable->getOpcode())));
Fixable->clearFlag(MachineInstr::MIFlag::NoSWrap);
Fixable->clearFlag(MachineInstr::MIFlag::NoUWrap);
Fixable->clearFlag(MachineInstr::MIFlag::IsExact);
LLVM_DEBUG(dbgs() << " with " << *Fixable);
++NumTransformedToWInstrs;
}

I don't know how to test it actually.

LLVM_DEBUG(dbgs() << " with " << MI);
++NumTransformedToWInstrs;
MadeChange = true;
}
}
}

return MadeChange;
}

bool RISCVOptWInstrs::runOnMachineFunction(MachineFunction &MF) {
if (skipFunction(MF.getFunction()))
return false;
Expand All @@ -711,7 +771,12 @@ bool RISCVOptWInstrs::runOnMachineFunction(MachineFunction &MF) {

bool MadeChange = false;
MadeChange |= removeSExtWInstrs(MF, TII, ST, MRI);
MadeChange |= stripWSuffixes(MF, TII, ST, MRI);

if (!(DisableStripWSuffix || ST.preferWInst()))
MadeChange |= stripWSuffixes(MF, TII, ST, MRI);

if (ST.preferWInst())
MadeChange |= appendWSuffixes(MF, TII, ST, MRI);

return MadeChange;
}
105 changes: 105 additions & 0 deletions llvm/test/CodeGen/RISCV/prefer-w-inst.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=riscv64 -mattr=+m -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefixes=NO-PREFER-W-INST %s
; RUN: llc -mtriple=riscv64 -mattr=+m -riscv-disable-strip-w-suffix -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefixes=NO-STRIP %s
; RUN: llc -mtriple=riscv64 -mattr=+m,+prefer-w-inst -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefixes=PREFER-W-INST %s

define i32 @addiw(i32 %a) {
; NO-PREFER-W-INST-LABEL: addiw:
; NO-PREFER-W-INST: # %bb.0:
; NO-PREFER-W-INST-NEXT: lui a1, 1
; NO-PREFER-W-INST-NEXT: addi a1, a1, -1
; NO-PREFER-W-INST-NEXT: addw a0, a0, a1
; NO-PREFER-W-INST-NEXT: ret
;
; NO-STRIP-LABEL: addiw:
; NO-STRIP: # %bb.0:
; NO-STRIP-NEXT: lui a1, 1
; NO-STRIP-NEXT: addiw a1, a1, -1
; NO-STRIP-NEXT: addw a0, a0, a1
; NO-STRIP-NEXT: ret
;
; PREFER-W-INST-LABEL: addiw:
; PREFER-W-INST: # %bb.0:
; PREFER-W-INST-NEXT: lui a1, 1
; PREFER-W-INST-NEXT: addiw a1, a1, -1
; PREFER-W-INST-NEXT: addw a0, a0, a1
; PREFER-W-INST-NEXT: ret
%ret = add i32 %a, 4095
ret i32 %ret
}

define i32 @addw(i32 %a, i32 %b) {
; NO-PREFER-W-INST-LABEL: addw:
; NO-PREFER-W-INST: # %bb.0:
; NO-PREFER-W-INST-NEXT: add a0, a0, a1
; NO-PREFER-W-INST-NEXT: addiw a0, a0, 1024
; NO-PREFER-W-INST-NEXT: ret
;
; NO-STRIP-LABEL: addw:
; NO-STRIP: # %bb.0:
; NO-STRIP-NEXT: addw a0, a0, a1
; NO-STRIP-NEXT: addiw a0, a0, 1024
; NO-STRIP-NEXT: ret
;
; PREFER-W-INST-LABEL: addw:
; PREFER-W-INST: # %bb.0:
; PREFER-W-INST-NEXT: addw a0, a0, a1
; PREFER-W-INST-NEXT: addiw a0, a0, 1024
; PREFER-W-INST-NEXT: ret
%add = add i32 %a, %b
%ret = add i32 %add, 1024
ret i32 %ret
}

define i32 @mulw(i32 %a, i32 %b) {
; NO-PREFER-W-INST-LABEL: mulw:
; NO-PREFER-W-INST: # %bb.0:
; NO-PREFER-W-INST-NEXT: mul a1, a0, a1
; NO-PREFER-W-INST-NEXT: mul a0, a0, a1
; NO-PREFER-W-INST-NEXT: addiw a0, a0, 1024
; NO-PREFER-W-INST-NEXT: ret
;
; NO-STRIP-LABEL: mulw:
; NO-STRIP: # %bb.0:
; NO-STRIP-NEXT: mulw a1, a0, a1
; NO-STRIP-NEXT: mulw a0, a0, a1
; NO-STRIP-NEXT: addiw a0, a0, 1024
; NO-STRIP-NEXT: ret
;
; PREFER-W-INST-LABEL: mulw:
; PREFER-W-INST: # %bb.0:
; PREFER-W-INST-NEXT: mulw a1, a0, a1
; PREFER-W-INST-NEXT: mulw a0, a0, a1
; PREFER-W-INST-NEXT: addiw a0, a0, 1024
; PREFER-W-INST-NEXT: ret
%mul1 = mul i32 %a, %b
%mul = mul i32 %a, %mul1
%ret = add i32 %mul, 1024
ret i32 %ret
}

define i32 @slliw(i32 %a) {
; NO-PREFER-W-INST-LABEL: slliw:
; NO-PREFER-W-INST: # %bb.0:
; NO-PREFER-W-INST-NEXT: slli a0, a0, 1
; NO-PREFER-W-INST-NEXT: addiw a0, a0, 1024
; NO-PREFER-W-INST-NEXT: ret
;
; NO-STRIP-LABEL: slliw:
; NO-STRIP: # %bb.0:
; NO-STRIP-NEXT: slliw a0, a0, 1
; NO-STRIP-NEXT: addiw a0, a0, 1024
; NO-STRIP-NEXT: ret
;
; PREFER-W-INST-LABEL: slliw:
; PREFER-W-INST: # %bb.0:
; PREFER-W-INST-NEXT: slliw a0, a0, 1
; PREFER-W-INST-NEXT: addiw a0, a0, 1024
; PREFER-W-INST-NEXT: ret
%shl = shl i32 %a, 1
%ret = add i32 %shl, 1024
ret i32 %ret
}
Loading