shader: Implement CSET and CSETP

This commit is contained in:
ameerj 2021-03-17 00:53:53 -04:00
parent 32b6c63485
commit 3b7fd3ad0f
6 changed files with 114 additions and 15 deletions

View File

@ -63,6 +63,7 @@ add_library(shader_recompiler STATIC
frontend/maxwell/translate/impl/common_encoding.h frontend/maxwell/translate/impl/common_encoding.h
frontend/maxwell/translate/impl/common_funcs.cpp frontend/maxwell/translate/impl/common_funcs.cpp
frontend/maxwell/translate/impl/common_funcs.h frontend/maxwell/translate/impl/common_funcs.h
frontend/maxwell/translate/impl/condition_code_set.cpp
frontend/maxwell/translate/impl/find_leading_one.cpp frontend/maxwell/translate/impl/find_leading_one.cpp
frontend/maxwell/translate/impl/floating_point_add.cpp frontend/maxwell/translate/impl/floating_point_add.cpp
frontend/maxwell/translate/impl/floating_point_compare.cpp frontend/maxwell/translate/impl/floating_point_compare.cpp

View File

@ -5,12 +5,13 @@
#pragma once #pragma once
#include <string> #include <string>
#include <fmt/format.h> #include <fmt/format.h>
#include "common/common_types.h"
namespace Shader::IR { namespace Shader::IR {
enum class FlowTest { enum class FlowTest : u64 {
F, F,
LT, LT,
EQ, EQ,

View File

@ -169,16 +169,62 @@ void IREmitter::SetOFlag(const U1& value) {
static U1 GetFlowTest(IREmitter& ir, FlowTest flow_test) { static U1 GetFlowTest(IREmitter& ir, FlowTest flow_test) {
switch (flow_test) { switch (flow_test) {
case FlowTest::T:
return ir.Imm1(true);
case FlowTest::F: case FlowTest::F:
return ir.Imm1(false); return ir.Imm1(false);
case FlowTest::LT:
return ir.LogicalXor(ir.LogicalAnd(ir.GetSFlag(), ir.LogicalNot(ir.GetZFlag())),
ir.GetOFlag());
case FlowTest::EQ: case FlowTest::EQ:
// TODO: Test this return ir.LogicalAnd(ir.LogicalNot(ir.GetSFlag()), ir.GetZFlag());
return ir.GetZFlag(); case FlowTest::LE:
return ir.LogicalXor(ir.GetSFlag(), ir.LogicalOr(ir.GetZFlag(), ir.GetOFlag()));
case FlowTest::GT:
return ir.LogicalAnd(ir.LogicalXor(ir.LogicalNot(ir.GetSFlag()), ir.GetOFlag()),
ir.LogicalNot(ir.GetZFlag()));
case FlowTest::NE: case FlowTest::NE:
// TODO: Test this
return ir.LogicalNot(ir.GetZFlag()); return ir.LogicalNot(ir.GetZFlag());
case FlowTest::GE:
return ir.LogicalNot(ir.LogicalXor(ir.GetSFlag(), ir.GetOFlag()));
case FlowTest::NUM:
return ir.LogicalOr(ir.LogicalNot(ir.GetSFlag()), ir.LogicalNot(ir.GetZFlag()));
case FlowTest::NaN:
return ir.LogicalAnd(ir.GetSFlag(), ir.GetZFlag());
case FlowTest::LTU:
return ir.LogicalXor(ir.GetSFlag(), ir.GetOFlag());
case FlowTest::EQU:
return ir.GetZFlag();
case FlowTest::LEU:
return ir.LogicalOr(ir.LogicalXor(ir.GetSFlag(), ir.GetOFlag()), ir.GetZFlag());
case FlowTest::GTU:
return ir.LogicalXor(ir.LogicalNot(ir.GetSFlag()),
ir.LogicalOr(ir.GetZFlag(), ir.GetOFlag()));
case FlowTest::NEU:
return ir.LogicalOr(ir.GetSFlag(), ir.LogicalNot(ir.GetZFlag()));
case FlowTest::GEU:
return ir.LogicalXor(ir.LogicalOr(ir.LogicalNot(ir.GetSFlag()), ir.GetZFlag()),
ir.GetOFlag());
case FlowTest::T:
return ir.Imm1(true);
case FlowTest::OFF:
return ir.LogicalNot(ir.GetOFlag());
case FlowTest::LO:
return ir.LogicalNot(ir.GetCFlag());
case FlowTest::SFF:
return ir.LogicalNot(ir.GetSFlag());
case FlowTest::LS:
return ir.LogicalOr(ir.GetZFlag(), ir.LogicalNot(ir.GetCFlag()));
case FlowTest::HI:
return ir.LogicalAnd(ir.GetCFlag(), ir.LogicalNot(ir.GetZFlag()));
case FlowTest::SFT:
return ir.GetSFlag();
case FlowTest::HS:
return ir.GetCFlag();
case FlowTest::OFT:
return ir.GetOFlag();
case FlowTest::RLE:
return ir.LogicalOr(ir.GetSFlag(), ir.GetZFlag());
case FlowTest::RGT:
return ir.LogicalAnd(ir.LogicalNot(ir.GetSFlag()), ir.LogicalNot(ir.GetZFlag()));
default: default:
throw NotImplementedException("Flow test {}", flow_test); throw NotImplementedException("Flow test {}", flow_test);
} }
@ -190,6 +236,10 @@ U1 IREmitter::Condition(IR::Condition cond) {
return LogicalAnd(GetPred(pred, is_negated), GetFlowTest(*this, flow_test)); return LogicalAnd(GetPred(pred, is_negated), GetFlowTest(*this, flow_test));
} }
U1 IREmitter::GetFlowTestResult(FlowTest test) {
return GetFlowTest(*this, test);
}
F32 IREmitter::GetAttribute(IR::Attribute attribute) { F32 IREmitter::GetAttribute(IR::Attribute attribute) {
return Inst<F32>(Opcode::GetAttribute, attribute); return Inst<F32>(Opcode::GetAttribute, attribute);
} }

View File

@ -62,6 +62,7 @@ public:
void SetOFlag(const U1& value); void SetOFlag(const U1& value);
[[nodiscard]] U1 Condition(IR::Condition cond); [[nodiscard]] U1 Condition(IR::Condition cond);
[[nodiscard]] U1 GetFlowTestResult(FlowTest test);
[[nodiscard]] F32 GetAttribute(IR::Attribute attribute); [[nodiscard]] F32 GetAttribute(IR::Attribute attribute);
void SetAttribute(IR::Attribute attribute, const F32& value); void SetAttribute(IR::Attribute attribute, const F32& value);

View File

@ -0,0 +1,54 @@
// 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/frontend/maxwell/translate/impl/common_funcs.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
namespace Shader::Maxwell {
void TranslatorVisitor::CSET(u64 insn) {
union {
u64 raw;
BitField<0, 8, IR::Reg> dest_reg;
BitField<8, 5, IR::FlowTest> cc_test;
BitField<39, 3, IR::Pred> bop_pred;
BitField<42, 1, u64> neg_bop_pred;
BitField<44, 1, u64> bf;
BitField<45, 2, BooleanOp> bop;
} const cset{insn};
const IR::U32 one_mask{ir.Imm32(-1)};
const IR::U32 fp_one{ir.Imm32(0x3f800000)};
const IR::U32 fail_result{ir.Imm32(0)};
const IR::U32 pass_result{cset.bf == 0 ? one_mask : fp_one};
const IR::U1 cc_test_result{ir.GetFlowTestResult(cset.cc_test)};
const IR::U1 bop_pred{ir.GetPred(cset.bop_pred, cset.neg_bop_pred != 0)};
const IR::U1 pred_result{PredicateCombine(ir, cc_test_result, bop_pred, cset.bop)};
const IR::U32 result{ir.Select(pred_result, pass_result, fail_result)};
X(cset.dest_reg, result);
}
void TranslatorVisitor::CSETP(u64 insn) {
union {
u64 raw;
BitField<0, 3, IR::Pred> dest_pred_b;
BitField<3, 3, IR::Pred> dest_pred_a;
BitField<8, 5, IR::FlowTest> cc_test;
BitField<39, 3, IR::Pred> bop_pred;
BitField<42, 1, u64> neg_bop_pred;
BitField<45, 2, BooleanOp> bop;
} const csetp{insn};
const BooleanOp bop{csetp.bop};
const IR::U1 bop_pred{ir.GetPred(csetp.bop_pred, csetp.neg_bop_pred != 0)};
const IR::U1 cc_test_result{ir.GetFlowTestResult(csetp.cc_test)};
const IR::U1 result_a{PredicateCombine(ir, cc_test_result, bop_pred, bop)};
const IR::U1 result_b{PredicateCombine(ir, ir.LogicalNot(cc_test_result), bop_pred, bop)};
ir.SetPred(csetp.dest_pred_a, result_a);
ir.SetPred(csetp.dest_pred_b, result_b);
}
} // namespace Shader::Maxwell

View File

@ -85,14 +85,6 @@ void TranslatorVisitor::CS2R(u64) {
ThrowNotImplemented(Opcode::CS2R); ThrowNotImplemented(Opcode::CS2R);
} }
void TranslatorVisitor::CSET(u64) {
ThrowNotImplemented(Opcode::CSET);
}
void TranslatorVisitor::CSETP(u64) {
ThrowNotImplemented(Opcode::CSETP);
}
void TranslatorVisitor::DADD_reg(u64) { void TranslatorVisitor::DADD_reg(u64) {
ThrowNotImplemented(Opcode::DADD_reg); ThrowNotImplemented(Opcode::DADD_reg);
} }