glasm: Initial GLASM fp64 support
This commit is contained in:
parent
9f851e3832
commit
4502595bc2
9 changed files with 152 additions and 55 deletions
|
@ -29,6 +29,13 @@ public:
|
||||||
code += '\n';
|
code += '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void LongAdd(const char* format_str, IR::Inst& inst, Args&&... args) {
|
||||||
|
code += fmt::format(format_str, reg_alloc.LongDefine(inst), std::forward<Args>(args)...);
|
||||||
|
// TODO: Remove this
|
||||||
|
code += '\n';
|
||||||
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
void Add(const char* format_str, Args&&... args) {
|
void Add(const char* format_str, Args&&... args) {
|
||||||
code += fmt::format(format_str, std::forward<Args>(args)...);
|
code += fmt::format(format_str, std::forward<Args>(args)...);
|
||||||
|
|
|
@ -42,7 +42,11 @@ template <bool scalar>
|
||||||
struct RegWrapper {
|
struct RegWrapper {
|
||||||
RegWrapper(EmitContext& ctx, Value value)
|
RegWrapper(EmitContext& ctx, Value value)
|
||||||
: reg_alloc{ctx.reg_alloc}, allocated{value.type != Type::Register} {
|
: reg_alloc{ctx.reg_alloc}, allocated{value.type != Type::Register} {
|
||||||
reg = allocated ? reg_alloc.AllocReg() : Register{value};
|
if (allocated) {
|
||||||
|
reg = value.type == Type::F64 ? reg_alloc.AllocLongReg() : reg_alloc.AllocReg();
|
||||||
|
} else {
|
||||||
|
reg = Register{value};
|
||||||
|
}
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
case Type::Register:
|
case Type::Register:
|
||||||
break;
|
break;
|
||||||
|
@ -55,6 +59,9 @@ struct RegWrapper {
|
||||||
case Type::F32:
|
case Type::F32:
|
||||||
ctx.Add("MOV.F {}.x,{};", reg, value.imm_f32);
|
ctx.Add("MOV.F {}.x,{};", reg, value.imm_f32);
|
||||||
break;
|
break;
|
||||||
|
case Type::F64:
|
||||||
|
ctx.Add("MOV.F64 {}.x,{};", reg, value.imm_f64);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
~RegWrapper() {
|
~RegWrapper() {
|
||||||
|
@ -162,10 +169,12 @@ std::string EmitGLASM(const Profile&, IR::Program& program, Bindings&) {
|
||||||
for (size_t index = 0; index < ctx.reg_alloc.NumUsedRegisters(); ++index) {
|
for (size_t index = 0; index < ctx.reg_alloc.NumUsedRegisters(); ++index) {
|
||||||
header += fmt::format("R{},", index);
|
header += fmt::format("R{},", index);
|
||||||
}
|
}
|
||||||
header += "RC;";
|
header += "RC;"
|
||||||
if (!program.info.storage_buffers_descriptors.empty()) {
|
"LONG TEMP ";
|
||||||
header += "LONG TEMP LC;";
|
for (size_t index = 0; index < ctx.reg_alloc.NumUsedLongRegisters(); ++index) {
|
||||||
|
header += fmt::format("D{},", index);
|
||||||
}
|
}
|
||||||
|
header += "DC;";
|
||||||
ctx.code.insert(0, header);
|
ctx.code.insert(0, header);
|
||||||
ctx.code += "END";
|
ctx.code += "END";
|
||||||
return ctx.code;
|
return ctx.code;
|
||||||
|
|
|
@ -72,4 +72,12 @@ void EmitUnpackHalf2x16(EmitContext& ctx, IR::Inst& inst, Register value) {
|
||||||
ctx.Add("UP2H {}.xy,{}.x;", inst, value);
|
ctx.Add("UP2H {}.xy,{}.x;", inst, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmitPackDouble2x32(EmitContext& ctx, IR::Inst& inst, Register value) {
|
||||||
|
ctx.LongAdd("PK64 {}.x,{};", inst, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmitUnpackDouble2x32(EmitContext& ctx, IR::Inst& inst, Register value) {
|
||||||
|
ctx.Add("UP64 {}.xy,{}.x;", inst, value);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Shader::Backend::GLASM
|
} // namespace Shader::Backend::GLASM
|
||||||
|
|
|
@ -10,7 +10,8 @@
|
||||||
|
|
||||||
namespace Shader::Backend::GLASM {
|
namespace Shader::Backend::GLASM {
|
||||||
|
|
||||||
void EmitFPAbs16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] Register value) {
|
void EmitFPAbs16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
|
||||||
|
[[maybe_unused]] Register value) {
|
||||||
throw NotImplementedException("GLASM instruction");
|
throw NotImplementedException("GLASM instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,8 +19,8 @@ void EmitFPAbs32(EmitContext& ctx, IR::Inst& inst, ScalarF32 value) {
|
||||||
ctx.Add("MOV.F {}.x,|{}|;", inst, value);
|
ctx.Add("MOV.F {}.x,|{}|;", inst, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitFPAbs64([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] Register value) {
|
void EmitFPAbs64(EmitContext& ctx, IR::Inst& inst, ScalarF64 value) {
|
||||||
throw NotImplementedException("GLASM instruction");
|
ctx.LongAdd("MOV.F64 {}.x,|{}|;", inst, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitFPAdd16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
|
void EmitFPAdd16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
|
||||||
|
@ -31,9 +32,8 @@ void EmitFPAdd32(EmitContext& ctx, IR::Inst& inst, ScalarF32 a, ScalarF32 b) {
|
||||||
ctx.Add("ADD.F {}.x,{},{};", inst, a, b);
|
ctx.Add("ADD.F {}.x,{},{};", inst, a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitFPAdd64([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
|
void EmitFPAdd64(EmitContext& ctx, IR::Inst& inst, ScalarF64 a, ScalarF64 b) {
|
||||||
[[maybe_unused]] Register a, [[maybe_unused]] Register b) {
|
ctx.LongAdd("ADD.F64 {}.x,{},{};", inst, a, b);
|
||||||
throw NotImplementedException("GLASM instruction");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitFPFma16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
|
void EmitFPFma16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
|
||||||
|
@ -94,8 +94,8 @@ void EmitFPNeg32(EmitContext& ctx, IR::Inst& inst, ScalarRegister value) {
|
||||||
ctx.Add("MOV.F {}.x,-{};", inst, value);
|
ctx.Add("MOV.F {}.x,-{};", inst, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitFPNeg64([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] Register value) {
|
void EmitFPNeg64(EmitContext& ctx, IR::Inst& inst, Register value) {
|
||||||
throw NotImplementedException("GLASM instruction");
|
ctx.LongAdd("MOV.F64 {}.x,-{};", inst, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitFPSin([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] ScalarF32 value) {
|
void EmitFPSin([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] ScalarF32 value) {
|
||||||
|
|
|
@ -202,20 +202,20 @@ void EmitPackFloat2x16(EmitContext& ctx, Register value);
|
||||||
void EmitUnpackFloat2x16(EmitContext& ctx, Register value);
|
void EmitUnpackFloat2x16(EmitContext& ctx, Register value);
|
||||||
void EmitPackHalf2x16(EmitContext& ctx, IR::Inst& inst, Register value);
|
void EmitPackHalf2x16(EmitContext& ctx, IR::Inst& inst, Register value);
|
||||||
void EmitUnpackHalf2x16(EmitContext& ctx, IR::Inst& inst, Register value);
|
void EmitUnpackHalf2x16(EmitContext& ctx, IR::Inst& inst, Register value);
|
||||||
void EmitPackDouble2x32(EmitContext& ctx, Register value);
|
void EmitPackDouble2x32(EmitContext& ctx, IR::Inst& inst, Register value);
|
||||||
void EmitUnpackDouble2x32(EmitContext& ctx, Register value);
|
void EmitUnpackDouble2x32(EmitContext& ctx, IR::Inst& inst, Register value);
|
||||||
void EmitGetZeroFromOp(EmitContext& ctx);
|
void EmitGetZeroFromOp(EmitContext& ctx);
|
||||||
void EmitGetSignFromOp(EmitContext& ctx);
|
void EmitGetSignFromOp(EmitContext& ctx);
|
||||||
void EmitGetCarryFromOp(EmitContext& ctx);
|
void EmitGetCarryFromOp(EmitContext& ctx);
|
||||||
void EmitGetOverflowFromOp(EmitContext& ctx);
|
void EmitGetOverflowFromOp(EmitContext& ctx);
|
||||||
void EmitGetSparseFromOp(EmitContext& ctx);
|
void EmitGetSparseFromOp(EmitContext& ctx);
|
||||||
void EmitGetInBoundsFromOp(EmitContext& ctx);
|
void EmitGetInBoundsFromOp(EmitContext& ctx);
|
||||||
void EmitFPAbs16(EmitContext& ctx, Register value);
|
void EmitFPAbs16(EmitContext& ctx, IR::Inst& inst, Register value);
|
||||||
void EmitFPAbs32(EmitContext& ctx, IR::Inst& inst, ScalarF32 value);
|
void EmitFPAbs32(EmitContext& ctx, IR::Inst& inst, ScalarF32 value);
|
||||||
void EmitFPAbs64(EmitContext& ctx, Register value);
|
void EmitFPAbs64(EmitContext& ctx, IR::Inst& inst, ScalarF64 value);
|
||||||
void EmitFPAdd16(EmitContext& ctx, IR::Inst& inst, Register a, Register b);
|
void EmitFPAdd16(EmitContext& ctx, IR::Inst& inst, Register a, Register b);
|
||||||
void EmitFPAdd32(EmitContext& ctx, IR::Inst& inst, ScalarF32 a, ScalarF32 b);
|
void EmitFPAdd32(EmitContext& ctx, IR::Inst& inst, ScalarF32 a, ScalarF32 b);
|
||||||
void EmitFPAdd64(EmitContext& ctx, IR::Inst& inst, Register a, Register b);
|
void EmitFPAdd64(EmitContext& ctx, IR::Inst& inst, ScalarF64 a, ScalarF64 b);
|
||||||
void EmitFPFma16(EmitContext& ctx, IR::Inst& inst, Register a, Register b, Register c);
|
void EmitFPFma16(EmitContext& ctx, IR::Inst& inst, Register a, Register b, Register c);
|
||||||
void EmitFPFma32(EmitContext& ctx, IR::Inst& inst, ScalarF32 a, ScalarF32 b, ScalarF32 c);
|
void EmitFPFma32(EmitContext& ctx, IR::Inst& inst, ScalarF32 a, ScalarF32 b, ScalarF32 c);
|
||||||
void EmitFPFma64(EmitContext& ctx, IR::Inst& inst, Register a, Register b, Register c);
|
void EmitFPFma64(EmitContext& ctx, IR::Inst& inst, Register a, Register b, Register c);
|
||||||
|
@ -228,7 +228,7 @@ void EmitFPMul32(EmitContext& ctx, IR::Inst& inst, ScalarF32 a, ScalarF32 b);
|
||||||
void EmitFPMul64(EmitContext& ctx, IR::Inst& inst, Register a, Register b);
|
void EmitFPMul64(EmitContext& ctx, IR::Inst& inst, Register a, Register b);
|
||||||
void EmitFPNeg16(EmitContext& ctx, Register value);
|
void EmitFPNeg16(EmitContext& ctx, Register value);
|
||||||
void EmitFPNeg32(EmitContext& ctx, IR::Inst& inst, ScalarRegister value);
|
void EmitFPNeg32(EmitContext& ctx, IR::Inst& inst, ScalarRegister value);
|
||||||
void EmitFPNeg64(EmitContext& ctx, Register value);
|
void EmitFPNeg64(EmitContext& ctx, IR::Inst& inst, Register value);
|
||||||
void EmitFPSin(EmitContext& ctx, ScalarF32 value);
|
void EmitFPSin(EmitContext& ctx, ScalarF32 value);
|
||||||
void EmitFPCos(EmitContext& ctx, ScalarF32 value);
|
void EmitFPCos(EmitContext& ctx, ScalarF32 value);
|
||||||
void EmitFPExp2(EmitContext& ctx, ScalarF32 value);
|
void EmitFPExp2(EmitContext& ctx, ScalarF32 value);
|
||||||
|
|
|
@ -17,9 +17,9 @@ void StorageOp(EmitContext& ctx, const IR::Value& binding, ScalarU32 offset,
|
||||||
// address = c[binding].xy
|
// address = c[binding].xy
|
||||||
// length = c[binding].z
|
// length = c[binding].z
|
||||||
const u32 sb_binding{binding.U32()};
|
const u32 sb_binding{binding.U32()};
|
||||||
ctx.Add("PK64.U LC,c[{}];" // pointer = address
|
ctx.Add("PK64.U DC,c[{}];" // pointer = address
|
||||||
"CVT.U64.U32 LC.z,{};" // offset = uint64_t(offset)
|
"CVT.U64.U32 DC.z,{};" // offset = uint64_t(offset)
|
||||||
"ADD.U64 LC.x,LC.x,LC.z;" // pointer += offset
|
"ADD.U64 DC.x,DC.x,DC.z;" // pointer += offset
|
||||||
"SLT.U.CC RC.x,{},c[{}].z;", // cc = offset < length
|
"SLT.U.CC RC.x,{},c[{}].z;", // cc = offset < length
|
||||||
sb_binding, offset, offset, sb_binding);
|
sb_binding, offset, offset, sb_binding);
|
||||||
if (else_expr.empty()) {
|
if (else_expr.empty()) {
|
||||||
|
@ -32,13 +32,13 @@ void StorageOp(EmitContext& ctx, const IR::Value& binding, ScalarU32 offset,
|
||||||
template <typename ValueType>
|
template <typename ValueType>
|
||||||
void Store(EmitContext& ctx, const IR::Value& binding, ScalarU32 offset, ValueType value,
|
void Store(EmitContext& ctx, const IR::Value& binding, ScalarU32 offset, ValueType value,
|
||||||
std::string_view size) {
|
std::string_view size) {
|
||||||
StorageOp(ctx, binding, offset, fmt::format("STORE.{} {},LC.x;", size, value));
|
StorageOp(ctx, binding, offset, fmt::format("STORE.{} {},DC.x;", size, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Load(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset,
|
void Load(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset,
|
||||||
std::string_view size) {
|
std::string_view size) {
|
||||||
const Register ret{ctx.reg_alloc.Define(inst)};
|
const Register ret{ctx.reg_alloc.Define(inst)};
|
||||||
StorageOp(ctx, binding, offset, fmt::format("STORE.{} {},LC.x;", size, ret),
|
StorageOp(ctx, binding, offset, fmt::format("STORE.{} {},DC.x;", size, ret),
|
||||||
fmt::format("MOV.U {},{{0,0,0,0}};", ret));
|
fmt::format("MOV.U {},{{0,0,0,0}};", ret));
|
||||||
}
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
|
@ -281,14 +281,6 @@ void EmitSelectF64(EmitContext& ctx, ScalarS32 cond, Register true_value, Regist
|
||||||
NotImplemented();
|
NotImplemented();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitPackDouble2x32(EmitContext& ctx, Register value) {
|
|
||||||
NotImplemented();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmitUnpackDouble2x32(EmitContext& ctx, Register value) {
|
|
||||||
NotImplemented();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmitGetZeroFromOp(EmitContext& ctx) {
|
void EmitGetZeroFromOp(EmitContext& ctx) {
|
||||||
NotImplemented();
|
NotImplemented();
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,12 +14,11 @@
|
||||||
namespace Shader::Backend::GLASM {
|
namespace Shader::Backend::GLASM {
|
||||||
|
|
||||||
Register RegAlloc::Define(IR::Inst& inst) {
|
Register RegAlloc::Define(IR::Inst& inst) {
|
||||||
const Id id{Alloc()};
|
return Define(inst, false);
|
||||||
inst.SetDefinition<Id>(id);
|
}
|
||||||
Register ret;
|
|
||||||
ret.type = Type::Register;
|
Register RegAlloc::LongDefine(IR::Inst& inst) {
|
||||||
ret.id = id;
|
return Define(inst, true);
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Value RegAlloc::Consume(const IR::Value& value) {
|
Value RegAlloc::Consume(const IR::Value& value) {
|
||||||
|
@ -40,6 +39,10 @@ Value RegAlloc::Consume(const IR::Value& value) {
|
||||||
ret.type = Type::F32;
|
ret.type = Type::F32;
|
||||||
ret.imm_f32 = value.F32();
|
ret.imm_f32 = value.F32();
|
||||||
break;
|
break;
|
||||||
|
case IR::Type::F64:
|
||||||
|
ret.type = Type::F64;
|
||||||
|
ret.imm_f64 = value.F64();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw NotImplementedException("Immediate type {}", value.Type());
|
throw NotImplementedException("Immediate type {}", value.Type());
|
||||||
}
|
}
|
||||||
|
@ -49,7 +52,14 @@ Value RegAlloc::Consume(const IR::Value& value) {
|
||||||
Register RegAlloc::AllocReg() {
|
Register RegAlloc::AllocReg() {
|
||||||
Register ret;
|
Register ret;
|
||||||
ret.type = Type::Register;
|
ret.type = Type::Register;
|
||||||
ret.id = Alloc();
|
ret.id = Alloc(false);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Register RegAlloc::AllocLongReg() {
|
||||||
|
Register ret;
|
||||||
|
ret.type = Type::Register;
|
||||||
|
ret.id = Alloc(true);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,6 +67,15 @@ void RegAlloc::FreeReg(Register reg) {
|
||||||
Free(reg.id);
|
Free(reg.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Register RegAlloc::Define(IR::Inst& inst, bool is_long) {
|
||||||
|
const Id id{Alloc(is_long)};
|
||||||
|
inst.SetDefinition<Id>(id);
|
||||||
|
Register ret;
|
||||||
|
ret.type = Type::Register;
|
||||||
|
ret.id = id;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
Value RegAlloc::Consume(IR::Inst& inst) {
|
Value RegAlloc::Consume(IR::Inst& inst) {
|
||||||
const Id id{inst.Definition<Id>()};
|
const Id id{inst.Definition<Id>()};
|
||||||
inst.DestructiveRemoveUsage();
|
inst.DestructiveRemoveUsage();
|
||||||
|
@ -69,19 +88,24 @@ Value RegAlloc::Consume(IR::Inst& inst) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Id RegAlloc::Alloc() {
|
Id RegAlloc::Alloc(bool is_long) {
|
||||||
|
size_t& num_regs{is_long ? num_used_long_registers : num_used_registers};
|
||||||
|
std::bitset<NUM_REGS>& use{is_long ? long_register_use : register_use};
|
||||||
|
if (num_used_registers + num_used_long_registers < NUM_REGS) {
|
||||||
for (size_t reg = 0; reg < NUM_REGS; ++reg) {
|
for (size_t reg = 0; reg < NUM_REGS; ++reg) {
|
||||||
if (register_use[reg]) {
|
if (use[reg]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
num_used_registers = std::max(num_used_registers, reg + 1);
|
num_regs = std::max(num_regs, reg + 1);
|
||||||
register_use[reg] = true;
|
use[reg] = true;
|
||||||
Id ret{};
|
Id ret{};
|
||||||
ret.index.Assign(static_cast<u32>(reg));
|
ret.index.Assign(static_cast<u32>(reg));
|
||||||
|
ret.is_long.Assign(is_long ? 1 : 0);
|
||||||
ret.is_spill.Assign(0);
|
ret.is_spill.Assign(0);
|
||||||
ret.is_condition_code.Assign(0);
|
ret.is_condition_code.Assign(0);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
throw NotImplementedException("Register spilling");
|
throw NotImplementedException("Register spilling");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,7 +113,11 @@ void RegAlloc::Free(Id id) {
|
||||||
if (id.is_spill != 0) {
|
if (id.is_spill != 0) {
|
||||||
throw NotImplementedException("Free spill");
|
throw NotImplementedException("Free spill");
|
||||||
}
|
}
|
||||||
|
if (id.is_long != 0) {
|
||||||
|
long_register_use[id.index] = false;
|
||||||
|
} else {
|
||||||
register_use[id.index] = false;
|
register_use[id.index] = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Shader::Backend::GLASM
|
} // namespace Shader::Backend::GLASM
|
||||||
|
|
|
@ -27,12 +27,14 @@ enum class Type : u32 {
|
||||||
U32,
|
U32,
|
||||||
S32,
|
S32,
|
||||||
F32,
|
F32,
|
||||||
|
F64,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Id {
|
struct Id {
|
||||||
union {
|
union {
|
||||||
u32 raw;
|
u32 raw;
|
||||||
BitField<0, 30, u32> index;
|
BitField<0, 29, u32> index;
|
||||||
|
BitField<29, 1, u32> is_long;
|
||||||
BitField<30, 1, u32> is_spill;
|
BitField<30, 1, u32> is_spill;
|
||||||
BitField<31, 1, u32> is_condition_code;
|
BitField<31, 1, u32> is_condition_code;
|
||||||
};
|
};
|
||||||
|
@ -53,6 +55,7 @@ struct Value {
|
||||||
u32 imm_u32;
|
u32 imm_u32;
|
||||||
s32 imm_s32;
|
s32 imm_s32;
|
||||||
f32 imm_f32;
|
f32 imm_f32;
|
||||||
|
f64 imm_f64;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool operator==(const Value& rhs) const noexcept {
|
bool operator==(const Value& rhs) const noexcept {
|
||||||
|
@ -68,6 +71,8 @@ struct Value {
|
||||||
return imm_s32 == rhs.imm_s32;
|
return imm_s32 == rhs.imm_s32;
|
||||||
case Type::F32:
|
case Type::F32:
|
||||||
return Common::BitCast<u32>(imm_f32) == Common::BitCast<u32>(rhs.imm_f32);
|
return Common::BitCast<u32>(imm_f32) == Common::BitCast<u32>(rhs.imm_f32);
|
||||||
|
case Type::F64:
|
||||||
|
return Common::BitCast<u64>(imm_f64) == Common::BitCast<u64>(rhs.imm_f64);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -80,6 +85,7 @@ struct ScalarRegister : Value {};
|
||||||
struct ScalarU32 : Value {};
|
struct ScalarU32 : Value {};
|
||||||
struct ScalarS32 : Value {};
|
struct ScalarS32 : Value {};
|
||||||
struct ScalarF32 : Value {};
|
struct ScalarF32 : Value {};
|
||||||
|
struct ScalarF64 : Value {};
|
||||||
|
|
||||||
class RegAlloc {
|
class RegAlloc {
|
||||||
public:
|
public:
|
||||||
|
@ -87,9 +93,13 @@ public:
|
||||||
|
|
||||||
Register Define(IR::Inst& inst);
|
Register Define(IR::Inst& inst);
|
||||||
|
|
||||||
|
Register LongDefine(IR::Inst& inst);
|
||||||
|
|
||||||
Value Consume(const IR::Value& value);
|
Value Consume(const IR::Value& value);
|
||||||
|
|
||||||
Register AllocReg();
|
[[nodiscard]] Register AllocReg();
|
||||||
|
|
||||||
|
[[nodiscard]] Register AllocLongReg();
|
||||||
|
|
||||||
void FreeReg(Register reg);
|
void FreeReg(Register reg);
|
||||||
|
|
||||||
|
@ -97,19 +107,27 @@ public:
|
||||||
return num_used_registers;
|
return num_used_registers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] size_t NumUsedLongRegisters() const noexcept {
|
||||||
|
return num_used_long_registers;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr size_t NUM_REGS = 4096;
|
static constexpr size_t NUM_REGS = 4096;
|
||||||
static constexpr size_t NUM_ELEMENTS = 4;
|
static constexpr size_t NUM_ELEMENTS = 4;
|
||||||
|
|
||||||
|
Register Define(IR::Inst& inst, bool is_long);
|
||||||
|
|
||||||
Value Consume(IR::Inst& inst);
|
Value Consume(IR::Inst& inst);
|
||||||
|
|
||||||
Id Alloc();
|
Id Alloc(bool is_long);
|
||||||
|
|
||||||
void Free(Id id);
|
void Free(Id id);
|
||||||
|
|
||||||
EmitContext& ctx;
|
EmitContext& ctx;
|
||||||
size_t num_used_registers{};
|
size_t num_used_registers{};
|
||||||
|
size_t num_used_long_registers{};
|
||||||
std::bitset<NUM_REGS> register_use{};
|
std::bitset<NUM_REGS> register_use{};
|
||||||
|
std::bitset<NUM_REGS> long_register_use{};
|
||||||
};
|
};
|
||||||
|
|
||||||
template <bool scalar, typename FormatContext>
|
template <bool scalar, typename FormatContext>
|
||||||
|
@ -121,11 +139,19 @@ auto FormatTo(FormatContext& ctx, Id id) {
|
||||||
throw NotImplementedException("Spill emission");
|
throw NotImplementedException("Spill emission");
|
||||||
}
|
}
|
||||||
if constexpr (scalar) {
|
if constexpr (scalar) {
|
||||||
|
if (id.is_long != 0) {
|
||||||
|
return fmt::format_to(ctx.out(), "D{}.x", id.index.Value());
|
||||||
|
} else {
|
||||||
return fmt::format_to(ctx.out(), "R{}.x", id.index.Value());
|
return fmt::format_to(ctx.out(), "R{}.x", id.index.Value());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (id.is_long != 0) {
|
||||||
|
return fmt::format_to(ctx.out(), "D{}", id.index.Value());
|
||||||
} else {
|
} else {
|
||||||
return fmt::format_to(ctx.out(), "R{}", id.index.Value());
|
return fmt::format_to(ctx.out(), "R{}", id.index.Value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Shader::Backend::GLASM
|
} // namespace Shader::Backend::GLASM
|
||||||
|
|
||||||
|
@ -184,6 +210,8 @@ struct fmt::formatter<Shader::Backend::GLASM::ScalarU32> {
|
||||||
return fmt::format_to(ctx.out(), "{}", static_cast<u32>(value.imm_s32));
|
return fmt::format_to(ctx.out(), "{}", static_cast<u32>(value.imm_s32));
|
||||||
case Shader::Backend::GLASM::Type::F32:
|
case Shader::Backend::GLASM::Type::F32:
|
||||||
return fmt::format_to(ctx.out(), "{}", Common::BitCast<u32>(value.imm_f32));
|
return fmt::format_to(ctx.out(), "{}", Common::BitCast<u32>(value.imm_f32));
|
||||||
|
case Shader::Backend::GLASM::Type::F64:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
throw Shader::InvalidArgument("Invalid value type {}", value.type);
|
throw Shader::InvalidArgument("Invalid value type {}", value.type);
|
||||||
}
|
}
|
||||||
|
@ -205,6 +233,8 @@ struct fmt::formatter<Shader::Backend::GLASM::ScalarS32> {
|
||||||
return fmt::format_to(ctx.out(), "{}", value.imm_s32);
|
return fmt::format_to(ctx.out(), "{}", value.imm_s32);
|
||||||
case Shader::Backend::GLASM::Type::F32:
|
case Shader::Backend::GLASM::Type::F32:
|
||||||
return fmt::format_to(ctx.out(), "{}", Common::BitCast<s32>(value.imm_f32));
|
return fmt::format_to(ctx.out(), "{}", Common::BitCast<s32>(value.imm_f32));
|
||||||
|
case Shader::Backend::GLASM::Type::F64:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
throw Shader::InvalidArgument("Invalid value type {}", value.type);
|
throw Shader::InvalidArgument("Invalid value type {}", value.type);
|
||||||
}
|
}
|
||||||
|
@ -226,6 +256,29 @@ struct fmt::formatter<Shader::Backend::GLASM::ScalarF32> {
|
||||||
return fmt::format_to(ctx.out(), "{}", Common::BitCast<s32>(value.imm_s32));
|
return fmt::format_to(ctx.out(), "{}", Common::BitCast<s32>(value.imm_s32));
|
||||||
case Shader::Backend::GLASM::Type::F32:
|
case Shader::Backend::GLASM::Type::F32:
|
||||||
return fmt::format_to(ctx.out(), "{}", value.imm_f32);
|
return fmt::format_to(ctx.out(), "{}", value.imm_f32);
|
||||||
|
case Shader::Backend::GLASM::Type::F64:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
throw Shader::InvalidArgument("Invalid value type {}", value.type);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct fmt::formatter<Shader::Backend::GLASM::ScalarF64> {
|
||||||
|
constexpr auto parse(format_parse_context& ctx) {
|
||||||
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const Shader::Backend::GLASM::ScalarF64& value, FormatContext& ctx) {
|
||||||
|
switch (value.type) {
|
||||||
|
case Shader::Backend::GLASM::Type::Register:
|
||||||
|
return Shader::Backend::GLASM::FormatTo<true>(ctx, value.id);
|
||||||
|
case Shader::Backend::GLASM::Type::U32:
|
||||||
|
case Shader::Backend::GLASM::Type::S32:
|
||||||
|
case Shader::Backend::GLASM::Type::F32:
|
||||||
|
break;
|
||||||
|
case Shader::Backend::GLASM::Type::F64:
|
||||||
|
return format_to(ctx.out(), "{}", value.imm_f64);
|
||||||
}
|
}
|
||||||
throw Shader::InvalidArgument("Invalid value type {}", value.type);
|
throw Shader::InvalidArgument("Invalid value type {}", value.type);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue