Skip to content

Commit

Permalink
[RISCV] Add a pass to rewrite rd to x0 for non-computational instrs w…
Browse files Browse the repository at this point in the history
…hose return values are unused

When AMOs are used to implement parallel reduction operations, typically the return value would be discarded.
This patch adds a peephole pass `RISCVDeadRegisterDefinitions`. It rewrites `rd` to `x0` when `rd` is marked as dead.
It may improve the register allocation and reduce pipeline hazards on CPUs without register renaming and OOO.
Comparison with GCC: https://godbolt.org/z/bKaxnEcec

Reviewed By: craig.topper

Differential Revision: https://reviews.llvm.org/D158759
  • Loading branch information
dtcxzyw committed Sep 19, 2023
1 parent fba457d commit 93fde2e
Show file tree
Hide file tree
Showing 19 changed files with 198 additions and 103 deletions.
1 change: 1 addition & 0 deletions llvm/lib/Target/RISCV/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ add_public_tablegen_target(RISCVCommonTableGen)
add_llvm_target(RISCVCodeGen
RISCVAsmPrinter.cpp
RISCVCodeGenPrepare.cpp
RISCVDeadRegisterDefinitions.cpp
RISCVMakeCompressible.cpp
RISCVExpandAtomicPseudoInsts.cpp
RISCVExpandPseudoInsts.cpp
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/RISCV/RISCV.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ class RISCVTargetMachine;
FunctionPass *createRISCVCodeGenPreparePass();
void initializeRISCVCodeGenPreparePass(PassRegistry &);

FunctionPass *createRISCVDeadRegisterDefinitionsPass();
void initializeRISCVDeadRegisterDefinitionsPass(PassRegistry &);

FunctionPass *createRISCVISelDag(RISCVTargetMachine &TM,
CodeGenOptLevel OptLevel);

Expand Down
106 changes: 106 additions & 0 deletions llvm/lib/Target/RISCV/RISCVDeadRegisterDefinitions.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
//===- RISCVDeadRegisterDefinitions.cpp - Replace dead defs w/ zero reg --===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===---------------------------------------------------------------------===//
//
// This pass rewrites Rd to x0 for instrs whose return values are unused.
//
//===---------------------------------------------------------------------===//

#include "RISCV.h"
#include "RISCVInstrInfo.h"
#include "RISCVSubtarget.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"

using namespace llvm;
#define DEBUG_TYPE "riscv-dead-defs"
#define RISCV_DEAD_REG_DEF_NAME "RISC-V Dead register definitions"

STATISTIC(NumDeadDefsReplaced, "Number of dead definitions replaced");

namespace {
class RISCVDeadRegisterDefinitions : public MachineFunctionPass {
public:
static char ID;

RISCVDeadRegisterDefinitions() : MachineFunctionPass(ID) {
initializeRISCVDeadRegisterDefinitionsPass(
*PassRegistry::getPassRegistry());
}
bool runOnMachineFunction(MachineFunction &MF) override;
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesCFG();
MachineFunctionPass::getAnalysisUsage(AU);
}

StringRef getPassName() const override { return RISCV_DEAD_REG_DEF_NAME; }
};
} // end anonymous namespace

char RISCVDeadRegisterDefinitions::ID = 0;
INITIALIZE_PASS(RISCVDeadRegisterDefinitions, DEBUG_TYPE,
RISCV_DEAD_REG_DEF_NAME, false, false)

FunctionPass *llvm::createRISCVDeadRegisterDefinitionsPass() {
return new RISCVDeadRegisterDefinitions();
}

bool RISCVDeadRegisterDefinitions::runOnMachineFunction(MachineFunction &MF) {
if (skipFunction(MF.getFunction()))
return false;

const MachineRegisterInfo *MRI = &MF.getRegInfo();
const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
LLVM_DEBUG(dbgs() << "***** RISCVDeadRegisterDefinitions *****\n");

bool MadeChange = false;
for (MachineBasicBlock &MBB : MF) {
for (MachineInstr &MI : MBB) {
// We only handle non-computational instructions since some NOP encodings
// are reserved for HINT instructions.
const MCInstrDesc &Desc = MI.getDesc();
if (!Desc.mayLoad() && !Desc.mayStore() &&
!Desc.hasUnmodeledSideEffects())
continue;
// For PseudoVSETVLIX0, Rd = X0 has special meaning.
if (MI.getOpcode() == RISCV::PseudoVSETVLIX0)
continue;
for (int I = 0, E = Desc.getNumDefs(); I != E; ++I) {
MachineOperand &MO = MI.getOperand(I);
if (!MO.isReg() || !MO.isDef() || MO.isEarlyClobber())
continue;
// Be careful not to change the register if it's a tied operand.
if (MI.isRegTiedToUseOperand(I)) {
LLVM_DEBUG(dbgs() << " Ignoring, def is tied operand.\n");
continue;
}
// We should not have any relevant physreg defs that are replacable by
// zero before register allocation. So we just check for dead vreg defs.
Register Reg = MO.getReg();
if (!Reg.isVirtual() || (!MO.isDead() && !MRI->use_nodbg_empty(Reg)))
continue;
LLVM_DEBUG(dbgs() << " Dead def operand #" << I << " in:\n ";
MI.print(dbgs()));
const TargetRegisterClass *RC = TII->getRegClass(Desc, I, TRI, MF);
if (!(RC && RC->contains(RISCV::X0))) {
LLVM_DEBUG(dbgs() << " Ignoring, register is not a GPR.\n");
continue;
}
MO.setReg(RISCV::X0);
MO.setIsDead();
LLVM_DEBUG(dbgs() << " Replacing with zero register. New:\n ";
MI.print(dbgs()));
++NumDeadDefsReplaced;
MadeChange = true;
}
}
}

return MadeChange;
}
16 changes: 0 additions & 16 deletions llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1592,22 +1592,6 @@ bool RISCVInsertVSETVLI::runOnMachineFunction(MachineFunction &MF) {
for (MachineBasicBlock &MBB : MF)
doLocalPostpass(MBB);

// Once we're fully done rewriting all the instructions, do a final pass
// through to check for VSETVLIs which write to an unused destination.
// For the non X0, X0 variant, we can replace the destination register
// with X0 to reduce register pressure. This is really a generic
// optimization which can be applied to any dead def (TODO: generalize).
for (MachineBasicBlock &MBB : MF) {
for (MachineInstr &MI : MBB) {
if (MI.getOpcode() == RISCV::PseudoVSETVLI ||
MI.getOpcode() == RISCV::PseudoVSETIVLI) {
Register VRegDef = MI.getOperand(0).getReg();
if (VRegDef != RISCV::X0 && MRI->use_nodbg_empty(VRegDef))
MI.getOperand(0).setReg(RISCV::X0);
}
}
}

// Insert PseudoReadVL after VLEFF/VLSEGFF and replace it with the vl output
// of VLEFF/VLSEGFF.
for (MachineBasicBlock &MBB : MF)
Expand Down
11 changes: 11 additions & 0 deletions llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ static cl::opt<bool> EnableRISCVCopyPropagation(
cl::desc("Enable the copy propagation with RISC-V copy instr"),
cl::init(true), cl::Hidden);

static cl::opt<bool> EnableRISCVDeadRegisterElimination(
"riscv-enable-dead-defs", cl::Hidden,
cl::desc("Enable the pass that removes dead"
" definitons and replaces stores to"
" them with stores to x0"),
cl::init(true));

extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTarget() {
RegisterTargetMachine<RISCVTargetMachine> X(getTheRISCV32Target());
RegisterTargetMachine<RISCVTargetMachine> Y(getTheRISCV64Target());
Expand All @@ -79,6 +86,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTarget() {
initializeRISCVO0PreLegalizerCombinerPass(*PR);
initializeRISCVPreLegalizerCombinerPass(*PR);
initializeKCFIPass(*PR);
initializeRISCVDeadRegisterDefinitionsPass(*PR);
initializeRISCVMakeCompressibleOptPass(*PR);
initializeRISCVGatherScatterLoweringPass(*PR);
initializeRISCVCodeGenPreparePass(*PR);
Expand Down Expand Up @@ -401,6 +409,9 @@ void RISCVPassConfig::addPreRegAlloc() {
if (TM->getOptLevel() != CodeGenOptLevel::None)
addPass(createRISCVMergeBaseOffsetOptPass());
addPass(createRISCVInsertVSETVLIPass());
if (TM->getOptLevel() != CodeGenOptLevel::None &&
EnableRISCVDeadRegisterElimination)
addPass(createRISCVDeadRegisterDefinitionsPass());
addPass(createRISCVInsertReadWriteCSRPass());
}

Expand Down
1 change: 1 addition & 0 deletions llvm/test/CodeGen/RISCV/O3-pipeline.ll
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@
; CHECK-NEXT: RISC-V Pre-RA pseudo instruction expansion pass
; CHECK-NEXT: RISC-V Merge Base Offset
; CHECK-NEXT: RISC-V Insert VSETVLI pass
; CHECK-NEXT: RISC-V Dead register definitions
; CHECK-NEXT: RISC-V Insert Read/Write CSR Pass
; CHECK-NEXT: Detect Dead Lanes
; CHECK-NEXT: RISC-V init undef pass
Expand Down
Loading

0 comments on commit 93fde2e

Please sign in to comment.