glasm: Release phi node registers after they are no longer needed
This commit is contained in:
parent
77ee733c3a
commit
48aafe0961
|
@ -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);
|
||||||
|
|
|
@ -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:
|
||||||
|
|
Reference in New Issue