mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 17:00:19 +02:00
Gets rid of potential extraneous copies. We also add handling for cases where two passes with the same name are unintentionally added. Previously we'd blindly overwrite the mapping.
131 lines
4.1 KiB
C++
131 lines
4.1 KiB
C++
// SPDX-License-Identifier: MIT
|
|
/*
|
|
$info$
|
|
meta: ir|opts ~ IR to IR Optimization
|
|
tags: ir|opts
|
|
desc: Defines which passes are run, and runs them
|
|
$end_info$
|
|
*/
|
|
|
|
#include "Interface/Context/Context.h"
|
|
#include "Interface/IR/PassManager.h"
|
|
#include "Interface/IR/Passes.h"
|
|
#include "Interface/IR/Passes/RegisterAllocationPass.h"
|
|
|
|
#include <FEXCore/Config/Config.h>
|
|
#include <FEXCore/Utils/LogManager.h>
|
|
#include <FEXCore/Utils/Profiler.h>
|
|
|
|
namespace FEXCore::IR {
|
|
class IREmitter;
|
|
|
|
void PassManager::Finalize() {
|
|
if (!PassManagerDumpIR()) {
|
|
// Not configured to dump any IR, just return.
|
|
return;
|
|
}
|
|
|
|
auto it = Passes.begin();
|
|
// Walk the passes and add them where asked.
|
|
if (PassManagerDumpIR() & FEXCore::Config::PassManagerDumpIR::BEFOREOPT) {
|
|
// Insert at the start.
|
|
it = InsertAt(it, Debug::CreateIRDumper());
|
|
++it; // Skip what we inserted.
|
|
}
|
|
|
|
if ((PassManagerDumpIR() & FEXCore::Config::PassManagerDumpIR::BEFOREPASS) ||
|
|
(PassManagerDumpIR() & FEXCore::Config::PassManagerDumpIR::AFTERPASS)) {
|
|
|
|
bool SkipFirstBefore = PassManagerDumpIR() & FEXCore::Config::PassManagerDumpIR::BEFOREOPT;
|
|
for (; it != Passes.end();) {
|
|
if (PassManagerDumpIR() & FEXCore::Config::PassManagerDumpIR::BEFOREPASS) {
|
|
if (SkipFirstBefore) {
|
|
// If we need to skip the first one, then continue.
|
|
SkipFirstBefore = false;
|
|
++it;
|
|
continue;
|
|
}
|
|
|
|
// Insert before
|
|
it = InsertAt(it, Debug::CreateIRDumper());
|
|
++it; // Skip what we inserted.
|
|
}
|
|
|
|
++it; // Skip current pass.
|
|
if (PassManagerDumpIR() & FEXCore::Config::PassManagerDumpIR::AFTERPASS) {
|
|
// Insert after
|
|
it = InsertAt(it, Debug::CreateIRDumper());
|
|
++it; // Skip what we inserted.
|
|
}
|
|
}
|
|
}
|
|
if (PassManagerDumpIR() & FEXCore::Config::PassManagerDumpIR::AFTEROPT) {
|
|
if (!(PassManagerDumpIR() & FEXCore::Config::PassManagerDumpIR::AFTERPASS)) {
|
|
// Insert final IRDumper.
|
|
InsertAt(Passes.end(), Debug::CreateIRDumper());
|
|
}
|
|
}
|
|
}
|
|
|
|
void PassManager::AddDefaultPasses(Context::ContextImpl* ctx) {
|
|
FEX_CONFIG_OPT(DisablePasses, O0);
|
|
|
|
// We only specifically disable optimization passes if desired, as IR output should
|
|
// still be well-formed regardless of the modifications made to it.
|
|
if (!DisablePasses()) {
|
|
InsertPass(CreateX87StackOptimizationPass(ctx->HostFeatures, ctx->Config.Is64BitMode ? IR::OpSize::i64Bit : IR::OpSize::i32Bit));
|
|
InsertPass(CreateDeadFlagCalculationEliminination());
|
|
}
|
|
|
|
InsertPass(IR::CreateRegisterAllocationPass(&ctx->CPUID), "RA");
|
|
|
|
#if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED
|
|
InsertValidationPass(Validation::CreateIRValidation(), "IRValidation");
|
|
#endif
|
|
}
|
|
|
|
Pass* PassManager::InsertPass(fextl::unique_ptr<Pass> Pass, const fextl::string& Name) {
|
|
auto* PassPtr = InsertAt(Passes.end(), std::move(Pass))->get();
|
|
AttemptNameMapping(Name, PassPtr);
|
|
return PassPtr;
|
|
}
|
|
|
|
PassManager::PassArrayType::iterator PassManager::InsertAt(PassArrayType::iterator pos, fextl::unique_ptr<Pass> Pass) {
|
|
Pass->RegisterPassManager(this);
|
|
return Passes.insert(pos, std::move(Pass));
|
|
}
|
|
|
|
#if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED
|
|
void PassManager::InsertValidationPass(fextl::unique_ptr<Pass> Pass, const fextl::string& Name) {
|
|
Pass->RegisterPassManager(this);
|
|
auto* PassPtr = ValidationPasses.emplace_back(std::move(Pass)).get();
|
|
AttemptNameMapping(Name, PassPtr);
|
|
}
|
|
#endif
|
|
|
|
void PassManager::Run(IREmitter* IREmit) {
|
|
FEXCORE_PROFILE_SCOPED("PassManager::Run");
|
|
|
|
for (const auto& Pass : Passes) {
|
|
Pass->Run(IREmit);
|
|
}
|
|
|
|
#if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED
|
|
for (const auto& Pass : ValidationPasses) {
|
|
Pass->Run(IREmit);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void PassManager::AttemptNameMapping(const fextl::string& Name, Pass* NewPass) {
|
|
if (Name.empty()) {
|
|
// Empty name is a 'don't care' case. e.g. Passes that just need to run,
|
|
// but don't need to be actively looked up.
|
|
return;
|
|
}
|
|
|
|
const auto Result = NameToPassMaping.emplace(Name, NewPass);
|
|
LOGMAN_THROW_A_FMT(Result.second, "Tried to insert pass with name '{}'. But name is already used", Name);
|
|
}
|
|
} // namespace FEXCore::IR
|