Skip to content

[RISCV] Split regalloc between RVV and other #72096

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 1 commit into from
Nov 16, 2023
Merged
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
108 changes: 108 additions & 0 deletions llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "llvm/CodeGen/MIRParser/MIParser.h"
#include "llvm/CodeGen/MIRYamlMapping.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/RegAllocRegistry.h"
#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/InitializePasses.h"
Expand Down Expand Up @@ -89,6 +90,11 @@ static cl::opt<bool>
cl::desc("Enable the loop data prefetch pass"),
cl::init(true));

static cl::opt<bool>
EnableSplitRegAlloc("riscv-split-regalloc", cl::Hidden,
cl::desc("Enable Split RegisterAlloc for RVV"),
cl::init(false));

Copy link
Contributor

Choose a reason for hiding this comment

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

Should we just enable split register allocation by default? I didn't notice any regressions with this enabled on the llvm test suite, and it doesn't seem to affect the output at all on RV64g (i.e. without v)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for reviewing.

I think the splitting register allocation only gain benefit when the following optimization is ready. Perhaps we can enable it by default when the following optimizations are stable.

extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTarget() {
RegisterTargetMachine<RISCVTargetMachine> X(getTheRISCV32Target());
RegisterTargetMachine<RISCVTargetMachine> Y(getTheRISCV64Target());
Expand Down Expand Up @@ -253,6 +259,76 @@ bool RISCVTargetMachine::isNoopAddrSpaceCast(unsigned SrcAS,
}

namespace {

class RVVRegisterRegAlloc : public RegisterRegAllocBase<RVVRegisterRegAlloc> {
public:
RVVRegisterRegAlloc(const char *N, const char *D, FunctionPassCtor C)
: RegisterRegAllocBase(N, D, C) {}
};

static bool onlyAllocateRVVReg(const TargetRegisterInfo &TRI,
const TargetRegisterClass &RC) {
return RISCV::VRRegClass.hasSubClassEq(&RC) ||
RISCV::VRM2RegClass.hasSubClassEq(&RC) ||
RISCV::VRM4RegClass.hasSubClassEq(&RC) ||
RISCV::VRM8RegClass.hasSubClassEq(&RC) ||
RISCV::VRN2M1RegClass.hasSubClassEq(&RC) ||
RISCV::VRN2M2RegClass.hasSubClassEq(&RC) ||
RISCV::VRN2M4RegClass.hasSubClassEq(&RC) ||
RISCV::VRN3M1RegClass.hasSubClassEq(&RC) ||
RISCV::VRN3M2RegClass.hasSubClassEq(&RC) ||
RISCV::VRN4M1RegClass.hasSubClassEq(&RC) ||
RISCV::VRN4M2RegClass.hasSubClassEq(&RC) ||
RISCV::VRN5M1RegClass.hasSubClassEq(&RC) ||
RISCV::VRN6M1RegClass.hasSubClassEq(&RC) ||
RISCV::VRN7M1RegClass.hasSubClassEq(&RC) ||
RISCV::VRN8M1RegClass.hasSubClassEq(&RC);
}

static FunctionPass *useDefaultRegisterAllocator() { return nullptr; }

static llvm::once_flag InitializeDefaultRVVRegisterAllocatorFlag;

/// -riscv-rvv-regalloc=<fast|basic|greedy> command line option.
/// This option could designate the rvv register allocator only.
/// For example: -riscv-rvv-regalloc=basic
static cl::opt<RVVRegisterRegAlloc::FunctionPassCtor, false,
RegisterPassParser<RVVRegisterRegAlloc>>
RVVRegAlloc("riscv-rvv-regalloc", cl::Hidden,
cl::init(&useDefaultRegisterAllocator),
cl::desc("Register allocator to use for RVV register."));

static void initializeDefaultRVVRegisterAllocatorOnce() {
RegisterRegAlloc::FunctionPassCtor Ctor = RVVRegisterRegAlloc::getDefault();

if (!Ctor) {
Ctor = RVVRegAlloc;
RVVRegisterRegAlloc::setDefault(RVVRegAlloc);
}
}

static FunctionPass *createBasicRVVRegisterAllocator() {
return createBasicRegisterAllocator(onlyAllocateRVVReg);
}

static FunctionPass *createGreedyRVVRegisterAllocator() {
return createGreedyRegisterAllocator(onlyAllocateRVVReg);
}

static FunctionPass *createFastRVVRegisterAllocator() {
return createFastRegisterAllocator(onlyAllocateRVVReg, false);
}

static RVVRegisterRegAlloc basicRegAllocRVVReg("basic",
"basic register allocator",
createBasicRVVRegisterAllocator);
static RVVRegisterRegAlloc
greedyRegAllocRVVReg("greedy", "greedy register allocator",
createGreedyRVVRegisterAllocator);

static RVVRegisterRegAlloc fastRegAllocRVVReg("fast", "fast register allocator",
createFastRVVRegisterAllocator);

class RISCVPassConfig : public TargetPassConfig {
public:
RISCVPassConfig(RISCVTargetMachine &TM, PassManagerBase &PM)
Expand Down Expand Up @@ -301,6 +377,9 @@ class RISCVPassConfig : public TargetPassConfig {
void addPreEmitPass2() override;
void addPreSched2() override;
void addMachineSSAOptimization() override;
FunctionPass *createRVVRegAllocPass(bool Optimized);
bool addRegAssignAndRewriteFast() override;
bool addRegAssignAndRewriteOptimized() override;
void addPreRegAlloc() override;
void addPostRegAlloc() override;
void addOptimizedRegAlloc() override;
Expand All @@ -312,6 +391,35 @@ TargetPassConfig *RISCVTargetMachine::createPassConfig(PassManagerBase &PM) {
return new RISCVPassConfig(*this, PM);
}

FunctionPass *RISCVPassConfig::createRVVRegAllocPass(bool Optimized) {
// Initialize the global default.
llvm::call_once(InitializeDefaultRVVRegisterAllocatorFlag,
initializeDefaultRVVRegisterAllocatorOnce);

RegisterRegAlloc::FunctionPassCtor Ctor = RVVRegisterRegAlloc::getDefault();
if (Ctor != useDefaultRegisterAllocator)
return Ctor();

if (Optimized)
return createGreedyRVVRegisterAllocator();

return createFastRVVRegisterAllocator();
}

bool RISCVPassConfig::addRegAssignAndRewriteFast() {
if (EnableSplitRegAlloc)
addPass(createRVVRegAllocPass(false));
return TargetPassConfig::addRegAssignAndRewriteFast();
}

bool RISCVPassConfig::addRegAssignAndRewriteOptimized() {
if (EnableSplitRegAlloc) {
addPass(createRVVRegAllocPass(true));
addPass(createVirtRegRewriter(false));
}
return TargetPassConfig::addRegAssignAndRewriteOptimized();
}

void RISCVPassConfig::addIRPasses() {
addPass(createAtomicExpandPass());

Expand Down