summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/frontend
diff options
context:
space:
mode:
Diffstat (limited to 'src/shader_recompiler/frontend')
-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
9 files changed, 315 insertions, 69 deletions
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) {