feat(shader): implement SOP1 saveexec/wrexec family
This commit is contained in:
parent
709d7fe0fd
commit
f2bfdd26f9
|
|
@ -615,6 +615,14 @@ if(BUILD_TESTING)
|
|||
set_tests_properties(vector_min_max_med16 PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
|
||||
endif()
|
||||
add_test_executable(scalar_saveexec_tests ${LIBS_INCLUDE_DIR}/tests/ScalarSaveexec.cpp)
|
||||
target_link_libraries(scalar_saveexec_tests PRIVATE shader_recompiler_agc_driver libc)
|
||||
configure_windows_unwind(scalar_saveexec_tests)
|
||||
add_test(NAME scalar_saveexec COMMAND scalar_saveexec_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(scalar_saveexec PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
|
||||
endif()
|
||||
add_test_executable(guest_indexed_draw_tests ${LIBS_INCLUDE_DIR}/tests/GuestIndexedDraw.cpp)
|
||||
target_include_directories(guest_indexed_draw_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_indexed_draw_tests PRIVATE libSceAgc libSceAgcDriver libc)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
#include "Translation/TranslationContext.hpp"
|
||||
#include "RdnaDecoder/RdnaScalarOpDecoder.hpp"
|
||||
#include <array>
|
||||
#include <stdexcept>
|
||||
|
||||
using namespace ShaderRecompiler;
|
||||
static void Require(bool value) { if (!value) throw std::runtime_error("scalar saveexec regression"); }
|
||||
static void Check(std::uint32_t encoding, RdnaOpcode opcode) {
|
||||
const std::array<std::uint32_t, 1> code{0x80000000u | (106u << 16u) | (encoding << 8u) | 10u};
|
||||
const RdnaInstruction instruction = DecodeRdnaSop1(0u, code, 0u);
|
||||
Require(instruction.op == opcode);
|
||||
Require(instruction.family == RdnaInstructionFamily::SOP1);
|
||||
Require(IsScalarAluOpcode(instruction.op));
|
||||
IrProgram program;
|
||||
auto& block = program.CreateBlock();
|
||||
program.SetEntryBlock(block);
|
||||
TranslationContext context(program, block, 256);
|
||||
context.TranslateInstruction(instruction);
|
||||
}
|
||||
int main() {
|
||||
Check(0x3du, RdnaOpcode::SOrSaveexecB32);
|
||||
Check(0x3eu, RdnaOpcode::SXorSaveexecB32);
|
||||
Check(0x3fu, RdnaOpcode::SAndn2SaveexecB32);
|
||||
Check(0x41u, RdnaOpcode::SNandSaveexecB32);
|
||||
Check(0x42u, RdnaOpcode::SNorSaveexecB32);
|
||||
Check(0x43u, RdnaOpcode::SXnorSaveexecB32);
|
||||
Check(0x45u, RdnaOpcode::SOrn1SaveexecB32);
|
||||
Check(0x46u, RdnaOpcode::SAndn1WrexecB32);
|
||||
Check(0x47u, RdnaOpcode::SAndn2WrexecB32);
|
||||
Check(0x29u, RdnaOpcode::SNandSaveexecB64);
|
||||
Check(0x2au, RdnaOpcode::SNorSaveexecB64);
|
||||
Check(0x2bu, RdnaOpcode::SXnorSaveexecB64);
|
||||
Check(0x38u, RdnaOpcode::SOrn1SaveexecB64);
|
||||
Check(0x39u, RdnaOpcode::SAndn1WrexecB64);
|
||||
Check(0x3au, RdnaOpcode::SAndn2WrexecB64);
|
||||
}
|
||||
|
|
@ -137,14 +137,29 @@ enum class RdnaOpcode : std::uint16_t {
|
|||
SSubvectorLoopBegin,
|
||||
SSubvectorLoopEnd,
|
||||
SAndSaveexecB32,
|
||||
SOrSaveexecB32,
|
||||
SXorSaveexecB32,
|
||||
SAndn2SaveexecB32,
|
||||
SOrn2SaveexecB32,
|
||||
SNandSaveexecB32,
|
||||
SNorSaveexecB32,
|
||||
SXnorSaveexecB32,
|
||||
SAndn1SaveexecB32,
|
||||
SOrn1SaveexecB32,
|
||||
SAndn1WrexecB32,
|
||||
SAndn2WrexecB32,
|
||||
SAndSaveexecB64,
|
||||
SOrSaveexecB64,
|
||||
SXorSaveexecB64,
|
||||
SAndn2SaveexecB64,
|
||||
SOrn2SaveexecB64,
|
||||
SNandSaveexecB64,
|
||||
SNorSaveexecB64,
|
||||
SXnorSaveexecB64,
|
||||
SAndn1SaveexecB64,
|
||||
SOrn1SaveexecB64,
|
||||
SAndn1WrexecB64,
|
||||
SAndn2WrexecB64,
|
||||
SNotB32,
|
||||
SNotB64,
|
||||
SWqmB32,
|
||||
|
|
|
|||
|
|
@ -56,14 +56,29 @@ bool IsScalarAluOpcode(RdnaOpcode opcode) {
|
|||
case RdnaOpcode::SBitreplicateB64B32:
|
||||
case RdnaOpcode::SQuadmaskB64:
|
||||
case RdnaOpcode::SAndSaveexecB32:
|
||||
case RdnaOpcode::SOrSaveexecB32:
|
||||
case RdnaOpcode::SXorSaveexecB32:
|
||||
case RdnaOpcode::SAndn2SaveexecB32:
|
||||
case RdnaOpcode::SOrn2SaveexecB32:
|
||||
case RdnaOpcode::SNandSaveexecB32:
|
||||
case RdnaOpcode::SNorSaveexecB32:
|
||||
case RdnaOpcode::SXnorSaveexecB32:
|
||||
case RdnaOpcode::SAndn1SaveexecB32:
|
||||
case RdnaOpcode::SOrn1SaveexecB32:
|
||||
case RdnaOpcode::SAndn1WrexecB32:
|
||||
case RdnaOpcode::SAndn2WrexecB32:
|
||||
case RdnaOpcode::SAndSaveexecB64:
|
||||
case RdnaOpcode::SOrSaveexecB64:
|
||||
case RdnaOpcode::SXorSaveexecB64:
|
||||
case RdnaOpcode::SAndn2SaveexecB64:
|
||||
case RdnaOpcode::SOrn2SaveexecB64:
|
||||
case RdnaOpcode::SNandSaveexecB64:
|
||||
case RdnaOpcode::SNorSaveexecB64:
|
||||
case RdnaOpcode::SXnorSaveexecB64:
|
||||
case RdnaOpcode::SAndn1SaveexecB64:
|
||||
case RdnaOpcode::SOrn1SaveexecB64:
|
||||
case RdnaOpcode::SAndn1WrexecB64:
|
||||
case RdnaOpcode::SAndn2WrexecB64:
|
||||
case RdnaOpcode::SNotB32:
|
||||
case RdnaOpcode::SNotB64:
|
||||
case RdnaOpcode::SWqmB32:
|
||||
|
|
|
|||
|
|
@ -40,13 +40,28 @@ RdnaOpcode decodeSop1Opcode(std::uint32_t opcode) {
|
|||
case 0x26u: return RdnaOpcode::SXorSaveexecB64;
|
||||
case 0x27u: return RdnaOpcode::SAndn2SaveexecB64;
|
||||
case 0x28u: return RdnaOpcode::SOrn2SaveexecB64;
|
||||
case 0x29u: return RdnaOpcode::SNandSaveexecB64;
|
||||
case 0x2au: return RdnaOpcode::SNorSaveexecB64;
|
||||
case 0x2bu: return RdnaOpcode::SXnorSaveexecB64;
|
||||
case 0x2du: return RdnaOpcode::SQuadmaskB64;
|
||||
case 0x34u: return RdnaOpcode::SAbsI32;
|
||||
case 0x37u: return RdnaOpcode::SAndn1SaveexecB64;
|
||||
case 0x38u: return RdnaOpcode::SOrn1SaveexecB64;
|
||||
case 0x39u: return RdnaOpcode::SAndn1WrexecB64;
|
||||
case 0x3au: return RdnaOpcode::SAndn2WrexecB64;
|
||||
case 0x3bu: return RdnaOpcode::SBitreplicateB64B32;
|
||||
case 0x3cu: return RdnaOpcode::SAndSaveexecB32;
|
||||
case 0x3du: return RdnaOpcode::SOrSaveexecB32;
|
||||
case 0x3eu: return RdnaOpcode::SXorSaveexecB32;
|
||||
case 0x3fu: return RdnaOpcode::SAndn2SaveexecB32;
|
||||
case 0x40u: return RdnaOpcode::SOrn2SaveexecB32;
|
||||
case 0x41u: return RdnaOpcode::SNandSaveexecB32;
|
||||
case 0x42u: return RdnaOpcode::SNorSaveexecB32;
|
||||
case 0x43u: return RdnaOpcode::SXnorSaveexecB32;
|
||||
case 0x44u: return RdnaOpcode::SAndn1SaveexecB32;
|
||||
case 0x45u: return RdnaOpcode::SOrn1SaveexecB32;
|
||||
case 0x46u: return RdnaOpcode::SAndn1WrexecB32;
|
||||
case 0x47u: return RdnaOpcode::SAndn2WrexecB32;
|
||||
default: throw std::invalid_argument("unsupported SOP1 opcode " + std::to_string(opcode));
|
||||
}
|
||||
}
|
||||
|
|
@ -218,6 +233,12 @@ std::uint32_t scalarDestinationDwordCount(RdnaOpcode opcode) {
|
|||
case RdnaOpcode::SXorSaveexecB64:
|
||||
case RdnaOpcode::SAndn2SaveexecB64:
|
||||
case RdnaOpcode::SOrn2SaveexecB64:
|
||||
case RdnaOpcode::SNandSaveexecB64:
|
||||
case RdnaOpcode::SNorSaveexecB64:
|
||||
case RdnaOpcode::SXnorSaveexecB64:
|
||||
case RdnaOpcode::SOrn1SaveexecB64:
|
||||
case RdnaOpcode::SAndn1WrexecB64:
|
||||
case RdnaOpcode::SAndn2WrexecB64:
|
||||
case RdnaOpcode::SQuadmaskB64:
|
||||
case RdnaOpcode::SAndn1SaveexecB64:
|
||||
case RdnaOpcode::SBitreplicateB64B32:
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ private:
|
|||
bool vCndmaskB32(const RdnaInstruction& inst);
|
||||
bool packB16(const RdnaInstruction& inst, bool high0, bool high1);
|
||||
void sSubvectorLoop(const RdnaInstruction& inst, bool begin);
|
||||
void sSaveexec(const RdnaInstruction& inst, IrOpcode operation, bool negateExec, bool negateSource, bool write64);
|
||||
void sSaveexec(const RdnaInstruction& inst, IrOpcode operation, bool negateExec, bool negateSource, bool write64, bool negateResult = false, bool writeDestination = true);
|
||||
void addU32(const RdnaInstruction& inst, bool vector, bool useCarryIn);
|
||||
void subU32(const RdnaInstruction& inst, bool vector, bool reverse);
|
||||
void subbU32(const RdnaInstruction& inst, bool vector, bool reverse);
|
||||
|
|
|
|||
|
|
@ -24,23 +24,25 @@ bool SaveexecWritesDestinationFirst() {
|
|||
return writeFirst;
|
||||
}
|
||||
|
||||
void TranslationContext::sSaveexec(const RdnaInstruction& inst, IrOpcode operation, bool negateExec, bool negateSource, bool write64) {
|
||||
void TranslationContext::sSaveexec(const RdnaInstruction& inst, IrOpcode operation, bool negateExec, bool negateSource, bool write64, bool negateResult, bool writeDestination) {
|
||||
// Callers name the lane-wise operation; the exec mask words themselves combine bitwise.
|
||||
if (operation == IrOpcode::LogicalAnd) operation = IrOpcode::BitwiseAnd32;
|
||||
else if (operation == IrOpcode::LogicalOr) operation = IrOpcode::BitwiseOr32;
|
||||
else if (operation == IrOpcode::LogicalXor) operation = IrOpcode::BitwiseXor32;
|
||||
const bool writeFirst = SaveexecWritesDestinationFirst();
|
||||
const bool writeFirst = SaveexecWritesDestinationFirst() && writeDestination;
|
||||
if (write64) {
|
||||
const std::array<IrU32, 2> oldExec{IrU32(ir.GetExecLo()), IrU32(ir.GetExecHi())};
|
||||
if (writeFirst) writeU32Pair(inst.destination, oldExec);
|
||||
const std::array<IrU32, 2> source = readU32Pair(sourceAt(inst, 0u));
|
||||
if (!writeFirst) writeU32Pair(inst.destination, oldExec);
|
||||
if (!writeFirst && writeDestination) writeU32Pair(inst.destination, oldExec);
|
||||
IrValue& lowExecOperand = negateExec ? ir.BitwiseNot(oldExec[0].Value()) : oldExec[0].Value();
|
||||
IrValue& lowSourceOperand = negateSource ? ir.BitwiseNot(source[0].Value()) : source[0].Value();
|
||||
IrValue& highExecOperand = negateExec ? ir.BitwiseNot(oldExec[1].Value()) : oldExec[1].Value();
|
||||
IrValue& highSourceOperand = negateSource ? ir.BitwiseNot(source[1].Value()) : source[1].Value();
|
||||
const IrU32 newExecLo(ir.Emit(operation, IrType::U32, {&lowExecOperand, &lowSourceOperand}));
|
||||
const IrU32 newExecHi(ir.Emit(operation, IrType::U32, {&highExecOperand, &highSourceOperand}));
|
||||
IrValue& lowCombined = ir.Emit(operation, IrType::U32, {&lowExecOperand, &lowSourceOperand});
|
||||
IrValue& highCombined = ir.Emit(operation, IrType::U32, {&highExecOperand, &highSourceOperand});
|
||||
const IrU32 newExecLo(negateResult ? ir.BitwiseNot(lowCombined) : lowCombined);
|
||||
const IrU32 newExecHi(negateResult ? ir.BitwiseNot(highCombined) : highCombined);
|
||||
ir.SetExecLo(newExecLo.Value());
|
||||
ir.SetExecHi(newExecHi.Value());
|
||||
const IrU1 nonZero(ir.LogicalOr(ir.INotEqual(newExecLo.Value(), ir.Constant(0u)), ir.INotEqual(newExecHi.Value(), ir.Constant(0u))));
|
||||
|
|
@ -51,10 +53,11 @@ void TranslationContext::sSaveexec(const RdnaInstruction& inst, IrOpcode operati
|
|||
const IrU32 oldExec(ir.GetExecLo());
|
||||
if (writeFirst) writeRawU32(inst.destination, oldExec);
|
||||
const IrU32 source = readU32(sourceAt(inst, 0u));
|
||||
if (!writeFirst) writeRawU32(inst.destination, oldExec);
|
||||
if (!writeFirst && writeDestination) writeRawU32(inst.destination, oldExec);
|
||||
IrValue& execOperand = negateExec ? ir.BitwiseNot(oldExec.Value()) : oldExec.Value();
|
||||
IrValue& sourceOperand = negateSource ? ir.BitwiseNot(source.Value()) : source.Value();
|
||||
const IrU32 newExec(ir.Emit(operation, IrType::U32, {&execOperand, &sourceOperand}));
|
||||
IrValue& combined = ir.Emit(operation, IrType::U32, {&execOperand, &sourceOperand});
|
||||
const IrU32 newExec(negateResult ? ir.BitwiseNot(combined) : combined);
|
||||
ir.SetExecLo(newExec.Value());
|
||||
const IrU1 nonZero(ir.INotEqual(newExec.Value(), ir.Constant(0u)));
|
||||
ir.SetScc(nonZero.Value());
|
||||
|
|
|
|||
|
|
@ -59,12 +59,39 @@ bool TranslationContext::emitScalar(const RdnaInstruction& inst) {
|
|||
case RdnaOpcode::SAndSaveexecB32:
|
||||
sSaveexec(inst, IrOpcode::LogicalAnd, false, false, false);
|
||||
return true;
|
||||
case RdnaOpcode::SOrSaveexecB32:
|
||||
sSaveexec(inst, IrOpcode::LogicalOr, false, false, false);
|
||||
return true;
|
||||
case RdnaOpcode::SXorSaveexecB32:
|
||||
sSaveexec(inst, IrOpcode::LogicalXor, false, false, false);
|
||||
return true;
|
||||
case RdnaOpcode::SAndn1SaveexecB32:
|
||||
sSaveexec(inst, IrOpcode::LogicalAnd, false, true, false);
|
||||
return true;
|
||||
case RdnaOpcode::SAndn2SaveexecB32:
|
||||
sSaveexec(inst, IrOpcode::LogicalAnd, true, false, false);
|
||||
return true;
|
||||
case RdnaOpcode::SOrn1SaveexecB32:
|
||||
sSaveexec(inst, IrOpcode::LogicalOr, false, true, false);
|
||||
return true;
|
||||
case RdnaOpcode::SOrn2SaveexecB32:
|
||||
sSaveexec(inst, IrOpcode::LogicalOr, true, false, false);
|
||||
return true;
|
||||
case RdnaOpcode::SNandSaveexecB32:
|
||||
sSaveexec(inst, IrOpcode::LogicalAnd, false, false, false, true);
|
||||
return true;
|
||||
case RdnaOpcode::SNorSaveexecB32:
|
||||
sSaveexec(inst, IrOpcode::LogicalOr, false, false, false, true);
|
||||
return true;
|
||||
case RdnaOpcode::SXnorSaveexecB32:
|
||||
sSaveexec(inst, IrOpcode::LogicalXor, false, false, false, true);
|
||||
return true;
|
||||
case RdnaOpcode::SAndn1WrexecB32:
|
||||
sSaveexec(inst, IrOpcode::LogicalAnd, false, true, false, false, false);
|
||||
return true;
|
||||
case RdnaOpcode::SAndn2WrexecB32:
|
||||
sSaveexec(inst, IrOpcode::LogicalAnd, true, false, false, false, false);
|
||||
return true;
|
||||
case RdnaOpcode::SAndSaveexecB64:
|
||||
sSaveexec(inst, IrOpcode::LogicalAnd, false, false, true);
|
||||
return true;
|
||||
|
|
@ -83,6 +110,24 @@ bool TranslationContext::emitScalar(const RdnaInstruction& inst) {
|
|||
case RdnaOpcode::SOrn2SaveexecB64:
|
||||
sSaveexec(inst, IrOpcode::LogicalOr, true, false, true);
|
||||
return true;
|
||||
case RdnaOpcode::SNandSaveexecB64:
|
||||
sSaveexec(inst, IrOpcode::LogicalAnd, false, false, true, true);
|
||||
return true;
|
||||
case RdnaOpcode::SNorSaveexecB64:
|
||||
sSaveexec(inst, IrOpcode::LogicalOr, false, false, true, true);
|
||||
return true;
|
||||
case RdnaOpcode::SXnorSaveexecB64:
|
||||
sSaveexec(inst, IrOpcode::LogicalXor, false, false, true, true);
|
||||
return true;
|
||||
case RdnaOpcode::SOrn1SaveexecB64:
|
||||
sSaveexec(inst, IrOpcode::LogicalOr, false, true, true);
|
||||
return true;
|
||||
case RdnaOpcode::SAndn1WrexecB64:
|
||||
sSaveexec(inst, IrOpcode::LogicalAnd, false, true, true, false, false);
|
||||
return true;
|
||||
case RdnaOpcode::SAndn2WrexecB64:
|
||||
sSaveexec(inst, IrOpcode::LogicalAnd, true, false, true, false, false);
|
||||
return true;
|
||||
case RdnaOpcode::SAddU32:
|
||||
addU32(inst, false, false);
|
||||
return true;
|
||||
|
|
|
|||
Loading…
Reference in New Issue