shader: Initial recompiler work

This commit is contained in:
ReinUsesLisp 2021-01-09 03:30:07 -03:00 committed by ameerj
parent 75059c46d6
commit 2d48a7b4d0
57 changed files with 7061 additions and 0 deletions

View file

@ -0,0 +1,15 @@
// 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/impl.h"
namespace Shader::Maxwell {
void TranslatorVisitor::EXIT(u64) {
ir.Exit();
}
} // namespace Shader::Maxwell

View file

@ -0,0 +1,133 @@
// 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/opcode.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
namespace Shader::Maxwell {
namespace {
enum class DestFormat : u64 {
Invalid,
I16,
I32,
I64,
};
enum class SrcFormat : u64 {
Invalid,
F16,
F32,
F64,
};
enum class Rounding : u64 {
Round,
Floor,
Ceil,
Trunc,
};
union F2I {
u64 raw;
BitField<0, 8, IR::Reg> dest_reg;
BitField<8, 2, DestFormat> dest_format;
BitField<10, 2, SrcFormat> src_format;
BitField<12, 1, u64> is_signed;
BitField<39, 1, Rounding> rounding;
BitField<49, 1, u64> half;
BitField<44, 1, u64> ftz;
BitField<45, 1, u64> abs;
BitField<47, 1, u64> cc;
BitField<49, 1, u64> neg;
};
size_t BitSize(DestFormat dest_format) {
switch (dest_format) {
case DestFormat::I16:
return 16;
case DestFormat::I32:
return 32;
case DestFormat::I64:
return 64;
default:
throw NotImplementedException("Invalid destination format {}", dest_format);
}
}
void TranslateF2I(TranslatorVisitor& v, u64 insn, const IR::U16U32U64& op_a) {
// F2I is used to convert from a floating point value to an integer
const F2I f2i{insn};
const IR::U16U32U64 float_value{v.ir.FPAbsNeg(op_a, f2i.abs != 0, f2i.neg != 0)};
const IR::U16U32U64 rounded_value{[&] {
switch (f2i.rounding) {
case Rounding::Round:
return v.ir.FPRoundEven(float_value);
case Rounding::Floor:
return v.ir.FPFloor(float_value);
case Rounding::Ceil:
return v.ir.FPCeil(float_value);
case Rounding::Trunc:
return v.ir.FPTrunc(float_value);
default:
throw NotImplementedException("Invalid F2I rounding {}", f2i.rounding.Value());
}
}()};
// TODO: Handle out of bounds conversions.
// For example converting F32 65537.0 to U16, the expected value is 0xffff,
const bool is_signed{f2i.is_signed != 0};
const size_t bitsize{BitSize(f2i.dest_format)};
const IR::U16U32U64 result{v.ir.ConvertFToI(bitsize, is_signed, rounded_value)};
v.X(f2i.dest_reg, result);
if (f2i.cc != 0) {
v.SetZFlag(v.ir.GetZeroFromOp(result));
if (is_signed) {
v.SetSFlag(v.ir.GetSignFromOp(result));
} else {
v.ResetSFlag();
}
v.ResetCFlag();
// TODO: Investigate if out of bound conversions sets the overflow flag
v.ResetOFlag();
}
}
} // Anonymous namespace
void TranslatorVisitor::F2I_reg(u64 insn) {
union {
F2I base;
BitField<20, 8, IR::Reg> src_reg;
} const f2i{insn};
const IR::U16U32U64 op_a{[&]() -> IR::U16U32U64 {
switch (f2i.base.src_format) {
case SrcFormat::F16:
return ir.CompositeExtract(ir.UnpackFloat2x16(X(f2i.src_reg)), f2i.base.half);
case SrcFormat::F32:
return X(f2i.src_reg);
case SrcFormat::F64:
return ir.PackDouble2x32(ir.CompositeConstruct(X(f2i.src_reg), X(f2i.src_reg + 1)));
default:
throw NotImplementedException("Invalid F2I source format {}",
f2i.base.src_format.Value());
}
}()};
TranslateF2I(*this, insn, op_a);
}
void TranslatorVisitor::F2I_cbuf(u64) {
throw NotImplementedException("{}", Opcode::F2I_cbuf);
}
void TranslatorVisitor::F2I_imm(u64) {
throw NotImplementedException("{}", Opcode::F2I_imm);
}
} // namespace Shader::Maxwell

View file

@ -0,0 +1,71 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/bit_field.h"
#include "common/common_types.h"
#include "shader_recompiler/exception.h"
#include "shader_recompiler/frontend/maxwell/opcode.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
namespace Shader::Maxwell {
namespace {
enum class Operation {
Cos = 0,
Sin = 1,
Ex2 = 2, // Base 2 exponent
Lg2 = 3, // Base 2 logarithm
Rcp = 4, // Reciprocal
Rsq = 5, // Reciprocal square root
Rcp64H = 6, // 64-bit reciprocal
Rsq64H = 7, // 64-bit reciprocal square root
Sqrt = 8,
};
} // Anonymous namespace
void TranslatorVisitor::MUFU(u64 insn) {
// MUFU is used to implement a bunch of special functions. See Operation.
union {
u64 raw;
BitField<0, 8, IR::Reg> dest_reg;
BitField<8, 8, IR::Reg> src_reg;
BitField<20, 4, Operation> operation;
BitField<46, 1, u64> abs;
BitField<48, 1, u64> neg;
BitField<50, 1, u64> sat;
} const mufu{insn};
const IR::U32 op_a{ir.FPAbsNeg(X(mufu.src_reg), mufu.abs != 0, mufu.neg != 0)};
IR::U32 value{[&]() -> IR::U32 {
switch (mufu.operation) {
case Operation::Cos:
return ir.FPCosNotReduced(op_a);
case Operation::Sin:
return ir.FPSinNotReduced(op_a);
case Operation::Ex2:
return ir.FPExp2NotReduced(op_a);
case Operation::Lg2:
return ir.FPLog2(op_a);
case Operation::Rcp:
return ir.FPRecip(op_a);
case Operation::Rsq:
return ir.FPRecipSqrt(op_a);
case Operation::Rcp64H:
throw NotImplementedException("MUFU.RCP64H");
case Operation::Rsq64H:
throw NotImplementedException("MUFU.RSQ64H");
case Operation::Sqrt:
return ir.FPSqrt(op_a);
default:
throw NotImplementedException("Invalid MUFU operation {}", mufu.operation.Value());
}
}()};
if (mufu.sat) {
value = ir.FPSaturate(value);
}
X(mufu.dest_reg, value);
}
} // namespace Shader::Maxwell

View file

@ -0,0 +1,79 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/bit_field.h"
#include "shader_recompiler/frontend/ir/ir_emitter.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
namespace Shader::Maxwell {
IR::U32 TranslatorVisitor::X(IR::Reg reg) {
return ir.GetReg(reg);
}
void TranslatorVisitor::X(IR::Reg dest_reg, const IR::U32& value) {
ir.SetReg(dest_reg, value);
}
IR::U32 TranslatorVisitor::GetCbuf(u64 insn) {
union {
u64 raw;
BitField<20, 14, s64> offset;
BitField<34, 5, u64> binding;
} const cbuf{insn};
if (cbuf.binding >= 18) {
throw NotImplementedException("Out of bounds constant buffer binding {}", cbuf.binding);
}
if (cbuf.offset >= 0x10'000 || cbuf.offset < 0) {
throw NotImplementedException("Out of bounds constant buffer offset {}", cbuf.offset);
}
const IR::U32 binding{ir.Imm32(static_cast<u32>(cbuf.binding))};
const IR::U32 byte_offset{ir.Imm32(static_cast<u32>(cbuf.offset) * 4)};
return ir.GetCbuf(binding, byte_offset);
}
IR::U32 TranslatorVisitor::GetImm(u64 insn) {
union {
u64 raw;
BitField<20, 19, u64> value;
BitField<56, 1, u64> is_negative;
} const imm{insn};
const s32 positive_value{static_cast<s32>(imm.value)};
const s32 value{imm.is_negative != 0 ? -positive_value : positive_value};
return ir.Imm32(value);
}
void TranslatorVisitor::SetZFlag(const IR::U1& value) {
ir.SetZFlag(value);
}
void TranslatorVisitor::SetSFlag(const IR::U1& value) {
ir.SetSFlag(value);
}
void TranslatorVisitor::SetCFlag(const IR::U1& value) {
ir.SetCFlag(value);
}
void TranslatorVisitor::SetOFlag(const IR::U1& value) {
ir.SetOFlag(value);
}
void TranslatorVisitor::ResetZero() {
SetZFlag(ir.Imm1(false));
}
void TranslatorVisitor::ResetSFlag() {
SetSFlag(ir.Imm1(false));
}
void TranslatorVisitor::ResetCFlag() {
SetCFlag(ir.Imm1(false));
}
void TranslatorVisitor::ResetOFlag() {
SetOFlag(ir.Imm1(false));
}
} // namespace Shader::Maxwell

View file

@ -0,0 +1,316 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "shader_recompiler/environment.h"
#include "shader_recompiler/frontend/ir/basic_block.h"
#include "shader_recompiler/frontend/ir/ir_emitter.h"
#include "shader_recompiler/frontend/maxwell/instruction.h"
namespace Shader::Maxwell {
class TranslatorVisitor {
public:
explicit TranslatorVisitor(Environment& env_, IR::Block& block) : env{env_} ,ir(block) {}
Environment& env;
IR::IREmitter ir;
void AL2P(u64 insn);
void ALD(u64 insn);
void AST(u64 insn);
void ATOM_cas(u64 insn);
void ATOM(u64 insn);
void ATOMS_cas(u64 insn);
void ATOMS(u64 insn);
void B2R(u64 insn);
void BAR(u64 insn);
void BFE_reg(u64 insn);
void BFE_cbuf(u64 insn);
void BFE_imm(u64 insn);
void BFI_reg(u64 insn);
void BFI_rc(u64 insn);
void BFI_cr(u64 insn);
void BFI_imm(u64 insn);
void BPT(u64 insn);
void BRA(u64 insn);
void BRK(u64 insn);
void BRX(u64 insn);
void CAL(u64 insn);
void CCTL(u64 insn);
void CCTLL(u64 insn);
void CONT(u64 insn);
void CS2R(u64 insn);
void CSET(u64 insn);
void CSETP(u64 insn);
void DADD_reg(u64 insn);
void DADD_cbuf(u64 insn);
void DADD_imm(u64 insn);
void DEPBAR(u64 insn);
void DFMA_reg(u64 insn);
void DFMA_rc(u64 insn);
void DFMA_cr(u64 insn);
void DFMA_imm(u64 insn);
void DMNMX_reg(u64 insn);
void DMNMX_cbuf(u64 insn);
void DMNMX_imm(u64 insn);
void DMUL_reg(u64 insn);
void DMUL_cbuf(u64 insn);
void DMUL_imm(u64 insn);
void DSET_reg(u64 insn);
void DSET_cbuf(u64 insn);
void DSET_imm(u64 insn);
void DSETP_reg(u64 insn);
void DSETP_cbuf(u64 insn);
void DSETP_imm(u64 insn);
void EXIT(u64 insn);
void F2F_reg(u64 insn);
void F2F_cbuf(u64 insn);
void F2F_imm(u64 insn);
void F2I_reg(u64 insn);
void F2I_cbuf(u64 insn);
void F2I_imm(u64 insn);
void FADD_reg(u64 insn);
void FADD_cbuf(u64 insn);
void FADD_imm(u64 insn);
void FADD32I(u64 insn);
void FCHK_reg(u64 insn);
void FCHK_cbuf(u64 insn);
void FCHK_imm(u64 insn);
void FCMP_reg(u64 insn);
void FCMP_rc(u64 insn);
void FCMP_cr(u64 insn);
void FCMP_imm(u64 insn);
void FFMA_reg(u64 insn);
void FFMA_rc(u64 insn);
void FFMA_cr(u64 insn);
void FFMA_imm(u64 insn);
void FFMA32I(u64 insn);
void FLO_reg(u64 insn);
void FLO_cbuf(u64 insn);
void FLO_imm(u64 insn);
void FMNMX_reg(u64 insn);
void FMNMX_cbuf(u64 insn);
void FMNMX_imm(u64 insn);
void FMUL_reg(u64 insn);
void FMUL_cbuf(u64 insn);
void FMUL_imm(u64 insn);
void FMUL32I(u64 insn);
void FSET_reg(u64 insn);
void FSET_cbuf(u64 insn);
void FSET_imm(u64 insn);
void FSETP_reg(u64 insn);
void FSETP_cbuf(u64 insn);
void FSETP_imm(u64 insn);
void FSWZADD(u64 insn);
void GETCRSPTR(u64 insn);
void GETLMEMBASE(u64 insn);
void HADD2_reg(u64 insn);
void HADD2_cbuf(u64 insn);
void HADD2_imm(u64 insn);
void HADD2_32I(u64 insn);
void HFMA2_reg(u64 insn);
void HFMA2_rc(u64 insn);
void HFMA2_cr(u64 insn);
void HFMA2_imm(u64 insn);
void HFMA2_32I(u64 insn);
void HMUL2_reg(u64 insn);
void HMUL2_cbuf(u64 insn);
void HMUL2_imm(u64 insn);
void HMUL2_32I(u64 insn);
void HSET2_reg(u64 insn);
void HSET2_cbuf(u64 insn);
void HSET2_imm(u64 insn);
void HSETP2_reg(u64 insn);
void HSETP2_cbuf(u64 insn);
void HSETP2_imm(u64 insn);
void I2F_reg(u64 insn);
void I2F_cbuf(u64 insn);
void I2F_imm(u64 insn);
void I2I_reg(u64 insn);
void I2I_cbuf(u64 insn);
void I2I_imm(u64 insn);
void IADD_reg(u64 insn);
void IADD_cbuf(u64 insn);
void IADD_imm(u64 insn);
void IADD3_reg(u64 insn);
void IADD3_cbuf(u64 insn);
void IADD3_imm(u64 insn);
void IADD32I(u64 insn);
void ICMP_reg(u64 insn);
void ICMP_rc(u64 insn);
void ICMP_cr(u64 insn);
void ICMP_imm(u64 insn);
void IDE(u64 insn);
void IDP_reg(u64 insn);
void IDP_imm(u64 insn);
void IMAD_reg(u64 insn);
void IMAD_rc(u64 insn);
void IMAD_cr(u64 insn);
void IMAD_imm(u64 insn);
void IMAD32I(u64 insn);
void IMADSP_reg(u64 insn);
void IMADSP_rc(u64 insn);
void IMADSP_cr(u64 insn);
void IMADSP_imm(u64 insn);
void IMNMX_reg(u64 insn);
void IMNMX_cbuf(u64 insn);
void IMNMX_imm(u64 insn);
void IMUL_reg(u64 insn);
void IMUL_cbuf(u64 insn);
void IMUL_imm(u64 insn);
void IMUL32I(u64 insn);
void IPA(u64 insn);
void ISBERD(u64 insn);
void ISCADD_reg(u64 insn);
void ISCADD_cbuf(u64 insn);
void ISCADD_imm(u64 insn);
void ISCADD32I(u64 insn);
void ISET_reg(u64 insn);
void ISET_cbuf(u64 insn);
void ISET_imm(u64 insn);
void ISETP_reg(u64 insn);
void ISETP_cbuf(u64 insn);
void ISETP_imm(u64 insn);
void JCAL(u64 insn);
void JMP(u64 insn);
void JMX(u64 insn);
void KIL(u64 insn);
void LD(u64 insn);
void LDC(u64 insn);
void LDG(u64 insn);
void LDL(u64 insn);
void LDS(u64 insn);
void LEA_hi_reg(u64 insn);
void LEA_hi_cbuf(u64 insn);
void LEA_lo_reg(u64 insn);
void LEA_lo_cbuf(u64 insn);
void LEA_lo_imm(u64 insn);
void LEPC(u64 insn);
void LONGJMP(u64 insn);
void LOP_reg(u64 insn);
void LOP_cbuf(u64 insn);
void LOP_imm(u64 insn);
void LOP3_reg(u64 insn);
void LOP3_cbuf(u64 insn);
void LOP3_imm(u64 insn);
void LOP32I(u64 insn);
void MEMBAR(u64 insn);
void MOV_reg(u64 insn);
void MOV_cbuf(u64 insn);
void MOV_imm(u64 insn);
void MOV32I(u64 insn);
void MUFU(u64 insn);
void NOP(u64 insn);
void OUT_reg(u64 insn);
void OUT_cbuf(u64 insn);
void OUT_imm(u64 insn);
void P2R_reg(u64 insn);
void P2R_cbuf(u64 insn);
void P2R_imm(u64 insn);
void PBK(u64 insn);
void PCNT(u64 insn);
void PEXIT(u64 insn);
void PIXLD(u64 insn);
void PLONGJMP(u64 insn);
void POPC_reg(u64 insn);
void POPC_cbuf(u64 insn);
void POPC_imm(u64 insn);
void PRET(u64 insn);
void PRMT_reg(u64 insn);
void PRMT_rc(u64 insn);
void PRMT_cr(u64 insn);
void PRMT_imm(u64 insn);
void PSET(u64 insn);
void PSETP(u64 insn);
void R2B(u64 insn);
void R2P_reg(u64 insn);
void R2P_cbuf(u64 insn);
void R2P_imm(u64 insn);
void RAM(u64 insn);
void RED(u64 insn);
void RET(u64 insn);
void RRO_reg(u64 insn);
void RRO_cbuf(u64 insn);
void RRO_imm(u64 insn);
void RTT(u64 insn);
void S2R(u64 insn);
void SAM(u64 insn);
void SEL_reg(u64 insn);
void SEL_cbuf(u64 insn);
void SEL_imm(u64 insn);
void SETCRSPTR(u64 insn);
void SETLMEMBASE(u64 insn);
void SHF_l_reg(u64 insn);
void SHF_l_imm(u64 insn);
void SHF_r_reg(u64 insn);
void SHF_r_imm(u64 insn);
void SHFL(u64 insn);
void SHL_reg(u64 insn);
void SHL_cbuf(u64 insn);
void SHL_imm(u64 insn);
void SHR_reg(u64 insn);
void SHR_cbuf(u64 insn);
void SHR_imm(u64 insn);
void SSY(u64 insn);
void ST(u64 insn);
void STG(u64 insn);
void STL(u64 insn);
void STP(u64 insn);
void STS(u64 insn);
void SUATOM_cas(u64 insn);
void SULD(u64 insn);
void SURED(u64 insn);
void SUST(u64 insn);
void SYNC(u64 insn);
void TEX(u64 insn);
void TEX_b(u64 insn);
void TEXS(u64 insn);
void TLD(u64 insn);
void TLD_b(u64 insn);
void TLD4(u64 insn);
void TLD4_b(u64 insn);
void TLD4S(u64 insn);
void TLDS(u64 insn);
void TMML(u64 insn);
void TMML_b(u64 insn);
void TXA(u64 insn);
void TXD(u64 insn);
void TXD_b(u64 insn);
void TXQ(u64 insn);
void TXQ_b(u64 insn);
void VABSDIFF(u64 insn);
void VABSDIFF4(u64 insn);
void VADD(u64 insn);
void VMAD(u64 insn);
void VMNMX(u64 insn);
void VOTE(u64 insn);
void VOTE_vtg(u64 insn);
void VSET(u64 insn);
void VSETP(u64 insn);
void VSHL(u64 insn);
void VSHR(u64 insn);
void XMAD_reg(u64 insn);
void XMAD_rc(u64 insn);
void XMAD_cr(u64 insn);
void XMAD_imm(u64 insn);
[[nodiscard]] IR::U32 X(IR::Reg reg);
void X(IR::Reg dest_reg, const IR::U32& value);
[[nodiscard]] IR::U32 GetCbuf(u64 insn);
[[nodiscard]] IR::U32 GetImm(u64 insn);
void SetZFlag(const IR::U1& value);
void SetSFlag(const IR::U1& value);
void SetCFlag(const IR::U1& value);
void SetOFlag(const IR::U1& value);
void ResetZero();
void ResetSFlag();
void ResetCFlag();
void ResetOFlag();
};
} // namespace Shader::Maxwell

View file

@ -0,0 +1,92 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/bit_field.h"
#include "common/common_types.h"
#include "shader_recompiler/exception.h"
#include "shader_recompiler/frontend/maxwell/opcode.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
namespace Shader::Maxwell {
namespace {
enum class InterpolationMode : u64 {
Pass = 0,
Multiply = 1,
Constant = 2,
Sc = 3,
};
enum class SampleMode : u64 {
Default = 0,
Centroid = 1,
Offset = 2,
};
} // Anonymous namespace
void TranslatorVisitor::IPA(u64 insn) {
// IPA is the instruction used to read varyings from a fragment shader.
// gl_FragCoord is mapped to the gl_Position attribute.
// It yields unknown results when used outside of the fragment shader stage.
union {
u64 raw;
BitField<0, 8, IR::Reg> dest_reg;
BitField<8, 8, IR::Reg> index_reg;
BitField<20, 8, IR::Reg> multiplier;
BitField<30, 8, IR::Attribute> attribute;
BitField<38, 1, u64> idx;
BitField<51, 1, u64> sat;
BitField<52, 2, SampleMode> sample_mode;
BitField<54, 2, InterpolationMode> interpolation_mode;
} const ipa{insn};
// Indexed IPAs are used for indexed varyings.
// For example:
//
// in vec4 colors[4];
// uniform int idx;
// void main() {
// gl_FragColor = colors[idx];
// }
const bool is_indexed{ipa.idx != 0 && ipa.index_reg != IR::Reg::RZ};
if (is_indexed) {
throw NotImplementedException("IPA.IDX");
}
const IR::Attribute attribute{ipa.attribute};
IR::U32 value{ir.GetAttribute(attribute)};
if (IR::IsGeneric(attribute)) {
// const bool is_perspective{UnimplementedReadHeader(GenericAttributeIndex(attribute))};
const bool is_perspective{false};
if (is_perspective) {
const IR::U32 rcp_position_w{ir.FPRecip(ir.GetAttribute(IR::Attribute::PositionW))};
value = ir.FPMul(value, rcp_position_w);
}
}
switch (ipa.interpolation_mode) {
case InterpolationMode::Pass:
break;
case InterpolationMode::Multiply:
value = ir.FPMul(value, ir.GetReg(ipa.multiplier));
break;
case InterpolationMode::Constant:
throw NotImplementedException("IPA.CONSTANT");
case InterpolationMode::Sc:
throw NotImplementedException("IPA.SC");
}
// Saturated IPAs are generally generated out of clamped varyings.
// For example: clamp(some_varying, 0.0, 1.0)
const bool is_saturated{ipa.sat != 0};
if (is_saturated) {
if (attribute == IR::Attribute::FrontFace) {
throw NotImplementedException("IPA.SAT on FrontFace");
}
value = ir.FPSaturate(value);
}
ir.SetReg(ipa.dest_reg, value);
}
} // namespace Shader::Maxwell

View file

@ -0,0 +1,90 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/bit_field.h"
#include "common/common_types.h"
#include "shader_recompiler/exception.h"
#include "shader_recompiler/frontend/maxwell/opcode.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
namespace Shader::Maxwell {
namespace {
enum class StoreSize : u64 {
U8,
S8,
U16,
S16,
B32,
B64,
B128,
};
// See Table 28 in https://docs.nvidia.com/cuda/parallel-thread-execution/index.html
enum class StoreCache : u64 {
WB, // Cache write-back all coherent levels
CG, // Cache at global level
CS, // Cache streaming, likely to be accessed once
WT, // Cache write-through (to system memory)
};
} // Anonymous namespace
void TranslatorVisitor::STG(u64 insn) {
// STG stores registers into global memory.
union {
u64 raw;
BitField<0, 8, IR::Reg> data_reg;
BitField<8, 8, IR::Reg> addr_reg;
BitField<45, 1, u64> e;
BitField<46, 2, StoreCache> cache;
BitField<48, 3, StoreSize> size;
} const stg{insn};
const IR::U64 address{[&]() -> IR::U64 {
if (stg.e == 0) {
// STG without .E uses a 32-bit pointer, zero-extend it
return ir.ConvertU(64, X(stg.addr_reg));
}
if (!IR::IsAligned(stg.addr_reg, 2)) {
throw NotImplementedException("Unaligned address register");
}
// Pack two registers to build the 32-bit address
return ir.PackUint2x32(ir.CompositeConstruct(X(stg.addr_reg), X(stg.addr_reg + 1)));
}()};
switch (stg.size) {
case StoreSize::U8:
ir.WriteGlobalU8(address, X(stg.data_reg));
break;
case StoreSize::S8:
ir.WriteGlobalS8(address, X(stg.data_reg));
break;
case StoreSize::U16:
ir.WriteGlobalU16(address, X(stg.data_reg));
break;
case StoreSize::S16:
ir.WriteGlobalS16(address, X(stg.data_reg));
break;
case StoreSize::B32:
ir.WriteGlobal32(address, X(stg.data_reg));
break;
case StoreSize::B64: {
if (!IR::IsAligned(stg.data_reg, 2)) {
throw NotImplementedException("Unaligned data registers");
}
const IR::Value vector{ir.CompositeConstruct(X(stg.data_reg), X(stg.data_reg + 1))};
ir.WriteGlobal64(address, vector);
break;
}
case StoreSize::B128:
if (!IR::IsAligned(stg.data_reg, 4)) {
throw NotImplementedException("Unaligned data registers");
}
const IR::Value vector{ir.CompositeConstruct(X(stg.data_reg), X(stg.data_reg + 1),
X(stg.data_reg + 2), X(stg.data_reg + 3))};
ir.WriteGlobal128(address, vector);
break;
}
}
} // namespace Shader::Maxwell

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,45 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/bit_field.h"
#include "common/common_types.h"
#include "shader_recompiler/exception.h"
#include "shader_recompiler/frontend/maxwell/opcode.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
namespace Shader::Maxwell {
namespace {
union MOV {
u64 raw;
BitField<0, 8, IR::Reg> dest_reg;
BitField<20, 8, IR::Reg> src_reg;
BitField<39, 4, u64> mask;
};
void CheckMask(MOV mov) {
if (mov.mask != 0xf) {
throw NotImplementedException("Non-full move mask");
}
}
} // Anonymous namespace
void TranslatorVisitor::MOV_reg(u64 insn) {
const MOV mov{insn};
CheckMask(mov);
X(mov.dest_reg, X(mov.src_reg));
}
void TranslatorVisitor::MOV_cbuf(u64 insn) {
const MOV mov{insn};
CheckMask(mov);
X(mov.dest_reg, GetCbuf(insn));
}
void TranslatorVisitor::MOV_imm(u64 insn) {
const MOV mov{insn};
CheckMask(mov);
X(mov.dest_reg, GetImm(insn));
}
} // namespace Shader::Maxwell

View file

@ -0,0 +1,50 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "shader_recompiler/environment.h"
#include "shader_recompiler/frontend/ir/basic_block.h"
#include "shader_recompiler/frontend/maxwell/decode.h"
#include "shader_recompiler/frontend/maxwell/location.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
#include "shader_recompiler/frontend/maxwell/translate/translate.h"
namespace Shader::Maxwell {
template <auto visitor_method>
static void Invoke(TranslatorVisitor& visitor, Location pc, u64 insn) {
using MethodType = decltype(visitor_method);
if constexpr (std::is_invocable_r_v<void, MethodType, TranslatorVisitor&, Location, u64>) {
(visitor.*visitor_method)(pc, insn);
} else if constexpr (std::is_invocable_r_v<void, MethodType, TranslatorVisitor&, u64>) {
(visitor.*visitor_method)(insn);
} else {
(visitor.*visitor_method)();
}
}
IR::Block Translate(Environment& env, const Flow::Block& flow_block) {
IR::Block block{flow_block.begin.Offset(), flow_block.end.Offset()};
TranslatorVisitor visitor{env, block};
const Location pc_end{flow_block.end};
Location pc{flow_block.begin};
while (pc != pc_end) {
const u64 insn{env.ReadInstruction(pc.Offset())};
const Opcode opcode{Decode(insn)};
switch (opcode) {
#define INST(name, cute, mask) \
case Opcode::name: \
Invoke<&TranslatorVisitor::name>(visitor, pc, insn); \
break;
#include "shader_recompiler/frontend/maxwell/maxwell.inc"
#undef OPCODE
default:
throw LogicError("Invalid opcode {}", opcode);
}
++pc;
}
return block;
}
} // namespace Shader::Maxwell

View file

@ -0,0 +1,16 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "shader_recompiler/environment.h"
#include "shader_recompiler/frontend/ir/basic_block.h"
#include "shader_recompiler/frontend/maxwell/location.h"
#include "shader_recompiler/frontend/maxwell/control_flow.h"
namespace Shader::Maxwell {
[[nodiscard]] IR::Block Translate(Environment& env, const Flow::Block& flow_block);
} // namespace Shader::Maxwell