yuzu-emu
/
yuzu-android
Archived
1
0
Fork 0

glasm: Release phi node registers after they are no longer needed

This commit is contained in:
ReinUsesLisp 2021-05-25 17:37:35 -03:00 committed by ameerj
parent 77ee733c3a
commit 48aafe0961
2 changed files with 54 additions and 38 deletions

View File

@ -172,38 +172,29 @@ bool IsReference(IR::Inst& inst) {
return inst.GetOpcode() == IR::Opcode::Reference; return inst.GetOpcode() == IR::Opcode::Reference;
} }
void Precolor(EmitContext& ctx, const IR::Program& program) { void PrecolorInst(IR::Inst& phi) {
// Insert phi moves before references to avoid overwritting other phis
const size_t num_args{phi.NumArgs()};
for (size_t i = 0; i < num_args; ++i) {
IR::Block& phi_block{*phi.PhiBlock(i)};
auto it{std::find_if_not(phi_block.rbegin(), phi_block.rend(), IsReference).base()};
IR::IREmitter ir{phi_block, it};
const IR::Value arg{phi.Arg(i)};
if (arg.IsImmediate()) {
ir.PhiMove(phi, arg);
} else {
ir.PhiMove(phi, IR::Value{&RegAlloc::AliasInst(*arg.Inst())});
}
}
for (size_t i = 0; i < num_args; ++i) {
IR::IREmitter{*phi.PhiBlock(i)}.Reference(IR::Value{&phi});
}
}
void Precolor(const IR::Program& program) {
for (IR::Block* const block : program.blocks) { for (IR::Block* const block : program.blocks) {
for (IR::Inst& phi : block->Instructions() | std::views::take_while(IR::IsPhi)) { for (IR::Inst& phi : block->Instructions() | std::views::take_while(IR::IsPhi)) {
switch (phi.Arg(0).Type()) { PrecolorInst(phi);
case IR::Type::U1:
case IR::Type::U32:
case IR::Type::F32:
ctx.reg_alloc.Define(phi);
break;
case IR::Type::U64:
case IR::Type::F64:
ctx.reg_alloc.LongDefine(phi);
break;
default:
throw NotImplementedException("Phi node type {}", phi.Type());
}
// Insert phi moves before references to avoid overwritting them
const size_t num_args{phi.NumArgs()};
for (size_t i = 0; i < num_args; ++i) {
IR::Block& phi_block{*phi.PhiBlock(i)};
auto it{std::find_if_not(phi_block.rbegin(), phi_block.rend(), IsReference).base()};
IR::IREmitter ir{phi_block, it};
const IR::Value arg{phi.Arg(i)};
if (arg.IsImmediate()) {
ir.PhiMove(phi, arg);
} else {
ir.PhiMove(phi, IR::Value{&RegAlloc::AliasInst(*arg.Inst())});
}
}
for (size_t i = 0; i < num_args; ++i) {
IR::IREmitter{*phi.PhiBlock(i)}.Reference(IR::Value{&phi});
}
} }
} }
} }
@ -388,7 +379,7 @@ std::string_view GetTessSpacing(TessSpacing spacing) {
std::string EmitGLASM(const Profile& profile, const RuntimeInfo& runtime_info, IR::Program& program, std::string EmitGLASM(const Profile& profile, const RuntimeInfo& runtime_info, IR::Program& program,
Bindings& bindings) { Bindings& bindings) {
EmitContext ctx{program, bindings, profile, runtime_info}; EmitContext ctx{program, bindings, profile, runtime_info};
Precolor(ctx, program); Precolor(program);
EmitCode(ctx, program); EmitCode(ctx, program);
std::string header{StageHeader(program.stage)}; std::string header{StageHeader(program.stage)};
SetupOptions(program, profile, runtime_info, header); SetupOptions(program, profile, runtime_info, header);

View File

@ -17,10 +17,30 @@ namespace Shader::Backend::GLASM {
#define NotImplemented() throw NotImplementedException("GLASM instruction {}", __LINE__) #define NotImplemented() throw NotImplementedException("GLASM instruction {}", __LINE__)
void EmitPhi(EmitContext& ctx, IR::Inst& inst) { static void DefinePhi(EmitContext& ctx, IR::Inst& phi) {
const size_t num_args{inst.NumArgs()}; switch (phi.Arg(0).Type()) {
case IR::Type::U1:
case IR::Type::U32:
case IR::Type::F32:
ctx.reg_alloc.Define(phi);
break;
case IR::Type::U64:
case IR::Type::F64:
ctx.reg_alloc.LongDefine(phi);
break;
default:
throw NotImplementedException("Phi node type {}", phi.Type());
}
}
void EmitPhi(EmitContext& ctx, IR::Inst& phi) {
const size_t num_args{phi.NumArgs()};
for (size_t i = 0; i < num_args; ++i) { for (size_t i = 0; i < num_args; ++i) {
ctx.reg_alloc.Consume(inst.Arg(i)); ctx.reg_alloc.Consume(phi.Arg(i));
}
if (!phi.Definition<Id>().is_valid) {
// The phi node wasn't forward defined
DefinePhi(ctx, phi);
} }
} }
@ -30,14 +50,19 @@ void EmitReference(EmitContext& ctx, const IR::Value& value) {
ctx.reg_alloc.Consume(value); ctx.reg_alloc.Consume(value);
} }
void EmitPhiMove(EmitContext& ctx, const IR::Value& phi, const IR::Value& value) { void EmitPhiMove(EmitContext& ctx, const IR::Value& phi_value, const IR::Value& value) {
const Register phi_reg{ctx.reg_alloc.Consume(phi)}; IR::Inst& phi{RegAlloc::AliasInst(*phi_value.Inst())};
if (!phi.Definition<Id>().is_valid) {
// The phi node wasn't forward defined
DefinePhi(ctx, phi);
}
const Register phi_reg{ctx.reg_alloc.Consume(IR::Value{&phi})};
const Value eval_value{ctx.reg_alloc.Consume(value)}; const Value eval_value{ctx.reg_alloc.Consume(value)};
if (phi == value) { if (phi_reg == eval_value) {
return; return;
} }
switch (phi.Inst()->Flags<IR::Type>()) { switch (phi.Flags<IR::Type>()) {
case IR::Type::U1: case IR::Type::U1:
case IR::Type::U32: case IR::Type::U32:
case IR::Type::F32: case IR::Type::F32: