diff options
Diffstat (limited to 'src/shader_recompiler')
16 files changed, 427 insertions, 69 deletions
diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt index 31c394106..d0f0ec775 100644 --- a/src/shader_recompiler/CMakeLists.txt +++ b/src/shader_recompiler/CMakeLists.txt | |||
| @@ -84,6 +84,7 @@ add_library(shader_recompiler STATIC | |||
| 84 | frontend/maxwell/translate/impl/integer_add_three_input.cpp | 84 | frontend/maxwell/translate/impl/integer_add_three_input.cpp |
| 85 | frontend/maxwell/translate/impl/integer_compare.cpp | 85 | frontend/maxwell/translate/impl/integer_compare.cpp |
| 86 | frontend/maxwell/translate/impl/integer_compare_and_set.cpp | 86 | frontend/maxwell/translate/impl/integer_compare_and_set.cpp |
| 87 | frontend/maxwell/translate/impl/integer_floating_point_conversion.cpp | ||
| 87 | frontend/maxwell/translate/impl/integer_funnel_shift.cpp | 88 | frontend/maxwell/translate/impl/integer_funnel_shift.cpp |
| 88 | frontend/maxwell/translate/impl/integer_minimum_maximum.cpp | 89 | frontend/maxwell/translate/impl/integer_minimum_maximum.cpp |
| 89 | frontend/maxwell/translate/impl/integer_popcount.cpp | 90 | frontend/maxwell/translate/impl/integer_popcount.cpp |
diff --git a/src/shader_recompiler/backend/spirv/emit_context.cpp b/src/shader_recompiler/backend/spirv/emit_context.cpp index 6c79b611b..6c8f16562 100644 --- a/src/shader_recompiler/backend/spirv/emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/emit_context.cpp | |||
| @@ -89,6 +89,8 @@ Id EmitContext::Def(const IR::Value& value) { | |||
| 89 | return value.U1() ? true_value : false_value; | 89 | return value.U1() ? true_value : false_value; |
| 90 | case IR::Type::U32: | 90 | case IR::Type::U32: |
| 91 | return Constant(U32[1], value.U32()); | 91 | return Constant(U32[1], value.U32()); |
| 92 | case IR::Type::U64: | ||
| 93 | return Constant(U64, value.U64()); | ||
| 92 | case IR::Type::F32: | 94 | case IR::Type::F32: |
| 93 | return Constant(F32[1], value.F32()); | 95 | return Constant(F32[1], value.F32()); |
| 94 | case IR::Type::F64: | 96 | case IR::Type::F64: |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.h b/src/shader_recompiler/backend/spirv/emit_spirv.h index ae121f534..1fe65f8a9 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv.h | |||
| @@ -243,6 +243,7 @@ Id EmitIMul32(EmitContext& ctx, Id a, Id b); | |||
| 243 | Id EmitINeg32(EmitContext& ctx, Id value); | 243 | Id EmitINeg32(EmitContext& ctx, Id value); |
| 244 | Id EmitINeg64(EmitContext& ctx, Id value); | 244 | Id EmitINeg64(EmitContext& ctx, Id value); |
| 245 | Id EmitIAbs32(EmitContext& ctx, Id value); | 245 | Id EmitIAbs32(EmitContext& ctx, Id value); |
| 246 | Id EmitIAbs64(EmitContext& ctx, Id value); | ||
| 246 | Id EmitShiftLeftLogical32(EmitContext& ctx, Id base, Id shift); | 247 | Id EmitShiftLeftLogical32(EmitContext& ctx, Id base, Id shift); |
| 247 | Id EmitShiftLeftLogical64(EmitContext& ctx, Id base, Id shift); | 248 | Id EmitShiftLeftLogical64(EmitContext& ctx, Id base, Id shift); |
| 248 | Id EmitShiftRightLogical32(EmitContext& ctx, Id base, Id shift); | 249 | Id EmitShiftRightLogical32(EmitContext& ctx, Id base, Id shift); |
| @@ -302,16 +303,28 @@ Id EmitConvertF16F32(EmitContext& ctx, Id value); | |||
| 302 | Id EmitConvertF32F16(EmitContext& ctx, Id value); | 303 | Id EmitConvertF32F16(EmitContext& ctx, Id value); |
| 303 | Id EmitConvertF32F64(EmitContext& ctx, Id value); | 304 | Id EmitConvertF32F64(EmitContext& ctx, Id value); |
| 304 | Id EmitConvertF64F32(EmitContext& ctx, Id value); | 305 | Id EmitConvertF64F32(EmitContext& ctx, Id value); |
| 306 | Id EmitConvertF16S8(EmitContext& ctx, Id value); | ||
| 307 | Id EmitConvertF16S16(EmitContext& ctx, Id value); | ||
| 305 | Id EmitConvertF16S32(EmitContext& ctx, Id value); | 308 | Id EmitConvertF16S32(EmitContext& ctx, Id value); |
| 306 | Id EmitConvertF16S64(EmitContext& ctx, Id value); | 309 | Id EmitConvertF16S64(EmitContext& ctx, Id value); |
| 310 | Id EmitConvertF16U8(EmitContext& ctx, Id value); | ||
| 311 | Id EmitConvertF16U16(EmitContext& ctx, Id value); | ||
| 307 | Id EmitConvertF16U32(EmitContext& ctx, Id value); | 312 | Id EmitConvertF16U32(EmitContext& ctx, Id value); |
| 308 | Id EmitConvertF16U64(EmitContext& ctx, Id value); | 313 | Id EmitConvertF16U64(EmitContext& ctx, Id value); |
| 314 | Id EmitConvertF32S8(EmitContext& ctx, Id value); | ||
| 315 | Id EmitConvertF32S16(EmitContext& ctx, Id value); | ||
| 309 | Id EmitConvertF32S32(EmitContext& ctx, Id value); | 316 | Id EmitConvertF32S32(EmitContext& ctx, Id value); |
| 310 | Id EmitConvertF32S64(EmitContext& ctx, Id value); | 317 | Id EmitConvertF32S64(EmitContext& ctx, Id value); |
| 318 | Id EmitConvertF32U8(EmitContext& ctx, Id value); | ||
| 319 | Id EmitConvertF32U16(EmitContext& ctx, Id value); | ||
| 311 | Id EmitConvertF32U32(EmitContext& ctx, Id value); | 320 | Id EmitConvertF32U32(EmitContext& ctx, Id value); |
| 312 | Id EmitConvertF32U64(EmitContext& ctx, Id value); | 321 | Id EmitConvertF32U64(EmitContext& ctx, Id value); |
| 322 | Id EmitConvertF64S8(EmitContext& ctx, Id value); | ||
| 323 | Id EmitConvertF64S16(EmitContext& ctx, Id value); | ||
| 313 | Id EmitConvertF64S32(EmitContext& ctx, Id value); | 324 | Id EmitConvertF64S32(EmitContext& ctx, Id value); |
| 314 | Id EmitConvertF64S64(EmitContext& ctx, Id value); | 325 | Id EmitConvertF64S64(EmitContext& ctx, Id value); |
| 326 | Id EmitConvertF64U8(EmitContext& ctx, Id value); | ||
| 327 | Id EmitConvertF64U16(EmitContext& ctx, Id value); | ||
| 315 | Id EmitConvertF64U32(EmitContext& ctx, Id value); | 328 | Id EmitConvertF64U32(EmitContext& ctx, Id value); |
| 316 | Id EmitConvertF64U64(EmitContext& ctx, Id value); | 329 | Id EmitConvertF64U64(EmitContext& ctx, Id value); |
| 317 | Id EmitBindlessImageSampleImplicitLod(EmitContext&); | 330 | Id EmitBindlessImageSampleImplicitLod(EmitContext&); |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp index 2aff673aa..757165626 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp | |||
| @@ -102,6 +102,14 @@ Id EmitConvertF64F32(EmitContext& ctx, Id value) { | |||
| 102 | return ctx.OpFConvert(ctx.F64[1], value); | 102 | return ctx.OpFConvert(ctx.F64[1], value); |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | Id EmitConvertF16S8(EmitContext& ctx, Id value) { | ||
| 106 | return ctx.OpConvertSToF(ctx.F16[1], value); | ||
| 107 | } | ||
| 108 | |||
| 109 | Id EmitConvertF16S16(EmitContext& ctx, Id value) { | ||
| 110 | return ctx.OpConvertSToF(ctx.F16[1], value); | ||
| 111 | } | ||
| 112 | |||
| 105 | Id EmitConvertF16S32(EmitContext& ctx, Id value) { | 113 | Id EmitConvertF16S32(EmitContext& ctx, Id value) { |
| 106 | return ctx.OpConvertSToF(ctx.F16[1], value); | 114 | return ctx.OpConvertSToF(ctx.F16[1], value); |
| 107 | } | 115 | } |
| @@ -110,6 +118,14 @@ Id EmitConvertF16S64(EmitContext& ctx, Id value) { | |||
| 110 | return ctx.OpConvertSToF(ctx.F16[1], value); | 118 | return ctx.OpConvertSToF(ctx.F16[1], value); |
| 111 | } | 119 | } |
| 112 | 120 | ||
| 121 | Id EmitConvertF16U8(EmitContext& ctx, Id value) { | ||
| 122 | return ctx.OpConvertUToF(ctx.F16[1], value); | ||
| 123 | } | ||
| 124 | |||
| 125 | Id EmitConvertF16U16(EmitContext& ctx, Id value) { | ||
| 126 | return ctx.OpConvertUToF(ctx.F16[1], value); | ||
| 127 | } | ||
| 128 | |||
| 113 | Id EmitConvertF16U32(EmitContext& ctx, Id value) { | 129 | Id EmitConvertF16U32(EmitContext& ctx, Id value) { |
| 114 | return ctx.OpConvertUToF(ctx.F16[1], value); | 130 | return ctx.OpConvertUToF(ctx.F16[1], value); |
| 115 | } | 131 | } |
| @@ -118,6 +134,14 @@ Id EmitConvertF16U64(EmitContext& ctx, Id value) { | |||
| 118 | return ctx.OpConvertUToF(ctx.F16[1], value); | 134 | return ctx.OpConvertUToF(ctx.F16[1], value); |
| 119 | } | 135 | } |
| 120 | 136 | ||
| 137 | Id EmitConvertF32S8(EmitContext& ctx, Id value) { | ||
| 138 | return ctx.OpConvertSToF(ctx.F32[1], ctx.OpUConvert(ctx.U8, value)); | ||
| 139 | } | ||
| 140 | |||
| 141 | Id EmitConvertF32S16(EmitContext& ctx, Id value) { | ||
| 142 | return ctx.OpConvertSToF(ctx.F32[1], ctx.OpUConvert(ctx.U16, value)); | ||
| 143 | } | ||
| 144 | |||
| 121 | Id EmitConvertF32S32(EmitContext& ctx, Id value) { | 145 | Id EmitConvertF32S32(EmitContext& ctx, Id value) { |
| 122 | return ctx.OpConvertSToF(ctx.F32[1], value); | 146 | return ctx.OpConvertSToF(ctx.F32[1], value); |
| 123 | } | 147 | } |
| @@ -126,6 +150,14 @@ Id EmitConvertF32S64(EmitContext& ctx, Id value) { | |||
| 126 | return ctx.OpConvertSToF(ctx.F32[1], value); | 150 | return ctx.OpConvertSToF(ctx.F32[1], value); |
| 127 | } | 151 | } |
| 128 | 152 | ||
| 153 | Id EmitConvertF32U8(EmitContext& ctx, Id value) { | ||
| 154 | return ctx.OpConvertUToF(ctx.F32[1], ctx.OpUConvert(ctx.U8, value)); | ||
| 155 | } | ||
| 156 | |||
| 157 | Id EmitConvertF32U16(EmitContext& ctx, Id value) { | ||
| 158 | return ctx.OpConvertUToF(ctx.F32[1], ctx.OpUConvert(ctx.U16, value)); | ||
| 159 | } | ||
| 160 | |||
| 129 | Id EmitConvertF32U32(EmitContext& ctx, Id value) { | 161 | Id EmitConvertF32U32(EmitContext& ctx, Id value) { |
| 130 | return ctx.OpConvertUToF(ctx.F32[1], value); | 162 | return ctx.OpConvertUToF(ctx.F32[1], value); |
| 131 | } | 163 | } |
| @@ -134,6 +166,14 @@ Id EmitConvertF32U64(EmitContext& ctx, Id value) { | |||
| 134 | return ctx.OpConvertUToF(ctx.F32[1], value); | 166 | return ctx.OpConvertUToF(ctx.F32[1], value); |
| 135 | } | 167 | } |
| 136 | 168 | ||
| 169 | Id EmitConvertF64S8(EmitContext& ctx, Id value) { | ||
| 170 | return ctx.OpConvertSToF(ctx.F64[1], ctx.OpUConvert(ctx.U8, value)); | ||
| 171 | } | ||
| 172 | |||
| 173 | Id EmitConvertF64S16(EmitContext& ctx, Id value) { | ||
| 174 | return ctx.OpConvertSToF(ctx.F64[1], ctx.OpUConvert(ctx.U16, value)); | ||
| 175 | } | ||
| 176 | |||
| 137 | Id EmitConvertF64S32(EmitContext& ctx, Id value) { | 177 | Id EmitConvertF64S32(EmitContext& ctx, Id value) { |
| 138 | return ctx.OpConvertSToF(ctx.F64[1], value); | 178 | return ctx.OpConvertSToF(ctx.F64[1], value); |
| 139 | } | 179 | } |
| @@ -142,6 +182,14 @@ Id EmitConvertF64S64(EmitContext& ctx, Id value) { | |||
| 142 | return ctx.OpConvertSToF(ctx.F64[1], value); | 182 | return ctx.OpConvertSToF(ctx.F64[1], value); |
| 143 | } | 183 | } |
| 144 | 184 | ||
| 185 | Id EmitConvertF64U8(EmitContext& ctx, Id value) { | ||
| 186 | return ctx.OpConvertUToF(ctx.F64[1], ctx.OpUConvert(ctx.U8, value)); | ||
| 187 | } | ||
| 188 | |||
| 189 | Id EmitConvertF64U16(EmitContext& ctx, Id value) { | ||
| 190 | return ctx.OpConvertUToF(ctx.F64[1], ctx.OpUConvert(ctx.U16, value)); | ||
| 191 | } | ||
| 192 | |||
| 145 | Id EmitConvertF64U32(EmitContext& ctx, Id value) { | 193 | Id EmitConvertF64U32(EmitContext& ctx, Id value) { |
| 146 | return ctx.OpConvertUToF(ctx.F64[1], value); | 194 | return ctx.OpConvertUToF(ctx.F64[1], value); |
| 147 | } | 195 | } |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp index c9de204b0..a9c5e9cca 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp | |||
| @@ -70,6 +70,10 @@ Id EmitIAbs32(EmitContext& ctx, Id value) { | |||
| 70 | return ctx.OpSAbs(ctx.U32[1], value); | 70 | return ctx.OpSAbs(ctx.U32[1], value); |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | Id EmitIAbs64(EmitContext& ctx, Id value) { | ||
| 74 | return ctx.OpSAbs(ctx.U64, value); | ||
| 75 | } | ||
| 76 | |||
| 73 | Id EmitShiftLeftLogical32(EmitContext& ctx, Id base, Id shift) { | 77 | Id EmitShiftLeftLogical32(EmitContext& ctx, Id base, Id shift) { |
| 74 | return ctx.OpShiftLeftLogical(ctx.U32[1], base, shift); | 78 | return ctx.OpShiftLeftLogical(ctx.U32[1], base, shift); |
| 75 | } | 79 | } |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp index 672836c0b..652f6949e 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp +++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp | |||
| @@ -53,6 +53,10 @@ U64 IREmitter::Imm64(u64 value) const { | |||
| 53 | return U64{Value{value}}; | 53 | return U64{Value{value}}; |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | U64 IREmitter::Imm64(s64 value) const { | ||
| 57 | return U64{Value{static_cast<u64>(value)}}; | ||
| 58 | } | ||
| 59 | |||
| 56 | F64 IREmitter::Imm64(f64 value) const { | 60 | F64 IREmitter::Imm64(f64 value) const { |
| 57 | return F64{Value{value}}; | 61 | return F64{Value{value}}; |
| 58 | } | 62 | } |
| @@ -363,7 +367,7 @@ U1 IREmitter::GetSparseFromOp(const Value& op) { | |||
| 363 | } | 367 | } |
| 364 | 368 | ||
| 365 | F16F32F64 IREmitter::FPAdd(const F16F32F64& a, const F16F32F64& b, FpControl control) { | 369 | F16F32F64 IREmitter::FPAdd(const F16F32F64& a, const F16F32F64& b, FpControl control) { |
| 366 | if (a.Type() != a.Type()) { | 370 | if (a.Type() != b.Type()) { |
| 367 | throw InvalidArgument("Mismatching types {} and {}", a.Type(), b.Type()); | 371 | throw InvalidArgument("Mismatching types {} and {}", a.Type(), b.Type()); |
| 368 | } | 372 | } |
| 369 | switch (a.Type()) { | 373 | switch (a.Type()) { |
| @@ -974,8 +978,15 @@ U32U64 IREmitter::INeg(const U32U64& value) { | |||
| 974 | } | 978 | } |
| 975 | } | 979 | } |
| 976 | 980 | ||
| 977 | U32 IREmitter::IAbs(const U32& value) { | 981 | U32U64 IREmitter::IAbs(const U32U64& value) { |
| 978 | return Inst<U32>(Opcode::IAbs32, value); | 982 | switch (value.Type()) { |
| 983 | case Type::U32: | ||
| 984 | return Inst<U32>(Opcode::IAbs32, value); | ||
| 985 | case Type::U64: | ||
| 986 | return Inst<U64>(Opcode::IAbs64, value); | ||
| 987 | default: | ||
| 988 | ThrowInvalidType(value.Type()); | ||
| 989 | } | ||
| 979 | } | 990 | } |
| 980 | 991 | ||
| 981 | U32U64 IREmitter::ShiftLeftLogical(const U32U64& base, const U32& shift) { | 992 | U32U64 IREmitter::ShiftLeftLogical(const U32U64& base, const U32& shift) { |
| @@ -1074,8 +1085,25 @@ U1 IREmitter::ILessThan(const U32& lhs, const U32& rhs, bool is_signed) { | |||
| 1074 | return Inst<U1>(is_signed ? Opcode::SLessThan : Opcode::ULessThan, lhs, rhs); | 1085 | return Inst<U1>(is_signed ? Opcode::SLessThan : Opcode::ULessThan, lhs, rhs); |
| 1075 | } | 1086 | } |
| 1076 | 1087 | ||
| 1077 | U1 IREmitter::IEqual(const U32& lhs, const U32& rhs) { | 1088 | U1 IREmitter::IEqual(const U32U64& lhs, const U32U64& rhs) { |
| 1078 | return Inst<U1>(Opcode::IEqual, lhs, rhs); | 1089 | if (lhs.Type() != rhs.Type()) { |
| 1090 | throw InvalidArgument("Mismatching types {} and {}", lhs.Type(), rhs.Type()); | ||
| 1091 | } | ||
| 1092 | switch (lhs.Type()) { | ||
| 1093 | case Type::U32: | ||
| 1094 | return Inst<U1>(Opcode::IEqual, lhs, rhs); | ||
| 1095 | case Type::U64: { | ||
| 1096 | // Manually compare the unpacked values | ||
| 1097 | const Value lhs_vector{UnpackUint2x32(lhs)}; | ||
| 1098 | const Value rhs_vector{UnpackUint2x32(rhs)}; | ||
| 1099 | return LogicalAnd(IEqual(IR::U32{CompositeExtract(lhs_vector, 0)}, | ||
| 1100 | IR::U32{CompositeExtract(rhs_vector, 0)}), | ||
| 1101 | IEqual(IR::U32{CompositeExtract(lhs_vector, 1)}, | ||
| 1102 | IR::U32{CompositeExtract(rhs_vector, 1)})); | ||
| 1103 | } | ||
| 1104 | default: | ||
| 1105 | ThrowInvalidType(lhs.Type()); | ||
| 1106 | } | ||
| 1079 | } | 1107 | } |
| 1080 | 1108 | ||
| 1081 | U1 IREmitter::ILessThanEqual(const U32& lhs, const U32& rhs, bool is_signed) { | 1109 | U1 IREmitter::ILessThanEqual(const U32& lhs, const U32& rhs, bool is_signed) { |
| @@ -1198,79 +1226,96 @@ U32U64 IREmitter::ConvertFToI(size_t bitsize, bool is_signed, const F16F32F64& v | |||
| 1198 | } | 1226 | } |
| 1199 | } | 1227 | } |
| 1200 | 1228 | ||
| 1201 | F16F32F64 IREmitter::ConvertSToF(size_t bitsize, const U32U64& value) { | 1229 | F16F32F64 IREmitter::ConvertSToF(size_t dest_bitsize, size_t src_bitsize, const Value& value) { |
| 1202 | switch (bitsize) { | 1230 | switch (dest_bitsize) { |
| 1203 | case 16: | 1231 | case 16: |
| 1204 | switch (value.Type()) { | 1232 | switch (src_bitsize) { |
| 1205 | case Type::U32: | 1233 | case 8: |
| 1234 | return Inst<F16>(Opcode::ConvertF16S8, value); | ||
| 1235 | case 16: | ||
| 1236 | return Inst<F16>(Opcode::ConvertF16S16, value); | ||
| 1237 | case 32: | ||
| 1206 | return Inst<F16>(Opcode::ConvertF16S32, value); | 1238 | return Inst<F16>(Opcode::ConvertF16S32, value); |
| 1207 | case Type::U64: | 1239 | case 64: |
| 1208 | return Inst<F16>(Opcode::ConvertF16S64, value); | 1240 | return Inst<F16>(Opcode::ConvertF16S64, value); |
| 1209 | default: | ||
| 1210 | ThrowInvalidType(value.Type()); | ||
| 1211 | } | 1241 | } |
| 1242 | break; | ||
| 1212 | case 32: | 1243 | case 32: |
| 1213 | switch (value.Type()) { | 1244 | switch (src_bitsize) { |
| 1214 | case Type::U32: | 1245 | case 8: |
| 1246 | return Inst<F32>(Opcode::ConvertF32S8, value); | ||
| 1247 | case 16: | ||
| 1248 | return Inst<F32>(Opcode::ConvertF32S16, value); | ||
| 1249 | case 32: | ||
| 1215 | return Inst<F32>(Opcode::ConvertF32S32, value); | 1250 | return Inst<F32>(Opcode::ConvertF32S32, value); |
| 1216 | case Type::U64: | 1251 | case 64: |
| 1217 | return Inst<F32>(Opcode::ConvertF32S64, value); | 1252 | return Inst<F32>(Opcode::ConvertF32S64, value); |
| 1218 | default: | ||
| 1219 | ThrowInvalidType(value.Type()); | ||
| 1220 | } | 1253 | } |
| 1254 | break; | ||
| 1221 | case 64: | 1255 | case 64: |
| 1222 | switch (value.Type()) { | 1256 | switch (src_bitsize) { |
| 1223 | case Type::U32: | 1257 | case 8: |
| 1224 | return Inst<F16>(Opcode::ConvertF64S32, value); | 1258 | return Inst<F64>(Opcode::ConvertF64S8, value); |
| 1225 | case Type::U64: | 1259 | case 16: |
| 1226 | return Inst<F16>(Opcode::ConvertF64S64, value); | 1260 | return Inst<F64>(Opcode::ConvertF64S16, value); |
| 1227 | default: | 1261 | case 32: |
| 1228 | ThrowInvalidType(value.Type()); | 1262 | return Inst<F64>(Opcode::ConvertF64S32, value); |
| 1263 | case 64: | ||
| 1264 | return Inst<F64>(Opcode::ConvertF64S64, value); | ||
| 1229 | } | 1265 | } |
| 1230 | default: | 1266 | break; |
| 1231 | throw InvalidArgument("Invalid destination bitsize {}", bitsize); | ||
| 1232 | } | 1267 | } |
| 1268 | throw InvalidArgument("Invalid bit size combination dst={} src={}", dest_bitsize, src_bitsize); | ||
| 1233 | } | 1269 | } |
| 1234 | 1270 | ||
| 1235 | F16F32F64 IREmitter::ConvertUToF(size_t bitsize, const U32U64& value) { | 1271 | F16F32F64 IREmitter::ConvertUToF(size_t dest_bitsize, size_t src_bitsize, const Value& value) { |
| 1236 | switch (bitsize) { | 1272 | switch (dest_bitsize) { |
| 1237 | case 16: | 1273 | case 16: |
| 1238 | switch (value.Type()) { | 1274 | switch (src_bitsize) { |
| 1239 | case Type::U32: | 1275 | case 8: |
| 1276 | return Inst<F16>(Opcode::ConvertF16U8, value); | ||
| 1277 | case 16: | ||
| 1278 | return Inst<F16>(Opcode::ConvertF16U16, value); | ||
| 1279 | case 32: | ||
| 1240 | return Inst<F16>(Opcode::ConvertF16U32, value); | 1280 | return Inst<F16>(Opcode::ConvertF16U32, value); |
| 1241 | case Type::U64: | 1281 | case 64: |
| 1242 | return Inst<F16>(Opcode::ConvertF16U64, value); | 1282 | return Inst<F16>(Opcode::ConvertF16U64, value); |
| 1243 | default: | ||
| 1244 | ThrowInvalidType(value.Type()); | ||
| 1245 | } | 1283 | } |
| 1284 | break; | ||
| 1246 | case 32: | 1285 | case 32: |
| 1247 | switch (value.Type()) { | 1286 | switch (src_bitsize) { |
| 1248 | case Type::U32: | 1287 | case 8: |
| 1288 | return Inst<F32>(Opcode::ConvertF32U8, value); | ||
| 1289 | case 16: | ||
| 1290 | return Inst<F32>(Opcode::ConvertF32U16, value); | ||
| 1291 | case 32: | ||
| 1249 | return Inst<F32>(Opcode::ConvertF32U32, value); | 1292 | return Inst<F32>(Opcode::ConvertF32U32, value); |
| 1250 | case Type::U64: | 1293 | case 64: |
| 1251 | return Inst<F32>(Opcode::ConvertF32U64, value); | 1294 | return Inst<F32>(Opcode::ConvertF32U64, value); |
| 1252 | default: | ||
| 1253 | ThrowInvalidType(value.Type()); | ||
| 1254 | } | 1295 | } |
| 1296 | break; | ||
| 1255 | case 64: | 1297 | case 64: |
| 1256 | switch (value.Type()) { | 1298 | switch (src_bitsize) { |
| 1257 | case Type::U32: | 1299 | case 8: |
| 1258 | return Inst<F16>(Opcode::ConvertF64U32, value); | 1300 | return Inst<F64>(Opcode::ConvertF64U8, value); |
| 1259 | case Type::U64: | 1301 | case 16: |
| 1260 | return Inst<F16>(Opcode::ConvertF64U64, value); | 1302 | return Inst<F64>(Opcode::ConvertF64U16, value); |
| 1261 | default: | 1303 | case 32: |
| 1262 | ThrowInvalidType(value.Type()); | 1304 | return Inst<F64>(Opcode::ConvertF64U32, value); |
| 1305 | case 64: | ||
| 1306 | return Inst<F64>(Opcode::ConvertF64U64, value); | ||
| 1263 | } | 1307 | } |
| 1264 | default: | 1308 | break; |
| 1265 | throw InvalidArgument("Invalid destination bitsize {}", bitsize); | ||
| 1266 | } | 1309 | } |
| 1310 | throw InvalidArgument("Invalid bit size combination dst={} src={}", dest_bitsize, src_bitsize); | ||
| 1267 | } | 1311 | } |
| 1268 | 1312 | ||
| 1269 | F16F32F64 IREmitter::ConvertIToF(size_t bitsize, bool is_signed, const U32U64& value) { | 1313 | F16F32F64 IREmitter::ConvertIToF(size_t dest_bitsize, size_t src_bitsize, bool is_signed, |
| 1314 | const Value& value) { | ||
| 1270 | if (is_signed) { | 1315 | if (is_signed) { |
| 1271 | return ConvertSToF(bitsize, value); | 1316 | return ConvertSToF(dest_bitsize, src_bitsize, value); |
| 1272 | } else { | 1317 | } else { |
| 1273 | return ConvertUToF(bitsize, value); | 1318 | return ConvertUToF(dest_bitsize, src_bitsize, value); |
| 1274 | } | 1319 | } |
| 1275 | } | 1320 | } |
| 1276 | 1321 | ||
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h index 72af5db37..8edb11154 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.h +++ b/src/shader_recompiler/frontend/ir/ir_emitter.h | |||
| @@ -29,6 +29,7 @@ public: | |||
| 29 | [[nodiscard]] U32 Imm32(s32 value) const; | 29 | [[nodiscard]] U32 Imm32(s32 value) const; |
| 30 | [[nodiscard]] F32 Imm32(f32 value) const; | 30 | [[nodiscard]] F32 Imm32(f32 value) const; |
| 31 | [[nodiscard]] U64 Imm64(u64 value) const; | 31 | [[nodiscard]] U64 Imm64(u64 value) const; |
| 32 | [[nodiscard]] U64 Imm64(s64 value) const; | ||
| 32 | [[nodiscard]] F64 Imm64(f64 value) const; | 33 | [[nodiscard]] F64 Imm64(f64 value) const; |
| 33 | 34 | ||
| 34 | void Branch(Block* label); | 35 | void Branch(Block* label); |
| @@ -170,7 +171,7 @@ public: | |||
| 170 | [[nodiscard]] U32U64 ISub(const U32U64& a, const U32U64& b); | 171 | [[nodiscard]] U32U64 ISub(const U32U64& a, const U32U64& b); |
| 171 | [[nodiscard]] U32 IMul(const U32& a, const U32& b); | 172 | [[nodiscard]] U32 IMul(const U32& a, const U32& b); |
| 172 | [[nodiscard]] U32U64 INeg(const U32U64& value); | 173 | [[nodiscard]] U32U64 INeg(const U32U64& value); |
| 173 | [[nodiscard]] U32 IAbs(const U32& value); | 174 | [[nodiscard]] U32U64 IAbs(const U32U64& value); |
| 174 | [[nodiscard]] U32U64 ShiftLeftLogical(const U32U64& base, const U32& shift); | 175 | [[nodiscard]] U32U64 ShiftLeftLogical(const U32U64& base, const U32& shift); |
| 175 | [[nodiscard]] U32U64 ShiftRightLogical(const U32U64& base, const U32& shift); | 176 | [[nodiscard]] U32U64 ShiftRightLogical(const U32U64& base, const U32& shift); |
| 176 | [[nodiscard]] U32U64 ShiftRightArithmetic(const U32U64& base, const U32& shift); | 177 | [[nodiscard]] U32U64 ShiftRightArithmetic(const U32U64& base, const U32& shift); |
| @@ -193,7 +194,7 @@ public: | |||
| 193 | [[nodiscard]] U32 UMax(const U32& a, const U32& b); | 194 | [[nodiscard]] U32 UMax(const U32& a, const U32& b); |
| 194 | 195 | ||
| 195 | [[nodiscard]] U1 ILessThan(const U32& lhs, const U32& rhs, bool is_signed); | 196 | [[nodiscard]] U1 ILessThan(const U32& lhs, const U32& rhs, bool is_signed); |
| 196 | [[nodiscard]] U1 IEqual(const U32& lhs, const U32& rhs); | 197 | [[nodiscard]] U1 IEqual(const U32U64& lhs, const U32U64& rhs); |
| 197 | [[nodiscard]] U1 ILessThanEqual(const U32& lhs, const U32& rhs, bool is_signed); | 198 | [[nodiscard]] U1 ILessThanEqual(const U32& lhs, const U32& rhs, bool is_signed); |
| 198 | [[nodiscard]] U1 IGreaterThan(const U32& lhs, const U32& rhs, bool is_signed); | 199 | [[nodiscard]] U1 IGreaterThan(const U32& lhs, const U32& rhs, bool is_signed); |
| 199 | [[nodiscard]] U1 INotEqual(const U32& lhs, const U32& rhs); | 200 | [[nodiscard]] U1 INotEqual(const U32& lhs, const U32& rhs); |
| @@ -207,9 +208,12 @@ public: | |||
| 207 | [[nodiscard]] U32U64 ConvertFToS(size_t bitsize, const F16F32F64& value); | 208 | [[nodiscard]] U32U64 ConvertFToS(size_t bitsize, const F16F32F64& value); |
| 208 | [[nodiscard]] U32U64 ConvertFToU(size_t bitsize, const F16F32F64& value); | 209 | [[nodiscard]] U32U64 ConvertFToU(size_t bitsize, const F16F32F64& value); |
| 209 | [[nodiscard]] U32U64 ConvertFToI(size_t bitsize, bool is_signed, const F16F32F64& value); | 210 | [[nodiscard]] U32U64 ConvertFToI(size_t bitsize, bool is_signed, const F16F32F64& value); |
| 210 | [[nodiscard]] F16F32F64 ConvertSToF(size_t bitsize, const U32U64& value); | 211 | [[nodiscard]] F16F32F64 ConvertSToF(size_t dest_bitsize, size_t src_bitsize, |
| 211 | [[nodiscard]] F16F32F64 ConvertUToF(size_t bitsize, const U32U64& value); | 212 | const Value& value); |
| 212 | [[nodiscard]] F16F32F64 ConvertIToF(size_t bitsize, bool is_signed, const U32U64& value); | 213 | [[nodiscard]] F16F32F64 ConvertUToF(size_t dest_bitsize, size_t src_bitsize, |
| 214 | const Value& value); | ||
| 215 | [[nodiscard]] F16F32F64 ConvertIToF(size_t dest_bitsize, size_t src_bitsize, bool is_signed, | ||
| 216 | const Value& value); | ||
| 213 | 217 | ||
| 214 | [[nodiscard]] U32U64 UConvert(size_t result_bitsize, const U32U64& value); | 218 | [[nodiscard]] U32U64 UConvert(size_t result_bitsize, const U32U64& value); |
| 215 | [[nodiscard]] F16F32F64 FPConvert(size_t result_bitsize, const F16F32F64& value); | 219 | [[nodiscard]] F16F32F64 FPConvert(size_t result_bitsize, const F16F32F64& value); |
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc index 593faca52..8471db7b9 100644 --- a/src/shader_recompiler/frontend/ir/opcodes.inc +++ b/src/shader_recompiler/frontend/ir/opcodes.inc | |||
| @@ -247,6 +247,7 @@ OPCODE(IMul32, U32, U32, | |||
| 247 | OPCODE(INeg32, U32, U32, ) | 247 | OPCODE(INeg32, U32, U32, ) |
| 248 | OPCODE(INeg64, U64, U64, ) | 248 | OPCODE(INeg64, U64, U64, ) |
| 249 | OPCODE(IAbs32, U32, U32, ) | 249 | OPCODE(IAbs32, U32, U32, ) |
| 250 | OPCODE(IAbs64, U64, U64, ) | ||
| 250 | OPCODE(ShiftLeftLogical32, U32, U32, U32, ) | 251 | OPCODE(ShiftLeftLogical32, U32, U32, U32, ) |
| 251 | OPCODE(ShiftLeftLogical64, U64, U64, U32, ) | 252 | OPCODE(ShiftLeftLogical64, U64, U64, U32, ) |
| 252 | OPCODE(ShiftRightLogical32, U32, U32, U32, ) | 253 | OPCODE(ShiftRightLogical32, U32, U32, U32, ) |
| @@ -311,16 +312,28 @@ OPCODE(ConvertF16F32, F16, F32, | |||
| 311 | OPCODE(ConvertF32F16, F32, F16, ) | 312 | OPCODE(ConvertF32F16, F32, F16, ) |
| 312 | OPCODE(ConvertF32F64, F32, F64, ) | 313 | OPCODE(ConvertF32F64, F32, F64, ) |
| 313 | OPCODE(ConvertF64F32, F64, F32, ) | 314 | OPCODE(ConvertF64F32, F64, F32, ) |
| 315 | OPCODE(ConvertF16S8, F16, U32, ) | ||
| 316 | OPCODE(ConvertF16S16, F16, U32, ) | ||
| 314 | OPCODE(ConvertF16S32, F16, U32, ) | 317 | OPCODE(ConvertF16S32, F16, U32, ) |
| 315 | OPCODE(ConvertF16S64, F16, U64, ) | 318 | OPCODE(ConvertF16S64, F16, U64, ) |
| 319 | OPCODE(ConvertF16U8, F16, U32, ) | ||
| 320 | OPCODE(ConvertF16U16, F16, U32, ) | ||
| 316 | OPCODE(ConvertF16U32, F16, U32, ) | 321 | OPCODE(ConvertF16U32, F16, U32, ) |
| 317 | OPCODE(ConvertF16U64, F16, U64, ) | 322 | OPCODE(ConvertF16U64, F16, U64, ) |
| 323 | OPCODE(ConvertF32S8, F32, U32, ) | ||
| 324 | OPCODE(ConvertF32S16, F32, U32, ) | ||
| 318 | OPCODE(ConvertF32S32, F32, U32, ) | 325 | OPCODE(ConvertF32S32, F32, U32, ) |
| 319 | OPCODE(ConvertF32S64, F32, U64, ) | 326 | OPCODE(ConvertF32S64, F32, U64, ) |
| 327 | OPCODE(ConvertF32U8, F32, U32, ) | ||
| 328 | OPCODE(ConvertF32U16, F32, U32, ) | ||
| 320 | OPCODE(ConvertF32U32, F32, U32, ) | 329 | OPCODE(ConvertF32U32, F32, U32, ) |
| 321 | OPCODE(ConvertF32U64, F32, U64, ) | 330 | OPCODE(ConvertF32U64, F32, U64, ) |
| 331 | OPCODE(ConvertF64S8, F64, U32, ) | ||
| 332 | OPCODE(ConvertF64S16, F64, U32, ) | ||
| 322 | OPCODE(ConvertF64S32, F64, U32, ) | 333 | OPCODE(ConvertF64S32, F64, U32, ) |
| 323 | OPCODE(ConvertF64S64, F64, U64, ) | 334 | OPCODE(ConvertF64S64, F64, U64, ) |
| 335 | OPCODE(ConvertF64U8, F64, U32, ) | ||
| 336 | OPCODE(ConvertF64U16, F64, U32, ) | ||
| 324 | OPCODE(ConvertF64U32, F64, U32, ) | 337 | OPCODE(ConvertF64U32, F64, U32, ) |
| 325 | OPCODE(ConvertF64U64, F64, U64, ) | 338 | OPCODE(ConvertF64U64, F64, U64, ) |
| 326 | 339 | ||
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp index e444dcd4f..c9af83010 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp | |||
| @@ -121,6 +121,22 @@ IR::F64 TranslatorVisitor::GetDoubleCbuf(u64 insn) { | |||
| 121 | return ir.PackDouble2x32(ir.CompositeConstruct(lower_bits, value)); | 121 | return ir.PackDouble2x32(ir.CompositeConstruct(lower_bits, value)); |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | IR::U64 TranslatorVisitor::GetPackedCbuf(u64 insn) { | ||
| 125 | union { | ||
| 126 | u64 raw; | ||
| 127 | BitField<20, 1, u64> unaligned; | ||
| 128 | } const cbuf{insn}; | ||
| 129 | |||
| 130 | if (cbuf.unaligned != 0) { | ||
| 131 | throw NotImplementedException("Unaligned packed constant buffer read"); | ||
| 132 | } | ||
| 133 | const auto [binding, lower_offset]{CbufAddr(insn)}; | ||
| 134 | const IR::U32 upper_offset{ir.Imm32(lower_offset.U32() + 4)}; | ||
| 135 | const IR::U32 lower_value{ir.GetCbuf(binding, lower_offset)}; | ||
| 136 | const IR::U32 upper_value{ir.GetCbuf(binding, upper_offset)}; | ||
| 137 | return ir.PackUint2x32(ir.CompositeConstruct(lower_value, upper_value)); | ||
| 138 | } | ||
| 139 | |||
| 124 | IR::U32 TranslatorVisitor::GetImm20(u64 insn) { | 140 | IR::U32 TranslatorVisitor::GetImm20(u64 insn) { |
| 125 | union { | 141 | union { |
| 126 | u64 raw; | 142 | u64 raw; |
| @@ -158,6 +174,11 @@ IR::F64 TranslatorVisitor::GetDoubleImm20(u64 insn) { | |||
| 158 | return ir.Imm64(Common::BitCast<f64>(value | sign_bit)); | 174 | return ir.Imm64(Common::BitCast<f64>(value | sign_bit)); |
| 159 | } | 175 | } |
| 160 | 176 | ||
| 177 | IR::U64 TranslatorVisitor::GetPackedImm20(u64 insn) { | ||
| 178 | const s64 value{GetImm20(insn).U32()}; | ||
| 179 | return ir.Imm64(static_cast<u64>(static_cast<s64>(value) << 32)); | ||
| 180 | } | ||
| 181 | |||
| 161 | IR::U32 TranslatorVisitor::GetImm32(u64 insn) { | 182 | IR::U32 TranslatorVisitor::GetImm32(u64 insn) { |
| 162 | union { | 183 | union { |
| 163 | u64 raw; | 184 | u64 raw; |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h index ed81d9c36..cb66cca25 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h | |||
| @@ -356,10 +356,12 @@ public: | |||
| 356 | [[nodiscard]] IR::U32 GetCbuf(u64 insn); | 356 | [[nodiscard]] IR::U32 GetCbuf(u64 insn); |
| 357 | [[nodiscard]] IR::F32 GetFloatCbuf(u64 insn); | 357 | [[nodiscard]] IR::F32 GetFloatCbuf(u64 insn); |
| 358 | [[nodiscard]] IR::F64 GetDoubleCbuf(u64 insn); | 358 | [[nodiscard]] IR::F64 GetDoubleCbuf(u64 insn); |
| 359 | [[nodiscard]] IR::U64 GetPackedCbuf(u64 insn); | ||
| 359 | 360 | ||
| 360 | [[nodiscard]] IR::U32 GetImm20(u64 insn); | 361 | [[nodiscard]] IR::U32 GetImm20(u64 insn); |
| 361 | [[nodiscard]] IR::F32 GetFloatImm20(u64 insn); | 362 | [[nodiscard]] IR::F32 GetFloatImm20(u64 insn); |
| 362 | [[nodiscard]] IR::F64 GetDoubleImm20(u64 insn); | 363 | [[nodiscard]] IR::F64 GetDoubleImm20(u64 insn); |
| 364 | [[nodiscard]] IR::U64 GetPackedImm20(u64 insn); | ||
| 363 | 365 | ||
| 364 | [[nodiscard]] IR::U32 GetImm32(u64 insn); | 366 | [[nodiscard]] IR::U32 GetImm32(u64 insn); |
| 365 | [[nodiscard]] IR::F32 GetFloatImm32(u64 insn); | 367 | [[nodiscard]] IR::F32 GetFloatImm32(u64 insn); |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/integer_floating_point_conversion.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/integer_floating_point_conversion.cpp new file mode 100644 index 000000000..e8b5ae1d2 --- /dev/null +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/integer_floating_point_conversion.cpp | |||
| @@ -0,0 +1,173 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/bit_field.h" | ||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "shader_recompiler/frontend/maxwell/translate/impl/common_encoding.h" | ||
| 8 | #include "shader_recompiler/frontend/maxwell/translate/impl/impl.h" | ||
| 9 | |||
| 10 | namespace Shader::Maxwell { | ||
| 11 | namespace { | ||
| 12 | enum class FloatFormat : u64 { | ||
| 13 | F16 = 1, | ||
| 14 | F32 = 2, | ||
| 15 | F64 = 3, | ||
| 16 | }; | ||
| 17 | |||
| 18 | enum class IntFormat : u64 { | ||
| 19 | U8 = 0, | ||
| 20 | U16 = 1, | ||
| 21 | U32 = 2, | ||
| 22 | U64 = 3, | ||
| 23 | }; | ||
| 24 | |||
| 25 | union Encoding { | ||
| 26 | u64 raw; | ||
| 27 | BitField<0, 8, IR::Reg> dest_reg; | ||
| 28 | BitField<8, 2, FloatFormat> float_format; | ||
| 29 | BitField<10, 2, IntFormat> int_format; | ||
| 30 | BitField<13, 1, u64> is_signed; | ||
| 31 | BitField<39, 2, FpRounding> fp_rounding; | ||
| 32 | BitField<41, 2, u64> selector; | ||
| 33 | BitField<47, 1, u64> cc; | ||
| 34 | BitField<45, 1, u64> neg; | ||
| 35 | BitField<49, 1, u64> abs; | ||
| 36 | }; | ||
| 37 | |||
| 38 | bool Is64(u64 insn) { | ||
| 39 | return Encoding{insn}.int_format == IntFormat::U64; | ||
| 40 | } | ||
| 41 | |||
| 42 | int BitSize(FloatFormat format) { | ||
| 43 | switch (format) { | ||
| 44 | case FloatFormat::F16: | ||
| 45 | return 16; | ||
| 46 | case FloatFormat::F32: | ||
| 47 | return 32; | ||
| 48 | case FloatFormat::F64: | ||
| 49 | return 64; | ||
| 50 | } | ||
| 51 | throw NotImplementedException("Invalid float format {}", format); | ||
| 52 | } | ||
| 53 | |||
| 54 | IR::U32 SmallAbs(TranslatorVisitor& v, const IR::U32& value, int bitsize) { | ||
| 55 | const IR::U32 least_value{v.ir.Imm32(-(1 << (bitsize - 1)))}; | ||
| 56 | const IR::U32 mask{v.ir.ShiftRightArithmetic(value, v.ir.Imm32(bitsize - 1))}; | ||
| 57 | const IR::U32 absolute{v.ir.BitwiseXor(v.ir.IAdd(value, mask), mask)}; | ||
| 58 | const IR::U1 is_least{v.ir.IEqual(value, least_value)}; | ||
| 59 | return IR::U32{v.ir.Select(is_least, value, absolute)}; | ||
| 60 | } | ||
| 61 | |||
| 62 | void I2F(TranslatorVisitor& v, u64 insn, IR::U32U64 src) { | ||
| 63 | const Encoding i2f{insn}; | ||
| 64 | if (i2f.cc != 0) { | ||
| 65 | throw NotImplementedException("CC"); | ||
| 66 | } | ||
| 67 | const bool is_signed{i2f.is_signed != 0}; | ||
| 68 | int src_bitsize{}; | ||
| 69 | switch (i2f.int_format) { | ||
| 70 | case IntFormat::U8: | ||
| 71 | src = v.ir.BitFieldExtract(src, v.ir.Imm32(static_cast<u32>(i2f.selector) * 8), | ||
| 72 | v.ir.Imm32(8), is_signed); | ||
| 73 | if (i2f.abs != 0) { | ||
| 74 | src = SmallAbs(v, src, 8); | ||
| 75 | } | ||
| 76 | src_bitsize = 8; | ||
| 77 | break; | ||
| 78 | case IntFormat::U16: | ||
| 79 | if (i2f.selector == 1 || i2f.selector == 3) { | ||
| 80 | throw NotImplementedException("Invalid U16 selector {}", i2f.selector.Value()); | ||
| 81 | } | ||
| 82 | src = v.ir.BitFieldExtract(src, v.ir.Imm32(static_cast<u32>(i2f.selector) * 8), | ||
| 83 | v.ir.Imm32(16), is_signed); | ||
| 84 | if (i2f.abs != 0) { | ||
| 85 | src = SmallAbs(v, src, 16); | ||
| 86 | } | ||
| 87 | src_bitsize = 16; | ||
| 88 | break; | ||
| 89 | case IntFormat::U32: | ||
| 90 | case IntFormat::U64: | ||
| 91 | if (i2f.selector != 0) { | ||
| 92 | throw NotImplementedException("Unexpected selector {}", i2f.selector.Value()); | ||
| 93 | } | ||
| 94 | if (i2f.abs != 0 && is_signed) { | ||
| 95 | src = v.ir.IAbs(src); | ||
| 96 | } | ||
| 97 | src_bitsize = i2f.int_format == IntFormat::U64 ? 64 : 32; | ||
| 98 | break; | ||
| 99 | } | ||
| 100 | const int conversion_src_bitsize{i2f.int_format == IntFormat::U64 ? 64 : 32}; | ||
| 101 | const int dst_bitsize{BitSize(i2f.float_format)}; | ||
| 102 | IR::F16F32F64 value{v.ir.ConvertIToF(dst_bitsize, conversion_src_bitsize, is_signed, src)}; | ||
| 103 | if (i2f.neg != 0) { | ||
| 104 | if (i2f.abs != 0 || !is_signed) { | ||
| 105 | // We know the value is positive | ||
| 106 | value = v.ir.FPNeg(value); | ||
| 107 | } else { | ||
| 108 | // Only negate if the input isn't the lowest value | ||
| 109 | IR::U1 is_least; | ||
| 110 | if (src_bitsize == 64) { | ||
| 111 | is_least = v.ir.IEqual(src, v.ir.Imm64(std::numeric_limits<s64>::min())); | ||
| 112 | } else { | ||
| 113 | const IR::U32 least_value{v.ir.Imm32(-(1 << (src_bitsize - 1)))}; | ||
| 114 | is_least = v.ir.IEqual(src, least_value); | ||
| 115 | } | ||
| 116 | value = IR::F16F32F64{v.ir.Select(is_least, value, v.ir.FPNeg(value))}; | ||
| 117 | } | ||
| 118 | } | ||
| 119 | switch (i2f.float_format) { | ||
| 120 | case FloatFormat::F16: { | ||
| 121 | const IR::F16 zero{v.ir.FPConvert(16, v.ir.Imm32(0.0f))}; | ||
| 122 | v.X(i2f.dest_reg, v.ir.PackFloat2x16(v.ir.CompositeConstruct(value, zero))); | ||
| 123 | break; | ||
| 124 | } | ||
| 125 | case FloatFormat::F32: | ||
| 126 | v.F(i2f.dest_reg, value); | ||
| 127 | break; | ||
| 128 | case FloatFormat::F64: { | ||
| 129 | if (!IR::IsAligned(i2f.dest_reg, 2)) { | ||
| 130 | throw NotImplementedException("Unaligned destination {}", i2f.dest_reg.Value()); | ||
| 131 | } | ||
| 132 | const IR::Value vector{v.ir.UnpackDouble2x32(value)}; | ||
| 133 | for (int i = 0; i < 2; ++i) { | ||
| 134 | v.X(i2f.dest_reg + i, IR::U32{v.ir.CompositeExtract(vector, i)}); | ||
| 135 | } | ||
| 136 | break; | ||
| 137 | } | ||
| 138 | default: | ||
| 139 | throw NotImplementedException("Invalid float format {}", i2f.float_format.Value()); | ||
| 140 | } | ||
| 141 | } | ||
| 142 | } // Anonymous namespace | ||
| 143 | |||
| 144 | void TranslatorVisitor::I2F_reg(u64 insn) { | ||
| 145 | if (Is64(insn)) { | ||
| 146 | union { | ||
| 147 | u64 raw; | ||
| 148 | BitField<20, 8, IR::Reg> reg; | ||
| 149 | } const value{insn}; | ||
| 150 | const IR::Value regs{ir.CompositeConstruct(ir.GetReg(value.reg), ir.GetReg(value.reg + 1))}; | ||
| 151 | I2F(*this, insn, ir.PackUint2x32(regs)); | ||
| 152 | } else { | ||
| 153 | I2F(*this, insn, GetReg20(insn)); | ||
| 154 | } | ||
| 155 | } | ||
| 156 | |||
| 157 | void TranslatorVisitor::I2F_cbuf(u64 insn) { | ||
| 158 | if (Is64(insn)) { | ||
| 159 | I2F(*this, insn, GetPackedCbuf(insn)); | ||
| 160 | } else { | ||
| 161 | I2F(*this, insn, GetCbuf(insn)); | ||
| 162 | } | ||
| 163 | } | ||
| 164 | |||
| 165 | void TranslatorVisitor::I2F_imm(u64 insn) { | ||
| 166 | if (Is64(insn)) { | ||
| 167 | I2F(*this, insn, GetPackedImm20(insn)); | ||
| 168 | } else { | ||
| 169 | I2F(*this, insn, GetImm20(insn)); | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | } // namespace Shader::Maxwell \ No newline at end of file | ||
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp index a4367fc5a..4078feafa 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp | |||
| @@ -241,18 +241,6 @@ void TranslatorVisitor::HSETP2_imm(u64) { | |||
| 241 | ThrowNotImplemented(Opcode::HSETP2_imm); | 241 | ThrowNotImplemented(Opcode::HSETP2_imm); |
| 242 | } | 242 | } |
| 243 | 243 | ||
| 244 | void TranslatorVisitor::I2F_reg(u64) { | ||
| 245 | ThrowNotImplemented(Opcode::I2F_reg); | ||
| 246 | } | ||
| 247 | |||
| 248 | void TranslatorVisitor::I2F_cbuf(u64) { | ||
| 249 | ThrowNotImplemented(Opcode::I2F_cbuf); | ||
| 250 | } | ||
| 251 | |||
| 252 | void TranslatorVisitor::I2F_imm(u64) { | ||
| 253 | ThrowNotImplemented(Opcode::I2F_imm); | ||
| 254 | } | ||
| 255 | |||
| 256 | void TranslatorVisitor::IDE(u64) { | 244 | void TranslatorVisitor::IDE(u64) { |
| 257 | ThrowNotImplemented(Opcode::IDE); | 245 | ThrowNotImplemented(Opcode::IDE); |
| 258 | } | 246 | } |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch.cpp index 0fbb87ec4..b691b4d1f 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch.cpp | |||
| @@ -56,7 +56,7 @@ Shader::TextureType GetType(TextureType type, bool dc) { | |||
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, TextureType type) { | 58 | IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, TextureType type) { |
| 59 | const auto read_array{[&]() -> IR::F32 { return v.ir.ConvertUToF(32, v.X(reg)); }}; | 59 | const auto read_array{[&]() -> IR::F32 { return v.ir.ConvertUToF(32, 16, v.X(reg)); }}; |
| 60 | switch (type) { | 60 | switch (type) { |
| 61 | case TextureType::_1D: | 61 | case TextureType::_1D: |
| 62 | return v.F(reg); | 62 | return v.F(reg); |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch_swizzled.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch_swizzled.cpp index 54f0df754..d5fda20f4 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch_swizzled.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch_swizzled.cpp | |||
| @@ -65,7 +65,7 @@ IR::Value Composite(TranslatorVisitor& v, Args... regs) { | |||
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | IR::F32 ReadArray(TranslatorVisitor& v, const IR::U32& value) { | 67 | IR::F32 ReadArray(TranslatorVisitor& v, const IR::U32& value) { |
| 68 | return v.ir.ConvertUToF(32, v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(16))); | 68 | return v.ir.ConvertUToF(32, 16, v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(16))); |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | IR::Value Sample(TranslatorVisitor& v, u64 insn) { | 71 | IR::Value Sample(TranslatorVisitor& v, u64 insn) { |
diff --git a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp index fbbe28632..e72505d61 100644 --- a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp +++ b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp | |||
| @@ -79,6 +79,14 @@ void VisitUsages(Info& info, IR::Inst& inst) { | |||
| 79 | case IR::Opcode::ConvertU16F16: | 79 | case IR::Opcode::ConvertU16F16: |
| 80 | case IR::Opcode::ConvertU32F16: | 80 | case IR::Opcode::ConvertU32F16: |
| 81 | case IR::Opcode::ConvertU64F16: | 81 | case IR::Opcode::ConvertU64F16: |
| 82 | case IR::Opcode::ConvertF16S8: | ||
| 83 | case IR::Opcode::ConvertF16S16: | ||
| 84 | case IR::Opcode::ConvertF16S32: | ||
| 85 | case IR::Opcode::ConvertF16S64: | ||
| 86 | case IR::Opcode::ConvertF16U8: | ||
| 87 | case IR::Opcode::ConvertF16U16: | ||
| 88 | case IR::Opcode::ConvertF16U32: | ||
| 89 | case IR::Opcode::ConvertF16U64: | ||
| 82 | case IR::Opcode::FPAbs16: | 90 | case IR::Opcode::FPAbs16: |
| 83 | case IR::Opcode::FPAdd16: | 91 | case IR::Opcode::FPAdd16: |
| 84 | case IR::Opcode::FPCeil16: | 92 | case IR::Opcode::FPCeil16: |
| @@ -105,6 +113,14 @@ void VisitUsages(Info& info, IR::Inst& inst) { | |||
| 105 | case IR::Opcode::FPRoundEven64: | 113 | case IR::Opcode::FPRoundEven64: |
| 106 | case IR::Opcode::FPSaturate64: | 114 | case IR::Opcode::FPSaturate64: |
| 107 | case IR::Opcode::FPTrunc64: | 115 | case IR::Opcode::FPTrunc64: |
| 116 | case IR::Opcode::ConvertF64S8: | ||
| 117 | case IR::Opcode::ConvertF64S16: | ||
| 118 | case IR::Opcode::ConvertF64S32: | ||
| 119 | case IR::Opcode::ConvertF64S64: | ||
| 120 | case IR::Opcode::ConvertF64U8: | ||
| 121 | case IR::Opcode::ConvertF64U16: | ||
| 122 | case IR::Opcode::ConvertF64U32: | ||
| 123 | case IR::Opcode::ConvertF64U64: | ||
| 108 | info.uses_fp64 = true; | 124 | info.uses_fp64 = true; |
| 109 | break; | 125 | break; |
| 110 | default: | 126 | default: |
| @@ -123,6 +139,12 @@ void VisitUsages(Info& info, IR::Inst& inst) { | |||
| 123 | case IR::Opcode::WriteStorageU8: | 139 | case IR::Opcode::WriteStorageU8: |
| 124 | case IR::Opcode::WriteStorageS8: | 140 | case IR::Opcode::WriteStorageS8: |
| 125 | case IR::Opcode::SelectU8: | 141 | case IR::Opcode::SelectU8: |
| 142 | case IR::Opcode::ConvertF16S8: | ||
| 143 | case IR::Opcode::ConvertF16U8: | ||
| 144 | case IR::Opcode::ConvertF32S8: | ||
| 145 | case IR::Opcode::ConvertF32U8: | ||
| 146 | case IR::Opcode::ConvertF64S8: | ||
| 147 | case IR::Opcode::ConvertF64U8: | ||
| 126 | info.uses_int8 = true; | 148 | info.uses_int8 = true; |
| 127 | break; | 149 | break; |
| 128 | default: | 150 | default: |
| @@ -149,6 +171,12 @@ void VisitUsages(Info& info, IR::Inst& inst) { | |||
| 149 | case IR::Opcode::ConvertU16F16: | 171 | case IR::Opcode::ConvertU16F16: |
| 150 | case IR::Opcode::ConvertU16F32: | 172 | case IR::Opcode::ConvertU16F32: |
| 151 | case IR::Opcode::ConvertU16F64: | 173 | case IR::Opcode::ConvertU16F64: |
| 174 | case IR::Opcode::ConvertF16S16: | ||
| 175 | case IR::Opcode::ConvertF16U16: | ||
| 176 | case IR::Opcode::ConvertF32S16: | ||
| 177 | case IR::Opcode::ConvertF32U16: | ||
| 178 | case IR::Opcode::ConvertF64S16: | ||
| 179 | case IR::Opcode::ConvertF64U16: | ||
| 152 | info.uses_int16 = true; | 180 | info.uses_int16 = true; |
| 153 | break; | 181 | break; |
| 154 | default: | 182 | default: |
diff --git a/src/shader_recompiler/ir_opt/lower_fp16_to_fp32.cpp b/src/shader_recompiler/ir_opt/lower_fp16_to_fp32.cpp index 74acb8bb6..baa3d22df 100644 --- a/src/shader_recompiler/ir_opt/lower_fp16_to_fp32.cpp +++ b/src/shader_recompiler/ir_opt/lower_fp16_to_fp32.cpp | |||
| @@ -70,6 +70,22 @@ IR::Opcode Replace(IR::Opcode op) { | |||
| 70 | return IR::Opcode::Identity; | 70 | return IR::Opcode::Identity; |
| 71 | case IR::Opcode::ConvertF16F32: | 71 | case IR::Opcode::ConvertF16F32: |
| 72 | return IR::Opcode::Identity; | 72 | return IR::Opcode::Identity; |
| 73 | case IR::Opcode::ConvertF16S8: | ||
| 74 | return IR::Opcode::ConvertF32S8; | ||
| 75 | case IR::Opcode::ConvertF16S16: | ||
| 76 | return IR::Opcode::ConvertF32S16; | ||
| 77 | case IR::Opcode::ConvertF16S32: | ||
| 78 | return IR::Opcode::ConvertF32S32; | ||
| 79 | case IR::Opcode::ConvertF16S64: | ||
| 80 | return IR::Opcode::ConvertF32S64; | ||
| 81 | case IR::Opcode::ConvertF16U8: | ||
| 82 | return IR::Opcode::ConvertF32U8; | ||
| 83 | case IR::Opcode::ConvertF16U16: | ||
| 84 | return IR::Opcode::ConvertF32U16; | ||
| 85 | case IR::Opcode::ConvertF16U32: | ||
| 86 | return IR::Opcode::ConvertF32U32; | ||
| 87 | case IR::Opcode::ConvertF16U64: | ||
| 88 | return IR::Opcode::ConvertF32U64; | ||
| 73 | default: | 89 | default: |
| 74 | return op; | 90 | return op; |
| 75 | } | 91 | } |