forked from OSchip/llvm-project
157 lines
4.9 KiB
C++
157 lines
4.9 KiB
C++
//===- RISCVCleanupVSETVLI.cpp - Cleanup unneeded VSETVLI instructions ----===//
|
|
//
|
|
// 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 file implements a function pass that removes duplicate vsetvli
|
|
// instructions within a basic block.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "RISCV.h"
|
|
#include "RISCVSubtarget.h"
|
|
#include "llvm/CodeGen/MachineFunctionPass.h"
|
|
using namespace llvm;
|
|
|
|
#define DEBUG_TYPE "riscv-cleanup-vsetvli"
|
|
#define RISCV_CLEANUP_VSETVLI_NAME "RISCV Cleanup VSETVLI pass"
|
|
|
|
namespace {
|
|
|
|
class RISCVCleanupVSETVLI : public MachineFunctionPass {
|
|
public:
|
|
static char ID;
|
|
|
|
RISCVCleanupVSETVLI() : MachineFunctionPass(ID) {
|
|
initializeRISCVCleanupVSETVLIPass(*PassRegistry::getPassRegistry());
|
|
}
|
|
bool runOnMachineFunction(MachineFunction &MF) override;
|
|
bool runOnMachineBasicBlock(MachineBasicBlock &MBB);
|
|
|
|
MachineFunctionProperties getRequiredProperties() const override {
|
|
return MachineFunctionProperties().set(
|
|
MachineFunctionProperties::Property::IsSSA);
|
|
}
|
|
|
|
// This pass modifies the program, but does not modify the CFG
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
AU.setPreservesCFG();
|
|
MachineFunctionPass::getAnalysisUsage(AU);
|
|
}
|
|
|
|
StringRef getPassName() const override { return RISCV_CLEANUP_VSETVLI_NAME; }
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
char RISCVCleanupVSETVLI::ID = 0;
|
|
|
|
INITIALIZE_PASS(RISCVCleanupVSETVLI, DEBUG_TYPE,
|
|
RISCV_CLEANUP_VSETVLI_NAME, false, false)
|
|
|
|
static bool isRedundantVSETVLI(MachineInstr &MI, MachineInstr *PrevVSETVLI) {
|
|
// If we don't have a previous VSET{I}VLI or the VL output isn't dead, we
|
|
// can't remove this VSETVLI.
|
|
if (!PrevVSETVLI || !MI.getOperand(0).isDead())
|
|
return false;
|
|
|
|
// Does this VSET{I}VLI use the same VTYPE immediate.
|
|
int64_t PrevVTYPEImm = PrevVSETVLI->getOperand(2).getImm();
|
|
int64_t VTYPEImm = MI.getOperand(2).getImm();
|
|
if (PrevVTYPEImm != VTYPEImm)
|
|
return false;
|
|
|
|
if (MI.getOpcode() == RISCV::PseudoVSETIVLI) {
|
|
// If the previous opcode wasn't vsetivli we can't compare them.
|
|
if (PrevVSETVLI->getOpcode() != RISCV::PseudoVSETIVLI)
|
|
return false;
|
|
|
|
// For VSETIVLI, we can just compare the immediates.
|
|
return PrevVSETVLI->getOperand(1).getImm() == MI.getOperand(1).getImm();
|
|
}
|
|
|
|
assert(MI.getOpcode() == RISCV::PseudoVSETVLI);
|
|
Register AVLReg = MI.getOperand(1).getReg();
|
|
|
|
// If this VSETVLI isn't changing VL, it is redundant.
|
|
if (AVLReg == RISCV::X0 && MI.getOperand(0).getReg() == RISCV::X0)
|
|
return true;
|
|
|
|
// If the previous opcode isn't vsetvli we can't do any more comparison.
|
|
if (PrevVSETVLI->getOpcode() != RISCV::PseudoVSETVLI)
|
|
return false;
|
|
|
|
// Does this VSETVLI use the same AVL register?
|
|
if (AVLReg != PrevVSETVLI->getOperand(1).getReg())
|
|
return false;
|
|
|
|
// If the AVLReg is X0 we must be setting VL to VLMAX. Keeping VL unchanged
|
|
// was handled above.
|
|
if (AVLReg == RISCV::X0) {
|
|
// This instruction is setting VL to VLMAX, this is redundant if the
|
|
// previous VSETVLI was also setting VL to VLMAX. But it is not redundant
|
|
// if they were setting it to any other value or leaving VL unchanged.
|
|
Register PrevOutVL = PrevVSETVLI->getOperand(0).getReg();
|
|
return PrevOutVL != RISCV::X0;
|
|
}
|
|
|
|
// This vsetvli is redundant.
|
|
return true;
|
|
}
|
|
|
|
bool RISCVCleanupVSETVLI::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
|
|
bool Changed = false;
|
|
MachineInstr *PrevVSETVLI = nullptr;
|
|
|
|
for (auto MII = MBB.begin(), MIE = MBB.end(); MII != MIE;) {
|
|
MachineInstr &MI = *MII++;
|
|
|
|
if (MI.getOpcode() != RISCV::PseudoVSETVLI &&
|
|
MI.getOpcode() != RISCV::PseudoVSETIVLI) {
|
|
if (PrevVSETVLI &&
|
|
(MI.isCall() || MI.modifiesRegister(RISCV::VL) ||
|
|
MI.modifiesRegister(RISCV::VTYPE))) {
|
|
// Old VL/VTYPE is overwritten.
|
|
PrevVSETVLI = nullptr;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (isRedundantVSETVLI(MI, PrevVSETVLI)) {
|
|
// This VSETVLI is redundant, remove it.
|
|
MI.eraseFromParent();
|
|
Changed = true;
|
|
} else {
|
|
// Otherwise update VSET{I}VLI for the next iteration.
|
|
PrevVSETVLI = &MI;
|
|
}
|
|
}
|
|
|
|
return Changed;
|
|
}
|
|
|
|
bool RISCVCleanupVSETVLI::runOnMachineFunction(MachineFunction &MF) {
|
|
if (skipFunction(MF.getFunction()))
|
|
return false;
|
|
|
|
// Skip if the vector extension is not enabled.
|
|
const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>();
|
|
if (!ST.hasStdExtV())
|
|
return false;
|
|
|
|
bool Changed = false;
|
|
|
|
for (MachineBasicBlock &MBB : MF)
|
|
Changed |= runOnMachineBasicBlock(MBB);
|
|
|
|
return Changed;
|
|
}
|
|
|
|
/// Returns an instance of the Cleanup VSETVLI pass.
|
|
FunctionPass *llvm::createRISCVCleanupVSETVLIPass() {
|
|
return new RISCVCleanupVSETVLI();
|
|
}
|