summaryrefslogtreecommitdiff
path: root/src/shader_recompiler
diff options
context:
space:
mode:
Diffstat (limited to 'src/shader_recompiler')
-rw-r--r--src/shader_recompiler/CMakeLists.txt1
-rw-r--r--src/shader_recompiler/backend/spirv/emit_context.cpp2
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv.h13
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp48
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp4
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.cpp145
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.h14
-rw-r--r--src/shader_recompiler/frontend/ir/opcodes.inc13
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp21
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/impl.h2
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/integer_floating_point_conversion.cpp173
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp12
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch.cpp2
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch_swizzled.cpp2
-rw-r--r--src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp28
-rw-r--r--src/shader_recompiler/ir_opt/lower_fp16_to_fp32.cpp16
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);
243Id EmitINeg32(EmitContext& ctx, Id value); 243Id EmitINeg32(EmitContext& ctx, Id value);
244Id EmitINeg64(EmitContext& ctx, Id value); 244Id EmitINeg64(EmitContext& ctx, Id value);
245Id EmitIAbs32(EmitContext& ctx, Id value); 245Id EmitIAbs32(EmitContext& ctx, Id value);
246Id EmitIAbs64(EmitContext& ctx, Id value);
246Id EmitShiftLeftLogical32(EmitContext& ctx, Id base, Id shift); 247Id EmitShiftLeftLogical32(EmitContext& ctx, Id base, Id shift);
247Id EmitShiftLeftLogical64(EmitContext& ctx, Id base, Id shift); 248Id EmitShiftLeftLogical64(EmitContext& ctx, Id base, Id shift);
248Id EmitShiftRightLogical32(EmitContext& ctx, Id base, Id shift); 249Id EmitShiftRightLogical32(EmitContext& ctx, Id base, Id shift);
@@ -302,16 +303,28 @@ Id EmitConvertF16F32(EmitContext& ctx, Id value);
302Id EmitConvertF32F16(EmitContext& ctx, Id value); 303Id EmitConvertF32F16(EmitContext& ctx, Id value);
303Id EmitConvertF32F64(EmitContext& ctx, Id value); 304Id EmitConvertF32F64(EmitContext& ctx, Id value);
304Id EmitConvertF64F32(EmitContext& ctx, Id value); 305Id EmitConvertF64F32(EmitContext& ctx, Id value);
306Id EmitConvertF16S8(EmitContext& ctx, Id value);
307Id EmitConvertF16S16(EmitContext& ctx, Id value);
305Id EmitConvertF16S32(EmitContext& ctx, Id value); 308Id EmitConvertF16S32(EmitContext& ctx, Id value);
306Id EmitConvertF16S64(EmitContext& ctx, Id value); 309Id EmitConvertF16S64(EmitContext& ctx, Id value);
310Id EmitConvertF16U8(EmitContext& ctx, Id value);
311Id EmitConvertF16U16(EmitContext& ctx, Id value);
307Id EmitConvertF16U32(EmitContext& ctx, Id value); 312Id EmitConvertF16U32(EmitContext& ctx, Id value);
308Id EmitConvertF16U64(EmitContext& ctx, Id value); 313Id EmitConvertF16U64(EmitContext& ctx, Id value);
314Id EmitConvertF32S8(EmitContext& ctx, Id value);
315Id EmitConvertF32S16(EmitContext& ctx, Id value);
309Id EmitConvertF32S32(EmitContext& ctx, Id value); 316Id EmitConvertF32S32(EmitContext& ctx, Id value);
310Id EmitConvertF32S64(EmitContext& ctx, Id value); 317Id EmitConvertF32S64(EmitContext& ctx, Id value);
318Id EmitConvertF32U8(EmitContext& ctx, Id value);
319Id EmitConvertF32U16(EmitContext& ctx, Id value);
311Id EmitConvertF32U32(EmitContext& ctx, Id value); 320Id EmitConvertF32U32(EmitContext& ctx, Id value);
312Id EmitConvertF32U64(EmitContext& ctx, Id value); 321Id EmitConvertF32U64(EmitContext& ctx, Id value);
322Id EmitConvertF64S8(EmitContext& ctx, Id value);
323Id EmitConvertF64S16(EmitContext& ctx, Id value);
313Id EmitConvertF64S32(EmitContext& ctx, Id value); 324Id EmitConvertF64S32(EmitContext& ctx, Id value);
314Id EmitConvertF64S64(EmitContext& ctx, Id value); 325Id EmitConvertF64S64(EmitContext& ctx, Id value);
326Id EmitConvertF64U8(EmitContext& ctx, Id value);
327Id EmitConvertF64U16(EmitContext& ctx, Id value);
315Id EmitConvertF64U32(EmitContext& ctx, Id value); 328Id EmitConvertF64U32(EmitContext& ctx, Id value);
316Id EmitConvertF64U64(EmitContext& ctx, Id value); 329Id EmitConvertF64U64(EmitContext& ctx, Id value);
317Id EmitBindlessImageSampleImplicitLod(EmitContext&); 330Id 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
105Id EmitConvertF16S8(EmitContext& ctx, Id value) {
106 return ctx.OpConvertSToF(ctx.F16[1], value);
107}
108
109Id EmitConvertF16S16(EmitContext& ctx, Id value) {
110 return ctx.OpConvertSToF(ctx.F16[1], value);
111}
112
105Id EmitConvertF16S32(EmitContext& ctx, Id value) { 113Id 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
121Id EmitConvertF16U8(EmitContext& ctx, Id value) {
122 return ctx.OpConvertUToF(ctx.F16[1], value);
123}
124
125Id EmitConvertF16U16(EmitContext& ctx, Id value) {
126 return ctx.OpConvertUToF(ctx.F16[1], value);
127}
128
113Id EmitConvertF16U32(EmitContext& ctx, Id value) { 129Id 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
137Id EmitConvertF32S8(EmitContext& ctx, Id value) {
138 return ctx.OpConvertSToF(ctx.F32[1], ctx.OpUConvert(ctx.U8, value));
139}
140
141Id EmitConvertF32S16(EmitContext& ctx, Id value) {
142 return ctx.OpConvertSToF(ctx.F32[1], ctx.OpUConvert(ctx.U16, value));
143}
144
121Id EmitConvertF32S32(EmitContext& ctx, Id value) { 145Id 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
153Id EmitConvertF32U8(EmitContext& ctx, Id value) {
154 return ctx.OpConvertUToF(ctx.F32[1], ctx.OpUConvert(ctx.U8, value));
155}
156
157Id EmitConvertF32U16(EmitContext& ctx, Id value) {
158 return ctx.OpConvertUToF(ctx.F32[1], ctx.OpUConvert(ctx.U16, value));
159}
160
129Id EmitConvertF32U32(EmitContext& ctx, Id value) { 161Id 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
169Id EmitConvertF64S8(EmitContext& ctx, Id value) {
170 return ctx.OpConvertSToF(ctx.F64[1], ctx.OpUConvert(ctx.U8, value));
171}
172
173Id EmitConvertF64S16(EmitContext& ctx, Id value) {
174 return ctx.OpConvertSToF(ctx.F64[1], ctx.OpUConvert(ctx.U16, value));
175}
176
137Id EmitConvertF64S32(EmitContext& ctx, Id value) { 177Id 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
185Id EmitConvertF64U8(EmitContext& ctx, Id value) {
186 return ctx.OpConvertUToF(ctx.F64[1], ctx.OpUConvert(ctx.U8, value));
187}
188
189Id EmitConvertF64U16(EmitContext& ctx, Id value) {
190 return ctx.OpConvertUToF(ctx.F64[1], ctx.OpUConvert(ctx.U16, value));
191}
192
145Id EmitConvertF64U32(EmitContext& ctx, Id value) { 193Id 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
73Id EmitIAbs64(EmitContext& ctx, Id value) {
74 return ctx.OpSAbs(ctx.U64, value);
75}
76
73Id EmitShiftLeftLogical32(EmitContext& ctx, Id base, Id shift) { 77Id 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
56U64 IREmitter::Imm64(s64 value) const {
57 return U64{Value{static_cast<u64>(value)}};
58}
59
56F64 IREmitter::Imm64(f64 value) const { 60F64 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
365F16F32F64 IREmitter::FPAdd(const F16F32F64& a, const F16F32F64& b, FpControl control) { 369F16F32F64 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
977U32 IREmitter::IAbs(const U32& value) { 981U32U64 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
981U32U64 IREmitter::ShiftLeftLogical(const U32U64& base, const U32& shift) { 992U32U64 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
1077U1 IREmitter::IEqual(const U32& lhs, const U32& rhs) { 1088U1 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
1081U1 IREmitter::ILessThanEqual(const U32& lhs, const U32& rhs, bool is_signed) { 1109U1 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
1201F16F32F64 IREmitter::ConvertSToF(size_t bitsize, const U32U64& value) { 1229F16F32F64 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
1235F16F32F64 IREmitter::ConvertUToF(size_t bitsize, const U32U64& value) { 1271F16F32F64 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
1269F16F32F64 IREmitter::ConvertIToF(size_t bitsize, bool is_signed, const U32U64& value) { 1313F16F32F64 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,
247OPCODE(INeg32, U32, U32, ) 247OPCODE(INeg32, U32, U32, )
248OPCODE(INeg64, U64, U64, ) 248OPCODE(INeg64, U64, U64, )
249OPCODE(IAbs32, U32, U32, ) 249OPCODE(IAbs32, U32, U32, )
250OPCODE(IAbs64, U64, U64, )
250OPCODE(ShiftLeftLogical32, U32, U32, U32, ) 251OPCODE(ShiftLeftLogical32, U32, U32, U32, )
251OPCODE(ShiftLeftLogical64, U64, U64, U32, ) 252OPCODE(ShiftLeftLogical64, U64, U64, U32, )
252OPCODE(ShiftRightLogical32, U32, U32, U32, ) 253OPCODE(ShiftRightLogical32, U32, U32, U32, )
@@ -311,16 +312,28 @@ OPCODE(ConvertF16F32, F16, F32,
311OPCODE(ConvertF32F16, F32, F16, ) 312OPCODE(ConvertF32F16, F32, F16, )
312OPCODE(ConvertF32F64, F32, F64, ) 313OPCODE(ConvertF32F64, F32, F64, )
313OPCODE(ConvertF64F32, F64, F32, ) 314OPCODE(ConvertF64F32, F64, F32, )
315OPCODE(ConvertF16S8, F16, U32, )
316OPCODE(ConvertF16S16, F16, U32, )
314OPCODE(ConvertF16S32, F16, U32, ) 317OPCODE(ConvertF16S32, F16, U32, )
315OPCODE(ConvertF16S64, F16, U64, ) 318OPCODE(ConvertF16S64, F16, U64, )
319OPCODE(ConvertF16U8, F16, U32, )
320OPCODE(ConvertF16U16, F16, U32, )
316OPCODE(ConvertF16U32, F16, U32, ) 321OPCODE(ConvertF16U32, F16, U32, )
317OPCODE(ConvertF16U64, F16, U64, ) 322OPCODE(ConvertF16U64, F16, U64, )
323OPCODE(ConvertF32S8, F32, U32, )
324OPCODE(ConvertF32S16, F32, U32, )
318OPCODE(ConvertF32S32, F32, U32, ) 325OPCODE(ConvertF32S32, F32, U32, )
319OPCODE(ConvertF32S64, F32, U64, ) 326OPCODE(ConvertF32S64, F32, U64, )
327OPCODE(ConvertF32U8, F32, U32, )
328OPCODE(ConvertF32U16, F32, U32, )
320OPCODE(ConvertF32U32, F32, U32, ) 329OPCODE(ConvertF32U32, F32, U32, )
321OPCODE(ConvertF32U64, F32, U64, ) 330OPCODE(ConvertF32U64, F32, U64, )
331OPCODE(ConvertF64S8, F64, U32, )
332OPCODE(ConvertF64S16, F64, U32, )
322OPCODE(ConvertF64S32, F64, U32, ) 333OPCODE(ConvertF64S32, F64, U32, )
323OPCODE(ConvertF64S64, F64, U64, ) 334OPCODE(ConvertF64S64, F64, U64, )
335OPCODE(ConvertF64U8, F64, U32, )
336OPCODE(ConvertF64U16, F64, U32, )
324OPCODE(ConvertF64U32, F64, U32, ) 337OPCODE(ConvertF64U32, F64, U32, )
325OPCODE(ConvertF64U64, F64, U64, ) 338OPCODE(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
124IR::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
124IR::U32 TranslatorVisitor::GetImm20(u64 insn) { 140IR::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
177IR::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
161IR::U32 TranslatorVisitor::GetImm32(u64 insn) { 182IR::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
10namespace Shader::Maxwell {
11namespace {
12enum class FloatFormat : u64 {
13 F16 = 1,
14 F32 = 2,
15 F64 = 3,
16};
17
18enum class IntFormat : u64 {
19 U8 = 0,
20 U16 = 1,
21 U32 = 2,
22 U64 = 3,
23};
24
25union 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
38bool Is64(u64 insn) {
39 return Encoding{insn}.int_format == IntFormat::U64;
40}
41
42int 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
54IR::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
62void 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
144void 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
157void 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
165void 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
244void TranslatorVisitor::I2F_reg(u64) {
245 ThrowNotImplemented(Opcode::I2F_reg);
246}
247
248void TranslatorVisitor::I2F_cbuf(u64) {
249 ThrowNotImplemented(Opcode::I2F_cbuf);
250}
251
252void TranslatorVisitor::I2F_imm(u64) {
253 ThrowNotImplemented(Opcode::I2F_imm);
254}
255
256void TranslatorVisitor::IDE(u64) { 244void 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
58IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, TextureType type) { 58IR::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
67IR::F32 ReadArray(TranslatorVisitor& v, const IR::U32& value) { 67IR::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
71IR::Value Sample(TranslatorVisitor& v, u64 insn) { 71IR::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 }