feat(shader): add translation convert instructions impl
This commit is contained in:
parent
393a41fa2c
commit
fbb8fcbf4e
|
|
@ -1,99 +1,265 @@
|
|||
#include "Translation/ConvertInstructions.hpp"
|
||||
#include "Translation/ControlFlowInstructions.hpp"
|
||||
#include "Translation/TranslationContext.hpp"
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace ShaderRecompiler {
|
||||
|
||||
void TranslateConvertInstruction(IrBuilder& builder, const RdnaInstruction& instruction) {
|
||||
throw std::runtime_error("TranslateConvertInstruction not implemented");
|
||||
void TranslateControlFlowInstruction(IrBuilder& builder, const RdnaInstruction& instruction, const ControlFlowGraph& cfg) {
|
||||
throw std::runtime_error("TranslateControlFlowInstruction not implemented");
|
||||
}
|
||||
|
||||
IrF32 TranslationContext::selectF32(IrU1 condition, IrF32 trueValue, IrF32 falseValue) {
|
||||
throw std::runtime_error("TranslationContext::selectF32 not implemented");
|
||||
void TranslationContext::sSubvectorLoop(const RdnaInstruction& inst, bool begin) {
|
||||
throw std::runtime_error("GNM subvector loop instructions are not supported by this translator");
|
||||
}
|
||||
|
||||
IrU32 TranslationContext::convertF32ToU32Saturated(IrF32 value, float upperBound, float safeUpper, std::uint32_t highResult) {
|
||||
throw std::runtime_error("TranslationContext::convertF32ToU32Saturated not implemented");
|
||||
void TranslationContext::sSaveexec(const RdnaInstruction& inst, IrOpcode operation, bool negateExec, bool negateSource, bool write64) {
|
||||
if (write64) {
|
||||
const std::array<IrU32, 2> oldExec{IrU32(ir.GetExecLo()), IrU32(ir.GetExecHi())};
|
||||
writeU32Pair(inst.destination, oldExec);
|
||||
const std::array<IrU32, 2> source = readU32Pair(sourceAt(inst, 0u));
|
||||
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}));
|
||||
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))));
|
||||
ir.SetScc(nonZero.Value());
|
||||
ir.SetExec(nonZero.Value());
|
||||
return;
|
||||
}
|
||||
const IrU32 oldExec(ir.GetExecLo());
|
||||
writeRawU32(inst.destination, oldExec);
|
||||
const IrU32 source = readU32(sourceAt(inst, 0u));
|
||||
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}));
|
||||
ir.SetExecLo(newExec.Value());
|
||||
const IrU1 nonZero(ir.INotEqual(newExec.Value(), ir.Constant(0u)));
|
||||
ir.SetScc(nonZero.Value());
|
||||
ir.SetExec(nonZero.Value());
|
||||
}
|
||||
|
||||
IrU32 TranslationContext::convertF32ToI32Saturated(IrF32 value, float lowerBound, float upperBound, float safeUpper, std::uint32_t lowerResult, std::uint32_t upperResult) {
|
||||
throw std::runtime_error("TranslationContext::convertF32ToI32Saturated not implemented");
|
||||
void TranslationContext::addU32(const RdnaInstruction& inst, bool vector, bool useCarryIn) {
|
||||
const IrU32 lhs = readU32(sourceAt(inst, 0u));
|
||||
const IrU32 rhs = readU32(sourceAt(inst, 1u));
|
||||
IrValue& firstAdd = ir.Emit(IrOpcode::IAddCarry32, IrType::U32x2, {&lhs.Value(), &rhs.Value()});
|
||||
const IrU32 sum(ir.Emit(IrOpcode::CompositeExtractU32x2, IrType::U32, {&firstAdd, &ir.Constant(0u)}));
|
||||
const IrU32 firstCarry(ir.Emit(IrOpcode::CompositeExtractU32x2, IrType::U32, {&firstAdd, &ir.Constant(1u)}));
|
||||
if (!useCarryIn) {
|
||||
writeRawU32(inst.destination, sum);
|
||||
const IrU1 carryOut(ir.INotEqual(firstCarry.Value(), ir.Constant(0u)));
|
||||
if (vector) {
|
||||
writeMask(inst.destination2, carryOut);
|
||||
return;
|
||||
}
|
||||
ir.SetScc(carryOut.Value());
|
||||
return;
|
||||
}
|
||||
const IrU1 carryIn = vector ? IrU1(ir.GetVcc()) : IrU1(ir.GetScc());
|
||||
const IrU32 carryInU32(ir.Select(carryIn.Value(), ir.Constant(1u), ir.Constant(0u)));
|
||||
IrValue& secondAdd = ir.Emit(IrOpcode::IAddCarry32, IrType::U32x2, {&sum.Value(), &carryInU32.Value()});
|
||||
const IrU32 result(ir.Emit(IrOpcode::CompositeExtractU32x2, IrType::U32, {&secondAdd, &ir.Constant(0u)}));
|
||||
const IrU32 secondCarry(ir.Emit(IrOpcode::CompositeExtractU32x2, IrType::U32, {&secondAdd, &ir.Constant(1u)}));
|
||||
const IrU1 carryOut(ir.LogicalOr(ir.INotEqual(firstCarry.Value(), ir.Constant(0u)), ir.INotEqual(secondCarry.Value(), ir.Constant(0u))));
|
||||
writeRawU32(inst.destination, result);
|
||||
if (vector) {
|
||||
writeMask(inst.destination2, carryOut);
|
||||
return;
|
||||
}
|
||||
ir.SetScc(carryOut.Value());
|
||||
}
|
||||
|
||||
IrU32 TranslationContext::packU16Lanes(IrU32 low, IrU32 high) {
|
||||
throw std::runtime_error("TranslationContext::packU16Lanes not implemented");
|
||||
void TranslationContext::subU32(const RdnaInstruction& inst, bool vector, bool reverse) {
|
||||
const IrU32 first = readU32(sourceAt(inst, 0u));
|
||||
const IrU32 second = readU32(sourceAt(inst, 1u));
|
||||
const IrU32& lhs = reverse ? second : first;
|
||||
const IrU32& rhs = reverse ? first : second;
|
||||
const IrU32 result(ir.ISub(lhs.Value(), rhs.Value()));
|
||||
const IrU1 borrow(ir.ULessThan(lhs.Value(), rhs.Value()));
|
||||
writeRawU32(inst.destination, result);
|
||||
if (vector) {
|
||||
writeMask(inst.destination2, borrow);
|
||||
return;
|
||||
}
|
||||
ir.SetScc(borrow.Value());
|
||||
}
|
||||
|
||||
void TranslationContext::vCvtF32Ubyte(const RdnaInstruction& inst, std::uint32_t byteIndex) {
|
||||
throw std::runtime_error("TranslationContext::vCvtF32Ubyte not implemented");
|
||||
void TranslationContext::subbU32(const RdnaInstruction& inst, bool vector, bool reverse) {
|
||||
const IrU32 first = readU32(sourceAt(inst, 0u));
|
||||
const IrU32 second = readU32(sourceAt(inst, 1u));
|
||||
const IrU32& lhs = reverse ? second : first;
|
||||
const IrU32& rhs = reverse ? first : second;
|
||||
const IrU1 borrowIn = vector ? IrU1(ir.GetVcc()) : IrU1(ir.GetScc());
|
||||
const IrU32 borrowInU32(ir.Select(borrowIn.Value(), ir.Constant(1u), ir.Constant(0u)));
|
||||
const IrU32 partial(ir.ISub(lhs.Value(), rhs.Value()));
|
||||
const IrU1 firstBorrow(ir.ULessThan(lhs.Value(), rhs.Value()));
|
||||
const IrU32 result(ir.ISub(partial.Value(), borrowInU32.Value()));
|
||||
const IrU1 secondBorrow(ir.ULessThan(partial.Value(), borrowInU32.Value()));
|
||||
const IrU1 borrowOut(ir.LogicalOr(firstBorrow.Value(), secondBorrow.Value()));
|
||||
writeRawU32(inst.destination, result);
|
||||
if (vector) {
|
||||
writeMask(inst.destination2, borrowOut);
|
||||
return;
|
||||
}
|
||||
ir.SetScc(borrowOut.Value());
|
||||
}
|
||||
|
||||
void TranslationContext::vCvtF32U32(const RdnaInstruction& inst) {
|
||||
throw std::runtime_error("TranslationContext::vCvtF32U32 not implemented");
|
||||
void TranslationContext::sAbsdiffI32(const RdnaInstruction& inst) {
|
||||
const IrU32 lhs = readU32(sourceAt(inst, 0u));
|
||||
const IrU32 rhs = readU32(sourceAt(inst, 1u));
|
||||
const IrU32 difference(ir.ISub(lhs.Value(), rhs.Value()));
|
||||
const IrU32 result(ir.Emit(IrOpcode::IAbs32, IrType::U32, {&difference.Value()}));
|
||||
ir.SetScc(ir.INotEqual(result.Value(), ir.Constant(0u)));
|
||||
writeRawU32(inst.destination, result);
|
||||
}
|
||||
|
||||
void TranslationContext::vCvtF32I32(const RdnaInstruction& inst) {
|
||||
throw std::runtime_error("TranslationContext::vCvtF32I32 not implemented");
|
||||
void TranslationContext::sAddSubI32(const RdnaInstruction& inst, bool subtract) {
|
||||
const IrU32 lhs = readU32(sourceAt(inst, 0u));
|
||||
const IrU32 rhs = readU32(sourceAt(inst, 1u));
|
||||
const IrU32 result(subtract ? ir.ISub(lhs.Value(), rhs.Value()) : ir.IAdd(lhs.Value(), rhs.Value()));
|
||||
const IrU32 signCheck(subtract ? ir.BitwiseAnd(ir.BitwiseXor(lhs.Value(), rhs.Value()), ir.BitwiseXor(lhs.Value(), result.Value()))
|
||||
: ir.BitwiseAnd(ir.BitwiseXor(lhs.Value(), result.Value()), ir.BitwiseXor(rhs.Value(), result.Value())));
|
||||
ir.SetScc(ir.INotEqual(ir.BitwiseAnd(signCheck.Value(), ir.Constant(0x80000000u)), ir.Constant(0u)));
|
||||
writeRawU32(inst.destination, result);
|
||||
}
|
||||
|
||||
void TranslationContext::vCvtU32F32(const RdnaInstruction& inst) {
|
||||
throw std::runtime_error("TranslationContext::vCvtU32F32 not implemented");
|
||||
void TranslationContext::sLshlAddU32(const RdnaInstruction& inst, std::uint32_t shiftAmount) {
|
||||
const IrU32 lhs = readU32(sourceAt(inst, 0u));
|
||||
const IrU32 rhs = readU32(sourceAt(inst, 1u));
|
||||
const IrU32 shifted(ir.ShiftLeftLogical(lhs.Value(), ir.Constant(shiftAmount)));
|
||||
const IrU32 result(ir.IAdd(shifted.Value(), rhs.Value()));
|
||||
writeRawU32(inst.destination, result);
|
||||
}
|
||||
|
||||
void TranslationContext::vCvtI32F32(const RdnaInstruction& inst) {
|
||||
throw std::runtime_error("TranslationContext::vCvtI32F32 not implemented");
|
||||
void TranslationContext::scalarMinMax32(const RdnaInstruction& inst, IrOpcode valueOpcode, IrOpcode compareOpcode) {
|
||||
const IrU32 lhs = readU32(sourceAt(inst, 0u));
|
||||
const IrU32 rhs = readU32(sourceAt(inst, 1u));
|
||||
const IrU32 result(ir.Emit(valueOpcode, IrType::U32, {&lhs.Value(), &rhs.Value()}));
|
||||
const IrU1 selected(ir.Emit(compareOpcode, IrType::U1, {&lhs.Value(), &rhs.Value()}));
|
||||
ir.SetScc(selected.Value());
|
||||
writeRawU32(inst.destination, result);
|
||||
}
|
||||
|
||||
void TranslationContext::vCvtF16F32(const RdnaInstruction& inst) {
|
||||
throw std::runtime_error("TranslationContext::vCvtF16F32 not implemented");
|
||||
void TranslationContext::emitControlNop() {
|
||||
(void)ir.Emit(IrOpcode::ControlNop, IrType::Void, {});
|
||||
}
|
||||
|
||||
void TranslationContext::vCvtF32F16(const RdnaInstruction& inst) {
|
||||
throw std::runtime_error("TranslationContext::vCvtF32F16 not implemented");
|
||||
void TranslationContext::emitWaitcnt() {
|
||||
(void)ir.Emit(IrOpcode::Waitcnt, IrType::Void, {});
|
||||
}
|
||||
|
||||
void TranslationContext::vCvtF1616(const RdnaInstruction& inst, bool signedValue) {
|
||||
throw std::runtime_error("TranslationContext::vCvtF1616 not implemented");
|
||||
void TranslationContext::sBarrier() {
|
||||
(void)ir.Emit(IrOpcode::Barrier, IrType::Void, {});
|
||||
}
|
||||
|
||||
void TranslationContext::vCvt16F16(const RdnaInstruction& inst, bool signedValue) {
|
||||
throw std::runtime_error("TranslationContext::vCvt16F16 not implemented");
|
||||
void TranslationContext::sSendmsg(const RdnaInstruction&) {
|
||||
(void)ir.Emit(IrOpcode::Sendmsg, IrType::Void, {});
|
||||
}
|
||||
|
||||
void TranslationContext::vCvtRpiI32F32(const RdnaInstruction& inst) {
|
||||
throw std::runtime_error("TranslationContext::vCvtRpiI32F32 not implemented");
|
||||
void TranslationContext::sTtracedata() {
|
||||
(void)ir.Emit(IrOpcode::TtraceData, IrType::Void, {});
|
||||
}
|
||||
|
||||
void TranslationContext::vCvtFlrI32F32(const RdnaInstruction& inst) {
|
||||
throw std::runtime_error("TranslationContext::vCvtFlrI32F32 not implemented");
|
||||
void TranslationContext::sInstPrefetch() {
|
||||
(void)ir.Emit(IrOpcode::InstPrefetch, IrType::Void, {});
|
||||
}
|
||||
|
||||
void TranslationContext::vFrexpExpI32F32(const RdnaInstruction& inst) {
|
||||
throw std::runtime_error("TranslationContext::vFrexpExpI32F32 not implemented");
|
||||
void TranslationContext::sGetpcB64(const RdnaInstruction& inst) {
|
||||
const IrU64 pc(ir.ConstantU64(static_cast<std::uint64_t>(currentProgramCounter) + 4u));
|
||||
writeU32Pair(inst.destination, extractU64(pc));
|
||||
}
|
||||
|
||||
void TranslationContext::vCvtOffF32I4(const RdnaInstruction& inst) {
|
||||
throw std::runtime_error("TranslationContext::vCvtOffF32I4 not implemented");
|
||||
void TranslationContext::sCselectB32(const RdnaInstruction& inst) {
|
||||
const IrU32 trueValue = readU32(sourceAt(inst, 0u));
|
||||
const IrU32 falseValue = readU32(sourceAt(inst, 1u));
|
||||
const IrU32 result(ir.Select(ir.GetScc(), trueValue.Value(), falseValue.Value()));
|
||||
writeRawU32(inst.destination, result);
|
||||
}
|
||||
|
||||
void TranslationContext::vCvtPkrtzF16F32(const RdnaInstruction& inst) {
|
||||
throw std::runtime_error("TranslationContext::vCvtPkrtzF16F32 not implemented");
|
||||
void TranslationContext::scalarSelect64(const RdnaInstruction& inst, const RdnaOperand& falseSource) {
|
||||
const std::array<IrU32, 2> trueValue = readU32Pair(sourceAt(inst, 0u));
|
||||
const std::array<IrU32, 2> falseValue = readU32Pair(falseSource);
|
||||
IrValue& condition = ir.GetScc();
|
||||
const IrU32 low(ir.Select(condition, trueValue[0].Value(), falseValue[0].Value()));
|
||||
const IrU32 high(ir.Select(condition, trueValue[1].Value(), falseValue[1].Value()));
|
||||
writeU32Pair(inst.destination, {low, high});
|
||||
}
|
||||
|
||||
void TranslationContext::vCvtPknormF32(const RdnaInstruction& inst, IrOpcode opcode) {
|
||||
throw std::runtime_error("TranslationContext::vCvtPknormF32 not implemented");
|
||||
void TranslationContext::movB32(const RdnaInstruction& inst, bool applyFloatModifiers) {
|
||||
if (applyFloatModifiers) {
|
||||
IrF32 value(*readOperand(sourceAt(inst, 0u), IrType::F32));
|
||||
value = applyF32ResultModifiers(inst.destination, value);
|
||||
writeOperand(inst.destination, &value.Value());
|
||||
return;
|
||||
}
|
||||
IrValue* value = readOperand(sourceAt(inst, 0u), IrType::U32);
|
||||
writeOperand(inst.destination, value);
|
||||
}
|
||||
|
||||
void TranslationContext::vCvtPkU8F32(const RdnaInstruction& inst) {
|
||||
throw std::runtime_error("TranslationContext::vCvtPkU8F32 not implemented");
|
||||
void TranslationContext::sMovB64(const RdnaInstruction& inst) {
|
||||
const std::array<IrU32, 2> value = readU32Pair(sourceAt(inst, 0u));
|
||||
writeU32Pair(inst.destination, value);
|
||||
}
|
||||
|
||||
void TranslationContext::vPackB32F16(const RdnaInstruction& inst) {
|
||||
throw std::runtime_error("TranslationContext::vPackB32F16 not implemented");
|
||||
void TranslationContext::sWqm(const RdnaInstruction& inst, bool wide) {
|
||||
if (wide) {
|
||||
const std::array<IrU32, 2> source = readU32Pair(sourceAt(inst, 0u));
|
||||
const IrU64 wide64(ir.ConstructU64(source[0].Value(), source[1].Value()));
|
||||
const IrU64 result(ir.Emit(IrOpcode::WqmU64, IrType::U64, {&wide64.Value()}));
|
||||
writeU32Pair(inst.destination, extractU64(result));
|
||||
return;
|
||||
}
|
||||
const IrU32 source = readU32(sourceAt(inst, 0u));
|
||||
const IrU64 wide64(ir.ConstructU64(source.Value(), ir.Constant(0u)));
|
||||
const IrU64 result(ir.Emit(IrOpcode::WqmU64, IrType::U64, {&wide64.Value()}));
|
||||
writeRawU32(inst.destination, extractU64(result)[0]);
|
||||
}
|
||||
|
||||
void TranslateConvertInstruction(TranslationContext& context, const RdnaInstruction& instruction) {
|
||||
throw std::runtime_error("TranslateConvertInstruction not implemented");
|
||||
void TranslationContext::vMovrelsB32(const RdnaInstruction& inst) {
|
||||
throw std::runtime_error("dynamic M0-relative vector register addressing is not supported by this translator");
|
||||
}
|
||||
|
||||
void TranslationContext::vMovreldB32(const RdnaInstruction& inst) {
|
||||
throw std::runtime_error("dynamic M0-relative vector register addressing is not supported by this translator");
|
||||
}
|
||||
|
||||
void TranslationContext::vReadfirstlaneB32(const RdnaInstruction& inst) {
|
||||
const IrU32 value = readU32(sourceAt(inst, 0u));
|
||||
const IrU32 result(ir.Emit(IrOpcode::ReadFirstLane, IrType::U32, {&value.Value(), &ir.GetExec()}));
|
||||
writeRawU32(inst.destination, result);
|
||||
}
|
||||
|
||||
void TranslationContext::vReadlaneB32(const RdnaInstruction& inst) {
|
||||
const IrU32 value = readU32(sourceAt(inst, 0u));
|
||||
const IrU32 lane = readU32(sourceAt(inst, 1u));
|
||||
const IrU32 result(ir.Emit(IrOpcode::ReadLane, IrType::U32, {&value.Value(), &lane.Value()}));
|
||||
writeRawU32(inst.destination, result);
|
||||
}
|
||||
|
||||
void TranslationContext::vWritelaneB32(const RdnaInstruction& inst) {
|
||||
const IrU32 value = readU32(sourceAt(inst, 0u));
|
||||
const IrU32 lane = readU32(sourceAt(inst, 1u));
|
||||
const IrU32 previous = readRawU32(plainOperand(inst.destination));
|
||||
const IrU32 result(ir.Emit(IrOpcode::WriteLane, IrType::U32, {&value.Value(), &lane.Value(), &previous.Value()}));
|
||||
writeRawU32(inst.destination, result);
|
||||
}
|
||||
|
||||
void TranslationContext::vPermlane16B32(const RdnaInstruction& inst, bool x16) {
|
||||
const IrU32 value = readU32(sourceAt(inst, 0u));
|
||||
const IrU32 selectLow = readU32(sourceAt(inst, 1u));
|
||||
const IrU32 selectHigh = readU32(sourceAt(inst, 2u));
|
||||
const PermlaneFlags flags{x16, inst.destination.opSel, inst.destination.opSelHi};
|
||||
const IrU32 result(ir.Emit(IrOpcode::Permlane16U32, IrType::U32, {&value.Value(), &selectLow.Value(), &selectHigh.Value(), &ir.GetExec()}, flags));
|
||||
writeRawU32(inst.destination, result);
|
||||
}
|
||||
|
||||
void TranslateControlFlowInstruction(TranslationContext& context, const RdnaInstruction& instruction) {
|
||||
throw std::runtime_error("TranslateControlFlowInstruction not implemented");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue