summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.cpp275
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.h69
-rw-r--r--src/shader_recompiler/frontend/ir/opcode.inc200
-rw-r--r--src/shader_recompiler/frontend/ir/type.cpp4
-rw-r--r--src/shader_recompiler/frontend/ir/type.h15
-rw-r--r--src/shader_recompiler/frontend/ir/value.cpp28
-rw-r--r--src/shader_recompiler/frontend/ir/value.h10
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_add.cpp12
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp20
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_fused_multiply_add.cpp16
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_multi_function.cpp6
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_multiply.cpp13
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp20
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/impl.h6
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp23
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/load_store_memory.cpp4
-rw-r--r--src/shader_recompiler/ir_opt/constant_propagation_pass.cpp20
-rw-r--r--src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp21
-rw-r--r--src/shader_recompiler/main.cpp2
19 files changed, 495 insertions, 269 deletions
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
index 1c5ae0109..9d7dc034c 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
@@ -32,16 +32,16 @@ U32 IREmitter::Imm32(s32 value) const {
32 return U32{Value{static_cast<u32>(value)}}; 32 return U32{Value{static_cast<u32>(value)}};
33} 33}
34 34
35U32 IREmitter::Imm32(f32 value) const { 35F32 IREmitter::Imm32(f32 value) const {
36 return U32{Value{Common::BitCast<u32>(value)}}; 36 return F32{Value{value}};
37} 37}
38 38
39U64 IREmitter::Imm64(u64 value) const { 39U64 IREmitter::Imm64(u64 value) const {
40 return U64{Value{value}}; 40 return U64{Value{value}};
41} 41}
42 42
43U64 IREmitter::Imm64(f64 value) const { 43F64 IREmitter::Imm64(f64 value) const {
44 return U64{Value{Common::BitCast<u64>(value)}}; 44 return F64{Value{value}};
45} 45}
46 46
47void IREmitter::Branch(IR::Block* label) { 47void IREmitter::Branch(IR::Block* label) {
@@ -121,11 +121,11 @@ void IREmitter::SetOFlag(const U1& value) {
121 Inst(Opcode::SetOFlag, value); 121 Inst(Opcode::SetOFlag, value);
122} 122}
123 123
124U32 IREmitter::GetAttribute(IR::Attribute attribute) { 124F32 IREmitter::GetAttribute(IR::Attribute attribute) {
125 return Inst<U32>(Opcode::GetAttribute, attribute); 125 return Inst<F32>(Opcode::GetAttribute, attribute);
126} 126}
127 127
128void IREmitter::SetAttribute(IR::Attribute attribute, const U32& value) { 128void IREmitter::SetAttribute(IR::Attribute attribute, const F32& value) {
129 Inst(Opcode::SetAttribute, attribute, value); 129 Inst(Opcode::SetAttribute, attribute, value);
130} 130}
131 131
@@ -225,50 +225,113 @@ U1 IREmitter::GetOverflowFromOp(const Value& op) {
225 return Inst<U1>(Opcode::GetOverflowFromOp, op); 225 return Inst<U1>(Opcode::GetOverflowFromOp, op);
226} 226}
227 227
228U16U32U64 IREmitter::FPAdd(const U16U32U64& a, const U16U32U64& b, FpControl control) { 228F16F32F64 IREmitter::FPAdd(const F16F32F64& a, const F16F32F64& b, FpControl control) {
229 if (a.Type() != a.Type()) { 229 if (a.Type() != a.Type()) {
230 throw InvalidArgument("Mismatching types {} and {}", a.Type(), b.Type()); 230 throw InvalidArgument("Mismatching types {} and {}", a.Type(), b.Type());
231 } 231 }
232 switch (a.Type()) { 232 switch (a.Type()) {
233 case Type::U16: 233 case Type::F16:
234 return Inst<U16>(Opcode::FPAdd16, Flags{control}, a, b); 234 return Inst<F16>(Opcode::FPAdd16, Flags{control}, a, b);
235 case Type::U32: 235 case Type::F32:
236 return Inst<U32>(Opcode::FPAdd32, Flags{control}, a, b); 236 return Inst<F32>(Opcode::FPAdd32, Flags{control}, a, b);
237 case Type::U64: 237 case Type::F64:
238 return Inst<U64>(Opcode::FPAdd64, Flags{control}, a, b); 238 return Inst<F64>(Opcode::FPAdd64, Flags{control}, a, b);
239 default: 239 default:
240 ThrowInvalidType(a.Type()); 240 ThrowInvalidType(a.Type());
241 } 241 }
242} 242}
243 243
244Value IREmitter::CompositeConstruct(const UAny& e1, const UAny& e2) { 244Value IREmitter::CompositeConstruct(const Value& e1, const Value& e2) {
245 if (e1.Type() != e2.Type()) { 245 if (e1.Type() != e2.Type()) {
246 throw InvalidArgument("Mismatching types {} and {}", e1.Type(), e2.Type()); 246 throw InvalidArgument("Mismatching types {} and {}", e1.Type(), e2.Type());
247 } 247 }
248 return Inst(Opcode::CompositeConstruct2, e1, e2); 248 switch (e1.Type()) {
249 case Type::U32:
250 return Inst(Opcode::CompositeConstructU32x2, e1, e2);
251 case Type::F16:
252 return Inst(Opcode::CompositeConstructF16x2, e1, e2);
253 case Type::F32:
254 return Inst(Opcode::CompositeConstructF32x2, e1, e2);
255 case Type::F64:
256 return Inst(Opcode::CompositeConstructF64x2, e1, e2);
257 default:
258 ThrowInvalidType(e1.Type());
259 }
249} 260}
250 261
251Value IREmitter::CompositeConstruct(const UAny& e1, const UAny& e2, const UAny& e3) { 262Value IREmitter::CompositeConstruct(const Value& e1, const Value& e2, const Value& e3) {
252 if (e1.Type() != e2.Type() || e1.Type() != e3.Type()) { 263 if (e1.Type() != e2.Type() || e1.Type() != e3.Type()) {
253 throw InvalidArgument("Mismatching types {}, {}, and {}", e1.Type(), e2.Type(), e3.Type()); 264 throw InvalidArgument("Mismatching types {}, {}, and {}", e1.Type(), e2.Type(), e3.Type());
254 } 265 }
255 return Inst(Opcode::CompositeConstruct3, e1, e2, e3); 266 switch (e1.Type()) {
267 case Type::U32:
268 return Inst(Opcode::CompositeConstructU32x3, e1, e2, e3);
269 case Type::F16:
270 return Inst(Opcode::CompositeConstructF16x3, e1, e2, e3);
271 case Type::F32:
272 return Inst(Opcode::CompositeConstructF32x3, e1, e2, e3);
273 case Type::F64:
274 return Inst(Opcode::CompositeConstructF64x3, e1, e2, e3);
275 default:
276 ThrowInvalidType(e1.Type());
277 }
256} 278}
257 279
258Value IREmitter::CompositeConstruct(const UAny& e1, const UAny& e2, const UAny& e3, 280Value IREmitter::CompositeConstruct(const Value& e1, const Value& e2, const Value& e3,
259 const UAny& e4) { 281 const Value& e4) {
260 if (e1.Type() != e2.Type() || e1.Type() != e3.Type() || e1.Type() != e4.Type()) { 282 if (e1.Type() != e2.Type() || e1.Type() != e3.Type() || e1.Type() != e4.Type()) {
261 throw InvalidArgument("Mismatching types {}, {}, {}, and {}", e1.Type(), e2.Type(), 283 throw InvalidArgument("Mismatching types {}, {}, {}, and {}", e1.Type(), e2.Type(),
262 e3.Type(), e4.Type()); 284 e3.Type(), e4.Type());
263 } 285 }
264 return Inst(Opcode::CompositeConstruct4, e1, e2, e3, e4); 286 switch (e1.Type()) {
287 case Type::U32:
288 return Inst(Opcode::CompositeConstructU32x4, e1, e2, e3, e4);
289 case Type::F16:
290 return Inst(Opcode::CompositeConstructF16x4, e1, e2, e3, e4);
291 case Type::F32:
292 return Inst(Opcode::CompositeConstructF32x4, e1, e2, e3, e4);
293 case Type::F64:
294 return Inst(Opcode::CompositeConstructF64x4, e1, e2, e3, e4);
295 default:
296 ThrowInvalidType(e1.Type());
297 }
265} 298}
266 299
267UAny IREmitter::CompositeExtract(const Value& vector, size_t element) { 300Value IREmitter::CompositeExtract(const Value& vector, size_t element) {
268 if (element >= 4) { 301 const auto read = [&](Opcode opcode, size_t limit) -> Value {
269 throw InvalidArgument("Out of bounds element {}", element); 302 if (element >= limit) {
303 throw InvalidArgument("Out of bounds element {}", element);
304 }
305 return Inst(opcode, vector, Value{static_cast<u32>(element)});
306 };
307 switch (vector.Type()) {
308 case Type::U32x2:
309 return read(Opcode::CompositeExtractU32x2, 2);
310 case Type::U32x3:
311 return read(Opcode::CompositeExtractU32x3, 3);
312 case Type::U32x4:
313 return read(Opcode::CompositeExtractU32x4, 4);
314 case Type::F16x2:
315 return read(Opcode::CompositeExtractF16x2, 2);
316 case Type::F16x3:
317 return read(Opcode::CompositeExtractF16x3, 3);
318 case Type::F16x4:
319 return read(Opcode::CompositeExtractF16x4, 4);
320 case Type::F32x2:
321 return read(Opcode::CompositeExtractF32x2, 2);
322 case Type::F32x3:
323 return read(Opcode::CompositeExtractF32x3, 3);
324 case Type::F32x4:
325 return read(Opcode::CompositeExtractF32x4, 4);
326 case Type::F64x2:
327 return read(Opcode::CompositeExtractF64x2, 2);
328 case Type::F64x3:
329 return read(Opcode::CompositeExtractF64x3, 3);
330 case Type::F64x4:
331 return read(Opcode::CompositeExtractF64x4, 4);
332 default:
333 ThrowInvalidType(vector.Type());
270 } 334 }
271 return Inst<UAny>(Opcode::CompositeExtract, vector, Imm32(static_cast<u32>(element)));
272} 335}
273 336
274UAny IREmitter::Select(const U1& condition, const UAny& true_value, const UAny& false_value) { 337UAny IREmitter::Select(const U1& condition, const UAny& true_value, const UAny& false_value) {
@@ -289,6 +352,36 @@ UAny IREmitter::Select(const U1& condition, const UAny& true_value, const UAny&
289 } 352 }
290} 353}
291 354
355template <>
356IR::U32 IREmitter::BitCast<IR::U32, IR::F32>(const IR::F32& value) {
357 return Inst<IR::U32>(Opcode::BitCastU32F32, value);
358}
359
360template <>
361IR::F32 IREmitter::BitCast<IR::F32, IR::U32>(const IR::U32& value) {
362 return Inst<IR::F32>(Opcode::BitCastF32U32, value);
363}
364
365template <>
366IR::U16 IREmitter::BitCast<IR::U16, IR::F16>(const IR::F16& value) {
367 return Inst<IR::U16>(Opcode::BitCastU16F16, value);
368}
369
370template <>
371IR::F16 IREmitter::BitCast<IR::F16, IR::U16>(const IR::U16& value) {
372 return Inst<IR::F16>(Opcode::BitCastF16U16, value);
373}
374
375template <>
376IR::U64 IREmitter::BitCast<IR::U64, IR::F64>(const IR::F64& value) {
377 return Inst<IR::U64>(Opcode::BitCastU64F64, value);
378}
379
380template <>
381IR::F64 IREmitter::BitCast<IR::F64, IR::U64>(const IR::U64& value) {
382 return Inst<IR::F64>(Opcode::BitCastF64U64, value);
383}
384
292U64 IREmitter::PackUint2x32(const Value& vector) { 385U64 IREmitter::PackUint2x32(const Value& vector) {
293 return Inst<U64>(Opcode::PackUint2x32, vector); 386 return Inst<U64>(Opcode::PackUint2x32, vector);
294} 387}
@@ -305,75 +398,75 @@ Value IREmitter::UnpackFloat2x16(const U32& value) {
305 return Inst<Value>(Opcode::UnpackFloat2x16, value); 398 return Inst<Value>(Opcode::UnpackFloat2x16, value);
306} 399}
307 400
308U64 IREmitter::PackDouble2x32(const Value& vector) { 401F64 IREmitter::PackDouble2x32(const Value& vector) {
309 return Inst<U64>(Opcode::PackDouble2x32, vector); 402 return Inst<F64>(Opcode::PackDouble2x32, vector);
310} 403}
311 404
312Value IREmitter::UnpackDouble2x32(const U64& value) { 405Value IREmitter::UnpackDouble2x32(const F64& value) {
313 return Inst<Value>(Opcode::UnpackDouble2x32, value); 406 return Inst<Value>(Opcode::UnpackDouble2x32, value);
314} 407}
315 408
316U16U32U64 IREmitter::FPMul(const U16U32U64& a, const U16U32U64& b, FpControl control) { 409F16F32F64 IREmitter::FPMul(const F16F32F64& a, const F16F32F64& b, FpControl control) {
317 if (a.Type() != b.Type()) { 410 if (a.Type() != b.Type()) {
318 throw InvalidArgument("Mismatching types {} and {}", a.Type(), b.Type()); 411 throw InvalidArgument("Mismatching types {} and {}", a.Type(), b.Type());
319 } 412 }
320 switch (a.Type()) { 413 switch (a.Type()) {
321 case Type::U16: 414 case Type::F16:
322 return Inst<U16>(Opcode::FPMul16, Flags{control}, a, b); 415 return Inst<F16>(Opcode::FPMul16, Flags{control}, a, b);
323 case Type::U32: 416 case Type::F32:
324 return Inst<U32>(Opcode::FPMul32, Flags{control}, a, b); 417 return Inst<F32>(Opcode::FPMul32, Flags{control}, a, b);
325 case Type::U64: 418 case Type::F64:
326 return Inst<U64>(Opcode::FPMul64, Flags{control}, a, b); 419 return Inst<F64>(Opcode::FPMul64, Flags{control}, a, b);
327 default: 420 default:
328 ThrowInvalidType(a.Type()); 421 ThrowInvalidType(a.Type());
329 } 422 }
330} 423}
331 424
332U16U32U64 IREmitter::FPFma(const U16U32U64& a, const U16U32U64& b, const U16U32U64& c, 425F16F32F64 IREmitter::FPFma(const F16F32F64& a, const F16F32F64& b, const F16F32F64& c,
333 FpControl control) { 426 FpControl control) {
334 if (a.Type() != b.Type() || a.Type() != c.Type()) { 427 if (a.Type() != b.Type() || a.Type() != c.Type()) {
335 throw InvalidArgument("Mismatching types {}, {}, and {}", a.Type(), b.Type(), c.Type()); 428 throw InvalidArgument("Mismatching types {}, {}, and {}", a.Type(), b.Type(), c.Type());
336 } 429 }
337 switch (a.Type()) { 430 switch (a.Type()) {
338 case Type::U16: 431 case Type::F16:
339 return Inst<U16>(Opcode::FPFma16, Flags{control}, a, b, c); 432 return Inst<F16>(Opcode::FPFma16, Flags{control}, a, b, c);
340 case Type::U32: 433 case Type::F32:
341 return Inst<U32>(Opcode::FPFma32, Flags{control}, a, b, c); 434 return Inst<F32>(Opcode::FPFma32, Flags{control}, a, b, c);
342 case Type::U64: 435 case Type::F64:
343 return Inst<U64>(Opcode::FPFma64, Flags{control}, a, b, c); 436 return Inst<F64>(Opcode::FPFma64, Flags{control}, a, b, c);
344 default: 437 default:
345 ThrowInvalidType(a.Type()); 438 ThrowInvalidType(a.Type());
346 } 439 }
347} 440}
348 441
349U16U32U64 IREmitter::FPAbs(const U16U32U64& value) { 442F16F32F64 IREmitter::FPAbs(const F16F32F64& value) {
350 switch (value.Type()) { 443 switch (value.Type()) {
351 case Type::U16: 444 case Type::U16:
352 return Inst<U16>(Opcode::FPAbs16, value); 445 return Inst<F16>(Opcode::FPAbs16, value);
353 case Type::U32: 446 case Type::U32:
354 return Inst<U32>(Opcode::FPAbs32, value); 447 return Inst<F32>(Opcode::FPAbs32, value);
355 case Type::U64: 448 case Type::U64:
356 return Inst<U64>(Opcode::FPAbs64, value); 449 return Inst<F64>(Opcode::FPAbs64, value);
357 default: 450 default:
358 ThrowInvalidType(value.Type()); 451 ThrowInvalidType(value.Type());
359 } 452 }
360} 453}
361 454
362U16U32U64 IREmitter::FPNeg(const U16U32U64& value) { 455F16F32F64 IREmitter::FPNeg(const F16F32F64& value) {
363 switch (value.Type()) { 456 switch (value.Type()) {
364 case Type::U16: 457 case Type::U16:
365 return Inst<U16>(Opcode::FPNeg16, value); 458 return Inst<F16>(Opcode::FPNeg16, value);
366 case Type::U32: 459 case Type::U32:
367 return Inst<U32>(Opcode::FPNeg32, value); 460 return Inst<F32>(Opcode::FPNeg32, value);
368 case Type::U64: 461 case Type::U64:
369 return Inst<U64>(Opcode::FPNeg64, value); 462 return Inst<F64>(Opcode::FPNeg64, value);
370 default: 463 default:
371 ThrowInvalidType(value.Type()); 464 ThrowInvalidType(value.Type());
372 } 465 }
373} 466}
374 467
375U16U32U64 IREmitter::FPAbsNeg(const U16U32U64& value, bool abs, bool neg) { 468F16F32F64 IREmitter::FPAbsNeg(const F16F32F64& value, bool abs, bool neg) {
376 U16U32U64 result{value}; 469 F16F32F64 result{value};
377 if (abs) { 470 if (abs) {
378 result = FPAbs(value); 471 result = FPAbs(value);
379 } 472 }
@@ -383,108 +476,108 @@ U16U32U64 IREmitter::FPAbsNeg(const U16U32U64& value, bool abs, bool neg) {
383 return result; 476 return result;
384} 477}
385 478
386U32 IREmitter::FPCosNotReduced(const U32& value) { 479F32 IREmitter::FPCosNotReduced(const F32& value) {
387 return Inst<U32>(Opcode::FPCosNotReduced, value); 480 return Inst<F32>(Opcode::FPCosNotReduced, value);
388} 481}
389 482
390U32 IREmitter::FPExp2NotReduced(const U32& value) { 483F32 IREmitter::FPExp2NotReduced(const F32& value) {
391 return Inst<U32>(Opcode::FPExp2NotReduced, value); 484 return Inst<F32>(Opcode::FPExp2NotReduced, value);
392} 485}
393 486
394U32 IREmitter::FPLog2(const U32& value) { 487F32 IREmitter::FPLog2(const F32& value) {
395 return Inst<U32>(Opcode::FPLog2, value); 488 return Inst<F32>(Opcode::FPLog2, value);
396} 489}
397 490
398U32U64 IREmitter::FPRecip(const U32U64& value) { 491F32F64 IREmitter::FPRecip(const F32F64& value) {
399 switch (value.Type()) { 492 switch (value.Type()) {
400 case Type::U32: 493 case Type::U32:
401 return Inst<U32>(Opcode::FPRecip32, value); 494 return Inst<F32>(Opcode::FPRecip32, value);
402 case Type::U64: 495 case Type::U64:
403 return Inst<U64>(Opcode::FPRecip64, value); 496 return Inst<F64>(Opcode::FPRecip64, value);
404 default: 497 default:
405 ThrowInvalidType(value.Type()); 498 ThrowInvalidType(value.Type());
406 } 499 }
407} 500}
408 501
409U32U64 IREmitter::FPRecipSqrt(const U32U64& value) { 502F32F64 IREmitter::FPRecipSqrt(const F32F64& value) {
410 switch (value.Type()) { 503 switch (value.Type()) {
411 case Type::U32: 504 case Type::U32:
412 return Inst<U32>(Opcode::FPRecipSqrt32, value); 505 return Inst<F32>(Opcode::FPRecipSqrt32, value);
413 case Type::U64: 506 case Type::U64:
414 return Inst<U64>(Opcode::FPRecipSqrt64, value); 507 return Inst<F64>(Opcode::FPRecipSqrt64, value);
415 default: 508 default:
416 ThrowInvalidType(value.Type()); 509 ThrowInvalidType(value.Type());
417 } 510 }
418} 511}
419 512
420U32 IREmitter::FPSinNotReduced(const U32& value) { 513F32 IREmitter::FPSinNotReduced(const F32& value) {
421 return Inst<U32>(Opcode::FPSinNotReduced, value); 514 return Inst<F32>(Opcode::FPSinNotReduced, value);
422} 515}
423 516
424U32 IREmitter::FPSqrt(const U32& value) { 517F32 IREmitter::FPSqrt(const F32& value) {
425 return Inst<U32>(Opcode::FPSqrt, value); 518 return Inst<F32>(Opcode::FPSqrt, value);
426} 519}
427 520
428U16U32U64 IREmitter::FPSaturate(const U16U32U64& value) { 521F16F32F64 IREmitter::FPSaturate(const F16F32F64& value) {
429 switch (value.Type()) { 522 switch (value.Type()) {
430 case Type::U16: 523 case Type::U16:
431 return Inst<U16>(Opcode::FPSaturate16, value); 524 return Inst<F16>(Opcode::FPSaturate16, value);
432 case Type::U32: 525 case Type::U32:
433 return Inst<U32>(Opcode::FPSaturate32, value); 526 return Inst<F32>(Opcode::FPSaturate32, value);
434 case Type::U64: 527 case Type::U64:
435 return Inst<U64>(Opcode::FPSaturate64, value); 528 return Inst<F64>(Opcode::FPSaturate64, value);
436 default: 529 default:
437 ThrowInvalidType(value.Type()); 530 ThrowInvalidType(value.Type());
438 } 531 }
439} 532}
440 533
441U16U32U64 IREmitter::FPRoundEven(const U16U32U64& value) { 534F16F32F64 IREmitter::FPRoundEven(const F16F32F64& value) {
442 switch (value.Type()) { 535 switch (value.Type()) {
443 case Type::U16: 536 case Type::U16:
444 return Inst<U16>(Opcode::FPRoundEven16, value); 537 return Inst<F16>(Opcode::FPRoundEven16, value);
445 case Type::U32: 538 case Type::U32:
446 return Inst<U32>(Opcode::FPRoundEven32, value); 539 return Inst<F32>(Opcode::FPRoundEven32, value);
447 case Type::U64: 540 case Type::U64:
448 return Inst<U64>(Opcode::FPRoundEven64, value); 541 return Inst<F64>(Opcode::FPRoundEven64, value);
449 default: 542 default:
450 ThrowInvalidType(value.Type()); 543 ThrowInvalidType(value.Type());
451 } 544 }
452} 545}
453 546
454U16U32U64 IREmitter::FPFloor(const U16U32U64& value) { 547F16F32F64 IREmitter::FPFloor(const F16F32F64& value) {
455 switch (value.Type()) { 548 switch (value.Type()) {
456 case Type::U16: 549 case Type::U16:
457 return Inst<U16>(Opcode::FPFloor16, value); 550 return Inst<F16>(Opcode::FPFloor16, value);
458 case Type::U32: 551 case Type::U32:
459 return Inst<U32>(Opcode::FPFloor32, value); 552 return Inst<F32>(Opcode::FPFloor32, value);
460 case Type::U64: 553 case Type::U64:
461 return Inst<U64>(Opcode::FPFloor64, value); 554 return Inst<F64>(Opcode::FPFloor64, value);
462 default: 555 default:
463 ThrowInvalidType(value.Type()); 556 ThrowInvalidType(value.Type());
464 } 557 }
465} 558}
466 559
467U16U32U64 IREmitter::FPCeil(const U16U32U64& value) { 560F16F32F64 IREmitter::FPCeil(const F16F32F64& value) {
468 switch (value.Type()) { 561 switch (value.Type()) {
469 case Type::U16: 562 case Type::U16:
470 return Inst<U16>(Opcode::FPCeil16, value); 563 return Inst<F16>(Opcode::FPCeil16, value);
471 case Type::U32: 564 case Type::U32:
472 return Inst<U32>(Opcode::FPCeil32, value); 565 return Inst<F32>(Opcode::FPCeil32, value);
473 case Type::U64: 566 case Type::U64:
474 return Inst<U64>(Opcode::FPCeil64, value); 567 return Inst<F64>(Opcode::FPCeil64, value);
475 default: 568 default:
476 ThrowInvalidType(value.Type()); 569 ThrowInvalidType(value.Type());
477 } 570 }
478} 571}
479 572
480U16U32U64 IREmitter::FPTrunc(const U16U32U64& value) { 573F16F32F64 IREmitter::FPTrunc(const F16F32F64& value) {
481 switch (value.Type()) { 574 switch (value.Type()) {
482 case Type::U16: 575 case Type::U16:
483 return Inst<U16>(Opcode::FPTrunc16, value); 576 return Inst<F16>(Opcode::FPTrunc16, value);
484 case Type::U32: 577 case Type::U32:
485 return Inst<U32>(Opcode::FPTrunc32, value); 578 return Inst<F32>(Opcode::FPTrunc32, value);
486 case Type::U64: 579 case Type::U64:
487 return Inst<U64>(Opcode::FPTrunc64, value); 580 return Inst<F64>(Opcode::FPTrunc64, value);
488 default: 581 default:
489 ThrowInvalidType(value.Type()); 582 ThrowInvalidType(value.Type());
490 } 583 }
@@ -605,7 +698,7 @@ U1 IREmitter::LogicalNot(const U1& value) {
605 return Inst<U1>(Opcode::LogicalNot, value); 698 return Inst<U1>(Opcode::LogicalNot, value);
606} 699}
607 700
608U32U64 IREmitter::ConvertFToS(size_t bitsize, const U16U32U64& value) { 701U32U64 IREmitter::ConvertFToS(size_t bitsize, const F16F32F64& value) {
609 switch (bitsize) { 702 switch (bitsize) {
610 case 16: 703 case 16:
611 switch (value.Type()) { 704 switch (value.Type()) {
@@ -645,7 +738,7 @@ U32U64 IREmitter::ConvertFToS(size_t bitsize, const U16U32U64& value) {
645 } 738 }
646} 739}
647 740
648U32U64 IREmitter::ConvertFToU(size_t bitsize, const U16U32U64& value) { 741U32U64 IREmitter::ConvertFToU(size_t bitsize, const F16F32F64& value) {
649 switch (bitsize) { 742 switch (bitsize) {
650 case 16: 743 case 16:
651 switch (value.Type()) { 744 switch (value.Type()) {
@@ -685,7 +778,7 @@ U32U64 IREmitter::ConvertFToU(size_t bitsize, const U16U32U64& value) {
685 } 778 }
686} 779}
687 780
688U32U64 IREmitter::ConvertFToI(size_t bitsize, bool is_signed, const U16U32U64& value) { 781U32U64 IREmitter::ConvertFToI(size_t bitsize, bool is_signed, const F16F32F64& value) {
689 if (is_signed) { 782 if (is_signed) {
690 return ConvertFToS(bitsize, value); 783 return ConvertFToS(bitsize, value);
691 } else { 784 } else {
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h
index 84b844898..bfd9916cc 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.h
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.h
@@ -27,9 +27,9 @@ public:
27 [[nodiscard]] U16 Imm16(u16 value) const; 27 [[nodiscard]] U16 Imm16(u16 value) const;
28 [[nodiscard]] U32 Imm32(u32 value) const; 28 [[nodiscard]] U32 Imm32(u32 value) const;
29 [[nodiscard]] U32 Imm32(s32 value) const; 29 [[nodiscard]] U32 Imm32(s32 value) const;
30 [[nodiscard]] U32 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(f64 value) const; 32 [[nodiscard]] F64 Imm64(f64 value) const;
33 33
34 void Branch(IR::Block* label); 34 void Branch(IR::Block* label);
35 void BranchConditional(const U1& cond, IR::Block* true_label, IR::Block* false_label); 35 void BranchConditional(const U1& cond, IR::Block* true_label, IR::Block* false_label);
@@ -55,8 +55,8 @@ public:
55 void SetCFlag(const U1& value); 55 void SetCFlag(const U1& value);
56 void SetOFlag(const U1& value); 56 void SetOFlag(const U1& value);
57 57
58 [[nodiscard]] U32 GetAttribute(IR::Attribute attribute); 58 [[nodiscard]] F32 GetAttribute(IR::Attribute attribute);
59 void SetAttribute(IR::Attribute attribute, const U32& value); 59 void SetAttribute(IR::Attribute attribute, const F32& value);
60 60
61 [[nodiscard]] U32 WorkgroupIdX(); 61 [[nodiscard]] U32 WorkgroupIdX();
62 [[nodiscard]] U32 WorkgroupIdY(); 62 [[nodiscard]] U32 WorkgroupIdY();
@@ -87,44 +87,47 @@ public:
87 [[nodiscard]] U1 GetCarryFromOp(const Value& op); 87 [[nodiscard]] U1 GetCarryFromOp(const Value& op);
88 [[nodiscard]] U1 GetOverflowFromOp(const Value& op); 88 [[nodiscard]] U1 GetOverflowFromOp(const Value& op);
89 89
90 [[nodiscard]] Value CompositeConstruct(const UAny& e1, const UAny& e2); 90 [[nodiscard]] Value CompositeConstruct(const Value& e1, const Value& e2);
91 [[nodiscard]] Value CompositeConstruct(const UAny& e1, const UAny& e2, const UAny& e3); 91 [[nodiscard]] Value CompositeConstruct(const Value& e1, const Value& e2, const Value& e3);
92 [[nodiscard]] Value CompositeConstruct(const UAny& e1, const UAny& e2, const UAny& e3, 92 [[nodiscard]] Value CompositeConstruct(const Value& e1, const Value& e2, const Value& e3,
93 const UAny& e4); 93 const Value& e4);
94 [[nodiscard]] UAny CompositeExtract(const Value& vector, size_t element); 94 [[nodiscard]] Value CompositeExtract(const Value& vector, size_t element);
95 95
96 [[nodiscard]] UAny Select(const U1& condition, const UAny& true_value, const UAny& false_value); 96 [[nodiscard]] UAny Select(const U1& condition, const UAny& true_value, const UAny& false_value);
97 97
98 template <typename Dest, typename Source>
99 [[nodiscard]] Dest BitCast(const Source& value);
100
98 [[nodiscard]] U64 PackUint2x32(const Value& vector); 101 [[nodiscard]] U64 PackUint2x32(const Value& vector);
99 [[nodiscard]] Value UnpackUint2x32(const U64& value); 102 [[nodiscard]] Value UnpackUint2x32(const U64& value);
100 103
101 [[nodiscard]] U32 PackFloat2x16(const Value& vector); 104 [[nodiscard]] U32 PackFloat2x16(const Value& vector);
102 [[nodiscard]] Value UnpackFloat2x16(const U32& value); 105 [[nodiscard]] Value UnpackFloat2x16(const U32& value);
103 106
104 [[nodiscard]] U64 PackDouble2x32(const Value& vector); 107 [[nodiscard]] F64 PackDouble2x32(const Value& vector);
105 [[nodiscard]] Value UnpackDouble2x32(const U64& value); 108 [[nodiscard]] Value UnpackDouble2x32(const F64& value);
106 109
107 [[nodiscard]] U16U32U64 FPAdd(const U16U32U64& a, const U16U32U64& b, FpControl control = {}); 110 [[nodiscard]] F16F32F64 FPAdd(const F16F32F64& a, const F16F32F64& b, FpControl control = {});
108 [[nodiscard]] U16U32U64 FPMul(const U16U32U64& a, const U16U32U64& b, FpControl control = {}); 111 [[nodiscard]] F16F32F64 FPMul(const F16F32F64& a, const F16F32F64& b, FpControl control = {});
109 [[nodiscard]] U16U32U64 FPFma(const U16U32U64& a, const U16U32U64& b, const U16U32U64& c, 112 [[nodiscard]] F16F32F64 FPFma(const F16F32F64& a, const F16F32F64& b, const F16F32F64& c,
110 FpControl control = {}); 113 FpControl control = {});
111 114
112 [[nodiscard]] U16U32U64 FPAbs(const U16U32U64& value); 115 [[nodiscard]] F16F32F64 FPAbs(const F16F32F64& value);
113 [[nodiscard]] U16U32U64 FPNeg(const U16U32U64& value); 116 [[nodiscard]] F16F32F64 FPNeg(const F16F32F64& value);
114 [[nodiscard]] U16U32U64 FPAbsNeg(const U16U32U64& value, bool abs, bool neg); 117 [[nodiscard]] F16F32F64 FPAbsNeg(const F16F32F64& value, bool abs, bool neg);
115 118
116 [[nodiscard]] U32 FPCosNotReduced(const U32& value); 119 [[nodiscard]] F32 FPCosNotReduced(const F32& value);
117 [[nodiscard]] U32 FPExp2NotReduced(const U32& value); 120 [[nodiscard]] F32 FPExp2NotReduced(const F32& value);
118 [[nodiscard]] U32 FPLog2(const U32& value); 121 [[nodiscard]] F32 FPLog2(const F32& value);
119 [[nodiscard]] U32U64 FPRecip(const U32U64& value); 122 [[nodiscard]] F32F64 FPRecip(const F32F64& value);
120 [[nodiscard]] U32U64 FPRecipSqrt(const U32U64& value); 123 [[nodiscard]] F32F64 FPRecipSqrt(const F32F64& value);
121 [[nodiscard]] U32 FPSinNotReduced(const U32& value); 124 [[nodiscard]] F32 FPSinNotReduced(const F32& value);
122 [[nodiscard]] U32 FPSqrt(const U32& value); 125 [[nodiscard]] F32 FPSqrt(const F32& value);
123 [[nodiscard]] U16U32U64 FPSaturate(const U16U32U64& value); 126 [[nodiscard]] F16F32F64 FPSaturate(const F16F32F64& value);
124 [[nodiscard]] U16U32U64 FPRoundEven(const U16U32U64& value); 127 [[nodiscard]] F16F32F64 FPRoundEven(const F16F32F64& value);
125 [[nodiscard]] U16U32U64 FPFloor(const U16U32U64& value); 128 [[nodiscard]] F16F32F64 FPFloor(const F16F32F64& value);
126 [[nodiscard]] U16U32U64 FPCeil(const U16U32U64& value); 129 [[nodiscard]] F16F32F64 FPCeil(const F16F32F64& value);
127 [[nodiscard]] U16U32U64 FPTrunc(const U16U32U64& value); 130 [[nodiscard]] F16F32F64 FPTrunc(const F16F32F64& value);
128 131
129 [[nodiscard]] U32U64 IAdd(const U32U64& a, const U32U64& b); 132 [[nodiscard]] U32U64 IAdd(const U32U64& a, const U32U64& b);
130 [[nodiscard]] U32U64 ISub(const U32U64& a, const U32U64& b); 133 [[nodiscard]] U32U64 ISub(const U32U64& a, const U32U64& b);
@@ -154,9 +157,9 @@ public:
154 [[nodiscard]] U1 LogicalXor(const U1& a, const U1& b); 157 [[nodiscard]] U1 LogicalXor(const U1& a, const U1& b);
155 [[nodiscard]] U1 LogicalNot(const U1& value); 158 [[nodiscard]] U1 LogicalNot(const U1& value);
156 159
157 [[nodiscard]] U32U64 ConvertFToS(size_t bitsize, const U16U32U64& value); 160 [[nodiscard]] U32U64 ConvertFToS(size_t bitsize, const F16F32F64& value);
158 [[nodiscard]] U32U64 ConvertFToU(size_t bitsize, const U16U32U64& value); 161 [[nodiscard]] U32U64 ConvertFToU(size_t bitsize, const F16F32F64& value);
159 [[nodiscard]] U32U64 ConvertFToI(size_t bitsize, bool is_signed, const U16U32U64& value); 162 [[nodiscard]] U32U64 ConvertFToI(size_t bitsize, bool is_signed, const F16F32F64& value);
160 163
161 [[nodiscard]] U32U64 ConvertU(size_t result_bitsize, const U32U64& value); 164 [[nodiscard]] U32U64 ConvertU(size_t result_bitsize, const U32U64& value);
162 165
diff --git a/src/shader_recompiler/frontend/ir/opcode.inc b/src/shader_recompiler/frontend/ir/opcode.inc
index 4596bf39f..6eb105d92 100644
--- a/src/shader_recompiler/frontend/ir/opcode.inc
+++ b/src/shader_recompiler/frontend/ir/opcode.inc
@@ -52,15 +52,15 @@ OPCODE(LoadGlobalS8, U32, U64,
52OPCODE(LoadGlobalU16, U32, U64, ) 52OPCODE(LoadGlobalU16, U32, U64, )
53OPCODE(LoadGlobalS16, U32, U64, ) 53OPCODE(LoadGlobalS16, U32, U64, )
54OPCODE(LoadGlobal32, U32, U64, ) 54OPCODE(LoadGlobal32, U32, U64, )
55OPCODE(LoadGlobal64, Opaque, U64, ) 55OPCODE(LoadGlobal64, U32x2, U64, )
56OPCODE(LoadGlobal128, Opaque, U64, ) 56OPCODE(LoadGlobal128, U32x4, U64, )
57OPCODE(WriteGlobalU8, Void, U64, U32, ) 57OPCODE(WriteGlobalU8, Void, U64, U32, )
58OPCODE(WriteGlobalS8, Void, U64, U32, ) 58OPCODE(WriteGlobalS8, Void, U64, U32, )
59OPCODE(WriteGlobalU16, Void, U64, U32, ) 59OPCODE(WriteGlobalU16, Void, U64, U32, )
60OPCODE(WriteGlobalS16, Void, U64, U32, ) 60OPCODE(WriteGlobalS16, Void, U64, U32, )
61OPCODE(WriteGlobal32, Void, U64, U32, ) 61OPCODE(WriteGlobal32, Void, U64, U32, )
62OPCODE(WriteGlobal64, Void, U64, Opaque, ) 62OPCODE(WriteGlobal64, Void, U64, U32x2, )
63OPCODE(WriteGlobal128, Void, U64, Opaque, ) 63OPCODE(WriteGlobal128, Void, U64, U32x4, )
64 64
65// Storage buffer operations 65// Storage buffer operations
66OPCODE(LoadStorageU8, U32, U32, U32, ) 66OPCODE(LoadStorageU8, U32, U32, U32, )
@@ -68,21 +68,41 @@ OPCODE(LoadStorageS8, U32, U32,
68OPCODE(LoadStorageU16, U32, U32, U32, ) 68OPCODE(LoadStorageU16, U32, U32, U32, )
69OPCODE(LoadStorageS16, U32, U32, U32, ) 69OPCODE(LoadStorageS16, U32, U32, U32, )
70OPCODE(LoadStorage32, U32, U32, U32, ) 70OPCODE(LoadStorage32, U32, U32, U32, )
71OPCODE(LoadStorage64, Opaque, U32, U32, ) 71OPCODE(LoadStorage64, U32x2, U32, U32, )
72OPCODE(LoadStorage128, Opaque, U32, U32, ) 72OPCODE(LoadStorage128, U32x4, U32, U32, )
73OPCODE(WriteStorageU8, Void, U32, U32, U32, ) 73OPCODE(WriteStorageU8, Void, U32, U32, U32, )
74OPCODE(WriteStorageS8, Void, U32, U32, U32, ) 74OPCODE(WriteStorageS8, Void, U32, U32, U32, )
75OPCODE(WriteStorageU16, Void, U32, U32, U32, ) 75OPCODE(WriteStorageU16, Void, U32, U32, U32, )
76OPCODE(WriteStorageS16, Void, U32, U32, U32, ) 76OPCODE(WriteStorageS16, Void, U32, U32, U32, )
77OPCODE(WriteStorage32, Void, U32, U32, U32, ) 77OPCODE(WriteStorage32, Void, U32, U32, U32, )
78OPCODE(WriteStorage64, Void, U32, U32, Opaque, ) 78OPCODE(WriteStorage64, Void, U32, U32, U32x2, )
79OPCODE(WriteStorage128, Void, U32, U32, Opaque, ) 79OPCODE(WriteStorage128, Void, U32, U32, U32x4, )
80 80
81// Vector utility 81// Vector utility
82OPCODE(CompositeConstruct2, Opaque, Opaque, Opaque, ) 82OPCODE(CompositeConstructU32x2, U32x2, U32, U32, )
83OPCODE(CompositeConstruct3, Opaque, Opaque, Opaque, Opaque, ) 83OPCODE(CompositeConstructU32x3, U32x3, U32, U32, U32, )
84OPCODE(CompositeConstruct4, Opaque, Opaque, Opaque, Opaque, Opaque, ) 84OPCODE(CompositeConstructU32x4, U32x4, U32, U32, U32, U32, )
85OPCODE(CompositeExtract, Opaque, Opaque, U32, ) 85OPCODE(CompositeExtractU32x2, U32, U32x2, U32, )
86OPCODE(CompositeExtractU32x3, U32, U32x3, U32, )
87OPCODE(CompositeExtractU32x4, U32, U32x4, U32, )
88OPCODE(CompositeConstructF16x2, F16x2, F16, F16, )
89OPCODE(CompositeConstructF16x3, F16x3, F16, F16, F16, )
90OPCODE(CompositeConstructF16x4, F16x4, F16, F16, F16, F16, )
91OPCODE(CompositeExtractF16x2, F16, F16x2, U32, )
92OPCODE(CompositeExtractF16x3, F16, F16x3, U32, )
93OPCODE(CompositeExtractF16x4, F16, F16x4, U32, )
94OPCODE(CompositeConstructF32x2, F32x2, F32, F32, )
95OPCODE(CompositeConstructF32x3, F32x3, F32, F32, F32, )
96OPCODE(CompositeConstructF32x4, F32x4, F32, F32, F32, F32, )
97OPCODE(CompositeExtractF32x2, F32, F32x2, U32, )
98OPCODE(CompositeExtractF32x3, F32, F32x3, U32, )
99OPCODE(CompositeExtractF32x4, F32, F32x4, U32, )
100OPCODE(CompositeConstructF64x2, F64x2, F64, F64, )
101OPCODE(CompositeConstructF64x3, F64x3, F64, F64, F64, )
102OPCODE(CompositeConstructF64x4, F64x4, F64, F64, F64, F64, )
103OPCODE(CompositeExtractF64x2, F64, F64x2, U32, )
104OPCODE(CompositeExtractF64x3, F64, F64x3, U32, )
105OPCODE(CompositeExtractF64x4, F64, F64x4, U32, )
86 106
87// Select operations 107// Select operations
88OPCODE(Select8, U8, U1, U8, U8, ) 108OPCODE(Select8, U8, U1, U8, U8, )
@@ -91,12 +111,18 @@ OPCODE(Select32, U32, U1,
91OPCODE(Select64, U64, U1, U64, U64, ) 111OPCODE(Select64, U64, U1, U64, U64, )
92 112
93// Bitwise conversions 113// Bitwise conversions
94OPCODE(PackUint2x32, U64, Opaque, ) 114OPCODE(BitCastU16F16, U16, F16, )
95OPCODE(UnpackUint2x32, Opaque, U64, ) 115OPCODE(BitCastU32F32, U32, F32, )
96OPCODE(PackFloat2x16, U32, Opaque, ) 116OPCODE(BitCastU64F64, U64, F64, )
97OPCODE(UnpackFloat2x16, Opaque, U32, ) 117OPCODE(BitCastF16U16, F16, U16, )
98OPCODE(PackDouble2x32, U64, Opaque, ) 118OPCODE(BitCastF32U32, F32, U32, )
99OPCODE(UnpackDouble2x32, Opaque, U64, ) 119OPCODE(BitCastF64U64, F64, U64, )
120OPCODE(PackUint2x32, U64, U32x2, )
121OPCODE(UnpackUint2x32, U32x2, U64, )
122OPCODE(PackFloat2x16, U32, F16x2, )
123OPCODE(UnpackFloat2x16, F16x2, U32, )
124OPCODE(PackDouble2x32, U64, U32x2, )
125OPCODE(UnpackDouble2x32, U32x2, U64, )
100 126
101// Pseudo-operation, handled specially at final emit 127// Pseudo-operation, handled specially at final emit
102OPCODE(GetZeroFromOp, U1, Opaque, ) 128OPCODE(GetZeroFromOp, U1, Opaque, )
@@ -105,52 +131,52 @@ OPCODE(GetCarryFromOp, U1, Opaq
105OPCODE(GetOverflowFromOp, U1, Opaque, ) 131OPCODE(GetOverflowFromOp, U1, Opaque, )
106 132
107// Floating-point operations 133// Floating-point operations
108OPCODE(FPAbs16, U16, U16, ) 134OPCODE(FPAbs16, F16, F16, )
109OPCODE(FPAbs32, U32, U32, ) 135OPCODE(FPAbs32, F32, F32, )
110OPCODE(FPAbs64, U64, U64, ) 136OPCODE(FPAbs64, F64, F64, )
111OPCODE(FPAdd16, U16, U16, U16, ) 137OPCODE(FPAdd16, F16, F16, F16, )
112OPCODE(FPAdd32, U32, U32, U32, ) 138OPCODE(FPAdd32, F32, F32, F32, )
113OPCODE(FPAdd64, U64, U64, U64, ) 139OPCODE(FPAdd64, F64, F64, F64, )
114OPCODE(FPFma16, U16, U16, U16, U16, ) 140OPCODE(FPFma16, F16, F16, F16, F16, )
115OPCODE(FPFma32, U32, U32, U32, U32, ) 141OPCODE(FPFma32, F32, F32, F32, F32, )
116OPCODE(FPFma64, U64, U64, U64, U64, ) 142OPCODE(FPFma64, F64, F64, F64, F64, )
117OPCODE(FPMax32, U32, U32, U32, ) 143OPCODE(FPMax32, F32, F32, F32, )
118OPCODE(FPMax64, U64, U64, U64, ) 144OPCODE(FPMax64, F64, F64, F64, )
119OPCODE(FPMin32, U32, U32, U32, ) 145OPCODE(FPMin32, F32, F32, F32, )
120OPCODE(FPMin64, U64, U64, U64, ) 146OPCODE(FPMin64, F64, F64, F64, )
121OPCODE(FPMul16, U16, U16, U16, ) 147OPCODE(FPMul16, F16, F16, F16, )
122OPCODE(FPMul32, U32, U32, U32, ) 148OPCODE(FPMul32, F32, F32, F32, )
123OPCODE(FPMul64, U64, U64, U64, ) 149OPCODE(FPMul64, F64, F64, F64, )
124OPCODE(FPNeg16, U16, U16, ) 150OPCODE(FPNeg16, F16, F16, )
125OPCODE(FPNeg32, U32, U32, ) 151OPCODE(FPNeg32, F32, F32, )
126OPCODE(FPNeg64, U64, U64, ) 152OPCODE(FPNeg64, F64, F64, )
127OPCODE(FPRecip32, U32, U32, ) 153OPCODE(FPRecip32, F32, F32, )
128OPCODE(FPRecip64, U64, U64, ) 154OPCODE(FPRecip64, F64, F64, )
129OPCODE(FPRecipSqrt32, U32, U32, ) 155OPCODE(FPRecipSqrt32, F32, F32, )
130OPCODE(FPRecipSqrt64, U64, U64, ) 156OPCODE(FPRecipSqrt64, F64, F64, )
131OPCODE(FPSqrt, U32, U32, ) 157OPCODE(FPSqrt, F32, F32, )
132OPCODE(FPSin, U32, U32, ) 158OPCODE(FPSin, F32, F32, )
133OPCODE(FPSinNotReduced, U32, U32, ) 159OPCODE(FPSinNotReduced, F32, F32, )
134OPCODE(FPExp2, U32, U32, ) 160OPCODE(FPExp2, F32, F32, )
135OPCODE(FPExp2NotReduced, U32, U32, ) 161OPCODE(FPExp2NotReduced, F32, F32, )
136OPCODE(FPCos, U32, U32, ) 162OPCODE(FPCos, F32, F32, )
137OPCODE(FPCosNotReduced, U32, U32, ) 163OPCODE(FPCosNotReduced, F32, F32, )
138OPCODE(FPLog2, U32, U32, ) 164OPCODE(FPLog2, F32, F32, )
139OPCODE(FPSaturate16, U16, U16, ) 165OPCODE(FPSaturate16, F16, F16, )
140OPCODE(FPSaturate32, U32, U32, ) 166OPCODE(FPSaturate32, F32, F32, )
141OPCODE(FPSaturate64, U64, U64, ) 167OPCODE(FPSaturate64, F64, F64, )
142OPCODE(FPRoundEven16, U16, U16, ) 168OPCODE(FPRoundEven16, F16, F16, )
143OPCODE(FPRoundEven32, U32, U32, ) 169OPCODE(FPRoundEven32, F32, F32, )
144OPCODE(FPRoundEven64, U64, U64, ) 170OPCODE(FPRoundEven64, F64, F64, )
145OPCODE(FPFloor16, U16, U16, ) 171OPCODE(FPFloor16, F16, F16, )
146OPCODE(FPFloor32, U32, U32, ) 172OPCODE(FPFloor32, F32, F32, )
147OPCODE(FPFloor64, U64, U64, ) 173OPCODE(FPFloor64, F64, F64, )
148OPCODE(FPCeil16, U16, U16, ) 174OPCODE(FPCeil16, F16, F16, )
149OPCODE(FPCeil32, U32, U32, ) 175OPCODE(FPCeil32, F32, F32, )
150OPCODE(FPCeil64, U64, U64, ) 176OPCODE(FPCeil64, F64, F64, )
151OPCODE(FPTrunc16, U16, U16, ) 177OPCODE(FPTrunc16, F16, F16, )
152OPCODE(FPTrunc32, U32, U32, ) 178OPCODE(FPTrunc32, F32, F32, )
153OPCODE(FPTrunc64, U64, U64, ) 179OPCODE(FPTrunc64, F64, F64, )
154 180
155// Integer operations 181// Integer operations
156OPCODE(IAdd32, U32, U32, U32, ) 182OPCODE(IAdd32, U32, U32, U32, )
@@ -188,24 +214,24 @@ OPCODE(LogicalXor, U1, U1,
188OPCODE(LogicalNot, U1, U1, ) 214OPCODE(LogicalNot, U1, U1, )
189 215
190// Conversion operations 216// Conversion operations
191OPCODE(ConvertS16F16, U32, U16, ) 217OPCODE(ConvertS16F16, U32, F16, )
192OPCODE(ConvertS16F32, U32, U32, ) 218OPCODE(ConvertS16F32, U32, F32, )
193OPCODE(ConvertS16F64, U32, U64, ) 219OPCODE(ConvertS16F64, U32, F64, )
194OPCODE(ConvertS32F16, U32, U16, ) 220OPCODE(ConvertS32F16, U32, F16, )
195OPCODE(ConvertS32F32, U32, U32, ) 221OPCODE(ConvertS32F32, U32, F32, )
196OPCODE(ConvertS32F64, U32, U64, ) 222OPCODE(ConvertS32F64, U32, F64, )
197OPCODE(ConvertS64F16, U64, U16, ) 223OPCODE(ConvertS64F16, U64, F16, )
198OPCODE(ConvertS64F32, U64, U32, ) 224OPCODE(ConvertS64F32, U64, F32, )
199OPCODE(ConvertS64F64, U64, U64, ) 225OPCODE(ConvertS64F64, U64, F64, )
200OPCODE(ConvertU16F16, U32, U16, ) 226OPCODE(ConvertU16F16, U32, F16, )
201OPCODE(ConvertU16F32, U32, U32, ) 227OPCODE(ConvertU16F32, U32, F32, )
202OPCODE(ConvertU16F64, U32, U64, ) 228OPCODE(ConvertU16F64, U32, F64, )
203OPCODE(ConvertU32F16, U32, U16, ) 229OPCODE(ConvertU32F16, U32, F16, )
204OPCODE(ConvertU32F32, U32, U32, ) 230OPCODE(ConvertU32F32, U32, F32, )
205OPCODE(ConvertU32F64, U32, U64, ) 231OPCODE(ConvertU32F64, U32, F64, )
206OPCODE(ConvertU64F16, U64, U16, ) 232OPCODE(ConvertU64F16, U64, F16, )
207OPCODE(ConvertU64F32, U64, U32, ) 233OPCODE(ConvertU64F32, U64, F32, )
208OPCODE(ConvertU64F64, U64, U64, ) 234OPCODE(ConvertU64F64, U64, F64, )
209 235
210OPCODE(ConvertU64U32, U64, U32, ) 236OPCODE(ConvertU64U32, U64, U32, )
211OPCODE(ConvertU32U64, U32, U64, ) 237OPCODE(ConvertU32U64, U32, U64, )
diff --git a/src/shader_recompiler/frontend/ir/type.cpp b/src/shader_recompiler/frontend/ir/type.cpp
index 13cc09195..f28341bfe 100644
--- a/src/shader_recompiler/frontend/ir/type.cpp
+++ b/src/shader_recompiler/frontend/ir/type.cpp
@@ -11,7 +11,9 @@ namespace Shader::IR {
11 11
12std::string NameOf(Type type) { 12std::string NameOf(Type type) {
13 static constexpr std::array names{ 13 static constexpr std::array names{
14 "Opaque", "Label", "Reg", "Pred", "Attribute", "U1", "U8", "U16", "U32", "U64", 14 "Opaque", "Label", "Reg", "Pred", "Attribute", "U1", "U8", "U16", "U32",
15 "U64", "F16", "F32", "F64", "U32x2", "U32x3", "U32x4", "F16x2", "F16x3",
16 "F16x4", "F32x2", "F32x3", "F32x4", "F64x2", "F64x3", "F64x4",
15 }; 17 };
16 const size_t bits{static_cast<size_t>(type)}; 18 const size_t bits{static_cast<size_t>(type)};
17 if (bits == 0) { 19 if (bits == 0) {
diff --git a/src/shader_recompiler/frontend/ir/type.h b/src/shader_recompiler/frontend/ir/type.h
index 397875018..9a32ca1e8 100644
--- a/src/shader_recompiler/frontend/ir/type.h
+++ b/src/shader_recompiler/frontend/ir/type.h
@@ -25,6 +25,21 @@ enum class Type {
25 U16 = 1 << 7, 25 U16 = 1 << 7,
26 U32 = 1 << 8, 26 U32 = 1 << 8,
27 U64 = 1 << 9, 27 U64 = 1 << 9,
28 F16 = 1 << 10,
29 F32 = 1 << 11,
30 F64 = 1 << 12,
31 U32x2 = 1 << 13,
32 U32x3 = 1 << 14,
33 U32x4 = 1 << 15,
34 F16x2 = 1 << 16,
35 F16x3 = 1 << 17,
36 F16x4 = 1 << 18,
37 F32x2 = 1 << 19,
38 F32x3 = 1 << 20,
39 F32x4 = 1 << 21,
40 F64x2 = 1 << 22,
41 F64x3 = 1 << 23,
42 F64x4 = 1 << 24,
28}; 43};
29DECLARE_ENUM_FLAG_OPERATORS(Type) 44DECLARE_ENUM_FLAG_OPERATORS(Type)
30 45
diff --git a/src/shader_recompiler/frontend/ir/value.cpp b/src/shader_recompiler/frontend/ir/value.cpp
index 59a9b10dc..93ff8ccf1 100644
--- a/src/shader_recompiler/frontend/ir/value.cpp
+++ b/src/shader_recompiler/frontend/ir/value.cpp
@@ -26,8 +26,12 @@ Value::Value(u16 value) noexcept : type{Type::U16}, imm_u16{value} {}
26 26
27Value::Value(u32 value) noexcept : type{Type::U32}, imm_u32{value} {} 27Value::Value(u32 value) noexcept : type{Type::U32}, imm_u32{value} {}
28 28
29Value::Value(f32 value) noexcept : type{Type::F32}, imm_f32{value} {}
30
29Value::Value(u64 value) noexcept : type{Type::U64}, imm_u64{value} {} 31Value::Value(u64 value) noexcept : type{Type::U64}, imm_u64{value} {}
30 32
33Value::Value(f64 value) noexcept : type{Type::F64}, imm_f64{value} {}
34
31bool Value::IsIdentity() const noexcept { 35bool Value::IsIdentity() const noexcept {
32 return type == Type::Opaque && inst->Opcode() == Opcode::Identity; 36 return type == Type::Opaque && inst->Opcode() == Opcode::Identity;
33} 37}
@@ -122,6 +126,14 @@ u32 Value::U32() const {
122 return imm_u32; 126 return imm_u32;
123} 127}
124 128
129f32 Value::F32() const {
130 if (IsIdentity()) {
131 return inst->Arg(0).F32();
132 }
133 ValidateAccess(Type::F32);
134 return imm_f32;
135}
136
125u64 Value::U64() const { 137u64 Value::U64() const {
126 if (IsIdentity()) { 138 if (IsIdentity()) {
127 return inst->Arg(0).U64(); 139 return inst->Arg(0).U64();
@@ -152,11 +164,27 @@ bool Value::operator==(const Value& other) const {
152 case Type::U8: 164 case Type::U8:
153 return imm_u8 == other.imm_u8; 165 return imm_u8 == other.imm_u8;
154 case Type::U16: 166 case Type::U16:
167 case Type::F16:
155 return imm_u16 == other.imm_u16; 168 return imm_u16 == other.imm_u16;
156 case Type::U32: 169 case Type::U32:
170 case Type::F32:
157 return imm_u32 == other.imm_u32; 171 return imm_u32 == other.imm_u32;
158 case Type::U64: 172 case Type::U64:
173 case Type::F64:
159 return imm_u64 == other.imm_u64; 174 return imm_u64 == other.imm_u64;
175 case Type::U32x2:
176 case Type::U32x3:
177 case Type::U32x4:
178 case Type::F16x2:
179 case Type::F16x3:
180 case Type::F16x4:
181 case Type::F32x2:
182 case Type::F32x3:
183 case Type::F32x4:
184 case Type::F64x2:
185 case Type::F64x3:
186 case Type::F64x4:
187 break;
160 } 188 }
161 throw LogicError("Invalid type {}", type); 189 throw LogicError("Invalid type {}", type);
162} 190}
diff --git a/src/shader_recompiler/frontend/ir/value.h b/src/shader_recompiler/frontend/ir/value.h
index 31f831794..2f3688c73 100644
--- a/src/shader_recompiler/frontend/ir/value.h
+++ b/src/shader_recompiler/frontend/ir/value.h
@@ -28,7 +28,9 @@ public:
28 explicit Value(u8 value) noexcept; 28 explicit Value(u8 value) noexcept;
29 explicit Value(u16 value) noexcept; 29 explicit Value(u16 value) noexcept;
30 explicit Value(u32 value) noexcept; 30 explicit Value(u32 value) noexcept;
31 explicit Value(f32 value) noexcept;
31 explicit Value(u64 value) noexcept; 32 explicit Value(u64 value) noexcept;
33 explicit Value(f64 value) noexcept;
32 34
33 [[nodiscard]] bool IsIdentity() const noexcept; 35 [[nodiscard]] bool IsIdentity() const noexcept;
34 [[nodiscard]] bool IsEmpty() const noexcept; 36 [[nodiscard]] bool IsEmpty() const noexcept;
@@ -46,6 +48,7 @@ public:
46 [[nodiscard]] u8 U8() const; 48 [[nodiscard]] u8 U8() const;
47 [[nodiscard]] u16 U16() const; 49 [[nodiscard]] u16 U16() const;
48 [[nodiscard]] u32 U32() const; 50 [[nodiscard]] u32 U32() const;
51 [[nodiscard]] f32 F32() const;
49 [[nodiscard]] u64 U64() const; 52 [[nodiscard]] u64 U64() const;
50 53
51 [[nodiscard]] bool operator==(const Value& other) const; 54 [[nodiscard]] bool operator==(const Value& other) const;
@@ -65,7 +68,9 @@ private:
65 u8 imm_u8; 68 u8 imm_u8;
66 u16 imm_u16; 69 u16 imm_u16;
67 u32 imm_u32; 70 u32 imm_u32;
71 f32 imm_f32;
68 u64 imm_u64; 72 u64 imm_u64;
73 f64 imm_f64;
69 }; 74 };
70}; 75};
71 76
@@ -93,8 +98,13 @@ using U8 = TypedValue<Type::U8>;
93using U16 = TypedValue<Type::U16>; 98using U16 = TypedValue<Type::U16>;
94using U32 = TypedValue<Type::U32>; 99using U32 = TypedValue<Type::U32>;
95using U64 = TypedValue<Type::U64>; 100using U64 = TypedValue<Type::U64>;
101using F16 = TypedValue<Type::F16>;
102using F32 = TypedValue<Type::F32>;
103using F64 = TypedValue<Type::F64>;
96using U32U64 = TypedValue<Type::U32 | Type::U64>; 104using U32U64 = TypedValue<Type::U32 | Type::U64>;
105using F32F64 = TypedValue<Type::F32 | Type::F64>;
97using U16U32U64 = TypedValue<Type::U16 | Type::U32 | Type::U64>; 106using U16U32U64 = TypedValue<Type::U16 | Type::U32 | Type::U64>;
107using F16F32F64 = TypedValue<Type::F16 | Type::F32 | Type::F64>;
98using UAny = TypedValue<Type::U8 | Type::U16 | Type::U32 | Type::U64>; 108using UAny = TypedValue<Type::U8 | Type::U16 | Type::U32 | Type::U64>;
99 109
100} // namespace Shader::IR 110} // namespace Shader::IR
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_add.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_add.cpp
index d2c44b9cc..cb3a326cf 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_add.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_add.cpp
@@ -11,7 +11,7 @@ namespace Shader::Maxwell {
11namespace { 11namespace {
12 12
13void FADD(TranslatorVisitor& v, u64 insn, bool sat, bool cc, bool ftz, FpRounding fp_rounding, 13void FADD(TranslatorVisitor& v, u64 insn, bool sat, bool cc, bool ftz, FpRounding fp_rounding,
14 const IR::U32& src_b, bool abs_a, bool neg_a, bool abs_b, bool neg_b) { 14 const IR::F32& src_b, bool abs_a, bool neg_a, bool abs_b, bool neg_b) {
15 union { 15 union {
16 u64 raw; 16 u64 raw;
17 BitField<0, 8, IR::Reg> dest_reg; 17 BitField<0, 8, IR::Reg> dest_reg;
@@ -24,17 +24,17 @@ void FADD(TranslatorVisitor& v, u64 insn, bool sat, bool cc, bool ftz, FpRoundin
24 if (cc) { 24 if (cc) {
25 throw NotImplementedException("FADD CC"); 25 throw NotImplementedException("FADD CC");
26 } 26 }
27 const IR::U32 op_a{v.ir.FPAbsNeg(v.X(fadd.src_a), abs_a, neg_a)}; 27 const IR::F32 op_a{v.ir.FPAbsNeg(v.F(fadd.src_a), abs_a, neg_a)};
28 const IR::U32 op_b{v.ir.FPAbsNeg(src_b, abs_b, neg_b)}; 28 const IR::F32 op_b{v.ir.FPAbsNeg(src_b, abs_b, neg_b)};
29 IR::FpControl control{ 29 IR::FpControl control{
30 .no_contraction{true}, 30 .no_contraction{true},
31 .rounding{CastFpRounding(fp_rounding)}, 31 .rounding{CastFpRounding(fp_rounding)},
32 .fmz_mode{ftz ? IR::FmzMode::FTZ : IR::FmzMode::None}, 32 .fmz_mode{ftz ? IR::FmzMode::FTZ : IR::FmzMode::None},
33 }; 33 };
34 v.X(fadd.dest_reg, v.ir.FPAdd(op_a, op_b, control)); 34 v.F(fadd.dest_reg, v.ir.FPAdd(op_a, op_b, control));
35} 35}
36 36
37void FADD(TranslatorVisitor& v, u64 insn, const IR::U32& src_b) { 37void FADD(TranslatorVisitor& v, u64 insn, const IR::F32& src_b) {
38 union { 38 union {
39 u64 raw; 39 u64 raw;
40 BitField<39, 2, FpRounding> fp_rounding; 40 BitField<39, 2, FpRounding> fp_rounding;
@@ -53,7 +53,7 @@ void FADD(TranslatorVisitor& v, u64 insn, const IR::U32& src_b) {
53} // Anonymous namespace 53} // Anonymous namespace
54 54
55void TranslatorVisitor::FADD_reg(u64 insn) { 55void TranslatorVisitor::FADD_reg(u64 insn) {
56 FADD(*this, insn, GetReg20(insn)); 56 FADD(*this, insn, GetReg20F(insn));
57} 57}
58 58
59void TranslatorVisitor::FADD_cbuf(u64) { 59void TranslatorVisitor::FADD_cbuf(u64) {
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp
index c4288d9a8..acd8445ad 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp
@@ -55,21 +55,21 @@ size_t BitSize(DestFormat dest_format) {
55 } 55 }
56} 56}
57 57
58void TranslateF2I(TranslatorVisitor& v, u64 insn, const IR::U16U32U64& op_a) { 58void TranslateF2I(TranslatorVisitor& v, u64 insn, const IR::F16F32F64& src_a) {
59 // F2I is used to convert from a floating point value to an integer 59 // F2I is used to convert from a floating point value to an integer
60 const F2I f2i{insn}; 60 const F2I f2i{insn};
61 61
62 const IR::U16U32U64 float_value{v.ir.FPAbsNeg(op_a, f2i.abs != 0, f2i.neg != 0)}; 62 const IR::F16F32F64 op_a{v.ir.FPAbsNeg(src_a, f2i.abs != 0, f2i.neg != 0)};
63 const IR::U16U32U64 rounded_value{[&] { 63 const IR::F16F32F64 rounded_value{[&] {
64 switch (f2i.rounding) { 64 switch (f2i.rounding) {
65 case Rounding::Round: 65 case Rounding::Round:
66 return v.ir.FPRoundEven(float_value); 66 return v.ir.FPRoundEven(op_a);
67 case Rounding::Floor: 67 case Rounding::Floor:
68 return v.ir.FPFloor(float_value); 68 return v.ir.FPFloor(op_a);
69 case Rounding::Ceil: 69 case Rounding::Ceil:
70 return v.ir.FPCeil(float_value); 70 return v.ir.FPCeil(op_a);
71 case Rounding::Trunc: 71 case Rounding::Trunc:
72 return v.ir.FPTrunc(float_value); 72 return v.ir.FPTrunc(op_a);
73 default: 73 default:
74 throw NotImplementedException("Invalid F2I rounding {}", f2i.rounding.Value()); 74 throw NotImplementedException("Invalid F2I rounding {}", f2i.rounding.Value());
75 } 75 }
@@ -105,12 +105,12 @@ void TranslatorVisitor::F2I_reg(u64 insn) {
105 BitField<20, 8, IR::Reg> src_reg; 105 BitField<20, 8, IR::Reg> src_reg;
106 } const f2i{insn}; 106 } const f2i{insn};
107 107
108 const IR::U16U32U64 op_a{[&]() -> IR::U16U32U64 { 108 const IR::F16F32F64 op_a{[&]() -> IR::F16F32F64 {
109 switch (f2i.base.src_format) { 109 switch (f2i.base.src_format) {
110 case SrcFormat::F16: 110 case SrcFormat::F16:
111 return ir.CompositeExtract(ir.UnpackFloat2x16(X(f2i.src_reg)), f2i.base.half); 111 return IR::F16{ir.CompositeExtract(ir.UnpackFloat2x16(X(f2i.src_reg)), f2i.base.half)};
112 case SrcFormat::F32: 112 case SrcFormat::F32:
113 return X(f2i.src_reg); 113 return F(f2i.src_reg);
114 case SrcFormat::F64: 114 case SrcFormat::F64:
115 return ir.PackDouble2x32(ir.CompositeConstruct(X(f2i.src_reg), X(f2i.src_reg + 1))); 115 return ir.PackDouble2x32(ir.CompositeConstruct(X(f2i.src_reg), X(f2i.src_reg + 1)));
116 default: 116 default:
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_fused_multiply_add.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_fused_multiply_add.cpp
index 30ca052ec..1464f2807 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_fused_multiply_add.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_fused_multiply_add.cpp
@@ -9,7 +9,7 @@
9 9
10namespace Shader::Maxwell { 10namespace Shader::Maxwell {
11namespace { 11namespace {
12void FFMA(TranslatorVisitor& v, u64 insn, const IR::U32& src_b, const IR::U32& src_c, bool neg_a, 12void FFMA(TranslatorVisitor& v, u64 insn, const IR::F32& src_b, const IR::F32& src_c, bool neg_a,
13 bool neg_b, bool neg_c, bool sat, bool cc, FmzMode fmz_mode, FpRounding fp_rounding) { 13 bool neg_b, bool neg_c, bool sat, bool cc, FmzMode fmz_mode, FpRounding fp_rounding) {
14 union { 14 union {
15 u64 raw; 15 u64 raw;
@@ -23,18 +23,18 @@ void FFMA(TranslatorVisitor& v, u64 insn, const IR::U32& src_b, const IR::U32& s
23 if (cc) { 23 if (cc) {
24 throw NotImplementedException("FFMA CC"); 24 throw NotImplementedException("FFMA CC");
25 } 25 }
26 const IR::U32 op_a{v.ir.FPAbsNeg(v.X(ffma.src_a), false, neg_a)}; 26 const IR::F32 op_a{v.ir.FPAbsNeg(v.F(ffma.src_a), false, neg_a)};
27 const IR::U32 op_b{v.ir.FPAbsNeg(src_b, false, neg_b)}; 27 const IR::F32 op_b{v.ir.FPAbsNeg(src_b, false, neg_b)};
28 const IR::U32 op_c{v.ir.FPAbsNeg(src_c, false, neg_c)}; 28 const IR::F32 op_c{v.ir.FPAbsNeg(src_c, false, neg_c)};
29 const IR::FpControl fp_control{ 29 const IR::FpControl fp_control{
30 .no_contraction{true}, 30 .no_contraction{true},
31 .rounding{CastFpRounding(fp_rounding)}, 31 .rounding{CastFpRounding(fp_rounding)},
32 .fmz_mode{CastFmzMode(fmz_mode)}, 32 .fmz_mode{CastFmzMode(fmz_mode)},
33 }; 33 };
34 v.X(ffma.dest_reg, v.ir.FPFma(op_a, op_b, op_c, fp_control)); 34 v.F(ffma.dest_reg, v.ir.FPFma(op_a, op_b, op_c, fp_control));
35} 35}
36 36
37void FFMA(TranslatorVisitor& v, u64 insn, const IR::U32& src_b, const IR::U32& src_c) { 37void FFMA(TranslatorVisitor& v, u64 insn, const IR::F32& src_b, const IR::F32& src_c) {
38 union { 38 union {
39 u64 raw; 39 u64 raw;
40 BitField<47, 1, u64> cc; 40 BitField<47, 1, u64> cc;
@@ -51,7 +51,7 @@ void FFMA(TranslatorVisitor& v, u64 insn, const IR::U32& src_b, const IR::U32& s
51} // Anonymous namespace 51} // Anonymous namespace
52 52
53void TranslatorVisitor::FFMA_reg(u64 insn) { 53void TranslatorVisitor::FFMA_reg(u64 insn) {
54 FFMA(*this, insn, GetReg20(insn), GetReg39(insn)); 54 FFMA(*this, insn, GetReg20F(insn), GetReg39F(insn));
55} 55}
56 56
57void TranslatorVisitor::FFMA_rc(u64) { 57void TranslatorVisitor::FFMA_rc(u64) {
@@ -59,7 +59,7 @@ void TranslatorVisitor::FFMA_rc(u64) {
59} 59}
60 60
61void TranslatorVisitor::FFMA_cr(u64 insn) { 61void TranslatorVisitor::FFMA_cr(u64 insn) {
62 FFMA(*this, insn, GetCbuf(insn), GetReg39(insn)); 62 FFMA(*this, insn, GetCbufF(insn), GetReg39F(insn));
63} 63}
64 64
65void TranslatorVisitor::FFMA_imm(u64) { 65void TranslatorVisitor::FFMA_imm(u64) {
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_multi_function.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_multi_function.cpp
index e2ab0dab2..90cddb18b 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_multi_function.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_multi_function.cpp
@@ -35,8 +35,8 @@ void TranslatorVisitor::MUFU(u64 insn) {
35 BitField<50, 1, u64> sat; 35 BitField<50, 1, u64> sat;
36 } const mufu{insn}; 36 } const mufu{insn};
37 37
38 const IR::U32 op_a{ir.FPAbsNeg(X(mufu.src_reg), mufu.abs != 0, mufu.neg != 0)}; 38 const IR::F32 op_a{ir.FPAbsNeg(F(mufu.src_reg), mufu.abs != 0, mufu.neg != 0)};
39 IR::U32 value{[&]() -> IR::U32 { 39 IR::F32 value{[&]() -> IR::F32 {
40 switch (mufu.operation) { 40 switch (mufu.operation) {
41 case Operation::Cos: 41 case Operation::Cos:
42 return ir.FPCosNotReduced(op_a); 42 return ir.FPCosNotReduced(op_a);
@@ -65,7 +65,7 @@ void TranslatorVisitor::MUFU(u64 insn) {
65 value = ir.FPSaturate(value); 65 value = ir.FPSaturate(value);
66 } 66 }
67 67
68 X(mufu.dest_reg, value); 68 F(mufu.dest_reg, value);
69} 69}
70 70
71} // namespace Shader::Maxwell 71} // namespace Shader::Maxwell
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_multiply.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_multiply.cpp
index 743a1e2f0..1b1d38be7 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_multiply.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_multiply.cpp
@@ -4,6 +4,7 @@
4 4
5#include "common/bit_field.h" 5#include "common/bit_field.h"
6#include "common/common_types.h" 6#include "common/common_types.h"
7#include "shader_recompiler/frontend/ir/ir_emitter.h"
7#include "shader_recompiler/frontend/ir/modifiers.h" 8#include "shader_recompiler/frontend/ir/modifiers.h"
8#include "shader_recompiler/frontend/maxwell/translate/impl/common_encoding.h" 9#include "shader_recompiler/frontend/maxwell/translate/impl/common_encoding.h"
9#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h" 10#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
@@ -43,7 +44,7 @@ float ScaleFactor(Scale scale) {
43 throw NotImplementedException("Invalid FMUL scale {}", scale); 44 throw NotImplementedException("Invalid FMUL scale {}", scale);
44} 45}
45 46
46void FMUL(TranslatorVisitor& v, u64 insn, const IR::U32& src_b, FmzMode fmz_mode, 47void FMUL(TranslatorVisitor& v, u64 insn, const IR::F32& src_b, FmzMode fmz_mode,
47 FpRounding fp_rounding, Scale scale, bool sat, bool cc, bool neg_b) { 48 FpRounding fp_rounding, Scale scale, bool sat, bool cc, bool neg_b) {
48 union { 49 union {
49 u64 raw; 50 u64 raw;
@@ -57,23 +58,23 @@ void FMUL(TranslatorVisitor& v, u64 insn, const IR::U32& src_b, FmzMode fmz_mode
57 if (sat) { 58 if (sat) {
58 throw NotImplementedException("FMUL SAT"); 59 throw NotImplementedException("FMUL SAT");
59 } 60 }
60 IR::U32 op_a{v.X(fmul.src_a)}; 61 IR::F32 op_a{v.F(fmul.src_a)};
61 if (scale != Scale::None) { 62 if (scale != Scale::None) {
62 if (fmz_mode != FmzMode::FTZ || fp_rounding != FpRounding::RN) { 63 if (fmz_mode != FmzMode::FTZ || fp_rounding != FpRounding::RN) {
63 throw NotImplementedException("FMUL scale with non-FMZ or non-RN modifiers"); 64 throw NotImplementedException("FMUL scale with non-FMZ or non-RN modifiers");
64 } 65 }
65 op_a = v.ir.FPMul(op_a, v.ir.Imm32(ScaleFactor(scale))); 66 op_a = v.ir.FPMul(op_a, v.ir.Imm32(ScaleFactor(scale)));
66 } 67 }
67 const IR::U32 op_b{v.ir.FPAbsNeg(src_b, false, neg_b)}; 68 const IR::F32 op_b{v.ir.FPAbsNeg(src_b, false, neg_b)};
68 const IR::FpControl fp_control{ 69 const IR::FpControl fp_control{
69 .no_contraction{true}, 70 .no_contraction{true},
70 .rounding{CastFpRounding(fp_rounding)}, 71 .rounding{CastFpRounding(fp_rounding)},
71 .fmz_mode{CastFmzMode(fmz_mode)}, 72 .fmz_mode{CastFmzMode(fmz_mode)},
72 }; 73 };
73 v.X(fmul.dest_reg, v.ir.FPMul(op_a, op_b, fp_control)); 74 v.F(fmul.dest_reg, v.ir.FPMul(op_a, op_b, fp_control));
74} 75}
75 76
76void FMUL(TranslatorVisitor& v, u64 insn, const IR::U32& src_b) { 77void FMUL(TranslatorVisitor& v, u64 insn, const IR::F32& src_b) {
77 union { 78 union {
78 u64 raw; 79 u64 raw;
79 BitField<39, 2, FpRounding> fp_rounding; 80 BitField<39, 2, FpRounding> fp_rounding;
@@ -90,7 +91,7 @@ void FMUL(TranslatorVisitor& v, u64 insn, const IR::U32& src_b) {
90} // Anonymous namespace 91} // Anonymous namespace
91 92
92void TranslatorVisitor::FMUL_reg(u64 insn) { 93void TranslatorVisitor::FMUL_reg(u64 insn) {
93 return FMUL(*this, insn, GetReg20(insn)); 94 return FMUL(*this, insn, GetReg20F(insn));
94} 95}
95 96
96void TranslatorVisitor::FMUL_cbuf(u64) { 97void TranslatorVisitor::FMUL_cbuf(u64) {
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp
index 548c7f611..3c9eaddd9 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp
@@ -12,10 +12,18 @@ IR::U32 TranslatorVisitor::X(IR::Reg reg) {
12 return ir.GetReg(reg); 12 return ir.GetReg(reg);
13} 13}
14 14
15IR::F32 TranslatorVisitor::F(IR::Reg reg) {
16 return ir.BitCast<IR::F32>(X(reg));
17}
18
15void TranslatorVisitor::X(IR::Reg dest_reg, const IR::U32& value) { 19void TranslatorVisitor::X(IR::Reg dest_reg, const IR::U32& value) {
16 ir.SetReg(dest_reg, value); 20 ir.SetReg(dest_reg, value);
17} 21}
18 22
23void TranslatorVisitor::F(IR::Reg dest_reg, const IR::F32& value) {
24 X(dest_reg, ir.BitCast<IR::U32>(value));
25}
26
19IR::U32 TranslatorVisitor::GetReg20(u64 insn) { 27IR::U32 TranslatorVisitor::GetReg20(u64 insn) {
20 union { 28 union {
21 u64 raw; 29 u64 raw;
@@ -32,6 +40,14 @@ IR::U32 TranslatorVisitor::GetReg39(u64 insn) {
32 return X(reg.index); 40 return X(reg.index);
33} 41}
34 42
43IR::F32 TranslatorVisitor::GetReg20F(u64 insn) {
44 return ir.BitCast<IR::F32>(GetReg20(insn));
45}
46
47IR::F32 TranslatorVisitor::GetReg39F(u64 insn) {
48 return ir.BitCast<IR::F32>(GetReg39(insn));
49}
50
35IR::U32 TranslatorVisitor::GetCbuf(u64 insn) { 51IR::U32 TranslatorVisitor::GetCbuf(u64 insn) {
36 union { 52 union {
37 u64 raw; 53 u64 raw;
@@ -49,6 +65,10 @@ IR::U32 TranslatorVisitor::GetCbuf(u64 insn) {
49 return ir.GetCbuf(binding, byte_offset); 65 return ir.GetCbuf(binding, byte_offset);
50} 66}
51 67
68IR::F32 TranslatorVisitor::GetCbufF(u64 insn) {
69 return ir.BitCast<IR::F32>(GetCbuf(insn));
70}
71
52IR::U32 TranslatorVisitor::GetImm20(u64 insn) { 72IR::U32 TranslatorVisitor::GetImm20(u64 insn) {
53 union { 73 union {
54 u64 raw; 74 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 ef6d977fe..b701605d7 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h
@@ -296,12 +296,18 @@ public:
296 void XMAD_imm(u64 insn); 296 void XMAD_imm(u64 insn);
297 297
298 [[nodiscard]] IR::U32 X(IR::Reg reg); 298 [[nodiscard]] IR::U32 X(IR::Reg reg);
299 [[nodiscard]] IR::F32 F(IR::Reg reg);
300
299 void X(IR::Reg dest_reg, const IR::U32& value); 301 void X(IR::Reg dest_reg, const IR::U32& value);
302 void F(IR::Reg dest_reg, const IR::F32& value);
300 303
301 [[nodiscard]] IR::U32 GetReg20(u64 insn); 304 [[nodiscard]] IR::U32 GetReg20(u64 insn);
302 [[nodiscard]] IR::U32 GetReg39(u64 insn); 305 [[nodiscard]] IR::U32 GetReg39(u64 insn);
306 [[nodiscard]] IR::F32 GetReg20F(u64 insn);
307 [[nodiscard]] IR::F32 GetReg39F(u64 insn);
303 308
304 [[nodiscard]] IR::U32 GetCbuf(u64 insn); 309 [[nodiscard]] IR::U32 GetCbuf(u64 insn);
310 [[nodiscard]] IR::F32 GetCbufF(u64 insn);
305 311
306 [[nodiscard]] IR::U32 GetImm20(u64 insn); 312 [[nodiscard]] IR::U32 GetImm20(u64 insn);
307 313
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp
index 23512db1a..de65173e8 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp
@@ -5,22 +5,23 @@
5#include "common/bit_field.h" 5#include "common/bit_field.h"
6#include "common/common_types.h" 6#include "common/common_types.h"
7#include "shader_recompiler/exception.h" 7#include "shader_recompiler/exception.h"
8#include "shader_recompiler/frontend/ir/ir_emitter.h"
8#include "shader_recompiler/frontend/maxwell/opcode.h" 9#include "shader_recompiler/frontend/maxwell/opcode.h"
9#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h" 10#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
10 11
11namespace Shader::Maxwell { 12namespace Shader::Maxwell {
12namespace { 13namespace {
13enum class InterpolationMode : u64 { 14enum class InterpolationMode : u64 {
14 Pass = 0, 15 Pass,
15 Multiply = 1, 16 Multiply,
16 Constant = 2, 17 Constant,
17 Sc = 3, 18 Sc,
18}; 19};
19 20
20enum class SampleMode : u64 { 21enum class SampleMode : u64 {
21 Default = 0, 22 Default,
22 Centroid = 1, 23 Centroid,
23 Offset = 2, 24 Offset,
24}; 25};
25} // Anonymous namespace 26} // Anonymous namespace
26 27
@@ -54,12 +55,12 @@ void TranslatorVisitor::IPA(u64 insn) {
54 } 55 }
55 56
56 const IR::Attribute attribute{ipa.attribute}; 57 const IR::Attribute attribute{ipa.attribute};
57 IR::U32 value{ir.GetAttribute(attribute)}; 58 IR::F32 value{ir.GetAttribute(attribute)};
58 if (IR::IsGeneric(attribute)) { 59 if (IR::IsGeneric(attribute)) {
59 // const bool is_perspective{UnimplementedReadHeader(GenericAttributeIndex(attribute))}; 60 // const bool is_perspective{UnimplementedReadHeader(GenericAttributeIndex(attribute))};
60 const bool is_perspective{false}; 61 const bool is_perspective{false};
61 if (is_perspective) { 62 if (is_perspective) {
62 const IR::U32 rcp_position_w{ir.FPRecip(ir.GetAttribute(IR::Attribute::PositionW))}; 63 const IR::F32 rcp_position_w{ir.FPRecip(ir.GetAttribute(IR::Attribute::PositionW))};
63 value = ir.FPMul(value, rcp_position_w); 64 value = ir.FPMul(value, rcp_position_w);
64 } 65 }
65 } 66 }
@@ -68,7 +69,7 @@ void TranslatorVisitor::IPA(u64 insn) {
68 case InterpolationMode::Pass: 69 case InterpolationMode::Pass:
69 break; 70 break;
70 case InterpolationMode::Multiply: 71 case InterpolationMode::Multiply:
71 value = ir.FPMul(value, ir.GetReg(ipa.multiplier)); 72 value = ir.FPMul(value, F(ipa.multiplier));
72 break; 73 break;
73 case InterpolationMode::Constant: 74 case InterpolationMode::Constant:
74 throw NotImplementedException("IPA.CONSTANT"); 75 throw NotImplementedException("IPA.CONSTANT");
@@ -86,7 +87,7 @@ void TranslatorVisitor::IPA(u64 insn) {
86 value = ir.FPSaturate(value); 87 value = ir.FPSaturate(value);
87 } 88 }
88 89
89 ir.SetReg(ipa.dest_reg, value); 90 F(ipa.dest_reg, value);
90} 91}
91 92
92} // namespace Shader::Maxwell 93} // namespace Shader::Maxwell
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_memory.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_memory.cpp
index c9669c617..9f1570479 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_memory.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_memory.cpp
@@ -114,7 +114,7 @@ void TranslatorVisitor::LDG(u64 insn) {
114 } 114 }
115 const IR::Value vector{ir.LoadGlobal64(address)}; 115 const IR::Value vector{ir.LoadGlobal64(address)};
116 for (int i = 0; i < 2; ++i) { 116 for (int i = 0; i < 2; ++i) {
117 X(dest_reg + i, ir.CompositeExtract(vector, i)); 117 X(dest_reg + i, IR::U32{ir.CompositeExtract(vector, i)});
118 } 118 }
119 break; 119 break;
120 } 120 }
@@ -124,7 +124,7 @@ void TranslatorVisitor::LDG(u64 insn) {
124 } 124 }
125 const IR::Value vector{ir.LoadGlobal128(address)}; 125 const IR::Value vector{ir.LoadGlobal128(address)};
126 for (int i = 0; i < 4; ++i) { 126 for (int i = 0; i < 4; ++i) {
127 X(dest_reg + i, ir.CompositeExtract(vector, i)); 127 X(dest_reg + i, IR::U32{ir.CompositeExtract(vector, i)});
128 } 128 }
129 break; 129 break;
130 } 130 }
diff --git a/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp b/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp
index 02f5b653d..7fb3192d8 100644
--- a/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp
+++ b/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp
@@ -5,6 +5,7 @@
5#include <algorithm> 5#include <algorithm>
6#include <type_traits> 6#include <type_traits>
7 7
8#include "common/bit_cast.h"
8#include "common/bit_util.h" 9#include "common/bit_util.h"
9#include "shader_recompiler/exception.h" 10#include "shader_recompiler/exception.h"
10#include "shader_recompiler/frontend/ir/microinstruction.h" 11#include "shader_recompiler/frontend/ir/microinstruction.h"
@@ -25,6 +26,8 @@ template <typename T>
25 return value.U1(); 26 return value.U1();
26 } else if constexpr (std::is_same_v<T, u32>) { 27 } else if constexpr (std::is_same_v<T, u32>) {
27 return value.U32(); 28 return value.U32();
29 } else if constexpr (std::is_same_v<T, f32>) {
30 return value.F32();
28 } else if constexpr (std::is_same_v<T, u64>) { 31 } else if constexpr (std::is_same_v<T, u64>) {
29 return value.U64(); 32 return value.U64();
30 } 33 }
@@ -115,6 +118,19 @@ void FoldLogicalAnd(IR::Inst& inst) {
115 } 118 }
116} 119}
117 120
121template <typename Dest, typename Source>
122void FoldBitCast(IR::Inst& inst, IR::Opcode reverse) {
123 const IR::Value value{inst.Arg(0)};
124 if (value.IsImmediate()) {
125 inst.ReplaceUsesWith(IR::Value{Common::BitCast<Dest>(Arg<Source>(value))});
126 return;
127 }
128 IR::Inst* const arg_inst{value.InstRecursive()};
129 if (value.InstRecursive()->Opcode() == reverse) {
130 inst.ReplaceUsesWith(arg_inst->Arg(0));
131 }
132}
133
118void ConstantPropagation(IR::Inst& inst) { 134void ConstantPropagation(IR::Inst& inst) {
119 switch (inst.Opcode()) { 135 switch (inst.Opcode()) {
120 case IR::Opcode::GetRegister: 136 case IR::Opcode::GetRegister:
@@ -123,6 +139,10 @@ void ConstantPropagation(IR::Inst& inst) {
123 return FoldGetPred(inst); 139 return FoldGetPred(inst);
124 case IR::Opcode::IAdd32: 140 case IR::Opcode::IAdd32:
125 return FoldAdd<u32>(inst); 141 return FoldAdd<u32>(inst);
142 case IR::Opcode::BitCastF32U32:
143 return FoldBitCast<f32, u32>(inst, IR::Opcode::BitCastU32F32);
144 case IR::Opcode::BitCastU32F32:
145 return FoldBitCast<u32, f32>(inst, IR::Opcode::BitCastF32U32);
126 case IR::Opcode::IAdd64: 146 case IR::Opcode::IAdd64:
127 return FoldAdd<u64>(inst); 147 return FoldAdd<u64>(inst);
128 case IR::Opcode::BitFieldUExtract: 148 case IR::Opcode::BitFieldUExtract:
diff --git a/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp b/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp
index ee69a5c9d..34393e1d5 100644
--- a/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp
+++ b/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp
@@ -108,8 +108,8 @@ bool MeetsBias(const StorageBufferAddr& storage_buffer, const Bias& bias) noexce
108 storage_buffer.offset < bias.offset_end; 108 storage_buffer.offset < bias.offset_end;
109} 109}
110 110
111/// Ignores a global memory operation, reads return zero and writes are ignored 111/// Discards a global memory operation, reads return zero and writes are ignored
112void IgnoreGlobalMemory(IR::Block& block, IR::Block::iterator inst) { 112void DiscardGlobalMemory(IR::Block& block, IR::Block::iterator inst) {
113 const IR::Value zero{u32{0}}; 113 const IR::Value zero{u32{0}};
114 switch (inst->Opcode()) { 114 switch (inst->Opcode()) {
115 case IR::Opcode::LoadGlobalS8: 115 case IR::Opcode::LoadGlobalS8:
@@ -120,12 +120,12 @@ void IgnoreGlobalMemory(IR::Block& block, IR::Block::iterator inst) {
120 inst->ReplaceUsesWith(zero); 120 inst->ReplaceUsesWith(zero);
121 break; 121 break;
122 case IR::Opcode::LoadGlobal64: 122 case IR::Opcode::LoadGlobal64:
123 inst->ReplaceUsesWith( 123 inst->ReplaceUsesWith(IR::Value{
124 IR::Value{&*block.PrependNewInst(inst, IR::Opcode::CompositeConstruct2, {zero, zero})}); 124 &*block.PrependNewInst(inst, IR::Opcode::CompositeConstructU32x2, {zero, zero})});
125 break; 125 break;
126 case IR::Opcode::LoadGlobal128: 126 case IR::Opcode::LoadGlobal128:
127 inst->ReplaceUsesWith(IR::Value{&*block.PrependNewInst( 127 inst->ReplaceUsesWith(IR::Value{&*block.PrependNewInst(
128 inst, IR::Opcode::CompositeConstruct4, {zero, zero, zero, zero})}); 128 inst, IR::Opcode::CompositeConstructU32x4, {zero, zero, zero, zero})});
129 break; 129 break;
130 case IR::Opcode::WriteGlobalS8: 130 case IR::Opcode::WriteGlobalS8:
131 case IR::Opcode::WriteGlobalU8: 131 case IR::Opcode::WriteGlobalU8:
@@ -137,7 +137,8 @@ void IgnoreGlobalMemory(IR::Block& block, IR::Block::iterator inst) {
137 inst->Invalidate(); 137 inst->Invalidate();
138 break; 138 break;
139 default: 139 default:
140 throw LogicError("Invalid opcode to ignore its global memory operation {}", inst->Opcode()); 140 throw LogicError("Invalid opcode to discard its global memory operation {}",
141 inst->Opcode());
141 } 142 }
142} 143}
143 144
@@ -196,7 +197,7 @@ void CollectStorageBuffers(IR::Block& block, IR::Block::iterator inst,
196 storage_buffer = Track(addr, nullptr); 197 storage_buffer = Track(addr, nullptr);
197 if (!storage_buffer) { 198 if (!storage_buffer) {
198 // If that also failed, drop the global memory usage 199 // If that also failed, drop the global memory usage
199 IgnoreGlobalMemory(block, inst); 200 DiscardGlobalMemory(block, inst);
200 } 201 }
201 } 202 }
202 // Collect storage buffer and the instruction 203 // Collect storage buffer and the instruction
@@ -242,12 +243,12 @@ std::optional<IR::U32> TrackLowAddress(IR::IREmitter& ir, IR::Inst* inst) {
242 if (vector.IsImmediate()) { 243 if (vector.IsImmediate()) {
243 return std::nullopt; 244 return std::nullopt;
244 } 245 }
245 // This vector is expected to be a CompositeConstruct2 246 // This vector is expected to be a CompositeConstructU32x2
246 IR::Inst* const vector_inst{vector.InstRecursive()}; 247 IR::Inst* const vector_inst{vector.InstRecursive()};
247 if (vector_inst->Opcode() != IR::Opcode::CompositeConstruct2) { 248 if (vector_inst->Opcode() != IR::Opcode::CompositeConstructU32x2) {
248 return std::nullopt; 249 return std::nullopt;
249 } 250 }
250 // Grab the first argument from the CompositeConstruct2, this is the low address. 251 // Grab the first argument from the CompositeConstructU32x2, this is the low address.
251 // Re-apply the offset in case we found one. 252 // Re-apply the offset in case we found one.
252 const IR::U32 low_addr{vector_inst->Arg(0)}; 253 const IR::U32 low_addr{vector_inst->Arg(0)};
253 return imm_offset != 0 ? IR::U32{ir.IAdd(low_addr, ir.Imm32(imm_offset))} : low_addr; 254 return imm_offset != 0 ? IR::U32{ir.IAdd(low_addr, ir.Imm32(imm_offset))} : low_addr;
diff --git a/src/shader_recompiler/main.cpp b/src/shader_recompiler/main.cpp
index 4022c6fe2..e6596d828 100644
--- a/src/shader_recompiler/main.cpp
+++ b/src/shader_recompiler/main.cpp
@@ -52,7 +52,7 @@ int main() {
52 // RunDatabase(); 52 // RunDatabase();
53 53
54 // FileEnvironment env{"D:\\Shaders\\Database\\test.bin"}; 54 // FileEnvironment env{"D:\\Shaders\\Database\\test.bin"};
55 FileEnvironment env{"D:\\Shaders\\Database\\Oninaki\\CS8F146B41DB6BD826.bin"}; 55 FileEnvironment env{"D:\\Shaders\\Database\\Oninaki\\CS15C2FB1F0B965767.bin"};
56 auto cfg{std::make_unique<Flow::CFG>(env, 0)}; 56 auto cfg{std::make_unique<Flow::CFG>(env, 0)};
57 // fmt::print(stdout, "{}\n", cfg->Dot()); 57 // fmt::print(stdout, "{}\n", cfg->Dot());
58 58