shader: Add denorm flush support
This commit is contained in:
parent
6db69990da
commit
e2bc05b17d
20 changed files with 260 additions and 93 deletions
|
@ -558,53 +558,53 @@ F16F32F64 IREmitter::FPSaturate(const F16F32F64& value) {
|
|||
}
|
||||
}
|
||||
|
||||
F16F32F64 IREmitter::FPRoundEven(const F16F32F64& value) {
|
||||
F16F32F64 IREmitter::FPRoundEven(const F16F32F64& value, FpControl control) {
|
||||
switch (value.Type()) {
|
||||
case Type::F16:
|
||||
return Inst<F16>(Opcode::FPRoundEven16, value);
|
||||
return Inst<F16>(Opcode::FPRoundEven16, Flags{control}, value);
|
||||
case Type::F32:
|
||||
return Inst<F32>(Opcode::FPRoundEven32, value);
|
||||
return Inst<F32>(Opcode::FPRoundEven32, Flags{control}, value);
|
||||
case Type::F64:
|
||||
return Inst<F64>(Opcode::FPRoundEven64, value);
|
||||
return Inst<F64>(Opcode::FPRoundEven64, Flags{control}, value);
|
||||
default:
|
||||
ThrowInvalidType(value.Type());
|
||||
}
|
||||
}
|
||||
|
||||
F16F32F64 IREmitter::FPFloor(const F16F32F64& value) {
|
||||
F16F32F64 IREmitter::FPFloor(const F16F32F64& value, FpControl control) {
|
||||
switch (value.Type()) {
|
||||
case Type::F16:
|
||||
return Inst<F16>(Opcode::FPFloor16, value);
|
||||
return Inst<F16>(Opcode::FPFloor16, Flags{control}, value);
|
||||
case Type::F32:
|
||||
return Inst<F32>(Opcode::FPFloor32, value);
|
||||
return Inst<F32>(Opcode::FPFloor32, Flags{control}, value);
|
||||
case Type::F64:
|
||||
return Inst<F64>(Opcode::FPFloor64, value);
|
||||
return Inst<F64>(Opcode::FPFloor64, Flags{control}, value);
|
||||
default:
|
||||
ThrowInvalidType(value.Type());
|
||||
}
|
||||
}
|
||||
|
||||
F16F32F64 IREmitter::FPCeil(const F16F32F64& value) {
|
||||
F16F32F64 IREmitter::FPCeil(const F16F32F64& value, FpControl control) {
|
||||
switch (value.Type()) {
|
||||
case Type::F16:
|
||||
return Inst<F16>(Opcode::FPCeil16, value);
|
||||
return Inst<F16>(Opcode::FPCeil16, Flags{control}, value);
|
||||
case Type::F32:
|
||||
return Inst<F32>(Opcode::FPCeil32, value);
|
||||
return Inst<F32>(Opcode::FPCeil32, Flags{control}, value);
|
||||
case Type::F64:
|
||||
return Inst<F64>(Opcode::FPCeil64, value);
|
||||
return Inst<F64>(Opcode::FPCeil64, Flags{control}, value);
|
||||
default:
|
||||
ThrowInvalidType(value.Type());
|
||||
}
|
||||
}
|
||||
|
||||
F16F32F64 IREmitter::FPTrunc(const F16F32F64& value) {
|
||||
F16F32F64 IREmitter::FPTrunc(const F16F32F64& value, FpControl control) {
|
||||
switch (value.Type()) {
|
||||
case Type::F16:
|
||||
return Inst<F16>(Opcode::FPTrunc16, value);
|
||||
return Inst<F16>(Opcode::FPTrunc16, Flags{control}, value);
|
||||
case Type::F32:
|
||||
return Inst<F32>(Opcode::FPTrunc32, value);
|
||||
return Inst<F32>(Opcode::FPTrunc32, Flags{control}, value);
|
||||
case Type::F64:
|
||||
return Inst<F64>(Opcode::FPTrunc64, value);
|
||||
return Inst<F64>(Opcode::FPTrunc64, Flags{control}, value);
|
||||
default:
|
||||
ThrowInvalidType(value.Type());
|
||||
}
|
||||
|
|
|
@ -129,10 +129,10 @@ public:
|
|||
[[nodiscard]] F32 FPSinNotReduced(const F32& value);
|
||||
[[nodiscard]] F32 FPSqrt(const F32& value);
|
||||
[[nodiscard]] F16F32F64 FPSaturate(const F16F32F64& value);
|
||||
[[nodiscard]] F16F32F64 FPRoundEven(const F16F32F64& value);
|
||||
[[nodiscard]] F16F32F64 FPFloor(const F16F32F64& value);
|
||||
[[nodiscard]] F16F32F64 FPCeil(const F16F32F64& value);
|
||||
[[nodiscard]] F16F32F64 FPTrunc(const F16F32F64& value);
|
||||
[[nodiscard]] F16F32F64 FPRoundEven(const F16F32F64& value, FpControl control = {});
|
||||
[[nodiscard]] F16F32F64 FPFloor(const F16F32F64& value, FpControl control = {});
|
||||
[[nodiscard]] F16F32F64 FPCeil(const F16F32F64& value, FpControl control = {});
|
||||
[[nodiscard]] F16F32F64 FPTrunc(const F16F32F64& value, FpControl control = {});
|
||||
|
||||
[[nodiscard]] U32U64 IAdd(const U32U64& a, const U32U64& b);
|
||||
[[nodiscard]] U32U64 ISub(const U32U64& a, const U32U64& b);
|
||||
|
|
|
@ -4,25 +4,30 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Shader::IR {
|
||||
|
||||
enum class FmzMode : u8 {
|
||||
None, // Denorms are not flushed, NAN is propagated (nouveau)
|
||||
FTZ, // Flush denorms to zero, NAN is propagated (D3D11, NVN, GL, VK)
|
||||
FMZ, // Flush denorms to zero, x * 0 == 0 (D3D9)
|
||||
DontCare, // Not specified for this instruction
|
||||
FTZ, // Flush denorms to zero, NAN is propagated (D3D11, NVN, GL, VK)
|
||||
FMZ, // Flush denorms to zero, x * 0 == 0 (D3D9)
|
||||
None, // Denorms are not flushed, NAN is propagated (nouveau)
|
||||
};
|
||||
|
||||
enum class FpRounding : u8 {
|
||||
RN, // Round to nearest even,
|
||||
RM, // Round towards negative infinity
|
||||
RP, // Round towards positive infinity
|
||||
RZ, // Round towards zero
|
||||
DontCare, // Not specified for this instruction
|
||||
RN, // Round to nearest even,
|
||||
RM, // Round towards negative infinity
|
||||
RP, // Round towards positive infinity
|
||||
RZ, // Round towards zero
|
||||
};
|
||||
|
||||
struct FpControl {
|
||||
bool no_contraction{false};
|
||||
FpRounding rounding{FpRounding::RN};
|
||||
FmzMode fmz_mode{FmzMode::FTZ};
|
||||
FpRounding rounding{FpRounding::DontCare};
|
||||
FmzMode fmz_mode{FmzMode::DontCare};
|
||||
};
|
||||
static_assert(sizeof(FpControl) <= sizeof(u32));
|
||||
|
||||
} // namespace Shader::IR
|
||||
|
|
|
@ -81,17 +81,28 @@ void TranslateF2I(TranslatorVisitor& v, u64 insn, const IR::F16F32F64& src_a) {
|
|||
// F2I is used to convert from a floating point value to an integer
|
||||
const F2I f2i{insn};
|
||||
|
||||
const bool denorm_cares{f2i.src_format != SrcFormat::F16 && f2i.src_format != SrcFormat::F64 &&
|
||||
f2i.dest_format != DestFormat::I64};
|
||||
IR::FmzMode fmz_mode{IR::FmzMode::DontCare};
|
||||
if (denorm_cares) {
|
||||
fmz_mode = f2i.ftz != 0 ? IR::FmzMode::FTZ : IR::FmzMode::None;
|
||||
}
|
||||
const IR::FpControl fp_control{
|
||||
.no_contraction{true},
|
||||
.rounding{IR::FpRounding::DontCare},
|
||||
.fmz_mode{fmz_mode},
|
||||
};
|
||||
const IR::F16F32F64 op_a{v.ir.FPAbsNeg(src_a, f2i.abs != 0, f2i.neg != 0)};
|
||||
const IR::F16F32F64 rounded_value{[&] {
|
||||
switch (f2i.rounding) {
|
||||
case Rounding::Round:
|
||||
return v.ir.FPRoundEven(op_a);
|
||||
return v.ir.FPRoundEven(op_a, fp_control);
|
||||
case Rounding::Floor:
|
||||
return v.ir.FPFloor(op_a);
|
||||
return v.ir.FPFloor(op_a, fp_control);
|
||||
case Rounding::Ceil:
|
||||
return v.ir.FPCeil(op_a);
|
||||
return v.ir.FPCeil(op_a, fp_control);
|
||||
case Rounding::Trunc:
|
||||
return v.ir.FPTrunc(op_a);
|
||||
return v.ir.FPTrunc(op_a, fp_control);
|
||||
default:
|
||||
throw NotImplementedException("Invalid F2I rounding {}", f2i.rounding.Value());
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue