shader: Implement DADD
This commit is contained in:
parent
3b7fd3ad0f
commit
72990df7ba
|
@ -64,6 +64,7 @@ add_library(shader_recompiler STATIC
|
|||
frontend/maxwell/translate/impl/common_funcs.cpp
|
||||
frontend/maxwell/translate/impl/common_funcs.h
|
||||
frontend/maxwell/translate/impl/condition_code_set.cpp
|
||||
frontend/maxwell/translate/impl/double_add.cpp
|
||||
frontend/maxwell/translate/impl/find_leading_one.cpp
|
||||
frontend/maxwell/translate/impl/floating_point_add.cpp
|
||||
frontend/maxwell/translate/impl/floating_point_compare.cpp
|
||||
|
|
|
@ -94,6 +94,8 @@ Id EmitContext::Def(const IR::Value& value) {
|
|||
return Constant(U32[1], value.U32());
|
||||
case IR::Type::F32:
|
||||
return Constant(F32[1], value.F32());
|
||||
case IR::Type::F64:
|
||||
return Constant(F64[1], value.F64());
|
||||
default:
|
||||
throw NotImplementedException("Immediate type {}", value.Type());
|
||||
}
|
||||
|
|
|
@ -153,6 +153,14 @@ u64 Value::U64() const {
|
|||
return imm_u64;
|
||||
}
|
||||
|
||||
f64 Value::F64() const {
|
||||
if (IsIdentity()) {
|
||||
return inst->Arg(0).F64();
|
||||
}
|
||||
ValidateAccess(Type::F64);
|
||||
return imm_f64;
|
||||
}
|
||||
|
||||
bool Value::operator==(const Value& other) const {
|
||||
if (type != other.type) {
|
||||
return false;
|
||||
|
|
|
@ -52,6 +52,7 @@ public:
|
|||
[[nodiscard]] u32 U32() const;
|
||||
[[nodiscard]] f32 F32() const;
|
||||
[[nodiscard]] u64 U64() const;
|
||||
[[nodiscard]] f64 F64() const;
|
||||
|
||||
[[nodiscard]] bool operator==(const Value& other) const;
|
||||
[[nodiscard]] bool operator!=(const Value& other) const;
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "shader_recompiler/exception.h"
|
||||
#include "shader_recompiler/frontend/maxwell/translate/impl/common_encoding.h"
|
||||
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
|
||||
|
||||
namespace Shader::Maxwell {
|
||||
namespace {
|
||||
|
||||
void DADD(TranslatorVisitor& v, u64 insn, const IR::F64& src_b) {
|
||||
union {
|
||||
u64 raw;
|
||||
BitField<0, 8, IR::Reg> dest_reg;
|
||||
BitField<8, 8, IR::Reg> src_a_reg;
|
||||
BitField<39, 2, FpRounding> fp_rounding;
|
||||
BitField<45, 1, u64> neg_b;
|
||||
BitField<46, 1, u64> abs_a;
|
||||
BitField<47, 1, u64> cc;
|
||||
BitField<48, 1, u64> neg_a;
|
||||
BitField<49, 1, u64> abs_b;
|
||||
} const dadd{insn};
|
||||
|
||||
if (!IR::IsAligned(dadd.dest_reg, 2)) {
|
||||
throw NotImplementedException("Unaligned destination register {}", dadd.dest_reg.Value());
|
||||
}
|
||||
if (!IR::IsAligned(dadd.src_a_reg, 2)) {
|
||||
throw NotImplementedException("Unaligned destination register {}", dadd.src_a_reg.Value());
|
||||
}
|
||||
if (dadd.cc != 0) {
|
||||
throw NotImplementedException("DADD CC");
|
||||
}
|
||||
|
||||
const IR::Reg reg_a{dadd.src_a_reg};
|
||||
const IR::F64 src_a{v.ir.PackDouble2x32(v.ir.CompositeConstruct(v.X(reg_a), v.X(reg_a + 1)))};
|
||||
const IR::F64 op_a{v.ir.FPAbsNeg(src_a, dadd.abs_a != 0, dadd.neg_a != 0)};
|
||||
const IR::F64 op_b{v.ir.FPAbsNeg(src_b, dadd.abs_b != 0, dadd.neg_b != 0)};
|
||||
|
||||
IR::FpControl control{
|
||||
.no_contraction{true},
|
||||
.rounding{CastFpRounding(dadd.fp_rounding)},
|
||||
.fmz_mode{IR::FmzMode::None},
|
||||
};
|
||||
const IR::F64 value{v.ir.FPAdd(op_a, op_b, control)};
|
||||
const IR::Value result{v.ir.UnpackDouble2x32(value)};
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
v.X(dadd.dest_reg + i, IR::U32{v.ir.CompositeExtract(result, i)});
|
||||
}
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
void TranslatorVisitor::DADD_reg(u64 insn) {
|
||||
DADD(*this, insn, GetDoubleReg20(insn));
|
||||
}
|
||||
|
||||
void TranslatorVisitor::DADD_cbuf(u64 insn) {
|
||||
DADD(*this, insn, GetDoubleCbuf(insn));
|
||||
}
|
||||
|
||||
void TranslatorVisitor::DADD_imm(u64 insn) {
|
||||
DADD(*this, insn, GetDoubleImm20(insn));
|
||||
}
|
||||
|
||||
} // namespace Shader::Maxwell
|
|
@ -7,6 +7,15 @@
|
|||
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
|
||||
|
||||
namespace Shader::Maxwell {
|
||||
namespace {
|
||||
[[nodiscard]] IR::U32 CbufLowerBits(IR::IREmitter& ir, bool unaligned, const IR::U32& binding,
|
||||
u32 offset) {
|
||||
if (unaligned) {
|
||||
return ir.Imm32(0);
|
||||
}
|
||||
return ir.GetCbuf(binding, IR::U32{IR::Value{offset}});
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
IR::U32 TranslatorVisitor::X(IR::Reg reg) {
|
||||
return ir.GetReg(reg);
|
||||
|
@ -56,6 +65,18 @@ IR::F32 TranslatorVisitor::GetFloatReg39(u64 insn) {
|
|||
return ir.BitCast<IR::F32>(GetReg39(insn));
|
||||
}
|
||||
|
||||
IR::F64 TranslatorVisitor::GetDoubleReg20(u64 insn) {
|
||||
union {
|
||||
u64 raw;
|
||||
BitField<20, 8, IR::Reg> src;
|
||||
} const index{insn};
|
||||
const IR::Reg reg{index.src};
|
||||
if (!IR::IsAligned(reg, 2)) {
|
||||
throw NotImplementedException("Unaligned source register {}", reg);
|
||||
}
|
||||
return ir.PackDouble2x32(ir.CompositeConstruct(X(reg), X(reg + 1)));
|
||||
}
|
||||
|
||||
static std::pair<IR::U32, IR::U32> CbufAddr(u64 insn) {
|
||||
union {
|
||||
u64 raw;
|
||||
|
@ -84,6 +105,22 @@ IR::F32 TranslatorVisitor::GetFloatCbuf(u64 insn) {
|
|||
return ir.GetFloatCbuf(binding, byte_offset);
|
||||
}
|
||||
|
||||
IR::F64 TranslatorVisitor::GetDoubleCbuf(u64 insn) {
|
||||
union {
|
||||
u64 raw;
|
||||
BitField<20, 1, u64> unaligned;
|
||||
} const cbuf{insn};
|
||||
|
||||
const auto [binding, offset_value]{CbufAddr(insn)};
|
||||
const bool unaligned{cbuf.unaligned != 0};
|
||||
const u32 offset{offset_value.U32()};
|
||||
const IR::Value addr{unaligned ? offset | 4 : (offset & ~7) | 4};
|
||||
|
||||
const IR::U32 value{ir.GetCbuf(binding, IR::U32{addr})};
|
||||
const IR::U32 lower_bits{CbufLowerBits(ir, unaligned, binding, offset)};
|
||||
return ir.PackDouble2x32(ir.CompositeConstruct(lower_bits, value));
|
||||
}
|
||||
|
||||
IR::U32 TranslatorVisitor::GetImm20(u64 insn) {
|
||||
union {
|
||||
u64 raw;
|
||||
|
@ -110,6 +147,17 @@ IR::F32 TranslatorVisitor::GetFloatImm20(u64 insn) {
|
|||
return ir.Imm32(Common::BitCast<f32>(value | sign_bit));
|
||||
}
|
||||
|
||||
IR::F64 TranslatorVisitor::GetDoubleImm20(u64 insn) {
|
||||
union {
|
||||
u64 raw;
|
||||
BitField<20, 19, u64> value;
|
||||
BitField<56, 1, u64> is_negative;
|
||||
} const imm{insn};
|
||||
const u64 sign_bit{imm.is_negative != 0 ? (1ULL << 63) : 0};
|
||||
const u64 value{imm.value << 44};
|
||||
return ir.Imm64(Common::BitCast<f64>(value | sign_bit));
|
||||
}
|
||||
|
||||
IR::U32 TranslatorVisitor::GetImm32(u64 insn) {
|
||||
union {
|
||||
u64 raw;
|
||||
|
|
|
@ -351,12 +351,15 @@ public:
|
|||
[[nodiscard]] IR::U32 GetReg39(u64 insn);
|
||||
[[nodiscard]] IR::F32 GetFloatReg20(u64 insn);
|
||||
[[nodiscard]] IR::F32 GetFloatReg39(u64 insn);
|
||||
[[nodiscard]] IR::F64 GetDoubleReg20(u64 insn);
|
||||
|
||||
[[nodiscard]] IR::U32 GetCbuf(u64 insn);
|
||||
[[nodiscard]] IR::F32 GetFloatCbuf(u64 insn);
|
||||
[[nodiscard]] IR::F64 GetDoubleCbuf(u64 insn);
|
||||
|
||||
[[nodiscard]] IR::U32 GetImm20(u64 insn);
|
||||
[[nodiscard]] IR::F32 GetFloatImm20(u64 insn);
|
||||
[[nodiscard]] IR::F64 GetDoubleImm20(u64 insn);
|
||||
|
||||
[[nodiscard]] IR::U32 GetImm32(u64 insn);
|
||||
[[nodiscard]] IR::F32 GetFloatImm32(u64 insn);
|
||||
|
|
|
@ -85,18 +85,6 @@ void TranslatorVisitor::CS2R(u64) {
|
|||
ThrowNotImplemented(Opcode::CS2R);
|
||||
}
|
||||
|
||||
void TranslatorVisitor::DADD_reg(u64) {
|
||||
ThrowNotImplemented(Opcode::DADD_reg);
|
||||
}
|
||||
|
||||
void TranslatorVisitor::DADD_cbuf(u64) {
|
||||
ThrowNotImplemented(Opcode::DADD_cbuf);
|
||||
}
|
||||
|
||||
void TranslatorVisitor::DADD_imm(u64) {
|
||||
ThrowNotImplemented(Opcode::DADD_imm);
|
||||
}
|
||||
|
||||
void TranslatorVisitor::DEPBAR() {
|
||||
// DEPBAR is a no-op
|
||||
}
|
||||
|
|
Reference in New Issue